Back to index

tor  0.2.3.18-rc
Classes | Defines | Typedefs | Functions | Variables
dns.c File Reference

Implements a local cache for DNS results for Tor servers. More...

#include "or.h"
#include "circuitlist.h"
#include "circuituse.h"
#include "config.h"
#include "connection.h"
#include "connection_edge.h"
#include "control.h"
#include "dns.h"
#include "main.h"
#include "policies.h"
#include "relay.h"
#include "router.h"
#include "ht.h"
#include <event.h>
#include "eventdns.h"

Go to the source code of this file.

Classes

struct  pending_connection_t
 Linked list of connections waiting for a DNS answer. More...
struct  cached_resolve_t
 A DNS request: possibly completed, possibly pending; cached_resolve structs are stored at the OR side in a hash table, and as a linked list from oldest to newest. More...

Defines

#define HAVE_EVDNS_SET_DEFAULT_OUTGOING_BIND_ADDRESS
#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)
#define evdns_base_resolve_reverse(base, addr, options, cb, ptr)
#define evdns_base_resolve_reverse_ipv6(base, addr, options, cb, ptr)
#define MAX_ADDRESSLEN   256
 Longest hostname we're willing to resolve.
#define RESOLVE_MAX_TIMEOUT   300
 How long will we wait for an answer from the resolver before we decide that the resolver is wedged?
#define DNS_RESOLVE_FAILED_TRANSIENT   1
 Possible outcomes from hostname lookup: permanent failure, transient (retryable) failure, and success.
#define DNS_RESOLVE_FAILED_PERMANENT   2
#define DNS_RESOLVE_SUCCEEDED   3
#define CACHED_RESOLVE_MAGIC   0x1234F00D
 Value of 'magic' field for cached_resolve_t.
#define CACHE_STATE_PENDING   0
 We are waiting for the resolver system to tell us an answer here.
#define CACHE_STATE_DONE   1
 This used to be a pending cached_resolve_t, and we got an answer for it.
#define CACHE_STATE_CACHED_VALID   2
 We are caching an answer for this address.
#define CACHE_STATE_CACHED_FAILED   3
 We are caching a failure for this address.
#define assert_cache_ok()   STMT_NIL
#define SET(k, v)   evdns_base_set_option_(the_evdns_base, (k), (v))
#define N_WILDCARD_CHECKS   2

Typedefs

typedef struct pending_connection_t pending_connection_t
 Linked list of connections waiting for a DNS answer.
typedef struct cached_resolve_t cached_resolve_t
 A DNS request: possibly completed, possibly pending; cached_resolve structs are stored at the OR side in a hash table, and as a linked list from oldest to newest.

Functions

static void purge_expired_resolves (time_t now)
 Remove every cached_resolve whose expire time is before or equal to now from the cache.
static void dns_found_answer (const char *address, uint8_t is_reverse, uint32_t addr, const char *hostname, char outcome, uint32_t ttl)
 Called on the OR side when a DNS worker or the eventdns library tells us the outcome of a DNS resolve: tell all pending connections about the result of the lookup, and cache the value.
static void send_resolved_cell (edge_connection_t *conn, uint8_t answer_type)
 Send a response to the RESOLVE request of a connection.
static int launch_resolve (edge_connection_t *exitconn)
 For eventdns: start resolving as necessary to find the target for exitconn.
static void add_wildcarded_test_address (const char *address)
 Note that a single test address (one believed to be good) seems to be getting redirected to the same IP as failures are.
static int configure_nameservers (int force)
 Configure eventdns nameservers if force is true, or if the configuration has changed since the last time we called this function, or if we failed on our last attempt.
static int answer_is_wildcarded (const char *ip)
 Return true iff we have noticed that the dotted-quad ip has been returned in response to requests for nonexistent hostnames.
static int dns_resolve_impl (edge_connection_t *exitconn, int is_resolve, or_circuit_t *oncirc, char **hostname_out)
 Helper function for dns_resolve: same functionality, but does not handle:
static void assert_resolve_ok (cached_resolve_t *resolve)
 Exit with an assertion if resolve is corrupt.
static HT_HEAD (cache_map, cached_resolve_t)
 Hash table of cached_resolve objects.
