dnsapi: Add support for returning ipv6 dns server addresses.

Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Huw Davies 2021-08-03 09:20:22 +01:00 committed by Alexandre Julliard
parent bd80dd0903
commit f705f5837c
3 changed files with 155 additions and 12 deletions

View File

@ -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,36 +229,148 @@ 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 = _res.nscount;
addrs->AddrCount = addrs->MaxCount = found;
for (i = 0; i < _res.nscount; i++)
for (i = 0, found = 0; i < total; 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);
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 = found;
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;
#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 )
{
int i;

View File

@ -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 );

View File

@ -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 );
}