aboutsummaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2012-10-31 18:27:48 -0400
committerNick Mathewson <nickm@torproject.org>2012-11-14 23:16:23 -0500
commitcac5335195d3bb9a39af77886992ffa98b8c7817 (patch)
tree8aebb8c010f7a3d926ceadf92be0d9e433d2a250 /src/or
parent93dc7dcf418f37023b5a1e3f4e8485d8286996b4 (diff)
downloadtor-cac5335195d3bb9a39af77886992ffa98b8c7817.tar
tor-cac5335195d3bb9a39af77886992ffa98b8c7817.tar.gz
Get the client side of receiving an IPv6 address to work
This makes it so we can handle getting an IPv6 in the 3 different formats we specified it for in RESOLVED cells, END_STREAM_REASON_EXITPOLICY cells, and CONNECTED cells. We don't cache IPv6 addresses yet, since proposal 205 isn't implemented. There's a refactored function for parsing connected cells; it has unit tests.
Diffstat (limited to 'src/or')
-rw-r--r--src/or/addressmap.c35
-rw-r--r--src/or/addressmap.h2
-rw-r--r--src/or/connection_edge.c15
-rw-r--r--src/or/connection_edge.h1
-rw-r--r--src/or/relay.c134
-rw-r--r--src/or/relay.h2
6 files changed, 140 insertions, 49 deletions
diff --git a/src/or/addressmap.c b/src/or/addressmap.c
index 4aa46fc6e..45e29c185 100644
--- a/src/or/addressmap.c
+++ b/src/or/addressmap.c
@@ -576,10 +576,7 @@ client_dns_set_addressmap_impl(origin_circuit_t *on_circ,
const char *exitname,
int ttl)
{
- /* <address>.<hex or nickname>.exit\0 or just <address>\0 */
- char extendedaddress[MAX_SOCKS_ADDR_LEN+MAX_VERBOSE_NICKNAME_LEN+10];
- /* 123.123.123.123.<hex or nickname>.exit\0 or just 123.123.123.123\0 */
- char extendedval[INET_NTOA_BUF_LEN+MAX_VERBOSE_NICKNAME_LEN+10];
+ char *extendedaddress=NULL, *extendedval=NULL;
(void)on_circ;
tor_assert(address);
@@ -594,18 +591,19 @@ client_dns_set_addressmap_impl(origin_circuit_t *on_circ,
/* XXXX fails to ever get attempts to get an exit address of
* google.com.digest[=~]nickname.exit; we need a syntax for this that
* won't make strict RFC952-compliant applications (like us) barf. */
- tor_snprintf(extendedaddress, sizeof(extendedaddress),
+ tor_asprintf(&extendedaddress,
"%s.%s.exit", address, exitname);
- tor_snprintf(extendedval, sizeof(extendedval),
+ tor_asprintf(&extendedval,
"%s.%s.exit", name, exitname);
} else {
- tor_snprintf(extendedaddress, sizeof(extendedaddress),
+ tor_asprintf(&extendedaddress,
"%s", address);
- tor_snprintf(extendedval, sizeof(extendedval),
+ tor_asprintf(&extendedval,
"%s", name);
}
- addressmap_register(extendedaddress, tor_strdup(extendedval),
+ addressmap_register(extendedaddress, extendedval,
time(NULL) + ttl, ADDRMAPSRC_DNS, 0, 0);
+ tor_free(extendedaddress);
}
/** Record the fact that <b>address</b> resolved to <b>val</b>.
@@ -620,19 +618,26 @@ client_dns_set_addressmap_impl(origin_circuit_t *on_circ,
*/
void
client_dns_set_addressmap(origin_circuit_t *on_circ,
- const char *address, uint32_t val,
+ const char *address,
+ const tor_addr_t *val,
const char *exitname,
int ttl)
{
- struct in_addr in;
- char valbuf[INET_NTOA_BUF_LEN];
+ tor_addr_t addr_tmp;
+ char valbuf[TOR_ADDR_BUF_LEN];
tor_assert(address);
+ tor_assert(val);
- if (tor_inet_aton(address, &in))
+ if (tor_addr_parse(&addr_tmp, address) == 0)
return; /* If address was an IP address already, don't add a mapping. */
- in.s_addr = htonl(val);
- tor_inet_ntoa(&in,valbuf,sizeof(valbuf));
+
+ /* XXXXX For now, don't cache IPv6 addresses. */
+ if (tor_addr_family(val) != AF_INET)
+ return;
+
+ if (! tor_addr_to_str(valbuf, val, sizeof(valbuf), 0)) /* XXXX decorate? */
+ return;
client_dns_set_addressmap_impl(on_circ, address, valbuf, exitname, ttl);
}
diff --git a/src/or/addressmap.h b/src/or/addressmap.h
index dd8fc9bcf..9b0734147 100644
--- a/src/or/addressmap.h
+++ b/src/or/addressmap.h
@@ -29,7 +29,7 @@ int parse_virtual_addr_network(const char *val, int validate_only,
int client_dns_incr_failures(const char *address);
void client_dns_clear_failures(const char *address);
void client_dns_set_addressmap(origin_circuit_t *on_circ,
- const char *address, uint32_t val,
+ const char *address, const tor_addr_t *val,
const char *exitname, int ttl);
const char *addressmap_register_virtual_address(int type, char *new_address);
void addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index dc7d863f4..969128fcf 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -1949,10 +1949,19 @@ connection_ap_handshake_socks_resolved(entry_connection_t *conn,
if (CIRCUIT_IS_ORIGIN(circ)) /* should always be true */
origin_circ = TO_ORIGIN_CIRCUIT(circ);
if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) {
- uint32_t a = ntohl(get_uint32(answer));
- if (a) {
+ tor_addr_t a;
+ tor_addr_from_ipv4n(&a, get_uint32(answer));
+ if (! tor_addr_is_null(&a)) {
client_dns_set_addressmap(origin_circ,
- conn->socks_request->address, a,
+ conn->socks_request->address, &a,
+ conn->chosen_exit_name, ttl);
+ }
+ } else if (answer_type == RESOLVED_TYPE_IPV6 && answer_len == 16) {
+ tor_addr_t a;
+ tor_addr_from_ipv6_bytes(&a, (char*)answer);
+ if (! tor_addr_is_null(&a)) {
+ client_dns_set_addressmap(origin_circ,
+ conn->socks_request->address, &a,
conn->chosen_exit_name, ttl);
}
} else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) {
diff --git a/src/or/connection_edge.h b/src/or/connection_edge.h
index 39f492de9..9c4318ccf 100644
--- a/src/or/connection_edge.h
+++ b/src/or/connection_edge.h
@@ -108,6 +108,7 @@ typedef struct begin_cell_t {
int begin_cell_parse(const cell_t *cell, begin_cell_t *bcell,
uint8_t *end_reason_out);
+
#endif
diff --git a/src/or/relay.c b/src/or/relay.c
index 76e9d2550..a05e955ec 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -705,21 +705,37 @@ connection_ap_process_end_not_open(
switch (reason) {
case END_STREAM_REASON_EXITPOLICY:
if (rh->length >= 5) {
- uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+1));
- int ttl;
- if (!addr) {
+ tor_addr_t addr;
+ int ttl = -1;
+ tor_addr_make_unspec(&addr);
+ if (rh->length == 5 || rh->length == 9) {
+ tor_addr_from_ipv4n(&addr,
+ get_uint32(cell->payload+RELAY_HEADER_SIZE+1));
+ if (rh->length == 9)
+ ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+5));
+ } else if (rh->length == 17 || rh->length == 21) {
+ tor_addr_from_ipv6_bytes(&addr,
+ (char*)(cell->payload+RELAY_HEADER_SIZE+1));
+ if (rh->length == 21)
+ ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+17));
+ }
+ if (tor_addr_is_null(&addr)) {
log_info(LD_APP,"Address '%s' resolved to 0.0.0.0. Closing,",
safe_str(conn->socks_request->address));
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
return 0;
}
- if (rh->length >= 9)
- ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+5));
- else
- ttl = -1;
+ if ((tor_addr_family(&addr) == AF_INET && !conn->ipv4_traffic_ok) ||
+ (tor_addr_family(&addr) == AF_INET6 && !conn->ipv6_traffic_ok)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_APP,
+ "Got an EXITPOLICY failure on a connection with a "
+ "mismatched family. Closing.");
+ connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
+ return 0;
+ }
if (get_options()->ClientDNSRejectInternalAddresses &&
- is_internal_IP(addr, 0)) {
+ tor_addr_is_internal(&addr, 0)) {
log_info(LD_APP,"Address '%s' resolved to internal. Closing,",
safe_str(conn->socks_request->address));
connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
@@ -727,7 +743,7 @@ connection_ap_process_end_not_open(
}
client_dns_set_addressmap(circ,
- conn->socks_request->address, addr,
+ conn->socks_request->address, &addr,
conn->chosen_exit_name, ttl);
}
/* check if he *ought* to have allowed it */
@@ -830,20 +846,56 @@ connection_ap_process_end_not_open(
}
/** Helper: change the socks_request-&gt;address field on conn to the
- * dotted-quad representation of <b>new_addr</b> (given in host order),
+ * dotted-quad representation of <b>new_addr</b>,
* and send an appropriate REMAP event. */
static void
-remap_event_helper(entry_connection_t *conn, uint32_t new_addr)
+remap_event_helper(entry_connection_t *conn, const tor_addr_t *new_addr)
{
- struct in_addr in;
-
- in.s_addr = htonl(new_addr);
- tor_inet_ntoa(&in, conn->socks_request->address,
- sizeof(conn->socks_request->address));
+ tor_addr_to_str(conn->socks_request->address, new_addr,
+ sizeof(conn->socks_request->address),
+ 0); /* XXXXX Should decorate be 1? */
control_event_stream_status(conn, STREAM_EVENT_REMAP,
REMAP_STREAM_SOURCE_EXIT);
}
+/**DOCDOC*/
+int
+connected_cell_parse(const relay_header_t *rh, const cell_t *cell,
+ tor_addr_t *addr_out, int *ttl_out)
+{
+ uint32_t bytes;
+ const uint8_t *payload = cell->payload + RELAY_HEADER_SIZE;
+
+ tor_addr_make_unspec(addr_out);
+ *ttl_out = -1;
+ if (rh->length == 0)
+ return 0;
+ if (rh->length < 4)
+ return -1;
+ bytes = ntohl(get_uint32(payload));
+
+ /* If bytes is 0, this is maybe a v6 address. Otherwise it's a v4 address */
+ if (bytes != 0) {
+ /* v4 address */
+ tor_addr_from_ipv4h(addr_out, bytes);
+ if (rh->length >= 8) {
+ bytes = ntohl(get_uint32(payload + 4));
+ if (bytes <= INT32_MAX)
+ *ttl_out = bytes;
+ }
+ } else {
+ if (rh->length < 25) /* 4 bytes of 0s, 1 addr, 16 ipv4, 4 ttl. */
+ return -1;
+ if (get_uint8(payload + 4) != 6)
+ return -1;
+ tor_addr_from_ipv6_bytes(addr_out, (char*)(payload + 5));
+ bytes = ntohl(get_uint32(payload + 21));
+ if (bytes <= INT32_MAX)
+ *ttl_out = (int) bytes;
+ }
+ return 0;
+}
+
/** An incoming relay cell has arrived from circuit <b>circ</b> to
* stream <b>conn</b>.
*
@@ -874,6 +926,8 @@ connection_edge_process_relay_cell_not_open(
if (conn->base_.type == CONN_TYPE_AP &&
rh->command == RELAY_COMMAND_CONNECTED) {
+ tor_addr_t addr;
+ int ttl;
entry_connection_t *entry_conn = EDGE_TO_ENTRY_CONN(conn);
tor_assert(CIRCUIT_IS_ORIGIN(circ));
if (conn->base_.state != AP_CONN_STATE_CONNECT_WAIT) {
@@ -884,27 +938,41 @@ connection_edge_process_relay_cell_not_open(
conn->base_.state = AP_CONN_STATE_OPEN;
log_info(LD_APP,"'connected' received after %d seconds.",
(int)(time(NULL) - conn->base_.timestamp_lastread));
- if (rh->length >= 4) {
- uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE));
- int ttl;
- if (!addr || (get_options()->ClientDNSRejectInternalAddresses &&
- is_internal_IP(addr, 0))) {
+ if (connected_cell_parse(rh, cell, &addr, &ttl) < 0) {
+ log_fn(LOG_PROTOCOL_WARN, LD_APP,
+ "Got a badly formatted connected cell. Closing.");
+ connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL);
+ connection_mark_unattached_ap(entry_conn, END_STREAM_REASON_TORPROTOCOL);
+ }
+ if (tor_addr_family(&addr) != AF_UNSPEC) {
+ const sa_family_t family = tor_addr_family(&addr);
+ if (tor_addr_is_null(&addr) ||
+ (get_options()->ClientDNSRejectInternalAddresses &&
+ tor_addr_is_internal(&addr, 0))) {
log_info(LD_APP, "...but it claims the IP address was %s. Closing.",
- fmt_addr32(addr));
+ fmt_addr(&addr));
+ connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL);
+ connection_mark_unattached_ap(entry_conn,
+ END_STREAM_REASON_TORPROTOCOL);
+ return 0;
+ }
+
+ if ((family == AF_INET && ! entry_conn->ipv4_traffic_ok) ||
+ (family == AF_INET6 && ! entry_conn->ipv6_traffic_ok)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_APP,
+ "Got a connected cell to %s with unsupported address family."
+ " Closing.", fmt_addr(&addr));
connection_edge_end(conn, END_STREAM_REASON_TORPROTOCOL);
connection_mark_unattached_ap(entry_conn,
END_STREAM_REASON_TORPROTOCOL);
return 0;
}
- if (rh->length >= 8)
- ttl = (int)ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+4));
- else
- ttl = -1;
+
client_dns_set_addressmap(TO_ORIGIN_CIRCUIT(circ),
- entry_conn->socks_request->address, addr,
+ entry_conn->socks_request->address, &addr,
entry_conn->chosen_exit_name, ttl);
- remap_event_helper(entry_conn, addr);
+ remap_event_helper(entry_conn, &addr);
}
circuit_log_path(LOG_INFO,LD_APP,TO_ORIGIN_CIRCUIT(circ));
/* don't send a socks reply to transparent conns */
@@ -994,8 +1062,14 @@ connection_edge_process_relay_cell_not_open(
ttl,
-1);
if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) {
- uint32_t addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+2));
- remap_event_helper(entry_conn, addr);
+ tor_addr_t addr;
+ tor_addr_from_ipv4n(&addr, get_uint32(cell->payload+RELAY_HEADER_SIZE+2));
+ remap_event_helper(entry_conn, &addr);
+ } else if (answer_type == RESOLVED_TYPE_IPV6 && answer_len == 16) {
+ tor_addr_t addr;
+ tor_addr_from_ipv6_bytes(&addr,
+ (char*)(cell->payload+RELAY_HEADER_SIZE+2));
+ remap_event_helper(entry_conn, &addr);
}
connection_mark_unattached_ap(entry_conn,
END_STREAM_REASON_DONE |
diff --git a/src/or/relay.h b/src/or/relay.h
index 0f7b45fef..57400fdbd 100644
--- a/src/or/relay.h
+++ b/src/or/relay.h
@@ -68,6 +68,8 @@ void circuit_clear_cell_queue(circuit_t *circ, channel_t *chan);
#ifdef RELAY_PRIVATE
int relay_crypt(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction,
crypt_path_t **layer_hint, char *recognized);
+int connected_cell_parse(const relay_header_t *rh, const cell_t *cell,
+ tor_addr_t *addr_out, int *ttl_out);
#endif
#endif