From b7843ca5544e741e74fe5f93fb49579e01b468c8 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Sat, 27 Oct 2012 16:34:49 -0400 Subject: [PATCH] Make DNS callback pass IPv6 answers to dns_answer_found Also, count ipv6 timeouts vs others. If we have too many ipv6 requests time out, then we could be degrading performance because of a broken DNS server that ignores AAAA requests. Other cases in which we never learn an AAAA address aren't so bad, since they don't slow A (ipv4) answers down very much. --- src/or/dns.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++----- src/or/dns.h | 1 + 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/src/or/dns.c b/src/or/dns.c index c590e01da3..3832421007 100644 --- a/src/or/dns.c +++ b/src/or/dns.c @@ -1342,6 +1342,10 @@ configure_nameservers(int force) return -1; } +static uint64_t n_ipv6_requests_made = 0; +static uint64_t n_ipv6_timeouts = 0; +static int dns_is_broken_for_ipv6 = 0; + /** For eventdns: Called when we get an answer for a request we launched. * See eventdns.h for arguments; 'arg' holds the address we tried to resolve. */ @@ -1352,20 +1356,39 @@ evdns_callback(int result, char type, int count, int ttl, void *addresses, char *string_address = arg; uint8_t is_reverse = 0; int status = DNS_RESOLVE_FAILED_PERMANENT; - uint32_t addr = 0; + tor_addr_t addr; const char *hostname = NULL; int was_wildcarded = 0; + tor_addr_make_unspec(&addr); /*WRONG WRONG WRONG XXXX XXXXX IPV6 prop208*/ + + /* Keep track of whether IPv6 is working */ + if (type == DNS_IPv6_AAAA) { + if (result == DNS_ERR_TIMEOUT) { + ++n_ipv6_timeouts; + } + + if (n_ipv6_timeouts > 10 && + n_ipv6_timeouts > n_ipv6_requests_made / 2) { + if (! dns_is_broken_for_ipv6) { + log_notice(LD_EXIT, "More than half of our IPv6 requests seem to " + "have timed out. I'm going to assume I can't get AAAA " + "responses."); + dns_is_broken_for_ipv6 = 1; + } + } + } + if (result == DNS_ERR_NONE) { if (type == DNS_IPv4_A && count) { char answer_buf[INET_NTOA_BUF_LEN+1]; struct in_addr in; char *escaped_address; uint32_t *addrs = addresses; - in.s_addr = addrs[0]; - addr = ntohl(addrs[0]); + tor_addr_from_ipv4n(&addr, addrs[0]); status = DNS_RESOLVE_SUCCEEDED; - tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf)); + + tor_addr_to_str(answer_buf, &addr, sizeof(answer_buf), 0); escaped_address = esc_for_log(string_address); if (answer_is_wildcarded(answer_buf)) { @@ -1382,6 +1405,29 @@ evdns_callback(int result, char type, int count, int ttl, void *addresses, escaped_safe_str(answer_buf)); } tor_free(escaped_address); + } else if (type == DNS_IPv6_AAAA && count) { + char answer_buf[TOR_ADDR_BUF_LEN]; + char *escaped_address; + struct in6_addr *addrs = addresses; + tor_addr_from_in6(&addr, &addrs[0]); + status = DNS_RESOLVE_SUCCEEDED; + tor_inet_ntop(AF_INET6, &addrs[0], answer_buf, sizeof(answer_buf)); + escaped_address = esc_for_log(string_address); + + if (answer_is_wildcarded(answer_buf)) { + log_debug(LD_EXIT, "eventdns said that %s resolves to ISP-hijacked " + "address %s; treating as a failure.", + safe_str(escaped_address), + escaped_safe_str(answer_buf)); + was_wildcarded = 1; + tor_addr_make_unspec(&addr); /* WRONG WRONG ETC XXXXXXXX */ + status = DNS_RESOLVE_FAILED_PERMANENT; + } else { + log_debug(LD_EXIT, "eventdns said that %s resolves to %s", + safe_str(escaped_address), + escaped_safe_str(answer_buf)); + } + tor_free(escaped_address); } else if (type == DNS_PTR && count) { char *escaped_address; is_reverse = 1; @@ -1666,8 +1712,8 @@ launch_test_addresses(int fd, short event, void *args) /* This situation is worse than the failure-hijacking situation. When this * happens, we're no good for DNS requests at all, and we shouldn't really * be an exit server.*/ - if (!options->ServerDNSTestAddresses) - return; + if (options->ServerDNSTestAddresses) { + tor_assert(the_evdns_base); SMARTLIST_FOREACH_BEGIN(options->ServerDNSTestAddresses, const char *, address) { @@ -1683,12 +1729,16 @@ launch_test_addresses(int fd, short event, void *args) a = tor_strdup(address); req = evdns_base_resolve_ipv6(the_evdns_base, address, DNS_QUERY_NO_SEARCH, evdns_callback, a); + ++n_ipv6_requests_made; if (!req) { log_info(LD_EXIT, "eventdns rejected test address %s", escaped_safe_str(address)); tor_free(a); } } SMARTLIST_FOREACH_END(address); + + } /*XXXX REINDENT */ + } #define N_WILDCARD_CHECKS 2 @@ -1756,6 +1806,13 @@ dns_seems_to_be_broken(void) return dns_is_completely_invalid; } +/** DOCDOC */ +int +dns_seems_to_be_broken_for_ipv6(void) +{ + return dns_is_broken_for_ipv6; +} + /** Forget what we've previously learned about our DNS servers' correctness. */ void dns_reset_correctness_checks(void) @@ -1765,6 +1822,8 @@ dns_reset_correctness_checks(void) n_wildcard_requests = 0; + n_ipv6_requests_made = n_ipv6_timeouts = 0; + if (dns_wildcard_list) { SMARTLIST_FOREACH(dns_wildcard_list, char *, cp, tor_free(cp)); smartlist_clear(dns_wildcard_list); @@ -1775,7 +1834,8 @@ dns_reset_correctness_checks(void) smartlist_clear(dns_wildcarded_test_address_list); } dns_wildcard_one_notice_given = dns_wildcard_notice_given = - dns_wildcarded_test_address_notice_given = dns_is_completely_invalid = 0; + dns_wildcarded_test_address_notice_given = dns_is_completely_invalid = + dns_is_broken_for_ipv6 = 0; } /** Return true iff we have noticed that the dotted-quad ip has been diff --git a/src/or/dns.h b/src/or/dns.h index 441a6c3506..d2f6614e64 100644 --- a/src/or/dns.h +++ b/src/or/dns.h @@ -24,6 +24,7 @@ void dns_cancel_pending_resolve(const char *question); int dns_resolve(edge_connection_t *exitconn); void dns_launch_correctness_checks(void); int dns_seems_to_be_broken(void); +int dns_seems_to_be_broken_for_ipv6(void); void dns_reset_correctness_checks(void); void dump_dns_mem_usage(int severity);