mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2025-02-23 06:35:28 +01:00
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:
parent
04bec67574
commit
e4a9b4de4e
7 changed files with 142 additions and 6 deletions
|
@ -1,6 +1,5 @@
|
||||||
Changes in version 0.1.2.2-alpha - 2006-??-??
|
Changes in version 0.1.2.2-alpha - 2006-??-??
|
||||||
o Major features:
|
o Major features:
|
||||||
|
|
||||||
- Add server-side support for "reverse" DNS lookups (using PTR
|
- Add server-side support for "reverse" DNS lookups (using PTR
|
||||||
records so clients can determine the canonical hostname for a given
|
records so clients can determine the canonical hostname for a given
|
||||||
IPv4 address). This has been specified for a long time, but was
|
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
|
servers now announce in their descriptors whether they support
|
||||||
eventdns.
|
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
|
o Security Fixes, minor
|
||||||
- If a client asked for a server by name, and we didn't have a
|
- 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
|
descriptor for a named server with that name, we might return an old
|
||||||
|
|
4
doc/TODO
4
doc/TODO
|
@ -87,9 +87,9 @@ d - Write limiting; separate token bucket for write
|
||||||
- Write-limit directory responses (need to research)
|
- Write-limit directory responses (need to research)
|
||||||
|
|
||||||
N - DNS improvements
|
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.
|
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.
|
- Don't ask reject *:* nodes for DNS unless client wants you to.
|
||||||
. Asynchronous DNS
|
. Asynchronous DNS
|
||||||
o Document and rename SearchDomains, ResolvConf options
|
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".
|
connected to "www.example.com".
|
||||||
This option only effects name lookup for addresses requested by clients.
|
This option only effects name lookup for addresses requested by clients.
|
||||||
(Defaults to "0".)
|
(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
|
.SH DIRECTORY SERVER OPTIONS
|
||||||
.PP
|
.PP
|
||||||
|
|
|
@ -222,6 +222,7 @@ static config_var_t _option_vars[] = {
|
||||||
VAR("RunTesting", BOOL, RunTesting, "0"),
|
VAR("RunTesting", BOOL, RunTesting, "0"),
|
||||||
VAR("SafeLogging", BOOL, SafeLogging, "1"),
|
VAR("SafeLogging", BOOL, SafeLogging, "1"),
|
||||||
VAR("SafeSocks", BOOL, SafeSocks, "0"),
|
VAR("SafeSocks", BOOL, SafeSocks, "0"),
|
||||||
|
VAR("ServerDNSDetectHijacking",BOOL, ServerDNSDetectHijacking,"1"),
|
||||||
VAR("ServerDNSResolvConfFile", STRING, ServerDNSResolvConfFile, NULL),
|
VAR("ServerDNSResolvConfFile", STRING, ServerDNSResolvConfFile, NULL),
|
||||||
VAR("ServerDNSSearchDomains", BOOL, ServerDNSSearchDomains, "0"),
|
VAR("ServerDNSSearchDomains", BOOL, ServerDNSSearchDomains, "0"),
|
||||||
VAR("ShutdownWaitLength", INTERVAL, ShutdownWaitLength, "30 seconds"),
|
VAR("ShutdownWaitLength", INTERVAL, ShutdownWaitLength, "30 seconds"),
|
||||||
|
|
110
src/or/dns.c
110
src/or/dns.c
|
@ -122,6 +122,7 @@ static int spawn_dnsworker(void);
|
||||||
static int spawn_enough_dnsworkers(void);
|
static int spawn_enough_dnsworkers(void);
|
||||||
#else
|
#else
|
||||||
static int configure_nameservers(int force);
|
static int configure_nameservers(int force);
|
||||||
|
static int answer_is_wildcarded(const char *ip);
|
||||||
#endif
|
#endif
|
||||||
#ifdef DEBUG_DNS_CACHE
|
#ifdef DEBUG_DNS_CACHE
|
||||||
static void _assert_cache_ok(void);
|
static void _assert_cache_ok(void);
|
||||||
|
@ -1330,6 +1331,11 @@ spawn_enough_dnsworkers(void)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dns_launch_wildcard_checks(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
#else /* !USE_EVENTDNS */
|
#else /* !USE_EVENTDNS */
|
||||||
|
|
||||||
/** Eventdns helper: return true iff the eventdns result <b>err</b> is
|
/** 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;
|
status = DNS_RESOLVE_SUCCEEDED;
|
||||||
tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf));
|
tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf));
|
||||||
escaped_address = esc_for_log(string_address);
|
escaped_address = esc_for_log(string_address);
|
||||||
log_debug(LD_EXIT, "eventdns said that %s resolves to %s",
|
|
||||||
safe_str(escaped_address),
|
if (answer_is_wildcarded(answer_buf)) {
|
||||||
escaped_safe_str(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);
|
tor_free(escaped_address);
|
||||||
} else if (type == DNS_PTR && count) {
|
} else if (type == DNS_PTR && count) {
|
||||||
char *escaped_address;
|
char *escaped_address;
|
||||||
|
@ -1546,6 +1562,94 @@ launch_resolve(edge_connection_t *exitconn)
|
||||||
}
|
}
|
||||||
return r ? -1 : 0;
|
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 */
|
#endif /* USE_EVENTDNS */
|
||||||
|
|
||||||
/** Exit with an assertion if <b>resolve</b> is corrupt. */
|
/** 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_try_getting_descriptors = 0;
|
||||||
static time_t time_to_reset_descriptor_failures = 0;
|
static time_t time_to_reset_descriptor_failures = 0;
|
||||||
static time_t time_to_add_entropy = 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();
|
or_options_t *options = get_options();
|
||||||
int i;
|
int i;
|
||||||
int have_dir_info;
|
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.
|
* we'll pass it to poll/select and bad things will happen.
|
||||||
*/
|
*/
|
||||||
close_closeable_connections();
|
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;
|
static struct event *timeout_event = NULL;
|
||||||
|
|
|
@ -1574,6 +1574,8 @@ typedef struct {
|
||||||
int ServerDNSSearchDomains; /**< Boolean: If set, we don't force exit
|
int ServerDNSSearchDomains; /**< Boolean: If set, we don't force exit
|
||||||
* addresses to be FQDNs, but rather search for them in
|
* addresses to be FQDNs, but rather search for them in
|
||||||
* the local domains. */
|
* the local domains. */
|
||||||
|
int ServerDNSDetectHijacking; /**< Boolean: If true, check for DNS failure
|
||||||
|
* hijacking */
|
||||||
char *ServerDNSResolvConfFile; /**< If provided, we configure our internal
|
char *ServerDNSResolvConfFile; /**< If provided, we configure our internal
|
||||||
* resolver from the file here rather than from
|
* resolver from the file here rather than from
|
||||||
* /etc/resolv.conf (unix) or the registry (windows) */
|
* /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 assert_all_pending_dns_resolves_ok(void);
|
||||||
void dns_cancel_pending_resolve(const char *question);
|
void dns_cancel_pending_resolve(const char *question);
|
||||||
int dns_resolve(edge_connection_t *exitconn);
|
int dns_resolve(edge_connection_t *exitconn);
|
||||||
|
void dns_launch_wildcard_checks(void);
|
||||||
|
|
||||||
/********************************* hibernate.c **********************/
|
/********************************* hibernate.c **********************/
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue