From 977e1069240470d22f2a492210ce521b25ff1c67 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 10 Jun 2004 13:11:32 +0000 Subject: Gisle Vanem's init patch for Windows --- ares/CHANGES | 18 ++++++++ ares/ares_init.c | 129 ++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 122 insertions(+), 25 deletions(-) (limited to 'ares') 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 +#include #else #include #include @@ -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; -- cgit v1.2.3