Huw Davies : dnsapi: Add support for returning ipv6 dns server addresses.

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


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

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

dnsapi: Add support for returning ipv6 dns server addresses.

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

---

 dlls/dnsapi/libresolv.c   | 131 ++++++++++++++++++++++++++++++++++++++++++----
 dlls/dnsapi/query.c       |   4 ++
 dlls/dnsapi/tests/query.c |  30 ++++++++++-
 3 files changed, 154 insertions(+), 11 deletions(-)

diff --git a/dlls/dnsapi/libresolv.c b/dlls/dnsapi/libresolv.c
index 7e754d73af3..b0374927b6d 100644
--- a/dlls/dnsapi/libresolv.c
+++ b/dlls/dnsapi/libresolv.c
@@ -28,6 +28,7 @@
 #include <stdarg.h>
 #include <string.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <sys/types.h>
 
 #ifdef HAVE_NETINET_IN_H
@@ -228,35 +229,147 @@ static DNS_STATUS map_h_errno( int error )
     }
 }
 
+static inline int filter( unsigned short sin_family, USHORT family )
+{
+    if (sin_family != AF_INET && sin_family != AF_INET6) return TRUE;
+    if (sin_family == AF_INET6 && family == WS_AF_INET) return TRUE;
+    if (sin_family == AF_INET && family == WS_AF_INET6) return TRUE;
+
+    return FALSE;
+}
+
+#ifdef HAVE_RES_GETSERVERS
+
 DNS_STATUS CDECL resolv_get_serverlist( USHORT family, DNS_ADDR_ARRAY *addrs, DWORD *len )
 {
-    DWORD needed, i;
+    struct __res_state *state = &_res;
+    DWORD i, found, total, needed;
+    union res_sockaddr_union *buf;
 
     init_resolver();
 
-    if (family != WS_AF_INET) return ERROR_NOT_SUPPORTED;
+    total = res_getservers( state, NULL, 0 );
+    if (!total) return DNS_ERROR_NO_DNS_SERVERS;
 
-    needed = FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[_res.nscount]);
+    if (!addrs && family != WS_AF_INET && family != WS_AF_INET6)
+    {
+        *len = FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[total]);
+        return ERROR_SUCCESS;
+    }
 
+    buf = malloc( total * sizeof(union res_sockaddr_union) );
+    if (!buf) return ERROR_NOT_ENOUGH_MEMORY;
+
+    total = res_getservers( state, buf, total );
+
+    for (i = 0, found = 0; i < total; i++)
+    {
+        if (filter( buf[i].sin.sin_family, family )) continue;
+        found++;
+    }
+    if (!found) return DNS_ERROR_NO_DNS_SERVERS;
+
+    needed = FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[found]);
     if (!addrs || *len < needed)
     {
         *len = needed;
         return !addrs ? ERROR_SUCCESS : ERROR_MORE_DATA;
     }
+    *len = needed;
+    memset( addrs, 0, needed );
+    addrs->AddrCount = addrs->MaxCount = found;
+
+    for (i = 0, found = 0; i < total; i++)
+    {
+        if (filter( buf[i].sin.sin_family, family )) continue;
+
+        if (buf[i].sin6.sin6_family == AF_INET6)
+        {
+            SOCKADDR_IN6 *sa = (SOCKADDR_IN6 *)addrs->AddrArray[found].MaxSa;
+            sa->sin6_family = WS_AF_INET6;
+            memcpy( &sa->sin6_addr, &buf[i].sin6.sin6_addr, sizeof(sa->sin6_addr) );
+            addrs->AddrArray[found].Data.DnsAddrUserDword[0] = sizeof(*sa);
+        }
+        else
+        {
+            SOCKADDR_IN *sa = (SOCKADDR_IN *)addrs->AddrArray[found].MaxSa;
+            sa->sin_family = WS_AF_INET;
+            sa->sin_addr.WS_s_addr = buf[i].sin.sin_addr.s_addr;
+            addrs->AddrArray[found].Data.DnsAddrUserDword[0] = sizeof(*sa);
+        }
+        found++;
+    }
+
+    free( buf );
+    return ERROR_SUCCESS;
+}
+
+#else
+
+DNS_STATUS CDECL resolv_get_serverlist( USHORT family, DNS_ADDR_ARRAY *addrs, DWORD *len )
+{
+    DWORD needed, found, i;
+
+    init_resolver();
+
+    if (!_res.nscount) return DNS_ERROR_NO_DNS_SERVERS;
+    if (!addrs && family != WS_AF_INET && family != WS_AF_INET6)
+    {
+        *len = FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[_res.nscount]);
+        return ERROR_SUCCESS;
+    }
+
+    for (i = 0, found = 0; i < _res.nscount; i++)
+    {
+        unsigned short sin_family = AF_INET;
+#ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
+        if (_res._u._ext.nsaddrs[i]) sin_family = _res._u._ext.nsaddrs[i]->sin6_family;
+#endif
+        if (filter( sin_family, family )) continue;
+        found++;
+    }
+    if (!found) return DNS_ERROR_NO_DNS_SERVERS;
 
+    needed = FIELD_OFFSET(DNS_ADDR_ARRAY, AddrArray[found]);
+    if (!addrs || *len < needed)
+    {
+        *len = needed;
+        return !addrs ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
+    }
     *len = needed;
     memset( addrs, 0, needed );
