Browse Source

Merge branch 'tickets_5529_5534_5974_6406'

Nick Mathewson 12 years ago
parent
commit
a4995d1507
16 changed files with 193 additions and 53 deletions
  1. 3 0
      changes/bug5529
  2. 4 0
      changes/bug5534
  3. 4 0
      changes/bug5974
  4. 4 0
      changes/enh6406
  5. 14 0
      doc/tor.1.txt
  6. 2 0
      src/or/config.c
  7. 1 1
      src/or/connection_or.c
  8. 74 23
      src/or/dirserv.c
  9. 1 1
      src/or/dirserv.h
  10. 33 4
      src/or/nodelist.c
  11. 1 1
      src/or/nodelist.h
  12. 19 12
      src/or/or.h
  13. 20 0
      src/or/router.c
  14. 2 0
      src/or/router.h
  15. 10 10
      src/or/routerlist.c
  16. 1 1
      src/or/routerlist.h

+ 3 - 0
changes/bug5529

@@ -0,0 +1,3 @@
+  o Code refactoring:
+    - Move last_reachable and testing_since from routerinfo_t to
+      node_t.  Implements enhancement 5529.

+ 4 - 0
changes/bug5534

@@ -0,0 +1,4 @@
+  o Major features (IPv6):
+    Add support for bridge authorities to accept IPv6 bridge addresses
+    and include them in network status documents.  Implements
+    enhancement 5534.

+ 4 - 0
changes/bug5974

@@ -0,0 +1,4 @@
+  o Minor features:
+
+    - Add new configure option AuthDirHasIPv6Connectivity.  Implements
+      feature #5974.

+ 4 - 0
changes/enh6406

@@ -0,0 +1,4 @@
+  o Minor features:
+
+    - Add new configure option AuthDirPublishIPv6.  Implements
+      enhancement #6406.

+ 14 - 0
doc/tor.1.txt

@@ -1728,6 +1728,20 @@ DIRECTORY AUTHORITY SERVER OPTIONS
     votes on whether to accept relays as hidden service directories.
     (Default: 1)
 
+**AuthDirHasIPv6Connectivity** **0**|**1**|**auto**::
+
+    Authoritative directories only. When set to 0, OR ports with an
+    IPv6 address are being accepted without reachability testing.
+    When set to 1, IPv6 OR ports are being tested just like IPv4 OR
+    ports.  When set to auto, Tor tries to find out if the authority
+    relay has IPv6 connectivity or not. (Default: auto)
+
+**AuthDirPublishIPv6** **0**|**1**::
+
+    Authoritative directories only. When set to 0, Tor will not
+    include IPv6 OR ports in votes. When set to 1, Tor will vote for
+    IPv6 OR ports. (Default: 0).
+
 HIDDEN SERVICE OPTIONS
 ----------------------
 

+ 2 - 0
src/or/config.c

@@ -201,6 +201,8 @@ static config_var_t _option_vars[] = {
   V(AuthDirListBadExits,         BOOL,     "0"),
   V(AuthDirMaxServersPerAddr,    UINT,     "2"),
   V(AuthDirMaxServersPerAuthAddr,UINT,     "5"),
+  V(AuthDirHasIPv6Connectivity,  AUTOBOOL, "auto"),
+  V(AuthDirPublishIPv6,          BOOL,     "0"),
   VAR("AuthoritativeDirectory",  BOOL, AuthoritativeDir,    "0"),
   V(AutomapHostsOnResolve,       BOOL,     "0"),
   V(AutomapHostsSuffixes,        CSV,      ".onion,.exit"),

+ 1 - 1
src/or/connection_or.c

@@ -1540,7 +1540,7 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
     return -1;
   }
   if (authdir_mode_tests_reachability(options)) {
-    dirserv_orconn_tls_done(conn->_base.address, conn->_base.port,
+    dirserv_orconn_tls_done(&conn->_base.addr, conn->_base.port,
                             (const char*)peer_id);
   }
 

+ 74 - 23
src/or/dirserv.c

@@ -988,7 +988,7 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
     answer = ! we_are_hibernating();
   } else if (router->is_hibernating &&
              (router->cache_info.published_on +
-              HIBERNATION_PUBLICATION_SKEW) > router->last_reachable) {
+              HIBERNATION_PUBLICATION_SKEW) > node->last_reachable) {
     /* A hibernating router is down unless we (somehow) had contact with it
      * since it declared itself to be hibernating. */
     answer = 0;
@@ -998,7 +998,7 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
   } else {
     /* Otherwise, a router counts as up if we found it reachable in the last
        REACHABLE_TIMEOUT seconds. */
-    answer = (now < router->last_reachable + REACHABLE_TIMEOUT);
+    answer = (now < node->last_reachable + REACHABLE_TIMEOUT);
   }
 
   if (!answer && running_long_enough_to_decide_unreachable()) {
@@ -1010,9 +1010,9 @@ dirserv_set_router_is_running(routerinfo_t *router, time_t now)
        it.
      */
     time_t when = now;
-    if (router->last_reachable &&
-        router->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD < now)
-      when = router->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD;
+    if (node->last_reachable &&
+        node->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD < now)
+      when = node->last_reachable + REACHABILITY_TEST_CYCLE_PERIOD;
     rep_hist_note_router_unreachable(router->cache_info.identity_digest, when);
   }
 
