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