[PATCH] Disabling IPV6_V6ONLY on AF_INET succeeds in Windows starting with Vista

Anton Romanov theli.ua at gmail.com
Tue Jan 10 11:44:09 CST 2017


Fixes Magic The Gathering Online not able to login
---
 dlls/ws2_32/socket.c     | 22 ++++++++++++++++++++++
 dlls/ws2_32/tests/sock.c | 24 +++++++++++++++++++++++-
 2 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index 6bf3c9d..b46f1ab 100644
--- a/dlls/ws2_32/socket.c
+++ b/dlls/ws2_32/socket.c
@@ -6050,6 +6050,28 @@ int WINAPI WS_setsockopt(SOCKET s, int level, int optname,
     fd = get_sock_fd( s, 0, NULL );
     if (fd == -1) return SOCKET_ERROR;
 
+    if (level == IPPROTO_IPV6 && optname == IPV6_V6ONLY && optlen == sizeof(int) 
+            && *(int*) optval == 0 && is_fd_bound(fd, NULL, NULL) == 0)
+    {
+        /* MSDN: Note  If the setsockopt function is called before the bind
+           function, TCP/IP options will not be checked by using TCP/IP until
+           the bind occurs. In this case, the setsockopt function call will
+           always succeed, but the bind function call can fail because of an
+           early setsockopt call failing.
+
+           This leads to succeeding disabling IPV6_V6ONLY on unbound AF_INET socket
+           */
+        int ret, addr_size = 0;
+        WSAPROTOCOL_INFOW infow;
+
+        ret = ws_protocol_info(s, TRUE, &infow, &addr_size);
+        if (ret && infow.iAddressFamily == WS_AF_INET)
+        {
+            release_sock_fd( s, fd );
+            return 0;
+        }
+    }
+
     if (setsockopt(fd, level, optname, optval, optlen) == 0)
     {
 #ifdef __APPLE__
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index ba755a5..ce57e94 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -6154,6 +6154,27 @@ end:
         CloseHandle(ov2.hEvent);
 }
 
+static void test_ipv6only_unbound(void)
+{
+    SOCKET v4 = INVALID_SOCKET;
+    int ret, enabled, len = sizeof(enabled);
+
+    v4 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    ok(v4 != INVALID_SOCKET, "Could not create IPv4 socket (LastError: %d)\n", WSAGetLastError());
+
+    /*
+        On Windows, disabling IPV6_V6ONLY on AF_INET succeeds
+        starting with vista
+    */
+    enabled = 0;
+    ret = setsockopt(v4, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&enabled, len);
+    ok(!ret || broken(ret), "Could not disable IPV6_V6ONLY (LastError: %d).\n", WSAGetLastError());
+
+end:
+    if (v4 != INVALID_SOCKET)
+        closesocket(v4);
+}
+
 static void test_ipv6only(void)
 {
     SOCKET v4 = INVALID_SOCKET, v6;
@@ -6189,7 +6210,7 @@ static void test_ipv6only(void)
     }
 
     v4 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-    ok(v4 != INVALID_SOCKET, "Could not create IPv6 socket (LastError: %d)\n", WSAGetLastError());
+    ok(v4 != INVALID_SOCKET, "Could not create IPv4 socket (LastError: %d)\n", WSAGetLastError());
 
     /* bind on IPv4 socket should succeed - IPV6_V6ONLY is enabled by default */
     ret = bind(v4, (struct sockaddr*)&sin4, sizeof(sin4));
@@ -10087,6 +10108,7 @@ START_TEST( sock )
     test_events(1);
 
     test_ipv6only();
+    test_ipv6only_unbound();
     test_TransmitFile();
     test_GetAddrInfoW();
     test_getaddrinfo();
-- 
2.9.0




More information about the wine-patches mailing list