aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--changes/ticket320217
-rw-r--r--src/core/or/circuituse.c13
-rw-r--r--src/feature/hs/hs_circuit.c48
-rw-r--r--src/feature/hs/hs_circuit.h2
4 files changed, 61 insertions, 9 deletions
diff --git a/changes/ticket32021 b/changes/ticket32021
new file mode 100644
index 0000000000..24a6d9d981
--- /dev/null
+++ b/changes/ticket32021
@@ -0,0 +1,7 @@
+ o Minor bugfixes (onion services v3, client):
+ - Properly handle the client rendezvous circuit timeout. This results in
+ better reachability because tor doesn't timeout a rendezvous circuit
+ awaiting the introduction ACK and thus preventing tor to re-establish all
+ circuits because the rendezvous circuit timed out too early. Fixes bug
+ 32021; bugfix on 0.3.2.1-alpha.
+
diff --git a/src/core/or/circuituse.c b/src/core/or/circuituse.c
index ad9841cc36..e5013fe968 100644
--- a/src/core/or/circuituse.c
+++ b/src/core/or/circuituse.c
@@ -775,16 +775,11 @@ circuit_expire_building(void)
if (!(TO_ORIGIN_CIRCUIT(victim)->hs_circ_has_timed_out)) {
switch (victim->purpose) {
case CIRCUIT_PURPOSE_C_REND_READY:
- /* We only want to spare a rend circ if it has been specified in
- * an INTRODUCE1 cell sent to a hidden service. A circ's
- * pending_final_cpath field is non-NULL iff it is a rend circ
- * and we have tried to send an INTRODUCE1 cell specifying it.
- * Thus, if the pending_final_cpath field *is* NULL, then we
- * want to not spare it. */
- if (TO_ORIGIN_CIRCUIT(victim)->build_state &&
- TO_ORIGIN_CIRCUIT(victim)->build_state->pending_final_cpath ==
- NULL)
+ /* We only want to spare a rend circ iff it has been specified in an
+ * INTRODUCE1 cell sent to a hidden service. */
+ if (!hs_circ_is_rend_sent_in_intro1(CONST_TO_ORIGIN_CIRCUIT(victim))) {
break;
+ }
/* fallthrough! */
case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT:
case CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED:
diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c
index a43e7f0e23..2a420394f0 100644
--- a/src/feature/hs/hs_circuit.c
+++ b/src/feature/hs/hs_circuit.c
@@ -1296,3 +1296,51 @@ hs_circ_cleanup_on_repurpose(circuit_t *circ)
hs_circuitmap_remove_circuit(circ);
}
}
+
+/** Return true iff the given established client rendezvous circuit was sent
+ * into the INTRODUCE1 cell. This is called so we can take a decision on
+ * expiring or not the circuit.
+ *
+ * The caller MUST make sure the circuit is an established client rendezvous
+ * circuit (purpose: CIRCUIT_PURPOSE_C_REND_READY).
+ *
+ * This function supports all onion service versions. */
+bool
+hs_circ_is_rend_sent_in_intro1(const origin_circuit_t *circ)
+{
+ tor_assert(circ);
+ /* This can only be called for a rendezvous circuit that is an established
+ * confirmed rendezsvous circuit but without an introduction ACK. */
+ tor_assert(TO_CIRCUIT(circ)->purpose == CIRCUIT_PURPOSE_C_REND_READY);
+
+ /* The v2 and v3 circuit are handled differently:
+ *
+ * v2: A circ's pending_final_cpath field is non-NULL iff it is a rend circ
+ * and we have tried to send an INTRODUCE1 cell specifying it. Thus, if the
+ * pending_final_cpath field *is* NULL, then we want to not spare it.
+ *
+ * v3: When the INTRODUCE1 cell is sent, the introduction encryption public
+ * key is copied in the rendezvous circuit hs identifier. If it is a valid
+ * key, we know that this circuit is waiting the ACK on the introduction
+ * circuit. We want to _not_ spare the circuit if the key was never set. */
+
+ if (circ->rend_data) {
+ /* v2. */
+ if (circ->build_state && circ->build_state->pending_final_cpath != NULL) {
+ return true;
+ }
+ } else if (circ->hs_ident) {
+ /* v3. */
+ if (curve25519_public_key_is_ok(&circ->hs_ident->intro_enc_pk)) {
+ return true;
+ }
+ } else {
+ /* A circuit with an HS purpose without an hs_ident or rend_data in theory
+ * can not happen. In case, scream loudly and return false to the caller
+ * that the rendezvous was not sent in the INTRO1 cell. */
+ tor_assert_nonfatal_unreached();
+ }
+
+ /* The rendezvous has not been specified in the INTRODUCE1 cell. */
+ return false;
+}
diff --git a/src/feature/hs/hs_circuit.h b/src/feature/hs/hs_circuit.h
index 42e5ca1348..c044ad89c4 100644
--- a/src/feature/hs/hs_circuit.h
+++ b/src/feature/hs/hs_circuit.h
@@ -66,6 +66,8 @@ int hs_circuit_setup_e2e_rend_circ(origin_circuit_t *circ,
int hs_circuit_setup_e2e_rend_circ_legacy_client(origin_circuit_t *circ,
const uint8_t *rend_cell_body);
+bool hs_circ_is_rend_sent_in_intro1(const origin_circuit_t *circ);
+
#ifdef HS_CIRCUIT_PRIVATE
STATIC hs_ident_circuit_t *