PATCH] ws2_32: Allow user to enable IP dual stack.

Matthieu Nottale matthieu.nottale at infinit.io
Mon Jul 4 04:35:34 CDT 2016


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.

Signed-off-by: Matthieu Nottale <matthieu.nottale at infinit.io>
---
  dlls/ws2_32/socket.c     | 22 ++++++++--------------
  dlls/ws2_32/tests/sock.c | 40 ++++++++++++++++++++++++++++++++++++++++
  2 files changed, 48 insertions(+), 14 deletions(-)

diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
index b0af3d7..c29bd2b 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;
@@ -7163,6 +7149,14 @@ 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)
+        {
+          /* Winsock documentation stipulates that IPV6_V6ONLY is 
enabled by default*/
+          int enable = 1;
+          WS_setsockopt(ret, WS_IPPROTO_IPV6, WS_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 6853279..7c8d834 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -6114,6 +6114,46 @@ 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);

+    if (v4 != INVALID_SOCKET)
+        closesocket(v4);
+    if (v6 != INVALID_SOCKET)
+        closesocket(v6);
+
+    /* Test again, this time disabling V6ONLY*/
+    v6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
+    if (v6 == INVALID_SOCKET) {
+        skip("Could not create IPv6 socket (LastError: %d; %d expected 
if IPv6 not available).\n",
+            WSAGetLastError(), WSAEAFNOSUPPORT);
+        goto end;
+    }
+    DWORD enabled = 0;
+    int len = sizeof(enabled);
+    ret = setsockopt(v6, IPPROTO_IPV6, IPV6_V6ONLY, &enabled, len);
+    if (ret) {
+      ok(!ret, "Failed to disable IPV6_V6ONLY (LastError: %d).\n", 
WSAGetLastError());
+      goto end;
+    }
+    ret = bind(v6, (struct sockaddr*)&sin6, sizeof(sin6));
+    if (ret) {
+        skip("Could not bind IPv6 address (LastError: %d).\n",
+            WSAGetLastError());
+        goto end;
+    }
+    ret = getsockopt(v6, IPPROTO_IPV6, IPV6_V6ONLY, &enabled, &len);
+    if (ret) {
+      ok(!ret, "Failed to check IPV6_V6ONLY (LastError: %d).\n", 
WSAGetLastError());
+      goto end;
+    }
+    ok(!enabled, "IPV6_V6ONLY is enabled after bind\n");
+    v4 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (v4 == INVALID_SOCKET) {
+        skip("Could not create IPv4 socket (LastError: %d).\n",
+            WSAGetLastError());
+        goto end;
+    }
+    ret = bind(v4, (struct sockaddr*)&sin4, sizeof(sin4));
+    ok(ret, "Could bind IPv4 address when it should have failed 
(LastError: %d; %d expected if IPv6 binds to IPv4 as well).\n",
+        WSAGetLastError(), WSAEADDRINUSE);
  end:
      if (v4 != INVALID_SOCKET)
          closesocket(v4);
-- 
2.5.0



Attached is a test program that shows the behaviour difference between 
wine and Windows.
Here is its output:

WINE
$ ./st
default v6only 0
v6only after bind: 1
$ ./st set
default v6only 0
vs6only disabled: 0
v6only after bind: 1

WINE WITH PATCH and NATIVE
$ ./st
default v6only 1
v6only after bind: 1
$ ./st set
default v6only 1
vs6only disabled: 0
v6only after bind: 0








-------------- next part --------------
A non-text attachment was scrubbed...
Name: sockettest.c
Type: text/x-c
Size: 1372 bytes
Desc: not available
URL: <http://www.winehq.org/pipermail/wine-patches/attachments/20160704/3ce478fe/attachment-0001.bin>


More information about the wine-patches mailing list