diff --git a/src/or/hs_circuitmap.c b/src/or/hs_circuitmap.c index 09704d796c..63d5c1ba2e 100644 --- a/src/or/hs_circuitmap.c +++ b/src/or/hs_circuitmap.c @@ -407,9 +407,20 @@ hs_circuitmap_get_rend_circ_service_side(const uint8_t *cookie) } /* Public function: Return client-side rendezvous circuit with rendezvous - * cookie. It will first lookup for the CIRCUIT_PURPOSE_C_REND_READY - * purpose and then try for CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED and then - * finally tries for CIRCUIT_PURPOSE_C_ESTABLISH_REND. + * cookie. It will look for circuits with the following purposes: + + * a) CIRCUIT_PURPOSE_C_REND_READY: Established rend circuit (received + * RENDEZVOUS_ESTABLISHED). Waiting for RENDEZVOUS2 from service, and for + * INTRODUCE_ACK from intro point. + * + * b) CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED: Established rend circuit and + * introduce circuit acked. Waiting for RENDEZVOUS2 from service. + * + * c) CIRCUIT_PURPOSE_C_REND_JOINED: Established rend circuit and received + * RENDEZVOUS2 from service. + * + * d) CIRCUIT_PURPOSE_C_ESTABLISH_REND: Rend circuit open but not yet + * established. * * Return NULL if no such circuit is found in the circuitmap. */ origin_circuit_t * @@ -431,6 +442,13 @@ hs_circuitmap_get_rend_circ_client_side(const uint8_t *cookie) return circ; } + circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_REND_CLIENT_SIDE, + REND_TOKEN_LEN, cookie, + CIRCUIT_PURPOSE_C_REND_JOINED); + if (circ) { + return circ; + } + circ = hs_circuitmap_get_origin_circuit(HS_TOKEN_REND_CLIENT_SIDE, REND_TOKEN_LEN, cookie, CIRCUIT_PURPOSE_C_ESTABLISH_REND); diff --git a/src/or/hs_client.c b/src/or/hs_client.c index f85ebc8473..652b7cf74f 100644 --- a/src/or/hs_client.c +++ b/src/or/hs_client.c @@ -746,6 +746,14 @@ handle_introduce_ack_success(origin_circuit_t *intro_circ) } assert_circ_anonymity_ok(rend_circ, get_options()); + + /* It is possible to get a RENDEZVOUS2 cell before the INTRODUCE_ACK which + * means that the circuit will be joined and already transmitting data. In + * that case, simply skip the purpose change and close the intro circuit + * like it should be. */ + if (TO_CIRCUIT(rend_circ)->purpose == CIRCUIT_PURPOSE_C_REND_JOINED) { + goto end; + } circuit_change_purpose(TO_CIRCUIT(rend_circ), CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED); /* Set timestamp_dirty, because circuit_expire_building expects it to