[tor-commits] [tor/master] First chunk of support for bridges on IPv6

nickm at torproject.org nickm at torproject.org
Wed Nov 30 17:02:43 UTC 2011


commit f786307ab7f601a3cb41c46df0a09758671a0bcf
Author: Linus Nordberg <linus at nordberg.se>
Date:   Thu Nov 24 18:29:56 2011 +0100

    First chunk of support for bridges on IPv6
    
    Comments below focus on changes, see diff for added code.
    
    New type tor_addr_port_t holding an IP address and a TCP/UDP port.
    
    New flag in routerinfo_t, ipv6_preferred.  This should go in the
    node_t instead but not now.
    
    Replace node_get_addr() with
    - node_get_prim_addr() for primary address, i.e. IPv4 for now
    - node_get_pref_addr() for preferred address, IPv4 or IPv6.
    
    Rename node_get_addr_ipv4h() node_get_prim_addr_ipv4h() for
    consistency.  The primary address will not allways be an IPv4 address.
    Same for node_get_orport() -> node_get_prim_orport().
    
    Rewrite node_is_a_configured_bridge() to take all OR ports into account.
    
    Extend argument list to extend_info_from_node and
    extend_info_from_router with a flag indicating if we want to use the
    routers primary address or the preferred address.  Use the preferred
    address in as few situtations as possible for allowing clients to
    connect to bridges over IPv6.
---
 src/common/address.h  |    7 +++
 src/or/circuitbuild.c |   75 +++++++++++++++++++++----------
 src/or/circuitbuild.h |    6 ++-
 src/or/circuituse.c   |    5 ++-
 src/or/control.c      |    2 +-
 src/or/nodelist.c     |  121 +++++++++++++++++++++++++++++++++++++++++++------
 src/or/nodelist.h     |   16 +++++-
 src/or/or.h           |    2 +
 src/or/rendclient.c   |    2 +-
 src/or/rendservice.c  |    4 +-
 src/or/router.c       |   56 ++++++++++++++++++++++-
 src/or/router.h       |    7 +++
 12 files changed, 253 insertions(+), 50 deletions(-)

diff --git a/src/common/address.h b/src/common/address.h
index bc225a6..4568c32 100644
--- a/src/common/address.h
+++ b/src/common/address.h
@@ -31,6 +31,13 @@ typedef struct tor_addr_t
   } addr;
 } tor_addr_t;
 
+/** Holds an IP address and a TCP/UDP port.  */
+typedef struct tor_addr_port_t
+{
+  tor_addr_t addr;
+  uint16_t port;
+} tor_addr_port_t;
+
 static INLINE const struct in6_addr *tor_addr_to_in6(const tor_addr_t *a);
 static INLINE uint32_t tor_addr_to_ipv4n(const tor_addr_t *a);
 static INLINE uint32_t tor_addr_to_ipv4h(const tor_addr_t *a);
diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 1cfeb03..fbd55dd 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -3012,7 +3012,7 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit)
       log_warn(LD_CIRC,"failed to choose an exit server");
       return -1;
     }
-    exit = extend_info_from_node(node);
+    exit = extend_info_from_node(node, 0);
     tor_assert(exit);
   }
   state->chosen_exit = exit;
@@ -3254,14 +3254,19 @@ onion_extend_cpath(origin_circuit_t *circ)
   } else if (cur_len == 0) { /* picking first node */
     const node_t *r = choose_good_entry_server(purpose, state);
     if (r) {
-      info = extend_info_from_node(r);
+      /* If we're extending to a bridge, use the preferred address
+         rather than the primary, for potentially extending to an IPv6
+         bridge.  */
+      int use_pref_addr = (r->ri != NULL &&
+                           r->ri->purpose == ROUTER_PURPOSE_BRIDGE);
+      info = extend_info_from_node(r, use_pref_addr);
       tor_assert(info);
     }
   } else {
     const node_t *r =
       choose_good_middle_server(purpose, state, circ->cpath, cur_len);
     if (r) {
-      info = extend_info_from_node(r);
+      info = extend_info_from_node(r, 0);
       tor_assert(info);
     }
   }
