diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 9a4f274bb1..d97bea7e66 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -2408,6 +2408,9 @@ connection_exit_connect(edge_connection_t *edge_conn) addr = &conn->addr; port = conn->port; + if (tor_addr_family(addr) == AF_INET6) + conn->socket_family = AF_INET6; + log_debug(LD_EXIT,"about to try connecting"); switch (connection_connect(conn, conn->address, addr, port, &socket_error)) { case -1: { diff --git a/src/or/dns.c b/src/or/dns.c index 5e1d0b48db..d26314a429 100644 --- a/src/or/dns.c +++ b/src/or/dns.c @@ -160,7 +160,8 @@ typedef struct cached_resolve_t { static void purge_expired_resolves(time_t now); static void dns_found_answer(const char *address, uint8_t is_reverse, - uint32_t addr, const char *hostname, char outcome, + uint32_t addr, + const char *hostname, char outcome, uint32_t ttl); static void send_resolved_cell(edge_connection_t *conn, uint8_t answer_type); static int launch_resolve(edge_connection_t *exitconn); @@ -490,9 +491,13 @@ purge_expired_resolves(time_t now) assert_cache_ok(); } +/* argument for send_resolved_cell only, meaning "let the answer type be ipv4 + * or ipv6 depending on the connection's address". */ +#define RESOLVED_TYPE_AUTO 0xff + /** Send a response to the RESOLVE request of a connection. * answer_type must be one of - * RESOLVED_TYPE_(IPV4|ERROR|ERROR_TRANSIENT). + * RESOLVED_TYPE_(IPV4|IPV6|ERROR|ERROR_TRANSIENT|AUTO). * * If circ is provided, and we have a cached answer, send the * answer back along circ; otherwise, send the answer back along @@ -505,6 +510,16 @@ send_resolved_cell(edge_connection_t *conn, uint8_t answer_type) size_t buflen; uint32_t ttl; + if (answer_type == RESOLVED_TYPE_AUTO) { + sa_family_t family = tor_addr_family(&conn->base_.addr); + if (family == AF_INET) + answer_type = RESOLVED_TYPE_IPV4; + else if (family == AF_INET6) + answer_type = RESOLVED_TYPE_IPV6; + else + answer_type = RESOLVED_TYPE_ERROR_TRANSIENT; + } + buf[0] = answer_type; ttl = dns_clip_ttl(conn->address_ttl); @@ -516,7 +531,15 @@ send_resolved_cell(edge_connection_t *conn, uint8_t answer_type) set_uint32(buf+6, htonl(ttl)); buflen = 10; break; - /*XXXX IP6 need ipv6 implementation */ + case RESOLVED_TYPE_IPV6: + { + const uint8_t *bytes = tor_addr_to_in6_addr8(&conn->base_.addr); + buf[1] = 16; + memcpy(buf+2, bytes, 16); + set_uint32(buf+18, htonl(ttl)); + buflen = 22; + } + break; case RESOLVED_TYPE_ERROR_TRANSIENT: case RESOLVED_TYPE_ERROR: { @@ -614,7 +637,7 @@ dns_resolve(edge_connection_t *exitconn) if (hostname) send_resolved_hostname_cell(exitconn, hostname); else - send_resolved_cell(exitconn, RESOLVED_TYPE_IPV4); + send_resolved_cell(exitconn, RESOLVED_TYPE_AUTO); exitconn->on_circuit = NULL; } else { /* Add to the n_streams list; the calling function will send back a @@ -693,12 +716,13 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve, /* first check if exitconn->base_.address is an IP. If so, we already * know the answer. */ if (tor_addr_parse(&addr, exitconn->base_.address) >= 0) { - if (tor_addr_family(&addr) == AF_INET) { + if (tor_addr_family(&addr) == AF_INET || + tor_addr_family(&addr) == AF_INET6) { tor_addr_copy(&exitconn->base_.addr, &addr); exitconn->address_ttl = DEFAULT_DNS_TTL; return 1; } else { - /* XXXX IPv6 */ + /* XXXX unspec? Bogus? */ return -1; } } @@ -1140,7 +1164,7 @@ dns_found_answer(const char *address, uint8_t is_reverse, uint32_t addr, if (is_reverse) send_resolved_hostname_cell(pendconn, hostname); else - send_resolved_cell(pendconn, RESOLVED_TYPE_IPV4); + send_resolved_cell(pendconn, RESOLVED_TYPE_AUTO); circ = circuit_get_by_edge_conn(pendconn); tor_assert(circ); circuit_detach_stream(circ, pendconn); diff --git a/src/or/router.c b/src/or/router.c index cdd33bb6f6..642656fc05 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -1380,8 +1380,8 @@ router_compare_to_my_exit_policy(edge_connection_t *conn) if (tor_addr_is_null(&conn->base_.addr)) return -1; - /* XXXX IPv6 */ - if (tor_addr_family(&conn->base_.addr) != AF_INET) + if (tor_addr_family(&conn->base_.addr) != AF_INET && + tor_addr_family(&conn->base_.addr) != AF_INET6) return -1; return compare_tor_addr_to_addr_policy(&conn->base_.addr, conn->base_.port,