mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 13:13:44 +01:00
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:
parent
4cd302a1eb
commit
e5f5b96ca6
@ -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
|
||||
|
4
doc/TODO
4
doc/TODO
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
135
src/or/dns.c
135
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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 **********************/
|
||||
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user