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
...@@ -3,6 +3,10 @@ Changes in version 0.2.2.6-alpha - 2009-10-?? ...@@ -3,6 +3,10 @@ Changes in version 0.2.2.6-alpha - 2009-10-??
- Numerous changes, bugfixes, and workarounds from Nathan Freitas - Numerous changes, bugfixes, and workarounds from Nathan Freitas
to help Tor build correctly for Android phones. 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 Changes in version 0.2.2.5-alpha - 2009-10-11
o Major bugfixes: o Major bugfixes:
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#ifdef HAVE_EVENT2_DNS_H #ifdef HAVE_EVENT2_DNS_H
#include <event2/event.h> #include <event2/event.h>
#include <event2/dns.h> #include <event2/dns.h>
#include <event2/dns_compat.h>
#else #else
#include <event.h> #include <event.h>
#include "eventdns.h" #include "eventdns.h"
...@@ -25,6 +24,33 @@ ...@@ -25,6 +24,33 @@
#endif #endif
#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. */ /** Longest hostname we're willing to resolve. */
#define MAX_ADDRESSLEN 256 #define MAX_ADDRESSLEN 256
...@@ -38,6 +64,9 @@ ...@@ -38,6 +64,9 @@
#define DNS_RESOLVE_FAILED_PERMANENT 2 #define DNS_RESOLVE_FAILED_PERMANENT 2
#define DNS_RESOLVE_SUCCEEDED 3 #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? */ /** Have we currently configured nameservers with eventdns? */
static int nameservers_configured = 0; static int nameservers_configured = 0;
/** Did our most recent attempt to configure nameservers with eventdns fail? */ /** Did our most recent attempt to configure nameservers with eventdns fail? */
...@@ -221,8 +250,8 @@ dns_reset(void) ...@@ -221,8 +250,8 @@ dns_reset(void)
{ {
or_options_t *options = get_options(); or_options_t *options = get_options();
if (! server_mode(options)) { if (! server_mode(options)) {
evdns_clear_nameservers_and_suspend(); evdns_base_clear_nameservers_and_suspend(the_evdns_base);
evdns_search_clear(); evdns_base_search_clear(the_evdns_base);
nameservers_configured = 0; nameservers_configured = 0;
tor_free(resolv_conf_fname); tor_free(resolv_conf_fname);
resolv_conf_mtime = 0; resolv_conf_mtime = 0;
...@@ -1118,6 +1147,13 @@ configure_nameservers(int force) ...@@ -1118,6 +1147,13 @@ configure_nameservers(int force)
conf_fname = "/etc/resolv.conf"; conf_fname = "/etc/resolv.conf";
#endif #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 #ifdef HAVE_EVDNS_SET_DEFAULT_OUTGOING_BIND_ADDRESS
if (options->OutboundBindAddress) { if (options->OutboundBindAddress) {
tor_addr_t addr; tor_addr_t addr;
...@@ -1133,18 +1169,14 @@ configure_nameservers(int force) ...@@ -1133,18 +1169,14 @@ configure_nameservers(int force)
log_warn(LD_BUG, "Couldn't convert outbound bind address to sockaddr." log_warn(LD_BUG, "Couldn't convert outbound bind address to sockaddr."
" Ignoring."); " Ignoring.");
} else { } else {
evdns_set_default_outgoing_bind_address((struct sockaddr *)&ss, evdns_base_set_default_outgoing_bind_address(the_evdns_base,
(struct sockaddr *)&ss,
socklen); socklen);
} }
} }
} }
#endif #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); evdns_set_log_fn(evdns_log_cb);
if (conf_fname) { if (conf_fname) {
if (stat(conf_fname, &st)) { if (stat(conf_fname, &st)) {
...@@ -1158,16 +1190,17 @@ configure_nameservers(int force) ...@@ -1158,16 +1190,17 @@ configure_nameservers(int force)
return 0; return 0;
} }
if (nameservers_configured) { if (nameservers_configured) {
evdns_search_clear(); evdns_base_search_clear(the_evdns_base);
evdns_clear_nameservers_and_suspend(); evdns_base_clear_nameservers_and_suspend(the_evdns_base);
} }
log_info(LD_EXIT, "Parsing resolver configuration in '%s'", conf_fname); 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)", log_warn(LD_EXIT, "Unable to parse '%s', or no nameservers in '%s' (%d)",
conf_fname, conf_fname, r); conf_fname, conf_fname, r);
goto err; 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); log_warn(LD_EXIT, "Unable to find any nameservers in '%s'.", conf_fname);
goto err; goto err;
} }
...@@ -1175,38 +1208,48 @@ configure_nameservers(int force) ...@@ -1175,38 +1208,48 @@ configure_nameservers(int force)
resolv_conf_fname = tor_strdup(conf_fname); resolv_conf_fname = tor_strdup(conf_fname);
resolv_conf_mtime = st.st_mtime; resolv_conf_mtime = st.st_mtime;
if (nameservers_configured) if (nameservers_configured)
evdns_resume(); evdns_base_resume(the_evdns_base);
} }
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
else { else {
if (nameservers_configured) { if (nameservers_configured) {
evdns_search_clear(); evdns_base_search_clear(the_evdns_base);
evdns_clear_nameservers_and_suspend(); 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."); log_warn(LD_EXIT,"Could not config nameservers.");
goto err; 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 " log_warn(LD_EXIT, "Unable to find any platform nameservers in "
"your Windows configuration."); "your Windows configuration.");
goto err; goto err;
} }
if (nameservers_configured) if (nameservers_configured)
evdns_resume(); evdns_base_resume(the_evdns_base);
tor_free(resolv_conf_fname); tor_free(resolv_conf_fname);
resolv_conf_mtime = 0; resolv_conf_mtime = 0;
} }
#endif #endif
if (evdns_count_nameservers() == 1) { #define SET(k,v) \
evdns_set_option("max-timeouts:", "16", DNS_OPTIONS_ALL); evdns_base_set_option(the_evdns_base, (k), (v), DNS_OPTIONS_ALL)
evdns_set_option("timeout:", "10", DNS_OPTIONS_ALL);
if (evdns_base_count_nameservers(the_evdns_base) == 1) {
SET("max-timeouts:", "16");
SET("timeout:", "10");
} else { } else {
evdns_set_option("max-timeouts:", "3", DNS_OPTIONS_ALL); SET("max-timeouts:", "3");
evdns_set_option("timeout:", "5", DNS_OPTIONS_ALL); SET("timeout:", "5");
} }
if (options->ServerDNSRandomizeCase)
SET("randomize-case:", "1");
else
SET("randomize-case:", "0");
#undef SET
dns_servers_relaunch_checks(); dns_servers_relaunch_checks();
nameservers_configured = 1; nameservers_configured = 1;
...@@ -1304,6 +1347,7 @@ static int ...@@ -1304,6 +1347,7 @@ static int
launch_resolve(edge_connection_t *exitconn) launch_resolve(edge_connection_t *exitconn)
{ {
char *addr = tor_strdup(exitconn->_base.address); char *addr = tor_strdup(exitconn->_base.address);
struct evdns_request *req = NULL;
tor_addr_t a; tor_addr_t a;
int r; int r;
int options = get_options()->ServerDNSSearchDomains ? 0 int options = get_options()->ServerDNSSearchDomains ? 0
...@@ -1322,25 +1366,28 @@ launch_resolve(edge_connection_t *exitconn) ...@@ -1322,25 +1366,28 @@ launch_resolve(edge_connection_t *exitconn)
if (r == 0) { if (r == 0) {
log_info(LD_EXIT, "Launching eventdns request for %s", log_info(LD_EXIT, "Launching eventdns request for %s",
escaped_safe_str(exitconn->_base.address)); 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); evdns_callback, addr);
} else if (r == 1) { } else if (r == 1) {
log_info(LD_EXIT, "Launching eventdns reverse request for %s", log_info(LD_EXIT, "Launching eventdns reverse request for %s",
escaped_safe_str(exitconn->_base.address)); escaped_safe_str(exitconn->_base.address));
if (tor_addr_family(&a) == AF_INET) 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); evdns_callback, addr);
else 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); evdns_callback, addr);
} else if (r == -1) { } else if (r == -1) {
log_warn(LD_BUG, "Somehow a malformed in-addr.arpa address reached here."); log_warn(LD_BUG, "Somehow a malformed in-addr.arpa address reached here.");
} }
if (r) { r = 0;
log_warn(LD_EXIT, "eventdns rejected address %s: error %d.", if (!req) {
escaped_safe_str(addr), r); log_warn(LD_EXIT, "eventdns rejected address %s.", escaped_safe_str(addr));
r = evdns_err_is_transient(r) ? -2 : -1; r = -1;
tor_free(addr); /* There is no evdns request in progress; stop tor_free(addr); /* There is no evdns request in progress; stop
* addr from getting leaked. */ * addr from getting leaked. */
} }
...@@ -1478,17 +1525,19 @@ static void ...@@ -1478,17 +1525,19 @@ static void
launch_wildcard_check(int min_len, int max_len, const char *suffix) launch_wildcard_check(int min_len, int max_len, const char *suffix)
{ {
char *addr; char *addr;
int r; struct evdns_request *req;
addr = crypto_random_hostname(min_len, max_len, "", suffix); addr = crypto_random_hostname(min_len, max_len, "", suffix);
log_info(LD_EXIT, "Testing whether our DNS server is hijacking nonexistent " log_info(LD_EXIT, "Testing whether our DNS server is hijacking nonexistent "
"domains with request for bogus hostname \"%s\"", addr); "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, addr,
DNS_QUERY_NO_SEARCH, evdns_wildcard_check_callback, DNS_QUERY_NO_SEARCH, evdns_wildcard_check_callback,
/* This "addr" is an argument to the callback*/ addr); /* 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 */ /* There is no evdns request in progress; stop addr from getting leaked */
tor_free(addr); tor_free(addr);
} }
...@@ -1500,6 +1549,7 @@ static void ...@@ -1500,6 +1549,7 @@ static void
launch_test_addresses(int fd, short event, void *args) launch_test_addresses(int fd, short event, void *args)
{ {
or_options_t *options = get_options(); or_options_t *options = get_options();
struct evdns_request *req;
(void)fd; (void)fd;
(void)event; (void)event;
(void)args; (void)args;
...@@ -1511,14 +1561,18 @@ launch_test_addresses(int fd, short event, void *args) ...@@ -1511,14 +1561,18 @@ launch_test_addresses(int fd, short event, void *args)
* be an exit server.*/ * be an exit server.*/
if (!options->ServerDNSTestAddresses) if (!options->ServerDNSTestAddresses)
return; return;
SMARTLIST_FOREACH(options->ServerDNSTestAddresses, const char *, address, SMARTLIST_FOREACH_BEGIN(options->ServerDNSTestAddresses,
{ const char *, address) {
int r = evdns_resolve_ipv4(address, DNS_QUERY_NO_SEARCH, evdns_callback, char *a = tor_strdup(address);
tor_strdup(address)); req = evdns_base_resolve_ipv4(the_evdns_base,
if (r) address, DNS_QUERY_NO_SEARCH, evdns_callback, a);
log_info(LD_EXIT, "eventdns rejected test address %s: error %d",
escaped_safe_str(address), r); 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 #define N_WILDCARD_CHECKS 2
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment