[tor-commits] [tor/master] core/or: Support IPv6 EXTEND2 cells

nickm at torproject.org nickm at torproject.org
Wed Apr 29 23:23:42 UTC 2020


commit bd6ab90ad4b40a64c604c1a4b6b37da6991fad9e
Author: teor <teor at torproject.org>
Date:   Tue Apr 14 15:08:42 2020 +1000

    core/or: Support IPv6 EXTEND2 cells
    
    Allow clients and relays to send dual-stack and IPv6-only EXTEND2 cells.
    Parse dual-stack and IPv6-only EXTEND2 cells on relays.
    
    Relays do not make connections or extend circuits via IPv6: that's the
    next step.
    
    Closes ticket 33901.
---
 changes/ticket33901          |  4 ++++
 src/core/or/onion.c          | 41 ++++++++++++++++++++++++++++++++++-------
 src/lib/net/address.c        | 14 ++++++++++++++
 src/lib/net/address.h        |  1 +
 src/test/test_cell_formats.c | 39 ++++++++++++++++++++++++++-------------
 5 files changed, 79 insertions(+), 20 deletions(-)

diff --git a/changes/ticket33901 b/changes/ticket33901
new file mode 100644
index 000000000..b824cc5b0
--- /dev/null
+++ b/changes/ticket33901
@@ -0,0 +1,4 @@
+  o Minor features (IPv6, relay):
+    - Allow clients and relays to send dual-stack and IPv6-only EXTEND2 cells.
+      Parse dual-stack and IPv6-only EXTEND2 cells on relays.
+      Closes ticket 33901.
diff --git a/src/core/or/onion.c b/src/core/or/onion.c
index 45144b5e6..543d9f3e4 100644
--- a/src/core/or/onion.c
+++ b/src/core/or/onion.c
@@ -240,11 +240,21 @@ created_cell_parse(created_cell_t *cell_out, const cell_t *cell_in)
 static int
 check_extend_cell(const extend_cell_t *cell)
 {
+  const bool is_extend2 = (cell->cell_type == RELAY_COMMAND_EXTEND2);
+
   if (tor_digest_is_zero((const char*)cell->node_id))
     return -1;
-  /* We don't currently allow EXTEND2 cells without an IPv4 address */
-  if (tor_addr_family(&cell->orport_ipv4.addr) == AF_UNSPEC)
-    return -1;
+  if (tor_addr_family(&cell->orport_ipv4.addr) == AF_UNSPEC) {
+    /* EXTEND cells must have an IPv4 address. */
+    if (!is_extend2) {
+      return -1;
+    }
+    /* EXTEND2 cells must have at least one IP address.
+     * It can be IPv4 or IPv6. */
+    if (tor_addr_family(&cell->orport_ipv6.addr) == AF_UNSPEC) {
+      return -1;
+    }
+  }
   if (cell->create_cell.cell_type == CELL_CREATE) {
     if (cell->cell_type != RELAY_COMMAND_EXTEND)
       return -1;
@@ -364,7 +374,12 @@ extend_cell_from_extend2_cell_body(extend_cell_t *cell_out,
     }
   }
 
-  if (!found_rsa_id || !found_ipv4) /* These are mandatory */
+  /* EXTEND2 cells must have an RSA ID */
+  if (!found_rsa_id)
+    return -1;
+
+  /* EXTEND2 cells must have at least one IP address */
+  if (!found_ipv4 && !found_ipv6)
     return -1;
 
   return create_cell_from_create2_cell_body(&cell_out->create_cell,
@@ -620,12 +635,13 @@ extend_cell_format(uint8_t *command_out, uint16_t *len_out,
     break;
   case RELAY_COMMAND_EXTEND2:
     {
-      uint8_t n_specifiers = 2;
+      uint8_t n_specifiers = 1;
       *command_out = RELAY_COMMAND_EXTEND2;
       extend2_cell_body_t *cell = extend2_cell_body_new();
       link_specifier_t *ls;
-      {
-        /* IPv4 specifier first. */
+      if (tor_addr_port_is_valid_ap(&cell_in->orport_ipv4, 0)) {
+        /* Maybe IPv4 specifier first. */
+        ++n_specifiers;
         ls = link_specifier_new();
         extend2_cell_body_add_ls(cell, ls);
         ls->ls_type = LS_IPV4;
@@ -651,6 +667,17 @@ extend_cell_format(uint8_t *command_out, uint16_t *len_out,
         ls->ls_len = 32;
         memcpy(ls->un_ed25519_id, cell_in->ed_pubkey.pubkey, 32);
       }
+      if (tor_addr_port_is_valid_ap(&cell_in->orport_ipv6, 0)) {
+        /* Then maybe IPv6 specifier. */
+        ++n_specifiers;
+        ls = link_specifier_new();
+        extend2_cell_body_add_ls(cell, ls);
+        ls->ls_type = LS_IPV6;
+        ls->ls_len = 18;
+        tor_addr_get_ipv6_bytes((char *)ls->un_ipv6_addr,
+                                &cell_in->orport_ipv6.addr);
+        ls->un_ipv6_port = cell_in->orport_ipv6.port;
+      }
       cell->n_spec = n_specifiers;
 
       /* Now, the handshake */
diff --git a/src/lib/net/address.c b/src/lib/net/address.c
index 5dbef6a79..5fe9abca1 100644
--- a/src/lib/net/address.c
+++ b/src/lib/net/address.c
@@ -903,6 +903,20 @@ tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6)
   tor_addr_from_ipv6_bytes(dest, (const char*)in6->s6_addr);
 }
 
+/** Set the 16 bytes at <b>dest</b> to equal the IPv6 address <b>src</b>.
+ * <b>src</b> must be an IPv6 address, if it is not, log a warning, and clear
+ * <b>dest</b>. */
+void
+tor_addr_get_ipv6_bytes(char *dest, const tor_addr_t *src)
+{
+  tor_assert(dest);
+  tor_assert(src);
+  memset(dest, 0, 16);
+  IF_BUG_ONCE(src->family != AF_INET6)
+    return;
+  memcpy(dest, src->addr.in6_addr.s6_addr, 16);
+}
+
 /** Copy a tor_addr_t from <b>src</b> to <b>dest</b>.
  */
 void
diff --git a/src/lib/net/address.h b/src/lib/net/address.h
index 498449493..f1c223310 100644
--- a/src/lib/net/address.h
+++ b/src/lib/net/address.h
@@ -303,6 +303,7 @@ void tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *bytes);
 #define tor_addr_from_in(dest, in) \
   tor_addr_from_ipv4n((dest), (in)->s_addr);
 void tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6);
+void tor_addr_get_ipv6_bytes(char *dest, const tor_addr_t *src);
 
 int tor_addr_is_null(const tor_addr_t *addr);
 int tor_addr_is_loopback(const tor_addr_t *addr);
diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c
index 8d6d1940f..3d3f151fc 100644
--- a/src/test/test_cell_formats.c
+++ b/src/test/test_cell_formats.c
@@ -713,16 +713,20 @@ test_cfmt_extend_cells(void *arg)
   tt_mem_op(cc->onionskin,OP_EQ, b, 99+20);
   tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
   tt_int_op(p2_cmd, OP_EQ, RELAY_COMMAND_EXTEND2);
-  /* We'll generate it minus the IPv6 address and minus the konami code */
-  tt_int_op(p2_len, OP_EQ, 89+99-34-20);
+  /* We'll generate it minus the konami code */
+  tt_int_op(p2_len, OP_EQ, 89+99-34);
   test_memeq_hex(p2,
-                 /* Two items: one that same darn IP address. */
-                 "02000612F40001F0F1"
-                 /* The next is a digest : anthropomorphization */
-                 "0214616e7468726f706f6d6f727068697a6174696f6e"
+                 /* Three items */
+                 "03"
+                 /* IPv4 address */
+                 "0006" "12F40001" "F0F1"
+                 /* The next is an RSA digest: anthropomorphization */
+                 "0214" "616e7468726f706f6d6f727068697a6174696f6e"
+                 /*IPv6 address */
+                 "0112" "20020000000000000000000000f0c51e" "1112"
                  /* Now the handshake prologue */
                  "01050063");
-  tt_mem_op(p2+1+8+22+4,OP_EQ, b, 99+20);
+  tt_mem_op(p2+1+8+22+20+4, OP_EQ, b, 99+20);
   tt_int_op(0, OP_EQ, create_cell_format_relayed(&cell, cc));
 
   /* Now let's add an ed25519 key to that extend2 cell. */
@@ -732,22 +736,31 @@ test_cfmt_extend_cells(void *arg)
   /* As before, since we aren't extending by ed25519. */
   get_options_mutable()->ExtendByEd25519ID = 0;
   tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
-  tt_int_op(p2_len, OP_EQ, 89+99-34-20);
+  tt_int_op(p2_len, OP_EQ, 89+99-34);
   test_memeq_hex(p2,
-                 "02000612F40001F0F1"
+                 "03"
+                 "000612F40001F0F1"
                  "0214616e7468726f706f6d6f727068697a6174696f6e"
+                 "011220020000000000000000000000f0c51e1112"
                  "01050063");
 
   /* Now try with the ed25519 ID. */
   get_options_mutable()->ExtendByEd25519ID = 1;
   tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
-  tt_int_op(p2_len, OP_EQ, 89+99-34-20 + 34);
+  tt_int_op(p2_len, OP_EQ, 89+99);
   test_memeq_hex(p2,
-                 "03000612F40001F0F1"
+                 /* Four items */
+                 "04"
+                 /* IPv4 address */
+                 "0006" "12F40001" "F0F1"
+                 /* The next is an RSA digest: anthropomorphization */
                  "0214616e7468726f706f6d6f727068697a6174696f6e"
-                 // ed digest follows:
+                 /* Then an ed public key: brownshoesdontmakeit/brownshoesd */
                  "0320" "62726f776e73686f6573646f6e746d616b656"
                         "9742f62726f776e73686f657364"
+                 /*IPv6 address */
+                 "0112" "20020000000000000000000000f0c51e" "1112"
+                 /* Now the handshake prologue */
                  "01050063");
   /* Can we parse that? Did the key come through right? */
   memset(&ec, 0, sizeof(ec));
@@ -816,7 +829,7 @@ test_cfmt_extend_cells(void *arg)
   memcpy(p+1, "\x02\x14" "anarchoindividualist", 22);
   memcpy(p+23, "\x01\x12" "xxxxxxxxxxxxxxxxYY", 18);
   memcpy(p+41, "\xff\xff\x00\x20", 4);
-  tt_int_op(-1, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
+  tt_int_op(0, OP_EQ, extend_cell_parse(&ec, RELAY_COMMAND_EXTEND2,
                                       p, sizeof(p)));
 
   /* Running out of space in specifiers  */





More information about the tor-commits mailing list