Merge remote-tracking branch 'tor-github/pr/425'

This commit is contained in:
Nick Mathewson 2018-10-30 09:16:55 -04:00
commit 30d853a906
6 changed files with 152 additions and 18 deletions

4
changes/bug21900 Normal file
View file

@ -0,0 +1,4 @@
o Minor bugfixes (DNS):
- Gracefully handle empty or absent resolve.conf file by falling
back to using localhost DNS service and hoping it works. Fixes
bug 21900; bugfix on 0.2.1.10-alpha.

View file

@ -812,6 +812,8 @@ fi
dnl Now check for particular libevent functions.
AC_CHECK_FUNCS([evutil_secure_rng_set_urandom_device_file \
evutil_secure_rng_add_bytes \
evdns_base_get_nameserver_addr \
])
LIBS="$save_LIBS"

View file

@ -2211,7 +2211,8 @@ is non-zero):
__filename__. The file format is the same as the standard Unix
"**resolv.conf**" file (7). This option, like all other ServerDNS options,
only affects name lookups that your server does on behalf of clients.
(Defaults to use the system DNS configuration.)
(Defaults to use the system DNS configuration or a localhost DNS service
in case no nameservers are found in a given configuration.)
[[ServerDNSAllowBrokenConfig]] **ServerDNSAllowBrokenConfig** **0**|**1**::
If this option is false, Tor exits immediately if there are problems

View file

@ -1357,6 +1357,41 @@ evdns_err_is_transient(int err)
}
}
/**
* Return number of configured nameservers in <b>the_evdns_base</b>.
*/
size_t
number_of_configured_nameservers(void)
{
return evdns_base_count_nameservers(the_evdns_base);
}
#ifdef HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR
/**
* Return address of configured nameserver in <b>the_evdns_base</b>
* at index <b>idx</b>.
*/
tor_addr_t *
configured_nameserver_address(const size_t idx)
{
struct sockaddr_storage sa;
ev_socklen_t sa_len = sizeof(sa);
if (evdns_base_get_nameserver_addr(the_evdns_base, (int)idx,
(struct sockaddr *)&sa,
sa_len) > 0) {
tor_addr_t *tor_addr = tor_malloc(sizeof(tor_addr_t));
if (tor_addr_from_sockaddr(tor_addr,
(const struct sockaddr *)&sa,
NULL) == 0) {
return tor_addr;
}
}
return NULL;
}
#endif
/** 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
@ -1388,16 +1423,23 @@ configure_nameservers(int force)
evdns_set_log_fn(evdns_log_cb);
if (conf_fname) {
log_debug(LD_FS, "stat()ing %s", conf_fname);
if (stat(sandbox_intern_string(conf_fname), &st)) {
int missing_resolv_conf = 0;
int stat_res = stat(sandbox_intern_string(conf_fname), &st);
if (stat_res) {
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)
missing_resolv_conf = 1;
} else 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 (stat_res == 0 && st.st_size == 0)
missing_resolv_conf = 1;
if (nameservers_configured) {
evdns_base_search_clear(the_evdns_base);
evdns_base_clear_nameservers_and_suspend(the_evdns_base);
@ -1410,20 +1452,34 @@ configure_nameservers(int force)
sandbox_intern_string("/etc/hosts"));
}
#endif /* defined(DNS_OPTION_HOSTSFILE) && defined(USE_LIBSECCOMP) */
log_info(LD_EXIT, "Parsing resolver configuration in '%s'", conf_fname);
if ((r = evdns_base_resolv_conf_parse(the_evdns_base, flags,
sandbox_intern_string(conf_fname)))) {
log_warn(LD_EXIT, "Unable to parse '%s', or no nameservers in '%s' (%d)",
conf_fname, conf_fname, r);
goto err;
if (!missing_resolv_conf) {
log_info(LD_EXIT, "Parsing resolver configuration in '%s'", conf_fname);
if ((r = evdns_base_resolv_conf_parse(the_evdns_base, flags,
sandbox_intern_string(conf_fname)))) {
log_warn(LD_EXIT, "Unable to parse '%s', or no nameservers "
"in '%s' (%d)", conf_fname, conf_fname, r);
if (r != 6) // "r = 6" means "no DNS servers were in resolv.conf" -
goto err; // in which case we expect libevent to add 127.0.0.1 as
// fallback.
}
if (evdns_base_count_nameservers(the_evdns_base) == 0) {
log_warn(LD_EXIT, "Unable to find any nameservers in '%s'.",
conf_fname);
}
tor_free(resolv_conf_fname);
resolv_conf_fname = tor_strdup(conf_fname);
resolv_conf_mtime = st.st_mtime;
} else {
log_warn(LD_EXIT, "Could not read your DNS config from '%s' - "
"please investigate your DNS configuration. "
"This is possibly a problem. Meanwhile, falling"
" back to local DNS at 127.0.0.1.", conf_fname);
evdns_base_nameserver_ip_add(the_evdns_base, "127.0.0.1");
}
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);
}

