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:
parent
bd80dd0903
commit
f705f5837c
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue