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