@@ -3320,28 +3325,37 @@ extend_info_alloc(const char *nickname, const char *digest,
   return info;
 }
 
-/** Allocate and return a new extend_info_t that can be used to build a
- * circuit to or through the router <b>r</b>. */
+/** Allocate and return a new extend_info_t that can be used to build
+ * a circuit to or through the router <b>r</b>. Use the primary
+ * address of the router unless <b>for_direct_connect</b> is true, in
+ * which case the preferred address is used instead. */
 extend_info_t *
-extend_info_from_router(const routerinfo_t *r)
+extend_info_from_router(const routerinfo_t *r, int for_direct_connect)
 {
   tor_addr_t addr;
+  uint16_t port;
   tor_assert(r);
-  tor_addr_from_ipv4h(&addr, r->addr);
+
+  if (for_direct_connect)
+    router_get_pref_addr_port(r, &addr, &port);
+  else
+    router_get_prim_addr_port(r, &addr, &port);
   return extend_info_alloc(r->nickname, r->cache_info.identity_digest,
-                           r->onion_pkey, &addr, r->or_port);
+                           r->onion_pkey, &addr, port);
 }
 
-/** Allocate and return a new extend_info that can be used to build a ircuit
- * to or through the node <b>node</b>.  May return NULL if there is not
- * enough info about <b>node</b> to extend to it--for example, if there
- * is no routerinfo_t or microdesc_t.
+/** Allocate and return a new extend_info that can be used to build a
+ * ircuit to or through the node <b>node</b>. Use the primary address
+ * of the node unless <b>for_direct_connect</b> is true, in which case
+ * the preferred address is used instead. May return NULL if there is
+ * not enough info about <b>node</b> to extend to it--for example, if
+ * there is no routerinfo_t or microdesc_t.
  **/
 extend_info_t *
