mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-27 22:03:31 +01:00
r8910@Kushana: nickm | 2006-09-22 12:14:05 -0400
Instead of just checking known-invalid addresses for DNS hijacking, we now check randomly generated addresses, and if too many of them map to the same IP, we assume that IP is the destination of a DNS hijack attempt. A little bird tells me that some DNS hijackers think that declining to give an A record for RFC2606 addresses (like .invalid and .example) makes them more standards compliant. Standardswise, this is like an illicit brothel making sure that nobody has pulled the tags off the mattresss, but that doesn't get us out of working around it. svn:r8465
This commit is contained in:
parent
bde5939ad3
commit
4218f09820
@ -12,7 +12,9 @@ Changes in version 0.1.2.2-alpha - 2006-??-??
|
|||||||
o Minor features:
|
o Minor features:
|
||||||
- Check for name servers (like Earthlink's) that hijack failing DNS
|
- Check for name servers (like Earthlink's) that hijack failing DNS
|
||||||
requests and replace the 'no such server' answer with a "helpful"
|
requests and replace the 'no such server' answer with a "helpful"
|
||||||
redirect to an advertising-driven search portal. [Resolves bug 330.]
|
redirect to an advertising-driven search portal. We're a little clever
|
||||||
|
about this, in order to work around DNS hijackers who "helpfully"
|
||||||
|
decline to hijack known-invalid RFC2606 addresses. [Resolves bug 330.]
|
||||||
- When asked to resolve a hostname, don't use non-exit servers unless
|
- When asked to resolve a hostname, don't use non-exit servers unless
|
||||||
requested to do so. This allows servers with broken DNS be useful to
|
requested to do so. This allows servers with broken DNS be useful to
|
||||||
the network.
|
the network.
|
||||||
|
95
src/or/dns.c
95
src/or/dns.c
@ -575,7 +575,7 @@ dns_resolve(edge_connection_t *exitconn)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
//log_notice(LD_EXIT, "Looks like an address %s",
|
//log_notice(LD_EXIT, "Looks like an address %s",
|
||||||
// exitconn->_base.address);
|
// exitconn->_base.address);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* now check the hash table to see if 'address' is already there. */
|
/* now check the hash table to see if 'address' is already there. */
|
||||||
@ -1580,11 +1580,50 @@ 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
|
/** How many requests for bogus addresses have we launched so far? */
|
||||||
* apparently wants to return in response to requests for nonexistent domains.
|
static int n_wildcard_requests = 0;
|
||||||
|
|
||||||
|
/** Map from dotted-quad IP address in response to an int holding how many
|
||||||
|
* times we've seen it for a randomly generated (hopefully bogus) address. It
|
||||||
|
* would be easier to use definitely-invalid addresses (as specified by
|
||||||
|
* RFC2606), but see comment in dns_launch_wildcard_checks(). */
|
||||||
|
static strmap_t *dns_wildcard_response_count = NULL;
|
||||||
|
|
||||||
|
/** If present, a list of dotted-quad IP addresses that we are pretty sure our
|
||||||
|
* nameserver wants to return in response to requests for nonexistent domains.
|
||||||
*/
|
*/
|
||||||
static smartlist_t *dns_wildcard_list = NULL;
|
static smartlist_t *dns_wildcard_list = NULL;
|
||||||
|
|
||||||
|
/** Called when we see <b>id</b> (a dotted quad) in response to a request for
|
||||||
|
* a hopefully bogus address. */
|
||||||
|
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();
|
||||||
|
|
||||||
|
ip = strmap_get(dns_wildcard_response_count, id); // may be null (0)
|
||||||
|
if (!ip) {
|
||||||
|
ip = tor_malloc_zero(sizeof(int));
|
||||||
|
strmap_set(dns_wildcard_response_count, id, ip);
|
||||||
|
}
|
||||||
|
++*ip;
|
||||||
|
|
||||||
|
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,
|
||||||
|
"Your DNS provider has given \"%s\" as an answer for %d different "
|
||||||
|
"invalid addresses. Apparently they are hijacking DNS failures. "
|
||||||
|
"I'll trying to correct for this by treating future occurrences of "
|
||||||
|
"\"%s\" as 'not found'.", id, *ip, id);
|
||||||
|
smartlist_add(dns_wildcard_list, tor_strdup(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Callback function when we get an answer (possibly failing) for a request
|
/** Callback function when we get an answer (possibly failing) for a request
|
||||||
* for a (hopefully) nonexistent domain. */
|
* for a (hopefully) nonexistent domain. */
|
||||||
static void
|
static void
|
||||||
@ -1593,43 +1632,43 @@ eventdns_wildcard_check_callback(int result, char type, int count, int ttl,
|
|||||||
{
|
{
|
||||||
static int notice_given = 0;
|
static int notice_given = 0;
|
||||||
(void)ttl;
|
(void)ttl;
|
||||||
|
++n_wildcard_requests;
|
||||||
if (result == DNS_ERR_NONE && type == DNS_IPv4_A && count) {
|
if (result == DNS_ERR_NONE && type == DNS_IPv4_A && count) {
|
||||||
uint32_t *addrs = addresses;
|
uint32_t *addrs = addresses;
|
||||||
int i;
|
int i;
|
||||||
char *string_address = arg;
|
char *string_address = arg;
|
||||||
if (!dns_wildcard_list) dns_wildcard_list = smartlist_create();
|
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
char answer_buf[INET_NTOA_BUF_LEN+1];
|
char answer_buf[INET_NTOA_BUF_LEN+1];
|
||||||
struct in_addr in;
|
struct in_addr in;
|
||||||
in.s_addr = addrs[i];
|
in.s_addr = addrs[i];
|
||||||
tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf));
|
tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf));
|
||||||
if (!smartlist_string_isin(dns_wildcard_list, answer_buf))
|
wildcard_increment_answer(answer_buf);
|
||||||
smartlist_add(dns_wildcard_list, tor_strdup(answer_buf));
|
|
||||||
}
|
}
|
||||||
log(notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT,
|
log(notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT,
|
||||||
"Your DNS provider gave an answer for \"%s\", which "
|
"Your DNS provider gave an answer for \"%s\", which "
|
||||||
"is not supposed to exist. Apparently they are hijacking "
|
"is not supposed to exist. Apparently they are hijacking "
|
||||||
"DNS failures. Trying to correct for this. We've noticed %d bad "
|
"DNS failures. Trying to correct for this. We've noticed %d possibly "
|
||||||
"addresses so far.", string_address, smartlist_len(dns_wildcard_list));
|
"bad addresses so far.",
|
||||||
|
string_address, strmap_size(dns_wildcard_response_count));
|
||||||
notice_given = 1;
|
notice_given = 1;
|
||||||
}
|
}
|
||||||
tor_free(arg);
|
tor_free(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Launch a single request for a nonexistent hostname consisting of
|
/** Launch a single request for a nonexistent hostname consisting of between
|
||||||
* <b>len</b> random (plausible) characters followed by <b>suffix</b> */
|
* <b>min_len</b> and <b>max_len</b> random (plausible) characters followed by
|
||||||
|
* <b>suffix</b> */
|
||||||
static void
|
static void
|
||||||
launch_wildcard_check(int len, const char *suffix)
|
launch_wildcard_check(int min_len, int max_len, const char *suffix)
|
||||||
{
|
{
|
||||||
char random_bytes[16], name[64], *addr;
|
char random_bytes[20], name[64], *addr;
|
||||||
size_t n = (len*5+7)/8;
|
size_t len;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
tor_assert(n <= sizeof(random_bytes));
|
len = min_len + crypto_rand_int(max_len-min_len+1);
|
||||||
|
if (crypto_rand(random_bytes, sizeof(random_bytes)) < 0)
|
||||||
if (crypto_rand(random_bytes, n) < 0)
|
|
||||||
return;
|
return;
|
||||||
base32_encode(name, sizeof(name), random_bytes, n);
|
base32_encode(name, sizeof(name), random_bytes, sizeof(random_bytes));
|
||||||
name[len] = '\0';
|
name[len] = '\0';
|
||||||
strlcat(name, suffix, sizeof(name));
|
strlcat(name, suffix, sizeof(name));
|
||||||
|
|
||||||
@ -1655,14 +1694,28 @@ dns_launch_wildcard_checks(void)
|
|||||||
log_info(LD_EXIT, "Launching checks to see whether our nameservers like "
|
log_info(LD_EXIT, "Launching checks to see whether our nameservers like "
|
||||||
"to hijack DNS failures.");
|
"to hijack DNS failures.");
|
||||||
for (i = 0; i < N_WILDCARD_CHECKS; ++i) {
|
for (i = 0; i < N_WILDCARD_CHECKS; ++i) {
|
||||||
/* RFC2606 reserves these */
|
/* RFC2606 reserves these. Sadly, some DNS hijackers, in a silly attempt
|
||||||
launch_wildcard_check(8, ".invalid");
|
* to 'comply' with rfc2606, refrain from giving A records for these.
|
||||||
launch_wildcard_check(8, ".test");
|
* This is the standards-complaince equivalent of making sure that your
|
||||||
|
* crackhouse's elevator inspection certificate is up to date.
|
||||||
|
*/
|
||||||
|
launch_wildcard_check(2, 16, "%s.invalid");
|
||||||
|
launch_wildcard_check(2, 16, "%s.test");
|
||||||
|
|
||||||
|
/* Thy somese will break specs if there are ever any number of
|
||||||
|
* 8+-character top-level domains. */
|
||||||
|
launch_wildcard_check(8, 16,"");
|
||||||
|
|
||||||
|
/* Try some random .com/org/net domains. This will work fine so long as
|
||||||
|
* not too many resolve to the same place. */
|
||||||
|
launch_wildcard_check(8, 16, "%s.com");
|
||||||
|
launch_wildcard_check(8, 16, "%s.org");
|
||||||
|
launch_wildcard_check(8, 16, "%s.net");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return true iff we have noticed that the dotted-quad <b>ip</b> has been
|
/** 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. */
|
* returned in response to requests for nonexistent hostnames. */
|
||||||
static int
|
static int
|
||||||
answer_is_wildcarded(const char *ip)
|
answer_is_wildcarded(const char *ip)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user