aboutsummaryrefslogtreecommitdiff
path: root/src/or/dns.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/dns.c')
-rw-r--r--src/or/dns.c235
1 files changed, 177 insertions, 58 deletions
diff --git a/src/or/dns.c b/src/or/dns.c
index 98eb27f8b3..192a1929d7 100644
--- a/src/or/dns.c
+++ b/src/or/dns.c
@@ -13,7 +13,51 @@
#include "or.h"
#include "ht.h"
+#ifdef HAVE_EVENT2_DNS_H
+#include <event2/event.h>
+#include <event2/dns.h>
+#else
+#include <event.h>
#include "eventdns.h"
+#ifndef HAVE_EVDNS_SET_DEFAULT_OUTGOING_BIND_ADDRESS
+#define HAVE_EVDNS_SET_DEFAULT_OUTGOING_BIND_ADDRESS
+#endif
+#endif
+
+#ifndef HAVE_EVENT2_DNS_H
+struct evdns_base;
+struct evdns_request;
+#define evdns_base_new(x,y) tor_malloc(1)
+#define evdns_base_clear_nameservers_and_suspend(base) \
+ evdns_clear_nameservers_and_suspend()
+#define evdns_base_search_clear(base) evdns_search_clear()
+#define evdns_base_set_default_outgoing_bind_address(base, a, len) \
+ evdns_set_default_outgoing_bind_address((a),(len))
+#define evdns_base_resolv_conf_parse(base, options, fname) \
+ evdns_resolv_conf_parse((options), (fname))
+#define evdns_base_count_nameservers(base) \
+ evdns_count_nameservers()
+#define evdns_base_resume(base) \
+ evdns_resume()
+#define evdns_base_config_windows_nameservers(base) \
+ evdns_config_windows_nameservers()
+#define evdns_base_set_option_(base, opt, val) \
+ evdns_set_option((opt),(val),DNS_OPTIONS_ALL)
+#define evdns_base_resolve_ipv4(base, addr, options, cb, ptr) \
+ ((evdns_resolve_ipv4(addr, options, cb, ptr)<0) ? NULL : ((void*)1))
+#define evdns_base_resolve_reverse(base, addr, options, cb, ptr) \
+ ((evdns_resolve_reverse(addr, options, cb, ptr)<0) ? NULL : ((void*)1))
+#define evdns_base_resolve_reverse_ipv6(base, addr, options, cb, ptr) \
+ ((evdns_resolve_reverse_ipv6(addr, options, cb, ptr)<0) ? NULL : ((void*)1))
+
+#elif defined(LIBEVENT_VERSION_NUMBER) && LIBEVENT_VERSION_NUMBER < 0x02000303
+#define evdns_base_set_option_(base, opt, val) \
+ evdns_base_set_option((base), (opt),(val),DNS_OPTIONS_ALL)
+
+#else
+#define evdns_base_set_option_ evdns_base_set_option
+
+#endif
/** Longest hostname we're willing to resolve. */
#define MAX_ADDRESSLEN 256
@@ -28,6 +72,9 @@
#define DNS_RESOLVE_FAILED_PERMANENT 2
#define DNS_RESOLVE_SUCCEEDED 3
+/** Our evdns_base; this structure handles all our name lookups. */
+static struct evdns_base *the_evdns_base = NULL;
+
/** Have we currently configured nameservers with eventdns? */
static int nameservers_configured = 0;
/** Did our most recent attempt to configure nameservers with eventdns fail? */
@@ -89,6 +136,8 @@ typedef struct cached_resolve_t {
uint32_t ttl; /**< What TTL did the nameserver tell us? */
/** Connections that want to know when we get an answer for this resolve. */
pending_connection_t *pending_connections;
+ /** Position of this element in the heap*/
+ int minheap_idx;
} cached_resolve_t;
static void purge_expired_resolves(time_t now);
@@ -211,8 +260,16 @@ dns_reset(void)
{
or_options_t *options = get_options();
if (! server_mode(options)) {
- evdns_clear_nameservers_and_suspend();
- evdns_search_clear();
+
+ if (!the_evdns_base) {
+ if (!(the_evdns_base = evdns_base_new(tor_libevent_get_base(), 0))) {
+ log_err(LD_BUG, "Couldn't create an evdns_base");
+ return -1;
+ }
+ }
+
+ evdns_base_clear_nameservers_and_suspend(the_evdns_base);
+ evdns_base_search_clear(the_evdns_base);
nameservers_configured = 0;
tor_free(resolv_conf_fname);
resolv_conf_mtime = 0;
@@ -262,6 +319,8 @@ dns_get_expiry_ttl(uint32_t ttl)
static void
_free_cached_resolve(cached_resolve_t *r)
{
+ if (!r)
+ return;
while (r->pending_connections) {
pending_connection_t *victim = r->pending_connections;
r->pending_connections = victim->next;
@@ -303,6 +362,7 @@ set_expiry(cached_resolve_t *resolve, time_t expires)
resolve->expire = expires;
smartlist_pqueue_add(cached_resolve_pqueue,
_compare_cached_resolves_by_expiry,
+ STRUCT_OFFSET(cached_resolve_t, minheap_idx),
resolve);
}
@@ -325,8 +385,7 @@ dns_free_all(void)
_free_cached_resolve(item);
}
HT_CLEAR(cache_map, &cache_root);
- if (cached_resolve_pqueue)
- smartlist_free(cached_resolve_pqueue);
+ smartlist_free(cached_resolve_pqueue);
cached_resolve_pqueue = NULL;
tor_free(resolv_conf_fname);
}
@@ -349,7 +408,8 @@ purge_expired_resolves(time_t now)
if (resolve->expire > now)
break;
smartlist_pqueue_pop(cached_resolve_pqueue,
- _compare_cached_resolves_by_expiry);
+ _compare_cached_resolves_by_expiry,
+ STRUCT_OFFSET(cached_resolve_t, minheap_idx));
if (resolve->state == CACHE_STATE_PENDING) {
log_debug(LD_EXIT,
@@ -611,7 +671,7 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
* know the answer. */
if (tor_addr_from_str(&addr, exitconn->_base.address) >= 0) {
if (tor_addr_family(&addr) == AF_INET) {
- tor_addr_assign(&exitconn->_base.addr, &addr);
+ tor_addr_copy(&exitconn->_base.addr, &addr);
exitconn->address_ttl = DEFAULT_DNS_TTL;
return 1;
} else {
@@ -711,6 +771,7 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
resolve = tor_malloc_zero(sizeof(cached_resolve_t));
resolve->magic = CACHED_RESOLVE_MAGIC;
resolve->state = CACHE_STATE_PENDING;
+ resolve->minheap_idx = -1;
resolve->is_reverse = is_reverse;
strlcpy(resolve->address, exitconn->_base.address, sizeof(resolve->address));
@@ -807,7 +868,8 @@ connection_dns_remove(edge_connection_t *conn)
tor_free(pend);
log_debug(LD_EXIT, "First connection (fd %d) no longer waiting "
"for resolve of %s",
- conn->_base.s, escaped_safe_str(conn->_base.address));
+ conn->_base.s,
+ escaped_safe_str(conn->_base.address));
return;
} else {
for ( ; pend->next; pend = pend->next) {
@@ -1108,6 +1170,14 @@ configure_nameservers(int force)
conf_fname = "/etc/resolv.conf";
#endif
+ if (!the_evdns_base) {
+ if (!(the_evdns_base = evdns_base_new(tor_libevent_get_base(), 0))) {
+ log_err(LD_BUG, "Couldn't create an evdns_base");
+ return -1;
+ }
+ }
+
+#ifdef HAVE_EVDNS_SET_DEFAULT_OUTGOING_BIND_ADDRESS
if (options->OutboundBindAddress) {
tor_addr_t addr;
if (tor_addr_from_str(&addr, options->OutboundBindAddress) < 0) {
@@ -1122,16 +1192,13 @@ configure_nameservers(int force)
log_warn(LD_BUG, "Couldn't convert outbound bind address to sockaddr."
" Ignoring.");
} else {
- evdns_set_default_outgoing_bind_address((struct sockaddr *)&ss,
- socklen);
+ evdns_base_set_default_outgoing_bind_address(the_evdns_base,
+ (struct sockaddr *)&ss,
+ socklen);
}
}
}
-
- if (options->ServerDNSRandomizeCase)
- evdns_set_option("randomize-case:", "1", DNS_OPTIONS_ALL);
- else
- evdns_set_option("randomize-case:", "0", DNS_OPTIONS_ALL);
+#endif
evdns_set_log_fn(evdns_log_cb);
if (conf_fname) {
@@ -1146,16 +1213,17 @@ configure_nameservers(int force)
return 0;
}
if (nameservers_configured) {
- evdns_search_clear();
- evdns_clear_nameservers_and_suspend();
+ evdns_base_search_clear(the_evdns_base);
+ evdns_base_clear_nameservers_and_suspend(the_evdns_base);
}
log_info(LD_EXIT, "Parsing resolver configuration in '%s'", conf_fname);
- if ((r = evdns_resolv_conf_parse(DNS_OPTIONS_ALL, conf_fname))) {
+ if ((r = evdns_base_resolv_conf_parse(the_evdns_base,
+ DNS_OPTIONS_ALL, conf_fname))) {
log_warn(LD_EXIT, "Unable to parse '%s', or no nameservers in '%s' (%d)",
conf_fname, conf_fname, r);
goto err;
}
- if (evdns_count_nameservers() == 0) {
+ if (evdns_base_count_nameservers(the_evdns_base) == 0) {
log_warn(LD_EXIT, "Unable to find any nameservers in '%s'.", conf_fname);
goto err;
}
@@ -1163,38 +1231,47 @@ configure_nameservers(int force)
resolv_conf_fname = tor_strdup(conf_fname);
resolv_conf_mtime = st.st_mtime;
if (nameservers_configured)
- evdns_resume();
+ evdns_base_resume(the_evdns_base);
}
#ifdef MS_WINDOWS
else {
if (nameservers_configured) {
- evdns_search_clear();
- evdns_clear_nameservers_and_suspend();
+ evdns_base_search_clear(the_evdns_base);
+ evdns_base_clear_nameservers_and_suspend(the_evdns_base);
}
- if (evdns_config_windows_nameservers()) {
+ if (evdns_base_config_windows_nameservers(the_evdns_base)) {
log_warn(LD_EXIT,"Could not config nameservers.");
goto err;
}
- if (evdns_count_nameservers() == 0) {
+ if (evdns_base_count_nameservers(the_evdns_base) == 0) {
log_warn(LD_EXIT, "Unable to find any platform nameservers in "
"your Windows configuration.");
goto err;
}
if (nameservers_configured)
- evdns_resume();
+ evdns_base_resume(the_evdns_base);
tor_free(resolv_conf_fname);
resolv_conf_mtime = 0;
}
#endif
- if (evdns_count_nameservers() == 1) {
- evdns_set_option("max-timeouts:", "16", DNS_OPTIONS_ALL);
- evdns_set_option("timeout:", "10", DNS_OPTIONS_ALL);
+#define SET(k,v) evdns_base_set_option_(the_evdns_base, (k), (v))
+
+ if (evdns_base_count_nameservers(the_evdns_base) == 1) {
+ SET("max-timeouts:", "16");
+ SET("timeout:", "10");
} else {
- evdns_set_option("max-timeouts:", "3", DNS_OPTIONS_ALL);
- evdns_set_option("timeout:", "5", DNS_OPTIONS_ALL);
+ SET("max-timeouts:", "3");
+ SET("timeout:", "5");
}
+ if (options->ServerDNSRandomizeCase)
+ SET("randomize-case:", "1");
+ else
+ SET("randomize-case:", "0");
+
+#undef SET
+
dns_servers_relaunch_checks();
nameservers_configured = 1;
@@ -1292,6 +1369,7 @@ static int
launch_resolve(edge_connection_t *exitconn)
{
char *addr = tor_strdup(exitconn->_base.address);
+ struct evdns_request *req = NULL;
tor_addr_t a;
int r;
int options = get_options()->ServerDNSSearchDomains ? 0
@@ -1307,28 +1385,34 @@ launch_resolve(edge_connection_t *exitconn)
r = tor_addr_parse_reverse_lookup_name(
&a, exitconn->_base.address, AF_UNSPEC, 0);
+
+ tor_assert(the_evdns_base);
if (r == 0) {
log_info(LD_EXIT, "Launching eventdns request for %s",
escaped_safe_str(exitconn->_base.address));
- r = evdns_resolve_ipv4(exitconn->_base.address, options,
- evdns_callback, addr);
+ req = evdns_base_resolve_ipv4(the_evdns_base,
+ exitconn->_base.address, options,
+ evdns_callback, addr);
} else if (r == 1) {
log_info(LD_EXIT, "Launching eventdns reverse request for %s",
escaped_safe_str(exitconn->_base.address));
if (tor_addr_family(&a) == AF_INET)
- r = evdns_resolve_reverse(tor_addr_to_in(&a), DNS_QUERY_NO_SEARCH,
+ req = evdns_base_resolve_reverse(the_evdns_base,
+ tor_addr_to_in(&a), DNS_QUERY_NO_SEARCH,
evdns_callback, addr);
else
- r = evdns_resolve_reverse_ipv6(tor_addr_to_in6(&a), DNS_QUERY_NO_SEARCH,
+ req = evdns_base_resolve_reverse_ipv6(the_evdns_base,
+ tor_addr_to_in6(&a), DNS_QUERY_NO_SEARCH,
evdns_callback, addr);
} else if (r == -1) {
log_warn(LD_BUG, "Somehow a malformed in-addr.arpa address reached here.");
}
- if (r) {
- log_warn(LD_EXIT, "eventdns rejected address %s: error %d.",
- escaped_safe_str(addr), r);
- r = evdns_err_is_transient(r) ? -2 : -1;
+ r = 0;
+ if (!req) {
+ log_warn(LD_EXIT, "eventdns rejected address %s.",
+ escaped_safe_str(addr));
+ r = -1;
tor_free(addr); /* There is no evdns request in progress; stop
* addr from getting leaked. */
}
@@ -1449,8 +1533,8 @@ evdns_wildcard_check_callback(int result, char type, int count, int ttl,
}
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 "
+ "is not supposed to exist. Apparently they are hijacking "
+ "DNS failures. Trying to correct for this. We've noticed %d "
"possibly bad address%s so far.",
string_address, strmap_size(dns_wildcard_response_count),
(strmap_size(dns_wildcard_response_count) == 1) ? "" : "es");
@@ -1466,17 +1550,20 @@ static void
launch_wildcard_check(int min_len, int max_len, const char *suffix)
{
char *addr;
- int r;
+ struct evdns_request *req;
addr = crypto_random_hostname(min_len, max_len, "", suffix);
log_info(LD_EXIT, "Testing whether our DNS server is hijacking nonexistent "
"domains with request for bogus hostname \"%s\"", addr);
- r = evdns_resolve_ipv4(/* This "addr" tells us which address to resolve */
+ tor_assert(the_evdns_base);
+ req = evdns_base_resolve_ipv4(
+ the_evdns_base,
+ /* This "addr" tells us which address to resolve */
addr,
DNS_QUERY_NO_SEARCH, evdns_wildcard_check_callback,
/* This "addr" is an argument to the callback*/ addr);
- if (r) {
+ if (!req) {
/* There is no evdns request in progress; stop addr from getting leaked */
tor_free(addr);
}
@@ -1488,6 +1575,7 @@ static void
launch_test_addresses(int fd, short event, void *args)
{
or_options_t *options = get_options();
+ struct evdns_request *req;
(void)fd;
(void)event;
(void)args;
@@ -1499,14 +1587,19 @@ launch_test_addresses(int fd, short event, void *args)
* be an exit server.*/
if (!options->ServerDNSTestAddresses)
return;
- SMARTLIST_FOREACH(options->ServerDNSTestAddresses, const char *, address,
- {
- int r = evdns_resolve_ipv4(address, DNS_QUERY_NO_SEARCH, evdns_callback,
- tor_strdup(address));
- if (r)
- log_info(LD_EXIT, "eventdns rejected test address %s: error %d",
- escaped_safe_str(address), r);
- });
+ tor_assert(the_evdns_base);
+ SMARTLIST_FOREACH_BEGIN(options->ServerDNSTestAddresses,
+ const char *, address) {
+ char *a = tor_strdup(address);
+ req = evdns_base_resolve_ipv4(the_evdns_base,
+ address, DNS_QUERY_NO_SEARCH, evdns_callback, a);
+
+ if (!req) {
+ log_info(LD_EXIT, "eventdns rejected test address %s",
+ escaped_safe_str(address));
+ tor_free(a);
+ }
+ } SMARTLIST_FOREACH_END(address);
}
#define N_WILDCARD_CHECKS 2
@@ -1547,7 +1640,7 @@ dns_launch_wildcard_checks(void)
void
dns_launch_correctness_checks(void)
{
- static struct event launch_event;
+ static struct event *launch_event = NULL;
struct timeval timeout;
if (!get_options()->ServerDNSDetectHijacking)
return;
@@ -1555,10 +1648,12 @@ dns_launch_correctness_checks(void)
/* 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);
+ if (! launch_event)
+ launch_event = tor_evtimer_new(tor_libevent_get_base(),
+ launch_test_addresses, NULL);
timeout.tv_sec = 30;
timeout.tv_usec = 0;
- if (evtimer_add(&launch_event, &timeout)<0) {
+ if (evtimer_add(launch_event, &timeout)<0) {
log_warn(LD_BUG, "Couldn't add timer for checking for dns hijacking");
}
}
@@ -1574,10 +1669,9 @@ dns_seems_to_be_broken(void)
void
dns_reset_correctness_checks(void)
{
- if (dns_wildcard_response_count) {
- strmap_free(dns_wildcard_response_count, _tor_free);
- dns_wildcard_response_count = NULL;
- }
+ strmap_free(dns_wildcard_response_count, _tor_free);
+ dns_wildcard_response_count = NULL;
+
n_wildcard_requests = 0;
if (dns_wildcard_list) {
@@ -1622,6 +1716,30 @@ assert_resolve_ok(cached_resolve_t *resolve)
}
}
+/** Return the number of DNS cache entries as an int */
+static int
+dns_cache_entry_count(void)
+{
+ return HT_SIZE(&cache_root);
+}
+
+/** Log memory information about our internal DNS cache at level 'severity'. */
+void
+dump_dns_mem_usage(int severity)
+{
+ /* This should never be larger than INT_MAX. */
+ int hash_count = dns_cache_entry_count();
+ size_t hash_mem = sizeof(struct cached_resolve_t) * hash_count;
+ hash_mem += HT_MEM_USAGE(&cache_root);
+
+ /* Print out the count and estimated size of our &cache_root. It undercounts
+ hostnames in cached reverse resolves.
+ */
+ log(severity, LD_MM, "Our DNS cache has %d entries.", hash_count);
+ log(severity, LD_MM, "Our DNS cache size is approximately %u bytes.",
+ (unsigned)hash_mem);
+}
+
#ifdef DEBUG_DNS_CACHE
/** Exit with an assertion if the DNS cache is corrupt. */
static void
@@ -1642,7 +1760,8 @@ _assert_cache_ok(void)
return;
smartlist_pqueue_assert_ok(cached_resolve_pqueue,
- _compare_cached_resolves_by_expiry);
+ _compare_cached_resolves_by_expiry,
+ STRUCT_OFFSET(cached_resolve_t, minheap_idx));
SMARTLIST_FOREACH(cached_resolve_pqueue, cached_resolve_t *, res,
{