Commit 81eee0ec authored by Nick Mathewson's avatar Nick Mathewson 🦀
Browse files

Fix a crash when using evdns from Libevent 2.

When we tried to use the deprecated non-threadsafe evdns
interfaces in Libevent 2 without using the also-deprecated
event_init() interface, Libevent 2 would sensibly crash, since it
has no guess where to find the Libevent library.

Here we use the evdns_base_*() functions instead if they're
present, and fake them if they aren't.
parent 4b55ef26
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -3,6 +3,10 @@ Changes in version 0.2.2.6-alpha - 2009-10-??
    - Numerous changes, bugfixes, and workarounds from Nathan Freitas
      to help Tor build correctly for Android phones.

  o Minor bugfixes:
    - Fix a crash bug when trying to initialize the evdns module in
      Libevent 2.


Changes in version 0.2.2.5-alpha - 2009-10-11
  o Major bugfixes:
+98 −44
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@
#ifdef HAVE_EVENT2_DNS_H
#include <event2/event.h>
#include <event2/dns.h>
#include <event2/dns_compat.h>
#else
#include <event.h>
#include "eventdns.h"
@@ -25,6 +24,33 @@
#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, flags) \
  evdns_set_option((opt),(val),(flags))
#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))
#endif

/** Longest hostname we're willing to resolve. */
#define MAX_ADDRESSLEN 256

@@ -38,6 +64,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? */
@@ -221,8 +250,8 @@ dns_reset(void)
{
  or_options_t *options = get_options();
  if (! server_mode(options)) {
    evdns_clear_nameservers_and_suspend();
    evdns_search_clear();
    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;
@@ -1118,6 +1147,13 @@ 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;
@@ -1133,18 +1169,14 @@ 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,
        evdns_base_set_default_outgoing_bind_address(the_evdns_base,
                                                     (struct sockaddr *)&ss,
                                                     socklen);
      }
    }
  }
#endif

  if (options->ServerDNSRandomizeCase)
    evdns_set_option("randomize-case:", "1", DNS_OPTIONS_ALL);
  else
    evdns_set_option("randomize-case:", "0", DNS_OPTIONS_ALL);

  evdns_set_log_fn(evdns_log_cb);
  if (conf_fname) {
    if (stat(conf_fname, &st)) {
@@ -1158,16 +1190,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;
    }
@@ -1175,38 +1208,48 @@ 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), DNS_OPTIONS_ALL)

  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;
@@ -1304,6 +1347,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
@@ -1322,25 +1366,28 @@ launch_resolve(edge_connection_t *exitconn)
  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,
    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. */
  }
@@ -1478,17 +1525,19 @@ 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 */
  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);
  }
@@ -1500,6 +1549,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;
@@ -1511,14 +1561,18 @@ 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);
    });
  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