From 772577b547aa5e6b13b89f465acf656cd08f2917 Mon Sep 17 00:00:00 2001 From: "teor (Tim Wilson-Brown)" Date: Thu, 21 Jan 2016 13:30:57 +1100 Subject: [PATCH] Optimise reachability checks when iterating through relay lists Skip address checks on servers. Skip allowed-only address checks on non-bridge clients with IPv4. --- src/or/policies.c | 4 ++++ src/or/routerlist.c | 55 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/or/policies.c b/src/or/policies.c index 506edec394..0dc4f96c8b 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -323,6 +323,8 @@ firewall_is_fascist_impl(void) /** Return true iff the firewall options, including ClientUseIPv4 0 and * ClientUseIPv6 0, might block any OR address:port combination. + * Address preferences may still change which address is selected even if + * this function returns false. */ int firewall_is_fascist_or(void) @@ -332,6 +334,8 @@ firewall_is_fascist_or(void) /** Return true iff the firewall options, including ClientUseIPv4 0 and * ClientUseIPv6 0, might block any Dir address:port combination. + * Address preferences may still change which address is selected even if + * this function returns false. */ int firewall_is_fascist_dir(void) diff --git a/src/or/routerlist.c b/src/or/routerlist.c index 247818d8e6..9b8885e9c9 100644 --- a/src/or/routerlist.c +++ b/src/or/routerlist.c @@ -1623,6 +1623,30 @@ router_picked_poor_directory_log(const routerstatus_t *rs) } \ STMT_END +/* When iterating through the routerlist, can OR address/port preference + * and reachability checks be skipped? + */ +static int +router_skip_or_reachability(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, + * but there's no firewall, don't bother checking */ + return server_mode(options) || (!try_ip_pref && !firewall_is_fascist_or()); +} + +/* When iterating through the routerlist, can Dir address/port preference + * and reachability checks be skipped? + */ +static int +router_skip_dir_reachability(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, + * but there's no firewall, don't bother checking */ + return server_mode(options) || (!try_ip_pref && !firewall_is_fascist_dir()); +} + /** Pick a random running valid directory server/mirror from our * routerlist. Arguments are as for router_pick_directory_server(), except: * @@ -1661,6 +1685,9 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags, overloaded_direct = smartlist_new(); overloaded_tunnel = smartlist_new(); + const int skip_or = router_skip_or_reachability(options, try_ip_pref); + const int skip_dir = router_skip_dir_reachability(options, try_ip_pref); + /* Find all the running dirservers we know about. */ SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) { int is_trusted, is_trusted_extrainfo; @@ -1704,18 +1731,20 @@ router_pick_directory_server_impl(dirinfo_type_t type, int flags, is_overloaded = status->last_dir_503_at + DIR_503_TIMEOUT > now; - /* We use an IPv6 address if we have one and we prefer it. + /* Clients use IPv6 addresses if the server has one and the client + * prefers IPv6. * Add the router if its preferred address and port are reachable. * If we don't get any routers, we'll try again with the non-preferred * address for each router (if any). (To ensure correct load-balancing * we try routers that only have one address both times.) */ - if (!fascistfirewall || + if (!fascistfirewall || skip_or || fascist_firewall_allows_rs(status, FIREWALL_OR_CONNECTION, try_ip_pref)) smartlist_add(is_trusted ? trusted_tunnel : is_overloaded ? overloaded_tunnel : tunnel, (void*)node); - else if (fascist_firewall_allows_rs(status, FIREWALL_DIR_CONNECTION, + else if (skip_dir || + fascist_firewall_allows_rs(status, FIREWALL_DIR_CONNECTION, try_ip_pref)) smartlist_add(is_trusted ? trusted_direct : is_overloaded ? overloaded_direct : direct, (void*)node); @@ -1820,6 +1849,9 @@ router_pick_trusteddirserver_impl(const smartlist_t *sourcelist, overloaded_direct = smartlist_new(); overloaded_tunnel = smartlist_new(); + const int skip_or = router_skip_or_reachability(options, try_ip_pref); + const int skip_dir = router_skip_dir_reachability(options, try_ip_pref); + SMARTLIST_FOREACH_BEGIN(sourcelist, const dir_server_t *, d) { int is_overloaded = @@ -1845,17 +1877,19 @@ router_pick_trusteddirserver_impl(const smartlist_t *sourcelist, continue; } - /* We use an IPv6 address if we have one and we prefer it. + /* Clients use IPv6 addresses if the server has one and the client + * prefers IPv6. * Add the router if its preferred address and port are reachable. * If we don't get any routers, we'll try again with the non-preferred * address for each router (if any). (To ensure correct load-balancing * we try routers that only have one address both times.) */ - if (!fascistfirewall || + if (!fascistfirewall || skip_or || fascist_firewall_allows_dir_server(d, FIREWALL_OR_CONNECTION, try_ip_pref)) smartlist_add(is_overloaded ? overloaded_tunnel : tunnel, (void*)d); - else if (fascist_firewall_allows_dir_server(d, FIREWALL_DIR_CONNECTION, + else if (skip_dir || + fascist_firewall_allows_dir_server(d, FIREWALL_DIR_CONNECTION, try_ip_pref)) smartlist_add(is_overloaded ? overloaded_direct : direct, (void*)d); else if (!tor_addr_is_null(&d->ipv6_addr)) @@ -1965,7 +1999,10 @@ router_add_running_nodes_to_smartlist(smartlist_t *sl, int allow_invalid, int need_uptime, int need_capacity, int need_guard, int need_desc, int pref_addr) -{ /* XXXX MOVE */ +{ + const int check_reach = !router_skip_or_reachability(get_options(), + pref_addr); + /* XXXX MOVE */ SMARTLIST_FOREACH_BEGIN(nodelist_get_list(), const node_t *, node) { if (!node->is_running || (!node->is_valid && !allow_invalid)) @@ -1977,7 +2014,9 @@ router_add_running_nodes_to_smartlist(smartlist_t *sl, int allow_invalid, 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 (!fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION, pref_addr)) + if (check_reach && !fascist_firewall_allows_node(node, + FIREWALL_OR_CONNECTION, + pref_addr)) continue; smartlist_add(sl, (void *)node);