From: Roman Pišl Subject: [PATCH] ws2_32: Allow user to enable IP dual stack (v4). Message-Id: <1476728509-2511-1-git-send-email-rpisl@seznam.cz> Date: Mon, 17 Oct 2016 20:21:49 +0200 IP dual stack (v4+v6) should be disabled by default, but previous code was setting IPV6_V6ONLY in bind() which prevented user to override it. This patch moves setting IPV6_V6ONLY to socket creation time. Based on https://www.winehq.org/pipermail/wine-patches/2016-July/151919.html Signed-off-by: Matthieu Nottale Signed-off-by: Roman Pišl --- dlls/ws2_32/socket.c | 23 +++++++++------------- dlls/ws2_32/tests/sock.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 16 deletions(-) diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index e8c5130..d14e9d6 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -3240,20 +3240,6 @@ int WINAPI WS_bind(SOCKET s, const struct WS_sockaddr* name, int namelen) } else { -#ifdef IPV6_V6ONLY - const struct sockaddr_in6 *in6 = (const struct sockaddr_in6*) &uaddr; - if (name->sa_family == WS_AF_INET6 && - !memcmp(&in6->sin6_addr, &in6addr_any, sizeof(struct in6_addr))) - { - int enable = 1; - if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &enable, sizeof(enable)) == -1) - { - release_sock_fd( s, fd ); - SetLastError(WSAEAFNOSUPPORT); - return SOCKET_ERROR; - } - } -#endif if (name->sa_family == WS_AF_INET) { struct sockaddr_in *in4 = (struct sockaddr_in*) &uaddr; @@ -7233,6 +7219,15 @@ SOCKET WINAPI WSASocketW(int af, int type, int protocol, TRACE("\tcreated %04lx\n", ret ); if (ipxptype > 0) set_ipx_packettype(ret, ipxptype); + +#ifdef IPV6_V6ONLY + if (unixaf == AF_INET6) + { + int enable = 1; + int fd = get_sock_fd(ret, 0, NULL); + setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &enable, sizeof(enable)); + } +#endif return ret; } diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index a144bd3..a676255 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -1732,7 +1732,7 @@ static void test_so_reuseaddr(void) DWORD err; saddr.sin_family = AF_INET; - saddr.sin_port = htons(9375); + saddr.sin_port = htons(SERVERPORT+1); saddr.sin_addr.s_addr = inet_addr("127.0.0.1"); s1=socket(AF_INET, SOCK_STREAM, 0); @@ -6110,6 +6110,8 @@ static void test_ipv6only(void) struct sockaddr_in sin4; struct sockaddr_in6 sin6; int ret; + int enabled; + int len; memset(&sin4, 0, sizeof(sin4)); sin4.sin_family = AF_INET; @@ -6142,6 +6144,50 @@ static void test_ipv6only(void) ok(!ret, "Could not bind IPv4 address (LastError: %d; %d expected if IPv6 binds to IPv4 as well).\n", WSAGetLastError(), WSAEADDRINUSE); + closesocket(v4); + closesocket(v6); + v4 = INVALID_SOCKET; + v6 = INVALID_SOCKET; + + /* Test again, this time disabling V6ONLY. */ + sin4.sin_port = htons(SERVERPORT+2); + sin6.sin6_port = htons(SERVERPORT+2); + + v6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); + ok(v6 != INVALID_SOCKET, "Could not create IPv6 socket (LastError: %d; %d expected if IPv6 not available).\n", + WSAGetLastError(), WSAEAFNOSUPPORT); + + enabled = 2; + len = sizeof(enabled); + ret = getsockopt(v6, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&enabled, &len); + if (ret) { + skip("Could not check IPV6_V6ONLY (option not supported?) ((LastError: %d).\n", WSAGetLastError()); + goto end; + } + ok(enabled == 1, "IPV6_V6ONLY is not enabled by default.\n"); + + enabled = 0; + ret = setsockopt(v6, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&enabled, len); + ok(!ret, "Failed to disable IPV6_V6ONLY (LastError: %d).\n", WSAGetLastError()); + + ret = bind(v6, (struct sockaddr*)&sin6, sizeof(sin6)); + ok(!ret, "Could not bind IPv6 address (LastError: %d).\n", WSAGetLastError()); + + enabled = 2; + len = sizeof(enabled); + getsockopt(v6, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&enabled, &len); + ok(enabled == 0, "IPV6_V6ONLY is enabled after bind.\n"); + + v4 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + ok(v4 != INVALID_SOCKET, "Could not create IPv4 socket (LastError: %d).\n", + WSAGetLastError()); + + WSASetLastError(0xdeadbeef); + bind(v4, (struct sockaddr*)&sin4, sizeof(sin4)); + + ok(WSAGetLastError() == WSAEADDRINUSE, "Failed to disable IPV6_V6ONLY (LastError: %d; %d expected if IPv6 binds to IPv4 as well).\n", + WSAGetLastError(), WSAEADDRINUSE); + end: if (v4 != INVALID_SOCKET) closesocket(v4); @@ -8024,7 +8070,7 @@ static void test_TransmitFile(void) /* Setup a properly connected socket for transfers */ memset(&bindAddress, 0, sizeof(bindAddress)); bindAddress.sin_family = AF_INET; - bindAddress.sin_port = htons(9375); + bindAddress.sin_port = htons(SERVERPORT+1); bindAddress.sin_addr.s_addr = inet_addr("127.0.0.1"); iret = bind(server, (struct sockaddr*)&bindAddress, sizeof(bindAddress)); if (iret != 0) -- 2.7.3