Browse Source

Merge branch 'bug23577_squashed'

Nick Mathewson 6 years ago
parent
commit
f92736517b
4 changed files with 72 additions and 29 deletions
  1. 7 0
      changes/ticket23577
  2. 52 29
      src/or/hs_circuit.c
  3. 12 0
      src/or/nodelist.c
  4. 1 0
      src/or/nodelist.h

+ 7 - 0
changes/ticket23577

@@ -0,0 +1,7 @@
+  o Major features (v3 onion services):
+    - When v3 onion service clients send introduce cells, include the IPv6
+      address of the rendezvous point, if it has one. v3 onion services running
+      0.3.2 ignore IPv6 addresses. In future Tor versions, IPv6-only v3 single
+      onion services can use IPv6 addresses to connect directly to the
+      rendezvous point. Closes ticket 23577. Patch by Neel Chauhan.
+

+ 52 - 29
src/or/hs_circuit.c

@@ -13,6 +13,7 @@
 #include "circuitlist.h"
 #include "circuituse.h"
 #include "config.h"
+#include "nodelist.h"
 #include "policies.h"
 #include "relay.h"
 #include "rendservice.h"
@@ -553,76 +554,98 @@ retry_service_rendezvous_point(const origin_circuit_t *circ)
   return;
 }
 
-/* Using an extend info object ei, set all possible link specifiers in lspecs.
- * legacy ID is mandatory thus MUST be present in ei. If IPv4 is not present,
- * logs a BUG() warning, and returns an empty smartlist. Clients never make
- * direct connections to rendezvous points, so they should always have an
- * IPv4 address in ei. */
+/* Add all possible link specifiers in node to lspecs.
+ * legacy ID is mandatory thus MUST be present in node. If the primary address
+ * is not IPv4, log a BUG() warning, and return an empty smartlist.
+ * Includes ed25519 id and IPv6 link specifiers if present in the node. */
 static void
