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.
This commit is contained in:
teor 2020-04-14 15:08:42 +10:00
parent 3253c357ee
commit bd6ab90ad4
5 changed files with 79 additions and 20 deletions

4
changes/ticket33901 Normal file
View File

@ -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.

View File

@ -240,11 +240,21 @@ created_cell_parse(created_cell_t *cell_out, const cell_t *cell_in)
static int static int
check_extend_cell(const extend_cell_t *cell) 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)) if (tor_digest_is_zero((const char*)cell->node_id))
return -1; 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. */
return -1; 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->create_cell.cell_type == CELL_CREATE) {
if (cell->cell_type != RELAY_COMMAND_EXTEND) if (cell->cell_type != RELAY_COMMAND_EXTEND)
return -1; 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 -1;
return create_cell_from_create2_cell_body(&cell_out->create_cell, 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; break;
case RELAY_COMMAND_EXTEND2: case RELAY_COMMAND_EXTEND2:
{ {
uint8_t n_specifiers = 2; uint8_t n_specifiers = 1;
*command_out = RELAY_COMMAND_EXTEND2; *command_out = RELAY_COMMAND_EXTEND2;
extend2_cell_body_t *cell = extend2_cell_body_new(); extend2_cell_body_t *cell = extend2_cell_body_new();
link_specifier_t *ls; link_specifier_t *ls;
{ if (tor_addr_port_is_valid_ap(&cell_in->orport_ipv4, 0)) {
/* IPv4 specifier first. */ /* Maybe IPv4 specifier first. */
++n_specifiers;
ls = link_specifier_new(); ls = link_specifier_new();
extend2_cell_body_add_ls(cell, ls); extend2_cell_body_add_ls(cell, ls);
ls->ls_type = LS_IPV4; ls->ls_type = LS_IPV4;
@ -651,6 +667,17 @@ extend_cell_format(uint8_t *command_out, uint16_t *len_out,
ls->ls_len = 32; ls->ls_len = 32;
memcpy(ls->un_ed25519_id, cell_in->ed_pubkey.pubkey, 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; cell->n_spec = n_specifiers;
/* Now, the handshake */ /* Now, the handshake */

View File

@ -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); 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>. /** Copy a tor_addr_t from <b>src</b> to <b>dest</b>.
*/ */
void void

View File

@ -303,6 +303,7 @@ void tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *bytes);
#define tor_addr_from_in(dest, in) \ #define tor_addr_from_in(dest, in) \
tor_addr_from_ipv4n((dest), (in)->s_addr); 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_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_null(const tor_addr_t *addr);
int tor_addr_is_loopback(const tor_addr_t *addr); int tor_addr_is_loopback(const tor_addr_t *addr);

View File

@ -713,16 +713,20 @@ test_cfmt_extend_cells(void *arg)
tt_mem_op(cc->onionskin,OP_EQ, b, 99+20); 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(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec));
tt_int_op(p2_cmd, OP_EQ, RELAY_COMMAND_EXTEND2); tt_int_op(p2_cmd, OP_EQ, RELAY_COMMAND_EXTEND2);
/* We'll generate it minus the IPv6 address and minus the konami code */ /* We'll generate it minus the konami code */
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, test_memeq_hex(p2,
/* Two items: one that same darn IP address. */ /* Three items */
"02000612F40001F0F1" "03"
/* The next is a digest : anthropomorphization */ /* IPv4 address */
"0214616e7468726f706f6d6f727068697a6174696f6e" "0006" "12F40001" "F0F1"
/* The next is an RSA digest: anthropomorphization */
"0214" "616e7468726f706f6d6f727068697a6174696f6e"
/*IPv6 address */
"0112" "20020000000000000000000000f0c51e" "1112"
/* Now the handshake prologue */ /* Now the handshake prologue */
"01050063"); "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)); tt_int_op(0, OP_EQ, create_cell_format_relayed(&cell, cc));
/* Now let's add an ed25519 key to that extend2 cell. */ /* 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. */ /* As before, since we aren't extending by ed25519. */
get_options_mutable()->ExtendByEd25519ID = 0; get_options_mutable()->ExtendByEd25519ID = 0;
tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec)); 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, test_memeq_hex(p2,
"02000612F40001F0F1" "03"
"000612F40001F0F1"
"0214616e7468726f706f6d6f727068697a6174696f6e" "0214616e7468726f706f6d6f727068697a6174696f6e"
"011220020000000000000000000000f0c51e1112"
"01050063"); "01050063");
/* Now try with the ed25519 ID. */ /* Now try with the ed25519 ID. */
get_options_mutable()->ExtendByEd25519ID = 1; get_options_mutable()->ExtendByEd25519ID = 1;
tt_int_op(0, OP_EQ, extend_cell_format(&p2_cmd, &p2_len, p2, &ec)); 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, test_memeq_hex(p2,
"03000612F40001F0F1" /* Four items */
"04"
/* IPv4 address */
"0006" "12F40001" "F0F1"
/* The next is an RSA digest: anthropomorphization */
"0214616e7468726f706f6d6f727068697a6174696f6e" "0214616e7468726f706f6d6f727068697a6174696f6e"
// ed digest follows: /* Then an ed public key: brownshoesdontmakeit/brownshoesd */
"0320" "62726f776e73686f6573646f6e746d616b656" "0320" "62726f776e73686f6573646f6e746d616b656"
"9742f62726f776e73686f657364" "9742f62726f776e73686f657364"
/*IPv6 address */
"0112" "20020000000000000000000000f0c51e" "1112"
/* Now the handshake prologue */
"01050063"); "01050063");
/* Can we parse that? Did the key come through right? */ /* Can we parse that? Did the key come through right? */
memset(&ec, 0, sizeof(ec)); memset(&ec, 0, sizeof(ec));
@ -816,7 +829,7 @@ test_cfmt_extend_cells(void *arg)
memcpy(p+1, "\x02\x14" "anarchoindividualist", 22); memcpy(p+1, "\x02\x14" "anarchoindividualist", 22);
memcpy(p+23, "\x01\x12" "xxxxxxxxxxxxxxxxYY", 18); memcpy(p+23, "\x01\x12" "xxxxxxxxxxxxxxxxYY", 18);
memcpy(p+41, "\xff\xff\x00\x20", 4); 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))); p, sizeof(p)));
/* Running out of space in specifiers */ /* Running out of space in specifiers */