-    addrs->AddrCount = addrs->MaxCount = _res.nscount;
+    addrs->AddrCount = addrs->MaxCount = found;
 
-    for (i = 0; i < _res.nscount; i++)
+    for (i = 0, found = 0; i < _res.nscount; i++)
     {
-        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);
+        unsigned short sin_family = AF_INET;
+#ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
+        if (_res._u._ext.nsaddrs[i]) sin_family = _res._u._ext.nsaddrs[i]->sin6_family;
+#endif
+        if (filter( sin_family, family )) continue;
+
+#ifdef HAVE_STRUCT___RES_STATE__U__EXT_NSCOUNT6
+        if (sin_family == AF_INET6)
+        {
+            SOCKADDR_IN6 *sa = (SOCKADDR_IN6 *)addrs->AddrArray[found].MaxSa;
+            sa->sin6_family = WS_AF_INET6;
+            memcpy( &sa->sin6_addr, &_res._u._ext.nsaddrs[i]->sin6_addr, sizeof(sa->sin6_addr) );
+            addrs->AddrArray[found].Data.DnsAddrUserDword[0] = sizeof(*sa);
+        }
+        else
+#endif
+        {
+            SOCKADDR_IN *sa = (SOCKADDR_IN *)addrs->AddrArray[found].MaxSa;
+            sa->sin_family = WS_AF_INET;
+            sa->sin_addr.WS_s_addr = _res.nsaddr_list[i].sin_addr.s_addr;
+            addrs->AddrArray[found].Data.DnsAddrUserDword[0] = sizeof(*sa);
+        }
+        found++;
     }
+
     return ERROR_SUCCESS;
 }
+#endif
 
 DNS_STATUS CDECL resolv_set_serverlist( const IP4_ARRAY *addrs )
 {
diff --git a/dlls/dnsapi/query.c b/dlls/dnsapi/query.c
index b836cdaaf48..9900166aeb8 100644
--- a/dlls/dnsapi/query.c
+++ b/dlls/dnsapi/query.c
@@ -351,8 +351,12 @@ DNS_STATUS WINAPI DnsQueryConfig( DNS_CONFIG_TYPE config, DWORD flag, PCWSTR ada
         FIXME( "unimplemented config type %d\n", config );
         break;
 
+    case DnsConfigDnsServersUnspec:
+        return resolv_funcs->get_serverlist( AF_UNSPEC, buffer, len );
     case DnsConfigDnsServersIpv4:
         return resolv_funcs->get_serverlist( AF_INET, buffer, len );
+    case DnsConfigDnsServersIpv6:
+        return resolv_funcs->get_serverlist( AF_INET6, buffer, len );
 
     default:
         WARN( "unknown config type: %d\n", config );
diff --git a/dlls/dnsapi/tests/query.c b/dlls/dnsapi/tests/query.c
index d11a53b5306..5fb47d89782 100644
--- a/dlls/dnsapi/tests/query.c
+++ b/dlls/dnsapi/tests/query.c
@@ -138,10 +138,10 @@ static IP_ADAPTER_ADDRESSES *get_adapters(void)
 
 static void test_DnsQueryConfig( void )
 {
-    DWORD err, size, i;
+    DWORD err, size, i, ipv6_count;
     WCHAR name[MAX_ADAPTER_NAME_LENGTH + 1];
     IP_ADAPTER_ADDRESSES *adapters, *ptr;
-    DNS_ADDR_ARRAY *ipv4;
+    DNS_ADDR_ARRAY *ipv4, *ipv6, *unspec;
     IP4_ARRAY *ip4_array;
 
     if (!(adapters = get_adapters())) return;
@@ -186,7 +186,33 @@ static void test_DnsQueryConfig( void )
             ok( ipv4->AddrArray[i].Data.DnsAddrUserDword[0] == sizeof(*sa), "got %d\n",
                 ipv4->AddrArray[i].Data.DnsAddrUserDword[0] );
         }
+
+        size = 0;
+        err = DnsQueryConfig( DnsConfigDnsServersIpv6, 0, name, NULL, NULL, &size );
+        ok( !err || err == DNS_ERROR_NO_DNS_SERVERS, "got %d\n", err );
+        ipv6_count = 0;
+        ipv6 = NULL;
+        if (!err)
+        {
+            ipv6 = malloc( size );
+            err = DnsQueryConfig( DnsConfigDnsServersIpv6, 0, name, NULL, ipv6, &size );
+            ok( !err, "got %d\n", err );
+            ipv6_count = ipv6->AddrCount;
+        }
+
+        size = 0;
+        err = DnsQueryConfig( DnsConfigDnsServersUnspec, 0, name, NULL, NULL, &size );
+        ok( !err, "got %d\n", err );
+        unspec = malloc( size );
+        err = DnsQueryConfig( DnsConfigDnsServersUnspec, 0, name, NULL, unspec, &size );
+        ok( !err, "got %d\n", err );
+
+        ok( unspec->AddrCount == ipv4->AddrCount + ipv6_count, "got %d vs %d + %d\n",
+            unspec->AddrCount, ipv4->AddrCount, ipv6_count );
+
         free( ip4_array );
+        free( unspec );
+        free( ipv6 );
         free( ipv4 );
     }
 




More information about the wine-cvs mailing list