ws2_32: Implement AI_DNS_ONLY using DNS APIs.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52133
Signed-off-by: Hans Leidekker <hans@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Hans Leidekker 2021-11-30 17:29:07 +01:00 committed by Alexandre Julliard
parent d0acbcb0d7
commit 7c39ce0a6c
5 changed files with 112 additions and 1 deletions

View File

@ -1,7 +1,7 @@
MODULE = ws2_32.dll
UNIXLIB = ws2_32.so
IMPORTLIB = ws2_32
DELAYIMPORTS = advapi32 iphlpapi user32
DELAYIMPORTS = dnsapi advapi32 iphlpapi user32
C_SRCS = \
async.c \

View File

@ -69,6 +69,84 @@ static int do_getaddrinfo( const char *node, const char *service,
}
}
static int dns_only_query( const char *node, const struct addrinfo *hints, struct addrinfo **result )
{
DNS_STATUS status;
DNS_RECORDA *rec = NULL, *rec6 = NULL, *ptr;
struct addrinfo *info, *next;
struct sockaddr_in *addr;
struct sockaddr_in6 *addr6;
ULONG count = 0;
if (hints->ai_family != AF_INET && hints->ai_family != AF_INET6 && hints->ai_family != AF_UNSPEC)
{
FIXME( "unsupported family %u\n", hints->ai_family );
return EAI_FAMILY;
}
if (hints->ai_family == AF_INET || hints->ai_family == AF_UNSPEC)
{
status = DnsQuery_A( node, DNS_TYPE_A, DNS_QUERY_NO_NETBT | DNS_QUERY_NO_MULTICAST, NULL, &rec, NULL );
if (status != ERROR_SUCCESS && status != DNS_ERROR_RCODE_NAME_ERROR) return EAI_FAIL;
}
if (hints->ai_family == AF_INET6 || hints->ai_family == AF_UNSPEC)
{
status = DnsQuery_A( node, DNS_TYPE_AAAA, DNS_QUERY_NO_NETBT | DNS_QUERY_NO_MULTICAST, NULL, &rec6, NULL );
if (status != ERROR_SUCCESS && status != DNS_ERROR_RCODE_NAME_ERROR)
{
DnsRecordListFree( (DNS_RECORD *)rec, DnsFreeRecordList );
return EAI_FAIL;
}
}
for (ptr = rec; ptr; ptr = ptr->pNext) count++;
for (ptr = rec6; ptr; ptr = ptr->pNext) count++;
if (!count)
{
DnsRecordListFree( (DNS_RECORD *)rec, DnsFreeRecordList );
DnsRecordListFree( (DNS_RECORD *)rec6, DnsFreeRecordList );
return WSAHOST_NOT_FOUND;
}
if (!(info = calloc( count, sizeof(*info) + sizeof(SOCKADDR_STORAGE) )))
{
DnsRecordListFree( (DNS_RECORD *)rec, DnsFreeRecordList );
DnsRecordListFree( (DNS_RECORD *)rec6, DnsFreeRecordList );
return WSA_NOT_ENOUGH_MEMORY;
}
*result = info;
for (ptr = rec; ptr; ptr = ptr->pNext)
{
info->ai_family = AF_INET;
info->ai_socktype = hints->ai_socktype;
info->ai_protocol = hints->ai_protocol;
info->ai_addrlen = sizeof(struct sockaddr_in);
info->ai_addr = (struct sockaddr *)(info + 1);
addr = (struct sockaddr_in *)info->ai_addr;
addr->sin_family = info->ai_family;
addr->sin_addr.S_un.S_addr = ptr->Data.A.IpAddress;
next = (struct addrinfo *)((char *)info + sizeof(*info) + sizeof(SOCKADDR_STORAGE));
if (--count) info->ai_next = next;
info = next;
}
for (ptr = rec6; ptr; ptr = ptr->pNext)
{
info->ai_family = AF_INET6;
info->ai_socktype = hints->ai_socktype;
info->ai_protocol = hints->ai_protocol;
info->ai_addrlen = sizeof(struct sockaddr_in6);
info->ai_addr = (struct sockaddr *)(info + 1);
addr6 = (struct sockaddr_in6 *)info->ai_addr;
addr6->sin6_family = info->ai_family;
memcpy( &addr6->sin6_addr, &ptr->Data.AAAA.Ip6Address, sizeof(addr6->sin6_addr) );
next = (struct addrinfo *)((char *)info + sizeof(*info) + sizeof(SOCKADDR_STORAGE));
if (--count) info->ai_next = next;
info = next;
}
DnsRecordListFree( (DNS_RECORD *)rec, DnsFreeRecordList );
DnsRecordListFree( (DNS_RECORD *)rec6, DnsFreeRecordList );
return 0;
}
/***********************************************************************
* getaddrinfo (ws2_32.@)
@ -96,6 +174,11 @@ int WINAPI getaddrinfo( const char *node, const char *service,
if (!(fqdn = get_fqdn())) return WSA_NOT_ENOUGH_MEMORY;
node = fqdn;
}
else if (!service && hints && (hints->ai_flags == AI_DNS_ONLY || hints->ai_flags == (AI_ALL | AI_DNS_ONLY)))
{
ret = dns_only_query( node, hints, info );
goto done;
}
else if (!hints || hints->ai_family == AF_UNSPEC || hints->ai_family == AF_INET6)
{
/* [ipv6] or [ipv6]:portnumber are supported by Windows */
@ -139,6 +222,7 @@ int WINAPI getaddrinfo( const char *node, const char *service,
free( fqdn );
free( nodev6 );
done:
if (!ret && TRACE_ON(winsock))
{
struct addrinfo *ai;

View File

@ -2328,6 +2328,26 @@ static void test_getaddrinfo(void)
memset(&hint, 0, sizeof(hint));
ret = getaddrinfo(NULL, "nonexistentservice", &hint, &result);
ok(ret == WSATYPE_NOT_FOUND, "got %d\n", ret);
result = NULL;
memset(&hint, 0, sizeof(hint));
hint.ai_flags = AI_ALL | AI_DNS_ONLY;
hint.ai_family = AF_UNSPEC;
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = IPPROTO_TCP;
ret = getaddrinfo("winehq.org", NULL, &hint, &result);
ok(!ret, "getaddrinfo failed with %d\n", WSAGetLastError());
ok(!result->ai_flags, "ai_flags == %08x\n", result->ai_flags);
ok(result->ai_family == AF_INET, "ai_family == %d\n", result->ai_family);
ok(result->ai_socktype == SOCK_STREAM, "ai_socktype == %d\n", result->ai_socktype);
ok(result->ai_protocol == IPPROTO_TCP, "ai_protocol == %d\n", result->ai_protocol);
ok(!result->ai_canonname, "ai_canonname == %s\n", result->ai_canonname);
ok(result->ai_addrlen == sizeof(struct sockaddr_in), "ai_addrlen == %d\n", (int)result->ai_addrlen);
ok(result->ai_addr != NULL, "ai_addr == NULL\n");
sockaddr = (SOCKADDR_IN *)result->ai_addr;
ok(sockaddr->sin_family == AF_INET, "ai_addr->sin_family == %d\n", sockaddr->sin_family);
ok(sockaddr->sin_port == 0, "ai_addr->sin_port == %d\n", sockaddr->sin_port);
freeaddrinfo(result);
}
static void test_dns(void)

View File

@ -48,6 +48,7 @@
#define USE_WC_PREFIX /* For CMSG_DATA */
#include "iphlpapi.h"
#include "ip2string.h"
#include "windns.h"
#include "wine/afd.h"
#include "wine/debug.h"
#include "wine/unixlib.h"

View File

@ -284,6 +284,12 @@ typedef struct _WSAMSG {
(((unsigned char*)cmsg + WSA_CMSG_ALIGN(cmsg->cmsg_len)+WSA_CMSG_ALIGN(((WSACMSGHDR*)((unsigned char*)cmsg + WSA_CMSG_ALIGN(cmsg->cmsg_len)))->cmsg_len) > ((unsigned char*)(mhdr)->Control.buf + (mhdr)->Control.len)) ? NULL : \
(WSACMSGHDR*)((unsigned char*)cmsg + WSA_CMSG_ALIGN(cmsg->cmsg_len))))))
#ifndef USE_WS_PREFIX
#define AI_DNS_ONLY 0x00000010
#else
#define WS_AI_DNS_ONLY 0x00000010
#endif
typedef struct addrinfoexA {
int ai_flags;
int ai_family;