Huw Davies : dnsapi: Implement support for returning ipv4 servers in a DNS_ADDR_ARRAY.

Alexandre Julliard julliard at winehq.org
Tue Aug 3 16:52:22 CDT 2021


Module: wine
Branch: master
Commit: bd80dd0903069eacef818c1ebda898320578ec7f
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=bd80dd0903069eacef818c1ebda898320578ec7f

Author: Huw Davies <huw at codeweavers.com>
Date:   Tue Aug  3 09:20:21 2021 +0100

dnsapi: Implement support for returning ipv4 servers in a DNS_ADDR_ARRAY.

Signed-off-by: Huw Davies <huw at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/dnsapi/dnsapi.h          |  4 +--
 dlls/dnsapi/libresolv.c       | 31 ++++++++++++------
 dlls/dnsapi/query.c           | 50 +++++++++++++++++++++++++---
 dlls/dnsapi/tests/Makefile.in |  2 +-
 dlls/dnsapi/tests/query.c     | 76 +++++++++++++++++++++++++++++++++++++++++++
 include/windns.h              |  7 +++-
 6 files changed, 152 insertions(+), 18 deletions(-)

diff --git a/dlls/dnsapi/dnsapi.h b/dlls/dnsapi/dnsapi.h
index bcd6a6d5bc3..168c37282bd 100644
--- a/dlls/dnsapi/dnsapi.h
+++ b/dlls/dnsapi/dnsapi.h
@@ -121,13 +121,13 @@ static inline char *strdup_ua( const char *src )
 
 extern const char *type_to_str( unsigned short ) DECLSPEC_HIDDEN;
 
-extern DNS_STATUS CDECL resolv_get_serverlist( IP4_ARRAY *, DWORD * ) DECLSPEC_HIDDEN;
+extern DNS_STATUS CDECL resolv_get_serverlist( USHORT, DNS_ADDR_ARRAY *, DWORD * ) DECLSPEC_HIDDEN;
 extern DNS_STATUS CDECL resolv_query( const char *, WORD, DWORD, DNS_RECORDA ** ) DECLSPEC_HIDDEN;
 extern DNS_STATUS CDECL resolv_set_serverlist( const IP4_ARRAY * ) DECLSPEC_HIDDEN;
 
 struct resolv_funcs
 {
-    DNS_STATUS (CDECL *get_serverlist)( IP4_ARRAY *addrs, DWORD *len );
+    DNS_STATUS (CDECL *get_serverlist)( USHORT family, DNS_ADDR_ARRAY *addrs, DWORD *len );
     DNS_STATUS (CDECL *query)( const char *name, WORD type, DWORD options, DNS_RECORDA **result );
     DNS_STATUS (CDECL *set_serverlist)( const IP4_ARRAY *addrs );
 };
diff --git a/dlls/dnsapi/libresolv.c b/dlls/dnsapi/libresolv.c
index ac52147af01..7e754d73af3 100644
--- a/dlls/dnsapi/libresolv.c
+++ b/dlls/dnsapi/libresolv.c
@@ -50,6 +50,9 @@
 #include "winbase.h"
 #include "winnls.h"
 #include "windns.h"
+#define USE_WS_PREFIX
+#include "ws2def.h"
+#include "ws2ipdef.h"
 
 #include "wine/debug.h"
 #include "wine/heap.h"
@@ -225,25 +228,33 @@ static DNS_STATUS map_h_errno( int error )
     }
 }
 
-DNS_STATUS CDECL resolv_get_serverlist( IP4_ARRAY *addrs, DWORD *len )
+DNS_STATUS CDECL resolv_get_serverlist( USHORT family, DNS_ADDR_ARRAY *addrs, DWORD *len )
 {
-    unsigned int size;
-    int i;
+    DWORD needed, i;
 
     init_resolver();
 
-    size = FIELD_OFFSET(IP4_ARRAY, AddrArray[_res.nscount]);
-    if (!addrs || *len < size)
+    if (family != WS_AF_INET) return ERROR_NOT_SUPPORTED;
+
+    needed = FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[_res.nscount]);
+
+    if (!addrs || *len < needed)
     {
-        *len = size;
-        return ERROR_INSUFFICIENT_BUFFER;
+        *len = needed;
+        return !addrs ? ERROR_SUCCESS : ERROR_MORE_DATA;
     }
 
-    addrs->AddrCount = _res.nscount;
+    *len = needed;
+    memset( addrs, 0, needed );
+    addrs->AddrCount = addrs->MaxCount = _res.nscount;
 
     for (i = 0; i < _res.nscount; i++)
