|
@@ -76,6 +76,9 @@
|
|
|
#include "rephist.h"
|
|
|
#include "router.h"
|
|
|
|
|
|
+// trunnel
|
|
|
+#include "ed25519_cert.h"
|
|
|
+
|
|
|
/** Type for a linked list of circuits that are waiting for a free CPU worker
|
|
|
* to process a waiting onion handshake. */
|
|
|
typedef struct onion_queue_t {
|
|
@@ -871,13 +874,111 @@ check_extend_cell(const extend_cell_t *cell)
|
|
|
return check_create_cell(&cell->create_cell, 1);
|
|
|
}
|
|
|
|
|
|
-/** Protocol constants for specifier types in EXTEND2
|
|
|
- * @{
|
|
|
- */
|
|
|
-#define SPECTYPE_IPV4 0
|
|
|
-#define SPECTYPE_IPV6 1
|
|
|
-#define SPECTYPE_LEGACY_ID 2
|
|
|
-/** @} */
|
|
|
+static int
|
|
|
+extend_cell_from_extend1_cell_body(extend_cell_t *cell_out,
|
|
|
+ const extend1_cell_body_t *cell)
|
|
|
+{
|
|
|
+ tor_assert(cell_out);
|
|
|
+ memset(cell_out, 0, sizeof(*cell_out));
|
|
|
+ tor_addr_make_unspec(&cell_out->orport_ipv4.addr);
|
|
|
+ tor_addr_make_unspec(&cell_out->orport_ipv6.addr);
|
|
|
+
|
|
|
+ cell_out->cell_type = RELAY_COMMAND_EXTEND;
|
|
|
+ tor_addr_from_ipv4h(&cell_out->orport_ipv4.addr, cell->ipv4addr);
|
|
|
+ cell_out->orport_ipv4.port = cell->port;
|
|
|
+ if (tor_memeq(cell->onionskin, NTOR_CREATE_MAGIC, 16)) {
|
|
|
+ cell_out->create_cell.cell_type = CELL_CREATE2;
|
|
|
+ cell_out->create_cell.handshake_type = ONION_HANDSHAKE_TYPE_NTOR;
|
|
|
+ cell_out->create_cell.handshake_len = NTOR_ONIONSKIN_LEN;
|
|
|
+ memcpy(cell_out->create_cell.onionskin, cell->onionskin + 16,
|
|
|
+ NTOR_ONIONSKIN_LEN);
|
|
|
+ } else {
|
|
|
+ cell_out->create_cell.cell_type = CELL_CREATE;
|
|
|
+ cell_out->create_cell.handshake_type = ONION_HANDSHAKE_TYPE_TAP;
|
|
|
+ cell_out->create_cell.handshake_len = TAP_ONIONSKIN_CHALLENGE_LEN;
|
|
|
+ memcpy(cell_out->create_cell.onionskin, cell->onionskin,
|
|
|
+ TAP_ONIONSKIN_CHALLENGE_LEN);
|
|
|
+ }
|
|
|
+ memcpy(cell_out->node_id, cell->identity, DIGEST_LEN);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+create_cell_from_create2_cell_body(create_cell_t *cell_out,
|
|
|
+ const create2_cell_body_t *cell)
|
|
|
+{
|
|
|
+ tor_assert(cell_out);
|
|
|
+ memset(cell_out, 0, sizeof(create_cell_t));
|
|
|
+ if (BUG(cell->handshake_len > sizeof(cell_out->onionskin))) {
|
|
|
+ /* This should be impossible because there just isn't enough room in the
|
|
|
+ * input cell to make the handshake_len this large and provide a
|
|
|
+ * handshake_data to match. */
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ cell_out->cell_type = CELL_CREATE2;
|
|
|
+ cell_out->handshake_type = cell->handshake_type;
|
|
|
+ cell_out->handshake_len = cell->handshake_len;
|
|
|
+ memcpy(cell_out->onionskin,
|
|
|
+ create2_cell_body_getconstarray_handshake_data(cell),
|
|
|
+ cell->handshake_len);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+extend_cell_from_extend2_cell_body(extend_cell_t *cell_out,
|
|
|
+ const extend2_cell_body_t *cell)
|
|
|
+{
|
|
|
+ tor_assert(cell_out);
|
|
|
+ int found_ipv4 = 0, found_ipv6 = 0, found_rsa_id = 0, found_ed_id = 0;
|
|
|
+ memset(cell_out, 0, sizeof(*cell_out));
|
|
|
+ tor_addr_make_unspec(&cell_out->orport_ipv4.addr);
|
|
|
+ tor_addr_make_unspec(&cell_out->orport_ipv6.addr);
|
|
|
+ cell_out->cell_type = RELAY_COMMAND_EXTEND2;
|
|
|
+
|
|
|
+ unsigned i;
|
|
|
+ for (i = 0; i < cell->n_spec; ++i) {
|
|
|
+ const link_specifier_t *ls = extend2_cell_body_getconst_ls(cell, i);
|
|
|
+ switch (ls->ls_type) {
|
|
|
+ case LS_IPV4:
|
|
|
+ if (found_ipv4)
|
|
|
+ continue;
|
|
|
+ found_ipv4 = 1;
|
|
|
+ tor_addr_from_ipv4h(&cell_out->orport_ipv4.addr, ls->un_ipv4_addr);
|
|
|
+ cell_out->orport_ipv4.port = ls->un_ipv4_port;
|
|
|
+ break;
|
|
|
+ case LS_IPV6:
|
|
|
+ if (found_ipv6)
|
|
|
+ continue;
|
|
|
+ found_ipv6 = 1;
|
|
|
+ tor_addr_from_ipv6_bytes(&cell_out->orport_ipv6.addr,
|
|
|
+ (const char *)ls->un_ipv6_addr);
|
|
|
+ cell_out->orport_ipv6.port = ls->un_ipv6_port;
|
|
|
+ break;
|
|
|
+ case LS_LEGACY_ID:
|
|
|
+ if (found_rsa_id)
|
|
|
+ return -1;
|
|
|
+ found_rsa_id = 1;
|
|
|
+ memcpy(cell_out->node_id, ls->un_legacy_id, 20);
|
|
|
+ break;
|
|
|
+ case LS_ED25519_ID:
|
|
|
+ if (found_ed_id)
|
|
|
+ return -1;
|
|
|
+ found_ed_id = 1;
|
|
|
+ memcpy(cell_out->ed_pubkey.pubkey, ls->un_ed25519_id, 32);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ /* Ignore this, whatever it is. */
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!found_rsa_id || !found_ipv4) /* These are mandatory */
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ return create_cell_from_create2_cell_body(&cell_out->create_cell,
|
|
|
+ cell->create2);
|
|
|
+}
|
|
|
|
|
|
/** Parse an EXTEND or EXTEND2 cell (according to <b>command</b>) from the
|
|
|
* <b>payload_length</b> bytes of <b>payload</b> into <b>cell_out</b>. Return
|
|
@@ -886,101 +987,41 @@ int
|
|
|
extend_cell_parse(extend_cell_t *cell_out, const uint8_t command,
|
|
|
const uint8_t *payload, size_t payload_length)
|
|
|
{
|
|
|
- const uint8_t *eop;
|
|
|
|
|
|
- memset(cell_out, 0, sizeof(*cell_out));
|
|
|
if (payload_length > RELAY_PAYLOAD_SIZE)
|
|
|
return -1;
|
|
|
- eop = payload + payload_length;
|
|
|
|
|
|
switch (command) {
|
|
|
case RELAY_COMMAND_EXTEND:
|
|
|
{
|
|
|
- if (payload_length != 6 + TAP_ONIONSKIN_CHALLENGE_LEN + DIGEST_LEN)
|
|
|
+ extend1_cell_body_t *cell = NULL;
|
|
|
+ if (extend1_cell_body_parse(&cell, payload, payload_length)<0 ||
|
|
|
+ cell == NULL) {
|
|
|
+ if (cell)
|
|
|
+ extend1_cell_body_free(cell);
|
|
|
return -1;
|
|
|
-
|
|
|
- cell_out->cell_type = RELAY_COMMAND_EXTEND;
|
|
|
- tor_addr_from_ipv4n(&cell_out->orport_ipv4.addr, get_uint32(payload));
|
|
|
- cell_out->orport_ipv4.port = ntohs(get_uint16(payload+4));
|
|
|
- tor_addr_make_unspec(&cell_out->orport_ipv6.addr);
|
|
|
- if (tor_memeq(payload + 6, NTOR_CREATE_MAGIC, 16)) {
|
|
|
- cell_out->create_cell.cell_type = CELL_CREATE2;
|
|
|
- cell_out->create_cell.handshake_type = ONION_HANDSHAKE_TYPE_NTOR;
|
|
|
- cell_out->create_cell.handshake_len = NTOR_ONIONSKIN_LEN;
|
|
|
- memcpy(cell_out->create_cell.onionskin, payload + 22,
|
|
|
- NTOR_ONIONSKIN_LEN);
|
|
|
- } else {
|
|
|
- cell_out->create_cell.cell_type = CELL_CREATE;
|
|
|
- cell_out->create_cell.handshake_type = ONION_HANDSHAKE_TYPE_TAP;
|
|
|
- cell_out->create_cell.handshake_len = TAP_ONIONSKIN_CHALLENGE_LEN;
|
|
|
- memcpy(cell_out->create_cell.onionskin, payload + 6,
|
|
|
- TAP_ONIONSKIN_CHALLENGE_LEN);
|
|
|
}
|
|
|
- memcpy(cell_out->node_id, payload + 6 + TAP_ONIONSKIN_CHALLENGE_LEN,
|
|
|
- DIGEST_LEN);
|
|
|
- break;
|
|
|
+ int r = extend_cell_from_extend1_cell_body(cell_out, cell);
|
|
|
+ extend1_cell_body_free(cell);
|
|
|
+ if (r < 0)
|
|
|
+ return r;
|
|
|
}
|
|
|
+ break;
|
|
|
case RELAY_COMMAND_EXTEND2:
|
|
|
{
|
|
|
- uint8_t n_specs, spectype, speclen;
|
|
|
- int i;
|
|
|
- int found_ipv4 = 0, found_ipv6 = 0, found_id = 0;
|
|
|
- tor_addr_make_unspec(&cell_out->orport_ipv4.addr);
|
|
|
- tor_addr_make_unspec(&cell_out->orport_ipv6.addr);
|
|
|
-
|
|
|
- if (payload_length == 0)
|
|
|
+ extend2_cell_body_t *cell = NULL;
|
|
|
+ if (extend2_cell_body_parse(&cell, payload, payload_length) < 0 ||
|
|
|
+ cell == NULL) {
|
|
|
+ if (cell)
|
|
|
+ extend2_cell_body_free(cell);
|
|
|
return -1;
|
|
|
-
|
|
|
- cell_out->cell_type = RELAY_COMMAND_EXTEND2;
|
|
|
- n_specs = *payload++;
|
|
|
- /* Parse the specifiers. We'll only take the first IPv4 and first IPv6
|
|
|
- * address, and the node ID, and ignore everything else */
|
|
|
- for (i = 0; i < n_specs; ++i) {
|
|
|
- if (eop - payload < 2)
|
|
|
- return -1;
|
|
|
- spectype = payload[0];
|
|
|
- speclen = payload[1];
|
|
|
- payload += 2;
|
|
|
- if (eop - payload < speclen)
|
|
|
- return -1;
|
|
|
- switch (spectype) {
|
|
|
- case SPECTYPE_IPV4:
|
|
|
- if (speclen != 6)
|
|
|
- return -1;
|
|
|
- if (!found_ipv4) {
|
|
|
- tor_addr_from_ipv4n(&cell_out->orport_ipv4.addr,
|
|
|
- get_uint32(payload));
|
|
|
- cell_out->orport_ipv4.port = ntohs(get_uint16(payload+4));
|
|
|
- found_ipv4 = 1;
|
|
|
- }
|
|
|
- break;
|
|
|
- case SPECTYPE_IPV6:
|
|
|
- if (speclen != 18)
|
|
|
- return -1;
|
|
|
- if (!found_ipv6) {
|
|
|
- tor_addr_from_ipv6_bytes(&cell_out->orport_ipv6.addr,
|
|
|
- (const char*)payload);
|
|
|
- cell_out->orport_ipv6.port = ntohs(get_uint16(payload+16));
|
|
|
- found_ipv6 = 1;
|
|
|
- }
|
|
|
- break;
|
|
|
- case SPECTYPE_LEGACY_ID:
|
|
|
- if (speclen != 20)
|
|
|
- return -1;
|
|
|
- if (found_id)
|
|
|
- return -1;
|
|
|
- memcpy(cell_out->node_id, payload, 20);
|
|
|
- found_id = 1;
|
|
|
- break;
|
|
|
- }
|
|
|
- payload += speclen;
|
|
|
}
|
|
|
- if (!found_id || !found_ipv4)
|
|
|
- return -1;
|
|
|
- if (parse_create2_payload(&cell_out->create_cell,payload,eop-payload)<0)
|
|
|
- return -1;
|
|
|
- break;
|
|
|
+ int r = extend_cell_from_extend2_cell_body(cell_out, cell);
|
|
|
+ extend2_cell_body_free(cell);
|
|
|
+ if (r < 0)
|
|
|
+ return r;
|
|
|
}
|
|
|
+ break;
|
|
|
default:
|
|
|
return -1;
|
|
|
}
|
|
@@ -1137,12 +1178,11 @@ int
|
|
|
extend_cell_format(uint8_t *command_out, uint16_t *len_out,
|
|
|
uint8_t *payload_out, const extend_cell_t *cell_in)
|
|
|
{
|
|
|
- uint8_t *p, *eop;
|
|
|
+ uint8_t *p;
|
|
|
if (check_extend_cell(cell_in) < 0)
|
|
|
return -1;
|
|
|
|
|
|
p = payload_out;
|
|
|
- eop = payload_out + RELAY_PAYLOAD_SIZE;
|
|
|
|
|
|
memset(p, 0, RELAY_PAYLOAD_SIZE);
|
|
|
|
|
@@ -1165,33 +1205,56 @@ extend_cell_format(uint8_t *command_out, uint16_t *len_out,
|
|
|
break;
|
|
|
case RELAY_COMMAND_EXTEND2:
|
|
|
{
|
|
|
- uint8_t n = 2;
|
|
|
+ uint8_t n_specifiers = 2;
|
|
|
*command_out = RELAY_COMMAND_EXTEND2;
|
|
|
-
|
|
|
- *p++ = n; /* 2 identifiers */
|
|
|
- *p++ = SPECTYPE_IPV4; /* First is IPV4. */
|
|
|
- *p++ = 6; /* It's 6 bytes long. */
|
|
|
- set_uint32(p, tor_addr_to_ipv4n(&cell_in->orport_ipv4.addr));
|
|
|
- set_uint16(p+4, htons(cell_in->orport_ipv4.port));
|
|
|
- p += 6;
|
|
|
- *p++ = SPECTYPE_LEGACY_ID; /* Next is an identity digest. */
|
|
|
- *p++ = 20; /* It's 20 bytes long */
|
|
|
- memcpy(p, cell_in->node_id, DIGEST_LEN);
|
|
|
- p += 20;
|
|
|
-
|
|
|
- /* Now we can send the handshake */
|
|
|
- set_uint16(p, htons(cell_in->create_cell.handshake_type));
|
|
|
- set_uint16(p+2, htons(cell_in->create_cell.handshake_len));
|
|
|
- p += 4;
|
|
|
-
|
|
|
- if (cell_in->create_cell.handshake_len > eop - p)
|
|
|
- return -1;
|
|
|
-
|
|
|
- memcpy(p, cell_in->create_cell.onionskin,
|
|
|
+ extend2_cell_body_t *cell = extend2_cell_body_new();
|
|
|
+ link_specifier_t *ls;
|
|
|
+ {
|
|
|
+ /* IPv4 specifier first. */
|
|
|
+ ls = link_specifier_new();
|
|
|
+ extend2_cell_body_add_ls(cell, ls);
|
|
|
+ ls->ls_type = LS_IPV4;
|
|
|
+ ls->ls_len = 6;
|
|
|
+ ls->un_ipv4_addr = tor_addr_to_ipv4h(&cell_in->orport_ipv4.addr);
|
|
|
+ ls->un_ipv4_port = cell_in->orport_ipv4.port;
|
|
|
+ }
|
|
|
+ {
|
|
|
+ /* Then RSA id */
|
|
|
+ ls = link_specifier_new();
|
|
|
+ extend2_cell_body_add_ls(cell, ls);
|
|
|
+ ls->ls_type = LS_LEGACY_ID;
|
|
|
+ ls->ls_len = DIGEST_LEN;
|
|
|
+ memcpy(ls->un_legacy_id, cell_in->node_id, DIGEST_LEN);
|
|
|
+ }
|
|
|
+ if (should_include_ed25519_id_extend_cells(NULL, get_options()) &&
|
|
|
+ !ed25519_public_key_is_zero(&cell_in->ed_pubkey)) {
|
|
|
+ /* Then, maybe, the ed25519 id! */
|
|
|
+ ++n_specifiers;
|
|
|
+ ls = link_specifier_new();
|
|
|
+ extend2_cell_body_add_ls(cell, ls);
|
|
|
+ ls->ls_type = LS_ED25519_ID;
|
|
|
+ ls->ls_len = 32;
|
|
|
+ memcpy(ls->un_ed25519_id, cell_in->ed_pubkey.pubkey, 32);
|
|
|
+ }
|
|
|
+ cell->n_spec = n_specifiers;
|
|
|
+
|
|
|
+ /* Now, the handshake */
|
|
|
+ cell->create2 = create2_cell_body_new();
|
|
|
+ cell->create2->handshake_type = cell_in->create_cell.handshake_type;
|
|
|
+ cell->create2->handshake_len = cell_in->create_cell.handshake_len;
|
|
|
+ create2_cell_body_setlen_handshake_data(cell->create2,
|
|
|
+ cell_in->create_cell.handshake_len);
|
|
|
+ memcpy(create2_cell_body_getarray_handshake_data(cell->create2),
|
|
|
+ cell_in->create_cell.onionskin,
|
|
|
cell_in->create_cell.handshake_len);
|
|
|
|
|
|
- p += cell_in->create_cell.handshake_len;
|
|
|
- *len_out = p - payload_out;
|
|
|
+ ssize_t len_encoded = extend2_cell_body_encode(
|
|
|
+ payload_out, RELAY_PAYLOAD_SIZE,
|
|
|
+ cell);
|
|
|
+ extend2_cell_body_free(cell);
|
|
|
+ if (len_encoded < 0 || len_encoded > UINT16_MAX)
|
|
|
+ return -1;
|
|
|
+ *len_out = (uint16_t) len_encoded;
|
|
|
}
|
|
|
break;
|
|
|
default:
|