-extend_info_from_node(const node_t *node)
+extend_info_from_node(const node_t *node, int for_direct_connect)
 {
   if (node->ri) {
-    return extend_info_from_router(node->ri);
+    return extend_info_from_router(node->ri, for_direct_connect);
   } else if (node->rs && node->md) {
     tor_addr_t addr;
     tor_addr_from_ipv4h(&addr, node->rs->addr);
@@ -4858,18 +4872,31 @@ routerinfo_is_a_configured_bridge(const routerinfo_t *ri)
 int
 node_is_a_configured_bridge(const node_t *node)
 {
-  tor_addr_t addr;
-  uint16_t orport;
+  int retval = 0;		/* Negative.  */
+  smartlist_t *orports = NULL;
+
   if (!node)
-    return 0;
-  if (node_get_addr(node, &addr) < 0)
-    return 0;
-  orport = node_get_orport(node);
-  if (orport == 0)
-    return 0;
+    goto out;
+
+  orports = node_get_all_orports(node);
+  if (orports == NULL)
+    goto out;
 
-  return get_configured_bridge_by_addr_port_digest(
-                       &addr, orport, node->identity) != NULL;
+  SMARTLIST_FOREACH_BEGIN(orports, tor_addr_port_t *, orport) {
+    if (get_configured_bridge_by_addr_port_digest(&orport->addr, orport->port,
+						  node->identity) != NULL) {
+      retval = 1;
+      goto out;
+    }
+  } SMARTLIST_FOREACH_END(orport);
+
+out:
+  if (orports != NULL) {
+    SMARTLIST_FOREACH(orports, tor_addr_port_t *, p, tor_free(p));
+    smartlist_free(orports);
+    orports = NULL;
+  }
+  return retval;
 }
 
 /** We made a connection to a router at <b>addr</b>:<b>port</b>
diff --git a/src/or/circuitbuild.h b/src/or/circuitbuild.h
index 1052db6..8df2748 100644
--- a/src/or/circuitbuild.h
+++ b/src/or/circuitbuild.h
@@ -59,8 +59,10 @@ void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop);
 extend_info_t *extend_info_alloc(const char *nickname, const char *digest,
                                  crypto_pk_env_t *onion_key,
                                  const tor_addr_t *addr, uint16_t port);
-extend_info_t *extend_info_from_router(const routerinfo_t *r);
-extend_info_t *extend_info_from_node(const node_t *node);
+extend_info_t *extend_info_from_router(const routerinfo_t *r,
+                                       int for_direct_connect);
+extend_info_t *extend_info_from_node(const node_t *node,
+                                     int for_direct_connect);
 extend_info_t *extend_info_dup(extend_info_t *info);
 void extend_info_free(extend_info_t *info);
 const node_t *build_state_get_exit_node(cpath_build_state_t *state);
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index 23efe05..4382d44 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -1439,7 +1439,10 @@ circuit_get_open_circ_or_launch(entry_connection_t *conn,
         int opt = conn->chosen_exit_optional;
         r = node_get_by_nickname(conn->chosen_exit_name, 1);
         if (r && node_has_descriptor(r)) {
-          extend_info = extend_info_from_node(r);
+          /* We might want to connect to an IPv6 bridge for loading
+             descriptors so we use the preferred address rather than
+             the primary.  */
+          extend_info = extend_info_from_node(r, conn->want_onehop ? 1 : 0);
         } else {
           log_debug(LD_DIR, "considering %d, %s",
                     want_onehop, conn->chosen_exit_name);
diff --git a/src/or/control.c b/src/or/control.c
index e2d0eec..65b1619 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -2402,7 +2402,7 @@ handle_control_extendcircuit(control_connection_t *conn, uint32_t len,
   /* now circ refers to something that is ready to be extended */
   SMARTLIST_FOREACH(nodes, const node_t *, node,
   {
-    extend_info_t *info = extend_info_from_node(node);
+    extend_info_t *info = extend_info_from_node(node, 0);
     tor_assert(info); /* True, since node_has_descriptor(node) == true */
     circuit_append_new_exit(circ, info);
     extend_info_free(info);
diff --git a/src/or/nodelist.c b/src/or/nodelist.c
index b93b919..08dcde6 100644
--- a/src/or/nodelist.c
+++ b/src/or/nodelist.c
@@ -646,24 +646,59 @@ node_exit_policy_rejects_all(const node_t *node)
     return 1;
 }
 
-/** Copy the address for <b>node</b> into *<b>addr_out</b>. */
-int
-node_get_addr(const node_t *node, tor_addr_t *addr_out)
+/** Return list of tor_addr_port_t with all OR ports (in the sense IP
+ * addr + TCP port) for <b>node</b>.  Caller must free all elements
+ * using tor_free() and free the list using smartlist_free().
+ *
+ * XXX this is potentially a memory fragmentation hog -- if on
+ * critical path consider the option of having the caller allocate the
+ * memory
+ */
+smartlist_t *
+node_get_all_orports(const node_t *node)
+{
+  smartlist_t *sl = smartlist_create();
+
+  if (node->ri != NULL) {
+    if (node->ri->addr != 0) {
+      tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t));
+      tor_addr_from_ipv4h(&ap->addr, node->ri->addr);
+      ap->port = node->ri->or_port;
+      smartlist_add(sl, ap);
+    }
+    if (!tor_addr_is_null(&node->ri->ipv6_addr)) {
+      tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t));
+      tor_addr_copy(&ap->addr, &node->ri->ipv6_addr);
+      ap->port = node->ri->or_port;
+      smartlist_add(sl, ap);
+    }
+  } else if (node->rs != NULL) {
+      tor_addr_port_t *ap = tor_malloc(sizeof(tor_addr_port_t));
+      tor_addr_from_ipv4h(&ap->addr, node->rs->addr);
+      ap->port = node->rs->or_port;
+      smartlist_add(sl, ap);
+  }
+
+  return sl;
+}
+
+/** Copy the primary, IPv4, address for <b>node</b> into
+ * *<b>addr_out</b>.  */
+void
+node_get_prim_addr(const node_t *node, tor_addr_t *addr_out)
 {
   if (node->ri) {
-    tor_addr_from_ipv4h(addr_out, node->ri->addr);
-    return 0;
-  } else if (node->rs) {
+    router_get_prim_addr_port(node->ri, addr_out, NULL);
+  }
+  else if (node->rs) {
     tor_addr_from_ipv4h(addr_out, node->rs->addr);
-    return 0;
   }
-  return -1;
 }
 
 /** Return the host-order IPv4 address for <b>node</b>, or 0 if it doesn't
  * seem to have one.  */
 uint32_t
