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
This commit is contained in:
Nick Mathewson
2006-12-28 21:29:11 +00:00
parent 4cd302a1eb
commit e5f5b96ca6
8 changed files with 151 additions and 28 deletions
+2
View File
@@ -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),
+117 -18
View File
@@ -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
+6 -6
View File
@@ -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);
}
}
+5 -1
View File
@@ -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 **********************/
+8 -1
View File
@@ -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));