View file

@ -45,6 +45,11 @@ size_t dns_cache_handle_oom(time_t now, size_t min_remove_bytes);
#ifdef DNS_PRIVATE
#include "feature/relay/dns_structs.h"
size_t number_of_configured_nameservers(void);
#ifdef HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR
tor_addr_t *configured_nameserver_address(const size_t idx);
#endif
MOCK_DECL(STATIC int,dns_resolve_impl,(edge_connection_t *exitconn,
int is_resolve,or_circuit_t *oncirc, char **hostname_out,
int *made_connection_pending_out, cached_resolve_t **resolve_out));

View file

@ -1,6 +1,7 @@
/* Copyright (c) 2015-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#include "core/or/or.h"
#include "test/test.h"
@ -13,9 +14,71 @@
#include "core/or/edge_connection_st.h"
#include "core/or/or_circuit_st.h"
#include "app/config/or_options_st.h"
#include "app/config/config.h"
#include <event2/event.h>
#include <event2/dns.h>
#define NS_MODULE dns
#ifdef HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR
#define NS_SUBMODULE configure_nameservers_fallback
static or_options_t options = {
.ORPort_set = 1,
};
static const or_options_t *
mock_get_options(void)
{
return &options;
}
static void
NS(test_main)(void *arg)
{
(void)arg;
tor_addr_t *nameserver_addr = NULL;
MOCK(get_options, mock_get_options);
options.ServerDNSResolvConfFile = (char *)"no_such_file!!!";
dns_init(); // calls configure_nameservers()
tt_int_op(number_of_configured_nameservers(), OP_EQ, 1);
nameserver_addr = configured_nameserver_address(0);
tt_assert(tor_addr_family(nameserver_addr) == AF_INET);
tt_assert(tor_addr_eq_ipv4h(nameserver_addr, 0x7f000001));
#ifndef _WIN32
tor_free(nameserver_addr);
options.ServerDNSResolvConfFile = (char *)"/dev/null";
dns_init();
tt_int_op(number_of_configured_nameservers(), OP_EQ, 1);
nameserver_addr = configured_nameserver_address(0);
tt_assert(tor_addr_family(nameserver_addr) == AF_INET);
tt_assert(tor_addr_eq_ipv4h(nameserver_addr, 0x7f000001));
#endif
UNMOCK(get_options);
done:
tor_free(nameserver_addr);
return;
}
#undef NS_SUBMODULE
#endif
#define NS_SUBMODULE clip_ttl
static void
@ -736,6 +799,9 @@ NS(test_main)(void *arg)
#undef NS_SUBMODULE
struct testcase_t dns_tests[] = {
#ifdef HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR
TEST_CASE(configure_nameservers_fallback),
#endif
TEST_CASE(clip_ttl),
TEST_CASE(resolve),
TEST_CASE_ASPECT(resolve_impl, addr_is_ip_no_need_to_resolve),