-get_lspecs_from_extend_info(const extend_info_t *ei, smartlist_t *lspecs)
+get_lspecs_from_node(const node_t *node, smartlist_t *lspecs)
 {
   link_specifier_t *ls;
+  tor_addr_port_t ap;
 
-  tor_assert(ei);
+  tor_assert(node);
   tor_assert(lspecs);
 
-  /* We require IPv4, we will add IPv6 support in a later tor version */
-  if (BUG(!tor_addr_is_v4(&ei->addr))) {
+  /* Get the relay's IPv4 address. */
+  node_get_prim_orport(node, &ap);
+
+  /* We expect the node's primary address to be a valid IPv4 address.
+   * This conforms to the protocol, which requires either an IPv4 or IPv6
+   * address (or both). */
+  if (BUG(!tor_addr_is_v4(&ap.addr)) ||
+      BUG(!tor_addr_port_is_valid_ap(&ap, 0))) {
     return;
   }
 
   ls = link_specifier_new();
   link_specifier_set_ls_type(ls, LS_IPV4);
-  link_specifier_set_un_ipv4_addr(ls, tor_addr_to_ipv4h(&ei->addr));
-  link_specifier_set_un_ipv4_port(ls, ei->port);
+  link_specifier_set_un_ipv4_addr(ls, tor_addr_to_ipv4h(&ap.addr));
+  link_specifier_set_un_ipv4_port(ls, ap.port);
   /* Four bytes IPv4 and two bytes port. */
-  link_specifier_set_ls_len(ls, sizeof(ei->addr.addr.in_addr) +
-                            sizeof(ei->port));
+  link_specifier_set_ls_len(ls, sizeof(ap.addr.addr.in_addr) +
+                            sizeof(ap.port));
   smartlist_add(lspecs, ls);
 
-  /* Legacy ID is mandatory. */
+  /* Legacy ID is mandatory and will always be present in node. */
   ls = link_specifier_new();
   link_specifier_set_ls_type(ls, LS_LEGACY_ID);
-  memcpy(link_specifier_getarray_un_legacy_id(ls), ei->identity_digest,
+  memcpy(link_specifier_getarray_un_legacy_id(ls), node->identity,
          link_specifier_getlen_un_legacy_id(ls));
   link_specifier_set_ls_len(ls, link_specifier_getlen_un_legacy_id(ls));
   smartlist_add(lspecs, ls);
 
-  /* ed25519 ID is only included if the extend_info has it. */
-  if (!ed25519_public_key_is_zero(&ei->ed_identity)) {
+  /* ed25519 ID is only included if the node has it. */
+  if (!ed25519_public_key_is_zero(&node->ed25519_id)) {
     ls = link_specifier_new();
     link_specifier_set_ls_type(ls, LS_ED25519_ID);
-    memcpy(link_specifier_getarray_un_ed25519_id(ls), &ei->ed_identity,
+    memcpy(link_specifier_getarray_un_ed25519_id(ls), &node->ed25519_id,
            link_specifier_getlen_un_ed25519_id(ls));
     link_specifier_set_ls_len(ls, link_specifier_getlen_un_ed25519_id(ls));
     smartlist_add(lspecs, ls);
   }
+
+  /* Check for IPv6. If so, include it as well. */
+  if (node_has_ipv6_orport(node)) {
+    ls = link_specifier_new();
+    node_get_pref_ipv6_orport(node, &ap);
+    link_specifier_set_ls_type(ls, LS_IPV6);
+    size_t addr_len = link_specifier_getlen_un_ipv6_addr(ls);
+    const uint8_t *in6_addr = tor_addr_to_in6_addr8(&ap.addr);
+    uint8_t *ipv6_array = link_specifier_getarray_un_ipv6_addr(ls);
+    memcpy(ipv6_array, in6_addr, addr_len);
+    link_specifier_set_un_ipv6_port(ls, ap.port);
+    /* Sixteen bytes IPv6 and two bytes port. */
+    link_specifier_set_ls_len(ls, addr_len + sizeof(ap.port));
+  }
 }
 
-/* Using the given descriptor intro point ip, the extend information of the
- * rendezvous point rp_ei and the service's subcredential, populate the
+/* Using the given descriptor intro point ip, the node of the
+ * rendezvous point rp_node and the service's subcredential, populate the
  * already allocated intro1_data object with the needed key material and link
  * specifiers.
  *
- * This can't fail but the ip MUST be a valid object containing the needed
- * keys and authentication method. */
+ * If rp_node has an invalid primary address, intro1_data->link_specifiers
+ * will be an empty list. Otherwise, this function can't fail. The ip
+ * MUST be a valid object containing the needed keys and authentication
+ * method. */
 static void
 setup_introduce1_data(const hs_desc_intro_point_t *ip,
-                      const extend_info_t *rp_ei,
+                      const node_t *rp_node,
                       const uint8_t *subcredential,
                       hs_cell_introduce1_data_t *intro1_data)
 {
   smartlist_t *rp_lspecs;
 
   tor_assert(ip);
-  tor_assert(rp_ei);
+  tor_assert(rp_node);
   tor_assert(subcredential);
   tor_assert(intro1_data);
 
   /* Build the link specifiers from the extend information of the rendezvous
    * circuit that we've picked previously. */
   rp_lspecs = smartlist_new();
-  get_lspecs_from_extend_info(rp_ei, rp_lspecs);
+  get_lspecs_from_node(rp_node, rp_lspecs);
 
   /* Populate the introduce1 data object. */
   memset(intro1_data, 0, sizeof(hs_cell_introduce1_data_t));
@@ -633,7 +656,7 @@ setup_introduce1_data(const hs_desc_intro_point_t *ip,
   intro1_data->auth_pk = &ip->auth_key_cert->signed_key;
   intro1_data->enc_pk = &ip->enc_key;
   intro1_data->subcredential = subcredential;
-  intro1_data->onion_pk = &rp_ei->curve25519_onion_key;
+  intro1_data->onion_pk = node_get_curve25519_onion_key(rp_node);
   intro1_data->link_specifiers = rp_lspecs;
 }
 
@@ -1079,9 +1102,9 @@ hs_circ_send_introduce1(origin_circuit_t *intro_circ,
 
   /* This takes various objects in order to populate the introduce1 data
    * object which is used to build the content of the cell. */
-  setup_introduce1_data(ip, rend_circ->build_state->chosen_exit,
-                        subcredential, &intro1_data);
-  /* If we didn't get any link specifiers, it's because our extend info was
+  const node_t *exit_node = build_state_get_exit_node(rend_circ->build_state);
+  setup_introduce1_data(ip, exit_node, subcredential, &intro1_data);
+  /* If we didn't get any link specifiers, it's because our node was
    * bad. */
   if (BUG(!intro1_data.link_specifiers) ||
       !smartlist_len(intro1_data.link_specifiers)) {

+ 12 - 0
src/or/nodelist.c

@@ -1639,6 +1639,18 @@ node_has_curve25519_onion_key(const node_t *node)
     return 0;
 }
 
+/** Return the curve25519 key of <b>node</b>, or NULL if none. */
+curve25519_public_key_t *
+node_get_curve25519_onion_key(const node_t *node)
+{
+  if (node->ri)
+    return node->ri->onion_curve25519_pkey;
+  else if (node->md)
+    return node->md->onion_curve25519_pkey;
+  else
+    return NULL;
+}
+
 /** Refresh the country code of <b>ri</b>.  This function MUST be called on
  * each router when the GeoIP database is reloaded, and on all new routers. */
 void

+ 1 - 0
src/or/nodelist.h

@@ -86,6 +86,7 @@ int node_get_prim_dirport(const node_t *node, tor_addr_port_t *ap_out);
 void node_get_pref_dirport(const node_t *node, tor_addr_port_t *ap_out);
 void node_get_pref_ipv6_dirport(const node_t *node, tor_addr_port_t *ap_out);
 int node_has_curve25519_onion_key(const node_t *node);
+curve25519_public_key_t *node_get_curve25519_onion_key(const node_t *node);
 
 MOCK_DECL(smartlist_t *, nodelist_get_list, (void));