[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [tor/master] Make DNS resolve requests work for IPv6
commit 0f899518cf13ad2b6d99845ac82e7cbf93ef0fb4
Author: Nick Mathewson <nickm@xxxxxxxxxxxxxx>
Date: Wed Nov 14 22:06:13 2012 -0500
Make DNS resolve requests work for IPv6
* If there's an IPv4 and an IPv6 address, return both in the resolved
cell.
* Treat all resolve requests as permitting IPv6, since by the spec they're
allowed to, and by the code that won't break anything.
---
src/or/dns.c | 105 ++++++++++++++++++++++++++++++++++-----------------------
1 files changed, 63 insertions(+), 42 deletions(-)
diff --git a/src/or/dns.c b/src/or/dns.c
index 976d188..9834bd7 100644
--- a/src/or/dns.c
+++ b/src/or/dns.c
@@ -148,7 +148,8 @@ typedef struct cached_resolve_t {
char address[MAX_ADDRESSLEN]; /**< The hostname to be resolved. */
union {
- uint32_t addr_ipv4; /**< IPv4 addr for <b>address</b>, if successful */
+ uint32_t addr_ipv4; /**< IPv4 addr for <b>address</b>, if successful.
+ * (In host order.) */
int err_ipv4; /**< One of DNS_ERR_*, if IPv4 lookup failed. */
} result_ipv4; /**< Outcome of IPv4 lookup */
union {
@@ -188,14 +189,16 @@ static void dns_found_answer(const char *address, uint8_t query_type,
const tor_addr_t *addr,
const char *hostname,
uint32_t ttl);
-static void send_resolved_cell(edge_connection_t *conn, uint8_t answer_type);
+static void send_resolved_cell(edge_connection_t *conn, uint8_t answer_type,
+ const cached_resolve_t *resolve);
static int launch_resolve(cached_resolve_t *resolve);
static void add_wildcarded_test_address(const char *address);
static int configure_nameservers(int force);
static int answer_is_wildcarded(const char *ip);
static int dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
or_circuit_t *oncirc, char **resolved_to_hostname,
- int *made_connection_pending_out);
+ int *made_connection_pending_out,
+ cached_resolve_t **resolve_out);
static int set_exitconn_info_from_resolve(edge_connection_t *exitconn,
const cached_resolve_t *resolve,
char **hostname_out);
@@ -593,55 +596,55 @@ purge_expired_resolves(time_t now)
/** Send a response to the RESOLVE request of a connection.
* <b>answer_type</b> must be one of
- * RESOLVED_TYPE_(IPV4|IPV6|ERROR|ERROR_TRANSIENT|AUTO).
+ * RESOLVED_TYPE_(AUTO|ERROR|ERROR_TRANSIENT|).
*
* If <b>circ</b> is provided, and we have a cached answer, send the
* answer back along circ; otherwise, send the answer back along
* <b>conn</b>'s attached circuit.
*/
static void
-send_resolved_cell(edge_connection_t *conn, uint8_t answer_type)
+send_resolved_cell(edge_connection_t *conn, uint8_t answer_type,
+ const cached_resolve_t *resolved)
{
- char buf[RELAY_PAYLOAD_SIZE];
- size_t buflen;
+ char buf[RELAY_PAYLOAD_SIZE], *cp = buf;
+ size_t buflen = 0;
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);
switch (answer_type)
{
- case RESOLVED_TYPE_IPV4:
- buf[1] = 4;
- set_uint32(buf+2, tor_addr_to_ipv4n(&conn->base_.addr));
- set_uint32(buf+6, htonl(ttl));
- buflen = 10;
- break;
- 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;
+ case RESOLVED_TYPE_AUTO:
+ if (resolved && resolved->res_status_ipv4 == RES_STATUS_DONE_OK) {
+ cp[0] = RESOLVED_TYPE_IPV4;
+ cp[1] = 4;
+ set_uint32(cp+2, htonl(resolved->result_ipv4.addr_ipv4));
+ set_uint32(cp+6, htonl(ttl));
+ cp += 10;
+ }
+ if (resolved && resolved->res_status_ipv6 == RES_STATUS_DONE_OK) {
+ const uint8_t *bytes = resolved->result_ipv6.addr_ipv6.s6_addr;
+ cp[0] = RESOLVED_TYPE_IPV6;
+ cp[1] = 16;
+ memcpy(cp+2, bytes, 16);
+ set_uint32(cp+18, htonl(ttl));
+ cp += 22;
+ }
+ if (cp != buf) {
+ buflen = cp - buf;
+ break;
+ } else {
+ answer_type = RESOLVED_TYPE_ERROR;
+ /* fall through. */
}
- break;
case RESOLVED_TYPE_ERROR_TRANSIENT:
case RESOLVED_TYPE_ERROR:
{
const char *errmsg = "Error resolving hostname";
size_t msglen = strlen(errmsg);
+ buf[0] = answer_type;
buf[1] = msglen;
strlcpy(buf+2, errmsg, sizeof(buf)-2);
set_uint32(buf+2+msglen, htonl(ttl));
@@ -719,10 +722,11 @@ dns_resolve(edge_connection_t *exitconn)
int is_resolve, r;
int made_connection_pending = 0;
char *hostname = NULL;
+ cached_resolve_t *resolve = NULL;
is_resolve = exitconn->base_.purpose == EXIT_PURPOSE_RESOLVE;
r = dns_resolve_impl(exitconn, is_resolve, oncirc, &hostname,
- &made_connection_pending);
+ &made_connection_pending, &resolve);
switch (r) {
case 1:
@@ -733,7 +737,7 @@ dns_resolve(edge_connection_t *exitconn)
if (hostname)
send_resolved_hostname_cell(exitconn, hostname);
else
- send_resolved_cell(exitconn, RESOLVED_TYPE_AUTO);
+ send_resolved_cell(exitconn, RESOLVED_TYPE_AUTO, resolve);
exitconn->on_circuit = NULL;
} else {
/* Add to the n_streams list; the calling function will send back a
@@ -755,7 +759,8 @@ dns_resolve(edge_connection_t *exitconn)
* and stop everybody waiting for the same connection. */
if (is_resolve) {
send_resolved_cell(exitconn,
- (r == -1) ? RESOLVED_TYPE_ERROR : RESOLVED_TYPE_ERROR_TRANSIENT);
+ (r == -1) ? RESOLVED_TYPE_ERROR : RESOLVED_TYPE_ERROR_TRANSIENT,
+ NULL);
}
exitconn->on_circuit = NULL;
@@ -789,11 +794,14 @@ dns_resolve(edge_connection_t *exitconn)
* Set *<b>made_connection_pending_out</b> to true if we have placed
* <b>exitconn</b> on the list of pending connections for some resolve; set it
* to false otherwise.
+ *
+ * Set *<b>resolve_out</b> to a cached resolve, if we found one.
*/
static int
dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
or_circuit_t *oncirc, char **hostname_out,
- int *made_connection_pending_out)
+ int *made_connection_pending_out,
+ cached_resolve_t **resolve_out)
{
cached_resolve_t *resolve;
cached_resolve_t search;
@@ -891,6 +899,8 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
exitconn->base_.s,
escaped_safe_str(resolve->address));
+ *resolve_out = resolve;
+
return set_exitconn_info_from_resolve(exitconn, resolve, hostname_out);
case CACHE_STATE_DONE:
@@ -940,6 +950,8 @@ set_exitconn_info_from_resolve(edge_connection_t *exitconn,
char **hostname_out)
{
int ipv4_ok, ipv6_ok, answer_with_ipv4, r;
+ uint32_t begincell_flags;
+ const int is_resolve = exitconn->base_.purpose == EXIT_PURPOSE_RESOLVE;
tor_assert(exitconn);
tor_assert(resolve);
@@ -955,14 +967,22 @@ set_exitconn_info_from_resolve(edge_connection_t *exitconn,
/* If we're here then the connection wants one or either of ipv4, ipv6, and
* we can give it one or both. */
+ if (is_resolve) {
+ begincell_flags = BEGIN_FLAG_IPV6_OK;
+ } else {
+ begincell_flags = exitconn->begincell_flags;
+ }
+
ipv4_ok = (resolve->res_status_ipv4 == RES_STATUS_DONE_OK) &&
- ! (exitconn->begincell_flags & BEGIN_FLAG_IPV4_NOT_OK);
+ ! (begincell_flags & BEGIN_FLAG_IPV4_NOT_OK);
ipv6_ok = (resolve->res_status_ipv6 == RES_STATUS_DONE_OK) &&
- (exitconn->begincell_flags & BEGIN_FLAG_IPV6_OK) &&
+ (begincell_flags & BEGIN_FLAG_IPV6_OK) &&
get_options()->IPv6Exit;
/* Now decide which one to actually give. */
- if (ipv4_ok && ipv6_ok) {
+ if (ipv4_ok && ipv6_ok && is_resolve) {
+ answer_with_ipv4 = 1;
+ } else if (ipv4_ok && ipv6_ok) {
/* If we have both, see if our exit policy has an opinion. */
const uint16_t port = exitconn->base_.port;
int ipv4_allowed, ipv6_allowed;
@@ -978,7 +998,7 @@ set_exitconn_info_from_resolve(edge_connection_t *exitconn,
} else {
/* Our exit policy would permit both. Answer with whichever the user
* prefers */
- answer_with_ipv4 = !(exitconn->begincell_flags &
+ answer_with_ipv4 = !(begincell_flags &
BEGIN_FLAG_IPV6_PREFERRED);
}
} else {
@@ -989,7 +1009,7 @@ set_exitconn_info_from_resolve(edge_connection_t *exitconn,
answer_with_ipv4 = 0;
} else {
/* Neither one was okay. Choose based on user preference. */
- answer_with_ipv4 = !(exitconn->begincell_flags &
+ answer_with_ipv4 = !(begincell_flags &
BEGIN_FLAG_IPV6_PREFERRED);
}
}
@@ -1292,7 +1312,8 @@ inform_pending_connections(cached_resolve_t *resolve)
circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
} else {
send_resolved_cell(pendconn, r == -1 ?
- RESOLVED_TYPE_ERROR : RESOLVED_TYPE_ERROR_TRANSIENT);
+ RESOLVED_TYPE_ERROR : RESOLVED_TYPE_ERROR_TRANSIENT,
+ NULL);
/* This detach must happen after we send the resolved cell. */
circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
}
@@ -1321,7 +1342,7 @@ inform_pending_connections(cached_resolve_t *resolve)
if (pendconn->is_reverse_dns_lookup)
send_resolved_hostname_cell(pendconn, hostname);
else
- send_resolved_cell(pendconn, RESOLVED_TYPE_AUTO);
+ send_resolved_cell(pendconn, RESOLVED_TYPE_AUTO, resolve);
circ = circuit_get_by_edge_conn(pendconn);
tor_assert(circ);
circuit_detach_stream(circ, pendconn);
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits