HS can repick an expired intro points or one that we've already picked
Let's assume here we are about to cycle our intro points in
rend_services_introduce(), we do a dance and at the end we choose 3 new ones. To do that, we use
router_choose_random_node() that picks a random node using the torrc
ExcludeNodes list but also an exclude_nodes list that we've populated before which contains expired intro points.
After that, we happily launch an intro circuit by calling
rend_service_launch_establish_intro() and then
circuit_launch_by_extend_info(). In there, a circuit can be cannibalized and if so, the exit node is NOT extended to our intro points that we picked earlier because of our purpose:
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO: /* it's ready right now */
The IP is then changed to the one we just cannibalized once we have our circuit. This is not desirable for two reasons:
- We ignore the exclude nodes list thus we can end up picking an expired IP.
- We can use to the same IP multiple times for a single descriptor.
All of the above, I was able to reproduce in a chutney network that is having a set of IPs that expired in the previous period and a set of IPs that are all the same.
It's not that terrible in the real network because the probability of that happening is roughly
1/<relay count> which is < 1% currently, still worth fixing imo.
Possible solution for this: i) Use a 4th hop for the IP circuit meaning we allow cannibalization but we extend the circuit to the intro point.
ii) Disable cannibalization for intro point thus always creating a fresh circuit ending up at the right place.
My pick here would be i) because I think a 4th hop is cheaper than a creating a new circuit.