From 7f83c43594dcf13fb04352f5faa8db2cd86354c1 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 30 Oct 2019 15:56:17 -0400 Subject: [PATCH] hs-v3: Note client intro circuit failure Report back to the v3 subsystem any introduction point client circuit failure so they can be noted down in the failure cache. Fixes #32020 Signed-off-by: David Goulet --- src/feature/hs/hs_circuit.c | 34 +++++++++++++++---------- src/feature/hs/hs_client.c | 50 +++++++++++++++++++++++++++++++++++++ src/feature/hs/hs_client.h | 1 + 3 files changed, 72 insertions(+), 13 deletions(-) diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c index 1a3767ce62..8640129f3f 100644 --- a/src/feature/hs/hs_circuit.c +++ b/src/feature/hs/hs_circuit.c @@ -20,6 +20,7 @@ #include "feature/hs/hs_cell.h" #include "feature/hs/hs_circuit.h" #include "feature/hs/hs_circuitmap.h" +#include "feature/hs/hs_client.h" #include "feature/hs/hs_ident.h" #include "feature/hs/hs_service.h" #include "feature/nodelist/describe.h" @@ -619,6 +620,22 @@ setup_introduce1_data(const hs_desc_intro_point_t *ip, return ret; } +/** Helper: cleanup function for client circuit. This is for every HS version. + * It is called from hs_circ_cleanup() entry point. */ +static void +cleanup_client_circ(circuit_t *circ) +{ + tor_assert(circ); + + if (circuit_is_hs_v2(circ)) { + rend_client_circuit_cleanup(circ); + } else if (circuit_is_hs_v3(circ)) { + hs_client_circuit_cleanup(circ); + } + /* It is possible the circuit has an HS purpose but no identifier (rend_data + * or hs_ident). Thus possible that this passess through. */ +} + /* ========== */ /* Public API */ /* ========== */ @@ -1206,21 +1223,12 @@ hs_circ_cleanup(circuit_t *circ) { tor_assert(circ); - /* v2 specific circuits. */ - if (circuit_is_hs_v2(circ)) { - if (circuit_is_hs_client(circ)) { - rend_client_circuit_cleanup(circ); - } + if (circuit_purpose_is_hs_client(circ->purpose)) { + cleanup_client_circ(circ); } - /* From this point on, it is v3 specific. */ - - /* If it's a service-side intro circ, notify the HS subsystem for the intro - * point circuit closing so it can be dealt with cleanly. */ - if (circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO || - circ->purpose == CIRCUIT_PURPOSE_S_INTRO) { - hs_service_intro_circ_has_closed(TO_ORIGIN_CIRCUIT(circ)); - } + /* Actions that MUST happen for every circuits regardless of what was done + * on it before. */ /* Clear HS circuitmap token for this circ (if any). Very important to be * done after the HS subsystem has been notified of the close else the diff --git a/src/feature/hs/hs_client.c b/src/feature/hs/hs_client.c index 787b29b576..716b6a26a2 100644 --- a/src/feature/hs/hs_client.c +++ b/src/feature/hs/hs_client.c @@ -1522,6 +1522,56 @@ get_hs_client_auths_map(void) /* Public API */ /* ========== */ +/** Called when a circuit was just cleaned up. This is done right before the + * circuit is freed. */ +void +hs_client_circuit_cleanup(const circuit_t *circ) +{ + bool has_timed_out; + rend_intro_point_failure_t failure = INTRO_POINT_FAILURE_GENERIC; + const origin_circuit_t *orig_circ = NULL; + + tor_assert(circ); + tor_assert(CIRCUIT_IS_ORIGIN(circ)); + + orig_circ = CONST_TO_ORIGIN_CIRCUIT(circ); + tor_assert(orig_circ->hs_ident); + + has_timed_out = + (circ->marked_for_close_orig_reason == END_CIRC_REASON_TIMEOUT); + if (has_timed_out) { + failure = INTRO_POINT_FAILURE_TIMEOUT; + } + + switch (circ->purpose) { + case CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT: + log_info(LD_REND, "Failed v3 intro circ for service %s to intro point %s " + "(awaiting ACK). Failure code: %d", + safe_str_client(ed25519_fmt(&orig_circ->hs_ident->identity_pk)), + safe_str_client(build_state_get_exit_nickname(orig_circ->build_state)), + failure); + hs_cache_client_intro_state_note(&orig_circ->hs_ident->identity_pk, + &orig_circ->hs_ident->intro_auth_pk, + failure); + break; + case CIRCUIT_PURPOSE_C_INTRODUCING: + if (has_timed_out || !orig_circ->build_state) { + break; + } + failure = INTRO_POINT_FAILURE_UNREACHABLE; + log_info(LD_REND, "Failed v3 intro circ for service %s to intro point %s " + "(while building circuit). Marking as unreachable.", + safe_str_client(ed25519_fmt(&orig_circ->hs_ident->identity_pk)), + safe_str_client(build_state_get_exit_nickname(orig_circ->build_state))); + hs_cache_client_intro_state_note(&orig_circ->hs_ident->identity_pk, + &orig_circ->hs_ident->intro_auth_pk, + failure); + break; + default: + break; + } +} + /** A circuit just finished connecting to a hidden service that the stream * conn has been waiting for. Let the HS subsystem know about this. */ void diff --git a/src/feature/hs/hs_client.h b/src/feature/hs/hs_client.h index 04827ea92a..a0f1c7758f 100644 --- a/src/feature/hs/hs_client.h +++ b/src/feature/hs/hs_client.h @@ -112,6 +112,7 @@ int hs_client_send_introduce1(origin_circuit_t *intro_circ, origin_circuit_t *rend_circ); void hs_client_circuit_has_opened(origin_circuit_t *circ); +void hs_client_circuit_cleanup(const circuit_t *circ); int hs_client_receive_rendezvous_acked(origin_circuit_t *circ, const uint8_t *payload,