summaryrefslogtreecommitdiff
path: root/ares_init.c
diff options
context:
space:
mode:
Diffstat (limited to 'ares_init.c')
-rw-r--r--ares_init.c911
1 files changed, 551 insertions, 360 deletions
diff --git a/ares_init.c b/ares_init.c
index 44d4cf9..d23c1b0 100644
--- a/ares_init.c
+++ b/ares_init.c
@@ -1,6 +1,6 @@
/* Copyright 1998 by the Massachusetts Institute of Technology.
- * Copyright (C) 2007-2011 by Daniel Stenberg
+ * Copyright (C) 2007-2013 by Daniel Stenberg
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
@@ -21,14 +21,6 @@
#include <sys/param.h>
#endif
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
@@ -50,33 +42,26 @@
# include <arpa/nameser_compat.h>
#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <time.h>
-
-#ifdef ANDROID
+#if defined(ANDROID) || defined(__ANDROID__)
#include <sys/system_properties.h>
+/* From the Bionic sources */
+#define DNS_PROP_NAME_PREFIX "net.dns"
+#define MAX_DNS_PROPERTIES 8
#endif
#include "ares.h"
-#include "inet_net_pton.h"
+#include "ares_inet_net_pton.h"
#include "ares_library_init.h"
#include "ares_nowarn.h"
#include "ares_platform.h"
-#include "inet_ntop.h"
#include "ares_private.h"
#ifdef WATT32
#undef WIN32 /* Redefined in MingW/MSVC headers */
#endif
-static int init_by_options(ares_channel channel, const struct ares_options *options,
+static int init_by_options(ares_channel channel,
+ const struct ares_options *options,
int optmask);
static int init_by_environment(ares_channel channel);
static int init_by_resolv_conf(ares_channel channel);
@@ -91,8 +76,10 @@ static int set_options(ares_channel channel, const char *str);
static const char *try_option(const char *p, const char *q, const char *opt);
static int init_id_key(rc4_key* key,int key_data_len);
-#if !defined(WIN32) && !defined(WATT32)
-static int sortlist_alloc(struct apattern **sortlist, int *nsort, struct apattern *pat);
+#if !defined(WIN32) && !defined(WATT32) && \
+ !defined(ANDROID) && !defined(__ANDROID__)
+static int sortlist_alloc(struct apattern **sortlist, int *nsort,
+ struct apattern *pat);
static int ip_addr(const char *s, ssize_t len, struct in_addr *addr);
static void natural_mask(struct apattern *pat);
static int config_domain(ares_channel channel, char *str);
@@ -157,6 +144,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
channel->rotate = -1;
channel->udp_port = -1;
channel->tcp_port = -1;
+ channel->ednspsz = -1;
channel->socket_send_buffer_size = -1;
channel->socket_receive_buffer_size = -1;
channel->nservers = -1;
@@ -293,7 +281,8 @@ int ares_dup(ares_channel *dest, ares_channel src)
(*dest)->sock_create_cb = src->sock_create_cb;
(*dest)->sock_create_cb_data = src->sock_create_cb_data;
- strncpy((*dest)->local_dev_name, src->local_dev_name, sizeof(src->local_dev_name));
+ strncpy((*dest)->local_dev_name, src->local_dev_name,
+ sizeof(src->local_dev_name));
(*dest)->local_ip4 = src->local_ip4;
memcpy((*dest)->local_ip6, src->local_ip6, sizeof(src->local_ip6));
@@ -348,8 +337,8 @@ int ares_save_options(ares_channel channel, struct ares_options *options,
options->timeout = channel->timeout;
options->tries = channel->tries;
options->ndots = channel->ndots;
- options->udp_port = (unsigned short)channel->udp_port;
- options->tcp_port = (unsigned short)channel->tcp_port;
+ options->udp_port = ntohs(aresx_sitous(channel->udp_port));
+ options->tcp_port = ntohs(aresx_sitous(channel->tcp_port));
options->sock_state_cb = channel->sock_state_cb;
options->sock_state_cb_data = channel->sock_state_cb_data;
@@ -431,9 +420,9 @@ static int init_by_options(ares_channel channel,
if ((optmask & ARES_OPT_ROTATE) && channel->rotate == -1)
channel->rotate = 1;
if ((optmask & ARES_OPT_UDP_PORT) && channel->udp_port == -1)
- channel->udp_port = options->udp_port;
+ channel->udp_port = htons(options->udp_port);
if ((optmask & ARES_OPT_TCP_PORT) && channel->tcp_port == -1)
- channel->tcp_port = options->tcp_port;
+ channel->tcp_port = htons(options->tcp_port);
if ((optmask & ARES_OPT_SOCK_STATE_CB) && channel->sock_state_cb == NULL)
{
channel->sock_state_cb = options->sock_state_cb;
@@ -446,6 +435,9 @@ static int init_by_options(ares_channel channel,
&& channel->socket_receive_buffer_size == -1)
channel->socket_receive_buffer_size = options->socket_receive_buffer_size;
+ if ((optmask & ARES_OPT_EDNSPSZ) && channel->ednspsz == -1)
+ channel->ednspsz = options->ednspsz;
+
/* Copy the IPv4 servers, if given. */
if ((optmask & ARES_OPT_SERVERS) && channel->nservers == -1)
{
@@ -539,255 +531,531 @@ static int init_by_environment(ares_channel channel)
#ifdef WIN32
/*
- * Warning: returns a dynamically allocated buffer, the user MUST
- * use free() if the function returns 1
+ * get_REG_SZ()
+ *
+ * Given a 'hKey' handle to an open registry key and a 'leafKeyName' pointer
+ * to the name of the registry leaf key to be queried, fetch it's string
+ * value and return a pointer in *outptr to a newly allocated memory area
+ * holding it as a null-terminated string.
+ *
+ * Returns 0 and nullifies *outptr upon inability to return a string value.
+ *
+ * Returns 1 and sets *outptr when returning a dynamically allocated string.
+ *
+ * Supported on Windows NT 3.5 and newer.
*/
-static int get_res_nt(HKEY hKey, const char *subkey, char **obuf)
+static int get_REG_SZ(HKEY hKey, const char *leafKeyName, char **outptr)
{
- /* Test for the size we need */
DWORD size = 0;
- int result;
+ int res;
+
+ *outptr = NULL;
- result = RegQueryValueEx(hKey, subkey, 0, NULL, NULL, &size);
- if ((result != ERROR_SUCCESS && result != ERROR_MORE_DATA) || !size)
+ /* Find out size of string stored in registry */
+ res = RegQueryValueEx(hKey, leafKeyName, 0, NULL, NULL, &size);
+ if ((res != ERROR_SUCCESS && res != ERROR_MORE_DATA) || !size)
return 0;
- *obuf = malloc(size+1);
- if (!*obuf)
+
+ /* Allocate buffer of indicated size plus one given that string
+ might have been stored without null termination */
+ *outptr = malloc(size+1);
+ if (!*outptr)
return 0;
- if (RegQueryValueEx(hKey, subkey, 0, NULL,
- (LPBYTE)*obuf, &size) != ERROR_SUCCESS)
+ /* Get the value for real */
+ res = RegQueryValueEx(hKey, leafKeyName, 0, NULL,
+ (unsigned char *)*outptr, &size);
+ if ((res != ERROR_SUCCESS) || (size == 1))
{
- free(*obuf);
+ free(*outptr);
+ *outptr = NULL;
return 0;
}
- if (size == 1)
+
+ /* Null terminate buffer allways */
+ *(*outptr + size) = '\0';
+
+ return 1;
+}
+
+/*
+ * get_REG_SZ_9X()
+ *
+ * Functionally identical to get_REG_SZ()
+ *
+ * Supported on Windows 95, 98 and ME.
+ */
+static int get_REG_SZ_9X(HKEY hKey, const char *leafKeyName, char **outptr)
+{
+ DWORD dataType = 0;
+ DWORD size = 0;
+ int res;
+
+ *outptr = NULL;
+
+ /* Find out size of string stored in registry */
+ res = RegQueryValueEx(hKey, leafKeyName, 0, &dataType, NULL, &size);
+ if ((res != ERROR_SUCCESS && res != ERROR_MORE_DATA) || !size)
+ return 0;
+
+ /* Allocate buffer of indicated size plus one given that string
+ might have been stored without null termination */
+ *outptr = malloc(size+1);
+ if (!*outptr)
+ return 0;
+
+ /* Get the value for real */
+ res = RegQueryValueEx(hKey, leafKeyName, 0, &dataType,
+ (unsigned char *)*outptr, &size);
+ if ((res != ERROR_SUCCESS) || (size == 1))
{
- free(*obuf);
+ free(*outptr);
+ *outptr = NULL;
return 0;
}
+
+ /* Null terminate buffer allways */
+ *(*outptr + size) = '\0';
+
return 1;
}
-static int get_res_interfaces_nt(HKEY hKey, const char *subkey, char **obuf)
+/*
+ * get_enum_REG_SZ()
+ *
+ * Given a 'hKeyParent' handle to an open registry key and a 'leafKeyName'
+ * pointer to the name of the registry leaf key to be queried, parent key
+ * is enumerated searching in child keys for given leaf key name and its
+ * associated string value. When located, this returns a pointer in *outptr
+ * to a newly allocated memory area holding it as a null-terminated string.
+ *
+ * Returns 0 and nullifies *outptr upon inability to return a string value.
+ *
+ * Returns 1 and sets *outptr when returning a dynamically allocated string.
+ *
+ * Supported on Windows NT 3.5 and newer.
+ */
+static int get_enum_REG_SZ(HKEY hKeyParent, const char *leafKeyName,
+ char **outptr)
{
- char enumbuf[39]; /* GUIDs are 38 chars + 1 for NULL */
- DWORD enum_size = 39;
- int idx = 0;
- HKEY hVal;
+ char enumKeyName[256];
+ DWORD enumKeyNameBuffSize;
+ DWORD enumKeyIdx = 0;
+ HKEY hKeyEnum;
+ int gotString;
+ int res;
- while (RegEnumKeyEx(hKey, idx++, enumbuf, &enum_size, 0,
- NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS)
- {
- int rc;
+ *outptr = NULL;
- enum_size = 39;
- if (RegOpenKeyEx(hKey, enumbuf, 0, KEY_QUERY_VALUE, &hVal) !=
- ERROR_SUCCESS)
+ for(;;)
+ {
+ enumKeyNameBuffSize = sizeof(enumKeyName);
+ res = RegEnumKeyEx(hKeyParent, enumKeyIdx++, enumKeyName,
+ &enumKeyNameBuffSize, 0, NULL, NULL, NULL);
+ if (res != ERROR_SUCCESS)
+ break;
+ res = RegOpenKeyEx(hKeyParent, enumKeyName, 0, KEY_QUERY_VALUE,
+ &hKeyEnum);
+ if (res != ERROR_SUCCESS)
continue;
- rc = get_res_nt(hVal, subkey, obuf);
- RegCloseKey(hVal);
- if (rc)
- return 1;
- }
- return 0;
+ gotString = get_REG_SZ(hKeyEnum, leafKeyName, outptr);
+ RegCloseKey(hKeyEnum);
+ if (gotString)
+ break;
+ }
+
+ if (!*outptr)
+ return 0;
+
+ return 1;
}
-/**
- * The desired output for this method is that we set "ret_buf" to
- * something like:
+/*
+ * get_DNS_Registry_9X()
+ *
+ * Functionally identical to get_DNS_Registry()
*
- * 192.168.0.1,dns01.my.domain,fe80::200:f8ff:fe21:67cf
+ * Implementation supports Windows 95, 98 and ME.
+ */
+static int get_DNS_Registry_9X(char **outptr)
+{
+ HKEY hKey_VxD_MStcp;
+ int gotString;
+ int res;
+
+ *outptr = NULL;
+
+ res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X, 0, KEY_READ,
+ &hKey_VxD_MStcp);
+ if (res != ERROR_SUCCESS)
+ return 0;
+
+ gotString = get_REG_SZ_9X(hKey_VxD_MStcp, NAMESERVER, outptr);
+ RegCloseKey(hKey_VxD_MStcp);
+
+ if (!gotString || !*outptr)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * get_DNS_Registry_NT()
*
- * The only ordering requirement is that primary servers are listed
- * before secondary. There is no requirement that IPv4 addresses should
- * necessarily be before IPv6.
+ * Functionally identical to get_DNS_Registry()
*
- * Note that ret_size should ideally be big enough to hold around
- * 2-3 IPv4 and 2-3 IPv6 addresses.
+ * Refs: Microsoft Knowledge Base articles KB120642 and KB314053.
*
- * Finally, we need to return the total number of DNS servers located.
+ * Implementation supports Windows NT 3.5 and newer.
*/
-static int get_iphlpapi_dns_info (char *ret_buf, size_t ret_size)
+static int get_DNS_Registry_NT(char **outptr)
{
- const size_t ipv4_size = INET_ADDRSTRLEN + 1; /* +1 for ',' at end */
- const size_t ipv6_size = INET6_ADDRSTRLEN + 12; /* +12 for "%0123456789," at end */
- size_t left = ret_size;
- char *ret = ret_buf;
- int count = 0;
-
- /* Use the GetAdaptersAddresses method if it's available, otherwise
- fall back to GetNetworkParams. */
- if (ares_fpGetAdaptersAddresses != ZERO_NULL)
+ HKEY hKey_Interfaces = NULL;
+ HKEY hKey_Tcpip_Parameters;
+ int gotString;
+ int res;
+
+ *outptr = NULL;
+
+ res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, KEY_READ,
+ &hKey_Tcpip_Parameters);
+ if (res != ERROR_SUCCESS)
+ return 0;
+
+ /*
+ ** Global DNS settings override adapter specific parameters when both
+ ** are set. Additionally static DNS settings override DHCP-configured
+ ** parameters when both are set.
+ */
+
+ /* Global DNS static parameters */
+ gotString = get_REG_SZ(hKey_Tcpip_Parameters, NAMESERVER, outptr);
+ if (gotString)
+ goto done;
+
+ /* Global DNS DHCP-configured parameters */
+ gotString = get_REG_SZ(hKey_Tcpip_Parameters, DHCPNAMESERVER, outptr);
+ if (gotString)
+ goto done;
+
+ /* Try adapter specific parameters */
+ res = RegOpenKeyEx(hKey_Tcpip_Parameters, "Interfaces", 0,
+ KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
+ &hKey_Interfaces);
+ if (res != ERROR_SUCCESS)
{
- const ULONG working_buf_size = 15000;
- IP_ADAPTER_ADDRESSES *pFirstEntry = NULL;
- IP_ADAPTER_ADDRESSES *pEntry = NULL;
- ULONG bufSize = 0;
- ULONG result = 0;
-
- /* According to MSDN, the recommended way to do this is to use a temporary
- buffer of 15K, to "dramatically reduce the chance that the GetAdaptersAddresses
- method returns ERROR_BUFFER_OVERFLOW" */
- pFirstEntry = ( IP_ADAPTER_ADDRESSES * ) malloc( working_buf_size );
- bufSize = working_buf_size;
- if( !pFirstEntry )
- return 0;
-
- /* Call the method one time */
- result = ( *ares_fpGetAdaptersAddresses )( AF_UNSPEC, 0, 0, pFirstEntry, &bufSize );
- if( result == ERROR_BUFFER_OVERFLOW )
- {
- /* Reallocate, bufSize should now be set to the required size */
- pFirstEntry = ( IP_ADAPTER_ADDRESSES * ) realloc( pFirstEntry, bufSize );
- if( !pFirstEntry )
- return 0;
-
- /* Call the method a second time */
- result = ( *ares_fpGetAdaptersAddresses )( AF_UNSPEC, 0, 0, pFirstEntry, &bufSize );
- if( result == ERROR_BUFFER_OVERFLOW )
- {
- /* Reallocate, bufSize should now be set to the required size */
- pFirstEntry = ( IP_ADAPTER_ADDRESSES * ) realloc( pFirstEntry, bufSize );
- if( !pFirstEntry )
- return 0;
-
- /* Call the method a third time. The maximum number of times we're going to do
- this is 3. Three shall be the number thou shalt count, and the number of the
- counting shall be three. Five is right out. */
- result = ( *ares_fpGetAdaptersAddresses )( AF_UNSPEC, 0, 0, pFirstEntry, &bufSize );
- }
- }
+ hKey_Interfaces = NULL;
+ goto done;
+ }
- /* Check the current result for failure */
- if( result != ERROR_SUCCESS )
- {
- free( pFirstEntry );
- return 0;
- }
+ /* Adapter specific DNS static parameters */
+ gotString = get_enum_REG_SZ(hKey_Interfaces, NAMESERVER, outptr);
+ if (gotString)
+ goto done;
- /* process the results */
- for( pEntry = pFirstEntry ; pEntry != NULL ; pEntry = pEntry->Next )
- {
- IP_ADAPTER_DNS_SERVER_ADDRESS* pDNSAddr = pEntry->FirstDnsServerAddress;
- for( ; pDNSAddr != NULL ; pDNSAddr = pDNSAddr->Next )
- {
- struct sockaddr *pGenericAddr = pDNSAddr->Address.lpSockaddr;
- size_t stringlen = 0;
+ /* Adapter specific DNS DHCP-configured parameters */
+ gotString = get_enum_REG_SZ(hKey_Interfaces, DHCPNAMESERVER, outptr);
- if( pGenericAddr->sa_family == AF_INET && left > ipv4_size )
- {
- /* Handle the v4 case */
- struct sockaddr_in *pIPv4Addr = ( struct sockaddr_in * ) pGenericAddr;
- ares_inet_ntop( AF_INET, &pIPv4Addr->sin_addr, ret, ipv4_size - 1 ); /* -1 for comma */
-
- /* Append a comma to the end, THEN NULL. Should be OK because we
- already tested the size at the top of the if statement. */
- stringlen = strlen( ret );
- ret[ stringlen ] = ',';
- ret[ stringlen + 1 ] = '\0';
- ret += stringlen + 1;
- left -= ret - ret_buf;
- ++count;
- }
- else if( pGenericAddr->sa_family == AF_INET6 && left > ipv6_size )
- {
- /* Handle the v6 case */
- struct sockaddr_in6 *pIPv6Addr = ( struct sockaddr_in6 * ) pGenericAddr;
- ares_inet_ntop( AF_INET6, &pIPv6Addr->sin6_addr, ret, ipv6_size - 1 ); /* -1 for comma */
-
- /* Append a comma to the end, THEN NULL. Should be OK because we
- already tested the size at the top of the if statement. */
- stringlen = strlen( ret );
- ret[ stringlen ] = ',';
- ret[ stringlen + 1 ] = '\0';
- ret += stringlen + 1;
- left -= ret - ret_buf;
- ++count;
-
- /* NB on Windows this also returns stuff in the fec0::/10 range,
- seems to be hard-coded somehow. Do we need to ignore them? */
- }
- }
- }
+done:
+ if (hKey_Interfaces)
+ RegCloseKey(hKey_Interfaces);
+
+ RegCloseKey(hKey_Tcpip_Parameters);
+
+ if (!gotString || !*outptr)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * get_DNS_Registry()
+ *
+ * Locates DNS info in the registry. When located, this returns a pointer
+ * in *outptr to a newly allocated memory area holding a null-terminated
+ * string with a space or comma seperated list of DNS IP addresses.
+ *
+ * Returns 0 and nullifies *outptr upon inability to return DNSes string.
+ *
+ * Returns 1 and sets *outptr when returning a dynamically allocated string.
+ */
+static int get_DNS_Registry(char **outptr)
+{
+ win_platform platform;
+ int gotString = 0;
+
+ *outptr = NULL;
+
+ platform = ares__getplatform();
- if( pFirstEntry )
- free( pFirstEntry );
- if (ret > ret_buf)
- ret[-1] = '\0';
- return count;
+ if (platform == WIN_NT)
+ gotString = get_DNS_Registry_NT(outptr);
+ else if (platform == WIN_9X)
+ gotString = get_DNS_Registry_9X(outptr);
+
+ if (!gotString)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * commajoin()
+ *
+ * RTF code.
+ */
+static void commajoin(char **dst, const char *src)
+{
+ char *tmp;
+
+ if (*dst)
+ {
+ tmp = malloc(strlen(*dst) + strlen(src) + 2);
+ if (!tmp)
+ return;
+ sprintf(tmp, "%s,%s", *dst, src);
+ free(*dst);
+ *dst = tmp;
}
else
{
- FIXED_INFO *fi, *newfi;
- DWORD size = sizeof (*fi);
- IP_ADDR_STRING *ipAddr;
- int i;
- int debug = 0;
- HRESULT res;
-
- fi = malloc(size);
- if (!fi)
- return 0;
-
- res = (*ares_fpGetNetworkParams) (fi, &size);
- if ((res != ERROR_BUFFER_OVERFLOW) && (res != ERROR_SUCCESS))
- goto quit;
-
- newfi = realloc(fi, size);
- if (!newfi)
- goto quit;
-
- fi = newfi;
- res = (*ares_fpGetNetworkParams) (fi, &size);
- if (res != ERROR_SUCCESS)
- goto quit;
+ *dst = malloc(strlen(src) + 1);
+ if (!*dst)
+ return;
+ strcpy(*dst, src);
+ }
+}
- if (debug)
+/*
+ * get_DNS_NetworkParams()
+ *
+ * Locates DNS info using GetNetworkParams() function from the Internet
+ * Protocol Helper (IP Helper) API. When located, this returns a pointer
+ * in *outptr to a newly allocated memory area holding a null-terminated
+ * string with a space or comma seperated list of DNS IP addresses.
+ *
+ * Returns 0 and nullifies *outptr upon inability to return DNSes string.
+ *
+ * Returns 1 and sets *outptr when returning a dynamically allocated string.
+ *
+ * Implementation supports Windows 98 and newer.
+ *
+ * Note: Ancient PSDK required in order to build a W98 target.
+ */
+static int get_DNS_NetworkParams(char **outptr)
+{
+ FIXED_INFO *fi, *newfi;
+ struct ares_addr namesrvr;
+ char *txtaddr;
+ IP_ADDR_STRING *ipAddr;
+ int res;
+ DWORD size = sizeof (*fi);
+
+ *outptr = NULL;
+
+ /* Verify run-time availability of GetNetworkParams() */
+ if (ares_fpGetNetworkParams == ZERO_NULL)
+ return 0;
+
+ fi = malloc(size);
+ if (!fi)
+ return 0;
+
+ res = (*ares_fpGetNetworkParams) (fi, &size);
+ if ((res != ERROR_BUFFER_OVERFLOW) && (res != ERROR_SUCCESS))
+ goto done;
+
+ newfi = realloc(fi, size);
+ if (!newfi)
+ goto done;
+
+ fi = newfi;
+ res = (*ares_fpGetNetworkParams) (fi, &size);
+ if (res != ERROR_SUCCESS)
+ goto done;
+
+ for (ipAddr = &fi->DnsServerList; ipAddr; ipAddr = ipAddr->Next)
+ {
+ txtaddr = &ipAddr->IpAddress.String[0];
+
+ /* Validate converting textual address to binary format. */
+ if (ares_inet_pton(AF_INET, txtaddr, &namesrvr.addrV4) == 1)
+ {
+ if ((namesrvr.addrV4.S_un.S_addr == INADDR_ANY) ||
+ (namesrvr.addrV4.S_un.S_addr == INADDR_NONE))
+ continue;
+ }
+ else if (ares_inet_pton(AF_INET6, txtaddr, &namesrvr.addrV6) == 1)
{
- printf ("Host Name: %s\n", fi->HostName);
- printf ("Domain Name: %s\n", fi->DomainName);
- printf ("DNS Servers:\n"
- " %s (primary)\n", fi->DnsServerList.IpAddress.String);
+ if (memcmp(&namesrvr.addrV6, &ares_in6addr_any,
+ sizeof(namesrvr.addrV6)) == 0)
+ continue;
}
- if (strlen(fi->DnsServerList.IpAddress.String) > 0 &&
- inet_addr(fi->DnsServerList.IpAddress.String) != INADDR_NONE &&
- left > ipv4_size)
+ else
+ continue;
+
+ commajoin(outptr, txtaddr);
+
+ if (!*outptr)
+ break;
+ }
+
+done:
+ if (fi)
+ free(fi);
+
+ if (!*outptr)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * get_DNS_AdaptersAddresses()
+ *
+ * Locates DNS info using GetAdaptersAddresses() function from the Internet
+ * Protocol Helper (IP Helper) API. When located, this returns a pointer
+ * in *outptr to a newly allocated memory area holding a null-terminated
+ * string with a space or comma seperated list of DNS IP addresses.
+ *
+ * Returns 0 and nullifies *outptr upon inability to return DNSes string.
+ *
+ * Returns 1 and sets *outptr when returning a dynamically allocated string.
+ *
+ * Implementation supports Windows XP and newer.
+ */
+#define IPAA_INITIAL_BUF_SZ 15 * 1024
+#define IPAA_MAX_TRIES 3
+static int get_DNS_AdaptersAddresses(char **outptr)
+{
+ IP_ADAPTER_DNS_SERVER_ADDRESS *ipaDNSAddr;
+ IP_ADAPTER_ADDRESSES *ipaa, *newipaa, *ipaaEntry;
+ ULONG ReqBufsz = IPAA_INITIAL_BUF_SZ;
+ ULONG Bufsz = IPAA_INITIAL_BUF_SZ;
+ ULONG AddrFlags = 0;
+ int trying = IPAA_MAX_TRIES;
+ int res;
+
+ union {
+ struct sockaddr *sa;
+ struct sockaddr_in *sa4;
+ struct sockaddr_in6 *sa6;
+ } namesrvr;
+
+ char txtaddr[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
+
+ *outptr = NULL;
+
+ /* Verify run-time availability of GetAdaptersAddresses() */
+ if (ares_fpGetAdaptersAddresses == ZERO_NULL)
+ return 0;
+
+ ipaa = malloc(Bufsz);
+ if (!ipaa)
+ return 0;
+
+ /* Usually this call suceeds with initial buffer size */
+ res = (*ares_fpGetAdaptersAddresses) (AF_UNSPEC, AddrFlags, NULL,
+ ipaa, &ReqBufsz);
+ if ((res != ERROR_BUFFER_OVERFLOW) && (res != ERROR_SUCCESS))
+ goto done;
+
+ while ((res == ERROR_BUFFER_OVERFLOW) && (--trying))
+ {
+ if (Bufsz < ReqBufsz)
{
- ret += sprintf (ret, "%s,", fi->DnsServerList.IpAddress.String);
- left -= ret - ret_buf;
- ++count;
+ newipaa = realloc(ipaa, ReqBufsz);
+ if (!newipaa)
+ goto done;
+ Bufsz = ReqBufsz;
+ ipaa = newipaa;
}
+ res = (*ares_fpGetAdaptersAddresses) (AF_UNSPEC, AddrFlags, NULL,
+ ipaa, &ReqBufsz);
+ if (res == ERROR_SUCCESS)
+ break;
+ }
+ if (res != ERROR_SUCCESS)
+ goto done;
- for (i = 0, ipAddr = fi->DnsServerList.Next; ipAddr && left > ipv4_size;
- ipAddr = ipAddr->Next, i++)
+ for (ipaaEntry = ipaa; ipaaEntry; ipaaEntry = ipaaEntry->Next)
+ {
+ for (ipaDNSAddr = ipaaEntry->FirstDnsServerAddress;
+ ipaDNSAddr;
+ ipaDNSAddr = ipaDNSAddr->Next)
{
- if (inet_addr(ipAddr->IpAddress.String) != INADDR_NONE)
+ namesrvr.sa = ipaDNSAddr->Address.lpSockaddr;
+
+ if (namesrvr.sa->sa_family == AF_INET)
{
- ret += sprintf (ret, "%s,", ipAddr->IpAddress.String);
- left -= ret - ret_buf;
- ++count;
+ if ((namesrvr.sa4->sin_addr.S_un.S_addr == INADDR_ANY) ||
+ (namesrvr.sa4->sin_addr.S_un.S_addr == INADDR_NONE))
+ continue;
+ if (! ares_inet_ntop(AF_INET, &namesrvr.sa4->sin_addr,
+ txtaddr, sizeof(txtaddr)))
+ continue;
}
- if (debug)
- printf (" %s (secondary %d)\n", ipAddr->IpAddress.String, i+1);
- }
+ else if (namesrvr.sa->sa_family == AF_INET6)
+ {
+ if (memcmp(&namesrvr.sa6->sin6_addr, &ares_in6addr_any,
+ sizeof(namesrvr.sa6->sin6_addr)) == 0)
+ continue;
+ if (! ares_inet_ntop(AF_INET6, &namesrvr.sa6->sin6_addr,
+ txtaddr, sizeof(txtaddr)))
+ continue;
+ }
+ else
+ continue;
-quit:
- if (fi)
- free(fi);
+ commajoin(outptr, txtaddr);
- if (debug && left <= ipv4_size)
- printf ("Too many nameservers. Truncating to %d addressess", count);
- if (ret > ret_buf)
- ret[-1] = '\0';
- return count;
+ if (!*outptr)
+ goto done;
+ }
}
+
+done:
+ if (ipaa)
+ free(ipaa);
+
+ if (!*outptr)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * get_DNS_Windows()
+ *
+ * Locates DNS info from Windows employing most suitable methods available at
+ * run-time no matter which Windows version it is. When located, this returns
+ * a pointer in *outptr to a newly allocated memory area holding a string with
+ * a space or comma seperated list of DNS IP addresses, null-terminated.
+ *
+ * Returns 0 and nullifies *outptr upon inability to return DNSes string.
+ *
+ * Returns 1 and sets *outptr when returning a dynamically allocated string.
+ *
+ * Implementation supports Windows 95 and newer.
+ */
+static int get_DNS_Windows(char **outptr)
+{
+ /* Try using IP helper API GetAdaptersAddresses() */
+ if (get_DNS_AdaptersAddresses(outptr))
+ return 1;
+
+ /* Try using IP helper API GetNetworkParams() */
+ if (get_DNS_NetworkParams(outptr))
+ return 1;
+
+ /* Fall-back to registry information */
+ return get_DNS_Registry(outptr);
}
#endif
static int init_by_resolv_conf(ares_channel channel)
{
-#ifndef WATT32
+#if !defined(ANDROID) && !defined(__ANDROID__) && !defined(WATT32)
char *line = NULL;
#endif
int status = -1, nservers = 0, nsort = 0;
@@ -796,111 +1064,13 @@ static int init_by_resolv_conf(ares_channel channel)
#ifdef WIN32
- /*
- NameServer info via IPHLPAPI (IP helper API):
- GetNetworkParams() should be the trusted source for this.
- Available in Win-98/2000 and later. If that fail, fall-back to
- registry information.
-
- NameServer Registry:
-
- On Windows 9X, the DNS server can be found in:
-HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\MSTCP\NameServer
-
- On Windows NT/2000/XP/2003:
-HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\NameServer
- or
-HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\DhcpNameServer
- or
-HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\{AdapterID}\
-NameServer
- or
-HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\{AdapterID}\
-DhcpNameServer
- */
-
- HKEY mykey;
- HKEY subkey;
- DWORD data_type;
- DWORD bytes;
- DWORD result;
- char buf[512];
- win_platform platform;
-
if (channel->nservers > -1) /* don't override ARES_OPT_SERVER */
return ARES_SUCCESS;
- if (get_iphlpapi_dns_info(buf,sizeof(buf)) > 0)
+ if (get_DNS_Windows(&line))
{
- status = config_nameserver(&servers, &nservers, buf);
- if (status == ARES_SUCCESS)
- goto okay;
- }
-
- platform = ares__getplatform();
-
- if (platform == WIN_NT)
- {
- if (RegOpenKeyEx(
- HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
- KEY_READ, &mykey
- ) == ERROR_SUCCESS)
- {
- RegOpenKeyEx(mykey, "Interfaces", 0,
- KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS, &subkey);
- if (get_res_nt(mykey, NAMESERVER, &line))
- {
- status = config_nameserver(&servers, &nservers, line);
- free(line);
- }
- else if (get_res_nt(mykey, DHCPNAMESERVER, &line))
- {
- status = config_nameserver(&servers, &nservers, line);
- free(line);
- }
- /* Try the interfaces */
- else if (get_res_interfaces_nt(subkey, NAMESERVER, &line))
- {
- status = config_nameserver(&servers, &nservers, line);
- free(line);
- }
- else if (get_res_interfaces_nt(subkey, DHCPNAMESERVER, &line))
- {
- status = config_nameserver(&servers, &nservers, line);
- free(line);
- }
- RegCloseKey(subkey);
- RegCloseKey(mykey);
- }
- }
- else if (platform == WIN_9X)
- {
- if (RegOpenKeyEx(
- HKEY_LOCAL_MACHINE, WIN_NS_9X, 0,
- KEY_READ, &mykey
- ) == ERROR_SUCCESS)
- {
- if ((result = RegQueryValueEx(
- mykey, NAMESERVER, NULL, &data_type,
- NULL, &bytes
- )
- ) == ERROR_SUCCESS ||
- result == ERROR_MORE_DATA)
- {
- if (bytes)
- {
- line = malloc(bytes+1);
- if (RegQueryValueEx(mykey, NAMESERVER, NULL, &data_type,
- (unsigned char *)line, &bytes) ==
- ERROR_SUCCESS)
- {
- status = config_nameserver(&servers, &nservers, line);
- }
- free(line);
- }
- }
- }
- RegCloseKey(mykey);
+ status = config_nameserver(&servers, &nservers, line);
+ free(line);
}
if (status == ARES_SUCCESS)
@@ -961,12 +1131,22 @@ DhcpNameServer
}
status = ARES_EOF;
-#elif defined(ANDROID)
- char value[PROP_VALUE_MAX]="";
- __system_property_get("net.dns1", value);
- status = config_nameserver(&servers, &nservers, value);
- if (status == ARES_SUCCESS)
+#elif defined(ANDROID) || defined(__ANDROID__)
+ unsigned int i;
+ char propname[PROP_NAME_MAX];
+ char propvalue[PROP_VALUE_MAX]="";
+
+ 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;
+ }
#else
{
char *p;
@@ -1022,7 +1202,8 @@ DhcpNameServer
/* Many systems (Solaris, Linux, BSD's) use nsswitch.conf */
fp = fopen("/etc/nsswitch.conf", "r");
if (fp) {
- while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
+ while ((status = ares__read_line(fp, &line, &linesize)) ==
+ ARES_SUCCESS)
{
if ((p = try_config(line, "hosts:", '\0')) && !channel->lookups)
/* ignore errors */
@@ -1040,7 +1221,8 @@ DhcpNameServer
default:
DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n",
error, strerror(error)));
- DEBUGF(fprintf(stderr, "Error opening file: %s\n", "/etc/nsswitch.conf"));
+ DEBUGF(fprintf(stderr, "Error opening file: %s\n",
+ "/etc/nsswitch.conf"));
status = ARES_EFILE;
}
}
@@ -1050,7 +1232,8 @@ DhcpNameServer
/* Linux / GNU libc 2.x and possibly others have host.conf */
fp = fopen("/etc/host.conf", "r");
if (fp) {
- while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
+ while ((status = ares__read_line(fp, &line, &linesize)) ==
+ ARES_SUCCESS)
{
if ((p = try_config(line, "order", '\0')) && !channel->lookups)
/* ignore errors */
@@ -1068,7 +1251,8 @@ DhcpNameServer
default:
DEBUGF(fprintf(stderr, "fopen() failed with error: %d %s\n",
error, strerror(error)));
- DEBUGF(fprintf(stderr, "Error opening file: %s\n", "/etc/host.conf"));
+ DEBUGF(fprintf(stderr, "Error opening file: %s\n",
+ "/etc/host.conf"));
status = ARES_EFILE;
}
}
@@ -1078,7 +1262,8 @@ DhcpNameServer
/* Tru64 uses /etc/svc.conf */
fp = fopen("/etc/svc.conf", "r");
if (fp) {
- while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
+ while ((status = ares__read_line(fp, &line, &linesize)) ==
+ ARES_SUCCESS)
{
if ((p = try_config(line, "hosts=", '\0')) && !channel->lookups)
/* ignore errors */
@@ -1119,9 +1304,6 @@ DhcpNameServer
}
/* If we got any name server entries, fill them in. */
-#ifdef WIN32
-okay:
-#endif
if (servers)
{
channel->servers = servers;
@@ -1161,6 +1343,9 @@ static int init_by_defaults(ares_channel channel)
if (channel->tcp_port == -1)
channel->tcp_port = htons(NAMESERVER_PORT);
+ if (channel->ednspsz == -1)
+ channel->ednspsz = EDNSPACKETSZ;
+
if (channel->nservers == -1) {
/* If nobody specified servers, try a local named. */
channel->servers = malloc(sizeof(struct server_state));
@@ -1186,11 +1371,14 @@ static int init_by_defaults(ares_channel channel)
/* Derive a default domain search list from the kernel hostname,
* or set it to empty if the hostname isn't helpful.
*/
+#ifndef HAVE_GETHOSTNAME
+ channel->ndomains = 0; /* default to none */
+#else
+ GETHOSTNAME_TYPE_ARG2 lenv = 64;
size_t len = 64;
int res;
channel->ndomains = 0; /* default to none */
-#ifdef HAVE_GETHOSTNAME
hostname = malloc(len);
if(!hostname) {
rc = ARES_ENOMEM;
@@ -1198,11 +1386,12 @@ static int init_by_defaults(ares_channel channel)
}
do {
- res = gethostname(hostname, len);
+ res = gethostname(hostname, lenv);
if(toolong(res)) {
char *p;
len *= 2;
+ lenv *= 2;
p = realloc(hostname, len);
if(!p) {
rc = ARES_ENOMEM;
@@ -1216,7 +1405,7 @@ static int init_by_defaults(ares_channel channel)
goto error;
}
- } while(0);
+ } WHILE_FALSE;
dot = strchr(hostname, '.');
if (dot) {
@@ -1249,15 +1438,22 @@ static int init_by_defaults(ares_channel channel)
error:
if(rc) {
- if(channel->servers)
+ if(channel->servers) {
free(channel->servers);
+ channel->servers = NULL;
+ }
if(channel->domains && channel->domains[0])
free(channel->domains[0]);
- if(channel->domains)
+ if(channel->domains) {
free(channel->domains);
- if(channel->lookups)
+ channel->domains = NULL;
+ }
+
+ if(channel->lookups) {
free(channel->lookups);
+ channel->lookups = NULL;
+ }
}
if(hostname)
@@ -1266,7 +1462,8 @@ static int init_by_defaults(ares_channel channel)
return rc;
}
-#if !defined(WIN32) && !defined(WATT32)
+#if !defined(WIN32) && !defined(WATT32) && \
+ !defined(ANDROID) && !defined(__ANDROID__)
static int config_domain(ares_channel channel, char *str)
{
char *q;
@@ -1314,7 +1511,7 @@ static int config_lookup(ares_channel channel, const char *str,
channel->lookups = strdup(lookups);
return (channel->lookups) ? ARES_SUCCESS : ARES_ENOMEM;
}
-#endif /* !WIN32 & !WATT32 */
+#endif /* !WIN32 & !WATT32 & !ANDROID & !__ANDROID__ */
#ifndef WATT32
static int config_nameserver(struct server_state **servers, int *nservers,
@@ -1379,7 +1576,7 @@ static int config_nameserver(struct server_state **servers, int *nservers,
return ARES_SUCCESS;
}
-#ifndef WIN32
+#if !defined(WIN32) && !defined(ANDROID) && !defined(__ANDROID__)
static int config_sortlist(struct apattern **sortlist, int *nsort,
const char *str)
{
@@ -1460,7 +1657,7 @@ static int config_sortlist(struct apattern **sortlist, int *nsort,
return ARES_SUCCESS;
}
-#endif /* !WIN32 */
+#endif /* !WIN32 & !ANDROID & !__ANDROID__ */
#endif /* !WATT32 */
static int set_search(ares_channel channel, const char *str)
@@ -1559,7 +1756,8 @@ static const char *try_option(const char *p, const char *q, const char *opt)
return ((size_t)(q - p) >= len && !strncmp(p, opt, len)) ? &p[len] : NULL;
}
-#if !defined(WIN32) && !defined(WATT32)
+#if !defined(WIN32) && !defined(WATT32) && \
+ !defined(ANDROID) && !defined(__ANDROID__)
static char *try_config(char *s, const char *opt, char scc)
{
size_t len;
@@ -1675,7 +1873,7 @@ static void natural_mask(struct apattern *pat)
else
pat->mask.addr4.s_addr = htonl(IN_CLASSC_NET);
}
-#endif /* !WIN32 && !WATT32 */
+#endif /* !WIN32 & !WATT32 & !ANDROID & !__ANDROID__ */
/* initialize an rc4 key. If possible a cryptographically secure random key
is generated using a suitable function (for example win32's RtlGenRandom as
@@ -1706,7 +1904,7 @@ static void randomize_key(unsigned char* key,int key_data_len)
#endif
#endif /* WIN32 */
- if ( !randomized ) {
+ if (!randomized) {
for (;counter<key_data_len;counter++)
key[counter]=(unsigned char)(rand() % 256);
}
@@ -1745,13 +1943,6 @@ static int init_id_key(rc4_key* key,int key_data_len)
return ARES_SUCCESS;
}
-unsigned short ares__generate_new_id(rc4_key* key)
-{
- unsigned short r=0;
- ares__rc4(key, (unsigned char *)&r, sizeof(r));
- return r;
-}
-
void ares_set_local_ip4(ares_channel channel, unsigned int local_ip)
{
channel->local_ip4 = local_ip;