r8875@Kushana: nickm | 2006-09-21 16:46:28 -0400

Resolve bug 330: detect ISPs that want to hijack failing DNS requests and basically domain-squat the entire internet.


svn:r8440
This commit is contained in:
Nick Mathewson 2006-09-21 21:48:22 +00:00
parent 04bec67574
commit e4a9b4de4e
7 changed files with 142 additions and 6 deletions

View File

@ -1,6 +1,5 @@
Changes in version 0.1.2.2-alpha - 2006-??-??
o Major features:
- Add server-side support for "reverse" DNS lookups (using PTR
records so clients can determine the canonical hostname for a given
IPv4 address). This has been specified for a long time, but was
@ -8,6 +7,11 @@ Changes in version 0.1.2.2-alpha - 2006-??-??
servers now announce in their descriptors whether they support
eventdns.
o Minor features:
- Check for name servers (like Earthlink's) that hijack failing DNS
requests and replace the 'no such server' answer with a "helpful"
redirect to an advertising-driven search portal. [Resolves bug 330.]
o Security Fixes, minor
- If a client asked for a server by name, and we didn't have a
descriptor for a named server with that name, we might return an old

View File

@ -87,9 +87,9 @@ d - Write limiting; separate token bucket for write
- Write-limit directory responses (need to research)
N - DNS improvements
- Option to deal with broken DNS of the "ggoogle.com? Ah, you meant
o Option to deal with broken DNS of the "ggoogle.com? Ah, you meant
ads.me.com!" variety.
d - Autodetect whether DNS is broken in this way.
o Autodetect whether DNS is broken in this way.
- Don't ask reject *:* nodes for DNS unless client wants you to.
. Asynchronous DNS
o Document and rename SearchDomains, ResolvConf options

View File

@ -647,6 +647,15 @@ domain. For example, if this system is configured to believe it is in
connected to "www.example.com".
This option only effects name lookup for addresses requested by clients.
(Defaults to "0".)
.LP
.TP
\fBServerDNSDetectHijacking \fR\fB0\fR|\fB1\fR\fP
When this option is set to 1, we will test periodically to determine whether
our local nameservers have been configured to hijack failing DNS requests
(usually to an advertising site). If they are, we will attempt to correct
this. This option only effects name lookup for addresses requested by
clients; and only takes effect if Tor was built with eventdns support.
(Defaults to "1".)
.SH DIRECTORY SERVER OPTIONS
.PP

View File

@ -222,6 +222,7 @@ static config_var_t _option_vars[] = {
VAR("RunTesting", BOOL, RunTesting, "0"),
VAR("SafeLogging", BOOL, SafeLogging, "1"),
VAR("SafeSocks", BOOL, SafeSocks, "0"),
VAR("ServerDNSDetectHijacking",BOOL, ServerDNSDetectHijacking,"1"),
VAR("ServerDNSResolvConfFile", STRING, ServerDNSResolvConfFile, NULL),
VAR("ServerDNSSearchDomains", BOOL, ServerDNSSearchDomains, "0"),
VAR("ShutdownWaitLength", INTERVAL, ShutdownWaitLength, "30 seconds"),

View File

@ -122,6 +122,7 @@ static int spawn_dnsworker(void);
static int spawn_enough_dnsworkers(void);
#else
static int configure_nameservers(int force);
static int answer_is_wildcarded(const char *ip);
#endif
#ifdef DEBUG_DNS_CACHE
static void _assert_cache_ok(void);
@ -1330,6 +1331,11 @@ spawn_enough_dnsworkers(void)
return 0;
}
void
dns_launch_wildcard_checks(void)
{
}
#else /* !USE_EVENTDNS */
/** Eventdns helper: return true iff the eventdns result <b>err</b> is
@ -1470,9 +1476,19 @@ eventdns_callback(int result, char type, int count, int ttl, void *addresses,
status = DNS_RESOLVE_SUCCEEDED;
tor_inet_ntoa(&in, 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));
addr = 0;
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;
@ -1546,6 +1562,94 @@ launch_resolve(edge_connection_t *exitconn)
}
return r ? -1 : 0;
}
/** If present, a list of dotted-quad IP addresses that our nameserver
* apparently wants to return in response to requests for nonexistent domains.
*/
static smartlist_t *dns_wildcard_list = NULL;
/** Callback function when we get an answer (possibly failing) for a request
* for a (hopefully) nonexistent domain. */
static void
eventdns_wildcard_check_callback(int result, char type, int count, int ttl,
void *addresses, void *arg)
{
static int notice_given = 0;
if (result == DNS_ERR_NONE && type == DNS_IPv4_A && count) {
uint32_t *addrs = addresses;
int i;
char *string_address = arg;
if (!dns_wildcard_list) dns_wildcard_list = smartlist_create();
for (i = 0; i < count; ++i) {
char answer_buf[INET_NTOA_BUF_LEN+1];
struct in_addr in;
in.s_addr = addrs[i];
tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf));
if (!smartlist_string_isin(dns_wildcard_list, answer_buf))
smartlist_add(dns_wildcard_list, tor_strdup(answer_buf));
}
log(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 bad "
"addresses so far.", string_address, smartlist_len(dns_wildcard_list));
notice_given = 1;
}
tor_free(arg);
}
/** Launch a single request for a nonexistent hostname consisting of
* <b>len</b> random (plausible) characters followed by <b>suffix</b> */
static void
launch_wildcard_check(int len, const char *suffix)
{
char random_bytes[16], name[64], *addr;
size_t n = (len+1)/2;
int r;
tor_assert(n <= sizeof(random_bytes));
if (crypto_rand(random_bytes, n) < 0)
return;
base32_encode(name, sizeof(name), random_bytes, n);
name[len] = '\0';
strlcat(name, suffix, sizeof(name));
addr = tor_strdup(name);
r = eventdns_resolve_ipv4(name, DNS_QUERY_NO_SEARCH,
eventdns_wildcard_check_callback, addr);
if (r)
tor_free(addr);
}
#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
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) {
/* RFC2606 reserves these */
launch_wildcard_check(8, ".invalid");
launch_wildcard_check(8, ".test");
}
}
/** Return true iff we have noticed that the dotted-quad <b>ip</b> has been
* returned in response to a request for a nonexistent hostname. */
static int
answer_is_wildcarded(const char *ip)
{
return dns_wildcard_list && smartlist_string_isin(dns_wildcard_list, ip);
}
#endif /* USE_EVENTDNS */
/** Exit with an assertion if <b>resolve</b> is corrupt. */

View File

@ -722,6 +722,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;
or_options_t *options = get_options();
int i;
int have_dir_info;
@ -923,6 +924,20 @@ run_scheduled_events(time_t now)
* we'll pass it to poll/select and bad things will happen.
*/
close_closeable_connections();
/** 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);
} else {
dns_launch_wildcard_checks();
time_to_check_for_wildcarded_dns = now + 12*3600 +
crypto_rand_int(12*3600);
}
}
}
static struct event *timeout_event = NULL;

View File

@ -1574,6 +1574,8 @@ typedef struct {
int ServerDNSSearchDomains; /**< Boolean: If set, we don't force exit
* addresses to be FQDNs, but rather search for them in
* the local domains. */
int ServerDNSDetectHijacking; /**< Boolean: If true, check for DNS failure
* hijacking */
char *ServerDNSResolvConfFile; /**< If provided, we configure our internal
* resolver from the file here rather than from
* /etc/resolv.conf (unix) or the registry (windows) */
@ -2158,6 +2160,7 @@ 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);
void dns_launch_wildcard_checks(void);
/********************************* hibernate.c **********************/