summaryrefslogtreecommitdiff
path: root/src/core/or/circuitbuild.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/or/circuitbuild.c')
-rw-r--r--src/core/or/circuitbuild.c983
1 files changed, 264 insertions, 719 deletions
diff --git a/src/core/or/circuitbuild.c b/src/core/or/circuitbuild.c
index 70b5d8215a..78501c0aa2 100644
--- a/src/core/or/circuitbuild.c
+++ b/src/core/or/circuitbuild.c
@@ -1,13 +1,13 @@
/* 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 */
/**
* \file circuitbuild.c
*
- * \brief Implements the details of building circuits (by chosing paths,
+ * \brief Implements the details of building circuits (by choosing paths,
* constructing/sending create/extend cells, and so on).
*
* On the client side, this module handles launching circuits. Circuit
@@ -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,22 @@
#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/extendinfo.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/trace_probes_circuit.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"
@@ -68,6 +72,7 @@
#include "feature/rend/rendcommon.h"
#include "feature/stats/predict_ports.h"
#include "lib/crypt_ops/crypto_rand.h"
+#include "lib/trace/events.h"
#include "core/or/cell_st.h"
#include "core/or/cpath_build_state_st.h"
@@ -76,19 +81,7 @@
#include "feature/nodelist/node_st.h"
#include "core/or/or_circuit_st.h"
#include "core/or/origin_circuit_st.h"
-#include "feature/nodelist/microdesc_st.h"
-#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,14 +95,18 @@ 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 extend_info_t *ei))
{
channel_t *chan;
- chan = channel_connect(addr, port, id_digest, ed_id);
+ const tor_addr_port_t *orport = extend_info_pick_orport(ei);
+ if (!orport)
+ return NULL;
+ const char *id_digest = ei->identity_digest;
+ const ed25519_public_key_t *ed_id = &ei->ed_identity;
+
+ chan = channel_connect(&orport->addr, orport->port, id_digest, ed_id);
if (chan) command_setup_channel(chan);
return chan;
@@ -446,7 +443,8 @@ onion_populate_cpath(origin_circuit_t *circ)
/** Create and return a new origin circuit. Initialize its purpose and
* build-state based on our arguments. The <b>flags</b> argument is a
- * bitfield of CIRCLAUNCH_* flags. */
+ * bitfield of CIRCLAUNCH_* flags, see circuit_launch_by_extend_info() for
+ * more details. */
origin_circuit_t *
origin_circuit_init(uint8_t purpose, int flags)
{
@@ -462,13 +460,16 @@ origin_circuit_init(uint8_t purpose, int flags)
((flags & CIRCLAUNCH_NEED_CAPACITY) ? 1 : 0);
circ->build_state->is_internal =
((flags & CIRCLAUNCH_IS_INTERNAL) ? 1 : 0);
+ circ->build_state->is_ipv6_selftest =
+ ((flags & CIRCLAUNCH_IS_IPV6_SELFTEST) ? 1 : 0);
circ->base_.purpose = purpose;
return circ;
}
-/** Build a new circuit for <b>purpose</b>. If <b>exit</b>
- * is defined, then use that as your exit router, else choose a suitable
- * exit node.
+/** Build a new circuit for <b>purpose</b>. If <b>exit</b> is defined, then use
+ * that as your exit router, else choose a suitable exit node. The <b>flags</b>
+ * argument is a bitfield of CIRCLAUNCH_* flags, see
+ * circuit_launch_by_extend_info() for more details.
*
* Also launch a connection to the first OR in the chosen path, if
* it's not open already.
@@ -492,12 +493,14 @@ 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);
return NULL;
}
+
+ tor_trace(TR_SUBSYS(circuit), TR_EV(establish), circ);
return circ;
}
@@ -508,6 +511,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 +546,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);
@@ -532,7 +556,7 @@ circuit_handle_first_hop(origin_circuit_t *circ)
* - the address is internal, and
* - we're not connecting to a configured bridge, and
* - we're not configured to allow extends to private addresses. */
- if (tor_addr_is_internal(&firsthop->extend_info->addr, 0) &&
+ if (extend_info_any_orport_addr_is_internal(firsthop->extend_info) &&
!extend_info_is_a_configured_bridge(firsthop->extend_info) &&
!options->ExtendAllowPrivateAddresses) {
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
@@ -541,15 +565,18 @@ circuit_handle_first_hop(origin_circuit_t *circ)
}
/* now see if we're already connected to the first OR in 'route' */
- log_debug(LD_CIRC,"Looking for firsthop '%s'",
- 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);
+ const tor_addr_port_t *orport4 =
+ extend_info_get_orport(firsthop->extend_info, AF_INET);
+ const tor_addr_port_t *orport6 =
+ extend_info_get_orport(firsthop->extend_info, AF_INET6);
+ n_chan = channel_get_for_extend(
+ firsthop->extend_info->identity_digest,
+ &firsthop->extend_info->ed_identity,
+ orport4 ? &orport4->addr : NULL,
+ orport6 ? &orport6->addr : NULL,
+ true,
+ &msg,
+ &should_launch);
if (!n_chan) {
/* not currently connected in a useful way. */
@@ -559,17 +586,17 @@ 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,
- firsthop->extend_info->identity_digest,
- &firsthop->extend_info->ed_identity);
+ n_chan = channel_connect_for_circuit(firsthop->extend_info);
if (!n_chan) { /* connect failed, forget the whole thing */
log_info(LD_CIRC,"connect to firsthop failed. Closing.");
return -END_CIRC_REASON_CONNECTFAILED;
}
+ /* We didn't find a channel, but we're launching one for an origin
+ * circuit. (If we decided not to launch a channel, then we found at
+ * least one once good in-progress channel use for this circuit, and
+ * marked it in channel_get_for_extend().) */
+ channel_mark_as_used_for_origin_circuit(n_chan);
+ circuit_chan_publish(circ, n_chan);
}
log_debug(LD_CIRC,"connecting in progress (or finished). Good.");
@@ -581,7 +608,11 @@ 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;
- log_debug(LD_CIRC,"Conn open. Delivering first onion skin.");
+ /* We found a channel, and we're using it for an origin circuit. */
+ channel_mark_as_used_for_origin_circuit(n_chan);
+ circuit_chan_publish(circ, n_chan);
+ log_debug(LD_CIRC,"Conn open for %s. Delivering first onion skin.",
+ safe_str_client(extend_info_describe(firsthop->extend_info)));
if ((err_reason = circuit_send_next_onion_skin(circ)) < 0) {
log_info(LD_CIRC,"circuit_send_next_onion_skin failed.");
circ->base_.n_chan = NULL;
@@ -609,7 +640,7 @@ circuit_n_chan_done(channel_t *chan, int status, int close_origin_circuits)
tor_assert(chan);
log_debug(LD_CIRC,"chan to %s, status=%d",
- channel_get_canonical_remote_descr(chan), status);
+ channel_describe_peer(chan), status);
pending_circs = smartlist_new();
circuit_get_all_pending_on_channel(pending_circs, chan);
@@ -700,9 +731,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,61 +794,15 @@ 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
+/** Return true iff we should send a create_fast cell to start building a
+ * given circuit */
+static inline bool
should_use_create_fast_for_circuit(origin_circuit_t *circ)
{
- const or_options_t *options = get_options();
tor_assert(circ->cpath);
tor_assert(circ->cpath->extend_info);
- if (!circuit_has_usable_onion_key(circ)) {
- /* We don't have ntor, and we don't have or can't use TAP,
- * so our hand is forced: only a create_fast will work. */
- return 1;
- }
- if (public_server_mode(options)) {
- /* We're a server, and we have a usable onion key. We can choose.
- * Prefer to blend our circuit into the other circuits we are
- * creating on behalf of others. */
- return 0;
- }
- return networkstatus_get_param(NULL, "usecreatefast", 0, 0, 1);
+ return ! circuit_has_usable_onion_key(circ);
}
/**
@@ -895,14 +881,22 @@ circuit_pick_extend_handshake(uint8_t *cell_type_out,
}
/**
- * Return true iff <b>purpose</b> is a purpose for a circuit which is
- * allowed to have no guard configured, even if the circuit is multihop
+ * Return true iff <b>circ</b> is allowed
+ * to have no guard configured, even if the circuit is multihop
* and guards are enabled.
*/
static int
-circuit_purpose_may_omit_guard(int purpose)
+circuit_may_omit_guard(const origin_circuit_t *circ)
{
- switch (purpose) {
+ if (BUG(!circ))
+ return 0;
+
+ if (circ->first_hop_from_controller) {
+ /* The controller picked the first hop: that bypasses the guard system. */
+ return 1;
+ }
+
+ switch (circ->base_.purpose) {
case CIRCUIT_PURPOSE_TESTING:
case CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT:
/* Testing circuits may omit guards because they're measuring
@@ -941,15 +935,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);
}
@@ -1008,6 +1005,7 @@ circuit_send_first_onion_skin(origin_circuit_t *circ)
if (circuit_deliver_create_cell(TO_CIRCUIT(circ), &cc, 0) < 0)
return - END_CIRC_REASON_RESOURCELIMIT;
+ tor_trace(TR_SUBSYS(circuit), TR_EV(first_onion_skin), circ, circ->cpath);
circ->cpath->state = CPATH_STATE_AWAITING_KEYS;
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_BUILDING);
@@ -1029,7 +1027,7 @@ circuit_build_no_more_hops(origin_circuit_t *circ)
guard_usable_t r;
if (! circ->guard_state) {
if (circuit_get_cpath_len(circ) != 1 &&
- ! circuit_purpose_may_omit_guard(circ->base_.purpose) &&
+ ! circuit_may_omit_guard(circ) &&
get_options()->UseEntryGuards) {
log_warn(LD_BUG, "%d-hop circuit %p with purpose %d has no "
"guard state",
@@ -1078,8 +1076,8 @@ circuit_build_no_more_hops(origin_circuit_t *circ)
control_event_bootstrap(BOOTSTRAP_STATUS_DONE, 0);
control_event_client_status(LOG_NOTICE, "CIRCUIT_ESTABLISHED");
clear_broken_connection_map(1);
- if (server_mode(options) && !check_whether_orport_reachable(options)) {
- inform_testing_reachability();
+ if (server_mode(options) &&
+ !router_all_orports_seem_reachable(options)) {
router_do_reachability_checks(1, 1);
}
}
@@ -1103,23 +1101,40 @@ circuit_send_intermediate_onion_skin(origin_circuit_t *circ,
{
int len;
extend_cell_t ec;
+ /* Relays and bridges can send IPv6 extends. But for clients, it's an
+ * obvious version distinguisher. */
+ const bool include_ipv6 = server_mode(get_options());
memset(&ec, 0, sizeof(ec));
+ tor_addr_make_unspec(&ec.orport_ipv4.addr);
+ tor_addr_make_unspec(&ec.orport_ipv6.addr);
log_debug(LD_CIRC,"starting to send subsequent skin.");
- if (tor_addr_family(&hop->extend_info->addr) != AF_INET) {
- log_warn(LD_BUG, "Trying to extend to a non-IPv4 address.");
- return - END_CIRC_REASON_INTERNAL;
- }
-
circuit_pick_extend_handshake(&ec.cell_type,
&ec.create_cell.cell_type,
&ec.create_cell.handshake_type,
hop->extend_info);
- tor_addr_copy(&ec.orport_ipv4.addr, &hop->extend_info->addr);
- ec.orport_ipv4.port = hop->extend_info->port;
- tor_addr_make_unspec(&ec.orport_ipv6.addr);
+ const tor_addr_port_t *orport4 =
+ extend_info_get_orport(hop->extend_info, AF_INET);
+ const tor_addr_port_t *orport6 =
+ extend_info_get_orport(hop->extend_info, AF_INET6);
+ int n_addrs_set = 0;
+ if (orport4) {
+ tor_addr_copy(&ec.orport_ipv4.addr, &orport4->addr);
+ ec.orport_ipv4.port = orport4->port;
+ ++n_addrs_set;
+ }
+ if (orport6 && include_ipv6) {
+ tor_addr_copy(&ec.orport_ipv6.addr, &orport6->addr);
+ ec.orport_ipv6.port = orport6->port;
+ ++n_addrs_set;
+ }
+
+ if (n_addrs_set == 0) {
+ log_warn(LD_BUG, "No supported address family found in extend_info.");
+ return - END_CIRC_REASON_INTERNAL;
+ }
memcpy(ec.node_id, hop->extend_info->identity_digest, DIGEST_LEN);
/* Set the ED25519 identity too -- it will only get included
* in the extend2 cell if we're configured to use it, though. */
@@ -1154,6 +1169,7 @@ circuit_send_intermediate_onion_skin(origin_circuit_t *circ,
return 0; /* circuit is closed */
}
hop->state = CPATH_STATE_AWAITING_KEYS;
+ tor_trace(TR_SUBSYS(circuit), TR_EV(intermediate_onion_skin), circ, hop);
return 0;
}
@@ -1192,192 +1208,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 +1233,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 +1257,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 +1309,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 +1317,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 +1448,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;
}
@@ -1804,7 +1583,23 @@ choose_good_exit_server_general(router_crn_flags_t flags)
const node_t *selected_node=NULL;
const int need_uptime = (flags & CRN_NEED_UPTIME) != 0;
const int need_capacity = (flags & CRN_NEED_CAPACITY) != 0;
- const int direct_conn = (flags & CRN_DIRECT_CONN) != 0;
+
+ /* We should not require guard flags on exits. */
+ IF_BUG_ONCE(flags & CRN_NEED_GUARD)
+ return NULL;
+
+ /* We reject single-hop exits for all node positions. */
+ IF_BUG_ONCE(flags & CRN_DIRECT_CONN)
+ return NULL;
+
+ /* This isn't the function for picking rendezvous nodes. */
+ IF_BUG_ONCE(flags & CRN_RENDEZVOUS_V3)
+ return NULL;
+
+ /* We only want exits to extend if we cannibalize the circuit.
+ * But we don't require IPv6 extends yet. */
+ IF_BUG_ONCE(flags & CRN_INITIATE_IPV6_EXTEND)
+ return NULL;
connections = get_connection_array();
@@ -1837,19 +1632,14 @@ choose_good_exit_server_general(router_crn_flags_t flags)
*/
continue;
}
- if (!node_has_preferred_descriptor(node, direct_conn)) {
+ if (!router_can_choose_node(node, flags)) {
n_supported[i] = -1;
continue;
}
- if (!node->is_running || node->is_bad_exit) {
+ if (node->is_bad_exit) {
n_supported[i] = -1;
continue; /* skip routers that are known to be down or bad exits */
}
- if (node_get_purpose(node) != ROUTER_PURPOSE_GENERAL) {
- /* never pick a non-general node as a random exit. */
- n_supported[i] = -1;
- continue;
- }
if (routerset_contains_node(options->ExcludeExitNodesUnion_, node)) {
n_supported[i] = -1;
continue; /* user asked us not to use it, no matter what */
@@ -1859,27 +1649,6 @@ choose_good_exit_server_general(router_crn_flags_t flags)
n_supported[i] = -1;
continue; /* not one of our chosen exit nodes */
}
-
- if (node_is_unreliable(node, need_uptime, need_capacity, 0)) {
- n_supported[i] = -1;
- continue; /* skip routers that are not suitable. Don't worry if
- * this makes us reject all the possible routers: if so,
- * we'll retry later in this function with need_update and
- * need_capacity set to 0. */
- }
- if (!(node->is_valid)) {
- /* if it's invalid and we don't want it */
- n_supported[i] = -1;
-// log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- invalid router.",
-// router->nickname, i);
- continue; /* skip invalid routers */
- }
- /* We do not allow relays that allow single hop exits by default. Option
- * was deprecated in 0.2.9.2-alpha and removed in 0.3.1.0-alpha. */
- if (node_allows_single_hop_exits(node)) {
- n_supported[i] = -1;
- continue;
- }
if (node_exit_policy_rejects_all(node)) {
n_supported[i] = -1;
// log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- it rejects all.",
@@ -2030,35 +1799,29 @@ pick_restricted_middle_node(router_crn_flags_t flags,
{
const node_t *middle_node = NULL;
- smartlist_t *whitelisted_live_middles = smartlist_new();
+ smartlist_t *allowlisted_live_middles = smartlist_new();
smartlist_t *all_live_nodes = smartlist_new();
tor_assert(pick_from);
/* Add all running nodes to all_live_nodes */
- router_add_running_nodes_to_smartlist(all_live_nodes,
- (flags & CRN_NEED_UPTIME) != 0,
- (flags & CRN_NEED_CAPACITY) != 0,
- (flags & CRN_NEED_GUARD) != 0,
- (flags & CRN_NEED_DESC) != 0,
- (flags & CRN_PREF_ADDR) != 0,
- (flags & CRN_DIRECT_CONN) != 0);
-
- /* Filter all_live_nodes to only add live *and* whitelisted middles
- * to the list whitelisted_live_middles. */
+ router_add_running_nodes_to_smartlist(all_live_nodes, flags);
+
+ /* Filter all_live_nodes to only add live *and* allowlisted middles
+ * to the list allowlisted_live_middles. */
SMARTLIST_FOREACH_BEGIN(all_live_nodes, node_t *, live_node) {
if (routerset_contains_node(pick_from, live_node)) {
- smartlist_add(whitelisted_live_middles, live_node);
+ smartlist_add(allowlisted_live_middles, live_node);
}
} SMARTLIST_FOREACH_END(live_node);
/* Honor ExcludeNodes */
if (exclude_set) {
- routerset_subtract_nodes(whitelisted_live_middles, exclude_set);
+ routerset_subtract_nodes(allowlisted_live_middles, exclude_set);
}
if (exclude_list) {
- smartlist_subtract(whitelisted_live_middles, exclude_list);
+ smartlist_subtract(allowlisted_live_middles, exclude_list);
}
/**
@@ -2074,9 +1837,9 @@ pick_restricted_middle_node(router_crn_flags_t flags,
* If there are a lot of nodes in here, assume they did not load balance
* and do it for them, but also warn them that they may be Doing It Wrong.
*/
- if (smartlist_len(whitelisted_live_middles) <=
+ if (smartlist_len(allowlisted_live_middles) <=
MAX_SANE_RESTRICTED_NODES) {
- middle_node = smartlist_choose(whitelisted_live_middles);
+ middle_node = smartlist_choose(allowlisted_live_middles);
} else {
static ratelim_t pinned_notice_limit = RATELIM_INIT(24*3600);
log_fn_ratelim(&pinned_notice_limit, LOG_NOTICE, LD_CIRC,
@@ -2084,17 +1847,17 @@ pick_restricted_middle_node(router_crn_flags_t flags,
"in %d total nodes. This is a lot of nodes. "
"You may want to consider using a Tor controller "
"to select and update a smaller set of nodes instead.",
- position_hint, smartlist_len(whitelisted_live_middles));
+ position_hint, smartlist_len(allowlisted_live_middles));
/* NO_WEIGHTING here just means don't take node flags into account
* (ie: use consensus measurement only). This is done so that
* we don't further surprise the user by not using Exits that they
* specified at all */
- middle_node = node_sl_choose_by_bandwidth(whitelisted_live_middles,
+ middle_node = node_sl_choose_by_bandwidth(allowlisted_live_middles,
NO_WEIGHTING);
}
- smartlist_free(whitelisted_live_middles);
+ smartlist_free(allowlisted_live_middles);
smartlist_free(all_live_nodes);
return middle_node;
@@ -2222,6 +1985,43 @@ warn_if_last_router_excluded(origin_circuit_t *circ,
return;
}
+/* Return a set of generic CRN_* flags based on <b>state</b>.
+ *
+ * Called for every position in the circuit. */
+STATIC int
+cpath_build_state_to_crn_flags(const cpath_build_state_t *state)
+{
+ router_crn_flags_t flags = 0;
+ /* These flags apply to entry, middle, and exit nodes.
+ * If a flag only applies to a specific position, it should be checked in
+ * that function. */
+ if (state->need_uptime)
+ flags |= CRN_NEED_UPTIME;
+ if (state->need_capacity)
+ flags |= CRN_NEED_CAPACITY;
+ return flags;
+}
+
+/* Return the CRN_INITIATE_IPV6_EXTEND flag, based on <b>state</b> and
+ * <b>cur_len</b>.
+ *
+ * Only called for middle nodes (for now). Must not be called on single-hop
+ * circuits. */
+STATIC int
+cpath_build_state_to_crn_ipv6_extend_flag(const cpath_build_state_t *state,
+ int cur_len)
+{
+ IF_BUG_ONCE(state->desired_path_len < 2)
+ return 0;
+
+ /* The last node is the relay doing the self-test. So we want to extend over
+ * IPv6 from the second-last node. */
+ if (state->is_ipv6_selftest && cur_len == state->desired_path_len - 2)
+ return CRN_INITIATE_IPV6_EXTEND;
+ else
+ return 0;
+}
+
/** Decide a suitable length for circ's cpath, and pick an exit
* router (or use <b>exit</b> if provided). Store these in the
* cpath.
@@ -2255,14 +2055,13 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei,
exit_ei = extend_info_dup(exit_ei);
} else { /* we have to decide one */
router_crn_flags_t flags = CRN_NEED_DESC;
- if (state->need_uptime)
- flags |= CRN_NEED_UPTIME;
- if (state->need_capacity)
- flags |= CRN_NEED_CAPACITY;
- if (is_hs_v3_rp_circuit)
- flags |= CRN_RENDEZVOUS_V3;
+ flags |= cpath_build_state_to_crn_flags(state);
+ /* Some internal exits are one hop, for example directory connections.
+ * (Guards are always direct, middles are never direct.) */
if (state->onehop_tunnel)
flags |= CRN_DIRECT_CONN;
+ if (is_hs_v3_rp_circuit)
+ flags |= CRN_RENDEZVOUS_V3;
const node_t *node =
choose_good_exit_server(circ, flags, state->is_internal);
if (!node) {
@@ -2294,7 +2093,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;
}
@@ -2324,32 +2123,27 @@ circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *exit_ei)
return 0;
}
-/** Return the number of routers in <b>routers</b> that are currently up
- * and available for building circuits through.
+/** Return the number of routers in <b>nodes</b> that are currently up and
+ * available for building circuits through.
*
- * (Note that this function may overcount or undercount, if we have
- * descriptors that are not the type we would prefer to use for some
- * particular router. See bug #25885.)
+ * If <b>direct</b> is true, only count nodes that are suitable for direct
+ * connections. Counts nodes regardless of whether their addresses are
+ * preferred.
*/
MOCK_IMPL(STATIC int,
-count_acceptable_nodes, (smartlist_t *nodes))
+count_acceptable_nodes, (const smartlist_t *nodes, int direct))
{
int num=0;
+ int flags = CRN_NEED_DESC;
+
+ if (direct)
+ flags |= CRN_DIRECT_CONN;
SMARTLIST_FOREACH_BEGIN(nodes, const node_t *, node) {
// log_debug(LD_CIRC,
-// "Contemplating whether router %d (%s) is a new option.",
-// i, r->nickname);
- if (! node->is_running)
-// log_debug(LD_CIRC,"Nope, the directory says %d is not running.",i);
- continue;
- if (! node->is_valid)
-// log_debug(LD_CIRC,"Nope, the directory says %d is not valid.",i);
- continue;
- if (! node_has_any_descriptor(node))
- continue;
- /* The node has a descriptor, so we can just check the ntor key directly */
- if (!node_has_curve25519_onion_key(node))
+ // "Contemplating whether router %d (%s) is a new option.",
+ // i, r->nickname);
+ if (!router_can_choose_node(node, flags))
continue;
++num;
} SMARTLIST_FOREACH_END(node);
@@ -2359,47 +2153,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.
*
@@ -2415,7 +2168,7 @@ cpath_get_n_hops(crypt_path_t **head_ptr)
* The alternative is building the circuit in reverse. Reverse calls to
* onion_extend_cpath() (ie: select outer hops first) would then have the
* property that you don't gain information about inner hops by observing
- * outer ones. See https://trac.torproject.org/projects/tor/ticket/24487
+ * outer ones. See https://bugs.torproject.org/tpo/core/tor/24487
* for this.
*
* (Note further that we still exclude the exit to prevent A - B - A
@@ -2584,10 +2337,8 @@ choose_good_middle_server(uint8_t purpose,
excluded = build_middle_exclude_list(purpose, state, head, cur_len);
- if (state->need_uptime)
- flags |= CRN_NEED_UPTIME;
- if (state->need_capacity)
- flags |= CRN_NEED_CAPACITY;
+ flags |= cpath_build_state_to_crn_flags(state);
+ flags |= cpath_build_state_to_crn_ipv6_extend_flag(state, cur_len);
/** If a hidden service circuit wants a specific middle node, pin it. */
if (middle_node_must_be_vanguard(options, purpose, cur_len)) {
@@ -2597,7 +2348,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;
}
@@ -2646,10 +2414,7 @@ choose_good_entry_server(uint8_t purpose, cpath_build_state_t *state,
}
if (state) {
- if (state->need_uptime)
- flags |= CRN_NEED_UPTIME;
- if (state->need_capacity)
- flags |= CRN_NEED_CAPACITY;
+ flags |= cpath_build_state_to_crn_flags(state);
}
choice = router_choose_random_node(excluded, options->ExcludeNodes, flags);
@@ -2657,20 +2422,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.
*
@@ -2713,7 +2464,6 @@ onion_extend_cpath(origin_circuit_t *circ)
choose_good_middle_server(purpose, state, circ->cpath, cur_len);
if (r) {
info = extend_info_from_node(r, 0);
- tor_assert_nonfatal(info);
}
}
@@ -2727,176 +2477,17 @@ 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,
- const char *rsa_id_digest,
- const ed25519_public_key_t *ed_id,
- crypto_pk_t *onion_key,
- const curve25519_public_key_t *ntor_key,
- const tor_addr_t *addr, uint16_t port)
-{
- extend_info_t *info = tor_malloc_zero(sizeof(extend_info_t));
- memcpy(info->identity_digest, rsa_id_digest, DIGEST_LEN);
- if (ed_id && !ed25519_public_key_is_zero(ed_id))
- memcpy(&info->ed_identity, ed_id, sizeof(ed25519_public_key_t));
- if (nickname)
- strlcpy(info->nickname, nickname, sizeof(info->nickname));
- if (onion_key)
- info->onion_key = crypto_pk_dup_key(onion_key);
- if (ntor_key)
- memcpy(&info->curve25519_onion_key, ntor_key,
- sizeof(curve25519_public_key_t));
- tor_addr_copy(&info->addr, addr);
- info->port = port;
- return info;
-}
-
-/** Allocate and return a new extend_info that can be used to build a
- * circuit to or through the node <b>node</b>. Use the primary address
- * of the node (i.e. its IPv4 address) unless
- * <b>for_direct_connect</b> is true, in which case the preferred
- * address is used instead. May return NULL if there is not enough
- * info about <b>node</b> to extend to it--for example, if the preferred
- * routerinfo_t or microdesc_t is missing, or if for_direct_connect is
- * true and none of the node's addresses is allowed by tor's firewall
- * and IP version config.
- **/
-extend_info_t *
-extend_info_from_node(const node_t *node, int for_direct_connect)
-{
- crypto_pk_t *rsa_pubkey = NULL;
- extend_info_t *info = NULL;
- tor_addr_port_t ap;
- int valid_addr = 0;
-
- if (!node_has_preferred_descriptor(node, for_direct_connect)) {
- return NULL;
- }
-
- /* Choose a preferred address first, but fall back to an allowed address. */
- if (for_direct_connect)
- fascist_firewall_choose_address_node(node, FIREWALL_OR_CONNECTION, 0, &ap);
- else {
- node_get_prim_orport(node, &ap);
- }
- valid_addr = tor_addr_port_is_valid_ap(&ap, 0);
-
- if (valid_addr)
- log_debug(LD_CIRC, "using %s for %s",
- fmt_addrport(&ap.addr, ap.port),
- node->ri ? node->ri->nickname : node->rs->nickname);
- else
- log_warn(LD_CIRC, "Could not choose valid address for %s",
- node->ri ? node->ri->nickname : node->rs->nickname);
-
- /* Every node we connect or extend to must support ntor */
- if (!node_has_curve25519_onion_key(node)) {
- log_fn(LOG_PROTOCOL_WARN, LD_CIRC,
- "Attempted to create extend_info for a node that does not support "
- "ntor: %s", node_describe(node));
- return NULL;
- }
-
- const ed25519_public_key_t *ed_pubkey = NULL;
-
- /* Don't send the ed25519 pubkey unless the target node actually supports
- * authenticating with it. */
- if (node_supports_ed25519_link_authentication(node, 0)) {
- log_info(LD_CIRC, "Including Ed25519 ID for %s", node_describe(node));
- ed_pubkey = node_get_ed25519_id(node);
- } else if (node_get_ed25519_id(node)) {
- log_info(LD_CIRC, "Not including the ed25519 ID for %s, since it won't "
- "be able to authenticate it.",
- node_describe(node));
- }
-
- /* Retrieve the curve25519 pubkey. */
- const curve25519_public_key_t *curve_pubkey =
- node_get_curve25519_onion_key(node);
- rsa_pubkey = node_get_rsa_onion_key(node);
-
- if (valid_addr && node->ri) {
- info = extend_info_new(node->ri->nickname,
- node->identity,
- ed_pubkey,
- rsa_pubkey,
- curve_pubkey,
- &ap.addr,
- ap.port);
- } else if (valid_addr && node->rs && node->md) {
- info = extend_info_new(node->rs->nickname,
- node->identity,
- ed_pubkey,
- rsa_pubkey,
- curve_pubkey,
- &ap.addr,
- ap.port);
- }
-
- crypto_pk_free(rsa_pubkey);
- return info;
-}
-
-/** Release storage held by an extend_info_t struct. */
-void
-extend_info_free_(extend_info_t *info)
-{
- if (!info)
- return;
- crypto_pk_free(info->onion_key);
- tor_free(info);
-}
-
-/** Allocate and return a new extend_info_t with the same contents as
- * <b>info</b>. */
-extend_info_t *
-extend_info_dup(extend_info_t *info)
-{
- extend_info_t *newinfo;
- tor_assert(info);
- newinfo = tor_malloc(sizeof(extend_info_t));
- memcpy(newinfo, info, sizeof(extend_info_t));
- if (info->onion_key)
- newinfo->onion_key = crypto_pk_dup_key(info->onion_key);
- else
- newinfo->onion_key = NULL;
- return newinfo;
-}
-
/** Return the node_t for the chosen exit router in <b>state</b>.
* 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;
@@ -2926,43 +2517,6 @@ build_state_get_exit_nickname(cpath_build_state_t *state)
return state->chosen_exit->nickname;
}
-/** Return true iff the given address can be used to extend to. */
-int
-extend_info_addr_is_allowed(const tor_addr_t *addr)
-{
- tor_assert(addr);
-
- /* Check if we have a private address and if we can extend to it. */
- if ((tor_addr_is_internal(addr, 0) || tor_addr_is_multicast(addr)) &&
- !get_options()->ExtendAllowPrivateAddresses) {
- goto disallow;
- }
- /* Allowed! */
- return 1;
- disallow:
- return 0;
-}
-
-/* Does ei have a valid TAP key? */
-int
-extend_info_supports_tap(const extend_info_t* ei)
-{
- tor_assert(ei);
- /* Valid TAP keys are not NULL */
- return ei->onion_key != NULL;
-}
-
-/* Does ei have a valid ntor key? */
-int
-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(
- (const char*)ei->curve25519_onion_key.public_key,
- CURVE25519_PUBKEY_LEN);
-}
-
/* Is circuit purpose allowed to use the deprecated TAP encryption protocol?
* The hidden service protocol still uses TAP for some connections, because
* ntor onion keys aren't included in HS descriptors or INTRODUCE cells. */
@@ -2997,15 +2551,6 @@ circuit_has_usable_onion_key(const origin_circuit_t *circ)
circuit_can_use_tap(circ));
}
-/* Does ei have an onion key which it would prefer to use?
- * Currently, we prefer ntor keys*/
-int
-extend_info_has_preferred_onion_key(const extend_info_t* ei)
-{
- tor_assert(ei);
- return extend_info_supports_ntor(ei);
-}
-
/** Find the circuits that are waiting to find out whether their guards are
* usable, and if any are ready to become usable, mark them open and try
* attaching streams as appropriate. */