From 719715c77426c7cb759a012d24f898622db5db6b Mon Sep 17 00:00:00 2001 From: Bruno Jesus <00cpxxx@gmail.com> Date: Mon, 30 Dec 2013 23:45:07 -0200 Subject: [PATCH] ws2_32: Cope with invalid hints in getaddrinfo/GetAddrInfoW. --- dlls/ws2_32/socket.c | 46 +++++++++---- dlls/ws2_32/tests/sock.c | 142 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 171 insertions(+), 17 deletions(-) diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 462ff86b56e..03915543046 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -5464,19 +5464,33 @@ int WINAPI WS_getaddrinfo(LPCSTR nodename, LPCSTR servname, const struct WS_addr punixhints = &unixhints; memset(&unixhints, 0, sizeof(unixhints)); - punixhints->ai_flags = convert_aiflag_w2u(hints->ai_flags); - if (hints->ai_family == 0) /* wildcard, specific to getaddrinfo() */ - punixhints->ai_family = 0; - else + punixhints->ai_flags = convert_aiflag_w2u(hints->ai_flags); + + /* zero is a wildcard, no need to convert */ + if (hints->ai_family) punixhints->ai_family = convert_af_w2u(hints->ai_family); - if (hints->ai_socktype == 0) /* wildcard, specific to getaddrinfo() */ - punixhints->ai_socktype = 0; - else + if (hints->ai_socktype) punixhints->ai_socktype = convert_socktype_w2u(hints->ai_socktype); - if (hints->ai_protocol == 0) /* wildcard, specific to getaddrinfo() */ - punixhints->ai_protocol = 0; - else - punixhints->ai_protocol = convert_proto_w2u(hints->ai_protocol); + if (hints->ai_protocol) + punixhints->ai_protocol = max(convert_proto_w2u(hints->ai_protocol), 0); + + if (punixhints->ai_socktype < 0) + { + WSASetLastError(WSAESOCKTNOSUPPORT); + return SOCKET_ERROR; + } + + /* windows allows invalid combinations of socket type and protocol, unix does not. + * fix the parameters here to make getaddrinfo call always work */ + if (punixhints->ai_protocol == IPPROTO_TCP && + punixhints->ai_socktype != SOCK_STREAM && punixhints->ai_socktype != SOCK_SEQPACKET) + punixhints->ai_socktype = 0; + + else if (punixhints->ai_protocol == IPPROTO_UDP && punixhints->ai_socktype != SOCK_DGRAM) + punixhints->ai_socktype = 0; + + else if (IS_IPX_PROTO(punixhints->ai_protocol) && punixhints->ai_socktype != SOCK_DGRAM) + punixhints->ai_socktype = 0; } /* getaddrinfo(3) is thread safe, no need to wrap in CS */ @@ -5500,8 +5514,14 @@ int WINAPI WS_getaddrinfo(LPCSTR nodename, LPCSTR servname, const struct WS_addr *xai = ai;xai = &ai->ai_next; ai->ai_flags = convert_aiflag_u2w(xuai->ai_flags); ai->ai_family = convert_af_u2w(xuai->ai_family); - ai->ai_socktype = convert_socktype_u2w(xuai->ai_socktype); - ai->ai_protocol = convert_proto_u2w(xuai->ai_protocol); + /* copy whatever was sent in the hints */ + if(hints) { + ai->ai_socktype = hints->ai_socktype; + ai->ai_protocol = hints->ai_protocol; + } else { + ai->ai_socktype = convert_socktype_u2w(xuai->ai_socktype); + ai->ai_protocol = convert_proto_u2w(xuai->ai_protocol); + } if (xuai->ai_canonname) { TRACE("canon name - %s\n",debugstr_a(xuai->ai_canonname)); ai->ai_canonname = HeapAlloc(GetProcessHeap(),0,strlen(xuai->ai_canonname)+1); diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 59c356cf4ef..3c099742612 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -149,6 +149,38 @@ typedef struct select_thread_params BOOL ReadKilled; } select_thread_params; +/* Tests used in both getaddrinfo and GetAddrInfoW */ +static const struct addr_hint_tests +{ + int family, socktype, protocol; + DWORD error; +} hinttests[] = { + {AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, 0 }, + {AF_UNSPEC, SOCK_STREAM, IPPROTO_UDP, 0 }, + {AF_UNSPEC, SOCK_DGRAM, IPPROTO_TCP, 0 }, + {AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, 0 }, + {AF_INET, SOCK_STREAM, IPPROTO_TCP, 0 }, + {AF_INET, SOCK_STREAM, IPPROTO_UDP, 0 }, + {AF_INET, SOCK_DGRAM, IPPROTO_TCP, 0 }, + {AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0 }, + {AF_UNSPEC, 0, IPPROTO_TCP, 0 }, + {AF_UNSPEC, 0, IPPROTO_UDP, 0 }, + {AF_UNSPEC, SOCK_STREAM, 0, 0 }, + {AF_UNSPEC, SOCK_DGRAM, 0, 0 }, + {AF_INET, 0, IPPROTO_TCP, 0 }, + {AF_INET, 0, IPPROTO_UDP, 0 }, + {AF_INET, SOCK_STREAM, 0, 0 }, + {AF_INET, SOCK_DGRAM, 0, 0 }, + {AF_UNSPEC, 999, IPPROTO_TCP, WSAESOCKTNOSUPPORT }, + {AF_UNSPEC, 999, IPPROTO_UDP, WSAESOCKTNOSUPPORT }, + {AF_INET, 999, IPPROTO_TCP, WSAESOCKTNOSUPPORT }, + {AF_INET, 999, IPPROTO_UDP, WSAESOCKTNOSUPPORT }, + {AF_UNSPEC, SOCK_STREAM, 999, 0 }, + {AF_UNSPEC, SOCK_STREAM, 999, 0 }, + {AF_INET, SOCK_DGRAM, 999, 0 }, + {AF_INET, SOCK_DGRAM, 999, 0 }, +}; + /**************** Static variables ***************/ static DWORD tls; /* Thread local storage index */ @@ -5280,8 +5312,8 @@ static void test_GetAddrInfoW(void) static const WCHAR nxdomain[] = {'n','x','d','o','m','a','i','n','.','c','o','d','e','w','e','a','v','e','r','s','.','c','o','m',0}; static const WCHAR zero[] = {'0',0}; - int ret; - ADDRINFOW *result, hint; + int i, ret; + ADDRINFOW *result, *p, hint; if (!pGetAddrInfoW || !pFreeAddrInfoW) { @@ -5352,12 +5384,63 @@ static void test_GetAddrInfoW(void) ret = pGetAddrInfoW(nxdomain, NULL, NULL, &result); ok(ret == WSAHOST_NOT_FOUND, "got %d expected WSAHOST_NOT_FOUND\n", ret); ok(result == NULL, "got %p\n", result); + + for (i = 0;i < (sizeof(hinttests) / sizeof(hinttests[0]));i++) + { + hint.ai_family = hinttests[i].family; + hint.ai_socktype = hinttests[i].socktype; + hint.ai_protocol = hinttests[i].protocol; + + result = NULL; + SetLastError(0xdeadbeef); + ret = pGetAddrInfoW(localhost, NULL, &hint, &result); + if (!ret) + { + if (hinttests[i].error) + ok(0, "test %d: GetAddrInfoW succeeded unexpectedly\n", i); + else + { + p = result; + do + { + /* when AF_UNSPEC is used the return will be either AF_INET or AF_INET6 */ + if (hinttests[i].family == AF_UNSPEC) + ok(p->ai_family == AF_INET || p->ai_family == AF_INET6, + "test %d: expected AF_INET or AF_INET6, got %d\n", + i, p->ai_family); + else + ok(p->ai_family == hinttests[i].family, + "test %d: expected family %d, got %d\n", + i, hinttests[i].family, p->ai_family); + + ok(p->ai_socktype == hinttests[i].socktype, + "test %d: expected type %d, got %d\n", + i, hinttests[i].socktype, p->ai_socktype); + ok(p->ai_protocol == hinttests[i].protocol, + "test %d: expected protocol %d, got %d\n", + i, hinttests[i].protocol, p->ai_protocol); + p = p->ai_next; + } + while (p); + } + pFreeAddrInfoW(result); + } + else + { + DWORD err = WSAGetLastError(); + if (hinttests[i].error) + ok(hinttests[i].error == err, "test %d: GetAddrInfoW failed with error %d, expected %d\n", + i, err, hinttests[i].error); + else + ok(0, "test %d: GetAddrInfoW failed with %d (err %d)\n", i, ret, err); + } + } } static void test_getaddrinfo(void) { - int ret; - ADDRINFOA *result, hint; + int i, ret; + ADDRINFOA *result, *p, hint; if (!pgetaddrinfo || !pfreeaddrinfo) { @@ -5423,6 +5506,57 @@ static void test_getaddrinfo(void) ret = pgetaddrinfo("nxdomain.codeweavers.com", NULL, NULL, &result); ok(ret == WSAHOST_NOT_FOUND, "got %d expected WSAHOST_NOT_FOUND\n", ret); ok(result == NULL, "got %p\n", result); + + for (i = 0;i < (sizeof(hinttests) / sizeof(hinttests[0]));i++) + { + hint.ai_family = hinttests[i].family; + hint.ai_socktype = hinttests[i].socktype; + hint.ai_protocol = hinttests[i].protocol; + + result = NULL; + SetLastError(0xdeadbeef); + ret = pgetaddrinfo("localhost", NULL, &hint, &result); + if(!ret) + { + if (hinttests[i].error) + ok(0, "test %d: getaddrinfo succeeded unexpectedly\n", i); + else + { + p = result; + do + { + /* when AF_UNSPEC is used the return will be either AF_INET or AF_INET6 */ + if (hinttests[i].family == AF_UNSPEC) + ok(p->ai_family == AF_INET || p->ai_family == AF_INET6, + "test %d: expected AF_INET or AF_INET6, got %d\n", + i, p->ai_family); + else + ok(p->ai_family == hinttests[i].family, + "test %d: expected family %d, got %d\n", + i, hinttests[i].family, p->ai_family); + + ok(p->ai_socktype == hinttests[i].socktype, + "test %d: expected type %d, got %d\n", + i, hinttests[i].socktype, p->ai_socktype); + ok(p->ai_protocol == hinttests[i].protocol, + "test %d: expected protocol %d, got %d\n", + i, hinttests[i].protocol, p->ai_protocol); + p = p->ai_next; + } + while (p); + } + pfreeaddrinfo(result); + } + else + { + DWORD err = WSAGetLastError(); + if (hinttests[i].error) + ok(hinttests[i].error == err, "test %d: getaddrinfo failed with error %d, expected %d\n", + i, err, hinttests[i].error); + else + ok(0, "test %d: getaddrinfo failed with %d (err %d)\n", i, ret, err); + } + } } static void test_ConnectEx(void)