diff --git a/changes/ticket27490 b/changes/ticket27490 new file mode 100644 index 0000000000..523477dfea --- /dev/null +++ b/changes/ticket27490 @@ -0,0 +1,6 @@ + o Minor features (ipv6): + - We add an option ClientAutoIPv6ORPort which makes clients randomly + prefer a node's IPv4 or IPv6 ORPort. The random preference is set + every time a node is loaded from a new consensus or bridge config. + Closes ticket 27490. Patch by Neel Chauhan. + diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 406372433f..bd4dbbcbdb 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -1748,6 +1748,12 @@ The following options are useful only for clients (that is, if other clients prefer IPv4. Other things may influence the choice. This option breaks a tie to the favor of IPv6. (Default: auto) +[[ClientAutoIPv6ORPort]] **ClientAutoIPv6ORPort** **0**|**1**:: + If this option is set to 1, Tor clients randomly prefer a node's IPv4 or + IPv6 ORPort. The random preference is set every time a node is loaded + from a new consensus or bridge config. When this option is set to 1, + **ClientPreferIPv6ORPort** is ignored. (Default: 0) + [[PathsNeededToBuildCircuits]] **PathsNeededToBuildCircuits** __NUM__:: Tor clients don't build circuits for user traffic until they know about enough of the network so that they could potentially construct diff --git a/src/app/config/config.c b/src/app/config/config.c index 01b48e3c5f..6a510c56da 100644 --- a/src/app/config/config.c +++ b/src/app/config/config.c @@ -332,6 +332,7 @@ static config_var_t option_vars_[] = { V(ClientOnly, BOOL, "0"), V(ClientPreferIPv6ORPort, AUTOBOOL, "auto"), V(ClientPreferIPv6DirPort, AUTOBOOL, "auto"), + V(ClientAutoIPv6ORPort, BOOL, "0"), V(ClientRejectInternalAddresses, BOOL, "1"), V(ClientTransportPlugin, LINELIST, NULL), V(ClientUseIPv6, BOOL, "0"), diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h index 3524b99b53..ff3d30d7ec 100644 --- a/src/app/config/or_options_st.h +++ b/src/app/config/or_options_st.h @@ -666,6 +666,9 @@ struct or_options_t { * accessing this value directly. */ int ClientPreferIPv6DirPort; + /** If true, prefer an IPv4 or IPv6 OR port at random. */ + int ClientAutoIPv6ORPort; + /** The length of time that we think a consensus should be fresh. */ int V3AuthVotingInterval; /** The length of time we think it will take to distribute votes. */ diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c index 4231bec014..9f8169082c 100644 --- a/src/core/mainloop/connection.c +++ b/src/core/mainloop/connection.c @@ -2069,6 +2069,11 @@ connection_connect_log_client_use_ip_version(const connection_t *conn) return; } + if (fascist_firewall_use_ipv6(options)) { + log_info(LD_NET, "Our outgoing connection is using IPv%d.", + tor_addr_family(&real_addr) == AF_INET6 ? 6 : 4); + } + /* Check if we couldn't satisfy an address family preference */ if ((!pref_ipv6 && tor_addr_family(&real_addr) == AF_INET6) || (pref_ipv6 && tor_addr_family(&real_addr) == AF_INET)) { diff --git a/src/core/or/policies.c b/src/core/or/policies.c index 3443a17107..e51a49cf60 100644 --- a/src/core/or/policies.c +++ b/src/core/or/policies.c @@ -28,6 +28,7 @@ #include "feature/nodelist/routerparse.h" #include "feature/stats/geoip.h" #include "ht.h" +#include "lib/crypt_ops/crypto_rand.h" #include "lib/encoding/confline.h" #include "core/or/addr_policy_st.h" @@ -487,6 +488,15 @@ fascist_firewall_prefer_ipv6_impl(const or_options_t *options) return -1; } +/* Choose whether we prefer IPv4 or IPv6 by randomly choosing an address + * family. Return 0 for IPv4, and 1 for IPv6. */ +static int +fascist_firewall_rand_prefer_ipv6_addr(void) +{ + /* TODO: Check for failures, and infer our preference based on this. */ + return crypto_rand_int(2); +} + /** Do we prefer to connect to IPv6 ORPorts? * Use node_ipv6_or_preferred() whenever possible: it supports bridge client * per-node IPv6 preferences. @@ -501,7 +511,10 @@ fascist_firewall_prefer_ipv6_orport(const or_options_t *options) } /* We can use both IPv4 and IPv6 - which do we prefer? */ - if (options->ClientPreferIPv6ORPort == 1) { + if (options->ClientAutoIPv6ORPort == 1) { + /* If ClientAutoIPv6ORPort is 1, we prefer IPv4 or IPv6 at random. */ + return fascist_firewall_rand_prefer_ipv6_addr(); + } else if (options->ClientPreferIPv6ORPort == 1) { return 1; } diff --git a/src/feature/client/bridges.c b/src/feature/client/bridges.c index e8afb5a924..e3ed288415 100644 --- a/src/feature/client/bridges.c +++ b/src/feature/client/bridges.c @@ -844,7 +844,8 @@ rewrite_node_address_for_bridge(const bridge_info_t *bridge, node_t *node) } } - if (options->ClientPreferIPv6ORPort == -1) { + if (options->ClientPreferIPv6ORPort == -1 || + options->ClientAutoIPv6ORPort == 0) { /* 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));