diff options
Diffstat (limited to 'src/core/or/circuitlist.c')
-rw-r--r-- | src/core/or/circuitlist.c | 219 |
1 files changed, 95 insertions, 124 deletions
diff --git a/src/core/or/circuitlist.c b/src/core/or/circuitlist.c index ccf3041bb4..384835667d 100644 --- a/src/core/or/circuitlist.c +++ b/src/core/or/circuitlist.c @@ -1,7 +1,7 @@ /* Copyright 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -51,6 +51,7 @@ * logic, which was originally circuit-focused. **/ #define CIRCUITLIST_PRIVATE +#define OCIRC_EVENT_PRIVATE #include "lib/cc/torint.h" /* TOR_PRIuSZ */ #include "core/or/or.h" @@ -61,11 +62,13 @@ #include "core/or/circuitlist.h" #include "core/or/circuituse.h" #include "core/or/circuitstats.h" +#include "core/or/circuitpadding.h" +#include "core/or/crypt_path.h" #include "core/mainloop/connection.h" #include "app/config/config.h" #include "core/or/connection_edge.h" #include "core/or/connection_or.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" #include "lib/crypt_ops/crypto_dh.h" @@ -94,7 +97,9 @@ #include "lib/compress/compress_lzma.h" #include "lib/compress/compress_zlib.h" #include "lib/compress/compress_zstd.h" -#include "lib/container/buffers.h" +#include "lib/buf/buffers.h" + +#include "core/or/ocirc_event.h" #include "ht.h" @@ -127,7 +132,6 @@ static smartlist_t *circuits_pending_other_guards = NULL; * circuit_mark_for_close and which are waiting for circuit_about_to_free. */ static smartlist_t *circuits_pending_close = NULL; -static void circuit_free_cpath_node(crypt_path_t *victim); static void cpath_ref_decref(crypt_path_reference_t *cpath_ref); static void circuit_about_to_free_atexit(circuit_t *circ); static void circuit_about_to_free(circuit_t *circ); @@ -142,6 +146,9 @@ static int any_opened_circs_cached_val = 0; /********* END VARIABLES ************/ +/* Implement circuit handle helpers. */ +HANDLE_IMPL(circuit, circuit_t,) + or_circuit_t * TO_OR_CIRCUIT(circuit_t *x) { @@ -208,10 +215,10 @@ chan_circid_entry_hash_(chan_circid_circuit_map_t *a) static HT_HEAD(chan_circid_map, chan_circid_circuit_map_t) chan_circid_map = HT_INITIALIZER(); HT_PROTOTYPE(chan_circid_map, chan_circid_circuit_map_t, node, - chan_circid_entry_hash_, chan_circid_entries_eq_) + chan_circid_entry_hash_, chan_circid_entries_eq_); HT_GENERATE2(chan_circid_map, chan_circid_circuit_map_t, node, chan_circid_entry_hash_, chan_circid_entries_eq_, 0.6, - tor_reallocarray_, tor_free_) + tor_reallocarray_, tor_free_); /** The most recently returned entry from circuit_get_by_circid_chan; * used to improve performance when many cells arrive in a row from the @@ -481,6 +488,54 @@ circuit_set_n_circid_chan(circuit_t *circ, circid_t id, } } +/** + * Helper function to publish a message about events on an origin circuit + * + * Publishes a message to subscribers of origin circuit events, and + * sends the control event. + **/ +int +circuit_event_status(origin_circuit_t *circ, circuit_status_event_t tp, + int reason_code) +{ + ocirc_cevent_msg_t *msg = tor_malloc(sizeof(*msg)); + + tor_assert(circ); + + msg->gid = circ->global_identifier; + msg->evtype = tp; + msg->reason = reason_code; + msg->onehop = circ->build_state->onehop_tunnel; + + ocirc_cevent_publish(msg); + return control_event_circuit_status(circ, tp, reason_code); +} + +/** + * Helper function to publish a state change message + * + * circuit_set_state() calls this to notify subscribers about a change + * of the state of an origin circuit. @a circ must be an origin + * circuit. + **/ +static void +circuit_state_publish(const circuit_t *circ) +{ + ocirc_state_msg_t *msg = tor_malloc(sizeof(*msg)); + const origin_circuit_t *ocirc; + + tor_assert(CIRCUIT_IS_ORIGIN(circ)); + ocirc = CONST_TO_ORIGIN_CIRCUIT(circ); + /* Only inbound OR circuits can be in this state, not origin circuits. */ + tor_assert(circ->state != CIRCUIT_STATE_ONIONSKIN_PENDING); + + msg->gid = ocirc->global_identifier; + msg->state = circ->state; + msg->onehop = ocirc->build_state->onehop_tunnel; + + ocirc_state_publish(msg); +} + /** Change the state of <b>circ</b> to <b>state</b>, adding it to or removing * it from lists as appropriate. */ void @@ -510,6 +565,8 @@ circuit_set_state(circuit_t *circ, uint8_t state) if (state == CIRCUIT_STATE_GUARD_WAIT || state == CIRCUIT_STATE_OPEN) tor_assert(!circ->n_chan_create_cell); circ->state = state; + if (CIRCUIT_IS_ORIGIN(circ)) + circuit_state_publish(circ); } /** Append to <b>out</b> all circuits in state CHAN_WAIT waiting for @@ -767,6 +824,8 @@ circuit_purpose_to_controller_string(uint8_t purpose) return "PATH_BIAS_TESTING"; case CIRCUIT_PURPOSE_HS_VANGUARDS: return "HS_VANGUARDS"; + case CIRCUIT_PURPOSE_C_CIRCUIT_PADDING: + return "CIRCUIT_PADDING"; default: tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose); @@ -796,6 +855,7 @@ circuit_purpose_to_controller_hs_state_string(uint8_t purpose) case CIRCUIT_PURPOSE_CONTROLLER: case CIRCUIT_PURPOSE_PATH_BIAS_TESTING: case CIRCUIT_PURPOSE_HS_VANGUARDS: + case CIRCUIT_PURPOSE_C_CIRCUIT_PADDING: return NULL; case CIRCUIT_PURPOSE_INTRO_POINT: @@ -896,6 +956,9 @@ circuit_purpose_to_string(uint8_t purpose) case CIRCUIT_PURPOSE_HS_VANGUARDS: return "Hidden service: Pre-built vanguard circuit"; + case CIRCUIT_PURPOSE_C_CIRCUIT_PADDING: + return "Circuit kept open for padding"; + default: tor_snprintf(buf, sizeof(buf), "UNKNOWN_%d", (int)purpose); return buf; @@ -931,6 +994,7 @@ init_circuit_base(circuit_t *circ) circ->package_window = circuit_initial_package_window(); circ->deliver_window = CIRCWINDOW_START; + circuit_reset_sendme_randomness(circ); cell_queue_init(&circ->n_chan_cells); smartlist_add(circuit_get_global_list(), circ); @@ -1072,7 +1136,7 @@ circuit_free_(circuit_t *circ) * circuit is closed. This is to avoid any code path that free registered * circuits without closing them before. This needs to be done before the * hs identifier is freed. */ - hs_circ_cleanup(circ); + hs_circ_cleanup_on_free(circ); if (CIRCUIT_IS_ORIGIN(circ)) { origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); @@ -1092,7 +1156,7 @@ circuit_free_(circuit_t *circ) if (ocirc->build_state) { extend_info_free(ocirc->build_state->chosen_exit); - circuit_free_cpath_node(ocirc->build_state->pending_final_cpath); + cpath_free(ocirc->build_state->pending_final_cpath); cpath_ref_decref(ocirc->build_state->service_pending_final_cpath_ref); } tor_free(ocirc->build_state); @@ -1171,11 +1235,23 @@ circuit_free_(circuit_t *circ) * "active" checks will be violated. */ cell_queue_clear(&circ->n_chan_cells); + /* Cleanup possible SENDME state. */ + if (circ->sendme_last_digests) { + SMARTLIST_FOREACH(circ->sendme_last_digests, uint8_t *, d, tor_free(d)); + smartlist_free(circ->sendme_last_digests); + } + log_info(LD_CIRC, "Circuit %u (id: %" PRIu32 ") has been freed.", n_circ_id, CIRCUIT_IS_ORIGIN(circ) ? TO_ORIGIN_CIRCUIT(circ)->global_identifier : 0); + /* Free any circuit padding structures */ + circpad_circuit_free_all_machineinfos(circ); + + /* Clear all dangling handle references. */ + circuit_handles_clear(circ); + if (should_free) { memwipe(mem, 0xAA, memlen); /* poison memory */ tor_free(mem); @@ -1207,10 +1283,10 @@ circuit_clear_cpath(origin_circuit_t *circ) while (cpath->next && cpath->next != head) { victim = cpath; cpath = victim->next; - circuit_free_cpath_node(victim); + cpath_free(victim); } - circuit_free_cpath_node(cpath); + cpath_free(cpath); circ->cpath = NULL; } @@ -1267,29 +1343,13 @@ circuit_free_all(void) HT_CLEAR(chan_circid_map, &chan_circid_map); } -/** Deallocate space associated with the cpath node <b>victim</b>. */ -static void -circuit_free_cpath_node(crypt_path_t *victim) -{ - if (!victim) - return; - - relay_crypto_clear(&victim->crypto); - onion_handshake_state_release(&victim->handshake_state); - crypto_dh_free(victim->rend_dh_handshake_state); - extend_info_free(victim->extend_info); - - memwipe(victim, 0xBB, sizeof(crypt_path_t)); /* poison memory */ - tor_free(victim); -} - /** Release a crypt_path_reference_t*, which may be NULL. */ static void cpath_ref_decref(crypt_path_reference_t *cpath_ref) { if (cpath_ref != NULL) { if (--(cpath_ref->refcount) == 0) { - circuit_free_cpath_node(cpath_ref->cpath); + cpath_free(cpath_ref->cpath); tor_free(cpath_ref); } } @@ -2140,6 +2200,11 @@ circuit_mark_for_close_, (circuit_t *circ, int reason, int line, tor_assert(line); tor_assert(file); + /* Check whether the circuitpadding subsystem wants to block this close */ + if (circpad_marked_circuit_for_padding(circ, reason)) { + return; + } + if (circ->marked_for_close) { log_warn(LD_BUG, "Duplicate call to circuit_mark_for_close at %s:%d" @@ -2195,7 +2260,7 @@ circuit_mark_for_close_, (circuit_t *circ, int reason, int line, } /* Notify the HS subsystem that this circuit is closing. */ - hs_circ_cleanup(circ); + hs_circ_cleanup_on_close(circ); if (circuits_pending_close == NULL) circuits_pending_close = smartlist_new(); @@ -2270,50 +2335,13 @@ circuit_about_to_free(circuit_t *circ) smartlist_remove(circuits_pending_other_guards, circ); } if (CIRCUIT_IS_ORIGIN(circ)) { - control_event_circuit_status(TO_ORIGIN_CIRCUIT(circ), + circuit_event_status(TO_ORIGIN_CIRCUIT(circ), (circ->state == CIRCUIT_STATE_OPEN || circ->state == CIRCUIT_STATE_GUARD_WAIT) ? CIRC_EVENT_CLOSED:CIRC_EVENT_FAILED, orig_reason); } - if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) { - origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); - int timed_out = (reason == END_CIRC_REASON_TIMEOUT); - tor_assert(circ->state == CIRCUIT_STATE_OPEN); - tor_assert(ocirc->build_state->chosen_exit); - if (orig_reason != END_CIRC_REASON_IP_NOW_REDUNDANT && - ocirc->rend_data) { - /* treat this like getting a nack from it */ - log_info(LD_REND, "Failed intro circ %s to %s (awaiting ack). %s", - safe_str_client(rend_data_get_address(ocirc->rend_data)), - safe_str_client(build_state_get_exit_nickname(ocirc->build_state)), - timed_out ? "Recording timeout." : "Removing from descriptor."); - rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit, - ocirc->rend_data, - timed_out ? - INTRO_POINT_FAILURE_TIMEOUT : - INTRO_POINT_FAILURE_GENERIC); - } - } else if (circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCING && - reason != END_CIRC_REASON_TIMEOUT) { - origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ); - if (ocirc->build_state->chosen_exit && ocirc->rend_data) { - if (orig_reason != END_CIRC_REASON_IP_NOW_REDUNDANT && - ocirc->rend_data) { - log_info(LD_REND, "Failed intro circ %s to %s " - "(building circuit to intro point). " - "Marking intro point as possibly unreachable.", - safe_str_client(rend_data_get_address(ocirc->rend_data)), - safe_str_client(build_state_get_exit_nickname( - ocirc->build_state))); - rend_client_report_intro_point_failure(ocirc->build_state->chosen_exit, - ocirc->rend_data, - INTRO_POINT_FAILURE_UNREACHABLE); - } - } - } - if (circ->n_chan) { circuit_clear_cell_queue(circ, circ->n_chan); /* Only send destroy if the channel isn't closing anyway */ @@ -2374,13 +2402,9 @@ marked_circuit_free_cells(circuit_t *circ) return; } cell_queue_clear(&circ->n_chan_cells); - if (circ->n_mux) - circuitmux_clear_num_cells(circ->n_mux, circ); if (! CIRCUIT_IS_ORIGIN(circ)) { or_circuit_t *orcirc = TO_OR_CIRCUIT(circ); cell_queue_clear(&orcirc->p_chan_cells); - if (orcirc->p_mux) - circuitmux_clear_num_cells(orcirc->p_mux, circ); } } @@ -2724,59 +2748,6 @@ circuits_handle_oom(size_t current_allocation) n_dirconns_killed); } -/** Verify that cpath layer <b>cp</b> has all of its invariants - * correct. Trigger an assert if anything is invalid. - */ -void -assert_cpath_layer_ok(const crypt_path_t *cp) -{ -// tor_assert(cp->addr); /* these are zero for rendezvous extra-hops */ -// tor_assert(cp->port); - tor_assert(cp); - tor_assert(cp->magic == CRYPT_PATH_MAGIC); - switch (cp->state) - { - case CPATH_STATE_OPEN: - relay_crypto_assert_ok(&cp->crypto); - FALLTHROUGH; - case CPATH_STATE_CLOSED: - /*XXXX Assert that there's no handshake_state either. */ - tor_assert(!cp->rend_dh_handshake_state); - break; - case CPATH_STATE_AWAITING_KEYS: - /* tor_assert(cp->dh_handshake_state); */ - break; - default: - log_fn(LOG_ERR, LD_BUG, "Unexpected state %d", cp->state); - tor_assert(0); - } - tor_assert(cp->package_window >= 0); - tor_assert(cp->deliver_window >= 0); -} - -/** Verify that cpath <b>cp</b> has all of its invariants - * correct. Trigger an assert if anything is invalid. - */ -static void -assert_cpath_ok(const crypt_path_t *cp) -{ - const crypt_path_t *start = cp; - - do { - assert_cpath_layer_ok(cp); - /* layers must be in sequence of: "open* awaiting? closed*" */ - if (cp != start) { - if (cp->state == CPATH_STATE_AWAITING_KEYS) { - tor_assert(cp->prev->state == CPATH_STATE_OPEN); - } else if (cp->state == CPATH_STATE_OPEN) { - tor_assert(cp->prev->state == CPATH_STATE_OPEN); - } - } - cp = cp->next; - tor_assert(cp); - } while (cp != start); -} - /** Verify that circuit <b>c</b> has all of its invariants * correct. Trigger an assert if anything is invalid. */ @@ -2838,7 +2809,7 @@ assert_circuit_ok,(const circuit_t *c)) !smartlist_contains(circuits_pending_chans, c)); } if (origin_circ && origin_circ->cpath) { - assert_cpath_ok(origin_circ->cpath); + cpath_assert_ok(origin_circ->cpath); } if (c->purpose == CIRCUIT_PURPOSE_REND_ESTABLISHED) { tor_assert(or_circ); |