diff options
author | Nick Mathewson <nickm@torproject.org> | 2006-12-28 21:29:11 +0000 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2006-12-28 21:29:11 +0000 |
commit | e5f5b96ca6bc35d22478840600c2dfdf2778950f (patch) | |
tree | 1c6d406bffc1d2691ff125894146d191fe17ebd2 | |
parent | 4cd302a1ebd44eafe5ac57062288436ab41b1220 (diff) | |
download | tor-e5f5b96ca6bc35d22478840600c2dfdf2778950f.tar.gz tor-e5f5b96ca6bc35d22478840600c2dfdf2778950f.zip |
r11723@Kushana: nickm | 2006-12-28 13:52:48 -0500
Fix bug 364: check for whether popular hostnames (curently google, yahoo, mit, and slashdot) are getting wildcarded. If they are, we are probably behind a DNS server that is useless: change our exit policy to reject *:*.
svn:r9199
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | doc/TODO | 4 | ||||
-rw-r--r-- | doc/tor.1.in | 8 | ||||
-rw-r--r-- | src/or/config.c | 2 | ||||
-rw-r--r-- | src/or/dns.c | 135 | ||||
-rw-r--r-- | src/or/main.c | 12 | ||||
-rw-r--r-- | src/or/or.h | 6 | ||||
-rw-r--r-- | src/or/router.c | 9 |
8 files changed, 151 insertions, 28 deletions
@@ -67,6 +67,9 @@ Changes in version 0.1.2.5-xxxx - 200?-??-?? never believe reported remote addresses when they're internal. - Add client-side caching for reverse DNS lookups. - Add support to tor-resolve for reverse lookups and SOCKS5. + - We now check for the case when common DNS requests are going to + wildcarded addresses, and change our exit policy to reject *:* if + it's happening. (Bug #364) o Security bugfixes: - Stop sending the HttpProxyAuthenticator string to directory @@ -107,8 +107,8 @@ d - Be a DNS proxy. o address_is_invalid_destination() is the right thing to call here (and feel free to make that function smarter) o add a config option to turn it off. - - and a man page for that option - - Bug 364: notice when all the DNS requests we get back (including a few + o and a man page for that option + o Bug 364: notice when all the DNS requests we get back (including a few well-known sites) are all going to the same place. o Bug 363: Warn and die if we can't find a nameserver and we're running a server; don't fall back to 127.0.0.1. diff --git a/doc/tor.1.in b/doc/tor.1.in index 6ac3c1f735..32b9c63832 100644 --- a/doc/tor.1.in +++ b/doc/tor.1.in @@ -704,6 +704,14 @@ our local nameservers have been configured to hijack failing DNS requests this. This option only affects name lookup for addresses requested by clients; and only takes effect if Tor was built with eventdns support. (Defaults to "1".) +.LP +.TP +\fBServerDNSTestAddresses \fR\fIaddress\fR,\fIaddress\fR,\fI...\fP +When we're detecting DNS hijacking, make sure that these \fIvalid\fP +addresses aren't getting redirected. If they are, then our DNS is +completely useless, and we'll reset our exit policy to "reject *:*". +(Defaults to "www.google.com, www.mit.edu, www.yahoo.com, +www.slashdot.org".) .SH DIRECTORY SERVER OPTIONS .PP diff --git a/src/or/config.c b/src/or/config.c index 9b3cca19d3..be22da7374 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -232,6 +232,8 @@ static config_var_t _option_vars[] = { VAR("ServerDNSDetectHijacking",BOOL, ServerDNSDetectHijacking,"1"), VAR("ServerDNSResolvConfFile", STRING, ServerDNSResolvConfFile, NULL), VAR("ServerDNSSearchDomains", BOOL, ServerDNSSearchDomains, "0"), + VAR("ServerDNSTestAddresses", CSV, ServerDNSTestAddresses, + "www.google.com,www.mit.edu,www.yahoo.com,www.slashdot.org"), VAR("ShutdownWaitLength", INTERVAL, ShutdownWaitLength, "30 seconds"), VAR("SocksListenAddress", LINELIST, SocksListenAddress, NULL), VAR("SocksPolicy", LINELIST, SocksPolicy, NULL), diff --git a/src/or/dns.c b/src/or/dns.c index 1369c7da1a..a85b5ee212 100644 --- a/src/or/dns.c +++ b/src/or/dns.c @@ -122,6 +122,7 @@ static void dnsworker_main(void *data); static int spawn_dnsworker(void); static int spawn_enough_dnsworkers(void); #else +static void add_wildcarded_test_address(const char *address); static int configure_nameservers(int force); static int answer_is_wildcarded(const char *ip); #endif @@ -902,8 +903,12 @@ dns_found_answer(const char *address, int is_reverse, uint32_t addr, resolve = HT_FIND(cache_map, &cache_root, &search); if (!resolve) { - log_info(LD_EXIT,"Resolved unasked address %s; caching anyway.", - escaped_safe_str(address)); + or_options_t *options = get_options(); + int is_test_address = options->ServerDNSTestAddresses && + smartlist_string_isin_case(options->ServerDNSTestAddresses, address); + if (!is_test_address) + log_info(LD_EXIT,"Resolved unasked address %s; caching anyway.", + escaped_safe_str(address)); add_answer_to_cache(address, is_reverse, addr, hostname, outcome, ttl); return; } @@ -1385,9 +1390,15 @@ spawn_enough_dnsworkers(void) } void -dns_launch_wildcard_checks(void) +dns_launch_correctness_checks(void) { } + +int +dns_seems_to_be_broken(void) +{ + return 0; +} #else /* !USE_EVENTDNS */ /** Eventdns helper: return true iff the eventdns result <b>err</b> is @@ -1512,13 +1523,14 @@ configure_nameservers(int force) */ static void evdns_callback(int result, char type, int count, int ttl, void *addresses, - void *arg) + void *arg) { char *string_address = arg; int is_reverse = 0; int status = DNS_RESOLVE_FAILED_PERMANENT; uint32_t addr = 0; const char *hostname = NULL; + int was_wildcarded = 0; if (result == DNS_ERR_NONE) { if (type == DNS_IPv4_A && count) { @@ -1537,6 +1549,7 @@ evdns_callback(int result, char type, int count, int ttl, void *addresses, "address %s; treating as a failure.", safe_str(escaped_address), escaped_safe_str(answer_buf)); + was_wildcarded = 1; addr = 0; status = DNS_RESOLVE_FAILED_PERMANENT; } else { @@ -1566,6 +1579,17 @@ evdns_callback(int result, char type, int count, int ttl, void *addresses, if (evdns_err_is_transient(result)) status = DNS_RESOLVE_FAILED_TRANSIENT; } + if (was_wildcarded) { + or_options_t *options = get_options(); + int is_test_address = options->ServerDNSTestAddresses && + smartlist_string_isin_case(options->ServerDNSTestAddresses, hostname); + + if (is_test_address) { + /* Ick. We're getting redirected on known-good addresses. Our DNS + * server must really hate us. */ + add_wildcarded_test_address(hostname); + } + } if (result != DNS_ERR_SHUTDOWN) dns_found_answer(string_address, is_reverse, addr, hostname, status, ttl); tor_free(string_address); @@ -1634,6 +1658,13 @@ static strmap_t *dns_wildcard_response_count = NULL; * nameserver wants to return in response to requests for nonexistent domains. */ static smartlist_t *dns_wildcard_list = NULL; +static int dns_wildcard_one_notice_given = 0; +static int dns_wildcard_notice_given = 0; + +/** DOCDOC */ +static smartlist_t *dns_wildcarded_test_address_list = NULL; +static int dns_wildcarded_test_address_notice_given = 0; +static int dns_is_completely_invalid = 0; /** Called when we see <b>id</b> (a dotted quad) in response to a request for * a hopefully bogus address. */ @@ -1641,7 +1672,6 @@ static void wildcard_increment_answer(const char *id) { int *ip; - static int notice_given = 0; if (!dns_wildcard_response_count) dns_wildcard_response_count = strmap_new(); @@ -1655,14 +1685,40 @@ wildcard_increment_answer(const char *id) if (*ip > 5 && n_wildcard_requests > 10) { if (!dns_wildcard_list) dns_wildcard_list = smartlist_create(); if (!smartlist_string_isin(dns_wildcard_list, id)) { - log(notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT, + log(dns_wildcard_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT, "Your DNS provider has given \"%s\" as an answer for %d different " "invalid addresses. Apparently they are hijacking DNS failures. " "I'll try to correct for this by treating future occurrences of " "\"%s\" as 'not found'.", id, *ip, id); smartlist_add(dns_wildcard_list, tor_strdup(id)); } - notice_given = 1; + dns_wildcard_notice_given = 1; + } +} + +static void +add_wildcarded_test_address(const char *address) +{ + int n; + if (!dns_wildcarded_test_address_list) + dns_wildcarded_test_address_list = smartlist_create(); + + if (smartlist_string_isin_case(dns_wildcarded_test_address_list, address)) + return; + + smartlist_add(dns_wildcarded_test_address_list, tor_strdup(address)); + n = smartlist_len(dns_wildcarded_test_address_list); + if (n > smartlist_len(get_options()->ServerDNSTestAddresses)/2) { + log(dns_wildcarded_test_address_notice_given ? LOG_INFO : LOG_NOTICE, + LD_EXIT, "Your DNS provider tried to redirect \"%s\" to a junk " + "address. It has done this with %d test addresses so far. I'm " + "going to stop being an exit node for now, since our DNS seems so " + "broken.", address, n); + if (!dns_is_completely_invalid) { + dns_is_completely_invalid = 1; + mark_my_descriptor_dirty(); + } + dns_wildcarded_test_address_notice_given = 1; } } @@ -1670,9 +1726,8 @@ wildcard_increment_answer(const char *id) * for a (hopefully) nonexistent domain. */ static void evdns_wildcard_check_callback(int result, char type, int count, int ttl, - void *addresses, void *arg) + void *addresses, void *arg) { - static int notice_given = 0; (void)ttl; ++n_wildcard_requests; if (result == DNS_ERR_NONE && type == DNS_IPv4_A && count) { @@ -1686,13 +1741,13 @@ evdns_wildcard_check_callback(int result, char type, int count, int ttl, tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf)); wildcard_increment_answer(answer_buf); } - log(notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT, + log(dns_wildcard_one_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT, "Your DNS provider gave an answer for \"%s\", which " "is not supposed to exist. Apparently they are hijacking " "DNS failures. Trying to correct for this. We've noticed %d possibly " "bad addresses so far.", string_address, strmap_size(dns_wildcard_response_count)); - notice_given = 1; + dns_wildcard_one_notice_given = 1; } tor_free(arg); } @@ -1721,18 +1776,38 @@ launch_wildcard_check(int min_len, int max_len, const char *suffix) tor_free(addr); } +static void +launch_test_addresses(int fd, short event, void *args) +{ + or_options_t *options = get_options(); + (void)fd; + (void)event; + (void)args; + + log_info(LD_EXIT, "Launching checks to see whether our nameservers like to " + "hijack *everything*."); + /* 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; + SMARTLIST_FOREACH(options->ServerDNSTestAddresses, const char *, address, + { + evdns_resolve_ipv4(address, DNS_QUERY_NO_SEARCH, evdns_callback, + tor_strdup(address)); + }); +} + #define N_WILDCARD_CHECKS 2 -/** Launch DNS requests for a few nonexistent hostnames, and see if we can - * catch our nameserver trying to hijack them and map them to a stupid "I - * couldn't find ggoogle.com but maybe you'd like to buy these lovely - * encyclopedias" page. */ -void +/** Launch DNS requests for a few nonexistent hostnames and a few well-known + * hostnames, and see if we can catch our nameserver trying to hijack them and + * map them to a stupid "I couldn't find ggoogle.com but maybe you'd like to + * buy these lovely encyclopedias" page. */ +static void dns_launch_wildcard_checks(void) { int i; - if (!get_options()->ServerDNSDetectHijacking) - return; log_info(LD_EXIT, "Launching checks to see whether our nameservers like " "to hijack DNS failures."); for (i = 0; i < N_WILDCARD_CHECKS; ++i) { @@ -1756,6 +1831,30 @@ dns_launch_wildcard_checks(void) } } +/* DOCDOC */ +void +dns_launch_correctness_checks(void) +{ + static struct event launch_event; + struct timeval timeout; + if (!get_options()->ServerDNSDetectHijacking) + return; + dns_launch_wildcard_checks(); + + /* Wait a while before launching requests for test addresses, so we can + * get the results from checking for wildcarding. */ + evtimer_set(&launch_event, launch_test_addresses, NULL); + timeout.tv_sec = 30; + timeout.tv_usec = 0; + evtimer_add(&launch_event, &timeout); +} + +int +dns_seems_to_be_broken(void) +{ + return dns_is_completely_invalid; +} + /** Return true iff we have noticed that the dotted-quad <b>ip</b> has been * returned in response to requests for nonexistent hostnames. */ static int diff --git a/src/or/main.c b/src/or/main.c index 7120e06438..e0be4281a6 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -729,7 +729,7 @@ run_scheduled_events(time_t now) static time_t time_to_try_getting_descriptors = 0; static time_t time_to_reset_descriptor_failures = 0; static time_t time_to_add_entropy = 0; - static time_t time_to_check_for_wildcarded_dns = 0; + static time_t time_to_check_for_correct_dns = 0; or_options_t *options = get_options(); int i; int have_dir_info; @@ -937,12 +937,12 @@ run_scheduled_events(time_t now) /** 9. and if we're a server, check whether our DNS is telling stories to * us. */ - if (server_mode(options) && time_to_check_for_wildcarded_dns < now) { - if (!time_to_check_for_wildcarded_dns) { - time_to_check_for_wildcarded_dns = now + 60 + crypto_rand_int(120); + if (server_mode(options) && time_to_check_for_correct_dns < now) { + if (!time_to_check_for_correct_dns) { + time_to_check_for_correct_dns = now + 60 + crypto_rand_int(120); } else { - dns_launch_wildcard_checks(); - time_to_check_for_wildcarded_dns = now + 12*3600 + + dns_launch_correctness_checks(); + time_to_check_for_correct_dns = now + 12*3600 + crypto_rand_int(12*3600); } } diff --git a/src/or/or.h b/src/or/or.h index 82abdb3032..f107ab173b 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1656,6 +1656,9 @@ typedef struct { char *ServerDNSResolvConfFile; /**< If provided, we configure our internal * resolver from the file here rather than from * /etc/resolv.conf (Unix) or the registry (Windows). */ + smartlist_t *ServerDNSTestAddresses; /**< A list of addresses that definitely + * should be resolveable. Used for + * testing our DNS server. */ int EnforceDistinctSubnets; /**< If true, don't allow multiple routers in the * same network zone in the same circuit. */ int TunnelDirConns; /**< If true, use BEGIN_DIR rather than BEGIN when @@ -2318,7 +2321,8 @@ void assert_connection_edge_not_dns_pending(edge_connection_t *conn); void assert_all_pending_dns_resolves_ok(void); void dns_cancel_pending_resolve(const char *question); int dns_resolve(edge_connection_t *exitconn, or_circuit_t *circ); -void dns_launch_wildcard_checks(void); +void dns_launch_correctness_checks(void); +int dns_seems_to_be_broken(void); /********************************* hibernate.c **********************/ diff --git a/src/or/router.c b/src/or/router.c index 409dcf29bb..48c70039a9 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -1204,7 +1204,14 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router, } /* Write the exit policy to the end of 's'. */ - for (tmpe=router->exit_policy; tmpe; tmpe=tmpe->next) { + tmpe = router->exit_policy; + if (dns_seems_to_be_broken()) { + /* DNS is screwed up; don't claim to be an exit. */ + strlcat(s+written, "reject *:*\n", maxlen-written); + written += strlen("reject *:*\n"); + tmpe = NULL; + } + for ( ; tmpe; tmpe=tmpe->next) { /* Write: "accept 1.2.3.4" */ in.s_addr = htonl(tmpe->addr); tor_inet_ntoa(&in, addrbuf, sizeof(addrbuf)); |