-        addrs->AddrArray[i] = _res.nsaddr_list[i].sin_addr.s_addr;
-
+    {
+        SOCKADDR_INET *inet = (SOCKADDR_INET *)addrs->AddrArray[i].MaxSa;
+        inet->Ipv4.sin_family = WS_AF_INET;
+        inet->Ipv4.sin_addr.WS_s_addr = _res.nsaddr_list[i].sin_addr.s_addr;
+        addrs->AddrArray[i].Data.DnsAddrUserDword[0] = sizeof(SOCKADDR_IN);
+    }
     return ERROR_SUCCESS;
 }
 
diff --git a/dlls/dnsapi/query.c b/dlls/dnsapi/query.c
index a7ae77148be..b836cdaaf48 100644
--- a/dlls/dnsapi/query.c
+++ b/dlls/dnsapi/query.c
@@ -25,6 +25,7 @@
 #include "winnls.h"
 #include "windns.h"
 #include "nb30.h"
+#include "ws2def.h"
 
 #include "wine/debug.h"
 #include "dnsapi.h"
@@ -259,6 +260,46 @@ static DNS_STATUS get_hostname_w( COMPUTER_NAME_FORMAT format, PWSTR buffer, PDW
     return ERROR_SUCCESS;
 }
 
+static DNS_STATUS get_dns_server_list( IP4_ARRAY *out, DWORD *len )
+{
+    char buf[FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[3])];
+    DNS_ADDR_ARRAY *servers = (DNS_ADDR_ARRAY *)buf;
+    DWORD ret, needed, i, num, array_len = sizeof(buf);
+
+    for (;;)
+    {
+        ret = resolv_funcs->get_serverlist( AF_INET, servers, &array_len );
+        if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) goto err;
+        num = (array_len - FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[0])) / sizeof(DNS_ADDR);
+        needed = FIELD_OFFSET(IP4_ARRAY, AddrArray[num]);
+        if (!out || *len < needed)
+        {
+            *len = needed;
+            ret = !out ? ERROR_SUCCESS : ERROR_MORE_DATA;
+            goto err;
+        }
+        if (!ret) break;
+
+        if ((char *)servers != buf) heap_free( servers );
+        servers = heap_alloc( array_len );
+        if (!servers)
+        {
+            ret = ERROR_NOT_ENOUGH_MEMORY;
+            goto err;
+        }
+    }
+
+    out->AddrCount = num;
+    for (i = 0; i < num; i++)
+        out->AddrArray[i] = ((SOCKADDR_IN *)servers->AddrArray[i].MaxSa)->sin_addr.s_addr;
+    *len = needed;
+    ret = ERROR_SUCCESS;
+
+err:
+    if ((char *)servers != buf) heap_free( servers );
+    return ret;
+}
+
 /******************************************************************************
  * DnsQueryConfig          [DNSAPI.@]
  *
@@ -276,10 +317,8 @@ DNS_STATUS WINAPI DnsQueryConfig( DNS_CONFIG_TYPE config, DWORD flag, PCWSTR ada
     switch (config)
     {
     case DnsConfigDnsServerList:
-    {
-        ret = resolv_funcs->get_serverlist( buffer, len );
-        break;
-    }
+        return get_dns_server_list( buffer, len );
+
     case DnsConfigHostName_A:
     case DnsConfigHostName_UTF8:
         return get_hostname_a( ComputerNameDnsHostname, buffer, len );
@@ -312,6 +351,9 @@ DNS_STATUS WINAPI DnsQueryConfig( DNS_CONFIG_TYPE config, DWORD flag, PCWSTR ada
         FIXME( "unimplemented config type %d\n", config );
         break;
 
+    case DnsConfigDnsServersIpv4:
+        return resolv_funcs->get_serverlist( AF_INET, buffer, len );
+
     default:
         WARN( "unknown config type: %d\n", config );
         break;
diff --git a/dlls/dnsapi/tests/Makefile.in b/dlls/dnsapi/tests/Makefile.in
index f476103b096..3f8c424b4f7 100644
--- a/dlls/dnsapi/tests/Makefile.in
+++ b/dlls/dnsapi/tests/Makefile.in
@@ -1,5 +1,5 @@
 TESTDLL   = dnsapi.dll
-IMPORTS   = dnsapi ws2_32
+IMPORTS   = dnsapi ws2_32 iphlpapi
 
 C_SRCS = \
 	cache.c \
diff --git a/dlls/dnsapi/tests/query.c b/dlls/dnsapi/tests/query.c
index bee3353e1b9..d11a53b5306 100644
--- a/dlls/dnsapi/tests/query.c
+++ b/dlls/dnsapi/tests/query.c
@@ -25,6 +25,7 @@
 #include "windns.h"
 #include "winsock2.h"
 #include "ws2ipdef.h"
+#include "iphlpapi.h"
 
 #include "wine/test.h"
 
@@ -118,6 +119,80 @@ static void test_DnsQuery(void)
     }
 }
 
+static IP_ADAPTER_ADDRESSES *get_adapters(void)
+{
+    ULONG err, size = 1024;
+    IP_ADAPTER_ADDRESSES *ret = malloc( size );
+    for (;;)
+    {
+        err = GetAdaptersAddresses( AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
+                                               GAA_FLAG_SKIP_FRIENDLY_NAME,
+                                    NULL, ret, &size );
+        if (err != ERROR_BUFFER_OVERFLOW) break;
+        ret = realloc( ret, size );
+    }
+    if (err == ERROR_SUCCESS) return ret;
+    free( ret );
+    return NULL;
+}
+
+static void test_DnsQueryConfig( void )
+{
+    DWORD err, size, i;
+    WCHAR name[MAX_ADAPTER_NAME_LENGTH + 1];
+    IP_ADAPTER_ADDRESSES *adapters, *ptr;
+    DNS_ADDR_ARRAY *ipv4;
+    IP4_ARRAY *ip4_array;
+
+    if (!(adapters = get_adapters())) return;
+
+    for (ptr = adapters; ptr; ptr = ptr->Next)
+    {
+        MultiByteToWideChar( CP_ACP, 0, ptr->AdapterName, -1, name, ARRAY_SIZE(name) );
+        if (ptr->IfType == IF_TYPE_SOFTWARE_LOOPBACK) continue;
+
+        size = 0;
+        err = DnsQueryConfig( DnsConfigDnsServersIpv4, 0, name, NULL, NULL, &size );
+        if (err) continue;
+        ipv4 = malloc( size );
+        err = DnsQueryConfig( DnsConfigDnsServersIpv4, 0, name, NULL, ipv4, &size );
+        ok( !err, "got %d\n", err );
+
+        ok( ipv4->AddrCount == ipv4->MaxCount, "got %d vs %d\n", ipv4->AddrCount, ipv4->MaxCount );
+        ok( !ipv4->Tag, "got %08x\n", ipv4->Tag );
+        ok( !ipv4->Family, "got %d\n", ipv4->Family );
+        ok( !ipv4->WordReserved, "got %04x\n", ipv4->WordReserved );
+        ok( !ipv4->Flags, "got %08x\n", ipv4->Flags );
+        ok( !ipv4->MatchFlag, "got %08x\n", ipv4->MatchFlag );
+        ok( !ipv4->Reserved1, "got %08x\n", ipv4->Reserved1 );
+        ok( !ipv4->Reserved2, "got %08x\n", ipv4->Reserved2 );
+
+        size = 0;
+        err = DnsQueryConfig( DnsConfigDnsServerList, 0, name, NULL, NULL, &size );
+        ok( !err, "got %d\n", err );
+        ip4_array = malloc( size );
+        err = DnsQueryConfig( DnsConfigDnsServerList, 0, name, NULL, ip4_array, &size );
+        ok( !err, "got %d\n", err );
+
+        ok( ipv4->AddrCount == ip4_array->AddrCount, "got %d vs %d\n", ipv4->AddrCount, ip4_array->AddrCount );
+
+        for (i = 0; i < ipv4->AddrCount; i++)
+        {
+            SOCKADDR_IN *sa = (SOCKADDR_IN *)ipv4->AddrArray[i].MaxSa;
+
+            ok( sa->sin_family == AF_INET, "got %d\n", sa->sin_family );
+            ok( sa->sin_addr.s_addr == ip4_array->AddrArray[i], "got %08x vs %08x\n",
+                sa->sin_addr.s_addr, ip4_array->AddrArray[i] );
+            ok( ipv4->AddrArray[i].Data.DnsAddrUserDword[0] == sizeof(*sa), "got %d\n",
+                ipv4->AddrArray[i].Data.DnsAddrUserDword[0] );
+        }
+        free( ip4_array );
+        free( ipv4 );
+    }
+
+    free( adapters );
+}
+
 START_TEST(query)
 {
     WSADATA data;
@@ -125,4 +200,5 @@ START_TEST(query)
     WSAStartup(MAKEWORD(2, 2), &data);
 
     test_DnsQuery();
+    test_DnsQueryConfig();
 }
diff --git a/include/windns.h b/include/windns.h
index 26d37165ce1..f1f2184281c 100644
--- a/include/windns.h
+++ b/include/windns.h
@@ -152,7 +152,12 @@ typedef enum _DNS_CONFIG_TYPE
     DnsConfigHostName_UTF8,
     DnsConfigFullHostName_W,
     DnsConfigFullHostName_A,
-    DnsConfigFullHostName_UTF8
+    DnsConfigFullHostName_UTF8,
+
+    /* These are undocumented and return a DNS_ADDR_ARRAY */
+    DnsConfigDnsServersUnspec = 4144,
+    DnsConfigDnsServersIpv4,
+    DnsConfigDnsServersIpv6
 } DNS_CONFIG_TYPE;
 
 typedef enum _DnsSection




More information about the wine-cvs mailing list