Browse Source

Merge remote-tracking branch 'teor/feature17327-v4'

Nick Mathewson 8 years ago
parent
commit
aa4be914f0
11 changed files with 280 additions and 30 deletions
  1. 4 0
      changes/bug6027
  2. 5 0
      changes/feature17327
  3. 6 3
      doc/tor.1.txt
  4. 42 7
      src/or/config.c
  5. 5 3
      src/or/config.h
  6. 2 0
      src/or/or.h
  7. 1 0
      src/or/router.c
  8. 24 3
      src/or/routerlist.c
  9. 2 0
      src/or/routerlist.h
  10. 175 0
      src/test/test_config.c
  11. 14 14
      src/test/test_dir_handle_get.c

+ 4 - 0
changes/bug6027

@@ -0,0 +1,4 @@
+  o Minor features:
+    - Allow users to configure directory authorities and fallback
+      directory servers with IPv6 addresses and ORPorts.  Resolves
+      ticket 6027.

+ 5 - 0
changes/feature17327

@@ -0,0 +1,5 @@
+  o Minor feature (IPv6):
+    - Add a flag ipv6=address:orport to the DirAuthority and FallbackDir torrc
+      options. Add hard-coded ipv6 addresses for directory authorities with
+      ipv6 lines in their descriptors.
+      Closes ticket 17327; patch from Nick Mathewson / "teor".

+ 6 - 3
doc/tor.1.txt

@@ -358,7 +358,7 @@ GENERAL OPTIONS
     DataDirectory. If the option is set to 1, make the DataDirectory readable
     DataDirectory. If the option is set to 1, make the DataDirectory readable
     by the default GID. (Default: 0)
     by the default GID. (Default: 0)
 
 
