diff options
Diffstat (limited to 'src/core/or/circuitbuild.c')
-rw-r--r-- | src/core/or/circuitbuild.c | 501 |
1 files changed, 97 insertions, 404 deletions
diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c index 70b5d8215a..ec61b4a455 100644 --- a/src/core/or/circuitbuild.c +++ b/src/core/or/circuitbuild.c @@ -1,7 +1,7 @@ /* Copyright (c) 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 */ /** @@ -21,20 +21,19 @@ * cells arrive, the client will invoke circuit_send_next_onion_skin() to send * CREATE or RELAY_EXTEND cells. * - * On the server side, this module also handles the logic of responding to - * RELAY_EXTEND requests, using circuit_extend(). + * The server side is handled in feature/relay/circuitbuild_relay.c. **/ #define CIRCUITBUILD_PRIVATE +#define OCIRC_EVENT_PRIVATE #include "core/or/or.h" #include "app/config/config.h" -#include "app/config/confparse.h" +#include "lib/confmgt/confmgt.h" #include "core/crypto/hs_ntor.h" #include "core/crypto/onion_crypto.h" #include "core/crypto/onion_fast.h" #include "core/crypto/onion_tap.h" -#include "core/crypto/relay_crypto.h" #include "core/mainloop/connection.h" #include "core/mainloop/mainloop.h" #include "core/or/channel.h" @@ -42,17 +41,20 @@ #include "core/or/circuitlist.h" #include "core/or/circuitstats.h" #include "core/or/circuituse.h" +#include "core/or/circuitpadding.h" #include "core/or/command.h" #include "core/or/connection_edge.h" #include "core/or/connection_or.h" #include "core/or/onion.h" +#include "core/or/ocirc_event.h" #include "core/or/policies.h" #include "core/or/relay.h" +#include "core/or/crypt_path.h" #include "feature/client/bridges.h" #include "feature/client/circpathbias.h" #include "feature/client/entrynodes.h" #include "feature/client/transports.h" -#include "feature/control/control.h" +#include "feature/control/control_events.h" #include "feature/dircommon/directory.h" #include "feature/nodelist/describe.h" #include "feature/nodelist/microdesc.h" @@ -80,15 +82,6 @@ #include "feature/nodelist/routerinfo_st.h" #include "feature/nodelist/routerstatus_st.h" -static channel_t * channel_connect_for_circuit(const tor_addr_t *addr, - uint16_t port, - const char *id_digest, - const ed25519_public_key_t *ed_id); -static int circuit_deliver_create_cell(circuit_t *circ, - const create_cell_t *create_cell, - int relayed); -static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath); -STATIC int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice); static int circuit_send_first_onion_skin(origin_circuit_t *circ); static int circuit_build_no_more_hops(origin_circuit_t *circ); static int circuit_send_intermediate_onion_skin(origin_circuit_t *circ, @@ -102,10 +95,10 @@ static const node_t *choose_good_middle_server(uint8_t purpose, * and then calls command_setup_channel() to give it the right * callbacks. */ -static channel_t * -channel_connect_for_circuit(const tor_addr_t *addr, uint16_t port, - const char *id_digest, - const ed25519_public_key_t *ed_id) +MOCK_IMPL(channel_t *, +channel_connect_for_circuit,(const tor_addr_t *addr, uint16_t port, + const char *id_digest, + const struct ed25519_public_key_t *ed_id)) { channel_t *chan; @@ -492,7 +485,7 @@ circuit_establish_circuit(uint8_t purpose, extend_info_t *exit_ei, int flags) return NULL; } - control_event_circuit_status(circ, CIRC_EVENT_LAUNCHED, 0); + circuit_event_status(circ, CIRC_EVENT_LAUNCHED, 0); if ((err_reason = circuit_handle_first_hop(circ)) < 0) { circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason); @@ -508,6 +501,27 @@ origin_circuit_get_guard_state(origin_circuit_t *circ) return circ->guard_state; } +/** + * Helper function to publish a channel association message + * + * circuit_handle_first_hop() calls this to notify subscribers about a + * channel launch event, which associates a circuit with a channel. + * This doesn't always correspond to an assignment of the circuit's + * n_chan field, because that seems to be only for fully-open + * channels. + **/ +static void +circuit_chan_publish(const origin_circuit_t *circ, const channel_t *chan) +{ + ocirc_chan_msg_t *msg = tor_malloc(sizeof(*msg)); + + msg->gid = circ->global_identifier; + msg->chan = chan->global_identifier; + msg->onehop = circ->build_state->onehop_tunnel; + + ocirc_chan_publish(msg); +} + /** Start establishing the first hop of our circuit. Figure out what * OR we should connect to, and if necessary start the connection to * it. If we're already connected, then send the 'create' cell. @@ -522,7 +536,7 @@ circuit_handle_first_hop(origin_circuit_t *circ) int should_launch = 0; const or_options_t *options = get_options(); - firsthop = onion_next_hop_in_cpath(circ->cpath); + firsthop = cpath_get_next_non_open_hop(circ->cpath); tor_assert(firsthop); tor_assert(firsthop->extend_info); @@ -545,11 +559,17 @@ circuit_handle_first_hop(origin_circuit_t *circ) fmt_addrport(&firsthop->extend_info->addr, firsthop->extend_info->port)); - n_chan = channel_get_for_extend(firsthop->extend_info->identity_digest, - &firsthop->extend_info->ed_identity, - &firsthop->extend_info->addr, - &msg, - &should_launch); + /* We'll cleanup this code in #33220, when we add an IPv6 address to + * extend_info_t. */ + const bool addr_is_ipv4 = + (tor_addr_family(&firsthop->extend_info->addr) == AF_INET); + n_chan = channel_get_for_extend( + firsthop->extend_info->identity_digest, + &firsthop->extend_info->ed_identity, + addr_is_ipv4 ? &firsthop->extend_info->addr : NULL, + addr_is_ipv4 ? NULL : &firsthop->extend_info->addr, + &msg, + &should_launch); if (!n_chan) { /* not currently connected in a useful way. */ @@ -559,8 +579,6 @@ circuit_handle_first_hop(origin_circuit_t *circ) circ->base_.n_hop = extend_info_dup(firsthop->extend_info); if (should_launch) { - if (circ->build_state->onehop_tunnel) - control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DIR, 0); n_chan = channel_connect_for_circuit( &firsthop->extend_info->addr, firsthop->extend_info->port, @@ -570,6 +588,7 @@ circuit_handle_first_hop(origin_circuit_t *circ) log_info(LD_CIRC,"connect to firsthop failed. Closing."); return -END_CIRC_REASON_CONNECTFAILED; } + circuit_chan_publish(circ, n_chan); } log_debug(LD_CIRC,"connecting in progress (or finished). Good."); @@ -581,6 +600,7 @@ circuit_handle_first_hop(origin_circuit_t *circ) } else { /* it's already open. use it. */ tor_assert(!circ->base_.n_hop); circ->base_.n_chan = n_chan; + circuit_chan_publish(circ, n_chan); log_debug(LD_CIRC,"Conn open. Delivering first onion skin."); if ((err_reason = circuit_send_next_onion_skin(circ)) < 0) { log_info(LD_CIRC,"circuit_send_next_onion_skin failed."); @@ -700,9 +720,10 @@ circuit_n_chan_done(channel_t *chan, int status, int close_origin_circuits) * gave us via an EXTEND cell, so we shouldn't worry if we don't understand * it. Return -1 if we failed to find a suitable circid, else return 0. */ -static int -circuit_deliver_create_cell(circuit_t *circ, const create_cell_t *create_cell, - int relayed) +MOCK_IMPL(int, +circuit_deliver_create_cell,(circuit_t *circ, + const struct create_cell_t *create_cell, + int relayed)) { cell_t cell; circid_t id; @@ -762,40 +783,6 @@ circuit_deliver_create_cell(circuit_t *circ, const create_cell_t *create_cell, return -1; } -/** We've decided to start our reachability testing. If all - * is set, log this to the user. Return 1 if we did, or 0 if - * we chose not to log anything. */ -int -inform_testing_reachability(void) -{ - char dirbuf[128]; - char *address; - const routerinfo_t *me = router_get_my_routerinfo(); - if (!me) - return 0; - address = tor_dup_ip(me->addr); - control_event_server_status(LOG_NOTICE, - "CHECKING_REACHABILITY ORADDRESS=%s:%d", - address, me->or_port); - if (me->dir_port) { - tor_snprintf(dirbuf, sizeof(dirbuf), " and DirPort %s:%d", - address, me->dir_port); - control_event_server_status(LOG_NOTICE, - "CHECKING_REACHABILITY DIRADDRESS=%s:%d", - address, me->dir_port); - } - log_notice(LD_OR, "Now checking whether ORPort %s:%d%s %s reachable... " - "(this may take up to %d minutes -- look for log " - "messages indicating success)", - address, me->or_port, - me->dir_port ? dirbuf : "", - me->dir_port ? "are" : "is", - TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT/60); - - tor_free(address); - return 1; -} - /** Return true iff we should send a create_fast cell to start building a given * circuit */ static inline int @@ -941,15 +928,18 @@ circuit_send_next_onion_skin(origin_circuit_t *circ) tor_assert(circ->cpath->state == CPATH_STATE_OPEN); tor_assert(circ->base_.state == CIRCUIT_STATE_BUILDING); - crypt_path_t *hop = onion_next_hop_in_cpath(circ->cpath); + crypt_path_t *hop = cpath_get_next_non_open_hop(circ->cpath); circuit_build_times_handle_completed_hop(circ); + circpad_machine_event_circ_added_hop(circ); + if (hop) { /* Case two: we're on a hop after the first. */ return circuit_send_intermediate_onion_skin(circ, hop); } /* Case three: the circuit is finished. Do housekeeping tasks on it. */ + circpad_machine_event_circ_built(circ); return circuit_build_no_more_hops(circ); } @@ -1192,192 +1182,6 @@ circuit_note_clock_jumped(int64_t seconds_elapsed, bool was_idle) } } -/** Take the 'extend' <b>cell</b>, pull out addr/port plus the onion - * skin and identity digest for the next hop. If we're already connected, - * pass the onion skin to the next hop using a create cell; otherwise - * launch a new OR connection, and <b>circ</b> will notice when the - * connection succeeds or fails. - * - * Return -1 if we want to warn and tear down the circuit, else return 0. - */ -int -circuit_extend(cell_t *cell, circuit_t *circ) -{ - channel_t *n_chan; - relay_header_t rh; - extend_cell_t ec; - const char *msg = NULL; - int should_launch = 0; - - if (circ->n_chan) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "n_chan already set. Bug/attack. Closing."); - return -1; - } - if (circ->n_hop) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "conn to next hop already launched. Bug/attack. Closing."); - return -1; - } - - if (!server_mode(get_options())) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Got an extend cell, but running as a client. Closing."); - return -1; - } - - relay_header_unpack(&rh, cell->payload); - - if (extend_cell_parse(&ec, rh.command, - cell->payload+RELAY_HEADER_SIZE, - rh.length) < 0) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Can't parse extend cell. Closing circuit."); - return -1; - } - - if (!ec.orport_ipv4.port || tor_addr_is_null(&ec.orport_ipv4.addr)) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Client asked me to extend to zero destination port or addr."); - return -1; - } - - if (tor_addr_is_internal(&ec.orport_ipv4.addr, 0) && - !get_options()->ExtendAllowPrivateAddresses) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Client asked me to extend to a private address"); - return -1; - } - - /* Check if they asked us for 0000..0000. We support using - * an empty fingerprint for the first hop (e.g. for a bridge relay), - * but we don't want to let clients send us extend cells for empty - * fingerprints -- a) because it opens the user up to a mitm attack, - * and b) because it lets an attacker force the relay to hold open a - * new TLS connection for each extend request. */ - if (tor_digest_is_zero((const char*)ec.node_id)) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Client asked me to extend without specifying an id_digest."); - return -1; - } - - /* Fill in ed_pubkey if it was not provided and we can infer it from - * our networkstatus */ - if (ed25519_public_key_is_zero(&ec.ed_pubkey)) { - const node_t *node = node_get_by_id((const char*)ec.node_id); - const ed25519_public_key_t *node_ed_id = NULL; - if (node && - node_supports_ed25519_link_authentication(node, 1) && - (node_ed_id = node_get_ed25519_id(node))) { - ed25519_pubkey_copy(&ec.ed_pubkey, node_ed_id); - } - } - - /* Next, check if we're being asked to connect to the hop that the - * extend cell came from. There isn't any reason for that, and it can - * assist circular-path attacks. */ - if (tor_memeq(ec.node_id, - TO_OR_CIRCUIT(circ)->p_chan->identity_digest, - DIGEST_LEN)) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Client asked me to extend back to the previous hop."); - return -1; - } - - /* Check the previous hop Ed25519 ID too */ - if (! ed25519_public_key_is_zero(&ec.ed_pubkey) && - ed25519_pubkey_eq(&ec.ed_pubkey, - &TO_OR_CIRCUIT(circ)->p_chan->ed25519_identity)) { - log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, - "Client asked me to extend back to the previous hop " - "(by Ed25519 ID)."); - return -1; - } - - n_chan = channel_get_for_extend((const char*)ec.node_id, - &ec.ed_pubkey, - &ec.orport_ipv4.addr, - &msg, - &should_launch); - - if (!n_chan) { - log_debug(LD_CIRC|LD_OR,"Next router (%s): %s", - fmt_addrport(&ec.orport_ipv4.addr,ec.orport_ipv4.port), - msg?msg:"????"); - - circ->n_hop = extend_info_new(NULL /*nickname*/, - (const char*)ec.node_id, - &ec.ed_pubkey, - NULL, /*onion_key*/ - NULL, /*curve25519_key*/ - &ec.orport_ipv4.addr, - ec.orport_ipv4.port); - - circ->n_chan_create_cell = tor_memdup(&ec.create_cell, - sizeof(ec.create_cell)); - - circuit_set_state(circ, CIRCUIT_STATE_CHAN_WAIT); - - if (should_launch) { - /* we should try to open a connection */ - n_chan = channel_connect_for_circuit(&ec.orport_ipv4.addr, - ec.orport_ipv4.port, - (const char*)ec.node_id, - &ec.ed_pubkey); - if (!n_chan) { - log_info(LD_CIRC,"Launching n_chan failed. Closing circuit."); - circuit_mark_for_close(circ, END_CIRC_REASON_CONNECTFAILED); - return 0; - } - log_debug(LD_CIRC,"connecting in progress (or finished). Good."); - } - /* return success. The onion/circuit/etc will be taken care of - * automatically (may already have been) whenever n_chan reaches - * OR_CONN_STATE_OPEN. - */ - return 0; - } - - tor_assert(!circ->n_hop); /* Connection is already established. */ - circ->n_chan = n_chan; - log_debug(LD_CIRC, - "n_chan is %s", - channel_get_canonical_remote_descr(n_chan)); - - if (circuit_deliver_create_cell(circ, &ec.create_cell, 1) < 0) - return -1; - - return 0; -} - -/** Initialize cpath-\>{f|b}_{crypto|digest} from the key material in key_data. - * - * If <b>is_hs_v3</b> is set, this cpath will be used for next gen hidden - * service circuits and <b>key_data</b> must be at least - * HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN bytes in length. - * - * If <b>is_hs_v3</b> is not set, key_data must contain CPATH_KEY_MATERIAL_LEN - * bytes, which are used as follows: - * - 20 to initialize f_digest - * - 20 to initialize b_digest - * - 16 to key f_crypto - * - 16 to key b_crypto - * - * (If 'reverse' is true, then f_XX and b_XX are swapped.) - * - * Return 0 if init was successful, else -1 if it failed. - */ -int -circuit_init_cpath_crypto(crypt_path_t *cpath, - const char *key_data, size_t key_data_len, - int reverse, int is_hs_v3) -{ - - tor_assert(cpath); - return relay_crypto_init(&cpath->crypto, key_data, key_data_len, reverse, - is_hs_v3); -} - /** A "created" cell <b>reply</b> came back to us on circuit <b>circ</b>. * (The body of <b>reply</b> varies depending on what sort of handshake * this is.) @@ -1403,7 +1207,7 @@ circuit_finish_handshake(origin_circuit_t *circ, if (circ->cpath->state == CPATH_STATE_AWAITING_KEYS) { hop = circ->cpath; } else { - hop = onion_next_hop_in_cpath(circ->cpath); + hop = cpath_get_next_non_open_hop(circ->cpath); if (!hop) { /* got an extended when we're all done? */ log_warn(LD_PROTOCOL,"got extended when circ already built? Closing."); return - END_CIRC_REASON_TORPROTOCOL; @@ -1427,14 +1231,14 @@ circuit_finish_handshake(origin_circuit_t *circ, onion_handshake_state_release(&hop->handshake_state); - if (circuit_init_cpath_crypto(hop, keys, sizeof(keys), 0, 0)<0) { + if (cpath_init_circuit_crypto(hop, keys, sizeof(keys), 0, 0)<0) { return -END_CIRC_REASON_TORPROTOCOL; } hop->state = CPATH_STATE_OPEN; log_info(LD_CIRC,"Finished building circuit hop:"); circuit_log_path(LOG_INFO,LD_CIRC,circ); - control_event_circuit_status(circ, CIRC_EVENT_EXTENDED, 0); + circuit_event_status(circ, CIRC_EVENT_EXTENDED, 0); return 0; } @@ -1479,7 +1283,7 @@ circuit_truncated(origin_circuit_t *circ, int reason) } layer->next = victim->next; - circuit_free_cpath_node(victim); + cpath_free(victim); } log_info(LD_CIRC, "finished"); @@ -1487,61 +1291,6 @@ circuit_truncated(origin_circuit_t *circ, int reason) #endif /* 0 */ } -/** Given a response payload and keys, initialize, then send a created - * cell back. - */ -int -onionskin_answer(or_circuit_t *circ, - const created_cell_t *created_cell, - const char *keys, size_t keys_len, - const uint8_t *rend_circ_nonce) -{ - cell_t cell; - - tor_assert(keys_len == CPATH_KEY_MATERIAL_LEN); - - if (created_cell_format(&cell, created_cell) < 0) { - log_warn(LD_BUG,"couldn't format created cell (type=%d, len=%d)", - (int)created_cell->cell_type, (int)created_cell->handshake_len); - return -1; - } - cell.circ_id = circ->p_circ_id; - - circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_OPEN); - - log_debug(LD_CIRC,"init digest forward 0x%.8x, backward 0x%.8x.", - (unsigned int)get_uint32(keys), - (unsigned int)get_uint32(keys+20)); - if (relay_crypto_init(&circ->crypto, keys, keys_len, 0, 0)<0) { - log_warn(LD_BUG,"Circuit initialization failed"); - return -1; - } - - memcpy(circ->rend_circ_nonce, rend_circ_nonce, DIGEST_LEN); - - int used_create_fast = (created_cell->cell_type == CELL_CREATED_FAST); - - append_cell_to_circuit_queue(TO_CIRCUIT(circ), - circ->p_chan, &cell, CELL_DIRECTION_IN, 0); - log_debug(LD_CIRC,"Finished sending '%s' cell.", - used_create_fast ? "created_fast" : "created"); - - /* Ignore the local bit when ExtendAllowPrivateAddresses is set: - * it violates the assumption that private addresses are local. - * Also, many test networks run on local addresses, and - * TestingTorNetwork sets ExtendAllowPrivateAddresses. */ - if ((!channel_is_local(circ->p_chan) - || get_options()->ExtendAllowPrivateAddresses) - && !channel_is_outgoing(circ->p_chan)) { - /* record that we could process create cells from a non-local conn - * that we didn't initiate; presumably this means that create cells - * can reach us too. */ - router_orport_found_reachable(); - } - - return 0; -} - /** Helper for new_route_len(). Choose a circuit length for purpose * <b>purpose</b>: DEFAULT_ROUTE_LEN (+ 1 if someone else chose the * exit). If someone else chose the exit, they could be colluding @@ -1673,24 +1422,28 @@ route_len_for_purpose(uint8_t purpose, extend_info_t *exit_ei) * to handle the desired path length, return -1. */ STATIC int -new_route_len(uint8_t purpose, extend_info_t *exit_ei, smartlist_t *nodes) +new_route_len(uint8_t purpose, extend_info_t *exit_ei, + const smartlist_t *nodes) { - int num_acceptable_routers; int routelen; tor_assert(nodes); routelen = route_len_for_purpose(purpose, exit_ei); - num_acceptable_routers = count_acceptable_nodes(nodes); + int num_acceptable_direct = count_acceptable_nodes(nodes, 1); + int num_acceptable_indirect = count_acceptable_nodes(nodes, 0); - log_debug(LD_CIRC,"Chosen route length %d (%d/%d routers suitable).", - routelen, num_acceptable_routers, smartlist_len(nodes)); + log_debug(LD_CIRC,"Chosen route length %d (%d direct and %d indirect " + "routers suitable).", routelen, num_acceptable_direct, + num_acceptable_indirect); - if (num_acceptable_routers < routelen) { + if (num_acceptable_direct < 1 || num_acceptable_indirect < routelen - 1) { log_info(LD_CIRC, - "Not enough acceptable routers (%d/%d). Discarding this circuit.", - num_acceptable_routers, routelen); + "Not enough acceptable routers (%d/%d direct and %d/%d " + "indirect routers suitable). Discarding this circuit.", + num_acceptable_direct, routelen, + num_acceptable_indirect, routelen); return -1; } @@ -2294,7 +2047,7 @@ circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *exit_ei) state->chosen_exit = extend_info_dup(exit_ei); ++circ->build_state->desired_path_len; - onion_append_hop(&circ->cpath, exit_ei); + cpath_append_hop(&circ->cpath, exit_ei); return 0; } @@ -2332,7 +2085,7 @@ circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *exit_ei) * particular router. See bug #25885.) */ MOCK_IMPL(STATIC int, -count_acceptable_nodes, (smartlist_t *nodes)) +count_acceptable_nodes, (const smartlist_t *nodes, int direct)) { int num=0; @@ -2346,7 +2099,7 @@ count_acceptable_nodes, (smartlist_t *nodes)) if (! node->is_valid) // log_debug(LD_CIRC,"Nope, the directory says %d is not valid.",i); continue; - if (! node_has_any_descriptor(node)) + if (! node_has_preferred_descriptor(node, direct)) continue; /* The node has a descriptor, so we can just check the ntor key directly */ if (!node_has_curve25519_onion_key(node)) @@ -2359,47 +2112,6 @@ count_acceptable_nodes, (smartlist_t *nodes)) return num; } -/** Add <b>new_hop</b> to the end of the doubly-linked-list <b>head_ptr</b>. - * This function is used to extend cpath by another hop. - */ -void -onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop) -{ - if (*head_ptr) { - new_hop->next = (*head_ptr); - new_hop->prev = (*head_ptr)->prev; - (*head_ptr)->prev->next = new_hop; - (*head_ptr)->prev = new_hop; - } else { - *head_ptr = new_hop; - new_hop->prev = new_hop->next = new_hop; - } -} - -#ifdef TOR_UNIT_TESTS - -/** Unittest helper function: Count number of hops in cpath linked list. */ -unsigned int -cpath_get_n_hops(crypt_path_t **head_ptr) -{ - unsigned int n_hops = 0; - crypt_path_t *tmp; - - if (!*head_ptr) { - return 0; - } - - tmp = *head_ptr; - do { - n_hops++; - tmp = tmp->next; - } while (tmp != *head_ptr); - - return n_hops; -} - -#endif /* defined(TOR_UNIT_TESTS) */ - /** * Build the exclude list for vanguard circuits. * @@ -2597,7 +2309,24 @@ choose_good_middle_server(uint8_t purpose, return choice; } - choice = router_choose_random_node(excluded, options->ExcludeNodes, flags); + if (options->MiddleNodes) { + smartlist_t *sl = smartlist_new(); + routerset_get_all_nodes(sl, options->MiddleNodes, + options->ExcludeNodes, 1); + + smartlist_subtract(sl, excluded); + + choice = node_sl_choose_by_bandwidth(sl, WEIGHT_FOR_MID); + smartlist_free(sl); + if (choice) { + log_fn(LOG_INFO, LD_CIRC, "Chose fixed middle node: %s", + hex_str(choice->identity, DIGEST_LEN)); + } else { + log_fn(LOG_NOTICE, LD_CIRC, "Restricted middle not available"); + } + } else { + choice = router_choose_random_node(excluded, options->ExcludeNodes, flags); + } smartlist_free(excluded); return choice; } @@ -2657,20 +2386,6 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state, return choice; } -/** Return the first non-open hop in cpath, or return NULL if all - * hops are open. */ -static crypt_path_t * -onion_next_hop_in_cpath(crypt_path_t *cpath) -{ - crypt_path_t *hop = cpath; - do { - if (hop->state != CPATH_STATE_OPEN) - return hop; - hop = hop->next; - } while (hop != cpath); - return NULL; -} - /** Choose a suitable next hop for the circuit <b>circ</b>. * Append the hop info to circ->cpath. * @@ -2727,33 +2442,11 @@ onion_extend_cpath(origin_circuit_t *circ) extend_info_describe(info), cur_len+1, build_state_get_exit_nickname(state)); - onion_append_hop(&circ->cpath, info); + cpath_append_hop(&circ->cpath, info); extend_info_free(info); return 0; } -/** Create a new hop, annotate it with information about its - * corresponding router <b>choice</b>, and append it to the - * end of the cpath <b>head_ptr</b>. */ -STATIC int -onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice) -{ - crypt_path_t *hop = tor_malloc_zero(sizeof(crypt_path_t)); - - /* link hop into the cpath, at the end. */ - onion_append_to_cpath(head_ptr, hop); - - hop->magic = CRYPT_PATH_MAGIC; - hop->state = CPATH_STATE_CLOSED; - - hop->extend_info = extend_info_dup(choice); - - hop->package_window = circuit_initial_package_window(); - hop->deliver_window = CIRCWINDOW_START; - - return 0; -} - /** Allocate a new extend_info object based on the various arguments. */ extend_info_t * extend_info_new(const char *nickname, @@ -2895,8 +2588,8 @@ extend_info_dup(extend_info_t *info) * If there is no chosen exit, or if we don't know the node_t for * the chosen exit, return NULL. */ -const node_t * -build_state_get_exit_node(cpath_build_state_t *state) +MOCK_IMPL(const node_t *, +build_state_get_exit_node,(cpath_build_state_t *state)) { if (!state || !state->chosen_exit) return NULL; @@ -2958,7 +2651,7 @@ extend_info_supports_ntor(const extend_info_t* ei) { tor_assert(ei); /* Valid ntor keys have at least one non-zero byte */ - return !tor_mem_is_zero( + return !fast_mem_is_zero( (const char*)ei->curve25519_onion_key.public_key, CURVE25519_PUBKEY_LEN); } |