-node_get_addr_ipv4h(const node_t *node)
+node_get_prim_addr_ipv4h(const node_t *node)
 {
   if (node->ri) {
     return node->ri->addr;
@@ -673,9 +708,45 @@ node_get_addr_ipv4h(const node_t *node)
   return 0;
 }
 
-/** Copy a string representation of the IP address for <b>node</b> into the
- * <b>len</b>-byte buffer at <b>buf</b>.
- */
+/** Return 1 if we prefer the IPv6 address of <b>node</b>, else 0.  */
+static int
+node_ipv6_preferred(const node_t *node)
+{
+  if (node->ri != NULL)
+    return router_ipv6_preferred(node->ri);
+  return 0;
+}
+
+/** Copy the preferred address for <b>node</b> into
+ * <b>addr_out</b>.  */
+void
+node_get_pref_addr(const node_t *node, tor_addr_t *addr_out)
+{
+  if (node->ri) {
+    router_get_pref_addr_port(node->ri, addr_out, NULL);
+  } else if (node->rs) {
+    /* No IPv6 in routerstatus_t yet.  XXXprop186 ok for private
+       bridges but needs fixing */
+    tor_addr_from_ipv4h(addr_out, node->rs->addr);
+  }
+}
+
+/** Copy the preferred IPv6 address for <b>node</b> into
+ * *<b>addr_out</b>. */
+void
+node_get_pref_ipv6_addr(const node_t *node, tor_addr_t *addr_out)
+{
+  if (node->ri) {
+    tor_addr_copy(addr_out, &node->ri->ipv6_addr);
+  } else if (node->rs) {
+    /* No IPv6 in routerstatus_t yet.  XXXprop186 ok for private
+       bridges but needs fixing */
+    tor_addr_make_unspec(addr_out);
+  }
+}
+
+/** Copy a string representation of an IP address for <b>node</b> into
+ * the <b>len</b>-byte buffer at <b>buf</b>.  */
 void
 node_get_address_string(const node_t *node, char *buf, size_t len)
 {
@@ -701,9 +772,9 @@ node_get_declared_uptime(const node_t *node)
     return -1;
 }
 
-/** Return <b>node</b>'s declared or_port */
+/** Return <b>node</b>'s declared primary (IPv4) or_port. */
 uint16_t
-node_get_orport(const node_t *node)
+node_get_prim_orport(const node_t *node)
 {
   if (node->ri)
     return node->ri->or_port;
@@ -713,6 +784,28 @@ node_get_orport(const node_t *node)
     return 0;
 }
 
+/** Return <b>node</b>'s preferred or_port. */
+uint16_t
+node_get_pref_orport(const node_t *node)
+{
+  if (node_ipv6_preferred(node))
+    return node_get_pref_ipv6_orport(node);
+  else
+    return node_get_prim_orport(node);
+}
+
+/** Return <b>node</b>'s preferred IPv6 or_port. */
+uint16_t
+node_get_pref_ipv6_orport(const node_t *node)
+{
+  if (node->ri)
+    return node->ri->ipv6_orport;
+  else if (node->rs)
+    return 0;			/* No IPv6 in routerstatus_t yet. */
+  else
+    return 0;
+}
+
 /** Return <b>node</b>'s platform string, or NULL if we don't know it. */
 const char *
 node_get_platform(const node_t *node)
diff --git a/src/or/nodelist.h b/src/or/nodelist.h
index bd2e639..70c76d6 100644
--- a/src/or/nodelist.h
+++ b/src/or/nodelist.h
@@ -37,10 +37,15 @@ int node_get_purpose(const node_t *node);
   (node_get_purpose((node)) == ROUTER_PURPOSE_BRIDGE)
 int node_is_me(const node_t *node);
 int node_exit_policy_rejects_all(const node_t *node);
-int node_get_addr(const node_t *node, tor_addr_t *addr_out);
-uint32_t node_get_addr_ipv4h(const node_t *node);
+smartlist_t *node_get_all_orports(const node_t *node);
+void node_get_prim_addr(const node_t *node, tor_addr_t *addr_out);
+void node_get_pref_addr(const node_t *node, tor_addr_t *addr_out);
+void node_get_pref_ipv6_addr(const node_t *node, tor_addr_t *addr_out);
+uint32_t node_get_prim_addr_ipv4h(const node_t *node);
 int node_allows_single_hop_exits(const node_t *node);
-uint16_t node_get_orport(const node_t *node);
+uint16_t node_get_prim_orport(const node_t *node);
+uint16_t node_get_pref_orport(const node_t *node);
+uint16_t node_get_pref_ipv6_orport(const node_t *node);
 const char *node_get_nickname(const node_t *node);
 const char *node_get_platform(const node_t *node);
 void node_get_address_string(const node_t *node, char *cp, size_t len);
@@ -50,6 +55,11 @@ const smartlist_t *node_get_declared_family(const node_t *node);
 
 smartlist_t *nodelist_get_list(void);
 
+/* Temporary aliases during transition to multiple addresses.  */
+#define node_get_addr(n,a) node_get_prim_addr((n),(a))
+#define node_get_addr_ipv4h(n) node_get_prim_addr_ipv4h((n))
+#define node_get_orport(n) node_get_prim_orport((n))
+
 /* XXXX These need to move out of routerlist.c */
 void nodelist_refresh_countries(void);
 void node_set_country(node_t *node);
diff --git a/src/or/or.h b/src/or/or.h
index 2adaa22..c342880 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1760,6 +1760,8 @@ typedef struct {
   /** True if, after we have added this router, we should re-launch
    * tests for it. */
   unsigned int needs_retest_if_added:1;
+  /** True if ipv6_addr:ipv6_orport is preferred.  */
+  unsigned int ipv6_preferred:1;
 
 /** Tor can use this router for general positions in circuits; we got it
  * from a directory server as usual, or we're an authority and a server
diff --git a/src/or/rendclient.c b/src/or/rendclient.c
index 6a45207..cda03c2 100644
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@ -1059,7 +1059,7 @@ rend_client_get_random_intro_impl(const rend_cache_entry_t *entry,
       smartlist_del(usable_nodes, i);
       goto again;
     }
-    new_extend_info = extend_info_from_node(node);
+    new_extend_info = extend_info_from_node(node, 0);
     if (!new_extend_info) {
       log_info(LD_REND, "We don't have a descriptor for the intro-point relay "
                "'%s'; trying another.",
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index 0ded538..b4ef8b4 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -1142,7 +1142,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
       goto err;
     }
 
-    extend_info = extend_info_from_node(node);
+    extend_info = extend_info_from_node(node, 0);
   }
 
   if (len != REND_COOKIE_LEN+DH_KEY_LEN) {
@@ -2151,7 +2151,7 @@ rend_services_introduce(void)
       intro_point_set_changed = 1;
       smartlist_add(intro_nodes, (void*)node);
       intro = tor_malloc_zero(sizeof(rend_intro_point_t));
-      intro->extend_info = extend_info_from_node(node);
+      intro->extend_info = extend_info_from_node(node, 0);
       intro->intro_key = crypto_new_pk_env();
       tor_assert(!crypto_pk_generate_key(intro->intro_key));
       intro->time_published = -1;
diff --git a/src/or/router.c b/src/or/router.c
index c92c5bd..d021737 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -893,7 +893,8 @@ consider_testing_reachability(int test_or, int test_dir)
     log_info(LD_CIRC, "Testing %s of my ORPort: %s:%d.",
              !orport_reachable ? "reachability" : "bandwidth",
              me->address, me->or_port);
-    ei = extend_info_from_router(me);
+    /* XXX IPv6 self testing IPv6 orports will need pref_addr */
+    ei = extend_info_from_router(me, 0);
     circuit_launch_by_extend_info(CIRCUIT_PURPOSE_TESTING, ei,
                             CIRCLAUNCH_NEED_CAPACITY|CIRCLAUNCH_IS_INTERNAL);
     extend_info_free(ei);
@@ -1201,7 +1202,6 @@ consider_publishable_server(int force)
 /** Return the port that we should advertise as our ORPort; this is either
  * the one configured in the ORPort option, or the one we actually bound to
  * if ORPort is "auto".
- * DOCDOC
  */
 uint16_t
 router_get_advertised_or_port(const or_options_t *options)
@@ -2121,6 +2121,58 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
   return (int)written+1;
 }
 
+
+/** Copy the primary, IPv4, address and port for <b>router</b> into
+    *<b>addr_out</b> and *<b>port_out</b>. */
+void
+router_get_prim_addr_port(const routerinfo_t *router, tor_addr_t *addr_out,
+			  uint16_t *port_out)
+{
+  if (addr_out != NULL)
+    tor_addr_from_ipv4h(addr_out, router->addr);
+  if (port_out != NULL)
+    *port_out = router->or_port;
+}
+
+/** Copy the alternative, presumably IPv6, address and port for
+    <b>router</b> into *<b>addr_out</b> and *<b>port_out</b>. */
+void
+router_get_alt_addr_port(const routerinfo_t *router,
+			 tor_addr_t *addr_out,
+			 uint16_t *port_out)
+{
+  if (addr_out != NULL)
+    tor_addr_copy(addr_out, &router->ipv6_addr);
+  if (port_out != NULL)
+    *port_out = router->ipv6_orport;
+}
+
+/** Return 1 if we prefer the IPv6 address of <b>router</b>, else 0.
+
+    We prefer the IPv6 address if the router has one and
+    i) the routerinfo_t says so
+    or
+    ii) the router has no IPv4 address.  */
+int
+router_ipv6_preferred(const routerinfo_t *router)
+{
+  return (!tor_addr_is_null(&router->ipv6_addr)
+	  && (router->ipv6_preferred || router->addr == 0));
+}
+
+/** Copy the preferred IP address and port for <b>router</b> into
+    *<b>addr_out</b> and *<b>port_out</b> .  */
+void
+router_get_pref_addr_port(const routerinfo_t *router,
+			  tor_addr_t *addr_out,
+			  uint16_t *port_out)
+{
+  if (router_ipv6_preferred(router))
+    router_get_alt_addr_port(router, addr_out, port_out);
+  else
+    router_get_prim_addr_port(router, addr_out, port_out);
+}
+
 /** 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>,
diff --git a/src/or/router.h b/src/or/router.h
index 6a9851c..4094b66 100644
--- a/src/or/router.h
+++ b/src/or/router.h
@@ -85,6 +85,13 @@ int router_pick_published_address(const or_options_t *options, uint32_t *addr);
 int router_rebuild_descriptor(int force);
 int router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
                                  crypto_pk_env_t *ident_key);
+void router_get_prim_addr_port(const routerinfo_t *router, tor_addr_t *addr_out,
+			       uint16_t *port_out);
+void router_get_alt_addr_port(const routerinfo_t *router, tor_addr_t *addr_out,
+			      uint16_t *port_out);
+void router_get_pref_addr_port(const routerinfo_t *router, tor_addr_t *addr_out,
+			       uint16_t *port_out);
+int router_ipv6_preferred(const routerinfo_t *router);
 int extrainfo_dump_to_string(char **s, extrainfo_t *extrainfo,
                              crypto_pk_env_t *ident_key);
 int is_legal_nickname(const char *s);





More information about the tor-commits mailing list