Module: wine Branch: master Commit: 9b257ed63f44067e9c7bbe3abd731b2f212a325c URL: https://source.winehq.org/git/wine.git/?a=commit;h=9b257ed63f44067e9c7bbe3ab...
Author: Zebediah Figura zfigura@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@codeweavers.com Signed-off-by: Alexandre Julliard julliard@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) {