From c213f277cde00b258b159446f8d975026194c034 Mon Sep 17 00:00:00 2001 From: "teor (Tim Wilson-Brown)" Date: Wed, 3 Feb 2016 23:52:39 +1100 Subject: [PATCH] Make bridge clients prefer the configured bridge address When ClientPreferIPv6ORPort is auto, bridges prefer the configured bridge ORPort address. Otherwise, they use the value of the option. Other clients prefer IPv4 ORPorts if ClientPreferIPv6ORPort is auto. When ClientPreferIPv6DirPort is auto, all clients prefer IPv4 DirPorts. --- doc/tor.1.txt | 12 ++++++------ src/or/entrynodes.c | 22 ++++++++++++++++------ src/or/nodelist.c | 24 +++++++++++------------- src/or/policies.c | 18 +++++++----------- src/test/test_entrynodes.c | 10 ++++++---- src/test/test_policy.c | 25 +++++++++++++++---------- 6 files changed, 61 insertions(+), 50 deletions(-) diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 87d976b2fa..4c9c53d8cb 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -1504,17 +1504,17 @@ The following options are useful only for clients (that is, if If this option is set to 1, Tor prefers a directory port with an IPv6 address over one with IPv4, for direct connections, if a given directory server has both. (Tor also prefers an IPv6 DirPort if IPv4Client is set to - 0.) If this option is set to auto, Tor bridge clients prefer IPv6, and - other clients prefer IPv4. Other things may influence the choice. This - option breaks a tie to the favor of IPv6. (Default: auto) + 0.) If this option is set to auto, clients prefer IPv4. Other things may + influence the choice. This option breaks a tie to the favor of IPv6. + (Default: auto) [[ClientPreferIPv6ORPort]] **ClientPreferIPv6ORPort** **0**|**1**|**auto**:: If this option is set to 1, Tor prefers an OR port with an IPv6 address over one with IPv4 if a given entry node has both. (Tor also prefers an IPv6 ORPort if IPv4Client is set to 0.) If this option is set - to auto, Tor bridge clients prefer IPv6, and other clients prefer IPv4. - Other things may influence the choice. This option breaks a tie to the - favor of IPv6. (Default: auto) + to auto, Tor bridge clients prefer the configured bridge address, and + other clients prefer IPv4. Other things may influence the choice. This + option breaks a tie to the favor of IPv6. (Default: auto) [[PathsNeededToBuildCircuits]] **PathsNeededToBuildCircuits** __NUM__:: Tor clients don't build circuits for user traffic until they know diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c index d6bef658ff..a4b935065d 100644 --- a/src/or/entrynodes.c +++ b/src/or/entrynodes.c @@ -2240,6 +2240,7 @@ rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node) * does so through an address from any source other than node_get_addr(). */ tor_addr_t addr; + const or_options_t *options = get_options(); if (node->ri) { routerinfo_t *ri = node->ri; @@ -2272,9 +2273,15 @@ rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node) } } - /* Mark which address to use based on which bridge_t we got. */ - node->ipv6_preferred = (tor_addr_family(&bridge->addr) == AF_INET6 && - !tor_addr_is_null(&node->ri->ipv6_addr)); + if (options->ClientPreferIPv6ORPort == -1) { + /* Mark which address to use based on which bridge_t we got. */ + node->ipv6_preferred = (tor_addr_family(&bridge->addr) == AF_INET6 && + !tor_addr_is_null(&node->ri->ipv6_addr)); + } else { + /* Mark which address to use based on user preference */ + node->ipv6_preferred = (fascist_firewall_prefer_ipv6_orport(options) && + !tor_addr_is_null(&node->ri->ipv6_addr)); + } /* XXXipv6 we lack support for falling back to another address for the same relay, warn the user */ @@ -2283,10 +2290,13 @@ rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node) node_get_pref_orport(node, &ap); log_notice(LD_CONFIG, "Bridge '%s' has both an IPv4 and an IPv6 address. " - "Will prefer using its %s address (%s).", + "Will prefer using its %s address (%s) based on %s.", ri->nickname, - tor_addr_family(&ap.addr) == AF_INET6 ? "IPv6" : "IPv4", - fmt_addrport(&ap.addr, ap.port)); + node->ipv6_preferred ? "IPv6" : "IPv4", + fmt_addrport(&ap.addr, ap.port), + options->ClientPreferIPv6ORPort == -1 ? + "the configured Bridge address" : + "ClientPreferIPv6ORPort"); } } if (node->rs) { diff --git a/src/or/nodelist.c b/src/or/nodelist.c index d7cada94d3..23e9b0e176 100644 --- a/src/or/nodelist.c +++ b/src/or/nodelist.c @@ -981,10 +981,6 @@ node_has_ipv6_dirport(const node_t *node) * i) the node_t says that it prefers IPv6 * or * ii) the router has no IPv4 OR address. - * or - * iii) our preference is for IPv6 addresses. - * (This extra step is needed in case our preferences have changed since - * node->ipv6_preferred was set at the time the consensus was loaded.) */ int node_ipv6_or_preferred(const node_t *node) @@ -993,10 +989,12 @@ node_ipv6_or_preferred(const node_t *node) tor_addr_port_t ipv4_addr; node_assert_ok(node); + /* XX/teor - node->ipv6_preferred is set from + * fascist_firewall_prefer_ipv6_orport() each time the consensus is loaded. + */ if (!fascist_firewall_use_ipv6(options)) { return 0; - } else if (node->ipv6_preferred || node_get_prim_orport(node, &ipv4_addr) - || fascist_firewall_prefer_ipv6_orport(get_options())) { + } else if (node->ipv6_preferred || node_get_prim_orport(node, &ipv4_addr)) { return node_has_ipv6_orport(node); } return 0; @@ -1077,13 +1075,9 @@ node_get_pref_ipv6_orport(const node_t *node, tor_addr_port_t *ap_out) * * We prefer the IPv6 address if the router has an IPv6 address, * and we can use IPv6 addresses, and: - * i) the node_t says that it prefers IPv6 + * i) the router has no IPv4 Dir address. * or - * ii) the router has no IPv4 Dir address. - * or - * iii) our preference is for IPv6 addresses. - * (This extra step is needed in case our preferences have changed since - * node->ipv6_preferred was set at the time the consensus was loaded.) + * ii) our preference is for IPv6 Dir addresses. */ int node_ipv6_dir_preferred(const node_t *node) @@ -1092,9 +1086,13 @@ node_ipv6_dir_preferred(const node_t *node) tor_addr_port_t ipv4_addr; node_assert_ok(node); + /* node->ipv6_preferred is set from fascist_firewall_prefer_ipv6_orport(), + * so we can't use it to determine DirPort IPv6 preference. + * This means that bridge clients will use IPv4 DirPorts by default. + */ if (!fascist_firewall_use_ipv6(options)) { return 0; - } else if (node->ipv6_preferred || node_get_prim_dirport(node, &ipv4_addr) + } else if (node_get_prim_dirport(node, &ipv4_addr) || fascist_firewall_prefer_ipv6_dirport(get_options())) { return node_has_ipv6_dirport(node); } diff --git a/src/or/policies.c b/src/or/policies.c index 734558d836..e2cece56e4 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -458,6 +458,13 @@ fascist_firewall_prefer_ipv6_impl(const or_options_t *options) int fascist_firewall_prefer_ipv6_orport(const or_options_t *options) { + /* node->ipv6_preferred is set from fascist_firewall_prefer_ipv6_orport() + * each time the consensus is loaded. + * If our preferences change, we will only reset ipv6_preferred on the node + * when the next consensus is loaded. But the consensus is realoded when the + * configuration changes after a HUP. So as long as the result of this + * function only depends on Tor's options, everything should work ok. + */ int pref_ipv6 = fascist_firewall_prefer_ipv6_impl(options); if (pref_ipv6 >= 0) { @@ -469,11 +476,6 @@ fascist_firewall_prefer_ipv6_orport(const or_options_t *options) return 1; } - /* For bridge clients, ClientPreferIPv6ORPort auto means "prefer IPv6". */ - if (options->UseBridges && options->ClientPreferIPv6ORPort != 0) { - return 1; - } - return 0; } @@ -493,12 +495,6 @@ fascist_firewall_prefer_ipv6_dirport(const or_options_t *options) return 1; } - /* For bridge clients, ClientPreferIPv6ORPort auto means "prefer IPv6". - * XX/teor - do bridge clients ever use a DirPort? */ - if (options->UseBridges && options->ClientPreferIPv6DirPort != 0) { - return 1; - } - return 0; } diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c index 14baa8c9bf..fd19db095d 100644 --- a/src/test/test_entrynodes.c +++ b/src/test/test_entrynodes.c @@ -9,14 +9,16 @@ #include "or.h" #include "test.h" + +#include "config.h" #include "entrynodes.h" -#include "routerparse.h" #include "nodelist.h" -#include "util.h" +#include "policies.h" #include "routerlist.h" +#include "routerparse.h" #include "routerset.h" #include "statefile.h" -#include "config.h" +#include "util.h" #include "test_helpers.h" @@ -826,7 +828,7 @@ test_node_preferred_orport(void *arg) * ClientUseIPv4 is 0 */ mocked_options.ClientUseIPv4 = 0; mocked_options.ClientUseIPv6 = 1; - node.ipv6_preferred = 0; + node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(&mocked_options); node_get_pref_orport(&node, &ap); tt_assert(tor_addr_eq(&ap.addr, &ipv6_addr)); tt_assert(ap.port == ipv6_port); diff --git a/src/test/test_policy.c b/src/test/test_policy.c index b4cbfb2579..c044d9f210 100644 --- a/src/test/test_policy.c +++ b/src/test/test_policy.c @@ -1510,21 +1510,25 @@ test_policies_fascist_firewall_choose_address(void *arg) FIREWALL_DIR_CONNECTION, 1) == &ipv4_dir_ap); - /* Auto (Preferring IPv6 for bridge clients) */ + /* Auto: + * - bridge clients prefer the configured bridge OR address, + * - other clients prefer IPv4 OR by default, + * - all clients prefer IPv4 Dir by default. + */ mock_options.ClientPreferIPv6ORPort = -1; mock_options.ClientPreferIPv6DirPort = -1; tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, FIREWALL_OR_CONNECTION, 0) - == &ipv6_or_ap); + == &ipv4_or_ap); tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, FIREWALL_OR_CONNECTION, 1) - == &ipv6_or_ap); + == &ipv4_or_ap); tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, FIREWALL_DIR_CONNECTION, 0) - == &ipv6_dir_ap); + == &ipv4_dir_ap); tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, FIREWALL_DIR_CONNECTION, 1) - == &ipv6_dir_ap); + == &ipv4_dir_ap); /* Preferring IPv6 */ mock_options.ClientPreferIPv6ORPort = 1; @@ -1544,22 +1548,23 @@ test_policies_fascist_firewall_choose_address(void *arg) /* In the default configuration (Auto / IPv6 off), bridge clients should - * still use and prefer IPv6 regardless of ClientUseIPv6. */ + * still use IPv6, and only prefer it for bridges configured with an IPv6 + * address, regardless of ClientUseIPv6. */ mock_options.ClientUseIPv6 = 0; mock_options.ClientPreferIPv6ORPort = -1; mock_options.ClientPreferIPv6DirPort = -1; tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, FIREWALL_OR_CONNECTION, 0) - == &ipv6_or_ap); + == &ipv4_or_ap); tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, FIREWALL_OR_CONNECTION, 1) - == &ipv6_or_ap); + == &ipv4_or_ap); tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, FIREWALL_DIR_CONNECTION, 0) - == &ipv6_dir_ap); + == &ipv4_dir_ap); tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, FIREWALL_DIR_CONNECTION, 1) - == &ipv6_dir_ap); + == &ipv4_dir_ap); /* Choose an address with IPv4 on */ memset(&mock_options, 0, sizeof(or_options_t));