hs: Client rendez-vous circuit expiry is a mess
It turns out that once a rendezvous circuit is ready waiting for the RENDEZVOUS2
to arrive ( CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED
), we expire that circuit with general_cutoff
which is a very very low value. We then flip circ->hs_circ_has_timed_out
indicating that it timed out "but we'll keep it around in case it works". However, in circuit_is_acceptable()
, we return false if that flag is set meaning once flagged, it is good as dead until it finalizes which can be "never".
So, in the meantime, other rendezvous circuits get opened until one finally finalizes (all to the same RP). This can lead to a bomb of circuits opening by the client because it ain't cap and if the service never replies (because under DoS ;), then the client will just keep on trying.
There are a many issues here:
-
The cutoff of such circuit should be much higher because we end up in that circuit purpose when the
INTRODUCE_ACK
is received which could be before the service receives theINTRODUCE2
cell. Thus, the worst case is a full 3 hop latency, a 4-hop circuit creation latency (service -> RP), and then a 7-hop latency for theRENDEZVOUS2
cell to arrive. After talking to Mike, we'll apply a large value as in taking the basic CBT and multiplying it by 3. -
We should get rid of
hs_circ_has_timed_out
because it is extremely fragile in its current logic and we should simply apply a much longer CBT for theCIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED
purpose. -
It turns out that we can't have RP circuits in parallel to the same RP. The RP relay will discard any old circuits if a new one shows up with the same cookie. And so this whole dance is pointless.
-
Unrelated, the service rendezvous establish timeout cutoff is too low, it should be the "four hop" circuit cutoff and not the general cutoff so this also needs to be bumped.
-
I'm sure I'll find more problems in this logic.
Again, we need to backport this for the sake of HS client UX.