aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2004-06-10 13:11:32 +0000
committerDaniel Stenberg <daniel@haxx.se>2004-06-10 13:11:32 +0000
commit977e1069240470d22f2a492210ce521b25ff1c67 (patch)
treed3e35d3543616d84927a25499b3cc5ee88ff7332
parent8d76d4016d6ea9b8e9754d51592b027e6652cbfd (diff)
Gisle Vanem's init patch for Windows
-rw-r--r--ares/CHANGES18
-rw-r--r--ares/ares_init.c129
2 files changed, 122 insertions, 25 deletions
diff --git a/ares/CHANGES b/ares/CHANGES
index f7e04e13f..6facb453a 100644
--- a/ares/CHANGES
+++ b/ares/CHANGES
@@ -1,5 +1,23 @@
Changelog for the c-ares project
+* June 10
+- Gisle Vanem's init patch for Windows:
+
+ The init_by_resolv_conf() function fetches the DNS-server(s)
+ from a series of registry branches.
+
+ This can be wrong in the case where DHCP has assigned nameservers, but the
+ user has overridden these servers with other prefered settings. Then it's
+ wrong to use the DHCPNAMESERVER setting in registry.
+
+ In the case of no global DHCP-assigned or fixed servers, but DNS server(s)
+ per adapter, one has to query the adapter branches. But how can c-ares know
+ which adapter is valid for use? AFAICS it can't. There could be one adapter
+ that is down (e.g. a VPN adapter).
+
+ So it's better to leave this to the IP Helper API (iphlapi) available in
+ Win-98/2000 and later. My patch falls-back to the old way if not available.
+
* June 8
- James Bursa fixed an init issue for RISC OS.
diff --git a/ares/ares_init.c b/ares/ares_init.c
index 9ac8768ed..72ef990fb 100644
--- a/ares/ares_init.c
+++ b/ares/ares_init.c
@@ -17,6 +17,8 @@
#ifdef WIN32
#include "nameser.h"
+#include <iphlpapi.h>
+#include <malloc.h>
#else
#include <sys/param.h>
#include <sys/time.h>
@@ -231,24 +233,24 @@ static int init_by_environment(ares_channel channel)
return ARES_SUCCESS;
}
-#ifdef WIN32
-static int get_res_size_nt(HKEY hKey, char *subkey, int *size)
-{
- return RegQueryValueEx(hKey, subkey, 0, NULL, NULL, size);
-}
-/* Warning: returns a dynamically allocated buffer, the user MUST
+#ifdef WIN32
+/*
+ * Warning: returns a dynamically allocated buffer, the user MUST
* use free() if the function returns 1
*/
-static int get_res_nt(HKEY hKey, char *subkey, char **obuf)
+static int get_res_nt(HKEY hKey, const char *subkey, char **obuf)
{
/* Test for the size we need */
- int size = 0;
+ DWORD size = 0;
int result;
+
result = RegQueryValueEx(hKey, subkey, 0, NULL, NULL, &size);
if ((result != ERROR_SUCCESS && result != ERROR_MORE_DATA) || !size)
return 0;
*obuf = malloc(size+1);
+ if (!*obuf)
+ return 0;
if (RegQueryValueEx(hKey, subkey, 0, NULL, *obuf, &size) != ERROR_SUCCESS)
{
@@ -263,29 +265,99 @@ static int get_res_nt(HKEY hKey, char *subkey, char **obuf)
return 1;
}
-static int get_res_interfaces_nt(HKEY hKey, char *subkey, char **obuf)
+static int get_res_interfaces_nt(HKEY hKey, const char *subkey, char **obuf)
{
char enumbuf[39]; /* GUIDs are 38 chars + 1 for NULL */
- int enum_size = 39;
+ DWORD enum_size = 39;
int idx = 0;
HKEY hVal;
+
while (RegEnumKeyEx(hKey, idx++, enumbuf, &enum_size, 0,
NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS)
{
+ int rc;
+
enum_size = 39;
if (RegOpenKeyEx(hKey, enumbuf, 0, KEY_QUERY_VALUE, &hVal) !=
ERROR_SUCCESS)
continue;
- if (!get_res_nt(hVal, subkey, obuf))
- RegCloseKey(hVal);
- else
- {
+ rc = get_res_nt(hVal, subkey, obuf);
RegCloseKey(hVal);
+ if (rc)
return 1;
}
- }
return 0;
}
+
+static int get_iphlpapi_dns_info (char *ret_buf, size_t ret_size)
+{
+ FIXED_INFO *fi = alloca (sizeof(*fi));
+ DWORD size = sizeof (*fi);
+ DWORD WINAPI (*GetNetworkParams) (FIXED_INFO*, DWORD*); /* available only on Win-98/2000+ */
+ HMODULE handle;
+ IP_ADDR_STRING *ipAddr;
+ int i, count = 0;
+ int debug = 0;
+ size_t ip_size = sizeof("255.255.255.255,")-1;
+ size_t left = ret_size;
+ char *ret = ret_buf;
+
+ if (!fi)
+ return (0);
+
+ handle = LoadLibrary ("iphlpapi.dll");
+ if (!handle)
+ return (0);
+
+ (void*)GetNetworkParams = GetProcAddress (handle, "GetNetworkParams");
+ if (!GetNetworkParams)
+ goto quit;
+
+ if ((*GetNetworkParams) (fi, &size) != ERROR_BUFFER_OVERFLOW)
+ goto quit;
+
+ fi = alloca (size);
+ if (!fi || (*GetNetworkParams) (fi, &size) != ERROR_SUCCESS)
+ goto quit;
+
+ if (debug)
+ {
+ 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 (inet_addr(fi->DnsServerList.IpAddress.String) != INADDR_NONE &&
+ left > ip_size)
+ {
+ ret += sprintf (ret, "%s,", fi->DnsServerList.IpAddress.String);
+ left -= ret - ret_buf;
+ count++;
+ }
+
+ for (i = 0, ipAddr = fi->DnsServerList.Next; ipAddr && left > ip_size;
+ ipAddr = ipAddr->Next, i++)
+ {
+ if (inet_addr(ipAddr->IpAddress.String) != INADDR_NONE)
+ {
+ ret += sprintf (ret, "%s,", ipAddr->IpAddress.String);
+ left -= ret - ret_buf;
+ count++;
+ }
+ if (debug)
+ printf (" %s (secondary %d)\n", ipAddr->IpAddress.String, i+1);
+ }
+
+quit:
+ if (handle)
+ FreeLibrary (handle);
+
+ if (debug && left <= ip_size)
+ printf ("Too many nameservers. Truncating to %d addressess", count);
+ if (ret > ret_buf)
+ ret[-1] = '\0';
+ return (count);
+}
#endif
static int init_by_resolv_conf(ares_channel channel)
@@ -298,6 +370,11 @@ 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:
@@ -320,9 +397,17 @@ DhcpNameServer
DWORD data_type;
DWORD bytes;
DWORD result;
- DWORD keysize = MAX_PATH;
+ char buf[256];
- status = ARES_EFILE;
+ if (channel->nservers > -1) /* don't override ARES_OPT_SERVER */
+ return ARES_SUCCESS;
+
+ if (get_iphlpapi_dns_info(buf,sizeof(buf)) > 0)
+ {
+ status = config_nameserver(&servers, &nservers, buf);
+ if (status == ARES_SUCCESS)
+ goto okay;
+ }
if (IsNT)
{
@@ -388,15 +473,8 @@ DhcpNameServer
RegCloseKey(mykey);
}
- if (status != ARES_EFILE)
- {
- /*
- if (!channel->lookups) {
- status = config_lookup(channel, "file bind");
- }
- */
+ if (status == ARES_SUCCESS)
status = ARES_EOF;
- }
#elif defined(riscos)
@@ -474,6 +552,7 @@ DhcpNameServer
}
/* If we got any name server entries, fill them in. */
+okay:
if (servers)
{
channel->servers = servers;