Browse Source

Add new option ClientAutoIPv6ORPort to switch between IPv4 and IPv6 OR ports

Neel Chauhan 7 years ago
parent
commit
822cb93cab

+ 6 - 0
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.
+

+ 6 - 0
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
     other clients prefer IPv4. Other things may influence the choice. This
     option breaks a tie to the favor of IPv6. (Default: auto)
     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__::
 [[PathsNeededToBuildCircuits]] **PathsNeededToBuildCircuits** __NUM__::
     Tor clients don't build circuits for user traffic until they know
     Tor clients don't build circuits for user traffic until they know
     about enough of the network so that they could potentially construct
     about enough of the network so that they could potentially construct

+ 1 - 0
src/app/config/config.c

@@ -332,6 +332,7 @@ static config_var_t option_vars_[] = {
   V(ClientOnly,                  BOOL,     "0"),
   V(ClientOnly,                  BOOL,     "0"),
   V(ClientPreferIPv6ORPort,      AUTOBOOL, "auto"),
   V(ClientPreferIPv6ORPort,      AUTOBOOL, "auto"),
   V(ClientPreferIPv6DirPort,     AUTOBOOL, "auto"),
   V(ClientPreferIPv6DirPort,     AUTOBOOL, "auto"),
+  V(ClientAutoIPv6ORPort,        BOOL,     "0"),
   V(ClientRejectInternalAddresses, BOOL,   "1"),
   V(ClientRejectInternalAddresses, BOOL,   "1"),
   V(ClientTransportPlugin,       LINELIST, NULL),
   V(ClientTransportPlugin,       LINELIST, NULL),
   V(ClientUseIPv6,               BOOL,     "0"),
   V(ClientUseIPv6,               BOOL,     "0"),

+ 3 - 0
src/app/config/or_options_st.h

@@ -666,6 +666,9 @@ struct or_options_t {
    * accessing this value directly.  */
    * accessing this value directly.  */
   int ClientPreferIPv6DirPort;
   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. */
   /** The length of time that we think a consensus should be fresh. */
   int V3AuthVotingInterval;
   int V3AuthVotingInterval;
   /** The length of time we think it will take to distribute votes. */
   /** The length of time we think it will take to distribute votes. */

+ 5 - 0
src/core/mainloop/connection.c

@@ -2069,6 +2069,11 @@ connection_connect_log_client_use_ip_version(const connection_t *conn)
     return;
     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 */
   /* Check if we couldn't satisfy an address family preference */
   if ((!pref_ipv6 && tor_addr_family(&real_addr) == AF_INET6)
   if ((!pref_ipv6 && tor_addr_family(&real_addr) == AF_INET6)
       || (pref_ipv6 && tor_addr_family(&real_addr) == AF_INET)) {
       || (pref_ipv6 && tor_addr_family(&real_addr) == AF_INET)) {

+ 14 - 1
src/core/or/policies.c

@@ -28,6 +28,7 @@
 #include "feature/nodelist/routerparse.h"
 #include "feature/nodelist/routerparse.h"
 #include "feature/stats/geoip.h"
 #include "feature/stats/geoip.h"
 #include "ht.h"
 #include "ht.h"
+#include "lib/crypt_ops/crypto_rand.h"
 #include "lib/encoding/confline.h"
 #include "lib/encoding/confline.h"
 
 
 #include "core/or/addr_policy_st.h"
 #include "core/or/addr_policy_st.h"
@@ -487,6 +488,15 @@ fascist_firewall_prefer_ipv6_impl(const or_options_t *options)
   return -1;
   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?
 /** Do we prefer to connect to IPv6 ORPorts?
  * Use node_ipv6_or_preferred() whenever possible: it supports bridge client
  * Use node_ipv6_or_preferred() whenever possible: it supports bridge client
  * per-node IPv6 preferences.
  * 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? */
   /* 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;
     return 1;
   }
   }
 
 

+ 2 - 1
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. */
       /* Mark which address to use based on which bridge_t we got. */
       node->ipv6_preferred = (tor_addr_family(&bridge->addr) == AF_INET6 &&
       node->ipv6_preferred = (tor_addr_family(&bridge->addr) == AF_INET6 &&
                               !tor_addr_is_null(&node->ri->ipv6_addr));
                               !tor_addr_is_null(&node->ri->ipv6_addr));