소스 검색

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

Nick Mathewson 5 년 전
부모
커밋
30d853a906
6개의 변경된 파일152개의 추가작업 그리고 18개의 파일을 삭제
  1. 4 0
      changes/bug21900
  2. 2 0
      configure.ac
  3. 2 1
      doc/tor.1.txt
  4. 73 17
      src/feature/relay/dns.c
  5. 5 0
      src/feature/relay/dns.h
  6. 66 0
      src/test/test_dns.c

+ 4 - 0
changes/bug21900

@@ -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.

+ 2 - 0
configure.ac

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

+ 2 - 1
doc/tor.1.txt

@@ -2211,7 +2211,8 @@ is non-zero):
     __filename__. The file format is the same as the standard Unix
     __filename__. The file format is the same as the standard Unix
     "**resolv.conf**" file (7). This option, like all other ServerDNS options,
     "**resolv.conf**" file (7). This option, like all other ServerDNS options,
     only affects name lookups that your server does on behalf of clients.
     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**::
 [[ServerDNSAllowBrokenConfig]] **ServerDNSAllowBrokenConfig** **0**|**1**::
     If this option is false, Tor exits immediately if there are problems
     If this option is false, Tor exits immediately if there are problems

+ 73 - 17
src/feature/relay/dns.c

@@ -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
 /** 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
  * 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
  * 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);
   evdns_set_log_fn(evdns_log_cb);
   if (conf_fname) {
   if (conf_fname) {
     log_debug(LD_FS, "stat()ing %s", 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",
       log_warn(LD_EXIT, "Unable to stat resolver configuration in '%s': %s",
                conf_fname, strerror(errno));
                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) {
         && st.st_mtime == resolv_conf_mtime) {
       log_info(LD_EXIT, "No change to '%s'", conf_fname);
       log_info(LD_EXIT, "No change to '%s'", conf_fname);
       return 0;
       return 0;
     }
     }
+
+    if (stat_res == 0 && st.st_size == 0)
+      missing_resolv_conf = 1;
+
     if (nameservers_configured) {
     if (nameservers_configured) {
       evdns_base_search_clear(the_evdns_base);
       evdns_base_search_clear(the_evdns_base);
       evdns_base_clear_nameservers_and_suspend(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"));
           sandbox_intern_string("/etc/hosts"));
     }
     }
 #endif /* defined(DNS_OPTION_HOSTSFILE) && defined(USE_LIBSECCOMP) */
 #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 (evdns_base_count_nameservers(the_evdns_base) == 0) {
-      log_warn(LD_EXIT, "Unable to find any nameservers in '%s'.", conf_fname);
-      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");
     }
     }
-    tor_free(resolv_conf_fname);
-    resolv_conf_fname = tor_strdup(conf_fname);
-    resolv_conf_mtime = st.st_mtime;
+
     if (nameservers_configured)
     if (nameservers_configured)
       evdns_base_resume(the_evdns_base);
       evdns_base_resume(the_evdns_base);
   }
   }

+ 5 - 0
src/feature/relay/dns.h

@@ -45,6 +45,11 @@ size_t dns_cache_handle_oom(time_t now, size_t min_remove_bytes);
 #ifdef DNS_PRIVATE
 #ifdef DNS_PRIVATE
 #include "feature/relay/dns_structs.h"
 #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,
 MOCK_DECL(STATIC int,dns_resolve_impl,(edge_connection_t *exitconn,
 int is_resolve,or_circuit_t *oncirc, char **hostname_out,
 int is_resolve,or_circuit_t *oncirc, char **hostname_out,
 int *made_connection_pending_out, cached_resolve_t **resolve_out));
 int *made_connection_pending_out, cached_resolve_t **resolve_out));

+ 66 - 0
src/test/test_dns.c

@@ -1,6 +1,7 @@
 /* Copyright (c) 2015-2018, The Tor Project, Inc. */
 /* Copyright (c) 2015-2018, The Tor Project, Inc. */
 /* See LICENSE for licensing information */
 /* See LICENSE for licensing information */
 
 
+#include "orconfig.h"
 #include "core/or/or.h"
 #include "core/or/or.h"
 #include "test/test.h"
 #include "test/test.h"
 
 
@@ -13,9 +14,71 @@
 
 
 #include "core/or/edge_connection_st.h"
 #include "core/or/edge_connection_st.h"
 #include "core/or/or_circuit_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
 #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
 #define NS_SUBMODULE clip_ttl
 
 
 static void
 static void
@@ -736,6 +799,9 @@ NS(test_main)(void *arg)
 #undef NS_SUBMODULE
 #undef NS_SUBMODULE
 
 
 struct testcase_t dns_tests[] = {
 struct testcase_t dns_tests[] = {
+#ifdef HAVE_EVDNS_BASE_GET_NAMESERVER_ADDR
+   TEST_CASE(configure_nameservers_fallback),
+#endif
    TEST_CASE(clip_ttl),
    TEST_CASE(clip_ttl),
    TEST_CASE(resolve),
    TEST_CASE(resolve),
    TEST_CASE_ASPECT(resolve_impl, addr_is_ip_no_need_to_resolve),
    TEST_CASE_ASPECT(resolve_impl, addr_is_ip_no_need_to_resolve),