#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"
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 */
/* ========== */
{
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
/* 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
* <b>conn</b> has been waiting for. Let the HS subsystem know about this. */
void
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,