Commit e4a9b4de authored by Nick Mathewson's avatar Nick Mathewson 🎨
Browse files

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
parent 04bec675
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
......
......@@ -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
......
......@@ -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
......
......@@ -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"),
......
......@@ -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. */
......
......@@ -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;
......
......@@ -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 **********************/
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment