[or-cvs] [tor/master] Fix a crash when using evdns from Libevent 2.

Nick Mathewson nickm at seul.org
Tue Oct 13 21:57:51 UTC 2009


Author: Nick Mathewson <nickm at torproject.org>
Date: Tue, 13 Oct 2009 17:54:04 -0400
Subject: Fix a crash when using evdns from Libevent 2.
Commit: 81eee0ecfff3dac1e9438719d2f7dc0ba7e84a71

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.
---
 ChangeLog    |    4 ++
 src/or/dns.c |  142 ++++++++++++++++++++++++++++++++++++++++------------------
 2 files changed, 102 insertions(+), 44 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 72f4aa8..9ed1cbd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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:
diff --git a/src/or/dns.c b/src/or/dns.c
index c6f9e8b..6021ca5 100644
--- a/src/or/dns.c
+++ b/src/or/dns.c
@@ -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,
-                                                socklen);
+        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,
-                           evdns_callback, addr);
+    req = evdns_base_resolve_ipv4(the_evdns_base,
+                                exitconn->_base.address, options,
+                                evdns_callback, addr);
   } else if (r == 1) {
     log_info(LD_EXIT, "Launching eventdns reverse request for %s",
              escaped_safe_str(exitconn->_base.address));
     if (tor_addr_family(&a) == AF_INET)
-      r = evdns_resolve_reverse(tor_addr_to_in(&a), DNS_QUERY_NO_SEARCH,
+      req = evdns_base_resolve_reverse(the_evdns_base,
+                                tor_addr_to_in(&a), DNS_QUERY_NO_SEARCH,
                                 evdns_callback, addr);
     else
-      r = evdns_resolve_reverse_ipv6(tor_addr_to_in6(&a), DNS_QUERY_NO_SEARCH,
+      req = evdns_base_resolve_reverse_ipv6(the_evdns_base,
+                                     tor_addr_to_in6(&a), DNS_QUERY_NO_SEARCH,
                                      evdns_callback, addr);
   } else if (r == -1) {
     log_warn(LD_BUG, "Somehow a malformed in-addr.arpa address reached here.");
   }
 
-  if (r) {
-    log_warn(LD_EXIT, "eventdns rejected address %s: error %d.",
-             escaped_safe_str(addr), r);
-    r = evdns_err_is_transient(r) ? -2 : -1;
+  r = 0;
+  if (!req) {
+    log_warn(LD_EXIT, "eventdns rejected address %s.", escaped_safe_str(addr));
+    r = -1;
     tor_free(addr); /* There is no evdns request in progress; stop
                      * addr from getting leaked. */
   }
@@ -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
-- 
1.5.6.5



More information about the tor-commits mailing list