-[[FallbackDir]] **FallbackDir** __address__:__port__ orport=__port__ id=__fingerprint__ [weight=__num__]::
+[[FallbackDir]] **FallbackDir** __address__:__port__ orport=__port__ id=__fingerprint__ [weight=__num__] [ipv6=__address__:__orport__]::
     When we're unable to connect to any directory cache for directory info
     When we're unable to connect to any directory cache for directory info
     (usually because we don't know about any yet) we try a directory authority.
     (usually because we don't know about any yet) we try a directory authority.
     Clients also simultaneously try a FallbackDir, to avoid hangs on client
     Clients also simultaneously try a FallbackDir, to avoid hangs on client
@@ -384,9 +384,12 @@ GENERAL OPTIONS
     "bridge" flag is set. If a flag "orport=**port**" is given, Tor will use the
     "bridge" flag is set. If a flag "orport=**port**" is given, Tor will use the
     given port when opening encrypted tunnels to the dirserver. If a flag
     given port when opening encrypted tunnels to the dirserver. If a flag
     "weight=**num**" is given, then the directory server is chosen randomly
     "weight=**num**" is given, then the directory server is chosen randomly
-    with probability proportional to that weight (default 1.0). Lastly, if a
+    with probability proportional to that weight (default 1.0). If a
     flag "v3ident=**fp**" is given, the dirserver is a v3 directory authority
     flag "v3ident=**fp**" is given, the dirserver is a v3 directory authority
-    whose v3 long-term signing key has the fingerprint **fp**. +
+    whose v3 long-term signing key has the fingerprint **fp**. Lastly,
+    if an "ipv6=__address__:__orport__" flag is present, then the directory
+    authority is listening for IPv6 connections on the indicated IPv6 address
+    and OR Port. +
  +
  +
     If no **DirAuthority** line is given, Tor will use the default directory
     If no **DirAuthority** line is given, Tor will use the default directory
     authorities. NOTE: this option is intended for setting up a private Tor
     authorities. NOTE: this option is intended for setting up a private Tor

+ 42 - 7
src/or/config.c

@@ -600,9 +600,6 @@ static int options_transition_affects_descriptor(
 static int check_nickname_list(char **lst, const char *name, char **msg);
 static int check_nickname_list(char **lst, const char *name, char **msg);
 static char *get_bindaddr_from_transport_listen_line(const char *line,
 static char *get_bindaddr_from_transport_listen_line(const char *line,
                                                      const char *transport);
                                                      const char *transport);
-static int parse_dir_authority_line(const char *line,
-                                 dirinfo_type_t required_type,
-                                 int validate_only);
 static int parse_ports(or_options_t *options, int validate_only,
 static int parse_ports(or_options_t *options, int validate_only,
                               char **msg_out, int *n_ports_out,
                               char **msg_out, int *n_ports_out,
                               int *world_writable_control_socket);
                               int *world_writable_control_socket);
@@ -907,6 +904,7 @@ static const char *default_authorities[] = {
     "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
     "128.31.0.39:9131 9695 DFC3 5FFE B861 329B 9F1A B04C 4639 7020 CE31",
   "tor26 orport=443 "
   "tor26 orport=443 "
     "v3ident=14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4 "
     "v3ident=14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4 "
+    "ipv6=[2001:858:2:2:aabb:0:563b:1526]:443 "
     "86.59.21.38:80 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D",
     "86.59.21.38:80 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D",
   "dizum orport=443 "
   "dizum orport=443 "
     "v3ident=E8A9C45EDE6D711294FADF8E7951F4DE6CA56B58 "
     "v3ident=E8A9C45EDE6D711294FADF8E7951F4DE6CA56B58 "
@@ -915,21 +913,26 @@ static const char *default_authorities[] = {
     "82.94.251.203:80 4A0C CD2D DC79 9508 3D73 F5D6 6710 0C8A 5831 F16D",
     "82.94.251.203:80 4A0C CD2D DC79 9508 3D73 F5D6 6710 0C8A 5831 F16D",
   "gabelmoo orport=443 "
   "gabelmoo orport=443 "
     "v3ident=ED03BB616EB2F60BEC80151114BB25CEF515B226 "
     "v3ident=ED03BB616EB2F60BEC80151114BB25CEF515B226 "
+    "ipv6=[2001:638:a000:4140::ffff:189]:443 "
     "131.188.40.189:80 F204 4413 DAC2 E02E 3D6B CF47 35A1 9BCA 1DE9 7281",
     "131.188.40.189:80 F204 4413 DAC2 E02E 3D6B CF47 35A1 9BCA 1DE9 7281",
   "dannenberg orport=443 "
   "dannenberg orport=443 "
     "v3ident=585769C78764D58426B8B52B6651A5A71137189A "
     "v3ident=585769C78764D58426B8B52B6651A5A71137189A "
     "193.23.244.244:80 7BE6 83E6 5D48 1413 21C5 ED92 F075 C553 64AC 7123",
     "193.23.244.244:80 7BE6 83E6 5D48 1413 21C5 ED92 F075 C553 64AC 7123",
   "urras orport=80 "
   "urras orport=80 "
     "v3ident=80550987E1D626E3EBA5E5E75A458DE0626D088C "
     "v3ident=80550987E1D626E3EBA5E5E75A458DE0626D088C "
-    "208.83.223.34:443 0AD3 FA88 4D18 F89E EA2D 89C0 1937 9E0E 7FD9 4417",
+    "208.83.223.34:443 0AD3 FA88 4D18 F89E EA2D 89C0 1937 9E0E 7FD9 4417"
+    /* XX/teor - urras may have an IPv6 address, but it's not in urras'
+     * descriptor as of 11 Dec 2015. See #17813. */,
   "maatuska orport=80 "
   "maatuska orport=80 "
     "v3ident=49015F787433103580E3B66A1707A00E60F2D15B "
     "v3ident=49015F787433103580E3B66A1707A00E60F2D15B "
+    "ipv6=[2001:67c:289c::9]:80 "
     "171.25.193.9:443 BD6A 8292 55CB 08E6 6FBE 7D37 4836 3586 E46B 3810",
     "171.25.193.9:443 BD6A 8292 55CB 08E6 6FBE 7D37 4836 3586 E46B 3810",
   "Faravahar orport=443 "
   "Faravahar orport=443 "
     "v3ident=EFCBE720AB3A82B99F9E953CD5BF50F7EEFC7B97 "
     "v3ident=EFCBE720AB3A82B99F9E953CD5BF50F7EEFC7B97 "
     "154.35.175.225:80 CF6D 0AAF B385 BE71 B8E1 11FC 5CFF 4B47 9237 33BC",
     "154.35.175.225:80 CF6D 0AAF B385 BE71 B8E1 11FC 5CFF 4B47 9237 33BC",
   "longclaw orport=443 "
   "longclaw orport=443 "
     "v3ident=23D15D965BC35114467363C165C4F724B64B4F66 "
     "v3ident=23D15D965BC35114467363C165C4F724B64B4F66 "
+    "ipv6=[2620:13:4000:8000:60:f3ff:fea1:7cff]:443 "
     "199.254.238.52:80 74A9 1064 6BCE EFBC D2E8 74FC 1DC9 9743 0F96 8145",
     "199.254.238.52:80 74A9 1064 6BCE EFBC D2E8 74FC 1DC9 9743 0F96 8145",
   NULL
   NULL
 };
 };
@@ -938,7 +941,7 @@ static const char *default_authorities[] = {
  * but only add them insofar as they share bits with <b>type</b>.
  * but only add them insofar as they share bits with <b>type</b>.
  * Each authority's bits are restricted to the bits shared with <b>type</b>.
  * Each authority's bits are restricted to the bits shared with <b>type</b>.
  * If <b>type</b> is ALL_DIRINFO or NO_DIRINFO (zero), add all authorities. */
  * If <b>type</b> is ALL_DIRINFO or NO_DIRINFO (zero), add all authorities. */
-static void
+STATIC void
 add_default_trusted_dir_authorities(dirinfo_type_t type)
 add_default_trusted_dir_authorities(dirinfo_type_t type)
 {
 {
   int i;
   int i;
@@ -5634,13 +5637,14 @@ get_options_for_server_transport(const char *transport)
  * (minus whatever bits it's missing) as a valid authority.
  * (minus whatever bits it's missing) as a valid authority.
  * Return 0 on success or filtering out by type,
  * Return 0 on success or filtering out by type,
  * or -1 if the line isn't well-formed or if we can't add it. */
  * or -1 if the line isn't well-formed or if we can't add it. */
-static int
+STATIC int
 parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
 parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
                          int validate_only)
                          int validate_only)
 {
 {
   smartlist_t *items = NULL;
   smartlist_t *items = NULL;
   int r;
   int r;
   char *addrport=NULL, *address=NULL, *nickname=NULL, *fingerprint=NULL;
   char *addrport=NULL, *address=NULL, *nickname=NULL, *fingerprint=NULL;
+  tor_addr_port_t ipv6_addrport, *ipv6_addrport_ptr = NULL;
   uint16_t dir_port = 0, or_port = 0;
   uint16_t dir_port = 0, or_port = 0;
   char digest[DIGEST_LEN];
   char digest[DIGEST_LEN];
   char v3_digest[DIGEST_LEN];
   char v3_digest[DIGEST_LEN];
@@ -5697,6 +5701,20 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
       } else {
       } else {
         type |= V3_DIRINFO|EXTRAINFO_DIRINFO|MICRODESC_DIRINFO;
         type |= V3_DIRINFO|EXTRAINFO_DIRINFO|MICRODESC_DIRINFO;
       }
       }
+    } else if (!strcasecmpstart(flag, "ipv6=")) {
+      if (ipv6_addrport_ptr) {
+        log_warn(LD_CONFIG, "Redundant ipv6 addr/port on DirAuthority line");
+      } else {
+        if (tor_addr_port_parse(LOG_WARN, flag+strlen("ipv6="),
+                                &ipv6_addrport.addr, &ipv6_addrport.port,
+                                -1) < 0
+            || tor_addr_family(&ipv6_addrport.addr) != AF_INET6) {
+          log_warn(LD_CONFIG, "Bad ipv6 addr/port %s on DirAuthority line",
+                   escaped(flag));
+          goto err;
+        }
+        ipv6_addrport_ptr = &ipv6_addrport;
+      }
     } else {
     } else {
       log_warn(LD_CONFIG, "Unrecognized flag '%s' on DirAuthority line",
       log_warn(LD_CONFIG, "Unrecognized flag '%s' on DirAuthority line",
                flag);
                flag);
@@ -5739,6 +5757,7 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type,
     log_debug(LD_DIR, "Trusted %d dirserver at %s:%d (%s)", (int)type,
     log_debug(LD_DIR, "Trusted %d dirserver at %s:%d (%s)", (int)type,
               address, (int)dir_port, (char*)smartlist_get(items,0));
               address, (int)dir_port, (char*)smartlist_get(items,0));
     if (!(ds = trusted_dir_server_new(nickname, address, dir_port, or_port,
     if (!(ds = trusted_dir_server_new(nickname, address, dir_port, or_port,
+                                      ipv6_addrport_ptr,
                                       digest, v3_digest, type, weight)))
                                       digest, v3_digest, type, weight)))
       goto err;
       goto err;
     dir_server_add(ds);
     dir_server_add(ds);
@@ -5776,6 +5795,7 @@ parse_dir_fallback_line(const char *line,
   int ok;
   int ok;
   char id[DIGEST_LEN];
   char id[DIGEST_LEN];
   char *address=NULL;
   char *address=NULL;
+  tor_addr_port_t ipv6_addrport, *ipv6_addrport_ptr = NULL;
   double weight=1.0;
   double weight=1.0;
 
 
   memset(id, 0, sizeof(id));
   memset(id, 0, sizeof(id));
@@ -5794,6 +5814,20 @@ parse_dir_fallback_line(const char *line,
     } else if (!strcmpstart(cp, "id=")) {
     } else if (!strcmpstart(cp, "id=")) {
       ok = !base16_decode(id, DIGEST_LEN,
       ok = !base16_decode(id, DIGEST_LEN,
                           cp+strlen("id="), strlen(cp)-strlen("id="));
                           cp+strlen("id="), strlen(cp)-strlen("id="));
+    } else if (!strcasecmpstart(cp, "ipv6=")) {
+      if (ipv6_addrport_ptr) {
+        log_warn(LD_CONFIG, "Redundant ipv6 addr/port on FallbackDir line");
+      } else {
+        if (tor_addr_port_parse(LOG_WARN, cp+strlen("ipv6="),
+                                &ipv6_addrport.addr, &ipv6_addrport.port,
+                                -1) < 0
+            || tor_addr_family(&ipv6_addrport.addr) != AF_INET6) {
+          log_warn(LD_CONFIG, "Bad ipv6 addr/port %s on FallbackDir line",
+                   escaped(cp));
+          goto end;
+        }
+        ipv6_addrport_ptr = &ipv6_addrport;
+      }
     } else if (!strcmpstart(cp, "weight=")) {
     } else if (!strcmpstart(cp, "weight=")) {
       int ok;
       int ok;
       const char *wstring = cp + strlen("weight=");
       const char *wstring = cp + strlen("weight=");
@@ -5835,7 +5869,8 @@ parse_dir_fallback_line(const char *line,
 
 
   if (!validate_only) {
   if (!validate_only) {
     dir_server_t *ds;
     dir_server_t *ds;
-    ds = fallback_dir_server_new(&addr, dirport, orport, id, weight);
+    ds = fallback_dir_server_new(&addr, dirport, orport, ipv6_addrport_ptr,
+                                 id, weight);
     if (!ds) {
     if (!ds) {
       log_warn(LD_CONFIG, "Couldn't create FallbackDir %s", escaped(line));
       log_warn(LD_CONFIG, "Couldn't create FallbackDir %s", escaped(line));
       goto end;
       goto end;

+ 5 - 3
src/or/config.h

@@ -152,10 +152,12 @@ STATIC int parse_transport_line(const or_options_t *options,
                                 int server);
                                 int server);
 STATIC int consider_adding_dir_servers(const or_options_t *options,
 STATIC int consider_adding_dir_servers(const or_options_t *options,
                                        const or_options_t *old_options);
                                        const or_options_t *old_options);
+STATIC void add_default_trusted_dir_authorities(dirinfo_type_t type);
 MOCK_DECL(STATIC void, add_default_fallback_dir_servers, (void));
 MOCK_DECL(STATIC void, add_default_fallback_dir_servers, (void));
-STATIC int
-parse_dir_fallback_line(const char *line,
-                        int validate_only);
+STATIC int parse_dir_authority_line(const char *line,
+                                    dirinfo_type_t required_type,
+                                    int validate_only);
+STATIC int parse_dir_fallback_line(const char *line, int validate_only);
 #endif
 #endif
 
 
 #endif
 #endif

+ 2 - 0
src/or/or.h

@@ -5118,9 +5118,11 @@ typedef struct dir_server_t {
   char *description;
   char *description;
   char *nickname;
   char *nickname;
   char *address; /**< Hostname. */
   char *address; /**< Hostname. */
+  tor_addr_t ipv6_addr; /**< IPv6 address if present; AF_UNSPEC if not */
   uint32_t addr; /**< IPv4 address. */
   uint32_t addr; /**< IPv4 address. */
   uint16_t dir_port; /**< Directory port. */
   uint16_t dir_port; /**< Directory port. */
   uint16_t or_port; /**< OR port: Used for tunneling connections. */
   uint16_t or_port; /**< OR port: Used for tunneling connections. */
+  uint16_t ipv6_orport; /**< OR port corresponding to ipv6_addr. */
   double weight; /** Weight used when selecting this node at random */
   double weight; /** Weight used when selecting this node at random */
   char digest[DIGEST_LEN]; /**< Digest of identity key. */
   char digest[DIGEST_LEN]; /**< Digest of identity key. */
   char v3_identity_digest[DIGEST_LEN]; /**< Digest of v3 (authority only,
   char v3_identity_digest[DIGEST_LEN]; /**< Digest of v3 (authority only,

+ 1 - 0
src/or/router.c

@@ -1026,6 +1026,7 @@ init_keys(void)
     ds = trusted_dir_server_new(options->Nickname, NULL,
     ds = trusted_dir_server_new(options->Nickname, NULL,
                                 router_get_advertised_dir_port(options, 0),
                                 router_get_advertised_dir_port(options, 0),
                                 router_get_advertised_or_port(options),
                                 router_get_advertised_or_port(options),
+                                NULL,
                                 digest,
                                 digest,
                                 v3_digest,
                                 v3_digest,
                                 type, 0.0);
                                 type, 0.0);

+ 24 - 3
src/or/routerlist.c

@@ -4063,6 +4063,7 @@ dir_server_new(int is_authority,
                const tor_addr_t *addr,
                const tor_addr_t *addr,
                const char *hostname,
                const char *hostname,
                uint16_t dir_port, uint16_t or_port,
                uint16_t dir_port, uint16_t or_port,
+               const tor_addr_port_t *addrport_ipv6,
                const char *digest, const char *v3_auth_digest,
                const char *digest, const char *v3_auth_digest,
                dirinfo_type_t type,
                dirinfo_type_t type,
                double weight)
                double weight)
@@ -4079,7 +4080,7 @@ dir_server_new(int is_authority,
   if (tor_addr_family(addr) == AF_INET)
   if (tor_addr_family(addr) == AF_INET)
     a = tor_addr_to_ipv4h(addr);
     a = tor_addr_to_ipv4h(addr);
   else
   else
-    return NULL; /*XXXX Support IPv6 */
+    return NULL;
 
 
   if (!hostname)
   if (!hostname)
     hostname_ = tor_dup_addr(addr);
     hostname_ = tor_dup_addr(addr);
@@ -4096,6 +4097,18 @@ dir_server_new(int is_authority,
   ent->is_authority = is_authority;
   ent->is_authority = is_authority;
   ent->type = type;
   ent->type = type;
   ent->weight = weight;
   ent->weight = weight;
+  if (addrport_ipv6) {
+    if (tor_addr_family(&addrport_ipv6->addr) != AF_INET6) {
+      log_warn(LD_BUG, "Hey, I got a non-ipv6 addr as addrport_ipv6.");
+      tor_addr_make_unspec(&ent->ipv6_addr);
+    } else {
+      tor_addr_copy(&ent->ipv6_addr, &addrport_ipv6->addr);
+      ent->ipv6_orport = addrport_ipv6->port;
+    }
+  } else {
+    tor_addr_make_unspec(&ent->ipv6_addr);
+  }
+
   memcpy(ent->digest, digest, DIGEST_LEN);
   memcpy(ent->digest, digest, DIGEST_LEN);
   if (v3_auth_digest && (type & V3_DIRINFO))
   if (v3_auth_digest && (type & V3_DIRINFO))
     memcpy(ent->v3_identity_digest, v3_auth_digest, DIGEST_LEN);
     memcpy(ent->v3_identity_digest, v3_auth_digest, DIGEST_LEN);
@@ -4108,6 +4121,7 @@ dir_server_new(int is_authority,
                  hostname, (int)dir_port);
                  hostname, (int)dir_port);
 
 
   ent->fake_status.addr = ent->addr;
   ent->fake_status.addr = ent->addr;
+  tor_addr_copy(&ent->fake_status.ipv6_addr, &ent->ipv6_addr);
   memcpy(ent->fake_status.identity_digest, digest, DIGEST_LEN);
   memcpy(ent->fake_status.identity_digest, digest, DIGEST_LEN);
   if (nickname)
   if (nickname)
     strlcpy(ent->fake_status.nickname, nickname,
     strlcpy(ent->fake_status.nickname, nickname,
@@ -4116,6 +4130,7 @@ dir_server_new(int is_authority,
     ent->fake_status.nickname[0] = '\0';
     ent->fake_status.nickname[0] = '\0';
   ent->fake_status.dir_port = ent->dir_port;
   ent->fake_status.dir_port = ent->dir_port;
   ent->fake_status.or_port = ent->or_port;
   ent->fake_status.or_port = ent->or_port;
+  ent->fake_status.ipv6_orport = ent->ipv6_orport;
 
 
   return ent;
   return ent;
 }
 }
@@ -4127,6 +4142,7 @@ dir_server_new(int is_authority,
 dir_server_t *
 dir_server_t *
 trusted_dir_server_new(const char *nickname, const char *address,
 trusted_dir_server_new(const char *nickname, const char *address,
                        uint16_t dir_port, uint16_t or_port,
                        uint16_t dir_port, uint16_t or_port,
+                       const tor_addr_port_t *ipv6_addrport,
                        const char *digest, const char *v3_auth_digest,
                        const char *digest, const char *v3_auth_digest,
                        dirinfo_type_t type, double weight)
                        dirinfo_type_t type, double weight)
 {
 {
@@ -4157,7 +4173,9 @@ trusted_dir_server_new(const char *nickname, const char *address,
   tor_addr_from_ipv4h(&addr, a);
   tor_addr_from_ipv4h(&addr, a);
 
 
   result = dir_server_new(1, nickname, &addr, hostname,
   result = dir_server_new(1, nickname, &addr, hostname,
-                          dir_port, or_port, digest,
+                          dir_port, or_port,
+                          ipv6_addrport,
+                          digest,
                           v3_auth_digest, type, weight);
                           v3_auth_digest, type, weight);
   tor_free(hostname);
   tor_free(hostname);
   return result;
   return result;
@@ -4169,9 +4187,12 @@ trusted_dir_server_new(const char *nickname, const char *address,
 dir_server_t *
 dir_server_t *
 fallback_dir_server_new(const tor_addr_t *addr,
 fallback_dir_server_new(const tor_addr_t *addr,
                         uint16_t dir_port, uint16_t or_port,
                         uint16_t dir_port, uint16_t or_port,
+                        const tor_addr_port_t *addrport_ipv6,
                         const char *id_digest, double weight)
                         const char *id_digest, double weight)
 {
 {
-  return dir_server_new(0, NULL, addr, NULL, dir_port, or_port, id_digest,
+  return dir_server_new(0, NULL, addr, NULL, dir_port, or_port,
+                        addrport_ipv6,
+                        id_digest,
                         NULL, ALL_DIRINFO, weight);
                         NULL, ALL_DIRINFO, weight);
 }
 }
 
 

+ 2 - 0
src/or/routerlist.h

@@ -171,10 +171,12 @@ int router_exit_policy_rejects_all(const routerinfo_t *router);
 
 
 dir_server_t *trusted_dir_server_new(const char *nickname, const char *address,
 dir_server_t *trusted_dir_server_new(const char *nickname, const char *address,
                        uint16_t dir_port, uint16_t or_port,
                        uint16_t dir_port, uint16_t or_port,
+                       const tor_addr_port_t *addrport_ipv6,
                        const char *digest, const char *v3_auth_digest,
                        const char *digest, const char *v3_auth_digest,
                        dirinfo_type_t type, double weight);
                        dirinfo_type_t type, double weight);
 dir_server_t *fallback_dir_server_new(const tor_addr_t *addr,
 dir_server_t *fallback_dir_server_new(const tor_addr_t *addr,
                                       uint16_t dir_port, uint16_t or_port,
                                       uint16_t dir_port, uint16_t or_port,
+                                      const tor_addr_port_t *addrport_ipv6,
                                       const char *id_digest, double weight);
                                       const char *id_digest, double weight);
 void dir_server_add(dir_server_t *ent);
 void dir_server_add(dir_server_t *ent);
 
 

+ 175 - 0
src/test/test_config.c

@@ -1445,6 +1445,176 @@ test_config_resolve_my_address(void *arg)
   UNMOCK(tor_gethostname);
   UNMOCK(tor_gethostname);
 }
 }
 
 
+static void
+test_config_adding_trusted_dir_server(void *arg)
+{
+  (void)arg;
+
+  const char digest[DIGEST_LEN] = "";
+  dir_server_t *ds = NULL;
+  tor_addr_port_t ipv6;
+  int rv = -1;
+
+  clear_dir_servers();
+  routerlist_free_all();
+
+  /* create a trusted ds without an IPv6 address and port */
+  ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, NULL, digest,
+                              NULL, V3_DIRINFO, 1.0);
+  tt_assert(ds);
+  dir_server_add(ds);
+  tt_assert(get_n_authorities(V3_DIRINFO) == 1);
+  tt_assert(smartlist_len(router_get_fallback_dir_servers()) == 1);
+
+  /* create a trusted ds with an IPv6 address and port */
+  rv = tor_addr_port_parse(LOG_WARN, "[::1]:9061", &ipv6.addr, &ipv6.port, -1);
+  tt_assert(rv == 0);
+  ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, &ipv6, digest,
+                              NULL, V3_DIRINFO, 1.0);
+  tt_assert(ds);
+  dir_server_add(ds);
+  tt_assert(get_n_authorities(V3_DIRINFO) == 2);
+  tt_assert(smartlist_len(router_get_fallback_dir_servers()) == 2);
+
+ done:
+  clear_dir_servers();
+  routerlist_free_all();
+}
+
+static void
+test_config_adding_fallback_dir_server(void *arg)
+{
+  (void)arg;
+
+  const char digest[DIGEST_LEN] = "";
+  dir_server_t *ds = NULL;
+  tor_addr_t ipv4;
+  tor_addr_port_t ipv6;
+  int rv = -1;
+
+  clear_dir_servers();
+  routerlist_free_all();
+
+  rv = tor_addr_parse(&ipv4, "127.0.0.1");
+  tt_assert(rv == AF_INET);
+
+  /* create a trusted ds without an IPv6 address and port */
+  ds = fallback_dir_server_new(&ipv4, 9059, 9060, NULL, digest, 1.0);
+  tt_assert(ds);
+  dir_server_add(ds);
+  tt_assert(smartlist_len(router_get_fallback_dir_servers()) == 1);
+
+  /* create a trusted ds with an IPv6 address and port */
+  rv = tor_addr_port_parse(LOG_WARN, "[::1]:9061", &ipv6.addr, &ipv6.port, -1);
+  tt_assert(rv == 0);
+  ds = fallback_dir_server_new(&ipv4, 9059, 9060, &ipv6, digest, 1.0);
+  tt_assert(ds);
+  dir_server_add(ds);
+  tt_assert(smartlist_len(router_get_fallback_dir_servers()) == 2);
+
+ done:
+  clear_dir_servers();
+  routerlist_free_all();
+}
+
+/* No secrets here:
+ * v3ident is `echo "onion" | shasum | cut -d" " -f1 | tr "a-f" "A-F"`
+ * fingerprint is `echo "unionem" | shasum | cut -d" " -f1 | tr "a-f" "A-F"`
+ * with added spaces
+ */
+#define TEST_DIR_AUTH_LINE_START                                        \
+                    "foobar orport=12345 "                              \
+                    "v3ident=14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4 "
+#define TEST_DIR_AUTH_LINE_END                                          \
+                    "1.2.3.4:54321 "                                    \
+                    "FDB2 FBD2 AAA5 25FA 2999 E617 5091 5A32 C777 3B17"
+#define TEST_DIR_AUTH_IPV6_FLAG                                         \
+                    "ipv6=[feed::beef]:9 "
+
+static void
+test_config_parsing_trusted_dir_server(void *arg)
+{
+  (void)arg;
+  int rv = -1;
+
+  /* parse a trusted dir server without an IPv6 address and port */
+  rv = parse_dir_authority_line(TEST_DIR_AUTH_LINE_START
+                                TEST_DIR_AUTH_LINE_END,
+                                V3_DIRINFO, 1);
+  tt_assert(rv == 0);
+
+  /* parse a trusted dir server with an IPv6 address and port */
+  rv = parse_dir_authority_line(TEST_DIR_AUTH_LINE_START
+                                TEST_DIR_AUTH_IPV6_FLAG
+                                TEST_DIR_AUTH_LINE_END,
+                                V3_DIRINFO, 1);
+  tt_assert(rv == 0);
+
+  /* Since we are only validating, there is no cleanup. */
+ done:
+  ;
+}
+
+#undef TEST_DIR_AUTH_LINE_START
+#undef TEST_DIR_AUTH_LINE_END
+#undef TEST_DIR_AUTH_IPV6_FLAG
+
+/* No secrets here:
+ * id is `echo "syn-propanethial-S-oxide" | shasum | cut -d" " -f1`
+ */
+#define TEST_DIR_FALLBACK_LINE                                     \
+                    "1.2.3.4:54321 orport=12345 "                  \
+                    "id=50e643986f31ea1235bcc1af17a1c5c5cfc0ee54 "
+#define TEST_DIR_FALLBACK_IPV6_FLAG                                \
+                    "ipv6=[2015:c0de::deed]:9"
+
+static void
+test_config_parsing_fallback_dir_server(void *arg)
+{
+  (void)arg;
+  int rv = -1;
+
+  /* parse a trusted dir server without an IPv6 address and port */
+  rv = parse_dir_fallback_line(TEST_DIR_FALLBACK_LINE, 1);
+  tt_assert(rv == 0);
+
+  /* parse a trusted dir server with an IPv6 address and port */
+  rv = parse_dir_fallback_line(TEST_DIR_FALLBACK_LINE
+                               TEST_DIR_FALLBACK_IPV6_FLAG,
+                               1);
+  tt_assert(rv == 0);
+
+  /* Since we are only validating, there is no cleanup. */
+ done:
+  ;
+}
+
+#undef TEST_DIR_FALLBACK_LINE
+#undef TEST_DIR_FALLBACK_IPV6_FLAG
+
+static void
+test_config_adding_default_trusted_dir_servers(void *arg)
+{
+  (void)arg;
+
+  clear_dir_servers();
+  routerlist_free_all();
+
+  /* Assume we only have one bridge authority */
+  add_default_trusted_dir_authorities(BRIDGE_DIRINFO);
+  tt_assert(get_n_authorities(BRIDGE_DIRINFO) == 1);
+  tt_assert(smartlist_len(router_get_fallback_dir_servers()) == 1);
+
+  /* Assume we have nine V3 authorities */
+  add_default_trusted_dir_authorities(V3_DIRINFO);
+  tt_assert(get_n_authorities(V3_DIRINFO) == 9);
+  tt_assert(smartlist_len(router_get_fallback_dir_servers()) == 10);
+
+ done:
+  clear_dir_servers();
+  routerlist_free_all();
+}
+
 static int n_add_default_fallback_dir_servers_known_default = 0;
 static int n_add_default_fallback_dir_servers_known_default = 0;
 
 
 /**
 /**
@@ -3326,6 +3496,11 @@ test_config_use_multiple_directories(void *arg)
   { #name, test_config_ ## name, flags, NULL, NULL }
   { #name, test_config_ ## name, flags, NULL, NULL }
 
 
 struct testcase_t config_tests[] = {
 struct testcase_t config_tests[] = {
+  CONFIG_TEST(adding_trusted_dir_server, TT_FORK),
+  CONFIG_TEST(adding_fallback_dir_server, TT_FORK),
+  CONFIG_TEST(parsing_trusted_dir_server, 0),
+  CONFIG_TEST(parsing_fallback_dir_server, 0),
+  CONFIG_TEST(adding_default_trusted_dir_servers, TT_FORK),
   CONFIG_TEST(adding_dir_servers, TT_FORK),
   CONFIG_TEST(adding_dir_servers, TT_FORK),
   CONFIG_TEST(default_dir_servers, TT_FORK),
   CONFIG_TEST(default_dir_servers, TT_FORK),
   CONFIG_TEST(resolve_my_address, TT_FORK),
   CONFIG_TEST(resolve_my_address, TT_FORK),

+ 14 - 14
src/test/test_dir_handle_get.c

@@ -1242,8 +1242,8 @@ test_dir_handle_get_server_keys_all(void* data)
   routerlist_free_all();
   routerlist_free_all();
 
 
   /* create a trusted ds */
   /* create a trusted ds */
-  ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, digest, NULL,
-                              V3_DIRINFO, 1.0);
+  ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, NULL, digest,
+                              NULL, V3_DIRINFO, 1.0);
   tt_assert(ds);
   tt_assert(ds);
   dir_server_add(ds);
   dir_server_add(ds);
 
 
@@ -1400,8 +1400,8 @@ test_dir_handle_get_server_keys_fp(void* data)
   routerlist_free_all();
   routerlist_free_all();
 
 
   /* create a trusted ds */
   /* create a trusted ds */
-  ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, digest, NULL,
-                              V3_DIRINFO, 1.0);
+  ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, NULL, digest,
+                              NULL, V3_DIRINFO, 1.0);
   tt_assert(ds);
   tt_assert(ds);
   dir_server_add(ds);
   dir_server_add(ds);
 
 
@@ -1554,8 +1554,8 @@ test_dir_handle_get_server_keys_fpsk(void* data)
   routerlist_free_all();
   routerlist_free_all();
 
 
   /* create a trusted ds */
   /* create a trusted ds */
-  ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, digest, NULL,
-                              V3_DIRINFO, 1.0);
+  ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, NULL, digest,
+                              NULL, V3_DIRINFO, 1.0);
   tt_assert(ds);
   tt_assert(ds);
 
 
   /* ds v3_identity_digest is the certificate's identity_key */
   /* ds v3_identity_digest is the certificate's identity_key */
@@ -1610,8 +1610,8 @@ test_dir_handle_get_server_keys_busy(void* data)
   routerlist_free_all();
   routerlist_free_all();
 
 
   /* create a trusted ds */
   /* create a trusted ds */
-  ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, digest, NULL,
-                              V3_DIRINFO, 1.0);
+  ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, NULL, digest,
+                              NULL, V3_DIRINFO, 1.0);
   tt_assert(ds);
   tt_assert(ds);
 
 
   /* ds v3_identity_digest is the certificate's identity_key */
   /* ds v3_identity_digest is the certificate's identity_key */
@@ -2005,8 +2005,8 @@ test_dir_handle_get_status_vote_d(void* data)
   dirvote_free_all();
   dirvote_free_all();
 
 
   /* create a trusted ds */
   /* create a trusted ds */
-  ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, digest, NULL,
-                              V3_DIRINFO, 1.0);
+  ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, NULL, digest,
+                              NULL, V3_DIRINFO, 1.0);
   tt_assert(ds);
   tt_assert(ds);
   dir_server_add(ds);
   dir_server_add(ds);
 
 
@@ -2353,8 +2353,8 @@ test_dir_handle_get_status_vote_next_authority(void* data)
   mock_cert = authority_cert_parse_from_string(TEST_CERTIFICATE, NULL);
   mock_cert = authority_cert_parse_from_string(TEST_CERTIFICATE, NULL);
 
 
   /* create a trusted ds */
   /* create a trusted ds */
-  ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, digest, NULL,
-                              V3_DIRINFO, 1.0);
+  ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, NULL, digest,
+                              NULL, V3_DIRINFO, 1.0);
   tt_assert(ds);
   tt_assert(ds);
   dir_server_add(ds);
   dir_server_add(ds);
 
 
@@ -2431,8 +2431,8 @@ test_dir_handle_get_status_vote_current_authority(void* data)
   mock_cert = authority_cert_parse_from_string(TEST_CERTIFICATE, NULL);
   mock_cert = authority_cert_parse_from_string(TEST_CERTIFICATE, NULL);
 
 
   /* create a trusted ds */
   /* create a trusted ds */
-  ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, digest, NULL,
-                              V3_DIRINFO, 1.0);
+  ds = trusted_dir_server_new("ds", "127.0.0.1", 9059, 9060, NULL, digest,
+                              NULL, V3_DIRINFO, 1.0);
   tt_assert(ds);
   tt_assert(ds);
   dir_server_add(ds);
   dir_server_add(ds);