Actually send back correctly-formed IPv6 CONNECTED cells

We had some old code to send back connected cells for IPv6 addresses,
but it was wrong.  Fortunately, it was also unreachable.
This commit is contained in:
Nick Mathewson 2012-11-14 10:48:58 -05:00
parent 6b36142bcc
commit 882b389668
3 changed files with 94 additions and 29 deletions

View File

@ -392,6 +392,38 @@ connection_edge_finished_flushing(edge_connection_t *conn)
return 0;
}
/** DOCDOC */
#define MAX_CONNECTED_CELL_PAYLOAD_LEN 25
/** DOCDOC */
/* private */int
connected_cell_format_payload(uint8_t *payload_out,
const tor_addr_t *addr,
uint32_t ttl)
{
const sa_family_t family = tor_addr_family(addr);
int connected_payload_len;
if (family == AF_INET) {
set_uint32(payload_out, tor_addr_to_ipv4n(addr));
connected_payload_len = 4;
} else if (family == AF_INET6) {
set_uint32(payload_out, 0);
set_uint8(payload_out + 4, 6);
memcpy(payload_out + 5, tor_addr_to_in6_addr8(addr), 16);
connected_payload_len = 21;
} else {
return -1;
}
set_uint32(payload_out + connected_payload_len, htonl(dns_clip_ttl(ttl)));
connected_payload_len += 4;
tor_assert(connected_payload_len <= MAX_CONNECTED_CELL_PAYLOAD_LEN);
return connected_payload_len;
}
/** Connected handler for exit connections: start writing pending
* data, deliver 'CONNECTED' relay cells as appropriate, and check
* any pending data that may have been received. */
@ -423,22 +455,16 @@ connection_edge_finished_connecting(edge_connection_t *edge_conn)
RELAY_COMMAND_CONNECTED, NULL, 0) < 0)
return 0; /* circuit is closed, don't continue */
} else {
char connected_payload[20];
int connected_payload_len;
if (tor_addr_family(&conn->addr) == AF_INET) {
set_uint32(connected_payload, tor_addr_to_ipv4n(&conn->addr));
set_uint32(connected_payload+4,
htonl(dns_clip_ttl(edge_conn->address_ttl)));
connected_payload_len = 8;
} else {
memcpy(connected_payload, tor_addr_to_in6_addr8(&conn->addr), 16);
set_uint32(connected_payload+16,
htonl(dns_clip_ttl(edge_conn->address_ttl)));
connected_payload_len = 20;
}
uint8_t connected_payload[MAX_CONNECTED_CELL_PAYLOAD_LEN];
int connected_payload_len =
connected_cell_format_payload(connected_payload, &conn->addr,
edge_conn->address_ttl);
if (connected_payload_len < 0)
return -1;
if (connection_edge_send_command(edge_conn,
RELAY_COMMAND_CONNECTED,
connected_payload, connected_payload_len) < 0)
(char*)connected_payload, connected_payload_len) < 0)
return 0; /* circuit is closed, don't continue */
}
tor_assert(edge_conn->package_window > 0);
@ -2554,21 +2580,20 @@ connection_exit_connect(edge_connection_t *edge_conn)
RELAY_COMMAND_CONNECTED,
NULL, 0);
} else { /* normal stream */
char connected_payload[20];
int connected_payload_len;
if (tor_addr_family(&conn->addr) == AF_INET) {
set_uint32(connected_payload, tor_addr_to_ipv4n(&conn->addr));
connected_payload_len = 4;
} else {
memcpy(connected_payload, tor_addr_to_in6_addr8(&conn->addr), 16);
connected_payload_len = 16;
uint8_t connected_payload[MAX_CONNECTED_CELL_PAYLOAD_LEN];
int connected_payload_len =
connected_cell_format_payload(connected_payload, &conn->addr,
edge_conn->address_ttl);
if (connected_payload_len < 0) {
connection_edge_end(edge_conn, END_STREAM_REASON_INTERNAL);
circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn);
connection_free(conn);
}
set_uint32(connected_payload+connected_payload_len,
htonl(dns_clip_ttl(edge_conn->address_ttl)));
connected_payload_len += 4;
connection_edge_send_command(edge_conn,
RELAY_COMMAND_CONNECTED,
connected_payload, connected_payload_len);
(char*)connected_payload,
connected_payload_len);
}
}

View File

@ -109,7 +109,9 @@ typedef struct begin_cell_t {
int begin_cell_parse(const cell_t *cell, begin_cell_t *bcell,
uint8_t *end_reason_out);
int connected_cell_format_payload(uint8_t *payload_out,
const tor_addr_t *addr,
uint32_t ttl);
#endif
#endif

View File

@ -231,6 +231,7 @@ test_cfmt_connected_cells(void *arg)
cell_t cell;
tor_addr_t addr;
int ttl, r;
char *mem_op_hex_tmp = NULL;
(void)arg;
/* Let's try an oldschool one with nothing in it. */
@ -332,8 +333,45 @@ test_cfmt_connected_cells(void *arg)
r = connected_cell_parse(&rh, &cell, &addr, &ttl);
tt_int_op(r, ==, -1);
/* Now make sure we can generate connected cells correctly. */
/* Try an IPv4 address */
memset(&rh, 0, sizeof(rh));
memset(&cell, 0, sizeof(cell));
tor_addr_parse(&addr, "30.40.50.60");
rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE,
&addr, 128);
tt_int_op(rh.length, ==, 8);
test_memeq_hex(cell.payload+RELAY_HEADER_SIZE, "1e28323c" "00000080");
/* Try parsing it. */
tor_addr_make_unspec(&addr);
r = connected_cell_parse(&rh, &cell, &addr, &ttl);
tt_int_op(r, ==, 0);
tt_int_op(tor_addr_family(&addr), ==, AF_INET);
tt_str_op(fmt_addr(&addr), ==, "30.40.50.60");
tt_int_op(ttl, ==, 128);
/* Try an IPv6 address */
memset(&rh, 0, sizeof(rh));
memset(&cell, 0, sizeof(cell));
tor_addr_parse(&addr, "2620::6b0:b:1a1a:0:26e5:480e");
rh.length = connected_cell_format_payload(cell.payload+RELAY_HEADER_SIZE,
&addr, 3600);
tt_int_op(rh.length, ==, 25);
test_memeq_hex(cell.payload + RELAY_HEADER_SIZE,
"00000000" "06"
"2620000006b0000b1a1a000026e5480e" "00000e10");
/* Try parsing it. */
tor_addr_make_unspec(&addr);
r = connected_cell_parse(&rh, &cell, &addr, &ttl);
tt_int_op(r, ==, 0);
tt_int_op(tor_addr_family(&addr), ==, AF_INET6);
tt_str_op(fmt_addr(&addr), ==, "2620:0:6b0:b:1a1a:0:26e5:480e");
tt_int_op(ttl, ==, 3600);
done:
;
tor_free(mem_op_hex_tmp);
}
#define TEST(name, flags) \