Paul Gofman : server: Use SO_BINDTODEVICE in bind_to_index() if possible.
Alexandre Julliard
julliard at winehq.org
Mon Oct 18 16:16:29 CDT 2021
Module: wine
Branch: master
Commit: 5f916f7f35d648287ab2d8ce825c81341bfce983
URL: https://source.winehq.org/git/wine.git/?a=commit;h=5f916f7f35d648287ab2d8ce825c81341bfce983
Author: Paul Gofman <pgofman at codeweavers.com>
Date: Tue Oct 12 21:48:42 2021 +0300
server: Use SO_BINDTODEVICE in bind_to_index() if possible.
Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
server/sock.c | 74 +++++++++++++++++++++++++++++++----------------------------
1 file changed, 39 insertions(+), 35 deletions(-)
diff --git a/server/sock.c b/server/sock.c
index 43a7c707740..4cb5503ad25 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -1757,12 +1757,21 @@ static int accept_into_socket( struct sock *sock, struct sock *acceptsock )
#ifdef IP_BOUND_IF
-static int bind_to_index( int fd, in_addr_t bind_addr, unsigned int index )
+static int bind_to_iface_name( int fd, in_addr_t bind_addr, const char *name )
{
- return setsockopt( fd, IPPROTO_IP, IP_BOUND_IF, &index, sizeof(index) );
+ static const int enable = 1;
+ unsigned int index;
+
+ if (!(index = if_nametoindex( name )))
+ return -1;
+
+ if (setsockopt( fd, IPPROTO_IP, IP_BOUND_IF, &index, sizeof(index) ))
+ return -1;
+
+ return setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable) );
}
-#elif defined(IP_UNICAST_IF) && defined(SO_ATTACH_FILTER)
+#elif defined(IP_UNICAST_IF) && defined(SO_ATTACH_FILTER) && defined(SO_BINDTODEVICE)
struct interface_filter
{
@@ -1795,27 +1804,43 @@ static struct interface_filter generic_interface_filter =
BPF_STMT(BPF_RET+BPF_K, 0) /* dump packet */
};
-static int bind_to_index( int fd, in_addr_t bind_addr, unsigned int index )
+static int bind_to_iface_name( int fd, in_addr_t bind_addr, const char *name )
{
- in_addr_t ifindex = htonl( index );
struct interface_filter specific_interface_filter;
struct sock_fprog filter_prog;
- int ret;
+ static const int enable = 1;
+ unsigned int index;
+ in_addr_t ifindex;
- if ((ret = setsockopt( fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex, sizeof(ifindex) )) < 0)
- return ret;
+ if (!setsockopt( fd, SOL_SOCKET, SO_BINDTODEVICE, name, strlen( name ) + 1 ))
+ return 0;
+
+ /* SO_BINDTODEVICE requires NET_CAP_RAW until Linux 5.7. */
+ if (debug_level)
+ fprintf( stderr, "setsockopt SO_BINDTODEVICE fd %d, name %s failed: %s, falling back to SO_REUSE_ADDR\n",
+ fd, name, strerror( errno ));
+
+ if (!(index = if_nametoindex( name )))
+ return -1;
+
+ ifindex = htonl( index );
+ if (setsockopt( fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex, sizeof(ifindex) ) < 0)
+ return -1;
specific_interface_filter = generic_interface_filter;
specific_interface_filter.iface_rule.k = index;
specific_interface_filter.ip_rule.k = htonl( bind_addr );
filter_prog.len = sizeof(generic_interface_filter) / sizeof(struct sock_filter);
filter_prog.filter = (struct sock_filter *)&specific_interface_filter;
- return setsockopt( fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, sizeof(filter_prog) );
+ if (setsockopt( fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, sizeof(filter_prog) ))
+ return -1;
+
+ return setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable) );
}
#else
-static int bind_to_index( int fd, in_addr_t bind_addr, unsigned int index )
+static int bind_to_iface_name( int fd, in_addr_t bind_addr, const char *name )
{
errno = EOPNOTSUPP;
return -1;
@@ -1841,8 +1866,7 @@ static int bind_to_interface( struct sock *sock, const struct sockaddr_in *addr
in_addr_t bind_addr = addr->sin_addr.s_addr;
struct ifaddrs *ifaddrs, *ifaddr;
int fd = get_unix_fd( sock->fd );
- static const int enable = 1;
- unsigned int index;
+ int err = 0;
if (bind_addr == htonl( INADDR_ANY ) || bind_addr == htonl( INADDR_LOOPBACK ))
return 0;
@@ -1856,36 +1880,16 @@ static int bind_to_interface( struct sock *sock, const struct sockaddr_in *addr
if (ifaddr->ifa_addr && ifaddr->ifa_addr->sa_family == AF_INET
&& ((struct sockaddr_in *)ifaddr->ifa_addr)->sin_addr.s_addr == bind_addr)
{
- 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 );
-
- if (bind_to_index( fd, bind_addr, index ) < 0)
+ if ((err = bind_to_iface_name( fd, bind_addr, ifaddr->ifa_name )) < 0)
{
if (debug_level)
fprintf( stderr, "failed to bind to interface: %s\n", strerror( errno ) );
- return 0;
}
-
- if (setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable) ) < 0)
- {
- if (debug_level)
- fprintf( stderr, "failed to reuse address: %s\n", strerror( errno ) );
- return 0;
- }
- return 1;
+ break;
}
}
-
freeifaddrs( ifaddrs );
- return 0;
+ return !err;
}
#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
More information about the wine-cvs
mailing list