static INLINE unsigned int cached_resolve_hash (cached_resolve_t *a)
 Hash function for cached_resolve objects.
 HT_PROTOTYPE (HT_GENERATE(cache_map, HT_GENERATE(cached_resolve_t, HT_GENERATE(node, HT_GENERATE(cached_resolve_hash, HT_GENERATE(cached_resolves_eq)
 Initialize the DNS cache.
static void evdns_log_cb (int warn, const char *msg)
 Helper: called by eventdns when eventdns wants to log something.
static void _dns_randfn (char *b, size_t n)
 Helper: passed to eventdns.c as a callback so it can generate random numbers for transaction IDs and 0x20-hack coding.
int dns_init (void)
 Initialize the DNS subsystem; called by the OR process.
int dns_reset (void)
 Called when DNS-related options change (or may have changed).
int has_dns_init_failed (void)
 Return true iff the most recent attempt to initialize the DNS subsystem failed.
uint32_t dns_clip_ttl (uint32_t ttl)
 Helper: Given a TTL from a DNS response, determine what TTL to give the OP that asked us to resolve it.
static uint32_t dns_get_expiry_ttl (uint32_t ttl)
 Helper: Given a TTL from a DNS response, determine how long to hold it in our cache.
static void _free_cached_resolve (cached_resolve_t *r)
 Helper: free storage held by an entry in the DNS cache.
static int _compare_cached_resolves_by_expiry (const void *_a, const void *_b)
 Compare two cached_resolve_t pointers by expiry time, and return less-than-zero, zero, or greater-than-zero as appropriate.
static void set_expiry (cached_resolve_t *resolve, time_t expires)
 Set an expiry time for a cached_resolve_t, and add it to the expiry priority queue.
void dns_free_all (void)
 Free all storage held in the DNS cache and related structures.
static void send_resolved_hostname_cell (edge_connection_t *conn, const char *hostname)
 Send a response to the RESOLVE request of a connection for an in-addr.arpa address on connection conn which yielded the result hostname.
int dns_resolve (edge_connection_t *exitconn)
 See if we have a cache entry for exitconn->address.
void assert_connection_edge_not_dns_pending (edge_connection_t *conn)
 Log an error and abort if conn is waiting for a DNS resolve.
void assert_all_pending_dns_resolves_ok (void)
 Log an error and abort if any connection waiting for a DNS resolve is corrupted.
void connection_dns_remove (edge_connection_t *conn)
 Remove conn from the list of connections waiting for conn->address.
void dns_cancel_pending_resolve (const char *address)
 Mark all connections waiting for address for close.
static void add_answer_to_cache (const char *address, uint8_t is_reverse, uint32_t addr, const char *hostname, char outcome, uint32_t ttl)
 Helper: adds an entry to the DNS cache mapping address to the ipv4 address addr (if is_reverse is 0) or the hostname hostname (if is_reverse is 1).
static INLINE int is_test_address (const char *address)
 Return true iff address is one of the addresses we use to verify that well-known sites aren't being hijacked by our DNS servers.
static int evdns_err_is_transient (int err)
 Eventdns helper: return true iff the eventdns result err is a transient failure.
static void evdns_callback (int result, char type, int count, int ttl, void *addresses, void *arg)
 For eventdns: Called when we get an answer for a request we launched.
static void wildcard_increment_answer (const char *id)
 Called when we see id (a dotted quad) in response to a request for a hopefully bogus address.
static void evdns_wildcard_check_callback (int result, char type, int count, int ttl, void *addresses, void *arg)
 Callback function when we get an answer (possibly failing) for a request for a (hopefully) nonexistent domain.
static void launch_wildcard_check (int min_len, int max_len, const char *suffix)
 Launch a single request for a nonexistent hostname consisting of between min_len and max_len random (plausible) characters followed by suffix
static void launch_test_addresses (int fd, short event, void *args)
 Launch attempts to resolve a bunch of known-good addresses (configured in ServerDNSTestAddresses).
static void dns_launch_wildcard_checks (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.
void dns_launch_correctness_checks (void)
 If appropriate, start testing whether our DNS servers tend to lie to us.
int dns_seems_to_be_broken (void)
 Return true iff our DNS servers lie to us too much to be trusted.
void dns_reset_correctness_checks (void)
 Forget what we've previously learned about our DNS servers' correctness.
static int dns_cache_entry_count (void)
 Return the number of DNS cache entries as an int.
void dump_dns_mem_usage (int severity)
 Log memory information about our internal DNS cache at level 'severity'.

Variables

static struct evdns_base * the_evdns_base = NULL
 Our evdns_base; this structure handles all our name lookups.
static int nameservers_configured = 0
 Have we currently configured nameservers with eventdns?
static int nameserver_config_failed = 0
 Did our most recent attempt to configure nameservers with eventdns fail?
static char * resolv_conf_fname = NULL
 What was the resolv_conf fname we last used when configuring the nameservers? Used to check whether we need to reconfigure.
static time_t resolv_conf_mtime = 0
 What was the mtime on the resolv.conf file we last used when configuring the nameservers? Used to check whether we need to reconfigure.
static smartlist_tcached_resolve_pqueue = NULL
 Priority queue of cached_resolve_t objects to let us know when they will expire.
static int n_wildcard_requests = 0
 How many requests for bogus addresses have we launched so far?
static strmap_t * dns_wildcard_response_count = NULL
 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.
static smartlist_tdns_wildcard_list = 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 int dns_wildcard_one_notice_given = 0
 True iff we've logged about a single address getting wildcarded.
static int dns_wildcard_notice_given = 0
 True iff we've warned that our DNS server is wildcarding too many failures.
static smartlist_tdns_wildcarded_test_address_list = NULL
 List of supposedly good addresses that are getting wildcarded to the same addresses as nonexistent addresses.
static int dns_wildcarded_test_address_notice_given = 0
 True iff we've warned about a test address getting wildcarded.
static int dns_is_completely_invalid = 0
 True iff all addresses seem to be getting wildcarded.

Detailed Description

Implements a local cache for DNS results for Tor servers.

This is implemented as a wrapper around Adam Langley's eventdns.c code. (We can't just use gethostbyname() and friends because we really need to be nonblocking.)

Definition in file dns.c.


Class Documentation

struct pending_connection_t

Linked list of connections waiting for a DNS answer.

Definition at line 108 of file dns.c.

Collaboration diagram for pending_connection_t:
Class Members
edge_connection_t * conn
struct pending_connection_t * next

Define Documentation

#define assert_cache_ok ( )    STMT_NIL

Definition at line 176 of file dns.c.

#define CACHE_STATE_CACHED_FAILED   3

We are caching a failure for this address.

This should have no pending connections, and should appear in the hash table

Definition at line 134 of file dns.c.

#define CACHE_STATE_CACHED_VALID   2

We are caching an answer for this address.

This should have no pending connections, and should appear in the hash table.

Definition at line 131 of file dns.c.

#define CACHE_STATE_DONE   1

This used to be a pending cached_resolve_t, and we got an answer for it.

Now we're waiting for this cached_resolve_t to expire. This should have no pending connections, and should not appear in the hash table.

Definition at line 128 of file dns.c.

#define CACHE_STATE_PENDING   0

We are waiting for the resolver system to tell us an answer here.

When we get one, or when we time out, the state of this cached_resolve_t will become "DONE" and we'll possibly add a CACHED_VALID or a CACHED_FAILED entry. This cached_resolve_t will be in the hash table so that we will know not to launch more requests for this addr, but rather to add more connections to the pending list for the addr.

Definition at line 124 of file dns.c.

#define CACHED_RESOLVE_MAGIC   0x1234F00D

Value of 'magic' field for cached_resolve_t.

Used to try to catch bad pointers and memory stomping.

Definition at line 115 of file dns.c.

Definition at line 90 of file dns.c.

Possible outcomes from hostname lookup: permanent failure, transient (retryable) failure, and success.

Definition at line 89 of file dns.c.

#define DNS_RESOLVE_SUCCEEDED   3

Definition at line 91 of file dns.c.

Definition at line 42 of file dns.c.

#define evdns_base_config_windows_nameservers (   base)    evdns_config_windows_nameservers()

Definition at line 53 of file dns.c.

Definition at line 49 of file dns.c.

#define evdns_base_new (   x,
 
)    tor_malloc(1)

Definition at line 41 of file dns.c.

#define evdns_base_resolv_conf_parse (   base,
  options,
  fname 
)    evdns_resolv_conf_parse((options), (fname))

Definition at line 47 of file dns.c.

#define evdns_base_resolve_ipv4 (   base,
  addr,
  options,
  cb,
  ptr 
)
Value:
((evdns_resolve_ipv4((addr), (options), (cb), (ptr))!=0)    \
   ? NULL : ((void*)1))

Definition at line 61 of file dns.c.

#define evdns_base_resolve_reverse (   base,
  addr,
  options,
  cb,
  ptr 
)
Value:
((evdns_resolve_reverse((addr), (options), (cb), (ptr))!=0)           \
   ? NULL : ((void*)1))

Definition at line 64 of file dns.c.

#define evdns_base_resolve_reverse_ipv6 (   base,
  addr,
  options,
  cb,
  ptr 
)
Value:
((evdns_resolve_reverse_ipv6((addr), (options), (cb), (ptr))!=0)      \
   ? NULL : ((void*)1))

Definition at line 67 of file dns.c.

#define evdns_base_resume (   base)    evdns_resume()

Definition at line 51 of file dns.c.

#define evdns_base_search_clear (   base)    evdns_search_clear()

Definition at line 44 of file dns.c.

#define evdns_base_set_default_outgoing_bind_address (   base,
  a,
  len 
)    evdns_set_default_outgoing_bind_address((a),(len))

Definition at line 45 of file dns.c.

#define evdns_base_set_option_ (   base,
  opt,
  val 
)    evdns_set_option((opt),(val),DNS_OPTIONS_ALL)

Definition at line 55 of file dns.c.

Definition at line 34 of file dns.c.

#define MAX_ADDRESSLEN   256

Longest hostname we're willing to resolve.

Definition at line 81 of file dns.c.

#define N_WILDCARD_CHECKS   2

Definition at line 1635 of file dns.c.

#define RESOLVE_MAX_TIMEOUT   300

How long will we wait for an answer from the resolver before we decide that the resolver is wedged?

Definition at line 85 of file dns.c.

#define SET (   k,
 
)    evdns_base_set_option_(the_evdns_base, (k), (v))

Typedef Documentation

A DNS request: possibly completed, possibly pending; cached_resolve structs are stored at the OR side in a hash table, and as a linked list from oldest to newest.

Linked list of connections waiting for a DNS answer.


Function Documentation

static int _compare_cached_resolves_by_expiry ( const void *  _a,
const void *  _b 
) [static]

Compare two cached_resolve_t pointers by expiry time, and return less-than-zero, zero, or greater-than-zero as appropriate.

Used for the priority queue implementation.

Definition at line 357 of file dns.c.

{
  const cached_resolve_t *a = _a, *b = _b;
  if (a->expire < b->expire)
    return -1;
  else if (a->expire == b->expire)
    return 0;
  else
    return 1;
}

Here is the caller graph for this function:

static void _dns_randfn ( char *  b,
size_t  n 
) [static]

