diff --git a/src/feature/nodelist/routerlist.c b/src/feature/nodelist/routerlist.c index 72ea48898b..f606e3c18f 100644 --- a/src/feature/nodelist/routerlist.c +++ b/src/feature/nodelist/routerlist.c @@ -511,35 +511,34 @@ routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2) r1->ipv6_orport == r2->ipv6_orport; } -/** Add every suitable node from our nodelist to sl, so that - * we can pick a node for a circuit. +/* Returns true if node can be chosen based on flags. * - * If the following flags are set: - * - CRN_NEED_UPTIME: if any router has more than a minimum uptime, - * return one of those; - * - CRN_NEED_CAPACITY: weight your choice by the advertised capacity - * of each router; - * - CRN_NEED_GUARD: only consider Guard routers; - * - CRN_WEIGHT_AS_EXIT: we weight bandwidths as if picking an exit - * node, otherwise we weight bandwidths for - * picking a relay node (that is, possibly - * discounting exit nodes); - * - CRN_NEED_DESC: only consider nodes that have a routerinfo or - * microdescriptor -- that is, enough info to be - * used to build a circuit; - * - CRN_DIRECT_CONN: only consider nodes that are suitable for direct - * connections. Check ReachableAddresses, - * ClientUseIPv4 0, and + * The following conditions are applied to all nodes: + * - is running; + * - is valid; + * - has a general-purpose routerinfo; + * - supports EXTEND2 cells; + * - has an ntor circuit crypto key; and + * - does not allow single-hop exits. + * + * The flags chech that node: + * - CRN_NEED_UPTIME: has more than a minimum uptime; + * - CRN_NEED_CAPACITY: has more than a minimum capacity; + * - CRN_NEED_GUARD: is a Guard; + * - CRN_NEED_DESC: has a routerinfo or microdescriptor -- that is, + * enough info to be used to build a circuit; + * - CRN_DIRECT_CONN: is suitable for direct connections. Checks + * for the relevant descriptors. Checks the address + * against ReachableAddresses, ClientUseIPv4 0, and * fascist_firewall_use_ipv6() == 0); - * - CRN_PREF_ADDR: only consider nodes that have an address that is - * preferred by the ClientPreferIPv6ORPort setting. - * - CRN_RENDEZVOUS_V3: only consider nodes that can become v3 onion - * service rendezvous points. - * - CRN_INITIATE_IPV6_EXTEND: only consider routers than can initiate - * IPv6 extends. + * - CRN_PREF_ADDR: if we are connecting directly to the node, it has + * an address that is preferred by the + * ClientPreferIPv6ORPort setting; + * - CRN_RENDEZVOUS_V3: can become a v3 onion service rendezvous point; + * - CRN_INITIATE_IPV6_EXTEND: can initiate IPv6 extends. */ -void -router_add_running_nodes_to_smartlist(smartlist_t *sl, int flags) +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; @@ -555,38 +554,52 @@ router_add_running_nodes_to_smartlist(smartlist_t *sl, int flags) !router_or_conn_should_skip_reachable_address_check(get_options(), pref_addr); + if (!node->is_running || !node->is_valid) + return false; + if (need_desc && !node_has_preferred_descriptor(node, direct_conn)) + return false; + if (node->ri && 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 && + !fascist_firewall_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 sl, so that + * we can pick a node for a circuit based on flags. + * + * See router_can_choose_node() for details of flags. + */ +void +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; - /* 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)) - continue; - /* Exclude relays that can not become a rendezvous for a hidden service - * version 3. */ - if (rendezvous_v3 && - !node_supports_v3_rendezvous_point(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)) - continue; - if (initiate_ipv6_extend && !node_supports_initiating_ipv6_extends(node)) + if (!router_can_choose_node(node, flags)) continue; smartlist_add(sl, (void *)node); } SMARTLIST_FOREACH_END(node); diff --git a/src/feature/nodelist/routerlist.h b/src/feature/nodelist/routerlist.h index 7d0788bacb..98472b2771 100644 --- a/src/feature/nodelist/routerlist.h +++ b/src/feature/nodelist/routerlist.h @@ -58,6 +58,7 @@ int router_dir_conn_should_skip_reachable_address_check( int try_ip_pref); void router_reset_status_download_failures(void); int routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2); +bool router_can_choose_node(const node_t *node, int flags); void router_add_running_nodes_to_smartlist(smartlist_t *sl, int flags); const routerinfo_t *routerlist_find_my_routerinfo(void);