[tor-commits] [tor/master] Build and test most of the machinery needed for IPv6 virtualaddrmaps

nickm at torproject.org nickm at torproject.org
Mon Dec 17 20:49:21 UTC 2012


commit de4cc126cbb5e663bdd048fd782fde869be7b80a
Author: Nick Mathewson <nickm at torproject.org>
Date:   Fri Nov 23 17:31:53 2012 -0500

    Build and test most of the machinery needed for IPv6 virtualaddrmaps
    
    With an IPv6 virtual address map, we can basically hand out a new
    IPv6 address for _every_ address we connect to.  That'll be cool, and
    will let us maybe get around prop205 issues.
    
    This uses some fancy logic to try to make the code paths in the ipv4
    and the ipv6 case as close as possible, and moves to randomly
    generated addresses so we don't need to maintain those stupid counters
    that will collide if Tor restarts but apps don't.
    
    Also has some XXXX items to fix to make this useful. More design
    needed.
---
 doc/tor.1.txt            |   16 +++--
 src/or/addressmap.c      |  182 ++++++++++++++++++++++++++++++----------------
 src/or/addressmap.h      |   13 +++-
 src/or/config.c          |   19 ++++-
 src/or/connection_edge.c |    5 +-
 src/or/control.c         |    9 ++-
 src/or/or.h              |    6 +-
 src/test/test_addr.c     |   71 ++++++++++++++++++
 8 files changed, 239 insertions(+), 82 deletions(-)

diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index 5cf7ff7..ec350ba 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -1040,16 +1040,20 @@ The following options are useful only for clients (that is, if
     applications to do DNS resolves themselves is usually a bad idea and
     can leak your location to attackers. (Default: 1)
 
-**VirtualAddrNetwork** __Address__/__bits__::
+**VirtualAddrNetworkIPv4** __Address__/__bits__ +
+
+**VirtualAddrNetworkIPv6** [__Address__]/__bits__::
     When Tor needs to assign a virtual (unused) address because of a MAPADDRESS
     command from the controller or the AutomapHostsOnResolve feature, Tor
-    picks an unassigned address from this range. (Default:
-    127.192.0.0/10) +
+    picks an unassigned address from this range. (Defaults:
+    127.192.0.0/10 and [FE80::]/10 respectively.) +
  +
     When providing proxy server service to a network of computers using a tool
-    like dns-proxy-tor, change this address to "10.192.0.0/10" or
-    "172.16.0.0/12". The default **VirtualAddrNetwork** address range on a
-    properly configured machine will route to the loopback interface. For
+    like dns-proxy-tor, change the IPv4 network to "10.192.0.0/10" or
+    "172.16.0.0/12" and change the IPv6 network to "[FC00]/7".
+    The default **VirtualAddrNetwork** address ranges on a
+    properly configured machine will route to the loopback or link-local
+    interface. For
     local use, no change to the default VirtualAddrNetwork setting is needed.
 
 **AllowNonRFC953Hostnames** **0**|**1**::
diff --git a/src/or/addressmap.c b/src/or/addressmap.c
index 8502178..e1efbf4 100644
--- a/src/or/addressmap.c
+++ b/src/or/addressmap.c
@@ -4,6 +4,8 @@
  * Copyright (c) 2007-2012, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
+#define ADDRESSMAP_PRIVATE
+
 #include "or.h"
 #include "addressmap.h"
 #include "circuituse.h"
@@ -52,11 +54,13 @@ typedef struct {
 /** Entry for mapping addresses to which virtual address we mapped them to. */
 typedef struct {
   char *ipv4_address;
+  char *ipv6_address;
   char *hostname_address;
 } virtaddress_entry_t;
 
 /** A hash table to store client-side address rewrite instructions. */
 static strmap_t *addressmap=NULL;
+
 /**
  * Table mapping addresses to which virtual address, if any, we
  * assigned them to.
@@ -714,13 +718,9 @@ client_dns_set_reverse_addressmap(entry_connection_t *for_conn,
  *
  * These options are configured by parse_virtual_addr_network().
  */
-/** Which network should we use for virtual IPv4 addresses?  Only the first
- * bits of this value are fixed. */
-static uint32_t virtual_addr_network = 0x7fc00000u;
-/** How many bits of <b>virtual_addr_network</b> are fixed? */
-static maskbits_t virtual_addr_netmask_bits = 10;
-/** What's the next virtual address we will hand out? */
-static uint32_t next_virtual_addr    = 0x7fc00000u;
+
+static virtual_addr_conf_t virtaddr_conf_ipv4;
+static virtual_addr_conf_t virtaddr_conf_ipv6;
 
 /** Read a netmask of the form 127.192.0.0/10 from "val", and check whether
  * it's a valid set of virtual addresses to hand out in response to MAPADDRESS
@@ -728,37 +728,49 @@ static uint32_t next_virtual_addr    = 0x7fc00000u;
  * string and return -1 on failure.  If validate_only is false, sets the
  * actual virtual address range to the parsed value. */
 int
-parse_virtual_addr_network(const char *val, int validate_only,
+parse_virtual_addr_network(const char *val, sa_family_t family,
+                           int validate_only,
                            char **msg)
 {
-  uint32_t addr;
-  uint16_t port_min, port_max;
+  const int ipv6 = (family == AF_INET6);
+  tor_addr_t addr;
   maskbits_t bits;
+  const int max_bits = ipv6 ? 40 : 16;
+  virtual_addr_conf_t *conf = ipv6 ? &virtaddr_conf_ipv6 : &virtaddr_conf_ipv4;
 
-  if (parse_addr_and_port_range(val, &addr, &bits, &port_min, &port_max)) {
-    if (msg) *msg = tor_strdup("Error parsing VirtualAddressNetwork");
+  if (tor_addr_parse_mask_ports(val, 0, &addr, &bits, NULL, NULL) < 0) {
+    if (msg)
+      tor_asprintf(msg, "Error parsing VirtualAddressNetwork%s %s",
+                   ipv6?"IPv6":"", val);
     return -1;
   }
-
+  if (tor_addr_family(&addr) != family) {
+    if (msg)
+      tor_asprintf(msg, "Incorrect address type for VirtualAddressNetwork%s",
+                   ipv6?"IPv6":"");
+    return -1;
+  }
+#if 0
   if (port_min != 1 || port_max != 65535) {
-    if (msg) *msg = tor_strdup("Can't specify ports on VirtualAddressNetwork");
+    if (msg)
+      tor_asprintf(msg, "Can't specify ports on VirtualAddressNetwork%s",
+                   ipv6?"IPv6":"");
     return -1;
   }
+#endif
 
-  if (bits > 16) {
-    if (msg) *msg = tor_strdup("VirtualAddressNetwork expects a /16 "
-                               "network or larger");
+  if (bits > max_bits) {
+    if (msg)
+      tor_asprintf(msg, "VirtualAddressNetwork%s expects a /%d "
+                   "network or larger",ipv6?"IPv6":"", max_bits);
     return -1;
   }
 
   if (validate_only)
     return 0;
 
-  virtual_addr_network = (uint32_t)( addr & (0xfffffffful << (32-bits)) );
-  virtual_addr_netmask_bits = bits;
-
-  if (addr_mask_cmp_bits(next_virtual_addr, addr, bits))
-    next_virtual_addr = addr;
+  tor_addr_copy(&conf->addr, &addr);
+  conf->bits = bits;
 
   return 0;
 }
@@ -770,29 +782,60 @@ parse_virtual_addr_network(const char *val, int validate_only,
 int
 address_is_in_virtual_range(const char *address)
 {
-  struct in_addr in;
+  tor_addr_t addr;
   tor_assert(address);
   if (!strcasecmpend(address, ".virtual")) {
     return 1;
-  } else if (tor_inet_aton(address, &in)) {
-    uint32_t addr = ntohl(in.s_addr);
-    if (!addr_mask_cmp_bits(addr, virtual_addr_network,
-                            virtual_addr_netmask_bits))
+  } else if (tor_addr_parse(&addr, address) >= 0) {
+    const virtual_addr_conf_t *conf = (tor_addr_family(&addr) == AF_INET6) ?
+      &virtaddr_conf_ipv6 : &virtaddr_conf_ipv4;
+    if (tor_addr_compare_masked(&addr, &conf->addr, conf->bits, CMP_EXACT)==0)
       return 1;
   }
   return 0;
 }
 
-/** Increment the value of next_virtual_addr; reset it to the start of the
- * virtual address range if it wraps around.
+/** Return a random address conforming to the virtual address configuration
+ * in <b>conf</b>.
  */
-static INLINE void
-increment_virtual_addr(void)
+/* private */ void
+get_random_virtual_addr(const virtual_addr_conf_t *conf, tor_addr_t *addr_out)
 {
-  ++next_virtual_addr;
-  if (addr_mask_cmp_bits(next_virtual_addr, virtual_addr_network,
-                         virtual_addr_netmask_bits))
-    next_virtual_addr = virtual_addr_network;
+  uint8_t tmp[4];
+  const uint8_t *addr_bytes;
+  uint8_t bytes[16];
+  const int ipv6 = tor_addr_family(&conf->addr) == AF_INET6;
+  const int total_bytes = ipv6 ? 16 : 4;
+
+  tor_assert(conf->bits <= total_bytes * 8);
+
+  /* Set addr_bytes to the bytes of the virtual network, in host order */
+  if (ipv6) {
+    addr_bytes = tor_addr_to_in6_addr8(&conf->addr);
+  } else {
+    set_uint32(tmp, tor_addr_to_ipv4n(&conf->addr));
+    addr_bytes = tmp;
+  }
+
+  /* Get an appropriate number of random bytes. */
+  crypto_rand((char*)bytes, total_bytes);
+
+  /* Now replace the first "conf->bits" bits of 'bytes' with addr_bytes*/
+  if (conf->bits >= 8)
+    memcpy(bytes, addr_bytes, conf->bits / 8);
+  if (conf->bits & 7) {
+    uint8_t mask = 0xff >> (conf->bits & 7);
+    bytes[conf->bits/8] &= mask;
+    bytes[conf->bits/8] |= addr_bytes[conf->bits/8] & ~mask;
+  }
+
+  if (ipv6)
+    tor_addr_from_ipv6_bytes(addr_out, (char*) bytes);
+  else
+    tor_addr_from_ipv4n(addr_out, get_uint32(bytes));
+
+  tor_assert(tor_addr_compare_masked(addr_out, &conf->addr,
+                                     conf->bits, CMP_EXACT)==0);
 }
 
 /** Return a newly allocated string holding an address of <b>type</b>
@@ -815,37 +858,44 @@ addressmap_get_virtual_address(int type)
       strlcat(buf, ".virtual", sizeof(buf));
     } while (strmap_get(addressmap, buf));
     return tor_strdup(buf);
-  } else if (type == RESOLVED_TYPE_IPV4) {
+  } else if (type == RESOLVED_TYPE_IPV4 || type == RESOLVED_TYPE_IPV6) {
+    const int ipv6 = (type == RESOLVED_TYPE_IPV6);
+    const virtual_addr_conf_t *conf = ipv6 ?
+      &virtaddr_conf_ipv6 : &virtaddr_conf_ipv4;
+
     // This is an imperfect estimate of how many addresses are available, but
-    // that's ok.
-    struct in_addr in;
-    uint32_t available = 1u << (32-virtual_addr_netmask_bits);
-    while (available) {
-      /* Don't hand out any .0 or .255 address. */
-      while ((next_virtual_addr & 0xff) == 0 ||
-             (next_virtual_addr & 0xff) == 0xff) {
-        increment_virtual_addr();
-        if (! --available) {
-          log_warn(LD_CONFIG, "Ran out of virtual addresses!");
-          return NULL;
-        }
+    // that's ok.  We also don't try every one.
+    uint32_t attempts = ipv6 ? UINT32_MAX : (1u << (32- conf->bits));
+
+    tor_addr_t addr;
+
+    while (attempts--) {
+      get_random_virtual_addr(conf, &addr);
+
+      if (!ipv6) {
+        /* Don't hand out any .0 or .255 address. */
+        const uint32_t a = tor_addr_to_ipv4h(&addr);
+        if ((a & 0xff) == 0 || (a & 0xff) == 0xff)
+          continue;
       }
-      in.s_addr = htonl(next_virtual_addr);
-      tor_inet_ntoa(&in, buf, sizeof(buf));
+
+      tor_addr_to_str(buf, &addr, sizeof(buf), 1);
       if (!strmap_get(addressmap, buf)) {
-        increment_virtual_addr();
-        break;
-      }
+        /* XXXX This code is to make sure I didn't add an undecorated version
+         * by mistake. I hope it's needless. */
+        char tmp[TOR_ADDR_BUF_LEN];
+        tor_addr_to_str(buf, &addr, sizeof(tmp), 0);
+        if (strmap_get(addressmap, tmp)) {
+          log_warn(LD_BUG, "%s wasn't in the addressmap, but %s was.",
+                   buf, tmp);
+          continue;
+        }
 
-      increment_virtual_addr();
-      --available;
-      // log_info(LD_CONFIG, "%d addrs available", (int)available);
-      if (! available) {
-        log_warn(LD_CONFIG, "Ran out of virtual addresses!");
-        return NULL;
+        return tor_strdup(buf);
       }
     }
-    return tor_strdup(buf);
+    log_warn(LD_CONFIG, "Ran out of virtual addresses!");
+    return NULL;
   } else {
     log_warn(LD_BUG, "Called with unsupported address type (%d)", type);
     return NULL;
@@ -878,8 +928,13 @@ addressmap_register_virtual_address(int type, char *new_address)
     vent_needs_to_be_added = 1;
   }
 
-  addrp = (type == RESOLVED_TYPE_IPV4) ?
-    &vent->ipv4_address : &vent->hostname_address;
+  if (type == RESOLVED_TYPE_IPV4)
+    addrp = &vent->ipv4_address;
+  else if (type == RESOLVED_TYPE_IPV6)
+    addrp = &vent->ipv6_address;
+  else
+    addrp = &vent->hostname_address;
+
   if (*addrp) {
     addressmap_entry_t *ent = strmap_get(addressmap, *addrp);
     if (ent && ent->new_address &&
@@ -887,7 +942,7 @@ addressmap_register_virtual_address(int type, char *new_address)
       tor_free(new_address);
       tor_assert(!vent_needs_to_be_added);
       return tor_strdup(*addrp);
-    } else
+    } else {
       log_warn(LD_BUG,
                "Internal confusion: I thought that '%s' was mapped to by "
                "'%s', but '%s' really maps to '%s'. This is a harmless bug.",
@@ -895,6 +950,7 @@ addressmap_register_virtual_address(int type, char *new_address)
                safe_str_client(*addrp),
                safe_str_client(*addrp),
                ent?safe_str_client(ent->new_address):"(nothing)");
+    }
   }
 
   tor_free(*addrp);
diff --git a/src/or/addressmap.h b/src/or/addressmap.h
index 4534fff..3f1c445 100644
--- a/src/or/addressmap.h
+++ b/src/or/addressmap.h
@@ -27,7 +27,8 @@ void addressmap_register(const char *address, char *new_address,
                          time_t expires, addressmap_entry_source_t source,
                          const int address_wildcard,
                          const int new_address_wildcard);
-int parse_virtual_addr_network(const char *val, int validate_only,
+int parse_virtual_addr_network(const char *val,
+                               sa_family_t family, int validate_only,
                                char **msg);
 int client_dns_incr_failures(const char *address);
 void client_dns_clear_failures(const char *address);
@@ -45,5 +46,15 @@ void client_dns_set_reverse_addressmap(entry_connection_t *for_conn,
 int addressmap_address_should_automap(const char *address,
                                       const or_options_t *options);
 
+#ifdef ADDRESSMAP_PRIVATE
+typedef struct virtual_addr_conf_t {
+  tor_addr_t addr;
+  maskbits_t bits;
+} virtual_addr_conf_t;
+
+void get_random_virtual_addr(const virtual_addr_conf_t *conf,
+                             tor_addr_t *addr_out);
+#endif
+
 #endif
 
diff --git a/src/or/config.c b/src/or/config.c
index 04f512b..60028f2 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -98,6 +98,7 @@ static config_abbrev_t option_abbrevs_[] = {
   { "HashedControlPassword", "__HashedControlSessionPassword", 1, 0},
   { "StrictEntryNodes", "StrictNodes", 0, 1},
   { "StrictExitNodes", "StrictNodes", 0, 1},
+  { "VirtualAddrNetwork", "VirtualAddrNetworkIPv4", 0, 0},
   { "_UseFilteringSSLBufferevents", "UseFilteringSSLBufferevents", 0, 1},
   { NULL, NULL, 0, 0},
 };
@@ -396,7 +397,8 @@ static config_var_t option_vars_[] = {
   V(V3AuthUseLegacyKey,          BOOL,     "0"),
   V(V3BandwidthsFile,            FILENAME, NULL),
   VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "0"),
-  V(VirtualAddrNetwork,          STRING,   "127.192.0.0/10"),
+  V(VirtualAddrNetworkIPv4,      STRING,   "127.192.0.0/10"),
+  V(VirtualAddrNetworkIPv6,      STRING,   "[FE80::]/10"),
   V(WarnPlaintextPorts,          CSV,      "23,109,110,143"),
   V(UseFilteringSSLBufferevents, BOOL,    "0"),
   VAR("__ReloadTorrcOnSIGHUP",   BOOL,  ReloadTorrcOnSIGHUP,      "1"),
@@ -1379,7 +1381,8 @@ options_act(const or_options_t *old_options)
 
   /* Register addressmap directives */
   config_register_addressmaps(options);
-  parse_virtual_addr_network(options->VirtualAddrNetwork, 0, NULL);
+  parse_virtual_addr_network(options->VirtualAddrNetworkIPv4, AF_INET,0,NULL);
+  parse_virtual_addr_network(options->VirtualAddrNetworkIPv6, AF_INET6,0,NULL);
 
   /* Update address policies. */
   if (policies_parse_from_options(options) < 0) {
@@ -1492,8 +1495,10 @@ options_act(const or_options_t *old_options)
       if (!smartlist_strings_eq(old_options->AutomapHostsSuffixes,
                                 options->AutomapHostsSuffixes))
         revise_automap_entries = 1;
-      else if (!opt_streq(old_options->VirtualAddrNetwork,
-                          options->VirtualAddrNetwork))
+      else if (!opt_streq(old_options->VirtualAddrNetworkIPv4,
+                          options->VirtualAddrNetworkIPv4) ||
+               !opt_streq(old_options->VirtualAddrNetworkIPv6,
+                          options->VirtualAddrNetworkIPv6))
         revise_automap_entries = 1;
     }
 
@@ -2968,7 +2973,11 @@ options_validate(or_options_t *old_options, or_options_t *options,
     REJECT("Failed to configure client authorization for hidden services. "
            "See logs for details.");
 
-  if (parse_virtual_addr_network(options->VirtualAddrNetwork, 1, NULL)<0)
+  if (parse_virtual_addr_network(options->VirtualAddrNetworkIPv4,
+                                 AF_INET, 1, msg)<0)
+    return -1;
+  if (parse_virtual_addr_network(options->VirtualAddrNetworkIPv6,
+                                 AF_INET6, 1, msg)<0)
     return -1;
 
   if (options->PreferTunneledDirConns && !options->TunnelDirConns)
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 9ccf58e..9608026 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -897,7 +897,7 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
   socks_request_t *socks = conn->socks_request;
   hostname_type_t addresstype;
   const or_options_t *options = get_options();
-  struct in_addr addr_tmp;
+  tor_addr_t addr_tmp;
   /* We set this to true if this is an address we should automatically
    * remap to a local address in VirtualAddrNetwork */
   int automap = 0;
@@ -927,11 +927,12 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
     conn->original_dest_address = tor_strdup(conn->socks_request->address);
 
   if (socks->command == SOCKS_COMMAND_RESOLVE &&
-      !tor_inet_aton(socks->address, &addr_tmp) &&
+      tor_addr_parse(&addr_tmp, socks->address)<0 &&
       options->AutomapHostsOnResolve) {
     automap = addressmap_address_should_automap(socks->address, options);
     if (automap) {
       const char *new_addr;
+      /*XXXX IPv6 Sometimes this should be RESOLVED_TYPE_IPV6 */
       new_addr = addressmap_register_virtual_address(
                               RESOLVED_TYPE_IPV4, tor_strdup(socks->address));
       if (! new_addr) {
diff --git a/src/or/control.c b/src/or/control.c
index 75c9af6..65689c4 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -1373,10 +1373,13 @@ handle_control_mapaddress(control_connection_t *conn, uint32_t len,
                      "512-syntax error: invalid address '%s'", to);
         log_warn(LD_CONTROL,
                  "Skipping invalid argument '%s' in MapAddress msg", to);
-      } else if (!strcmp(from, ".") || !strcmp(from, "0.0.0.0")) {
+      } else if (!strcmp(from, ".") || !strcmp(from, "0.0.0.0") ||
+                 !strcmp(from, "::")) {
+        const char type =
+          !strcmp(from,".") ? RESOLVED_TYPE_HOSTNAME :
+          (!strcmp(from, "0.0.0.0") ? RESOLVED_TYPE_IPV4 : RESOLVED_TYPE_IPV6);
         const char *address = addressmap_register_virtual_address(
-              !strcmp(from,".") ? RESOLVED_TYPE_HOSTNAME : RESOLVED_TYPE_IPV4,
-               tor_strdup(to));
+                                                     type, tor_strdup(to));
         if (!address) {
           smartlist_add_asprintf(reply,
                        "451-resource exhausted: skipping '%s'", line);
diff --git a/src/or/or.h b/src/or/or.h
index a2c4122..5b60193 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -3588,8 +3588,10 @@ typedef struct {
   /** Should we fetch our dir info at the start of the consensus period? */
   int FetchDirInfoExtraEarly;
 
-  char *VirtualAddrNetwork; /**< Address and mask to hand out for virtual
-                             * MAPADDRESS requests. */
+  char *VirtualAddrNetworkIPv4; /**< Address and mask to hand out for virtual
+                                 * MAPADDRESS requests for IPv4 addresses */
+  char *VirtualAddrNetworkIPv6; /**< Address and mask to hand out for virtual
+                                 * MAPADDRESS requests for IPv6 addresses */
   int ServerDNSSearchDomains; /**< Boolean: If set, we don't force exit
                       * addresses to be FQDNs, but rather search for them in
                       * the local domains. */
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index d2b25e5..eea0fcd 100644
--- a/src/test/test_addr.c
+++ b/src/test/test_addr.c
@@ -3,9 +3,11 @@
  * Copyright (c) 2007-2012, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 
+#define ADDRESSMAP_PRIVATE
 #include "orconfig.h"
 #include "or.h"
 #include "test.h"
+#include "addressmap.h"
 
 static void
 test_addr_basic(void)
@@ -773,6 +775,74 @@ test_addr_parse(void)
   ;
 }
 
+static void
+update_difference(int ipv6, uint8_t *d,
+                  const tor_addr_t *a, const tor_addr_t *b)
+{
+  const int n_bytes = ipv6 ? 16 : 4;
+  uint8_t a_tmp[4], b_tmp[4];
+  const uint8_t *ba, *bb;
+  int i;
+
+  if (ipv6) {
+    ba = tor_addr_to_in6_addr8(a);
+    bb = tor_addr_to_in6_addr8(b);
+  } else {
+    set_uint32(a_tmp, tor_addr_to_ipv4n(a));
+    set_uint32(b_tmp, tor_addr_to_ipv4n(b));
+    ba = a_tmp; bb = b_tmp;
+  }
+
+  for (i = 0; i < n_bytes; ++i) {
+    d[i] |= ba[i] ^ bb[i];
+  }
+}
+
+static void
+test_virtaddrmap(void *data)
+{
+  /* Let's start with a bunch of random addresses. */
+  int ipv6, bits, iter, b;
+  virtual_addr_conf_t cfg[2];
+  uint8_t bytes[16];
+
+  (void)data;
+
+  tor_addr_parse(&cfg[0].addr, "64.65.0.0");
+  tor_addr_parse(&cfg[1].addr, "3491:c0c0::");
+
+  for (ipv6 = 0; ipv6 <= 1; ++ipv6) {
+    for (bits = 0; bits < 18; ++bits) {
+      tor_addr_t last_a;
+      cfg[ipv6].bits = bits;
+      memset(bytes, 0, sizeof(bytes));
+      tor_addr_copy(&last_a, &cfg[ipv6].addr);
+      /* Generate 128 addresses with each addr/bits combination. */
+      for (iter = 0; iter < 128; ++iter) {
+        tor_addr_t a;
+
+        get_random_virtual_addr(&cfg[ipv6], &a);
+        //printf("%s\n", fmt_addr(&a));
+        /* Make sure that the first b bits match the configured network */
+        tt_int_op(0, ==, tor_addr_compare_masked(&a, &cfg[ipv6].addr,
+                                                 bits, CMP_EXACT));
+
+        /* And track which bits have been different between pairs of
+         * addresses */
+        update_difference(ipv6, bytes, &last_a, &a);
+      }
+
+      /* Now make sure all but the first 'bits' bits of bytes are true */
+      for (b = bits+1; b < (ipv6?128:32); ++b) {
+        tt_assert(1 & (bytes[b/8] >> (7-(b&7))));
+      }
+    }
+  }
+
+ done:
+  ;
+}
+
 #define ADDR_LEGACY(name)                                               \
   { #name, legacy_test_helper, 0, &legacy_setup, test_addr_ ## name }
 
@@ -780,6 +850,7 @@ struct testcase_t addr_tests[] = {
   ADDR_LEGACY(basic),
   ADDR_LEGACY(ip6_helpers),
   ADDR_LEGACY(parse),
+  { "virtaddr", test_virtaddrmap, 0, NULL, NULL },
   END_OF_TESTCASES
 };
 





More information about the tor-commits mailing list