Helper: passed to eventdns.c as a callback so it can generate random numbers for transaction IDs and 0x20-hack coding.

Definition at line 256 of file dns.c.

{
  crypto_rand(b,n);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void _free_cached_resolve ( cached_resolve_t r) [static]

Helper: free storage held by an entry in the DNS cache.

Definition at line 338 of file dns.c.

{
  if (!r)
    return;
  while (r->pending_connections) {
    pending_connection_t *victim = r->pending_connections;
    r->pending_connections = victim->next;
    tor_free(victim);
  }
  if (r->is_reverse)
    tor_free(r->result.hostname);
  r->magic = 0xFF00FF00;
  tor_free(r);
}

Here is the caller graph for this function:

static void add_answer_to_cache ( const char *  address,
uint8_t  is_reverse,
uint32_t  addr,
const char *  hostname,
char  outcome,
uint32_t  ttl 
) [static]

Helper: adds an entry to the DNS cache mapping address to the ipv4 address addr (if is_reverse is 0) or the hostname hostname (if is_reverse is 1).

ttl is a cache ttl; outcome is one of DNS_RESOLVE_{FAILED_TRANSIENT|FAILED_PERMANENT|SUCCEEDED}.

Definition at line 989 of file dns.c.

{
  cached_resolve_t *resolve;
  if (outcome == DNS_RESOLVE_FAILED_TRANSIENT)
    return;

  //log_notice(LD_EXIT, "Adding to cache: %s -> %s (%lx, %s), %d",
  //           address, is_reverse?"(reverse)":"", (unsigned long)addr,
  //           hostname?hostname:"NULL",(int)outcome);

  resolve = tor_malloc_zero(sizeof(cached_resolve_t));
  resolve->magic = CACHED_RESOLVE_MAGIC;
  resolve->state = (outcome == DNS_RESOLVE_SUCCEEDED) ?
    CACHE_STATE_CACHED_VALID : CACHE_STATE_CACHED_FAILED;
  strlcpy(resolve->address, address, sizeof(resolve->address));
  resolve->is_reverse = is_reverse;
  if (is_reverse) {
    if (outcome == DNS_RESOLVE_SUCCEEDED) {
      tor_assert(hostname);
      resolve->result.hostname = tor_strdup(hostname);
    } else {
      tor_assert(! hostname);
      resolve->result.hostname = NULL;
    }
  } else {
    tor_assert(!hostname);
    resolve->result.a.addr = addr;
  }
  resolve->ttl = ttl;
  assert_resolve_ok(resolve);
  HT_INSERT(cache_map, &cache_root, resolve);
  set_expiry(resolve, time(NULL) + dns_get_expiry_ttl(ttl));
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void add_wildcarded_test_address ( const char *  address) [static]

Note that a single test address (one believed to be good) seems to be getting redirected to the same IP as failures are.

Definition at line 1512 of file dns.c.

{
  int n, n_test_addrs;
  if (!dns_wildcarded_test_address_list)
    dns_wildcarded_test_address_list = smartlist_new();

  if (smartlist_string_isin_case(dns_wildcarded_test_address_list, address))
    return;

  n_test_addrs = get_options()->ServerDNSTestAddresses ?
    smartlist_len(get_options()->ServerDNSTestAddresses) : 0;

  smartlist_add(dns_wildcarded_test_address_list, tor_strdup(address));
  n = smartlist_len(dns_wildcarded_test_address_list);
  if (n > n_test_addrs/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 hijacking confirmed");
    }
    if (!dns_wildcarded_test_address_notice_given)
      control_event_server_status(LOG_WARN, "DNS_USELESS");
    dns_wildcarded_test_address_notice_given = 1;
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int answer_is_wildcarded ( const char *  ip) [static]

Return true iff we have noticed that the dotted-quad ip has been returned in response to requests for nonexistent hostnames.

Definition at line 1723 of file dns.c.

Here is the call graph for this function:

Here is the caller graph for this function:

Log an error and abort if any connection waiting for a DNS resolve is corrupted.

Definition at line 842 of file dns.c.

{
  pending_connection_t *pend;
  cached_resolve_t **resolve;

  HT_FOREACH(resolve, cache_map, &cache_root) {
    for (pend = (*resolve)->pending_connections;
         pend;
         pend = pend->next) {
      assert_connection_ok(TO_CONN(pend->conn), 0);
      tor_assert(!SOCKET_OK(pend->conn->_base.s));
      tor_assert(!connection_in_array(TO_CONN(pend->conn)));
    }
  }
}

Here is the call graph for this function:

Log an error and abort if conn is waiting for a DNS resolve.

Definition at line 815 of file dns.c.

{
  pending_connection_t *pend;
  cached_resolve_t search;

#if 1
  cached_resolve_t *resolve;
  strlcpy(search.address, conn->_base.address, sizeof(search.address));
  resolve = HT_FIND(cache_map, &cache_root, &search);
  if (!resolve)
    return;
  for (pend = resolve->pending_connections; pend; pend = pend->next) {
    tor_assert(pend->conn != conn);
  }
#else
  cached_resolve_t **resolve;
  HT_FOREACH(resolve, cache_map, &cache_root) {
    for (pend = (*resolve)->pending_connections; pend; pend = pend->next) {
      tor_assert(pend->conn != conn);
    }
  }
#endif
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void assert_resolve_ok ( cached_resolve_t resolve) [static]

Exit with an assertion if resolve is corrupt.

Definition at line 1730 of file dns.c.

{
  tor_assert(resolve);
  tor_assert(resolve->magic == CACHED_RESOLVE_MAGIC);
  tor_assert(strlen(resolve->address) < MAX_ADDRESSLEN);
  tor_assert(tor_strisnonupper(resolve->address));
  if (resolve->state != CACHE_STATE_PENDING) {
    tor_assert(!resolve->pending_connections);
  }
  if (resolve->state == CACHE_STATE_PENDING ||
      resolve->state == CACHE_STATE_DONE) {
    tor_assert(!resolve->ttl);
    if (resolve->is_reverse)
      tor_assert(!resolve->result.hostname);
    else
      tor_assert(!resolve->result.a.addr);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static INLINE unsigned int cached_resolve_hash ( cached_resolve_t a) [static]

Hash function for cached_resolve objects.

Definition at line 195 of file dns.c.

{
  return ht_string_hash(a->address);
}

Here is the call graph for this function:

static int configure_nameservers ( int  force) [static]

Configure eventdns nameservers if force is true, or if the configuration has changed since the last time we called this function, or if we failed on our last attempt.

On Unix, this reads from /etc/resolv.conf or options->ServerDNSResolvConfFile; on Windows, this reads from options->ServerDNSResolvConfFile or the registry. Return 0 on success or -1 on failure.

Definition at line 1178 of file dns.c.

{
  const or_options_t *options;
  const char *conf_fname;
  struct stat st;
  int r;
  options = get_options();
  conf_fname = options->ServerDNSResolvConfFile;
#ifndef _WIN32
  if (!conf_fname)
    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_parse(&addr, options->OutboundBindAddress) < 0) {
      log_warn(LD_CONFIG,"Outbound bind address '%s' didn't parse. Ignoring.",
               options->OutboundBindAddress);
    } else {
      int socklen;
      struct sockaddr_storage ss;
      socklen = tor_addr_to_sockaddr(&addr, 0,
                                     (struct sockaddr *)&ss, sizeof(ss));
      if (socklen <= 0) {
        log_warn(LD_BUG, "Couldn't convert outbound bind address to sockaddr."
                 " Ignoring.");
      } else {
        evdns_base_set_default_outgoing_bind_address(the_evdns_base,
                                                     (struct sockaddr *)&ss,
                                                     socklen);
      }
    }
  }
#endif

  evdns_set_log_fn(evdns_log_cb);
  if (conf_fname) {
    if (stat(conf_fname, &st)) {
      log_warn(LD_EXIT, "Unable to stat resolver configuration in '%s': %s",
               conf_fname, strerror(errno));
      goto err;
    }
    if (!force && resolv_conf_fname && !strcmp(conf_fname,resolv_conf_fname)
        && st.st_mtime == resolv_conf_mtime) {
      log_info(LD_EXIT, "No change to '%s'", conf_fname);
      return 0;
    }
    if (nameservers_configured) {
      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_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_base_count_nameservers(the_evdns_base) == 0) {
      log_warn(LD_EXIT, "Unable to find any nameservers in '%s'.", conf_fname);
      goto err;
    }
    tor_free(resolv_conf_fname);
    resolv_conf_fname = tor_strdup(conf_fname);
    resolv_conf_mtime = st.st_mtime;
    if (nameservers_configured)
      evdns_base_resume(the_evdns_base);
  }
#ifdef _WIN32
  else {
    if (nameservers_configured) {
      evdns_base_search_clear(the_evdns_base);
      evdns_base_clear_nameservers_and_suspend(the_evdns_base);
    }
    if (evdns_base_config_windows_nameservers(the_evdns_base))  {
      log_warn(LD_EXIT,"Could not config nameservers.");
      goto err;
    }
    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_base_resume(the_evdns_base);
    tor_free(resolv_conf_fname);
    resolv_conf_mtime = 0;
  }
#endif

#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 {
    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;
  if (nameserver_config_failed) {
    nameserver_config_failed = 0;
    /* XXX the three calls to republish the descriptor might be producing
     * descriptors that are only cosmetically different, especially on
     * non-exit relays! -RD */
    mark_my_descriptor_dirty("dns resolvers back");
  }
  return 0;
 err:
  nameservers_configured = 0;
  if (! nameserver_config_failed) {
    nameserver_config_failed = 1;
    mark_my_descriptor_dirty("dns resolvers failed");
  }
  return -1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Remove conn from the list of connections waiting for conn->address.

Definition at line 861 of file dns.c.

{
  pending_connection_t *pend, *victim;
  cached_resolve_t search;
  cached_resolve_t *resolve;

  tor_assert(conn->_base.type == CONN_TYPE_EXIT);
  tor_assert(conn->_base.state == EXIT_CONN_STATE_RESOLVING);

  strlcpy(search.address, conn->_base.address, sizeof(search.address));

  resolve = HT_FIND(cache_map, &cache_root, &search);
  if (!resolve) {
    log_notice(LD_BUG, "Address %s is not pending. Dropping.",
               escaped_safe_str(conn->_base.address));
    return;
  }

  tor_assert(resolve->pending_connections);
  assert_connection_ok(TO_CONN(conn),0);

  pend = resolve->pending_connections;

  if (pend->conn == conn) {
    resolve->pending_connections = pend->next;
    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));
    return;
  } else {
    for ( ; pend->next; pend = pend->next) {
      if (pend->next->conn == conn) {
        victim = pend->next;
        pend->next = victim->next;
        tor_free(victim);
        log_debug(LD_EXIT,
                  "Connection (fd %d) no longer waiting for resolve of %s",
                  conn->_base.s, escaped_safe_str(conn->_base.address));
        return; /* more are pending */
      }
    }
    tor_assert(0); /* not reachable unless onlyconn not in pending list */
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int dns_cache_entry_count ( void  ) [static]

Return the number of DNS cache entries as an int.

Definition at line 1751 of file dns.c.

{
   return HT_SIZE(&cache_root);
}

Here is the caller graph for this function:

void dns_cancel_pending_resolve ( const char *  address)

Mark all connections waiting for address for close.

Then cancel the resolve for address itself, and remove any cached results for address from the cache.

Definition at line 913 of file dns.c.

{
  pending_connection_t *pend;
  cached_resolve_t search;
  cached_resolve_t *resolve, *tmp;
  edge_connection_t *pendconn;
  circuit_t *circ;

  strlcpy(search.address, address, sizeof(search.address));

  resolve = HT_FIND(cache_map, &cache_root, &search);
  if (!resolve)
    return;

  if (resolve->state != CACHE_STATE_PENDING) {
    /* We can get into this state if we never actually created the pending
     * resolve, due to finding an earlier cached error or something.  Just
     * ignore it. */
    if (resolve->pending_connections) {
      log_warn(LD_BUG,
               "Address %s is not pending but has pending connections!",
               escaped_safe_str(address));
      tor_fragile_assert();
    }
    return;
  }

  if (!resolve->pending_connections) {
    log_warn(LD_BUG,
             "Address %s is pending but has no pending connections!",
             escaped_safe_str(address));
    tor_fragile_assert();
    return;
  }
  tor_assert(resolve->pending_connections);

  /* mark all pending connections to fail */
  log_debug(LD_EXIT,
             "Failing all connections waiting on DNS resolve of %s",
             escaped_safe_str(address));
  while (resolve->pending_connections) {
    pend = resolve->pending_connections;
    pend->conn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
    pendconn = pend->conn;
    assert_connection_ok(TO_CONN(pendconn), 0);
    tor_assert(!SOCKET_OK(pendconn->_base.s));
    if (!pendconn->_base.marked_for_close) {
      connection_edge_end(pendconn, END_STREAM_REASON_RESOLVEFAILED);
    }
    circ = circuit_get_by_edge_conn(pendconn);
    if (circ)
      circuit_detach_stream(circ, pendconn);
    if (!pendconn->_base.marked_for_close)
      connection_free(TO_CONN(pendconn));
    resolve->pending_connections = pend->next;
    tor_free(pend);
  }

  tmp = HT_REMOVE(cache_map, &cache_root, resolve);
  if (tmp != resolve) {
    log_err(LD_BUG, "The cancelled resolve we purged didn't match any in"
            " the cache. Tried to purge %s (%p); instead got %s (%p).",
            resolve->address, (void*)resolve,
            tmp ? tmp->address : "NULL", (void*)tmp);
  }
  tor_assert(tmp == resolve);

  resolve->state = CACHE_STATE_DONE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

uint32_t dns_clip_ttl ( uint32_t  ttl)

Helper: Given a TTL from a DNS response, determine what TTL to give the OP that asked us to resolve it.

Definition at line 313 of file dns.c.

{
  if (ttl < MIN_DNS_TTL)
    return MIN_DNS_TTL;
  else if (ttl > MAX_DNS_TTL)
    return MAX_DNS_TTL;
  else
    return ttl;
}

Here is the caller graph for this function:

static void dns_found_answer ( const char *  address,
uint8_t  is_reverse,
uint32_t  addr,
const char *  hostname,
char  outcome,
uint32_t  ttl 
) [static]

Called on the OR side when a DNS worker or the eventdns library tells us the outcome of a DNS resolve: tell all pending connections about the result of the lookup, and cache the value.

(address is a NUL-terminated string containing the address to look up; addr is an IPv4 address in host order; outcome is one of DNS_RESOLVE_{FAILED_TRANSIENT|FAILED_PERMANENT|SUCCEEDED}.

Definition at line 1042 of file dns.c.

{
  pending_connection_t *pend;
  cached_resolve_t search;
  cached_resolve_t *resolve, *removed;
  edge_connection_t *pendconn;
  circuit_t *circ;

  assert_cache_ok();

  strlcpy(search.address, address, sizeof(search.address));

  resolve = HT_FIND(cache_map, &cache_root, &search);
  if (!resolve) {
    int is_test_addr = is_test_address(address);
    if (!is_test_addr)
      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;
  }
  assert_resolve_ok(resolve);

  if (resolve->state != CACHE_STATE_PENDING) {
    /* XXXX Maybe update addr? or check addr for consistency? Or let
     * VALID replace FAILED? */
    int is_test_addr = is_test_address(address);
    if (!is_test_addr)
      log_notice(LD_EXIT,
                 "Resolved %s which was already resolved; ignoring",
                 escaped_safe_str(address));
    tor_assert(resolve->pending_connections == NULL);
    return;
  }
  /* Removed this assertion: in fact, we'll sometimes get a double answer
   * to the same question.  This can happen when we ask one worker to resolve
   * X.Y.Z., then we cancel the request, and then we ask another worker to
   * resolve X.Y.Z. */
  /* tor_assert(resolve->state == CACHE_STATE_PENDING); */

  while (resolve->pending_connections) {
    pend = resolve->pending_connections;
    pendconn = pend->conn; /* don't pass complex things to the
                              connection_mark_for_close macro */
    assert_connection_ok(TO_CONN(pendconn),time(NULL));
    tor_addr_from_ipv4h(&pendconn->_base.addr, addr);
    pendconn->address_ttl = ttl;

    if (outcome != DNS_RESOLVE_SUCCEEDED) {
      /* prevent double-remove. */
      pendconn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
      if (pendconn->_base.purpose == EXIT_PURPOSE_CONNECT) {
        connection_edge_end(pendconn, END_STREAM_REASON_RESOLVEFAILED);
        /* This detach must happen after we send the end cell. */
        circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
      } else {
        send_resolved_cell(pendconn, outcome == DNS_RESOLVE_FAILED_PERMANENT ?
                          RESOLVED_TYPE_ERROR : RESOLVED_TYPE_ERROR_TRANSIENT);
        /* This detach must happen after we send the resolved cell. */
        circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
      }
      connection_free(TO_CONN(pendconn));
    } else {
      if (pendconn->_base.purpose == EXIT_PURPOSE_CONNECT) {
        tor_assert(!is_reverse);
        /* prevent double-remove. */
        pend->conn->_base.state = EXIT_CONN_STATE_CONNECTING;

        circ = circuit_get_by_edge_conn(pend->conn);
        tor_assert(circ);
        tor_assert(!CIRCUIT_IS_ORIGIN(circ));
        /* unlink pend->conn from resolving_streams, */
        circuit_detach_stream(circ, pend->conn);
        /* and link it to n_streams */
        pend->conn->next_stream = TO_OR_CIRCUIT(circ)->n_streams;
        pend->conn->on_circuit = circ;
        TO_OR_CIRCUIT(circ)->n_streams = pend->conn;

        connection_exit_connect(pend->conn);
      } else {
        /* prevent double-remove.  This isn't really an accurate state,
         * but it does the right thing. */
        pendconn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
        if (is_reverse)
          send_resolved_hostname_cell(pendconn, hostname);
        else
          send_resolved_cell(pendconn, RESOLVED_TYPE_IPV4);
        circ = circuit_get_by_edge_conn(pendconn);
        tor_assert(circ);
        circuit_detach_stream(circ, pendconn);
        connection_free(TO_CONN(pendconn));
      }
    }
    resolve->pending_connections = pend->next;
    tor_free(pend);
  }

  resolve->state = CACHE_STATE_DONE;
  removed = HT_REMOVE(cache_map, &cache_root, &search);
  if (removed != resolve) {
    log_err(LD_BUG, "The pending resolve we found wasn't removable from"
            " the cache. Tried to purge %s (%p); instead got %s (%p).",
            resolve->address, (void*)resolve,
            removed ? removed->address : "NULL", (void*)removed);
  }
  assert_resolve_ok(resolve);
  assert_cache_ok();

  add_answer_to_cache(address, is_reverse, addr, hostname, outcome, ttl);
  assert_cache_ok();
}

Here is the call graph for this function:

Here is the caller graph for this function:

void dns_free_all ( void  )

Free all storage held in the DNS cache and related structures.

Definition at line 389 of file dns.c.

{
  cached_resolve_t **ptr, **next, *item;
  assert_cache_ok();
  if (cached_resolve_pqueue) {
    SMARTLIST_FOREACH(cached_resolve_pqueue, cached_resolve_t *, res,
      {
        if (res->state == CACHE_STATE_DONE)
          _free_cached_resolve(res);
      });
  }
  for (ptr = HT_START(cache_map, &cache_root); ptr != NULL; ptr = next) {
    item = *ptr;
    next = HT_NEXT_RMV(cache_map, &cache_root, ptr);
    _free_cached_resolve(item);
  }
  HT_CLEAR(cache_map, &cache_root);
  smartlist_free(cached_resolve_pqueue);
  cached_resolve_pqueue = NULL;
  tor_free(resolv_conf_fname);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static uint32_t dns_get_expiry_ttl ( uint32_t  ttl) [static]

Helper: Given a TTL from a DNS response, determine how long to hold it in our cache.

Definition at line 326 of file dns.c.

{
  if (ttl < MIN_DNS_TTL)
    return MIN_DNS_TTL;
  else if (ttl > MAX_DNS_ENTRY_AGE)
    return MAX_DNS_ENTRY_AGE;
  else
    return ttl;
}

Here is the caller graph for this function:

int dns_init ( void  )

Initialize the DNS subsystem; called by the OR process.

Definition at line 263 of file dns.c.

{
  init_cache_map();
  evdns_set_random_bytes_fn(_dns_randfn);
  if (server_mode(get_options())) {
    int r = configure_nameservers(1);
    return r;
  }
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

If appropriate, start testing whether our DNS servers tend to lie to us.

Definition at line 1671 of file dns.c.

{
  static struct event *launch_event = NULL;
  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. */
  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) {
    log_warn(LD_BUG, "Couldn't add timer for checking for dns hijacking");
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void dns_launch_wildcard_checks ( void  ) [static]

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.

Definition at line 1642 of file dns.c.

{
  int i;
  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.  Sadly, some DNS hijackers, in a silly attempt
     * to 'comply' with rfc2606, refrain from giving A records for these.
     * This is the standards-compliance equivalent of making sure that your
     * crackhouse's elevator inspection certificate is up to date.
     */
    launch_wildcard_check(2, 16, ".invalid");
    launch_wildcard_check(2, 16, ".test");

    /* These 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, ".com");
    launch_wildcard_check(8, 16, ".org");
    launch_wildcard_check(8, 16, ".net");
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

int dns_reset ( void  )

Called when DNS-related options change (or may have changed).

Returns -1 on failure, 0 on success.

Definition at line 277 of file dns.c.

{
  const or_options_t *options = get_options();
  if (! server_mode(options)) {

    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;
  } else {
    if (configure_nameservers(0) < 0) {
      return -1;
    }
  }
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Forget what we've previously learned about our DNS servers' correctness.

Definition at line 1700 of file dns.c.

Here is the call graph for this function:

Here is the caller graph for this function:

int dns_resolve ( edge_connection_t exitconn)

See if we have a cache entry for exitconn->address.

if so, if resolve valid, put it into exitconn->addr and return 1. If resolve failed, free exitconn and return -1.

(For EXIT_PURPOSE_RESOLVE connections, send back a RESOLVED error cell on returning -1. For EXIT_PURPOSE_CONNECT connections, there's no need to send back an END cell, since connection_exit_begin_conn will do that for us.)

If we have a cached answer, send the answer back along exitconn's circuit.

Else, if seen before and pending, add conn to the pending list, and return 0.

Else, if not seen before, add conn to pending list, hand to dns farm, and return 0.

Exitconn's on_circuit field must be set, but exitconn should not yet be linked onto the n_streams/resolving_streams list of that circuit. On success, link the connection to n_streams if it's an exit connection. On "pending", link the connection to resolving streams. Otherwise, clear its on_circuit field.

Definition at line 595 of file dns.c.

{
  or_circuit_t *oncirc = TO_OR_CIRCUIT(exitconn->on_circuit);
  int is_resolve, r;
  char *hostname = NULL;
  is_resolve = exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE;

  r = dns_resolve_impl(exitconn, is_resolve, oncirc, &hostname);

  switch (r) {
    case 1:
      /* We got an answer without a lookup -- either the answer was
       * cached, or it was obvious (like an IP address). */
      if (is_resolve) {
        /* Send the answer back right now, and detach. */
        if (hostname)
          send_resolved_hostname_cell(exitconn, hostname);
        else
          send_resolved_cell(exitconn, RESOLVED_TYPE_IPV4);
        exitconn->on_circuit = NULL;
      } else {
        /* Add to the n_streams list; the calling function will send back a
         * connected cell. */
        exitconn->next_stream = oncirc->n_streams;
        oncirc->n_streams = exitconn;
      }
      break;
    case 0:
      /* The request is pending: add the connection into the linked list of
       * resolving_streams on this circuit. */
      exitconn->_base.state = EXIT_CONN_STATE_RESOLVING;
      exitconn->next_stream = oncirc->resolving_streams;
      oncirc->resolving_streams = exitconn;
      break;
    case -2:
    case -1:
      /* The request failed before it could start: cancel this connection,
       * and stop everybody waiting for the same connection. */
      if (is_resolve) {
        send_resolved_cell(exitconn,
             (r == -1) ? RESOLVED_TYPE_ERROR : RESOLVED_TYPE_ERROR_TRANSIENT);
      }

      exitconn->on_circuit = NULL;

      dns_cancel_pending_resolve(exitconn->_base.address);

      if (!exitconn->_base.marked_for_close) {
        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:
      tor_assert(0);
  }

  tor_free(hostname);
  return r;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int dns_resolve_impl ( edge_connection_t exitconn,
int  is_resolve,
or_circuit_t oncirc,
char **  hostname_out 
) [static]

Helper function for dns_resolve: same functionality, but does not handle:

- marking connections on error and clearing their on_circuit
- linking connections to n_streams/resolving_streams,
- sending resolved cells if we have an answer/error right away,

Return -2 on a transient error. If it's a reverse resolve and it's successful, sets *hostname_out to a newly allocated string holding the cached reverse DNS value.

Definition at line 672 of file dns.c.

{
  cached_resolve_t *resolve;
  cached_resolve_t search;
  pending_connection_t *pending_connection;
  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(!SOCKET_OK(exitconn->_base.s));
  assert_cache_ok();
  tor_assert(oncirc);

  /* first check if exitconn->_base.address is an IP. If so, we already
   * know the answer. */
  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;
      return 1;
    } else {
      /* XXXX IPv6 */
      return -1;
    }
  }

  /* If we're a non-exit, don't even do DNS lookups. */
  if (!(me = router_get_my_routerinfo()) ||
      policy_is_reject_star(me->exit_policy)) {
    return -1;
  }
  if (address_is_invalid_destination(exitconn->_base.address, 0)) {
    log(LOG_PROTOCOL_WARN, LD_EXIT,
        "Rejecting invalid destination address %s",
        escaped_safe_str(exitconn->_base.address));
    return -1;
  }

  /* then take this opportunity to see if there are any expired
   * resolves in the hash table. */
  purge_expired_resolves(now);

  /* lower-case exitconn->_base.address, so it's in canonical form */
  tor_strlower(exitconn->_base.address);

  /* Check whether this is a reverse lookup.  If it's malformed, or it's a
   * .in-addr.arpa address but this isn't a resolve request, kill the
   * connection.
   */
  if ((r = tor_addr_parse_PTR_name(&addr, exitconn->_base.address,
                                              AF_UNSPEC, 0)) != 0) {
    if (r == 1) {
      is_reverse = 1;
      if (tor_addr_is_internal(&addr, 0)) /* internal address? */
        return -1;
    }

    if (!is_reverse || !is_resolve) {
      if (!is_reverse)
        log_info(LD_EXIT, "Bad .in-addr.arpa address \"%s\"; sending error.",
                 escaped_safe_str(exitconn->_base.address));
      else if (!is_resolve)
        log_info(LD_EXIT,
                 "Attempt to connect to a .in-addr.arpa address \"%s\"; "
                 "sending error.",
                 escaped_safe_str(exitconn->_base.address));

      return -1;
    }
    //log_notice(LD_EXIT, "Looks like an address %s",
    //exitconn->_base.address);
  }

  /* now check the hash table to see if 'address' is already there. */
  strlcpy(search.address, exitconn->_base.address, sizeof(search.address));
  resolve = HT_FIND(cache_map, &cache_root, &search);
  if (resolve && resolve->expire > now) { /* already there */
    switch (resolve->state) {
      case CACHE_STATE_PENDING:
        /* add us to the pending list */
        pending_connection = tor_malloc_zero(
                                      sizeof(pending_connection_t));
        pending_connection->conn = exitconn;
        pending_connection->next = resolve->pending_connections;
        resolve->pending_connections = pending_connection;
        log_debug(LD_EXIT,"Connection (fd %d) waiting for pending DNS "
                  "resolve of %s", exitconn->_base.s,
                  escaped_safe_str(exitconn->_base.address));
        return 0;
      case CACHE_STATE_CACHED_VALID:
        log_debug(LD_EXIT,"Connection (fd %d) found cached answer for %s",
                  exitconn->_base.s,
                  escaped_safe_str(resolve->address));
        exitconn->address_ttl = resolve->ttl;
        if (resolve->is_reverse) {
          tor_assert(is_resolve);
          *hostname_out = tor_strdup(resolve->result.hostname);
        } else {
          tor_addr_from_ipv4h(&exitconn->_base.addr, resolve->result.a.addr);
        }
        return 1;
      case CACHE_STATE_CACHED_FAILED:
        log_debug(LD_EXIT,"Connection (fd %d) found cached error for %s",
                  exitconn->_base.s,
                  escaped_safe_str(exitconn->_base.address));
        return -1;
      case CACHE_STATE_DONE:
        log_err(LD_BUG, "Found a 'DONE' dns resolve still in the cache.");
        tor_fragile_assert();
    }
    tor_assert(0);
  }
  tor_assert(!resolve);
  /* not there, need to add it */
  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));

  /* add this connection to the pending list */
  pending_connection = tor_malloc_zero(sizeof(pending_connection_t));
  pending_connection->conn = exitconn;
  resolve->pending_connections = pending_connection;

  /* Add this resolve to the cache and priority queue. */
  HT_INSERT(cache_map, &cache_root, resolve);
  set_expiry(resolve, now + RESOLVE_MAX_TIMEOUT);

  log_debug(LD_EXIT,"Launching %s.",
            escaped_safe_str(exitconn->_base.address));
  assert_cache_ok();

  return launch_resolve(exitconn);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int dns_seems_to_be_broken ( void  )

Return true iff our DNS servers lie to us too much to be trusted.

Definition at line 1693 of file dns.c.

Here is the caller graph for this function:

void dump_dns_mem_usage ( int  severity)

Log memory information about our internal DNS cache at level 'severity'.

Definition at line 1758 of file dns.c.

{
  /* 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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void evdns_callback ( int  result,
char  type,
int  count,
int  ttl,
void *  addresses,
void *  arg 
) [static]

For eventdns: Called when we get an answer for a request we launched.

See eventdns.h for arguments; 'arg' holds the address we tried to resolve.

Definition at line 1317 of file dns.c.

{
  char *string_address = arg;
  uint8_t 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) {
      char answer_buf[INET_NTOA_BUF_LEN+1];
      struct in_addr in;
      char *escaped_address;
      uint32_t *addrs = addresses;
      in.s_addr = addrs[0];
      addr = ntohl(addrs[0]);
      status = DNS_RESOLVE_SUCCEEDED;
      tor_inet_ntoa(&in, answer_buf, sizeof(answer_buf));
      escaped_address = esc_for_log(string_address);

      if (answer_is_wildcarded(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));
        was_wildcarded = 1;
        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);
    } else if (type == DNS_PTR && count) {
      char *escaped_address;
      is_reverse = 1;
      hostname = ((char**)addresses)[0];
      status = DNS_RESOLVE_SUCCEEDED;
      escaped_address = esc_for_log(string_address);
      log_debug(LD_EXIT, "eventdns said that %s resolves to %s",
                safe_str(escaped_address),
                escaped_safe_str(hostname));
      tor_free(escaped_address);
    } else if (count) {
      log_warn(LD_EXIT, "eventdns returned only non-IPv4 answers for %s.",
               escaped_safe_str(string_address));
    } else {
      log_warn(LD_BUG, "eventdns returned no addresses or error for %s!",
               escaped_safe_str(string_address));
    }
  } else {
    if (evdns_err_is_transient(result))
      status = DNS_RESOLVE_FAILED_TRANSIENT;
  }
  if (was_wildcarded) {
    if (is_test_address(string_address)) {
      /* Ick.  We're getting redirected on known-good addresses.  Our DNS
       * server must really hate us.  */
      add_wildcarded_test_address(string_address);
    }
  }
  if (result != DNS_ERR_SHUTDOWN)
    dns_found_answer(string_address, is_reverse, addr, hostname, status, ttl);
  tor_free(string_address);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int evdns_err_is_transient ( int  err) [static]

Eventdns helper: return true iff the eventdns result err is a transient failure.

Definition at line 1158 of file dns.c.

{
  switch (err)
  {
    case DNS_ERR_SERVERFAILED:
    case DNS_ERR_TRUNCATED:
    case DNS_ERR_TIMEOUT:
      return 1;
    default:
      return 0;
  }
}

Here is the caller graph for this function:

static void evdns_log_cb ( int  warn,
const char *  msg 
) [static]

Helper: called by eventdns when eventdns wants to log something.

Definition at line 214 of file dns.c.

{
  const char *cp;
  static int all_down = 0;
  int severity = warn ? LOG_WARN : LOG_INFO;
  if (!strcmpstart(msg, "Resolve requested for") &&
      get_options()->SafeLogging) {
    log(LOG_INFO, LD_EXIT, "eventdns: Resolve requested.");
    return;
  } else if (!strcmpstart(msg, "Search: ")) {
    return;
  }
  if (!strcmpstart(msg, "Nameserver ") && (cp=strstr(msg, " has failed: "))) {
    char *ns = tor_strndup(msg+11, cp-(msg+11));
    const char *err = strchr(cp, ':')+2;
    tor_assert(err);
    /* Don't warn about a single failed nameserver; we'll warn with 'all
     * nameservers have failed' if we're completely out of nameservers;
     * otherwise, the situation is tolerable. */
    severity = LOG_INFO;
    control_event_server_status(LOG_NOTICE,
                                "NAMESERVER_STATUS NS=%s STATUS=DOWN ERR=%s",
                                ns, escaped(err));
    tor_free(ns);
  } else if (!strcmpstart(msg, "Nameserver ") &&
             (cp=strstr(msg, " is back up"))) {
    char *ns = tor_strndup(msg+11, cp-(msg+11));
    severity = (all_down && warn) ? LOG_NOTICE : LOG_INFO;
    all_down = 0;
    control_event_server_status(LOG_NOTICE,
                                "NAMESERVER_STATUS NS=%s STATUS=UP", ns);
    tor_free(ns);
  } else if (!strcmp(msg, "All nameservers have failed")) {
    control_event_server_status(LOG_WARN, "NAMESERVER_ALL_DOWN");
    all_down = 1;
  }
  log(severity, LD_EXIT, "eventdns: %s", msg);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void evdns_wildcard_check_callback ( int  result,
char  type,
int  count,
int  ttl,
void *  addresses,
void *  arg 
) [static]

Callback function when we get an answer (possibly failing) for a request for a (hopefully) nonexistent domain.

Definition at line 1545 of file dns.c.

{
  (void)ttl;
  ++n_wildcard_requests;
  if (result == DNS_ERR_NONE && type == DNS_IPv4_A && count) {
    uint32_t *addrs = addresses;
    int i;
    char *string_address = arg;
    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));
      wildcard_increment_answer(answer_buf);
    }
    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 address%s so far.",
        string_address, strmap_size(dns_wildcard_response_count),
        (strmap_size(dns_wildcard_response_count) == 1) ? "" : "es");
    dns_wildcard_one_notice_given = 1;
  }
  tor_free(arg);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int has_dns_init_failed ( void  )

Return true iff the most recent attempt to initialize the DNS subsystem failed.

Definition at line 305 of file dns.c.

Here is the caller graph for this function:

static HT_HEAD ( cache_map  ,
cached_resolve_t   
) [static]

Hash table of cached_resolve objects.

Definition at line 181 of file dns.c.

{
  /* make this smarter one day? */
  assert_resolve_ok(a); // Not b; b may be just a search.
  return !strncmp(a->address, b->address, MAX_ADDRESSLEN);
}

Here is the call graph for this function:

HT_PROTOTYPE ( HT_GENERATE cache_map,
HT_GENERATE cached_resolve_t,
HT_GENERATE node,
HT_GENERATE cached_resolve_hash,
HT_GENERATE cached_resolves_eq 
)

Initialize the DNS cache.

Definition at line 200 of file dns.c.

{
  HT_INIT(cache_map, &cache_root);
}
static INLINE int is_test_address ( const char *  address) [static]

Return true iff address is one of the addresses we use to verify that well-known sites aren't being hijacked by our DNS servers.

Definition at line 1027 of file dns.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static int launch_resolve ( edge_connection_t exitconn) [static]

For eventdns: start resolving as necessary to find the target for exitconn.

Returns -1 on error, -2 on transient error, 0 on "resolve launched."

Definition at line 1390 of file dns.c.

{
  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 "
             "launched.  Configuring.");
    if (configure_nameservers(1) < 0) {
      return -1;
    }
  }

  addr = tor_strdup(exitconn->_base.address);

  r = tor_addr_parse_PTR_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));
    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)
      req = evdns_base_resolve_reverse(the_evdns_base,
                                tor_addr_to_in(&a), DNS_QUERY_NO_SEARCH,
                                evdns_callback, addr);
    else
      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.");
  }

  r = 0;
  if (!req) {
    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
                     * addr from getting leaked. */
  }
  return r;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void launch_test_addresses ( int  fd,
short  event,
void *  args 
) [static]

