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;