Zebediah Figura : server: Support passing to bind a zero sin6_scope_id.

Alexandre Julliard julliard at winehq.org
Thu Jul 22 16:28:18 CDT 2021


Module: wine
Branch: master
Commit: 9b257ed63f44067e9c7bbe3abd731b2f212a325c
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=9b257ed63f44067e9c7bbe3abd731b2f212a325c

Author: Zebediah Figura <zfigura at codeweavers.com>
Date:   Wed Jul 21 20:34:54 2021 -0500

server: Support passing to bind a zero sin6_scope_id.

Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ws2_32/tests/sock.c | 19 ++++++++-----------
 server/sock.c            | 44 +++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 51 insertions(+), 12 deletions(-)

diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index dd880531047..ed7d5121332 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -10679,27 +10679,24 @@ static void test_bind(void)
 
                 addr6.sin6_scope_id = 0;
                 ret = bind(s, (struct sockaddr *)&addr6, sizeof(addr6));
-                todo_wine ok(!ret, "got error %u\n", WSAGetLastError());
+                todo_wine_if (!((const struct sockaddr_in6 *)unicast_addr->Address.lpSockaddr)->sin6_scope_id)
+                    ok(!ret, "got error %u\n", WSAGetLastError());
 
                 memcpy(&addr6, unicast_addr->Address.lpSockaddr, sizeof(addr6));
 
                 len = sizeof(struct sockaddr_in6_old);
                 ret = getsockname(s, (struct sockaddr *)&ret_addr6, &len);
                 ok(ret == -1, "expected failure\n");
-                todo_wine_if (addr6.sin6_scope_id)
-                    ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError());
+                ok(WSAGetLastError() == WSAEFAULT, "got error %u\n", WSAGetLastError());
 
                 len = sizeof(ret_addr6);
                 memset(&ret_addr6, 0, sizeof(ret_addr6));
                 ret = getsockname(s, (struct sockaddr *)&ret_addr6, &len);
-                todo_wine_if (addr6.sin6_scope_id)
-                {
-                    ok(!ret, "got error %u\n", WSAGetLastError());
-                    ok(ret_addr6.sin6_family == AF_INET6, "got family %u\n", ret_addr6.sin6_family);
-                    ok(ret_addr6.sin6_port != 0, "expected nonzero port\n");
-                    ok(!memcmp(&ret_addr6.sin6_addr, &addr6.sin6_addr, sizeof(addr6.sin6_addr)), "address didn't match\n");
-                    ok(ret_addr6.sin6_scope_id == addr6.sin6_scope_id, "got scope %u\n", ret_addr6.sin6_scope_id);
-                }
+                ok(!ret, "got error %u\n", WSAGetLastError());
+                ok(ret_addr6.sin6_family == AF_INET6, "got family %u\n", ret_addr6.sin6_family);
+                ok(ret_addr6.sin6_port != 0, "expected nonzero port\n");
+                ok(!memcmp(&ret_addr6.sin6_addr, &addr6.sin6_addr, sizeof(addr6.sin6_addr)), "address didn't match\n");
+                ok(ret_addr6.sin6_scope_id == addr6.sin6_scope_id, "got scope %u\n", ret_addr6.sin6_scope_id);
 
                 closesocket(s);
             }
diff --git a/server/sock.c b/server/sock.c
index 6a8cb328df2..e28b0349027 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -1849,6 +1849,38 @@ static int bind_to_interface( struct sock *sock, const struct sockaddr_in *addr
     return 0;
 }
 
+#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
+static unsigned int get_ipv6_interface_index( const struct in6_addr *addr )
+{
+    struct ifaddrs *ifaddrs, *ifaddr;
+
+    if (getifaddrs( &ifaddrs ) < 0) return 0;
+
+    for (ifaddr = ifaddrs; ifaddr != NULL; ifaddr = ifaddr->ifa_next)
+    {
+        if (ifaddr->ifa_addr && ifaddr->ifa_addr->sa_family == AF_INET6
+                && !memcmp( &((struct sockaddr_in6 *)ifaddr->ifa_addr)->sin6_addr, addr, sizeof(*addr) ))
+        {
+            unsigned int index = if_nametoindex( ifaddr->ifa_name );
+
+            if (!index)
+            {
+                if (debug_level)
+                    fprintf( stderr, "Unable to look up interface index for %s: %s\n",
+                             ifaddr->ifa_name, strerror( errno ) );
+                continue;
+            }
+
+            freeifaddrs( ifaddrs );
+            return index;
+        }
+    }
+
+    freeifaddrs( ifaddrs );
+    return 0;
+}
+#endif
+
 /* return an errno value mapped to a WSA error */
 static unsigned int sock_get_error( int err )
 {
@@ -2477,12 +2509,22 @@ static int sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
         }
         bind_addr = unix_addr;
 
-        if (unix_addr.addr.sa_family == WS_AF_INET)
+        if (unix_addr.addr.sa_family == AF_INET)
         {
             if (!memcmp( &unix_addr.in.sin_addr, magic_loopback_addr, 4 )
                     || bind_to_interface( sock, &unix_addr.in ))
                 bind_addr.in.sin_addr.s_addr = htonl( INADDR_ANY );
         }
+        else if (unix_addr.addr.sa_family == AF_INET6)
+        {
+#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
+            /* Windows allows specifying zero to use the default scope. Linux
+             * interprets it as an interface index and requires that it be
+             * nonzero. */
+            if (!unix_addr.in6.sin6_scope_id)
+                bind_addr.in6.sin6_scope_id = get_ipv6_interface_index( &unix_addr.in6.sin6_addr );
+#endif
+        }
 
         if (bind( unix_fd, &bind_addr.addr, unix_len ) < 0)
         {




More information about the wine-cvs mailing list