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.c99
1 files changed, 61 insertions, 38 deletions
diff --git a/src/or/dns.c b/src/or/dns.c
index 9b6b98afa..78893bfbe 100644
--- a/src/or/dns.c
+++ b/src/or/dns.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2011, The Tor Project, Inc. */
+ * Copyright (c) 2007-2012, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -168,7 +168,8 @@ static void add_wildcarded_test_address(const char *address);
static int configure_nameservers(int force);
static int answer_is_wildcarded(const char *ip);
static int dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
- or_circuit_t *oncirc, char **resolved_to_hostname);
+ or_circuit_t *oncirc, char **resolved_to_hostname,
+ int *made_connection_pending_out);
#ifdef DEBUG_DNS_CACHE
static void _assert_cache_ok(void);
#define assert_cache_ok() _assert_cache_ok()
@@ -276,7 +277,7 @@ dns_init(void)
int
dns_reset(void)
{
- or_options_t *options = get_options();
+ const or_options_t *options = get_options();
if (! server_mode(options)) {
if (!the_evdns_base) {
@@ -376,7 +377,7 @@ set_expiry(cached_resolve_t *resolve, time_t expires)
{
tor_assert(resolve && resolve->expire == 0);
if (!cached_resolve_pqueue)
- cached_resolve_pqueue = smartlist_create();
+ cached_resolve_pqueue = smartlist_new();
resolve->expire = expires;
smartlist_pqueue_add(cached_resolve_pqueue,
_compare_cached_resolves_by_expiry,
@@ -449,16 +450,17 @@ purge_expired_resolves(time_t now)
if (resolve->pending_connections) {
log_debug(LD_EXIT,
"Closing pending connections on timed-out DNS resolve!");
- tor_fragile_assert();
while (resolve->pending_connections) {
pend = resolve->pending_connections;
resolve->pending_connections = pend->next;
/* Connections should only be pending if they have no socket. */
- tor_assert(pend->conn->_base.s == -1);
+ tor_assert(!SOCKET_OK(pend->conn->_base.s));
pendconn = pend->conn;
- connection_edge_end(pendconn, END_STREAM_REASON_TIMEOUT);
- circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
- connection_free(TO_CONN(pendconn));
+ if (!pendconn->_base.marked_for_close) {
+ connection_edge_end(pendconn, END_STREAM_REASON_TIMEOUT);
+ circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
+ connection_free(TO_CONN(pendconn));
+ }
tor_free(pend);
}
}
@@ -567,7 +569,7 @@ send_resolved_hostname_cell(edge_connection_t *conn, const char *hostname)
// log_notice(LD_EXIT, "Sent");
}
-/** See if we have a cache entry for <b>exitconn</b>-\>address. if so,
+/** See if we have a cache entry for <b>exitconn</b>-\>address. If so,
* if resolve valid, put it into <b>exitconn</b>-\>addr and return 1.
* If resolve failed, free exitconn and return -1.
*
@@ -596,10 +598,12 @@ dns_resolve(edge_connection_t *exitconn)
{
or_circuit_t *oncirc = TO_OR_CIRCUIT(exitconn->on_circuit);
int is_resolve, r;
+ int made_connection_pending = 0;
char *hostname = NULL;
is_resolve = exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE;
- r = dns_resolve_impl(exitconn, is_resolve, oncirc, &hostname);
+ r = dns_resolve_impl(exitconn, is_resolve, oncirc, &hostname,
+ &made_connection_pending);
switch (r) {
case 1:
@@ -639,16 +643,11 @@ dns_resolve(edge_connection_t *exitconn)
dns_cancel_pending_resolve(exitconn->_base.address);
- if (!exitconn->_base.marked_for_close) {
+ if (!made_connection_pending && !exitconn->_base.marked_for_close) {
+ /* If we made the connection pending, then we freed it already in
+ * dns_cancel_pending_resolve(). If we marked it for close, it'll
+ * get freed from the main loop. Otherwise, can free it now. */
connection_free(TO_CONN(exitconn));
- // XXX ... and we just leak exitconn otherwise? -RD
- // If it's marked for close, it's on closeable_connection_lst in
- // main.c. If it's on the closeable list, it will get freed from
- // main.c. -NM
- // "<armadev> If that's true, there are other bugs around, where we
- // don't check if it's marked, and will end up double-freeing."
- // On the other hand, I don't know of any actual bugs here, so this
- // shouldn't be holding up the rc. -RD
}
break;
default:
@@ -667,27 +666,33 @@ dns_resolve(edge_connection_t *exitconn)
* Return -2 on a transient error. If it's a reverse resolve and it's
* successful, sets *<b>hostname_out</b> to a newly allocated string
* holding the cached reverse DNS value.
+ *
+ * Set *<b>made_connection_pending_out</b> to true if we have placed
+ * <b>exitconn</b> on the list of pending connections for some resolve; set it
+ * to false otherwise.
*/
static int
dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
- or_circuit_t *oncirc, char **hostname_out)
+ or_circuit_t *oncirc, char **hostname_out,
+ int *made_connection_pending_out)
{
cached_resolve_t *resolve;
cached_resolve_t search;
pending_connection_t *pending_connection;
- routerinfo_t *me;
+ const routerinfo_t *me;
tor_addr_t addr;
time_t now = time(NULL);
uint8_t is_reverse = 0;
int r;
assert_connection_ok(TO_CONN(exitconn), 0);
- tor_assert(exitconn->_base.s == -1);
+ tor_assert(!SOCKET_OK(exitconn->_base.s));
assert_cache_ok();
tor_assert(oncirc);
+ *made_connection_pending_out = 0;
/* first check if exitconn->_base.address is an IP. If so, we already
* know the answer. */
- if (tor_addr_from_str(&addr, exitconn->_base.address) >= 0) {
+ if (tor_addr_parse(&addr, exitconn->_base.address) >= 0) {
if (tor_addr_family(&addr) == AF_INET) {
tor_addr_copy(&exitconn->_base.addr, &addr);
exitconn->address_ttl = DEFAULT_DNS_TTL;
@@ -721,7 +726,7 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
* .in-addr.arpa address but this isn't a resolve request, kill the
* connection.
*/
- if ((r = tor_addr_parse_reverse_lookup_name(&addr, exitconn->_base.address,
+ if ((r = tor_addr_parse_PTR_name(&addr, exitconn->_base.address,
AF_UNSPEC, 0)) != 0) {
if (r == 1) {
is_reverse = 1;
@@ -757,6 +762,7 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
pending_connection->conn = exitconn;
pending_connection->next = resolve->pending_connections;
resolve->pending_connections = pending_connection;
+ *made_connection_pending_out = 1;
log_debug(LD_EXIT,"Connection (fd %d) waiting for pending DNS "
"resolve of %s", exitconn->_base.s,
escaped_safe_str(exitconn->_base.address));
@@ -797,6 +803,7 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
pending_connection = tor_malloc_zero(sizeof(pending_connection_t));
pending_connection->conn = exitconn;
resolve->pending_connections = pending_connection;
+ *made_connection_pending_out = 1;
/* Add this resolve to the cache and priority queue. */
HT_INSERT(cache_map, &cache_root, resolve);
@@ -849,7 +856,7 @@ assert_all_pending_dns_resolves_ok(void)
pend;
pend = pend->next) {
assert_connection_ok(TO_CONN(pend->conn), 0);
- tor_assert(pend->conn->_base.s == -1);
+ tor_assert(!SOCKET_OK(pend->conn->_base.s));
tor_assert(!connection_in_array(TO_CONN(pend->conn)));
}
}
@@ -955,7 +962,7 @@ dns_cancel_pending_resolve(const char *address)
pend->conn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
pendconn = pend->conn;
assert_connection_ok(TO_CONN(pendconn), 0);
- tor_assert(pendconn->_base.s == -1);
+ tor_assert(!SOCKET_OK(pendconn->_base.s));
if (!pendconn->_base.marked_for_close) {
connection_edge_end(pendconn, END_STREAM_REASON_RESOLVEFAILED);
}
@@ -1026,7 +1033,7 @@ add_answer_to_cache(const char *address, uint8_t is_reverse, uint32_t addr,
static INLINE int
is_test_address(const char *address)
{
- or_options_t *options = get_options();
+ const or_options_t *options = get_options();
return options->ServerDNSTestAddresses &&
smartlist_string_isin_case(options->ServerDNSTestAddresses, address);
}
@@ -1085,6 +1092,13 @@ dns_found_answer(const char *address, uint8_t is_reverse, uint32_t addr,
pendconn = pend->conn; /* don't pass complex things to the
connection_mark_for_close macro */
assert_connection_ok(TO_CONN(pendconn),time(NULL));
+ if (pendconn->_base.marked_for_close) {
+ /* prevent double-remove. */
+ pendconn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
+ resolve->pending_connections = pend->next;
+ tor_free(pend);
+ continue;
+ }
tor_addr_from_ipv4h(&pendconn->_base.addr, addr);
pendconn->address_ttl = ttl;
@@ -1177,13 +1191,13 @@ evdns_err_is_transient(int err)
static int
configure_nameservers(int force)
{
- or_options_t *options;
+ const or_options_t *options;
const char *conf_fname;
struct stat st;
int r;
options = get_options();
conf_fname = options->ServerDNSResolvConfFile;
-#ifndef MS_WINDOWS
+#ifndef _WIN32
if (!conf_fname)
conf_fname = "/etc/resolv.conf";
#endif
@@ -1198,7 +1212,7 @@ configure_nameservers(int force)
#ifdef HAVE_EVDNS_SET_DEFAULT_OUTGOING_BIND_ADDRESS
if (options->OutboundBindAddress) {
tor_addr_t addr;
- if (tor_addr_from_str(&addr, options->OutboundBindAddress) < 0) {
+ if (tor_addr_parse(&addr, options->OutboundBindAddress) < 0) {
log_warn(LD_CONFIG,"Outbound bind address '%s' didn't parse. Ignoring.",
options->OutboundBindAddress);
} else {
@@ -1251,7 +1265,7 @@ configure_nameservers(int force)
if (nameservers_configured)
evdns_base_resume(the_evdns_base);
}
-#ifdef MS_WINDOWS
+#ifdef _WIN32
else {
if (nameservers_configured) {
evdns_base_search_clear(the_evdns_base);
@@ -1389,12 +1403,16 @@ evdns_callback(int result, char type, int count, int ttl, void *addresses,
static int
launch_resolve(edge_connection_t *exitconn)
{
- char *addr = tor_strdup(exitconn->_base.address);
+ char *addr;
struct evdns_request *req = NULL;
tor_addr_t a;
int r;
int options = get_options()->ServerDNSSearchDomains ? 0
: DNS_QUERY_NO_SEARCH;
+
+ if (get_options()->DisableNetwork)
+ return -1;
+
/* What? Nameservers not configured? Sounds like a bug. */
if (!nameservers_configured) {
log_warn(LD_EXIT, "(Harmless.) Nameservers not configured, but resolve "
@@ -1404,7 +1422,9 @@ launch_resolve(edge_connection_t *exitconn)
}
}
- r = tor_addr_parse_reverse_lookup_name(
+ addr = tor_strdup(exitconn->_base.address);
+
+ r = tor_addr_parse_PTR_name(
&a, exitconn->_base.address, AF_UNSPEC, 0);
tor_assert(the_evdns_base);
@@ -1431,7 +1451,7 @@ launch_resolve(edge_connection_t *exitconn)
r = 0;
if (!req) {
- log_warn(LD_EXIT, "eventdns rejected address %s.",
+ log_fn(LOG_PROTOCOL_WARN, LD_EXIT, "eventdns rejected address %s.",
escaped_safe_str(addr));
r = -1;
tor_free(addr); /* There is no evdns request in progress; stop
@@ -1485,7 +1505,7 @@ wildcard_increment_answer(const char *id)
++*ip;
if (*ip > 5 && n_wildcard_requests > 10) {
- if (!dns_wildcard_list) dns_wildcard_list = smartlist_create();
+ if (!dns_wildcard_list) dns_wildcard_list = smartlist_new();
if (!smartlist_string_isin(dns_wildcard_list, id)) {
log(dns_wildcard_notice_given ? LOG_INFO : LOG_NOTICE, LD_EXIT,
"Your DNS provider has given \"%s\" as an answer for %d different "
@@ -1507,7 +1527,7 @@ add_wildcarded_test_address(const char *address)
{
int n, n_test_addrs;
if (!dns_wildcarded_test_address_list)
- dns_wildcarded_test_address_list = smartlist_create();
+ dns_wildcarded_test_address_list = smartlist_new();
if (smartlist_string_isin_case(dns_wildcarded_test_address_list, address))
return;
@@ -1595,12 +1615,15 @@ launch_wildcard_check(int min_len, int max_len, const char *suffix)
static void
launch_test_addresses(int fd, short event, void *args)
{
- or_options_t *options = get_options();
+ const or_options_t *options = get_options();
struct evdns_request *req;
(void)fd;
(void)event;
(void)args;
+ if (options->DisableNetwork)
+ return;
+
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