Launch attempts to resolve a bunch of known-good addresses (configured in ServerDNSTestAddresses).

[Callback for a libevent timer]

Definition at line 1602 of file dns.c.

{
  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
   * happens, we're no good for DNS requests at all, and we shouldn't really
   * be an exit server.*/
  if (!options->ServerDNSTestAddresses)
    return;
  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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void launch_wildcard_check ( int  min_len,
int  max_len,
const char *  suffix 
) [static]

Launch a single request for a nonexistent hostname consisting of between min_len and max_len random (plausible) characters followed by suffix

Definition at line 1577 of file dns.c.

{
  char *addr;
  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);

  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 (!req) {
    /* There is no evdns request in progress; stop addr from getting leaked */
    tor_free(addr);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void purge_expired_resolves ( time_t  now) [static]

Remove every cached_resolve whose expire time is before or equal to now from the cache.

Definition at line 414 of file dns.c.

{
  cached_resolve_t *resolve, *removed;
  pending_connection_t *pend;
  edge_connection_t *pendconn;

  assert_cache_ok();
  if (!cached_resolve_pqueue)
    return;

  while (smartlist_len(cached_resolve_pqueue)) {
    resolve = smartlist_get(cached_resolve_pqueue, 0);
    if (resolve->expire > now)
      break;
    smartlist_pqueue_pop(cached_resolve_pqueue,
                         _compare_cached_resolves_by_expiry,
                         STRUCT_OFFSET(cached_resolve_t, minheap_idx));

    if (resolve->state == CACHE_STATE_PENDING) {
      log_debug(LD_EXIT,
                "Expiring a dns resolve %s that's still pending. Forgot to "
                "cull it? DNS resolve didn't tell us about the timeout?",
                escaped_safe_str(resolve->address));
    } else if (resolve->state == CACHE_STATE_CACHED_VALID ||
               resolve->state == CACHE_STATE_CACHED_FAILED) {
      log_debug(LD_EXIT,
                "Forgetting old cached resolve (address %s, expires %lu)",
                escaped_safe_str(resolve->address),
                (unsigned long)resolve->expire);
      tor_assert(!resolve->pending_connections);
    } else {
      tor_assert(resolve->state == CACHE_STATE_DONE);
      tor_assert(!resolve->pending_connections);
    }

    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(!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));
        tor_free(pend);
      }
    }

    if (resolve->state == CACHE_STATE_CACHED_VALID ||
        resolve->state == CACHE_STATE_CACHED_FAILED ||
        resolve->state == CACHE_STATE_PENDING) {
      removed = HT_REMOVE(cache_map, &cache_root, resolve);
      if (removed != resolve) {
        log_err(LD_BUG, "The expired resolve we purged didn't match any in"
                " the cache. Tried to purge %s (%p); instead got %s (%p).",
                resolve->address, (void*)resolve,
                removed ? removed->address : "NULL", (void*)removed);
      }
      tor_assert(removed == resolve);
    } else {
      /* This should be in state DONE. Make sure it's not in the cache. */
      cached_resolve_t *tmp = HT_FIND(cache_map, &cache_root, resolve);
      tor_assert(tmp != resolve);
    }
    if (resolve->is_reverse)
      tor_free(resolve->result.hostname);
    resolve->magic = 0xF0BBF0BB;
    tor_free(resolve);
  }

  assert_cache_ok();
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void send_resolved_cell ( edge_connection_t conn,
uint8_t  answer_type 
) [static]

