summaryrefslogtreecommitdiff
path: root/deps/cares/src/ares_init.c
diff options
context:
space:
mode:
Diffstat (limited to 'deps/cares/src/ares_init.c')
-rw-r--r--deps/cares/src/ares_init.c400
1 files changed, 186 insertions, 214 deletions
diff --git a/deps/cares/src/ares_init.c b/deps/cares/src/ares_init.c
index 90cfcabdd3..c2c00d6523 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;
}