diff options
Diffstat (limited to 'src/feature/nodelist/routerlist.c')
-rw-r--r-- | src/feature/nodelist/routerlist.c | 199 |
1 files changed, 125 insertions, 74 deletions
diff --git a/src/feature/nodelist/routerlist.c b/src/feature/nodelist/routerlist.c index 96bea5a670..a1a348edb9 100644 --- a/src/feature/nodelist/routerlist.c +++ b/src/feature/nodelist/routerlist.c @@ -65,6 +65,9 @@ #include "app/config/config.h" #include "core/mainloop/connection.h" #include "core/mainloop/mainloop.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "core/or/extendinfo.h" #include "core/or/policies.h" #include "feature/client/bridges.h" #include "feature/control/control_events.h" @@ -89,6 +92,7 @@ #include "feature/nodelist/routerset.h" #include "feature/nodelist/torcert.h" #include "feature/relay/routermode.h" +#include "feature/relay/relay_find_addr.h" #include "feature/stats/rephist.h" #include "lib/crypt_ops/crypto_format.h" #include "lib/crypt_ops/crypto_rand.h" @@ -136,8 +140,6 @@ static int signed_desc_digest_is_recognized(signed_descriptor_t *desc); static const char *signed_descriptor_get_body_impl( const signed_descriptor_t *desc, int with_annotations); -static void launch_dummy_descriptor_download_as_needed(time_t now, - const or_options_t *options); /****************************************************************************/ @@ -465,11 +467,20 @@ router_reload_router_list(void) return 0; } -/* When iterating through the routerlist, can OR address/port preference - * and reachability checks be skipped? +/* When selecting a router for a direct connection, can OR address/port + * preference and reachability checks be skipped? + * + * Servers never check ReachableAddresses or ClientPreferIPv6. Returns + * true for servers. + * + * Otherwise, if <b>try_ip_pref</b> is true, returns false. Used to make + * clients check ClientPreferIPv6, even if ReachableAddresses is not set. + * Finally, return true if ReachableAddresses is set. */ int -router_skip_or_reachability(const or_options_t *options, int try_ip_pref) +router_or_conn_should_skip_reachable_address_check( + const or_options_t *options, + int try_ip_pref) { /* Servers always have and prefer IPv4. * And if clients are checking against the firewall for reachability only, @@ -477,11 +488,15 @@ router_skip_or_reachability(const or_options_t *options, int try_ip_pref) return server_mode(options) || (!try_ip_pref && !firewall_is_fascist_or()); } -/* When iterating through the routerlist, can Dir address/port preference +/* When selecting a router for a direct connection, can Dir address/port * and reachability checks be skipped? + * + * This function is obsolete, because clients only use ORPorts. */ int -router_skip_dir_reachability(const or_options_t *options, int try_ip_pref) +router_dir_conn_should_skip_reachable_address_check( + const or_options_t *options, + int try_ip_pref) { /* Servers always have and prefer IPv4. * And if clients are checking against the firewall for reachability only, @@ -493,45 +508,115 @@ router_skip_dir_reachability(const or_options_t *options, int try_ip_pref) int routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2) { - return r1->addr == r2->addr && r1->or_port == r2->or_port && + return tor_addr_eq(&r1->ipv4_addr, &r2->ipv4_addr) && + r1->ipv4_orport == r2->ipv4_orport && tor_addr_eq(&r1->ipv6_addr, &r2->ipv6_addr) && r1->ipv6_orport == r2->ipv6_orport; } +/* Returns true if <b>node</b> can be chosen based on <b>flags</b>. + * + * The following conditions are applied to all nodes: + * - is running; + * - is valid; + * - supports EXTEND2 cells; + * - has an ntor circuit crypto key; and + * - does not allow single-hop exits. + * + * If the node has a routerinfo, we're checking for a direct connection, and + * we're using bridges, the following condition is applied: + * - has a bridge-purpose routerinfo; + * and for all other nodes: + * - has a general-purpose routerinfo (or no routerinfo). + * + * Nodes that don't have a routerinfo must be general-purpose nodes, because + * routerstatuses and microdescriptors only come via consensuses. + * + * The <b>flags</b> check that <b>node</b>: + * - <b>CRN_NEED_UPTIME</b>: has more than a minimum uptime; + * - <b>CRN_NEED_CAPACITY</b>: has more than a minimum capacity; + * - <b>CRN_NEED_GUARD</b>: is a Guard; + * - <b>CRN_NEED_DESC</b>: has a routerinfo or microdescriptor -- that is, + * enough info to be used to build a circuit; + * - <b>CRN_DIRECT_CONN</b>: is suitable for direct connections. Checks + * for the relevant descriptors. Checks the address + * against ReachableAddresses, ClientUseIPv4 0, and + * reachable_addr_use_ipv6() == 0); + * - <b>CRN_PREF_ADDR</b>: if we are connecting directly to the node, it has + * an address that is preferred by the + * ClientPreferIPv6ORPort setting; + * - <b>CRN_RENDEZVOUS_V3</b>: can become a v3 onion service rendezvous point; + * - <b>CRN_INITIATE_IPV6_EXTEND</b>: can initiate IPv6 extends. + */ +bool +router_can_choose_node(const node_t *node, int flags) +{ + /* The full set of flags used for node selection. */ + const bool need_uptime = (flags & CRN_NEED_UPTIME) != 0; + const bool need_capacity = (flags & CRN_NEED_CAPACITY) != 0; + const bool need_guard = (flags & CRN_NEED_GUARD) != 0; + const bool need_desc = (flags & CRN_NEED_DESC) != 0; + const bool pref_addr = (flags & CRN_PREF_ADDR) != 0; + const bool direct_conn = (flags & CRN_DIRECT_CONN) != 0; + const bool rendezvous_v3 = (flags & CRN_RENDEZVOUS_V3) != 0; + const bool initiate_ipv6_extend = (flags & CRN_INITIATE_IPV6_EXTEND) != 0; + + const or_options_t *options = get_options(); + const bool check_reach = + !router_or_conn_should_skip_reachable_address_check(options, pref_addr); + const bool direct_bridge = direct_conn && options->UseBridges; + + if (!node->is_running || !node->is_valid) + return false; + if (need_desc && !node_has_preferred_descriptor(node, direct_conn)) + return false; + if (node->ri) { + if (direct_bridge && node->ri->purpose != ROUTER_PURPOSE_BRIDGE) + return false; + else if (node->ri->purpose != ROUTER_PURPOSE_GENERAL) + return false; + } + if (node_is_unreliable(node, need_uptime, need_capacity, need_guard)) + return false; + /* Don't choose nodes if we are certain they can't do EXTEND2 cells */ + if (node->rs && !routerstatus_version_supports_extend2_cells(node->rs, 1)) + return false; + /* Don't choose nodes if we are certain they can't do ntor. */ + if ((node->ri || node->md) && !node_has_curve25519_onion_key(node)) + return false; + /* Exclude relays that allow single hop exit circuits. This is an + * obsolete option since 0.2.9.2-alpha and done by default in + * 0.3.1.0-alpha. */ + if (node_allows_single_hop_exits(node)) + return false; + /* Exclude relays that can not become a rendezvous for a hidden service + * version 3. */ + if (rendezvous_v3 && + !node_supports_v3_rendezvous_point(node)) + return false; + /* Choose a node with an OR address that matches the firewall rules */ + if (direct_conn && check_reach && + !reachable_addr_allows_node(node, + FIREWALL_OR_CONNECTION, + pref_addr)) + return false; + if (initiate_ipv6_extend && !node_supports_initiating_ipv6_extends(node)) + return false; + + return true; +} + /** Add every suitable node from our nodelist to <b>sl</b>, so that - * we can pick a node for a circuit. + * we can pick a node for a circuit based on <b>flags</b>. + * + * See router_can_choose_node() for details of <b>flags</b>. */ void -router_add_running_nodes_to_smartlist(smartlist_t *sl, int need_uptime, - int need_capacity, int need_guard, - int need_desc, int pref_addr, - int direct_conn) -{ - const int check_reach = !router_skip_or_reachability(get_options(), - pref_addr); - /* XXXX MOVE */ +router_add_running_nodes_to_smartlist(smartlist_t *sl, int flags) +{ SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) { - if (!node->is_running || !node->is_valid) - continue; - if (need_desc && !node_has_preferred_descriptor(node, direct_conn)) - continue; - if (node->ri && node->ri->purpose != ROUTER_PURPOSE_GENERAL) - continue; - if (node_is_unreliable(node, need_uptime, need_capacity, need_guard)) - continue; - /* Don't choose nodes if we are certain they can't do EXTEND2 cells */ - if (node->rs && !routerstatus_version_supports_extend2_cells(node->rs, 1)) - continue; - /* Don't choose nodes if we are certain they can't do ntor. */ - 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)) + if (!router_can_choose_node(node, flags)) continue; - smartlist_add(sl, (void *)node); } SMARTLIST_FOREACH_END(node); } @@ -2222,7 +2307,6 @@ update_all_descriptor_downloads(time_t now) return; update_router_descriptor_downloads(now); update_microdesc_downloads(now); - launch_dummy_descriptor_download_as_needed(now, get_options()); } /** Clear all our timeouts for fetching v3 directory stuff, and then @@ -2676,39 +2760,6 @@ update_consensus_router_descriptor_downloads(time_t now, int is_vote, smartlist_free(no_longer_old); } -/** How often should we launch a server/authority request to be sure of getting - * a guess for our IP? */ -/*XXXX+ this info should come from netinfo cells or something, or we should - * do this only when we aren't seeing incoming data. see bug 652. */ -#define DUMMY_DOWNLOAD_INTERVAL (20*60) - -/** As needed, launch a dummy router descriptor fetch to see if our - * address has changed. */ -static void -launch_dummy_descriptor_download_as_needed(time_t now, - const or_options_t *options) -{ - static time_t last_dummy_download = 0; - /* XXXX+ we could be smarter here; see notes on bug 652. */ - /* If we're a server that doesn't have a configured address, we rely on - * directory fetches to learn when our address changes. So if we haven't - * tried to get any routerdescs in a long time, try a dummy fetch now. */ - if (!options->Address && - server_mode(options) && - last_descriptor_download_attempted + DUMMY_DOWNLOAD_INTERVAL < now && - last_dummy_download + DUMMY_DOWNLOAD_INTERVAL < now) { - last_dummy_download = now; - /* XX/teor - do we want an authority here, because they are less likely - * to give us the wrong address? (See #17782) - * I'm leaving the previous behaviour intact, because I don't like - * the idea of some relays contacting an authority every 20 minutes. */ - directory_get_from_dirserver(DIR_PURPOSE_FETCH_SERVERDESC, - ROUTER_PURPOSE_GENERAL, "authority.z", - PDS_RETRY_IF_NO_SERVERS, - DL_WANT_ANY_DIRSERVER); - } -} - /** Launch downloads for router status as needed. */ void update_router_descriptor_downloads(time_t now) @@ -2882,12 +2933,12 @@ router_differences_are_cosmetic(const routerinfo_t *r1, const routerinfo_t *r2) } /* If any key fields differ, they're different. */ - if (r1->addr != r2->addr || + if (!tor_addr_eq(&r1->ipv4_addr, &r2->ipv4_addr) || strcasecmp(r1->nickname, r2->nickname) || - r1->or_port != r2->or_port || + r1->ipv4_orport != r2->ipv4_orport || !tor_addr_eq(&r1->ipv6_addr, &r2->ipv6_addr) || r1->ipv6_orport != r2->ipv6_orport || - r1->dir_port != r2->dir_port || + r1->ipv4_dirport != r2->ipv4_dirport || r1->purpose != r2->purpose || r1->onion_pkey_len != r2->onion_pkey_len || !tor_memeq(r1->onion_pkey, r2->onion_pkey, r1->onion_pkey_len) || |