@@ -2088,6 +2088,21 @@ routerstatus_format_entry(char *buf, size_t buf_len,
     return 0;
 
   cp = buf + strlen(buf);
+
+  /* Possible "a" line, not included in consensus for now. */
+  if (!tor_addr_is_null(&rs->ipv6_addr)) {
+    const char *addr_str = fmt_and_decorate_addr(&rs->ipv6_addr);
+    r = tor_snprintf(cp, buf_len - (cp-buf),
+                     "a %s:%d\n",
+                     addr_str,
+                     (int)rs->ipv6_orport);
+    if (r<0) {
+      log_warn(LD_BUG, "Not enough space in buffer.");
+      return -1;
+    }
+    cp += strlen(cp);
+  }
+
   /* NOTE: Whenever this list expands, be sure to increase MAX_FLAG_LINE_LEN*/
   r = tor_snprintf(cp, buf_len - (cp-buf),
                    "s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
@@ -2453,6 +2468,16 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
   strlcpy(rs->nickname, ri->nickname, sizeof(rs->nickname));
   rs->or_port = ri->or_port;
   rs->dir_port = ri->dir_port;
+  if (options->AuthDirPublishIPv6 == 1 &&
+      !tor_addr_is_null(&ri->ipv6_addr) &&
+      (options->AuthDirHasIPv6Connectivity == 0 ||
+       node->last_reachable6 >= now - REACHABLE_TIMEOUT)) {
+    /* We're configured for publishing IPv6 OR ports. There's an IPv6
+       OR port and it's reachable (or we know that we're not on IPv6)
+       so copy it to the routerstatus.  */
+    tor_addr_copy(&rs->ipv6_addr, &ri->ipv6_addr);
+    rs->ipv6_orport = ri->ipv6_orport;
+  }
 }
 
 /** Routerstatus <b>rs</b> is part of a group of routers that are on
@@ -3273,36 +3298,42 @@ dirserv_get_routerdescs(smartlist_t *descs_out, const char *key,
  * Inform the reachability checker that we could get to this guy.
  */
 void
-dirserv_orconn_tls_done(const char *address,
+dirserv_orconn_tls_done(const tor_addr_t *addr,
                         uint16_t or_port,
                         const char *digest_rcvd)
 {
-  routerinfo_t *ri;
+  node_t *node = NULL;
+  tor_addr_port_t orport;
+  routerinfo_t *ri = NULL;
   time_t now = time(NULL);
-  tor_assert(address);
+  tor_assert(addr);
   tor_assert(digest_rcvd);
 
-  ri = router_get_mutable_by_digest(digest_rcvd);
-
-  if (ri == NULL)
+  node = node_get_mutable_by_id(digest_rcvd);
+  if (node == NULL || node->ri == NULL)
     return;
+  ri = node->ri;
 
-  if (!strcasecmp(address, ri->address) && or_port == ri->or_port) {
+  tor_addr_copy(&orport.addr, addr);
+  orport.port = or_port;
+  if (router_has_orport(ri, &orport)) {
     /* Found the right router.  */
     if (!authdir_mode_bridge(get_options()) ||
         ri->purpose == ROUTER_PURPOSE_BRIDGE) {
+      char addrstr[TOR_ADDR_BUF_LEN];
       /* This is a bridge or we're not a bridge authorititative --
          mark it as reachable.  */
-      tor_addr_t addr, *addrp=NULL;
       log_info(LD_DIRSERV, "Found router %s to be reachable at %s:%d. Yay.",
                router_describe(ri),
-               address, ri->or_port);
-      if (tor_addr_parse(&addr, ri->address) != -1)
-        addrp = &addr;
-      else
-        log_warn(LD_BUG, "Couldn't parse IP address \"%s\"", ri->address);
-      rep_hist_note_router_reachable(digest_rcvd, addrp, or_port, now);
-      ri->last_reachable = now;
+               tor_addr_to_str(addrstr, addr, sizeof(addrstr), 1),
+               ri->or_port);
+      if (tor_addr_family(addr) == AF_INET) {
+        rep_hist_note_router_reachable(digest_rcvd, addr, or_port, now);
+        node->last_reachable = now;
+      } else if (tor_addr_family(addr) == AF_INET6) {
+        /* No rephist for IPv6.  */
+        node->last_reachable6 = now;
+      }
     }
   }
 }
@@ -3325,7 +3356,7 @@ dirserv_should_launch_reachability_test(const routerinfo_t *ri,
     /* It just came out of hibernation; launch a reachability test */
     return 1;
   }
-  if (! routers_have_same_or_addr(ri, ri_old)) {
+  if (! routers_have_same_or_addrs(ri, ri_old)) {
     /* Address or port changed; launch a reachability test */
     return 1;
   }
@@ -3338,15 +3369,35 @@ dirserv_should_launch_reachability_test(const routerinfo_t *ri,
 void
 dirserv_single_reachability_test(time_t now, routerinfo_t *router)
 {
+  node_t *node = NULL;
   tor_addr_t router_addr;
+
+  tor_assert(router);
+  node = node_get_mutable_by_id(router->cache_info.identity_digest);
+  tor_assert(node);
+
+  /* IPv4. */
   log_debug(LD_OR,"Testing reachability of %s at %s:%u.",
             router->nickname, router->address, router->or_port);
   /* Remember when we started trying to determine reachability */
-  if (!router->testing_since)
-    router->testing_since = now;
+  if (!node->testing_since)
+    node->testing_since = now;
   tor_addr_from_ipv4h(&router_addr, router->addr);
   connection_or_connect(&router_addr, router->or_port,
                         router->cache_info.identity_digest);
+
+  /* Possible IPv6. */
+  if (!tor_addr_is_null(&router->ipv6_addr)) {
+    char addrstr[TOR_ADDR_BUF_LEN];
+    log_debug(LD_OR, "Testing reachability of %s at %s:%u.",
+              router->nickname,
+              tor_addr_to_str(addrstr, &router->ipv6_addr, sizeof(addrstr), 1),
+              router->ipv6_orport);
+    if (!node->testing_since6)
+      node->testing_since6 = now;
+    connection_or_connect(&router->ipv6_addr, router->ipv6_orport,
+                          router->cache_info.identity_digest);
+  }
 }
 
 /** Auth dir server only: load balance such that we only

+ 1 - 1
src/or/dirserv.h

@@ -107,7 +107,7 @@ int dirserv_get_routerdesc_fingerprints(smartlist_t *fps_out, const char *key,
                                         int is_extrainfo);
 int dirserv_get_routerdescs(smartlist_t *descs_out, const char *key,
                             const char **msg);
-void dirserv_orconn_tls_done(const char *address,
+void dirserv_orconn_tls_done(const tor_addr_t *addr,
                              uint16_t or_port,
                              const char *digest_rcvd);
 int dirserv_should_launch_reachability_test(const routerinfo_t *ri,

+ 33 - 4
src/or/nodelist.c

@@ -115,19 +115,48 @@ node_get_or_create(const char *identity_digest)
   return node;
 }
 
-/** Add <b>ri</b> to the nodelist. */
+/** Called when a node's address changes. */
+static void
+node_addrs_changed(node_t *node)
+{
+  node->last_reachable = node->last_reachable6 = 0;
+  node->testing_since = node->testing_since6 = 0;
+  node->country = -1;
+}
+
+/** Add <b>ri</b> to an appropriate node in the nodelist.  If we replace an
+ * old routerinfo, and <b>ri_old_out</b> is not NULL, set *<b>ri_old_out</b>
+ * to the previous routerinfo.
+ */
 node_t *
-nodelist_add_routerinfo(routerinfo_t *ri)
+nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out)
 {
   node_t *node;
+  const char *id_digest;
+  int had_router = 0;
+  tor_assert(ri);
+
   init_nodelist();
-  node = node_get_or_create(ri->cache_info.identity_digest);
+  id_digest = ri->cache_info.identity_digest;
+  node = node_get_or_create(id_digest);
+
+  if (node->ri) {
+    if (!routers_have_same_or_addrs(node->ri, ri)) {
+      node_addrs_changed(node);
+    }
+    had_router = 1;
+    if (ri_old_out)
+      *ri_old_out = node->ri;
+  } else {
+    if (ri_old_out)
+      *ri_old_out = NULL;
+  }
   node->ri = ri;
 
   if (node->country == -1)
     node_set_country(node);
 
-  if (authdir_mode(get_options())) {
+  if (authdir_mode(get_options()) && !had_router) {
     const char *discard=NULL;
     uint32_t status = dirserv_router_get_status(ri, &discard);
     dirserv_set_node_flags_from_authoritative_status(node, status);

+ 1 - 1
src/or/nodelist.h

@@ -15,7 +15,7 @@
 node_t *node_get_mutable_by_id(const char *identity_digest);
 const node_t *node_get_by_id(const char *identity_digest);
 const node_t *node_get_by_hex_id(const char *identity_digest);
-node_t *nodelist_add_routerinfo(routerinfo_t *ri);
+node_t *nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out);
 node_t *nodelist_add_microdesc(microdesc_t *md);
 void nodelist_set_consensus(networkstatus_t *ns);
 

+ 19 - 12
src/or/or.h

@@ -1793,15 +1793,6 @@ typedef struct {
    * things; see notes on ROUTER_PURPOSE_* macros above.
    */
   uint8_t purpose;
-
-  /* The below items are used only by authdirservers for
-   * reachability testing. */
-
-  /** When was the last time we could reach this OR? */
-  time_t last_reachable;
-  /** When did we start testing reachability for this OR? */
-  time_t testing_since;
-
 } routerinfo_t;
 
 /** Information needed to keep and cache a signed extra-info document. */
@@ -1833,6 +1824,8 @@ typedef struct routerstatus_t {
   uint32_t addr; /**< IPv4 address for this router. */
   uint16_t or_port; /**< OR port for this router. */
   uint16_t dir_port; /**< Directory port for this router. */
+  tor_addr_t ipv6_addr; /**< IPv6 address for this router. */
+  uint16_t ipv6_orport; /**<IPV6 OR port for this router. */
   unsigned int is_authority:1; /**< True iff this router is an authority. */
   unsigned int is_exit:1; /**< True iff this router is a good exit. */
   unsigned int is_stable:1; /**< True iff this router stays up a long time. */
@@ -2006,13 +1999,13 @@ typedef struct node_t {
   routerstatus_t *rs;
 
   /* local info: copied from routerstatus, then possibly frobbed based
-   * on experience.  Authorities set this stuff directly. */
+   * on experience.  Authorities set this stuff directly.  Note that
+   * these reflect knowledge of the primary (IPv4) OR port only.  */
 
   unsigned int is_running:1; /**< As far as we know, is this OR currently
                               * running? */
   unsigned int is_valid:1; /**< Has a trusted dirserver validated this OR?
-                               *  (For Authdir: Have we validated this OR?)
-                               */
+                            *  (For Authdir: Have we validated this OR?) */
   unsigned int is_fast:1; /** Do we think this is a fast OR? */
   unsigned int is_stable:1; /** Do we think this is a stable OR? */
   unsigned int is_possible_guard:1; /**< Do we think this is an OK guard? */
@@ -2036,7 +2029,19 @@ typedef struct node_t {
   /* Local info: derived. */
 
   /** According to the geoip db what country is this router in? */
+  /* XXXprop186 what is this suppose to mean with multiple OR ports? */
   country_t country;
+
+  /* The below items are used only by authdirservers for
+   * reachability testing. */
+
+  /** When was the last time we could reach this OR? */
+  time_t last_reachable;        /* IPv4. */
+  time_t last_reachable6;       /* IPv6. */
+
+  /** When did we start testing reachability for this OR? */
+  time_t testing_since;         /* IPv4. */
+  time_t testing_since6;        /* IPv6. */
 } node_t;
 
 /** How many times will we try to download a router's descriptor before giving
@@ -3268,6 +3273,8 @@ typedef struct {
   int AuthDirMaxServersPerAuthAddr; /**< Do not permit more than this
                                      * number of servers per IP address shared
                                      * with an authority. */
+  int AuthDirHasIPv6Connectivity; /**< Autoboolean: are we on IPv6?  */
+  int AuthDirPublishIPv6; /**< Boolean: should we list IPv6 OR ports? */
 
   /** If non-zero, always vote the Fast flag for any relay advertising
    * this amount of capacity or more. */

+ 20 - 0
src/or/router.c

@@ -2230,6 +2230,26 @@ router_get_pref_ipv6_orport(const routerinfo_t *router,
   ap_out->port = router->ipv6_orport;
 }
 
+/** Return 1 if any of <b>router</b>'s addresses are <b>addr</b>.
+ *   Otherwise return 0. */
+int
+router_has_addr(const routerinfo_t *router, const tor_addr_t *addr)
+{
+  return
+    tor_addr_eq_ipv4h(addr, router->addr) ||
+    tor_addr_eq(&router->ipv6_addr, addr);
+}
+
+int
+router_has_orport(const routerinfo_t *router, const tor_addr_port_t *orport)
+{
+  return
+    (tor_addr_eq_ipv4h(&orport->addr, router->addr) &&
+     orport->port == router->or_port) ||
+    (tor_addr_eq(&orport->addr, &router->ipv6_addr) &&
+     orport->port == router->ipv6_orport);
+}
+
 /** Load the contents of <b>filename</b>, find the last line starting with
  * <b>end_line</b>, ensure that its timestamp is not more than 25 hours in
  * the past or more than 1 hour in the future with respect to <b>now</b>,

+ 2 - 0
src/or/router.h

@@ -93,6 +93,8 @@ void router_get_pref_orport(const routerinfo_t *router,
 void router_get_pref_ipv6_orport(const routerinfo_t *router,
                                  tor_addr_port_t *addr_port_out);
 int router_ipv6_preferred(const routerinfo_t *router);
+int router_has_addr(const routerinfo_t *router, const tor_addr_t *addr);
+int router_has_orport(const routerinfo_t *router, const tor_addr_port_t *orport);
 int extrainfo_dump_to_string(char **s, extrainfo_t *extrainfo,
                              crypto_pk_t *ident_key);
 int is_legal_nickname(const char *s);

+ 10 - 10
src/or/routerlist.c

@@ -1343,9 +1343,11 @@ mark_all_trusteddirservers_up(void)
 
 /** Return true iff r1 and r2 have the same address and OR port. */
 int
-routers_have_same_or_addr(const routerinfo_t *r1, const routerinfo_t *r2)
+routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2)
 {
-  return r1->addr == r2->addr && r1->or_port == r2->or_port;
+  return r1->addr == r2->addr && r1->or_port == r2->or_port &&
+    tor_addr_eq(&r1->ipv6_addr, &r2->ipv6_addr) &&
+    r1->ipv6_orport == r2->ipv6_orport;
 }
 
 /** Reset all internal variables used to count failed downloads of network
@@ -2875,7 +2877,7 @@ routerlist_insert(routerlist_t *rl, routerinfo_t *ri)
               &ri->cache_info);
   smartlist_add(rl->routers, ri);
   ri->cache_info.routerlist_index = smartlist_len(rl->routers) - 1;
-  nodelist_add_routerinfo(ri);
+  nodelist_set_routerinfo(ri, NULL);
   router_dir_info_changed();
 #ifdef DEBUG_ROUTERLIST
   routerlist_assert_ok(rl);
@@ -3104,8 +3106,11 @@ routerlist_replace(routerlist_t *rl, routerinfo_t *ri_old,
   tor_assert(0 <= idx && idx < smartlist_len(rl->routers));
   tor_assert(smartlist_get(rl->routers, idx) == ri_old);
 
-  nodelist_remove_routerinfo(ri_old);
-  nodelist_add_routerinfo(ri_new);
+  {
+    routerinfo_t *ri_old_tmp=NULL;
+    nodelist_set_routerinfo(ri_new, &ri_old_tmp);
+    tor_assert(ri_old == ri_old_tmp);
+  }
 
   router_dir_info_changed();
   if (idx >= 0) {
@@ -3442,11 +3447,6 @@ router_add_to_routerlist(routerinfo_t *router, const char **msg,
       /* Same key, and either new, or listed in the consensus. */
       log_debug(LD_DIR, "Replacing entry for router %s",
                 router_describe(router));
-      if (routers_have_same_or_addr(router, old_router)) {
-        /* these carry over when the address and orport are unchanged. */
-        router->last_reachable = old_router->last_reachable;
-        router->testing_since = old_router->testing_since;
-      }
       routerlist_replace(routerlist, old_router, router);
       if (!from_cache) {
         signed_desc_append_to_journal(&router->cache_info,

+ 1 - 1
src/or/routerlist.h

@@ -36,7 +36,7 @@ const routerstatus_t *router_pick_trusteddirserver(dirinfo_type_t type,
 int router_get_my_share_of_directory_requests(double *v2_share_out,
                                               double *v3_share_out);
 void router_reset_status_download_failures(void);
-int routers_have_same_or_addr(const routerinfo_t *r1, const routerinfo_t *r2);
+int routers_have_same_or_addrs(const routerinfo_t *r1, const routerinfo_t *r2);
 int router_nickname_is_in_list(const routerinfo_t *router, const char *list);
 const routerinfo_t *routerlist_find_my_routerinfo(void);
 const node_t *router_find_exact_exit_enclave(const char *address,