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.c183
1 files changed, 151 insertions, 32 deletions
diff --git a/deps/cares/src/ares_init.c b/deps/cares/src/ares_init.c
index 3ba8cb3570..4cc2c76dbd 100644
--- a/deps/cares/src/ares_init.c
+++ b/deps/cares/src/ares_init.c
@@ -44,6 +44,7 @@
#if defined(ANDROID) || defined(__ANDROID__)
#include <sys/system_properties.h>
+#include "ares_android.h"
/* From the Bionic sources */
#define DNS_PROP_NAME_PREFIX "net.dns"
#define MAX_DNS_PROPERTIES 8
@@ -585,7 +586,7 @@ static int get_REG_SZ(HKEY hKey, const char *leafKeyName, char **outptr)
*outptr = NULL;
/* Find out size of string stored in registry */
- res = RegQueryValueEx(hKey, leafKeyName, 0, NULL, NULL, &size);
+ res = RegQueryValueExA(hKey, leafKeyName, 0, NULL, NULL, &size);
if ((res != ERROR_SUCCESS && res != ERROR_MORE_DATA) || !size)
return 0;
@@ -596,7 +597,7 @@ static int get_REG_SZ(HKEY hKey, const char *leafKeyName, char **outptr)
return 0;
/* Get the value for real */
- res = RegQueryValueEx(hKey, leafKeyName, 0, NULL,
+ res = RegQueryValueExA(hKey, leafKeyName, 0, NULL,
(unsigned char *)*outptr, &size);
if ((res != ERROR_SUCCESS) || (size == 1))
{
@@ -627,7 +628,7 @@ static int get_REG_SZ_9X(HKEY hKey, const char *leafKeyName, char **outptr)
*outptr = NULL;
/* Find out size of string stored in registry */
- res = RegQueryValueEx(hKey, leafKeyName, 0, &dataType, NULL, &size);
+ res = RegQueryValueExA(hKey, leafKeyName, 0, &dataType, NULL, &size);
if ((res != ERROR_SUCCESS && res != ERROR_MORE_DATA) || !size)
return 0;
@@ -638,7 +639,7 @@ static int get_REG_SZ_9X(HKEY hKey, const char *leafKeyName, char **outptr)
return 0;
/* Get the value for real */
- res = RegQueryValueEx(hKey, leafKeyName, 0, &dataType,
+ res = RegQueryValueExA(hKey, leafKeyName, 0, &dataType,
(unsigned char *)*outptr, &size);
if ((res != ERROR_SUCCESS) || (size == 1))
{
@@ -683,11 +684,11 @@ static int get_enum_REG_SZ(HKEY hKeyParent, const char *leafKeyName,
for(;;)
{
enumKeyNameBuffSize = sizeof(enumKeyName);
- res = RegEnumKeyEx(hKeyParent, enumKeyIdx++, enumKeyName,
+ res = RegEnumKeyExA(hKeyParent, enumKeyIdx++, enumKeyName,
&enumKeyNameBuffSize, 0, NULL, NULL, NULL);
if (res != ERROR_SUCCESS)
break;
- res = RegOpenKeyEx(hKeyParent, enumKeyName, 0, KEY_QUERY_VALUE,
+ res = RegOpenKeyExA(hKeyParent, enumKeyName, 0, KEY_QUERY_VALUE,
&hKeyEnum);
if (res != ERROR_SUCCESS)
continue;
@@ -718,7 +719,7 @@ static int get_DNS_Registry_9X(char **outptr)
*outptr = NULL;
- res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X, 0, KEY_READ,
+ res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_9X, 0, KEY_READ,
&hKey_VxD_MStcp);
if (res != ERROR_SUCCESS)
return 0;
@@ -750,7 +751,7 @@ static int get_DNS_Registry_NT(char **outptr)
*outptr = NULL;
- res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, KEY_READ,
+ res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, KEY_READ,
&hKey_Tcpip_Parameters);
if (res != ERROR_SUCCESS)
return 0;
@@ -772,7 +773,7 @@ static int get_DNS_Registry_NT(char **outptr)
goto done;
/* Try adapter specific parameters */
- res = RegOpenKeyEx(hKey_Tcpip_Parameters, "Interfaces", 0,
+ res = RegOpenKeyExA(hKey_Tcpip_Parameters, "Interfaces", 0,
KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
&hKey_Interfaces);
if (res != ERROR_SUCCESS)
@@ -949,9 +950,16 @@ static BOOL ares_IsWindowsVistaOrGreater(void)
OSVERSIONINFO vinfo;
memset(&vinfo, 0, sizeof(vinfo));
vinfo.dwOSVersionInfoSize = sizeof(vinfo);
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4996) /* warning C4996: 'GetVersionExW': was declared deprecated */
+#endif
if (!GetVersionEx(&vinfo) || vinfo.dwMajorVersion < 6)
return FALSE;
return TRUE;
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
}
/* A structure to hold the string form of IPv4 and IPv6 addresses so we can
@@ -962,6 +970,10 @@ typedef struct
/* The metric we sort them by. */
ULONG metric;
+ /* Original index of the item, used as a secondary sort parameter to make
+ * qsort() stable if the metrics are equal */
+ size_t orig_idx;
+
/* Room enough for the string form of any IPv4 or IPv6 address that
* ares_inet_ntop() will create. Based on the existing c-ares practice.
*/
@@ -976,8 +988,69 @@ static int compareAddresses(const void *arg1,
{
const Address * const left = arg1;
const Address * const right = arg2;
+ /* Lower metric the more preferred */
if(left->metric < right->metric) return -1;
if(left->metric > right->metric) return 1;
+ /* If metrics are equal, lower original index more preferred */
+ if(left->orig_idx < right->orig_idx) return -1;
+ if(left->orig_idx > right->orig_idx) return 1;
+ 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;
}
@@ -1187,6 +1260,9 @@ static int get_DNS_AdaptersAddresses(char **outptr)
addresses[addressesIndex].metric = -1;
}
+ /* Record insertion index to make qsort stable */
+ addresses[addressesIndex].orig_idx = addressesIndex;
+
if (! ares_inet_ntop(AF_INET, &namesrvr.sa4->sin_addr,
addresses[addressesIndex].text,
sizeof(addresses[0].text))) {
@@ -1196,15 +1272,15 @@ 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;
@@ -1231,6 +1307,9 @@ static int get_DNS_AdaptersAddresses(char **outptr)
addresses[addressesIndex].metric = -1;
}
+ /* Record insertion index to make qsort stable */
+ addresses[addressesIndex].orig_idx = addressesIndex;
+
if (! ares_inet_ntop(AF_INET6, &namesrvr.sa6->sin6_addr,
addresses[addressesIndex].text,
sizeof(addresses[0].text))) {
@@ -1245,7 +1324,8 @@ static int get_DNS_AdaptersAddresses(char **outptr)
}
}
- /* Sort all of the textual addresses by their metric. */
+ /* Sort all of the textual addresses by their metric (and original index if
+ * metrics are equal). */
qsort(addresses, addressesIndex, sizeof(*addresses), compareAddresses);
/* Join them all into a single string, removing duplicates. */
@@ -1382,7 +1462,7 @@ static int get_SuffixList_Windows(char **outptr)
DWORD keyNameBuffSize;
DWORD keyIdx = 0;
char *p = NULL;
- char *pp;
+ const char *pp;
size_t len = 0;
*outptr = NULL;
@@ -1391,7 +1471,7 @@ static int get_SuffixList_Windows(char **outptr)
return 0;
/* 1. Global DNS Suffix Search List */
- if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
KEY_READ, &hKey) == ERROR_SUCCESS)
{
if (get_REG_SZ(hKey, SEARCHLIST_KEY, outptr))
@@ -1403,7 +1483,7 @@ static int get_SuffixList_Windows(char **outptr)
/* 2. Connection Specific Search List composed of:
* a. Primary DNS Suffix */
- if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_DNSCLIENT, 0,
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_DNSCLIENT, 0,
KEY_READ, &hKey) == ERROR_SUCCESS)
{
get_REG_SZ(hKey, PRIMARYDNSSUFFIX_KEY, outptr);
@@ -1413,17 +1493,17 @@ static int get_SuffixList_Windows(char **outptr)
return 0;
/* b. Interface SearchList, Domain, DhcpDomain */
- if (!RegOpenKeyEx(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 (RegEnumKeyEx(hKey, keyIdx++, keyName, &keyNameBuffSize,
+ if (RegEnumKeyExA(hKey, keyIdx++, keyName, &keyNameBuffSize,
0, NULL, NULL, NULL)
!= ERROR_SUCCESS)
break;
- if (RegOpenKeyEx(hKey, keyName, 0, KEY_QUERY_VALUE, &hKeyEnum)
+ if (RegOpenKeyExA(hKey, keyName, 0, KEY_QUERY_VALUE, &hKeyEnum)
!= ERROR_SUCCESS)
continue;
if (get_REG_SZ(hKeyEnum, SEARCHLIST_KEY, &p) ||
@@ -1432,7 +1512,7 @@ static int get_SuffixList_Windows(char **outptr)
{
/* p can be comma separated (SearchList) */
pp = p;
- while (len = next_suffix(&pp, len))
+ while ((len = next_suffix(&pp, len)) != 0)
{
if (!contains_suffix(*outptr, pp, len))
commanjoin(outptr, pp, len);
@@ -1542,18 +1622,55 @@ static int init_by_resolv_conf(ares_channel channel)
unsigned int i;
char propname[PROP_NAME_MAX];
char propvalue[PROP_VALUE_MAX]="";
+ char **dns_servers;
+ size_t num_servers;
+
+ /* Use the Android connectivity manager to get a list
+ * of DNS servers. As of Android 8 (Oreo) net.dns#
+ * system properties are no longer available. Google claims this
+ * improves privacy. Apps now need the ACCESS_NETWORK_STATE
+ * permission and must use the ConnectivityManager which
+ * is Java only. */
+ dns_servers = ares_get_android_server_list(MAX_DNS_PROPERTIES, &num_servers);
+ if (dns_servers != NULL)
+ {
+ for (i = 0; i < num_servers; i++)
+ {
+ status = config_nameserver(&servers, &nservers, dns_servers[i]);
+ if (status != ARES_SUCCESS)
+ break;
+ status = ARES_EOF;
+ }
+ for (i = 0; i < num_servers; i++)
+ {
+ ares_free(dns_servers[i]);
+ }
+ ares_free(dns_servers);
+ }
- for (i = 1; i <= MAX_DNS_PROPERTIES; i++) {
- snprintf(propname, sizeof(propname), "%s%u", DNS_PROP_NAME_PREFIX, i);
- if (__system_property_get(propname, propvalue) < 1) {
+# ifdef HAVE___SYSTEM_PROPERTY_GET
+ /* Old way using the system property still in place as
+ * a fallback. Older android versions can still use this.
+ * it's possible for older apps not not have added the new
+ * permission and we want to try to avoid breaking those.
+ *
+ * We'll only run this if we don't have any dns servers
+ * because this will get the same ones (if it works). */
+ if (status != ARES_EOF) {
+ for (i = 1; i <= MAX_DNS_PROPERTIES; i++) {
+ snprintf(propname, sizeof(propname), "%s%u", DNS_PROP_NAME_PREFIX, i);
+ if (__system_property_get(propname, propvalue) < 1) {
+ status = ARES_EOF;
+ break;
+ }
+
+ status = config_nameserver(&servers, &nservers, propvalue);
+ if (status != ARES_SUCCESS)
+ break;
status = ARES_EOF;
- break;
}
- status = config_nameserver(&servers, &nservers, propvalue);
- if (status != ARES_SUCCESS)
- break;
- status = ARES_EOF;
}
+# endif /* HAVE___SYSTEM_PROPERTY_GET */
#elif defined(CARES_USE_LIBRESOLV)
struct __res_state res;
memset(&res, 0, sizeof(res));
@@ -1873,8 +1990,10 @@ static int init_by_defaults(ares_channel channel)
continue;
}
else if(res) {
- rc = ARES_EBADNAME;
- goto error;
+ /* Lets not treat a gethostname failure as critical, since we
+ * are ok if gethostname doesn't even exist */
+ *hostname = '\0';
+ break;
}
} while (res != 0);