From: Azat Khuzhin Date: Sun, 31 Mar 2019 22:47:00 +0000 (+0300) Subject: evdns: add DNS_OPTION_NAMESERVERS_NO_DEFAULT/EVDNS_BASE_NAMESERVERS_NO_DEFAULT X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e5b8f4c1925867d8e4cd7dc0390e5141d7ef1106;p=libevent evdns: add DNS_OPTION_NAMESERVERS_NO_DEFAULT/EVDNS_BASE_NAMESERVERS_NO_DEFAULT - DNS_OPTION_NAMESERVERS_NO_DEFAULT Do not "default" nameserver (i.e. "127.0.0.1:53") if there is no nameservers in resolv.conf, (iff DNS_OPTION_NAMESERVERS is set) - EVDNS_BASE_NAMESERVERS_NO_DEFAULT If EVDNS_BASE_INITIALIZE_NAMESERVERS isset, do not add default nameserver if there are no nameservers in resolv.conf (just set DNS_OPTION_NAMESERVERS_NO_DEFAULT internally) Fixes: #569 --- diff --git a/evdns.c b/evdns.c index b6863556..3cf6ef09 100644 --- a/evdns.c +++ b/evdns.c @@ -3327,10 +3327,16 @@ search_request_finished(struct evdns_request *const handle) { static void evdns_resolv_set_defaults(struct evdns_base *base, int flags) { + int add_default = flags & DNS_OPTION_NAMESERVERS; + if (flags & DNS_OPTION_NAMESERVERS_NO_DEFAULT) + add_default = 0; + /* if the file isn't found then we assume a local resolver */ ASSERT_LOCKED(base); - if (flags & DNS_OPTION_SEARCH) search_set_from_hostname(base); - if (flags & DNS_OPTION_NAMESERVERS) evdns_base_nameserver_ip_add(base,"127.0.0.1"); + if (flags & DNS_OPTION_SEARCH) + search_set_from_hostname(base); + if (add_default) + evdns_base_nameserver_ip_add(base, "127.0.0.1"); } #ifndef EVENT__HAVE_STRTOK_R @@ -3626,9 +3632,14 @@ evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char char *resolv; char *start; int err = 0; + int add_default; log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename); + add_default = flags & DNS_OPTION_NAMESERVERS; + if (flags & DNS_OPTION_NAMESERVERS_NO_DEFAULT) + add_default = 0; + if (flags & DNS_OPTION_HOSTSFILE) { char *fname = evdns_get_default_hosts_filename(); evdns_base_load_hosts(base, fname); @@ -3664,7 +3675,7 @@ evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char } } - if (!base->server_head && (flags & DNS_OPTION_NAMESERVERS)) { + if (!base->server_head && add_default) { /* no nameservers were configured. */ evdns_base_nameserver_ip_add(base, "127.0.0.1"); err = 6; @@ -3965,7 +3976,12 @@ evdns_base_new(struct event_base *event_base, int flags) TAILQ_INIT(&base->hostsdb); -#define EVDNS_BASE_ALL_FLAGS (0x8001) +#define EVDNS_BASE_ALL_FLAGS ( \ + EVDNS_BASE_INITIALIZE_NAMESERVERS | \ + EVDNS_BASE_DISABLE_WHEN_INACTIVE | \ + EVDNS_BASE_NAMESERVERS_NO_DEFAULT | \ + 0) + if (flags & ~EVDNS_BASE_ALL_FLAGS) { flags = EVDNS_BASE_INITIALIZE_NAMESERVERS; log(EVDNS_LOG_WARN, @@ -3976,10 +3992,15 @@ evdns_base_new(struct event_base *event_base, int flags) if (flags & EVDNS_BASE_INITIALIZE_NAMESERVERS) { int r; + int opts = DNS_OPTIONS_ALL; + if (flags & EVDNS_BASE_NAMESERVERS_NO_DEFAULT) { + opts |= DNS_OPTION_NAMESERVERS_NO_DEFAULT; + } + #ifdef _WIN32 r = evdns_base_config_windows_nameservers(base); #else - r = evdns_base_resolv_conf_parse(base, DNS_OPTIONS_ALL, "/etc/resolv.conf"); + r = evdns_base_resolv_conf_parse(base, opts, "/etc/resolv.conf"); #endif if (r == -1) { evdns_base_free_and_unlock(base, 0); diff --git a/include/event2/dns.h b/include/event2/dns.h index 358b30fd..3c548a1e 100644 --- a/include/event2/dns.h +++ b/include/event2/dns.h @@ -209,6 +209,9 @@ extern "C" { DNS_OPTION_HOSTSFILE | \ 0 \ ) +/* Do not "default" nameserver (i.e. "127.0.0.1:53") if there is no nameservers + * in resolv.conf, (iff DNS_OPTION_NAMESERVERS is set) */ +#define DNS_OPTION_NAMESERVERS_NO_DEFAULT 16 /* Obsolete name for DNS_QUERY_NO_SEARCH */ #define DNS_NO_SEARCH DNS_QUERY_NO_SEARCH @@ -233,6 +236,10 @@ struct event_base; /** Flag for evdns_base_new: Do not prevent the libevent event loop from * exiting when we have no active dns requests. */ #define EVDNS_BASE_DISABLE_WHEN_INACTIVE 0x8000 +/** Flag for evdns_base_new: If EVDNS_BASE_INITIALIZE_NAMESERVERS isset, do not + * add default nameserver if there are no nameservers in resolv.conf + * @see DNS_OPTION_NAMESERVERS_NO_DEFAULT */ +#define EVDNS_BASE_NAMESERVERS_NO_DEFAULT 0x10000 /** Initialize the asynchronous DNS library. @@ -243,7 +250,7 @@ struct event_base; @param event_base the event base to associate the dns client with @param flags any of EVDNS_BASE_INITIALIZE_NAMESERVERS| - EVDNS_BASE_DISABLE_WHEN_INACTIVE + EVDNS_BASE_DISABLE_WHEN_INACTIVE|EVDNS_BASE_NAMESERVERS_NO_DEFAULT @return evdns_base object if successful, or NULL if an error occurred. @see evdns_base_free() */ @@ -478,7 +485,7 @@ int evdns_base_set_option(struct evdns_base *base, const char *option, const cha @param base the evdns_base to which to apply this operation @param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC| - DNS_OPTION_HOSTSFILE|DNS_OPTIONS_ALL + DNS_OPTION_HOSTSFILE|DNS_OPTIONS_ALL|DNS_OPTION_NAMESERVERS_NO_DEFAULT @param filename the path to the resolv.conf file @return 0 if successful, or various positive error codes if an error occurred (see above) diff --git a/test/regress_dns.c b/test/regress_dns.c index 9f1d6283..25a5f5ac 100644 --- a/test/regress_dns.c +++ b/test/regress_dns.c @@ -204,7 +204,7 @@ dns_resolve_reverse(void *ptr) { struct in_addr in; struct event_base *base = event_base_new(); - struct evdns_base *dns = evdns_base_new(base, 1/* init name servers */); + struct evdns_base *dns = evdns_base_new(base, EVDNS_BASE_INITIALIZE_NAMESERVERS); struct evdns_request *req = NULL; tt_assert(base); @@ -1004,6 +1004,59 @@ end: event_base_free(inactive_base); } +static void +dns_initialize_nameservers_test(void *arg) +{ + struct basic_test_data *data = arg; + struct event_base *base = data->base; + struct evdns_base *dns = NULL; + + dns = evdns_base_new(base, 0); + tt_assert(dns); + tt_int_op(evdns_base_get_nameserver_addr(dns, 0, NULL, 0), ==, -1); + evdns_base_free(dns, 0); + + dns = evdns_base_new(base, EVDNS_BASE_INITIALIZE_NAMESERVERS); + tt_assert(dns); + tt_int_op(evdns_base_get_nameserver_addr(dns, 0, NULL, 0), ==, sizeof(struct sockaddr)); + +end: + if (dns) + evdns_base_free(dns, 0); +} +#ifndef _WIN32 +#define RESOLV_FILE "empty-resolv.conf" +static void +dns_nameservers_no_default_test(void *arg) +{ + struct basic_test_data *data = arg; + struct event_base *base = data->base; + struct evdns_base *dns = NULL; + int ok = access(RESOLV_FILE, R_OK); + + tt_assert(ok); + + dns = evdns_base_new(base, 0); + tt_assert(dns); + tt_int_op(evdns_base_get_nameserver_addr(dns, 0, NULL, 0), ==, -1); + + /* We cannot test + * EVDNS_BASE_INITIALIZE_NAMESERVERS|EVDNS_BASE_NAMESERVERS_NO_DEFAULT + * because we cannot mock "/etc/resolv.conf" (yet). */ + + evdns_base_resolv_conf_parse(dns, + DNS_OPTIONS_ALL|DNS_OPTION_NAMESERVERS_NO_DEFAULT, RESOLV_FILE); + tt_int_op(evdns_base_get_nameserver_addr(dns, 0, NULL, 0), ==, -1); + + evdns_base_resolv_conf_parse(dns, DNS_OPTIONS_ALL, RESOLV_FILE); + tt_int_op(evdns_base_get_nameserver_addr(dns, 0, NULL, 0), ==, sizeof(struct sockaddr)); + +end: + if (dns) + evdns_base_free(dns, 0); +} +#endif + /* === Test for bufferevent_socket_connect_hostname */ static int total_connected_or_failed = 0; @@ -2332,6 +2385,13 @@ struct testcase_t dns_testcases[] = { { "disable_when_inactive_no_ns", dns_disable_when_inactive_no_ns_test, TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, + { "initialize_nameservers", dns_initialize_nameservers_test, + TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, +#ifndef _WIN32 + { "nameservers_no_default", dns_nameservers_no_default_test, + TT_FORK|TT_NEED_BASE, &basic_setup, NULL }, +#endif + { "getaddrinfo_async", test_getaddrinfo_async, TT_FORK|TT_NEED_BASE, &basic_setup, (char*)"" }, { "getaddrinfo_cancel_stress", test_getaddrinfo_async_cancel_stress,