diff options
Diffstat (limited to 'src/or')
-rw-r--r-- | src/or/channel.c | 8 | ||||
-rw-r--r-- | src/or/channel.h | 4 | ||||
-rw-r--r-- | src/or/channeltls.c | 2 | ||||
-rw-r--r-- | src/or/circuitbuild.c | 227 | ||||
-rw-r--r-- | src/or/circuitbuild.h | 5 | ||||
-rw-r--r-- | src/or/circuitlist.c | 6 | ||||
-rw-r--r-- | src/or/config.c | 3 | ||||
-rw-r--r-- | src/or/dirserv.c | 14 | ||||
-rw-r--r-- | src/or/hibernate.c | 2 | ||||
-rw-r--r-- | src/or/networkstatus.c | 6 | ||||
-rw-r--r-- | src/or/nodelist.c | 28 | ||||
-rw-r--r-- | src/or/onion.c | 4 | ||||
-rw-r--r-- | src/or/or.h | 3 | ||||
-rw-r--r-- | src/or/rendclient.c | 7 | ||||
-rw-r--r-- | src/or/rendservice.c | 11 | ||||
-rw-r--r-- | src/or/rendservice.h | 2 | ||||
-rw-r--r-- | src/or/router.c | 9 | ||||
-rw-r--r-- | src/or/routerlist.c | 51 | ||||
-rw-r--r-- | src/or/routerlist.h | 3 | ||||
-rw-r--r-- | src/or/shared_random.c | 4 |
20 files changed, 311 insertions, 88 deletions
diff --git a/src/or/channel.c b/src/or/channel.c index 87fa721089..6a78b21988 100644 --- a/src/or/channel.c +++ b/src/or/channel.c @@ -838,7 +838,7 @@ channel_free(channel_t *chan) } /* Call a free method if there is one */ - if (chan->free) chan->free(chan); + if (chan->free_fn) chan->free_fn(chan); channel_clear_remote_end(chan); @@ -878,7 +878,7 @@ channel_listener_free(channel_listener_t *chan_l) tor_assert(!(chan_l->registered)); /* Call a free method if there is one */ - if (chan_l->free) chan_l->free(chan_l); + if (chan_l->free_fn) chan_l->free_fn(chan_l); /* * We're in CLOSED or ERROR, so the incoming channel queue is already @@ -916,7 +916,7 @@ channel_force_free(channel_t *chan) } /* Call a free method if there is one */ - if (chan->free) chan->free(chan); + if (chan->free_fn) chan->free_fn(chan); channel_clear_remote_end(chan); @@ -958,7 +958,7 @@ channel_listener_force_free(channel_listener_t *chan_l) chan_l); /* Call a free method if there is one */ - if (chan_l->free) chan_l->free(chan_l); + if (chan_l->free_fn) chan_l->free_fn(chan_l); /* * The incoming list just gets emptied and freed; we request close on diff --git a/src/or/channel.h b/src/or/channel.h index 78e1b71014..a711b56d44 100644 --- a/src/or/channel.h +++ b/src/or/channel.h @@ -90,7 +90,7 @@ struct channel_s { /* Methods implemented by the lower layer */ /** Free a channel */ - void (*free)(channel_t *); + void (*free_fn)(channel_t *); /** Close an open channel */ void (*close)(channel_t *); /** Describe the transport subclass for this channel */ @@ -273,7 +273,7 @@ struct channel_listener_s { /* Methods implemented by the lower layer */ /** Free a channel */ - void (*free)(channel_listener_t *); + void (*free_fn)(channel_listener_t *); /** Close an open channel */ void (*close)(channel_listener_t *); /** Describe the transport subclass for this channel */ diff --git a/src/or/channeltls.c b/src/or/channeltls.c index a62f80ef91..9c2411ede8 100644 --- a/src/or/channeltls.c +++ b/src/or/channeltls.c @@ -117,7 +117,7 @@ channel_tls_common_init(channel_tls_t *tlschan) chan->state = CHANNEL_STATE_OPENING; chan->close = channel_tls_close_method; chan->describe_transport = channel_tls_describe_transport_method; - chan->free = channel_tls_free_method; + chan->free_fn = channel_tls_free_method; chan->get_overhead_estimate = channel_tls_get_overhead_estimate_method; chan->get_remote_addr = channel_tls_get_remote_addr_method; chan->get_remote_descr = channel_tls_get_remote_descr_method; diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c index 14d40150db..12c75530e2 100644 --- a/src/or/circuitbuild.c +++ b/src/or/circuitbuild.c @@ -58,7 +58,6 @@ static crypt_path_t *onion_next_hop_in_cpath(crypt_path_t *cpath); static int onion_extend_cpath(origin_circuit_t *circ); static int count_acceptable_nodes(smartlist_t *routers); static int onion_append_hop(crypt_path_t **head_ptr, extend_info_t *choice); -static int circuits_can_use_ntor(void); /** This function tries to get a channel to the specified endpoint, * and then calls command_setup_channel() to give it the right @@ -365,7 +364,7 @@ circuit_rep_hist_note_result(origin_circuit_t *circ) } while (hop!=circ->cpath); } -/** Return 1 iff at least one node in circ's cpath supports ntor. */ +/** Return 1 iff every node in circ's cpath definitely supports ntor. */ static int circuit_cpath_supports_ntor(const origin_circuit_t *circ) { @@ -373,16 +372,19 @@ circuit_cpath_supports_ntor(const origin_circuit_t *circ) cpath = head = circ->cpath; do { - if (cpath->extend_info && - !tor_mem_is_zero( - (const char*)cpath->extend_info->curve25519_onion_key.public_key, - CURVE25519_PUBKEY_LEN)) - return 1; + /* if the extend_info is missing, we can't tell if it supports ntor */ + if (!cpath->extend_info) { + return 0; + } + /* if the key is blank, it definitely doesn't support ntor */ + if (!extend_info_supports_ntor(cpath->extend_info)) { + return 0; + } cpath = cpath->next; } while (cpath != head); - return 0; + return 1; } /** Pick all the entries in our cpath. Stop and return 0 when we're @@ -390,41 +392,61 @@ circuit_cpath_supports_ntor(const origin_circuit_t *circ) static int onion_populate_cpath(origin_circuit_t *circ) { - int n_tries = 0; - const int using_ntor = circuits_can_use_ntor(); + int r = 0; -#define MAX_POPULATE_ATTEMPTS 32 + /* onion_extend_cpath assumes these are non-NULL */ + tor_assert(circ); + tor_assert(circ->build_state); - while (1) { - int r = onion_extend_cpath(circ); + while (r == 0) { + r = onion_extend_cpath(circ); if (r < 0) { log_info(LD_CIRC,"Generating cpath hop failed."); return -1; } - if (r == 1) { - /* This circuit doesn't need/shouldn't be forced to have an ntor hop */ - if (circ->build_state->desired_path_len <= 1 || ! using_ntor) - return 0; + } - /* This circuit has an ntor hop. great! */ - if (circuit_cpath_supports_ntor(circ)) - return 0; + /* The path is complete */ + tor_assert(r == 1); - /* No node in the circuit supports ntor. Have we already tried too many - * times? */ - if (++n_tries >= MAX_POPULATE_ATTEMPTS) - break; + /* Does every node in this path support ntor? */ + int path_supports_ntor = circuit_cpath_supports_ntor(circ); - /* Clear the path and retry */ - circuit_clear_cpath(circ); + /* We would like every path to support ntor, but we have to allow for some + * edge cases. */ + tor_assert(circuit_get_cpath_len(circ)); + if (circuit_can_use_tap(circ)) { + /* Circuits from clients to intro points, and hidden services to + * rend points do not support ntor, because the hidden service protocol + * does not include ntor onion keys. This is also true for Tor2web clients + * and Single Onion Services. */ + return 0; + } + + if (circuit_get_cpath_len(circ) == 1) { + /* Allow for bootstrapping: when we're fetching directly from a fallback, + * authority, or bridge, we have no way of knowing its ntor onion key + * before we connect to it. So instead, we try connecting, and end up using + * CREATE_FAST. */ + tor_assert(circ->cpath); + tor_assert(circ->cpath->extend_info); + const node_t *node = node_get_by_id( + circ->cpath->extend_info->identity_digest); + /* If we don't know the node and its descriptor, we must be bootstrapping. + */ + if (!node || !node_has_descriptor(node)) { + return 0; } } - log_warn(LD_CIRC, "I tried for %d times, but I couldn't build a %d-hop " - "circuit with at least one node that supports ntor.", - MAX_POPULATE_ATTEMPTS, - circ->build_state->desired_path_len); - return -1; + if (BUG(!path_supports_ntor)) { + /* If we're building a multi-hop path, and it's not one of the HS or + * bootstrapping exceptions, and it doesn't support ntor, something has + * gone wrong. */ + return -1; + } + + return 0; } /** Create and return a new origin circuit. Initialize its purpose and @@ -757,10 +779,13 @@ should_use_create_fast_for_circuit(origin_circuit_t *circ) tor_assert(circ->cpath); tor_assert(circ->cpath->extend_info); - if (!circ->cpath->extend_info->onion_key) - return 1; /* our hand is forced: only a create_fast will work. */ + 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 know an onion key. We can choose. + /* 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; @@ -785,30 +810,20 @@ circuit_timeout_want_to_count_circ(origin_circuit_t *circ) && circ->build_state->desired_path_len == DEFAULT_ROUTE_LEN; } -/** Return true if the ntor handshake is enabled in the configuration, or if - * it's been set to "auto" in the configuration and it's enabled in the - * consensus. */ -static int -circuits_can_use_ntor(void) -{ - const or_options_t *options = get_options(); - if (options->UseNTorHandshake != -1) - return options->UseNTorHandshake; - return networkstatus_get_param(NULL, "UseNTorHandshake", 0, 0, 1); -} - /** Decide whether to use a TAP or ntor handshake for connecting to <b>ei</b> * directly, and set *<b>cell_type_out</b> and *<b>handshake_type_out</b> - * accordingly. */ + * accordingly. + * Note that TAP handshakes are only used for direct connections: + * - from Tor2web to intro points not in the client's consensus, and + * - from Single Onions to rend points not in the service's consensus. + * This is checked in onion_populate_cpath. */ static void circuit_pick_create_handshake(uint8_t *cell_type_out, uint16_t *handshake_type_out, const extend_info_t *ei) { - /* XXXX029 Remove support for deciding to use TAP. */ - if (!tor_mem_is_zero((const char*)ei->curve25519_onion_key.public_key, - CURVE25519_PUBKEY_LEN) && - circuits_can_use_ntor()) { + /* XXXX030 Remove support for deciding to use TAP. */ + if (extend_info_supports_ntor(ei)) { *cell_type_out = CELL_CREATE2; *handshake_type_out = ONION_HANDSHAKE_TYPE_NTOR; return; @@ -822,7 +837,11 @@ circuit_pick_create_handshake(uint8_t *cell_type_out, * directly, and set *<b>handshake_type_out</b> accordingly. Decide whether, * in extending through <b>node</b> to do so, we should use an EXTEND2 or an * EXTEND cell to do so, and set *<b>cell_type_out</b> and - * *<b>create_cell_type_out</b> accordingly. */ + * *<b>create_cell_type_out</b> accordingly. + * Note that TAP handshakes are only used for extend handshakes: + * - from clients to intro points, and + * - from hidden services to rend points. + * This is checked in onion_populate_cpath. */ static void circuit_pick_extend_handshake(uint8_t *cell_type_out, uint8_t *create_cell_type_out, @@ -833,11 +852,25 @@ circuit_pick_extend_handshake(uint8_t *cell_type_out, uint8_t t; circuit_pick_create_handshake(&t, handshake_type_out, ei); - /* XXXX029 Remove support for deciding to use TAP. */ - if (node_prev && - *handshake_type_out != ONION_HANDSHAKE_TYPE_TAP && + /* XXXX030 Remove support for deciding to use TAP. */ + + /* It is an error to extend if there is no previous node. */ + if (BUG(node_prev == NULL)) { + *cell_type_out = RELAY_COMMAND_EXTEND; + *create_cell_type_out = CELL_CREATE; + return; + } + + /* It is an error for a node with a known version to be so old it does not + * support ntor. */ + tor_assert_nonfatal(routerstatus_version_supports_ntor(node_prev->rs, 1)); + + /* Assume relays without tor versions or routerstatuses support ntor. + * The authorities enforce ntor support, and assuming and failing is better + * than allowing a malicious node to perform a protocol downgrade to TAP. */ + if (*handshake_type_out != ONION_HANDSHAKE_TYPE_TAP && (node_has_curve25519_onion_key(node_prev) || - (node_prev->rs && node_prev->rs->version_supports_extend2_cells))) { + (routerstatus_version_supports_ntor(node_prev->rs, 1)))) { *cell_type_out = RELAY_COMMAND_EXTEND2; *create_cell_type_out = CELL_CREATE2; } else { @@ -2058,15 +2091,18 @@ count_acceptable_nodes(smartlist_t *nodes) if (! node->is_running) // log_debug(LD_CIRC,"Nope, the directory says %d is not running.",i); continue; + /* XXX This clause makes us count incorrectly: if AllowInvalidRouters + * allows this node in some places, then we're getting an inaccurate + * count. For now, be conservative and don't count it. But later we + * should try to be smarter. */ if (! node->is_valid) // log_debug(LD_CIRC,"Nope, the directory says %d is not valid.",i); continue; if (! node_has_descriptor(node)) continue; - /* XXX This clause makes us count incorrectly: if AllowInvalidRouters - * allows this node in some places, then we're getting an inaccurate - * count. For now, be conservative and don't count it. But later we - * should try to be smarter. */ + /* The node has a descriptor, so we can just check the ntor key directly */ + if (!node_has_curve25519_onion_key(node)) + continue; ++num; } SMARTLIST_FOREACH_END(node); @@ -2356,6 +2392,14 @@ extend_info_from_node(const node_t *node, int for_direct_connect) 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; + } + if (valid_addr && node->ri) return extend_info_new(node->ri->nickname, node->identity, @@ -2441,3 +2485,66 @@ extend_info_addr_is_allowed(const tor_addr_t *addr) 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. */ +static int +circuit_purpose_can_use_tap_impl(uint8_t purpose) +{ + return (purpose == CIRCUIT_PURPOSE_S_CONNECT_REND || + purpose == CIRCUIT_PURPOSE_C_INTRODUCING); +} + +/* Is circ 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. */ +int +circuit_can_use_tap(const origin_circuit_t *circ) +{ + tor_assert(circ); + tor_assert(circ->cpath); + tor_assert(circ->cpath->extend_info); + return (circuit_purpose_can_use_tap_impl(circ->base_.purpose) && + extend_info_supports_tap(circ->cpath->extend_info)); +} + +/* Does circ have an onion key which it's allowed to use? */ +int +circuit_has_usable_onion_key(const origin_circuit_t *circ) +{ + tor_assert(circ); + tor_assert(circ->cpath); + tor_assert(circ->cpath->extend_info); + return (extend_info_supports_ntor(circ->cpath->extend_info) || + 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); +} + diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h index 7f5fd511a9..1244601f71 100644 --- a/src/or/circuitbuild.h +++ b/src/or/circuitbuild.h @@ -54,6 +54,11 @@ extend_info_t *extend_info_from_node(const node_t *r, int for_direct_connect); extend_info_t *extend_info_dup(extend_info_t *info); void extend_info_free(extend_info_t *info); int extend_info_addr_is_allowed(const tor_addr_t *addr); +int extend_info_supports_tap(const extend_info_t* ei); +int extend_info_supports_ntor(const extend_info_t* ei); +int circuit_can_use_tap(const origin_circuit_t *circ); +int circuit_has_usable_onion_key(const origin_circuit_t *circ); +int extend_info_has_preferred_onion_key(const extend_info_t* ei); const node_t *build_state_get_exit_node(cpath_build_state_t *state); const char *build_state_get_exit_nickname(cpath_build_state_t *state); diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c index 5c691644a4..3c92baa274 100644 --- a/src/or/circuitlist.c +++ b/src/or/circuitlist.c @@ -1613,7 +1613,8 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info, return best; } -/** Return the number of hops in circuit's path. */ +/** Return the number of hops in circuit's path. If circ has no entries, + * or is NULL, returns 0. */ int circuit_get_cpath_len(origin_circuit_t *circ) { @@ -1629,7 +1630,8 @@ circuit_get_cpath_len(origin_circuit_t *circ) } /** Return the <b>hopnum</b>th hop in <b>circ</b>->cpath, or NULL if there - * aren't that many hops in the list. */ + * aren't that many hops in the list. <b>hopnum</b> starts at 1. + * Returns NULL if <b>hopnum</b> is 0 or negative. */ crypt_path_t * circuit_get_cpath_hop(origin_circuit_t *circ, int hopnum) { diff --git a/src/or/config.c b/src/or/config.c index 31bf81877d..98b32708c6 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -438,7 +438,7 @@ static config_var_t option_vars_[] = { V(UseEntryGuardsAsDirGuards, BOOL, "1"), V(UseGuardFraction, AUTOBOOL, "auto"), V(UseMicrodescriptors, AUTOBOOL, "auto"), - V(UseNTorHandshake, AUTOBOOL, "1"), + OBSOLETE("UseNTorHandshake"), V(User, STRING, NULL), OBSOLETE("UserspaceIOCPBuffers"), V(AuthDirSharedRandomness, BOOL, "1"), @@ -613,7 +613,6 @@ static const config_deprecation_t option_deprecation_notes_[] = { "to accidentally lose your anonymity by leaking DNS information" }, { "TLSECGroup", "The default is a nice secure choice; the other option " "is less secure." }, - { "UseNTorHandshake", "The ntor handshake should always be used." }, { "ControlListenAddress", "Use ControlPort instead." }, { "DirListenAddress", "Use DirPort instead, possibly with the " "NoAdvertise sub-option" }, diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 64ebde6fdd..ff50ca4417 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -255,6 +255,20 @@ dirserv_router_get_status(const routerinfo_t *router, const char **msg, return FP_REJECT; } + /* dirserv_get_status_impl already rejects versions older than 0.2.4.18-rc, + * and onion_curve25519_pkey was introduced in 0.2.4.8-alpha. + * But just in case a relay doesn't provide or lies about its version, or + * doesn't include an ntor key in its descriptor, check that it exists, + * and is non-zero (clients check that it's non-zero before using it). */ + if (!routerinfo_has_curve25519_onion_key(router)) { + log_fn(severity, LD_DIR, + "Descriptor from router %s is missing an ntor curve25519 onion " + "key.", router_describe(router)); + if (msg) + *msg = "Missing ntor curve25519 onion key. Please upgrade!"; + return FP_REJECT; + } + if (router->cache_info.signing_key_cert) { /* This has an ed25519 identity key. */ if (KEYPIN_MISMATCH == diff --git a/src/or/hibernate.c b/src/or/hibernate.c index 209aae01cf..7e25306234 100644 --- a/src/or/hibernate.c +++ b/src/or/hibernate.c @@ -692,7 +692,7 @@ read_bandwidth_usage(void) int res; res = unlink(fname); - if (res != 0) { + if (res != 0 && errno != ENOENT) { log_warn(LD_FS, "Failed to unlink %s: %s", fname, strerror(errno)); diff --git a/src/or/networkstatus.c b/src/or/networkstatus.c index fe4b4562ff..72af505d19 100644 --- a/src/or/networkstatus.c +++ b/src/or/networkstatus.c @@ -2275,6 +2275,12 @@ client_would_use_router(const routerstatus_t *rs, time_t now, /* We'd drop it immediately for being too old. */ return 0; } + if (!routerstatus_version_supports_ntor(rs, 1)) { + /* We'd ignore it because it doesn't support ntor. + * If we don't know the version, download the descriptor so we can + * check if it supports ntor. */ + return 0; + } return 1; } diff --git a/src/or/nodelist.c b/src/or/nodelist.c index 7b64cafd79..070e2e9e0d 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -1173,14 +1173,38 @@ node_get_pref_ipv6_dirport(const node_t *node, tor_addr_port_t *ap_out) } } +/** Return true iff <b>md</b> has a curve25519 onion key. + * Use node_has_curve25519_onion_key() instead of calling this directly. */ +static int +microdesc_has_curve25519_onion_key(const microdesc_t *md) +{ + if (!md) { + return 0; + } + + if (!md->onion_curve25519_pkey) { + return 0; + } + + if (tor_mem_is_zero((const char*)md->onion_curve25519_pkey->public_key, + CURVE25519_PUBKEY_LEN)) { + return 0; + } + + return 1; +} + /** Return true iff <b>node</b> has a curve25519 onion key. */ int node_has_curve25519_onion_key(const node_t *node) { + if (!node) + return 0; + if (node->ri) - return node->ri->onion_curve25519_pkey != NULL; + return routerinfo_has_curve25519_onion_key(node->ri); else if (node->md) - return node->md->onion_curve25519_pkey != NULL; + return microdesc_has_curve25519_onion_key(node->md); else return 0; } diff --git a/src/or/onion.c b/src/or/onion.c index 5495074a83..8a566af766 100644 --- a/src/or/onion.c +++ b/src/or/onion.c @@ -11,6 +11,7 @@ **/ #include "or.h" +#include "circuitbuild.h" #include "circuitlist.h" #include "config.h" #include "cpuworker.h" @@ -438,8 +439,7 @@ onion_skin_create(int type, r = CREATE_FAST_LEN; break; case ONION_HANDSHAKE_TYPE_NTOR: - if (tor_mem_is_zero((const char*)node->curve25519_onion_key.public_key, - CURVE25519_PUBKEY_LEN)) + if (!extend_info_supports_ntor(node)) return -1; if (onion_skin_ntor_create((const uint8_t*)node->identity_digest, &node->curve25519_onion_key, diff --git a/src/or/or.h b/src/or/or.h index be58fa0d0a..34089ad994 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -4384,9 +4384,6 @@ typedef struct { char *TLSECGroup; /**< One of "P256", "P224", or nil for auto */ - /** Autobool: should we use the ntor handshake if we can? */ - int UseNTorHandshake; - /** Fraction: */ double PathsNeededToBuildCircuits; diff --git a/src/or/rendclient.c b/src/or/rendclient.c index 3468b07561..3a742fec0a 100644 --- a/src/or/rendclient.c +++ b/src/or/rendclient.c @@ -1368,8 +1368,13 @@ rend_client_get_random_intro_impl(const rend_cache_entry_t *entry, i = crypto_rand_int(smartlist_len(usable_nodes)); intro = smartlist_get(usable_nodes, i); + if (BUG(!intro->extend_info)) { + /* This should never happen, but it isn't fatal, just try another */ + smartlist_del(usable_nodes, i); + goto again; + } /* Do we need to look up the router or is the extend info complete? */ - if (!intro->extend_info->onion_key) { + if (!extend_info_supports_tap(intro->extend_info)) { const node_t *node; extend_info_t *new_extend_info; if (tor_digest_is_zero(intro->extend_info->identity_digest)) diff --git a/src/or/rendservice.c b/src/or/rendservice.c index 4c88f1fa5f..8d3a7d704c 100644 --- a/src/or/rendservice.c +++ b/src/or/rendservice.c @@ -508,7 +508,7 @@ rend_config_services(const or_options_t *options, int validate_only) if (!strcasecmp(line->key, "HiddenServiceDir")) { if (service) { /* register the one we just finished parsing */ if (validate_only) - rend_service_free(service); + rend_service_free(service); else rend_add_service(service); } @@ -3896,3 +3896,12 @@ rend_service_set_connection_addr_port(edge_connection_t *conn, return -2; } +/* Stub that should be replaced with the #17178 version of the function + * when merging. */ +int +rend_service_allow_direct_connection(const or_options_t *options) +{ + (void)options; + return 0; +} + diff --git a/src/or/rendservice.h b/src/or/rendservice.h index 4966cb0302..1622086a99 100644 --- a/src/or/rendservice.h +++ b/src/or/rendservice.h @@ -131,5 +131,7 @@ void directory_post_to_hs_dir(rend_service_descriptor_t *renddesc, const char *service_id, int seconds_valid); void rend_service_desc_has_uploaded(const rend_data_t *rend_data); +int rend_service_allow_direct_connection(const or_options_t *options); + #endif diff --git a/src/or/router.c b/src/or/router.c index e9961d4594..8fa5799896 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -452,7 +452,8 @@ init_key_from_file(const char *fname, int generate, int severity, goto error; } } else { - log_info(LD_GENERAL, "No key found in \"%s\"", fname); + tor_log(severity, LD_GENERAL, "No key found in \"%s\"", fname); + goto error; } return prkey; case FN_FILE: @@ -560,7 +561,7 @@ load_authority_keyset(int legacy, crypto_pk_t **key_out, fname = get_datadir_fname2("keys", legacy ? "legacy_signing_key" : "authority_signing_key"); - signing_key = init_key_from_file(fname, 0, LOG_INFO, 0); + signing_key = init_key_from_file(fname, 0, LOG_ERR, 0); if (!signing_key) { log_warn(LD_DIR, "No version 3 directory key found in %s", fname); goto done; @@ -2836,6 +2837,10 @@ router_dump_router_to_string(routerinfo_t *router, (const char *)router->onion_curve25519_pkey->public_key, CURVE25519_PUBKEY_LEN, BASE64_ENCODE_MULTILINE); smartlist_add_asprintf(chunks, "ntor-onion-key %s", kbuf); + } else { + /* Authorities will start rejecting relays without ntor keys in 0.2.9 */ + log_err(LD_BUG, "A relay must have an ntor onion key"); + goto err; } /* Write the exit policy to the end of 's'. */ diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 1773f1d05c..74b8d1b1d3 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -2260,10 +2260,16 @@ router_add_running_nodes_to_smartlist(smartlist_t *sl, int allow_invalid, continue; if (node_is_unreliable(node, need_uptime, need_capacity, need_guard)) continue; - /* Choose a node with an OR address that matches the firewall rules, - * if we are making a direct connection */ + /* Don't choose nodes if we are certain they can't do ntor */ + if (node->rs && !routerstatus_version_supports_ntor(node->rs, 1)) + continue; + if ((node->ri || node->md) && !node_has_curve25519_onion_key(node)) + continue; + /* Choose a node with an OR address that matches the firewall rules */ if (direct_conn && check_reach && - !fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION, pref_addr)) + !fascist_firewall_allows_node(node, + FIREWALL_OR_CONNECTION, + pref_addr)) continue; smartlist_add(sl, (void *)node); @@ -5497,6 +5503,45 @@ routerinfo_incompatible_with_extrainfo(const crypto_pk_t *identity_pkey, return r; } +/* Does ri have a valid ntor onion key? + * Valid ntor onion keys exist and have at least one non-zero byte. */ +int +routerinfo_has_curve25519_onion_key(const routerinfo_t *ri) +{ + if (!ri) { + return 0; + } + + if (!ri->onion_curve25519_pkey) { + return 0; + } + + if (tor_mem_is_zero((const char*)ri->onion_curve25519_pkey->public_key, + CURVE25519_PUBKEY_LEN)) { + return 0; + } + + return 1; +} + +/* Is rs running a tor version known to support ntor? + * If allow_unknown_versions is true, return true if the version is unknown. + * Otherwise, return false if the version is unknown. */ +int +routerstatus_version_supports_ntor(const routerstatus_t *rs, + int allow_unknown_versions) +{ + if (!rs) { + return allow_unknown_versions; + } + + if (!rs->version_known) { + return allow_unknown_versions; + } + + return rs->version_supports_extend2_cells; +} + /** Assert that the internal representation of <b>rl</b> is * self-consistent. */ void diff --git a/src/or/routerlist.h b/src/or/routerlist.h index 72ab6d9bf3..47e5445e57 100644 --- a/src/or/routerlist.h +++ b/src/or/routerlist.h @@ -206,6 +206,9 @@ int routerinfo_incompatible_with_extrainfo(const crypto_pk_t *ri, extrainfo_t *ei, signed_descriptor_t *sd, const char **msg); +int routerinfo_has_curve25519_onion_key(const routerinfo_t *ri); +int routerstatus_version_supports_ntor(const routerstatus_t *rs, + int allow_unknown_versions); void routerlist_assert_ok(const routerlist_t *rl); const char *esc_router_info(const routerinfo_t *router); diff --git a/src/or/shared_random.c b/src/or/shared_random.c index 19564f5924..e672a416be 100644 --- a/src/or/shared_random.c +++ b/src/or/shared_random.c @@ -578,8 +578,8 @@ commit_is_authoritative(const sr_commit_t *commit, tor_assert(commit); tor_assert(voter_key); - return !memcmp(commit->rsa_identity, voter_key, - sizeof(commit->rsa_identity)); + return fast_memeq(commit->rsa_identity, voter_key, + sizeof(commit->rsa_identity)); } /* Decide if the newly received <b>commit</b> should be kept depending on |