Commit bd6ab90a authored by teor's avatar teor
Browse files

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.
parent 3253c357
Loading
Loading
Loading
Loading

changes/ticket33901

0 → 100644
+4 −0
Original line number Diff line number Diff line
  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.
+34 −7
Original line number Diff line number Diff line
@@ -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)
  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 */
+14 −0
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -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);
+26 −13
Original line number Diff line number Diff line
@@ -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  */