Hans Leidekker : ws2_32: Implement AI_DNS_ONLY using DNS APIs.
Alexandre Julliard
julliard at winehq.org
Tue Nov 30 16:18:51 CST 2021
Module: wine
Branch: master
Commit: 7c39ce0a6cf8a3df1337a0768045c43044fce2f6
URL: https://source.winehq.org/git/wine.git/?a=commit;h=7c39ce0a6cf8a3df1337a0768045c43044fce2f6
Author: Hans Leidekker <hans at codeweavers.com>
Date: Tue Nov 30 17:29:07 2021 +0100
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 at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/ws2_32/Makefile.in | 2 +-
dlls/ws2_32/protocol.c | 84 ++++++++++++++++++++++++++++++++++++++++++++
dlls/ws2_32/tests/protocol.c | 20 +++++++++++
dlls/ws2_32/ws2_32_private.h | 1 +
include/ws2def.h | 6 ++++
5 files changed, 112 insertions(+), 1 deletion(-)
diff --git a/dlls/ws2_32/Makefile.in b/dlls/ws2_32/Makefile.in
index 232ce7f31fd..83ae5e915ae 100644
--- a/dlls/ws2_32/Makefile.in
+++ b/dlls/ws2_32/Makefile.in
@@ -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 \
diff --git a/dlls/ws2_32/protocol.c b/dlls/ws2_32/protocol.c
index 492400b17a7..239e4d14cd2 100644
--- a/dlls/ws2_32/protocol.c
+++ b/dlls/ws2_32/protocol.c
@@ -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;
diff --git a/dlls/ws2_32/tests/protocol.c b/dlls/ws2_32/tests/protocol.c
index bb09dc98f1c..6eebb5f6b4d 100644
--- a/dlls/ws2_32/tests/protocol.c
+++ b/dlls/ws2_32/tests/protocol.c
@@ -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)
diff --git a/dlls/ws2_32/ws2_32_private.h b/dlls/ws2_32/ws2_32_private.h
index 8ad3e0d17e9..fa2f89f6e98 100644
--- a/dlls/ws2_32/ws2_32_private.h
+++ b/dlls/ws2_32/ws2_32_private.h
@@ -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"
diff --git a/include/ws2def.h b/include/ws2def.h
index 9ddfa031633..46fb80db470 100644
--- a/include/ws2def.h
+++ b/include/ws2def.h
@@ -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;
More information about the wine-cvs
mailing list