Send a response to the RESOLVE request of a connection.

answer_type must be one of RESOLVED_TYPE_(IPV4|ERROR|ERROR_TRANSIENT).

If circ is provided, and we have a cached answer, send the answer back along circ; otherwise, send the answer back along conn's attached circuit.

Definition at line 500 of file dns.c.

{
  char buf[RELAY_PAYLOAD_SIZE];
  size_t buflen;
  uint32_t ttl;

  buf[0] = answer_type;
  ttl = dns_clip_ttl(conn->address_ttl);

  switch (answer_type)
    {
    case RESOLVED_TYPE_IPV4:
      buf[1] = 4;
      set_uint32(buf+2, tor_addr_to_ipv4n(&conn->_base.addr));
      set_uint32(buf+6, htonl(ttl));
      buflen = 10;
      break;
    /*XXXX IP6 need ipv6 implementation */
    case RESOLVED_TYPE_ERROR_TRANSIENT:
    case RESOLVED_TYPE_ERROR:
      {
        const char *errmsg = "Error resolving hostname";
        size_t msglen = strlen(errmsg);

        buf[1] = msglen;
        strlcpy(buf+2, errmsg, sizeof(buf)-2);
        set_uint32(buf+2+msglen, htonl(ttl));
        buflen = 6+msglen;
        break;
      }
    default:
      tor_assert(0);
      return;
    }
  // log_notice(LD_EXIT, "Sending a regular RESOLVED reply: ");

  connection_edge_send_command(conn, RELAY_COMMAND_RESOLVED, buf, buflen);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void send_resolved_hostname_cell ( edge_connection_t conn,
const char *  hostname 
) [static]

Send a response to the RESOLVE request of a connection for an in-addr.arpa address on connection conn which yielded the result hostname.

The answer type will be RESOLVED_HOSTNAME.

If circ is provided, and we have a cached answer, send the answer back along circ; otherwise, send the answer back along conn's attached circuit.

Definition at line 548 of file dns.c.

{
  char buf[RELAY_PAYLOAD_SIZE];
  size_t buflen;
  uint32_t ttl;
  size_t namelen = strlen(hostname);
  tor_assert(hostname);

  tor_assert(namelen < 256);
  ttl = dns_clip_ttl(conn->address_ttl);

  buf[0] = RESOLVED_TYPE_HOSTNAME;
  buf[1] = (uint8_t)namelen;
  memcpy(buf+2, hostname, namelen);
  set_uint32(buf+2+namelen, htonl(ttl));
  buflen = 2+namelen+4;

  // log_notice(LD_EXIT, "Sending a reply RESOLVED reply: %s", hostname);
  connection_edge_send_command(conn, RELAY_COMMAND_RESOLVED, buf, buflen);
  // log_notice(LD_EXIT, "Sent");
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void set_expiry ( cached_resolve_t resolve,
time_t  expires 
) [static]

Set an expiry time for a cached_resolve_t, and add it to the expiry priority queue.

Definition at line 375 of file dns.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static void wildcard_increment_answer ( const char *  id) [static]

Called when we see id (a dotted quad) in response to a request for a hopefully bogus address.

Definition at line 1480 of file dns.c.

{
  int *ip;
  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_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 "
        "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));
    }
    if (!dns_wildcard_notice_given)
      control_event_server_status(LOG_NOTICE, "DNS_HIJACKED");
    dns_wildcard_notice_given = 1;
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Priority queue of cached_resolve_t objects to let us know when they will expire.

Definition at line 370 of file dns.c.

int dns_is_completely_invalid = 0 [static]

True iff all addresses seem to be getting wildcarded.

Definition at line 1475 of file dns.c.

smartlist_t* dns_wildcard_list = NULL [static]

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.

Definition at line 1461 of file dns.c.

int dns_wildcard_notice_given = 0 [static]

True iff we've warned that our DNS server is wildcarding too many failures.

Definition at line 1467 of file dns.c.

True iff we've logged about a single address getting wildcarded.

Subsequent warnings will be less severe.

Definition at line 1464 of file dns.c.

strmap_t* dns_wildcard_response_count = NULL [static]

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().

Definition at line 1456 of file dns.c.

List of supposedly good addresses that are getting wildcarded to the same addresses as nonexistent addresses.

Definition at line 1471 of file dns.c.

True iff we've warned about a test address getting wildcarded.

Definition at line 1473 of file dns.c.

int n_wildcard_requests = 0 [static]

How many requests for bogus addresses have we launched so far?

Definition at line 1450 of file dns.c.

int nameserver_config_failed = 0 [static]

Did our most recent attempt to configure nameservers with eventdns fail?

Definition at line 99 of file dns.c.

int nameservers_configured = 0 [static]

Have we currently configured nameservers with eventdns?

Definition at line 97 of file dns.c.

char* resolv_conf_fname = NULL [static]

What was the resolv_conf fname we last used when configuring the nameservers? Used to check whether we need to reconfigure.

Definition at line 102 of file dns.c.

time_t resolv_conf_mtime = 0 [static]

What was the mtime on the resolv.conf file we last used when configuring the nameservers? Used to check whether we need to reconfigure.

Definition at line 105 of file dns.c.

struct evdns_base* the_evdns_base = NULL [static]

Our evdns_base; this structure handles all our name lookups.

Definition at line 94 of file dns.c.