diff options
-rw-r--r-- | deps/cares/LICENSE.md | 2 | ||||
-rw-r--r-- | deps/cares/cares.gyp | 1 | ||||
-rw-r--r-- | deps/cares/include/ares.h | 2 | ||||
-rw-r--r-- | deps/cares/include/ares_build.h | 12 | ||||
-rw-r--r-- | deps/cares/include/ares_rules.h | 2 | ||||
-rw-r--r-- | deps/cares/src/RELEASE-NOTES | 72 | ||||
-rw-r--r-- | deps/cares/src/ares_android.c | 99 | ||||
-rw-r--r-- | deps/cares/src/ares_android.h | 1 | ||||
-rw-r--r-- | deps/cares/src/ares_create_query.c | 6 | ||||
-rw-r--r-- | deps/cares/src/ares_destroy.c | 7 | ||||
-rw-r--r-- | deps/cares/src/ares_gethostbyname.c | 11 | ||||
-rw-r--r-- | deps/cares/src/ares_getnameinfo.c | 11 | ||||
-rw-r--r-- | deps/cares/src/ares_init.c | 400 | ||||
-rw-r--r-- | deps/cares/src/ares_library_init.c | 16 | ||||
-rw-r--r-- | deps/cares/src/ares_options.c | 8 | ||||
-rw-r--r-- | deps/cares/src/ares_parse_ptr_reply.c | 6 | ||||
-rw-r--r-- | deps/cares/src/ares_private.h | 30 | ||||
-rw-r--r-- | deps/cares/src/ares_process.c | 29 | ||||
-rw-r--r-- | deps/cares/src/ares_search.c | 7 | ||||
-rw-r--r-- | deps/cares/src/ares_send.c | 6 | ||||
-rw-r--r-- | deps/cares/src/ares_strsplit.c | 174 | ||||
-rw-r--r-- | deps/cares/src/ares_strsplit.h | 42 | ||||
-rw-r--r-- | deps/cares/src/inet_ntop.c | 3 |
23 files changed, 662 insertions, 285 deletions
diff --git a/deps/cares/LICENSE.md b/deps/cares/LICENSE.md index 86b520b91d3..ad6bb52b729 100644 --- a/deps/cares/LICENSE.md +++ b/deps/cares/LICENSE.md @@ -1,6 +1,6 @@ # c-ares license -Copyright (c) 2007 - 2016, Daniel Stenberg with many contributors, see AUTHORS +Copyright (c) 2007 - 2018, Daniel Stenberg with many contributors, see AUTHORS file. Copyright 1998 by the Massachusetts Institute of Technology. diff --git a/deps/cares/cares.gyp b/deps/cares/cares.gyp index c5719f4d90c..be7931f7743 100644 --- a/deps/cares/cares.gyp +++ b/deps/cares/cares.gyp @@ -92,6 +92,7 @@ 'src/ares_strdup.c', 'src/ares_strdup.h', 'src/ares_strerror.c', + 'src/ares_strsplit.c', 'src/ares_timeout.c', 'src/ares__timeval.c', 'src/ares_version.c', diff --git a/deps/cares/include/ares.h b/deps/cares/include/ares.h index 65a82cb5b7e..06f60b33304 100644 --- a/deps/cares/include/ares.h +++ b/deps/cares/include/ares.h @@ -164,6 +164,7 @@ extern "C" { #define ARES_OPT_ROTATE (1 << 14) #define ARES_OPT_EDNSPSZ (1 << 15) #define ARES_OPT_NOROTATE (1 << 16) +#define ARES_OPT_RESOLVCONF (1 << 17) /* Nameinfo flag values */ #define ARES_NI_NOFQDN (1 << 0) @@ -270,6 +271,7 @@ struct ares_options { struct apattern *sortlist; int nsort; int ednspsz; + char *resolvconf_path; }; struct hostent; diff --git a/deps/cares/include/ares_build.h b/deps/cares/include/ares_build.h index f5535b38493..5e3ba9f0d8c 100644 --- a/deps/cares/include/ares_build.h +++ b/deps/cares/include/ares_build.h @@ -194,16 +194,14 @@ /* Data type definition of ares_ssize_t. */ #ifdef _WIN32 # ifdef _WIN64 - typedef __int64 ares_ssize_t; +# define CARES_TYPEOF_ARES_SSIZE_T __int64 # else - typedef long ares_ssize_t; +# define CARES_TYPEOF_ARES_SSIZE_T long # endif #else -# ifdef CARES_TYPEOF_ARES_SSIZE_T - typedef CARES_TYPEOF_ARES_SSIZE_T ares_ssize_t; -# else - typedef ssize_t ares_ssize_t; -# endif +# define CARES_TYPEOF_ARES_SSIZE_T ssize_t #endif +typedef CARES_TYPEOF_ARES_SSIZE_T ares_ssize_t; + #endif /* __CARES_BUILD_H */ diff --git a/deps/cares/include/ares_rules.h b/deps/cares/include/ares_rules.h index e617fdc6daa..cac23cf2e32 100644 --- a/deps/cares/include/ares_rules.h +++ b/deps/cares/include/ares_rules.h @@ -83,7 +83,7 @@ /* * Verify that the size previously defined and expected for - * ares_socklen_t is actually the the same as the one reported + * ares_socklen_t is actually the same as the one reported * by sizeof() at compile time. */ diff --git a/deps/cares/src/RELEASE-NOTES b/deps/cares/src/RELEASE-NOTES index 91230a325b9..62276fdf4e3 100644 --- a/deps/cares/src/RELEASE-NOTES +++ b/deps/cares/src/RELEASE-NOTES @@ -1,47 +1,43 @@ -c-ares version 1.14.0 +c-ares version 1.15.0 Changes: - o android: Introduce new ares_library_init_android() call for Oreo support. [5] + o Add ares_init_options() configurability for path to resolv.conf file [1] + o Ability to exclude building of tools (adig, ahost, acountry) in CMake [3] + o Android: Support for domain search suffix [4] + o Report ARES_ENOTFOUND for .onion domain names as per RFC7686. [13] Bug fixes: - - o Fix patch for CVE-2017-1000381 to not be overly aggressive. [1] - o win32: Preserve DNS server order returned by Windows when sorting and exclude - DNS servers in legacy subnets. [2] [4] - o win32: Support most recent Visual Studio 2017 - o gethostbyaddr should fail with ECANCELLED not ENOTFOUND when ares_cancel - is called. [3] - o win32: Exclude legacy ipv6 subnets [4] - o android: Applications compiled for Oreo can no longer use - __system_property_get and must use Java calls to retrieve DNS servers. - [5] [7] - o win32: Force use of ANSI functions [6] - o CMake minimum version is now 3.1 - o ares_gethostbyname.3: fix callback status values [8] - o docs: Document WSAStartup requirement [9] - o Fix a typo in init_by_resolv_conf [10] - o Android JNI code leaks local references in some cases [11] - o Force using the ANSI versions of WinAPI functions [12] + o AIX build fix for trying to include both nameser_compat.h and + onameser_compat.h [2] + o Windows: Improve DNS suffixes extracting from WinNT registry [5] + o Fix modern GCC warnings [6] + o Apply the IPv6 server blacklist to all nameserver sources, not just Windows + [7] + o Fix warnings emitted by MSVC when using -W4 [8] + o Prevent changing name servers while queries are outstanding [9] + o Harden and rationalize c-ares timeout computation [10] + o Distribute ares_android.h [11] + o ares_set_servers_csv() on failure should not leave channel in a bad state + [12] + o Add missing docs to distribution Thanks go to these friendly people for their efforts and contributions: - - AC Thompson, Anna Henningsen, Antonio Tajuelo, Brad House, Brad Spencer, - Christian Ammer, Daniel Stenberg, David Drysdale, David Hotham, Felix Yan, - Gergely Nagy, Gregor Jasny, Jakub Hrozek, John Schember, - Konstantinos Sofokleous, Roman Teterin, Sergey Kolomenkin, Sheel Bedi, - (18 contributors) + @afalin, Andi Schnebinger, Ben Noordhuis, Brad House, Brad Spencer, + David Hotham, @flyingdutchman23, John Schember, Ruslan Baratov, + Sarat Addepalli, Tobias Nießen (11 contributors) References to bug reports and discussions on issues: + [1] = https://github.com/c-ares/c-ares/issues/220 + [2] = https://github.com/c-ares/c-ares/issues/224 + [3] = https://github.com/c-ares/c-ares/issues/200 + [4] = https://github.com/c-ares/c-ares/issues/207 + [5] = https://github.com/c-ares/c-ares/pull/202 + [6] = https://github.com/c-ares/c-ares/pull/201 + [7] = https://github.com/c-ares/c-ares/pull/193 + [8] = https://github.com/c-ares/c-ares/pull/192 + [9] = https://github.com/c-ares/c-ares/pull/191 + [10] = https://github.com/c-ares/c-ares/pull/187 + [11] = https://c-ares.haxx.se/mail/c-ares-archive-2018-04/0000.shtml + [12] = https://c-ares.haxx.se/mail/c-ares-archive-2018-03/0000.shtml + [13] = https://github.com/c-ares/c-ares/issues/196 - [1] = https://github.com/c-ares/c-ares/commit/18ea99 - [2] = https://github.com/c-ares/c-ares/issues/150 - [3] = https://github.com/c-ares/c-ares/pull/138 - [4] = https://github.com/c-ares/c-ares/pull/144 - [5] = https://github.com/c-ares/c-ares/pull/148 - [6] = https://github.com/c-ares/c-ares/pull/142 - [7] = https://github.com/c-ares/c-ares/pull/175 - [8] = https://c-ares.haxx.se/mail/c-ares-archive-2011-06/0012.shtml - [9] = https://github.com/c-ares/c-ares/pull/180 - [10] = https://github.com/c-ares/c-ares/pull/160 - [11] = https://github.com/c-ares/c-ares/pull/175 - [12] = https://github.com/c-ares/c-ares/pull/142 diff --git a/deps/cares/src/ares_android.c b/deps/cares/src/ares_android.c index ab388110bde..bf77131b58c 100644 --- a/deps/cares/src/ares_android.c +++ b/deps/cares/src/ares_android.c @@ -30,6 +30,8 @@ static jmethodID android_cm_active_net_mid = NULL; static jmethodID android_cm_link_props_mid = NULL; /* LinkProperties.getDnsServers */ static jmethodID android_lp_dns_servers_mid = NULL; +/* LinkProperties.getDomains */ +static jmethodID android_lp_domains_mid = NULL; /* List.size */ static jmethodID android_list_size_mid = NULL; /* List.get */ @@ -139,6 +141,12 @@ int ares_library_init_android(jobject connectivity_manager) if (android_lp_dns_servers_mid == NULL) goto cleanup; + /* getDomains in API 21. */ + android_lp_domains_mid = jni_get_method_id(env, obj_cls, "getDomains", + "()Ljava/lang/String;"); + if (android_lp_domains_mid == NULL) + goto cleanup; + (*env)->DeleteLocalRef(env, obj_cls); obj_cls = jni_get_class(env, "java/util/List"); if (obj_cls == NULL) @@ -173,6 +181,7 @@ cleanup: android_cm_active_net_mid = NULL; android_cm_link_props_mid = NULL; android_lp_dns_servers_mid = NULL; + android_lp_domains_mid = NULL; android_list_size_mid = NULL; android_list_get_mid = NULL; android_ia_host_addr_mid = NULL; @@ -213,6 +222,7 @@ void ares_library_cleanup_android(void) android_cm_active_net_mid = NULL; android_cm_link_props_mid = NULL; android_lp_dns_servers_mid = NULL; + android_lp_domains_mid = NULL; android_list_size_mid = NULL; android_list_get_mid = NULL; android_ia_host_addr_mid = NULL; @@ -341,6 +351,95 @@ done: (*android_jvm)->DetachCurrentThread(android_jvm); return dns_list; } + +char *ares_get_android_search_domains_list(void) +{ + JNIEnv *env = NULL; + jobject active_network = NULL; + jobject link_properties = NULL; + jstring domains = NULL; + const char *domain; + int res; + size_t i; + size_t cnt = 0; + char *domain_list = NULL; + int need_detatch = 0; + + if (android_jvm == NULL || android_connectivity_manager == NULL) + { + return NULL; + } + + if (android_cm_active_net_mid == NULL || android_cm_link_props_mid == NULL || + android_lp_domains_mid == NULL) + { + return NULL; + } + + res = (*android_jvm)->GetEnv(android_jvm, (void **)&env, JNI_VERSION_1_6); + if (res == JNI_EDETACHED) + { + env = NULL; + res = (*android_jvm)->AttachCurrentThread(android_jvm, &env, NULL); + need_detatch = 1; + } + if (res != JNI_OK || env == NULL) + goto done; + + /* JNI below is equivalent to this Java code. + import android.content.Context; + import android.net.ConnectivityManager; + import android.net.LinkProperties; + + ConnectivityManager cm = (ConnectivityManager)this.getApplicationContext() + .getSystemService(Context.CONNECTIVITY_SERVICE); + Network an = cm.getActiveNetwork(); + LinkProperties lp = cm.getLinkProperties(an); + String domains = lp.getDomains(); + for (String domain: domains.split(",")) { + String d = domain; + } + + Note: The JNI ConnectivityManager object and all method IDs were previously + initialized in ares_library_init_android. + */ + + active_network = (*env)->CallObjectMethod(env, android_connectivity_manager, + android_cm_active_net_mid); + if (active_network == NULL) + goto done; + + link_properties = + (*env)->CallObjectMethod(env, android_connectivity_manager, + android_cm_link_props_mid, active_network); + if (link_properties == NULL) + goto done; + + /* Get the domains. It is a common separated list of domains to search. */ + domains = (*env)->CallObjectMethod(env, link_properties, + android_lp_domains_mid); + if (domains == NULL) + goto done; + + /* Split on , */ + domain = (*env)->GetStringUTFChars(env, domains, 0); + domain_list = ares_strdup(domain); + (*env)->ReleaseStringUTFChars(env, domains, domain); + (*env)->DeleteLocalRef(env, domains); + +done: + if ((*env)->ExceptionOccurred(env)) + (*env)->ExceptionClear(env); + + if (link_properties != NULL) + (*env)->DeleteLocalRef(env, link_properties); + if (active_network != NULL) + (*env)->DeleteLocalRef(env, active_network); + + if (need_detatch) + (*android_jvm)->DetachCurrentThread(android_jvm); + return domain_list; +} #else /* warning: ISO C forbids an empty translation unit */ typedef int dummy_make_iso_compilers_happy; diff --git a/deps/cares/src/ares_android.h b/deps/cares/src/ares_android.h index ff520f96e8e..93fb75f5850 100644 --- a/deps/cares/src/ares_android.h +++ b/deps/cares/src/ares_android.h @@ -19,6 +19,7 @@ #if defined(ANDROID) || defined(__ANDROID__) char **ares_get_android_server_list(size_t max_servers, size_t *num_servers); +char *ares_get_android_search_domains_list(void); void ares_library_cleanup_android(void); #endif diff --git a/deps/cares/src/ares_create_query.c b/deps/cares/src/ares_create_query.c index 07d75701144..1606b1a1004 100644 --- a/deps/cares/src/ares_create_query.c +++ b/deps/cares/src/ares_create_query.c @@ -94,6 +94,10 @@ int ares_create_query(const char *name, int dnsclass, int type, size_t buflen; unsigned char *buf; + /* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */ + if (ares__is_onion_domain(name)) + return ARES_ENOTFOUND; + /* Set our results early, in case we bail out early with an error. */ *buflenp = 0; *bufp = NULL; @@ -188,7 +192,7 @@ int ares_create_query(const char *name, int dnsclass, int type, * specified in RFC 1035 ("To simplify implementations, the total length of * a domain name (i.e., label octets and label length octets) is restricted * to 255 octets or less."). */ - if (buflen > (MAXCDNAME + HFIXEDSZ + QFIXEDSZ + + if (buflen > (size_t)(MAXCDNAME + HFIXEDSZ + QFIXEDSZ + (max_udp_size ? EDNSFIXEDSZ : 0))) { ares_free (buf); return ARES_EBADNAME; diff --git a/deps/cares/src/ares_destroy.c b/deps/cares/src/ares_destroy.c index 8aa42236aec..fed2009ab32 100644 --- a/deps/cares/src/ares_destroy.c +++ b/deps/cares/src/ares_destroy.c @@ -36,6 +36,8 @@ void ares_destroy_options(struct ares_options *options) ares_free(options->sortlist); if(options->lookups) ares_free(options->lookups); + if(options->resolvconf_path) + ares_free(options->resolvconf_path); } void ares_destroy(ares_channel channel) @@ -44,7 +46,7 @@ void ares_destroy(ares_channel channel) struct query *query; struct list_node* list_head; struct list_node* list_node; - + if (!channel) return; @@ -85,6 +87,9 @@ void ares_destroy(ares_channel channel) if (channel->lookups) ares_free(channel->lookups); + if (channel->resolvconf_path) + ares_free(channel->resolvconf_path); + ares_free(channel); } diff --git a/deps/cares/src/ares_gethostbyname.c b/deps/cares/src/ares_gethostbyname.c index 7c46d96ceaf..8187746bb14 100644 --- a/deps/cares/src/ares_gethostbyname.c +++ b/deps/cares/src/ares_gethostbyname.c @@ -95,6 +95,13 @@ void ares_gethostbyname(ares_channel channel, const char *name, int family, return; } + /* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */ + if (ares__is_onion_domain(name)) + { + callback(arg, ARES_ENOTFOUND, 0, NULL); + return; + } + if (fake_hostent(name, family, callback, arg)) return; @@ -339,6 +346,10 @@ static int file_lookup(const char *name, int family, struct hostent **host) int status; int error; + /* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */ + if (ares__is_onion_domain(name)) + return ARES_ENOTFOUND; + #ifdef WIN32 char PATH_HOSTS[MAX_PATH]; win_platform platform; diff --git a/deps/cares/src/ares_getnameinfo.c b/deps/cares/src/ares_getnameinfo.c index c77b1f81537..aa089417060 100644 --- a/deps/cares/src/ares_getnameinfo.c +++ b/deps/cares/src/ares_getnameinfo.c @@ -440,3 +440,14 @@ STATIC_TESTABLE char *ares_striendstr(const char *s1, const char *s2) } return (char *)c1_begin; } + +int ares__is_onion_domain(const char *name) +{ + if (ares_striendstr(name, ".onion")) + return 1; + + if (ares_striendstr(name, ".onion.")) + return 1; + + return 0; +} diff --git a/deps/cares/src/ares_init.c b/deps/cares/src/ares_init.c index 90cfcabdd33..c2c00d65237 100644 --- a/deps/cares/src/ares_init.c +++ b/deps/cares/src/ares_init.c @@ -169,6 +169,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options, channel->sock_config_cb_data = NULL; channel->sock_funcs = NULL; channel->sock_func_cb_data = NULL; + channel->resolvconf_path = NULL; channel->last_server = 0; channel->last_timeout_processed = (time_t)now.tv_sec; @@ -236,16 +237,14 @@ done: /* Something failed; clean up memory we may have allocated. */ if (channel->servers) ares_free(channel->servers); - if (channel->domains) - { - for (i = 0; i < channel->ndomains; i++) - ares_free(channel->domains[i]); - ares_free(channel->domains); - } + if (channel->ndomains != -1) + ares_strsplit_free(channel->domains, channel->ndomains); if (channel->sortlist) ares_free(channel->sortlist); if(channel->lookups) ares_free(channel->lookups); + if(channel->resolvconf_path) + ares_free(channel->resolvconf_path); ares_free(channel); return status; } @@ -299,7 +298,7 @@ int ares_dup(ares_channel *dest, ares_channel src) (*dest)->sock_func_cb_data = src->sock_func_cb_data; strncpy((*dest)->local_dev_name, src->local_dev_name, - sizeof(src->local_dev_name)); + sizeof((*dest)->local_dev_name)); (*dest)->local_ip4 = src->local_ip4; memcpy((*dest)->local_ip6, src->local_ip6, sizeof(src->local_ip6)); @@ -354,6 +353,9 @@ int ares_save_options(ares_channel channel, struct ares_options *options, ARES_OPT_SORTLIST|ARES_OPT_TIMEOUTMS); (*optmask) |= (channel->rotate ? ARES_OPT_ROTATE : ARES_OPT_NOROTATE); + if (channel->resolvconf_path) + (*optmask) |= ARES_OPT_RESOLVCONF; + /* Copy easy stuff */ options->flags = channel->flags; @@ -426,6 +428,13 @@ int ares_save_options(ares_channel channel, struct ares_options *options, } options->nsort = channel->nsort; + /* copy path for resolv.conf file */ + if (channel->resolvconf_path) { + options->resolvconf_path = ares_strdup(channel->resolvconf_path); + if (!options->resolvconf_path) + return ARES_ENOMEM; + } + return ARES_SUCCESS; } @@ -534,6 +543,14 @@ static int init_by_options(ares_channel channel, channel->nsort = options->nsort; } + /* Set path for resolv.conf file, if given. */ + if ((optmask & ARES_OPT_RESOLVCONF) && !channel->resolvconf_path) + { + channel->resolvconf_path = ares_strdup(options->resolvconf_path); + if (!channel->resolvconf_path && options->resolvconf_path) + return ARES_ENOMEM; + } + channel->optmask = optmask; return ARES_SUCCESS; @@ -997,63 +1014,6 @@ static int compareAddresses(const void *arg1, return 0; } -/* Validate that the ip address matches the subnet (network base and network - * mask) specified. Addresses are specified in standard Network Byte Order as - * 16 bytes, and the netmask is 0 to 128 (bits). - */ -static int ares_ipv6_subnet_matches(const unsigned char netbase[16], - unsigned char netmask, - const unsigned char ipaddr[16]) -{ - unsigned char mask[16] = { 0 }; - unsigned char i; - - /* Misuse */ - if (netmask > 128) - return 0; - - /* Quickly set whole bytes */ - memset(mask, 0xFF, netmask / 8); - - /* Set remaining bits */ - if(netmask % 8) { - mask[netmask / 8] = (unsigned char)(0xff << (8 - (netmask % 8))); - } - - for (i=0; i<16; i++) { - if ((netbase[i] & mask[i]) != (ipaddr[i] & mask[i])) - return 0; - } - - return 1; -} - -static int ares_ipv6_server_blacklisted(const unsigned char ipaddr[16]) -{ - const struct { - const char *netbase; - unsigned char netmask; - } blacklist[] = { - /* Deprecated by [RFC3879] in September 2004. Formerly a Site-Local scoped - * address prefix. Causes known issues on Windows as these are not valid DNS - * servers. */ - { "fec0::", 10 }, - { NULL, 0 } - }; - size_t i; - - for (i=0; blacklist[i].netbase != NULL; i++) { - unsigned char netbase[16]; - - if (ares_inet_pton(AF_INET6, blacklist[i].netbase, netbase) != 1) - continue; - - if (ares_ipv6_subnet_matches(netbase, blacklist[i].netmask, ipaddr)) - return 1; - } - return 0; -} - /* There can be multiple routes to "the Internet". And there can be different * DNS servers associated with each of the interfaces that offer those routes. * We have to assume that any DNS server can serve any request. But, some DNS @@ -1257,7 +1217,7 @@ static int get_DNS_AdaptersAddresses(char **outptr) } else { - addresses[addressesIndex].metric = -1; + addresses[addressesIndex].metric = (ULONG)-1; } /* Record insertion index to make qsort stable */ @@ -1272,20 +1232,10 @@ static int get_DNS_AdaptersAddresses(char **outptr) } else if (namesrvr.sa->sa_family == AF_INET6) { - /* Windows apparently always reports some IPv6 DNS servers that - * prefixed with fec0:0:0:ffff. These ususally do not point to - * working DNS servers, so we ignore them. */ - if (strncmp(addresses[addressesIndex].text, "fec0:0:0:ffff:", 14) == 0) - continue; if (memcmp(&namesrvr.sa6->sin6_addr, &ares_in6addr_any, sizeof(namesrvr.sa6->sin6_addr)) == 0) continue; - if (ares_ipv6_server_blacklisted( - (const unsigned char *)&namesrvr.sa6->sin6_addr) - ) - continue; - /* Allocate room for another address, if necessary, else skip. */ if(addressesIndex == addressesSize) { const size_t newSize = addressesSize + 4; @@ -1309,7 +1259,7 @@ static int get_DNS_AdaptersAddresses(char **outptr) } else { - addresses[addressesIndex].metric = -1; + addresses[addressesIndex].metric = (ULONG)-1; } /* Record insertion index to make qsort stable */ @@ -1394,59 +1344,6 @@ static int get_DNS_Windows(char **outptr) return get_DNS_Registry(outptr); } -static void replace_comma_by_space(char* str) -{ - /* replace ',' by ' ' to coincide with resolv.conf search parameter */ - char *p; - for (p = str; *p != '\0'; p++) - { - if (*p == ',') - *p = ' '; - } -} - -/* Search if 'suffix' is containted in the 'searchlist'. Returns true if yes, - * otherwise false. 'searchlist' is a comma separated list of domain suffixes, - * 'suffix' is one domain suffix, 'len' is the length of 'suffix'. - * The search ignores case. E.g.: - * contains_suffix("abc.def,ghi.jkl", "ghi.JKL") returns true */ -static bool contains_suffix(const char* const searchlist, - const char* const suffix, const size_t len) -{ - const char* beg = searchlist; - const char* end; - if (!*suffix) - return true; - for (;;) - { - while (*beg && (ISSPACE(*beg) || (*beg == ','))) - ++beg; - if (!*beg) - return false; - end = beg; - while (*end && !ISSPACE(*end) && (*end != ',')) - ++end; - if (len == (end - beg) && !strnicmp(beg, suffix, len)) - return true; - beg = end; - } -} - -/* advances list to the next suffix within a comma separated search list. - * len is the length of the next suffix. */ -static size_t next_suffix(const char** list, const size_t advance) -{ - const char* beg = *list + advance; - const char* end; - while (*beg && (ISSPACE(*beg) || (*beg == ','))) - ++beg; - end = beg; - while (*end && !ISSPACE(*end) && (*end != ',')) - ++end; - *list = beg; - return end - beg; -} - /* * get_SuffixList_Windows() * @@ -1467,8 +1364,6 @@ static int get_SuffixList_Windows(char **outptr) DWORD keyNameBuffSize; DWORD keyIdx = 0; char *p = NULL; - const char *pp; - size_t len = 0; *outptr = NULL; @@ -1479,11 +1374,26 @@ static int get_SuffixList_Windows(char **outptr) if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { - if (get_REG_SZ(hKey, SEARCHLIST_KEY, outptr)) - replace_comma_by_space(*outptr); + get_REG_SZ(hKey, SEARCHLIST_KEY, outptr); + if (get_REG_SZ(hKey, DOMAIN_KEY, &p)) + { + commajoin(outptr, p); + ares_free(p); + p = NULL; + } + RegCloseKey(hKey); + } + + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NT_DNSCLIENT, 0, + KEY_READ, &hKey) == ERROR_SUCCESS) + { + if (get_REG_SZ(hKey, SEARCHLIST_KEY, &p)) + { + commajoin(outptr, p); + ares_free(p); + p = NULL; + } RegCloseKey(hKey); - if (*outptr) - return 1; } /* 2. Connection Specific Search List composed of: @@ -1491,45 +1401,53 @@ static int get_SuffixList_Windows(char **outptr) if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_DNSCLIENT, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { - get_REG_SZ(hKey, PRIMARYDNSSUFFIX_KEY, outptr); + if (get_REG_SZ(hKey, PRIMARYDNSSUFFIX_KEY, &p)) + { + commajoin(outptr, p); + ares_free(p); + p = NULL; + } RegCloseKey(hKey); } - if (!*outptr) - return 0; /* b. Interface SearchList, Domain, DhcpDomain */ - if (!RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY "\\" INTERFACES_KEY, 0, + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY "\\" INTERFACES_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS) - return 0; - for(;;) { - keyNameBuffSize = sizeof(keyName); - if (RegEnumKeyExA(hKey, keyIdx++, keyName, &keyNameBuffSize, - 0, NULL, NULL, NULL) - != ERROR_SUCCESS) - break; - if (RegOpenKeyExA(hKey, keyName, 0, KEY_QUERY_VALUE, &hKeyEnum) - != ERROR_SUCCESS) - continue; - if (get_REG_SZ(hKeyEnum, SEARCHLIST_KEY, &p) || - get_REG_SZ(hKeyEnum, DOMAIN_KEY, &p) || - get_REG_SZ(hKeyEnum, DHCPDOMAIN_KEY, &p)) + for(;;) { + keyNameBuffSize = sizeof(keyName); + if (RegEnumKeyExA(hKey, keyIdx++, keyName, &keyNameBuffSize, + 0, NULL, NULL, NULL) + != ERROR_SUCCESS) + break; + if (RegOpenKeyExA(hKey, keyName, 0, KEY_QUERY_VALUE, &hKeyEnum) + != ERROR_SUCCESS) + continue; /* p can be comma separated (SearchList) */ - pp = p; - while ((len = next_suffix(&pp, len)) != 0) + if (get_REG_SZ(hKeyEnum, SEARCHLIST_KEY, &p)) { - if (!contains_suffix(*outptr, pp, len)) - commanjoin(outptr, pp, len); + commajoin(outptr, p); + ares_free(p); + p = NULL; } - ares_free(p); - p = NULL; + if (get_REG_SZ(hKeyEnum, DOMAIN_KEY, &p)) + { + commajoin(outptr, p); + ares_free(p); + p = NULL; + } + if (get_REG_SZ(hKeyEnum, DHCPDOMAIN_KEY, &p)) + { + commajoin(outptr, p); + ares_free(p); + p = NULL; + } + RegCloseKey(hKeyEnum); } - RegCloseKey(hKeyEnum); + RegCloseKey(hKey); } - RegCloseKey(hKey); - if (*outptr) - replace_comma_by_space(*outptr); + return *outptr != NULL; } @@ -1628,6 +1546,7 @@ static int init_by_resolv_conf(ares_channel channel) char propname[PROP_NAME_MAX]; char propvalue[PROP_VALUE_MAX]=""; char **dns_servers; + char *domains; size_t num_servers; /* Use the Android connectivity manager to get a list @@ -1652,6 +1571,12 @@ static int init_by_resolv_conf(ares_channel channel) } ares_free(dns_servers); } + if (channel->ndomains == -1) + { + domains = ares_get_android_search_domains_list(); + set_search(channel, domains); + ares_free(domains); + } # ifdef HAVE___SYSTEM_PROPERTY_GET /* Old way using the system property still in place as @@ -1740,6 +1665,7 @@ static int init_by_resolv_conf(ares_channel channel) size_t linesize; int error; int update_domains; + const char *resolvconf_path; /* Don't read resolv.conf and friends if we don't have to */ if (ARES_CONFIG_CHECK(channel)) @@ -1748,7 +1674,14 @@ static int init_by_resolv_conf(ares_channel channel) /* Only update search domains if they're not already specified */ update_domains = (channel->ndomains == -1); - fp = fopen(PATH_RESOLV_CONF, "r"); + /* Support path for resolvconf filename set by ares_init_options */ + if(channel->resolvconf_path) { + resolvconf_path = channel->resolvconf_path; + } else { + resolvconf_path = PATH_RESOLV_CONF; + } + + fp = fopen(resolvconf_path, "r"); if (fp) { while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS) { @@ -1759,10 +1692,10 @@ static int init_by_resolv_conf(ares_channel channel) else if ((p = try_config(line, "search", ';')) && update_domains) status = set_search(channel, p); else if ((p = try_config(line, "nameserver", ';')) && - channel->nservers == -1) + channel->nservers == -1) status = config_nameserver(&servers, &nservers, p); else if ((p = try_config(line, "sortlist", ';')) && - channel->nsort == -1) + channel->nsort == -1) status = config_sortlist(&sortlist, &nsort, p); else if ((p = try_config(line, "options", ';'))) status = set_options(channel, p); @@ -1782,7 +1715,7 @@ static int init_by_resolv_conf(ares_channel channel) break; default: DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n", - error, strerror(error))); + error, strerror(error))); DEBUGF(fprintf(stderr, "Error opening file: %s\n", PATH_RESOLV_CONF)); status = ARES_EFILE; } @@ -2050,6 +1983,11 @@ static int init_by_defaults(ares_channel channel) ares_free(channel->lookups); channel->lookups = NULL; } + + if(channel->resolvconf_path) { + ares_free(channel->resolvconf_path); + channel->resolvconf_path = NULL; + } } if(hostname) @@ -2114,6 +2052,76 @@ static int config_lookup(ares_channel channel, const char *str, #endif /* !WIN32 & !WATT32 & !ANDROID & !__ANDROID__ & !CARES_USE_LIBRESOLV */ #ifndef WATT32 +/* Validate that the ip address matches the subnet (network base and network + * mask) specified. Addresses are specified in standard Network Byte Order as + * 16 bytes, and the netmask is 0 to 128 (bits). + */ +static int ares_ipv6_subnet_matches(const unsigned char netbase[16], + unsigned char netmask, + const unsigned char ipaddr[16]) +{ + unsigned char mask[16] = { 0 }; + unsigned char i; + + /* Misuse */ + if (netmask > 128) + return 0; + + /* Quickly set whole bytes */ + memset(mask, 0xFF, netmask / 8); + + /* Set remaining bits */ + if(netmask % 8) { + mask[netmask / 8] = (unsigned char)(0xff << (8 - (netmask % 8))); + } + + for (i=0; i<16; i++) { + if ((netbase[i] & mask[i]) != (ipaddr[i] & mask[i])) + return 0; + } + + return 1; +} + +/* Return true iff the IPv6 ipaddr is blacklisted. */ +static int ares_ipv6_server_blacklisted(const unsigned char ipaddr[16]) +{ + /* A list of blacklisted IPv6 subnets. */ + const struct { + const unsigned char netbase[16]; + unsigned char netmask; + } blacklist[] = { + /* fec0::/10 was deprecated by [RFC3879] in September 2004. Formerly a + * Site-Local scoped address prefix. These are never valid DNS servers, + * but are known to be returned at least sometimes on Windows and Android. + */ + { + { + 0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + 10 + } + }; + size_t i; + + /* See if ipaddr matches any of the entries in the blacklist. */ + for (i = 0; i < sizeof(blacklist) / sizeof(blacklist[0]); ++i) { + if (ares_ipv6_subnet_matches( + blacklist[i].netbase, blacklist[i].netmask, ipaddr)) + return 1; + } + return 0; +} + +/* Add the IPv4 or IPv6 nameservers in str (separated by commas) to the + * servers list, updating servers and nservers as required. + * + * This will silently ignore blacklisted IPv6 nameservers as detected by + * ares_ipv6_server_blacklisted(). + * + * Returns an error code on failure, else ARES_SUCCESS. + */ static int config_nameserver(struct server_state **servers, int *nservers, char *str) { @@ -2148,7 +2156,10 @@ static int config_nameserver(struct server_state **servers, int *nservers, /* Convert textual address to binary format. */ if (ares_inet_pton(AF_INET, txtaddr, &host.addrV4) == 1) host.family = AF_INET; - else if (ares_inet_pton(AF_INET6, txtaddr, &host.addrV6) == 1) + else if (ares_inet_pton(AF_INET6, txtaddr, &host.addrV6) == 1 + /* Silently skip blacklisted IPv6 servers. */ + && !ares_ipv6_server_blacklisted( + (const unsigned char *)&host.addrV6)) host.family = AF_INET6; else continue; @@ -2271,61 +2282,22 @@ static int config_sortlist(struct apattern **sortlist, int *nsort, static int set_search(ares_channel channel, const char *str) { - int n; - const char *p, *q; + size_t cnt; if(channel->ndomains != -1) { /* LCOV_EXCL_START: all callers check ndomains == -1 */ /* if we already have some domains present, free them first */ - for(n=0; n < channel->ndomains; n++) - ares_free(channel->domains[n]); - ares_free(channel->domains); + ares_strsplit_free(channel->domains, channel->ndomains); channel->domains = NULL; channel->ndomains = -1; } /* LCOV_EXCL_STOP */ - /* Count the domains given. */ - n = 0; - p = str; - while (*p) - { - while (*p && !ISSPACE(*p)) - p++; - while (ISSPACE(*p)) - p++; - n++; - } - - if (!n) - { - channel->ndomains = 0; - return ARES_SUCCESS; - } - - channel->domains = ares_malloc(n * sizeof(char *)); - if (!channel->domains) - return ARES_ENOMEM; - - /* Now copy the domains. */ - n = 0; - p = str; - while (*p) - { - channel->ndomains = n; - q = p; - while (*q && !ISSPACE(*q)) - q++; - channel->domains[n] = ares_malloc(q - p + 1); - if (!channel->domains[n]) - return ARES_ENOMEM; - memcpy(channel->domains[n], p, q - p); - channel->domains[n][q - p] = 0; - p = q; - while (ISSPACE(*p)) - p++; - n++; - } - channel->ndomains = n; + channel->domains = ares_strsplit(str, ", ", 1, &cnt); + channel->ndomains = (int)cnt; + if (channel->domains == NULL || channel->ndomains == 0) { + channel->domains = NULL; + channel->ndomains = -1; + } return ARES_SUCCESS; } diff --git a/deps/cares/src/ares_library_init.c b/deps/cares/src/ares_library_init.c index 88e7a537480..67563499bec 100644 --- a/deps/cares/src/ares_library_init.c +++ b/deps/cares/src/ares_library_init.c @@ -40,9 +40,19 @@ static unsigned int ares_initialized; static int ares_init_flags; /* library-private global vars with visibility across the whole library */ -void *(*ares_malloc)(size_t size) = malloc; -void *(*ares_realloc)(void *ptr, size_t size) = realloc; -void (*ares_free)(void *ptr) = free; +#if defined(WIN32) +/* We need indirections to handle Windows DLL rules. */ +static void *default_malloc(size_t size) { return malloc(size); } +static void *default_realloc(void *p, size_t size) { return realloc(p, size); } +static void default_free(void *p) { free(p); } +#else +# define default_malloc malloc +# define default_realloc realloc +# define default_free free +#endif +void *(*ares_malloc)(size_t size) = default_malloc; +void *(*ares_realloc)(void *ptr, size_t size) = default_realloc; +void (*ares_free)(void *ptr) = default_free; #ifdef USE_WINSOCK static HMODULE hnd_iphlpapi; diff --git a/deps/cares/src/ares_options.c b/deps/cares/src/ares_options.c index c3cbd1df707..de49de46259 100644 --- a/deps/cares/src/ares_options.c +++ b/deps/cares/src/ares_options.c @@ -153,6 +153,9 @@ int ares_set_servers(ares_channel channel, if (!channel) return ARES_ENODATA; + if (!ares__is_list_empty(&channel->all_queries)) + return ARES_ENOTIMP; + ares__destroy_servers_state(channel); for (srvr = servers; srvr; srvr = srvr->next) @@ -202,6 +205,9 @@ int ares_set_servers_ports(ares_channel channel, if (!channel) return ARES_ENODATA; + if (!ares__is_list_empty(&channel->all_queries)) + return ARES_ENOTIMP; + ares__destroy_servers_state(channel); for (srvr = servers; srvr; srvr = srvr->next) @@ -258,8 +264,6 @@ static int set_servers_csv(ares_channel channel, if (!channel) return ARES_ENODATA; - ares__destroy_servers_state(channel); - i = strlen(_csv); if (i == 0) return ARES_SUCCESS; /* blank all servers */ diff --git a/deps/cares/src/ares_parse_ptr_reply.c b/deps/cares/src/ares_parse_ptr_reply.c index 976a5311a24..29e22cb17b6 100644 --- a/deps/cares/src/ares_parse_ptr_reply.c +++ b/deps/cares/src/ares_parse_ptr_reply.c @@ -52,6 +52,7 @@ int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr, int aliascnt = 0; int alias_alloc = 8; char ** aliases; + size_t rr_data_len; /* Set *host to NULL for all failure cases. */ *host = NULL; @@ -124,14 +125,15 @@ int ares_parse_ptr_reply(const unsigned char *abuf, int alen, const void *addr, if (hostname) ares_free(hostname); hostname = rr_data; - aliases[aliascnt] = ares_malloc((strlen(rr_data)+1) * sizeof(char)); + rr_data_len = strlen(rr_data)+1; + aliases[aliascnt] = ares_malloc(rr_data_len * sizeof(char)); if (!aliases[aliascnt]) { ares_free(rr_name); status = ARES_ENOMEM; break; } - strncpy(aliases[aliascnt], rr_data, strlen(rr_data)+1); + strncpy(aliases[aliascnt], rr_data, rr_data_len); aliascnt++; if (aliascnt >= alias_alloc) { char **ptr; diff --git a/deps/cares/src/ares_private.h b/deps/cares/src/ares_private.h index 5d773869c72..1990f6902fc 100644 --- a/deps/cares/src/ares_private.h +++ b/deps/cares/src/ares_private.h @@ -52,18 +52,19 @@ #if defined(WIN32) && !defined(WATT32) -#define WIN_NS_9X "System\\CurrentControlSet\\Services\\VxD\\MSTCP" -#define WIN_NS_NT_KEY "System\\CurrentControlSet\\Services\\Tcpip\\Parameters" -#define WIN_DNSCLIENT "Software\\Policies\\Microsoft\\System\\DNSClient" -#define NAMESERVER "NameServer" -#define DHCPNAMESERVER "DhcpNameServer" -#define DATABASEPATH "DatabasePath" -#define WIN_PATH_HOSTS "\\hosts" -#define SEARCHLIST_KEY "SearchList" +#define WIN_NS_9X "System\\CurrentControlSet\\Services\\VxD\\MSTCP" +#define WIN_NS_NT_KEY "System\\CurrentControlSet\\Services\\Tcpip\\Parameters" +#define WIN_DNSCLIENT "Software\\Policies\\Microsoft\\System\\DNSClient" +#define WIN_NT_DNSCLIENT "Software\\Policies\\Microsoft\\Windows NT\\DNSClient" +#define NAMESERVER "NameServer" +#define DHCPNAMESERVER "DhcpNameServer" +#define DATABASEPATH "DatabasePath" +#define WIN_PATH_HOSTS "\\hosts" +#define SEARCHLIST_KEY "SearchList" #define PRIMARYDNSSUFFIX_KEY "PrimaryDNSSuffix" -#define INTERFACES_KEY "Interfaces" -#define DOMAIN_KEY "Domain" -#define DHCPDOMAIN_KEY "DhcpDomain" +#define INTERFACES_KEY "Interfaces" +#define DOMAIN_KEY "Domain" +#define DHCPDOMAIN_KEY "DhcpDomain" #elif defined(WATT32) @@ -100,6 +101,7 @@ #endif #include "ares_strdup.h" +#include "ares_strsplit.h" #ifndef HAVE_STRCASECMP # include "ares_strcasecmp.h" @@ -323,8 +325,14 @@ struct ares_channeldata { const struct ares_socket_functions * sock_funcs; void *sock_func_cb_data; + + /* Path for resolv.conf file, configurable via ares_options */ + char *resolvconf_path; }; +/* Does the domain end in ".onion" or ".onion."? Case-insensitive. */ +int ares__is_onion_domain(const char *name); + /* Memory management functions */ extern void *(*ares_malloc)(size_t size); extern void *(*ares_realloc)(void *ptr, size_t size); diff --git a/deps/cares/src/ares_process.c b/deps/cares/src/ares_process.c index df85524f624..df9f290bb13 100644 --- a/deps/cares/src/ares_process.c +++ b/deps/cares/src/ares_process.c @@ -53,6 +53,7 @@ #include <assert.h> #include <fcntl.h> +#include <limits.h> #include "ares.h" #include "ares_dns.h" @@ -871,8 +872,32 @@ void ares__send_query(ares_channel channel, struct query *query, return; } } - timeplus = channel->timeout << (query->try_count / channel->nservers); - timeplus = (timeplus * (9 + (rand () & 7))) / 16; + + /* For each trip through the entire server list, double the channel's + * assigned timeout, avoiding overflow. If channel->timeout is negative, + * leave it as-is, even though that should be impossible here. + */ + timeplus = channel->timeout; + { + /* How many times do we want to double it? Presume sane values here. */ + const int shift = query->try_count / channel->nservers; + + /* Is there enough room to shift timeplus left that many times? + * + * To find out, confirm that all of the bits we'll shift away are zero. + * Stop considering a shift if we get to the point where we could shift + * a 1 into the sign bit (i.e. when shift is within two of the bit + * count). + * + * This has the side benefit of leaving negative numbers unchanged. + */ + if(shift <= (int)(sizeof(int) * CHAR_BIT - 1) + && (timeplus >> (sizeof(int) * CHAR_BIT - 1 - shift)) == 0) + { + timeplus <<= shift; + } + } + query->timeout = *now; timeadd(&query->timeout, timeplus); /* Keep track of queries bucketed by timeout, so we can process diff --git a/deps/cares/src/ares_search.c b/deps/cares/src/ares_search.c index 68e852574f0..001c3482a7d 100644 --- a/deps/cares/src/ares_search.c +++ b/deps/cares/src/ares_search.c @@ -54,6 +54,13 @@ void ares_search(ares_channel channel, const char *name, int dnsclass, const char *p; int status, ndots; + /* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */ + if (ares__is_onion_domain(name)) + { + callback(arg, ARES_ENOTFOUND, 0, NULL, 0); + return; + } + /* If name only yields one domain to search, then we don't have * to keep extra state, so just do an ares_query(). */ diff --git a/deps/cares/src/ares_send.c b/deps/cares/src/ares_send.c index 88c0035520c..f4f1f951197 100644 --- a/deps/cares/src/ares_send.c +++ b/deps/cares/src/ares_send.c @@ -60,6 +60,12 @@ void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen, callback(arg, ARES_ENOMEM, 0, NULL, 0); return; } + if (channel->nservers < 1) + { + ares_free(query); + callback(arg, ARES_ESERVFAIL, 0, NULL, 0); + return; + } query->server_info = ares_malloc(channel->nservers * sizeof(query->server_info[0])); if (!query->server_info) diff --git a/deps/cares/src/ares_strsplit.c b/deps/cares/src/ares_strsplit.c new file mode 100644 index 00000000000..b57a30f2a99 --- /dev/null +++ b/deps/cares/src/ares_strsplit.c @@ -0,0 +1,174 @@ +/* Copyright (C) 2018 by John Schember <john@nachtimwald.com> + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" +#include "ares_strsplit.h" +#include "ares.h" +#include "ares_private.h" + +static int list_contains(char * const *list, size_t num_elem, const char *str, int insensitive) +{ + size_t len; + size_t i; + + len = strlen(str); + for (i=0; i<num_elem; i++) + { + if (insensitive) + { +#ifdef WIN32 + if (strnicmp(list[i], str, len) == 0) +#else + if (strncasecmp(list[i], str, len) == 0) +#endif + return 1; + } + else + { + if (strncmp(list[i], str, len) == 0) + return 1; + } + } + + return 0; +} + +static int is_delim(char c, const char *delims, size_t num_delims) +{ + size_t i; + + for (i=0; i<num_delims; i++) + { + if (c == delims[i]) + return 1; + } + return 0; +} + + +void ares_strsplit_free(char **elms, size_t num_elm) +{ + size_t i; + + if (elms == NULL) + return; + + for (i=0; i<num_elm; i++) + ares_free(elms[i]); + ares_free(elms); +} + + +char **ares_strsplit(const char *in, const char *delms, int make_set, size_t *num_elm) +{ + char *parsestr; + char **temp; + char **out; + size_t cnt; + size_t nelms; + size_t in_len; + size_t num_delims; + size_t i; + + if (in == NULL || delms == NULL || num_elm == NULL) + return NULL; + + *num_elm = 0; + + in_len = strlen(in); + num_delims = strlen(delms); + + /* Figure out how many elements. */ + nelms = 1; + for (i=0; i<in_len; i++) + { + if (is_delim(in[i], delms, num_delims)) + { + nelms++; + } + } + + /* Copy of input so we can cut it up. */ + parsestr = ares_strdup(in); + if (parsestr == NULL) + return NULL; + + /* Temporary array to store locations of start of each element + * within parsestr. */ + temp = ares_malloc(nelms * sizeof(*temp)); + if (temp == NULL) + { + ares_free(parsestr); + return NULL; + } + temp[0] = parsestr; + cnt = 1; + for (i=0; i<in_len && cnt<nelms; i++) + { + if (!is_delim(parsestr[i], delms, num_delims)) + continue; + + /* Replace sep with NULL. */ + parsestr[i] = '\0'; + /* Add the pointer to the array of elements */ + temp[cnt] = parsestr+i+1; + cnt++; + } + + /* Copy each element to our output array. */ + out = ares_malloc(nelms * sizeof(*out)); + if (out == NULL) + { + ares_free(parsestr); + ares_free(temp); + return NULL; + } + + nelms = 0; + for (i=0; i<cnt; i++) + { + if (temp[i][0] == '\0') + continue; + + if (make_set && list_contains(out, nelms, temp[i], 1)) + continue; + + out[nelms] = ares_strdup(temp[i]); + if (out[nelms] == NULL) + { + ares_strsplit_free(out, nelms); + ares_free(parsestr); + ares_free(temp); + return NULL; + } + nelms++; + } + + + /* If there are no elements don't return an empty allocated + * array. */ + if (nelms == 0) + { + ares_strsplit_free(out, nelms); + out = NULL; + } + + /* Get the true number of elements (recalculated because of make_set) */ + *num_elm = nelms; + + ares_free(parsestr); + ares_free(temp); + return out; +} diff --git a/deps/cares/src/ares_strsplit.h b/deps/cares/src/ares_strsplit.h new file mode 100644 index 00000000000..da286a9aef6 --- /dev/null +++ b/deps/cares/src/ares_strsplit.h @@ -0,0 +1,42 @@ +#ifndef HEADER_CARES_STRSPLIT_H +#define HEADER_CARES_STRSPLIT_H + +/* Copyright (C) 2018 by John Schember <john@nachtimwald.com> + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" + +/* Split a string on delem skipping empty elements. + * + * param in String to split. + * param delims String of characters to treat as a delimitor. + * Each character in the string is a delimitor so + * there can be multiple delimitors to split on. + * E.g. ", " will split on all comma's and spaces. + * param make_set Have the list be a Set where there are no + * duplicate entries. 1 for true, 0 or false. + * param num_elm Return parameter of the number of elements + * in the result array. + * + * returns an allocated array of allocated string elements. + * + */ +char **ares_strsplit(const char *in, const char *delms, int make_set, size_t *num_elm); + +/* Frees the result returned from ares_strsplit(). */ +void ares_strsplit_free(char **elms, size_t num_elm); + + +#endif /* HEADER_CARES_STRSPLIT_H */ diff --git a/deps/cares/src/inet_ntop.c b/deps/cares/src/inet_ntop.c index ce3ce588d3c..1935a871ced 100644 --- a/deps/cares/src/inet_ntop.c +++ b/deps/cares/src/inet_ntop.c @@ -180,8 +180,7 @@ inet_ntop6(const unsigned char *src, char *dst, size_t size) tp += sprintf(tp, "%x", words[i]); } /* Was it a trailing run of 0x00's? */ - if (best.base != -1 && (best.base + best.len) == - (NS_IN6ADDRSZ / NS_INT16SZ)) + if (best.base != -1 && (best.base + best.len) == (NS_IN6ADDRSZ / NS_INT16SZ)) *tp++ = ':'; *tp++ = '\0'; |