[PATCH] server: Use SO_BINDTODEVICE in bind_to_index() if possible.
Stefan Dösinger
stefandoesinger at gmail.com
Tue Oct 12 12:50:06 CDT 2021
Does this qualify for Wine-bug: 50499 and 33008?
> Am 12.10.2021 um 19:55 schrieb Paul Gofman <pgofman at codeweavers.com>:
>
> Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
> ---
> Using SO_REUSEADDR is currently problematic when more than one UDP socket is bound
> to different interfaces. While that succeeds, it is unspecified which socket will
> receive a packet coming to INADDR_ANY. The filter being installed for each socket
> with SO_ATTACH_FILTER can only reject the packet coming for another interface but
> that rejected packed doesn't arrive to another socket.
>
> SO_BINDTODEVICE seems to do exactly what we want without installing any socket
> filters and without requiring SO_REUSEADDR or SO_REUSEPORT. It originally considered
> for implementing broadcast listen on interface bound sockets but it wasn't much
> useful by that time as the SO_BINDTODEVICE required CAP_NET_RAW privilege which
> is normally not available for a non-root user. However, that changed since Linux 5.7
> [2].
>
> This patch uses SO_BINDTODEVICE but falls back to the previous way if that fails.
>
> 1. https://www.winehq.org/pipermail/wine-devel/2011-October/092681.html
> 2. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/patch/?id=c427bfec18f2190b8f4718785ee8ed2db4f84ee6
>
> server/sock.c | 28 ++++++++++++++++++++++------
> 1 file changed, 22 insertions(+), 6 deletions(-)
>
> diff --git a/server/sock.c b/server/sock.c
> index 03716cba90f..af08cd6be24 100644
> --- a/server/sock.c
> +++ b/server/sock.c
> @@ -1756,12 +1756,14 @@ 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_index( int fd, in_addr_t bind_addr, const char *name, unsigned int index, BOOL *need_reuse_addr )
> {
> + *need_reuse_addr = TRUE;
> +
> return setsockopt( fd, IPPROTO_IP, IP_BOUND_IF, &index, sizeof(index) );
> }
>
> -#elif defined(IP_UNICAST_IF) && defined(SO_ATTACH_FILTER)
> +#elif defined(IP_UNICAST_IF) && defined(SO_ATTACH_FILTER) && defined(SO_BINDTODEVICE)
>
> struct interface_filter
> {
> @@ -1794,13 +1796,26 @@ 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_index( int fd, in_addr_t bind_addr, const char *name, unsigned int index, BOOL *need_reuse_addr )
> {
> in_addr_t ifindex = htonl( index );
> struct interface_filter specific_interface_filter;
> struct sock_fprog filter_prog;
> int ret;
>
> + if (!setsockopt( fd, SOL_SOCKET, SO_BINDTODEVICE, name, strlen( name ) + 1 ))
> + {
> + *need_reuse_addr = FALSE;
> + 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 ));
> +
> + *need_reuse_addr = TRUE;
> +
> if ((ret = setsockopt( fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex, sizeof(ifindex) )) < 0)
> return ret;
>
> @@ -1814,7 +1829,7 @@ static int bind_to_index( int fd, in_addr_t bind_addr, unsigned int index )
>
> #else
>
> -static int bind_to_index( int fd, in_addr_t bind_addr, unsigned int index )
> +static int bind_to_index( int fd, in_addr_t bind_addr, const char *name, unsigned int index, BOOL *need_reuse_addr )
> {
> errno = EOPNOTSUPP;
> return -1;
> @@ -1841,6 +1856,7 @@ static int bind_to_interface( struct sock *sock, const struct sockaddr_in *addr
> struct ifaddrs *ifaddrs, *ifaddr;
> int fd = get_unix_fd( sock->fd );
> static const int enable = 1;
> + BOOL need_reuse_addr;
> unsigned int index;
>
> if (bind_addr == htonl( INADDR_ANY ) || bind_addr == htonl( INADDR_LOOPBACK ))
> @@ -1866,14 +1882,14 @@ static int bind_to_interface( struct sock *sock, const struct sockaddr_in *addr
>
> freeifaddrs( ifaddrs );
>
> - if (bind_to_index( fd, bind_addr, index ) < 0)
> + if (bind_to_index( fd, bind_addr, ifaddr->ifa_name, index, &need_reuse_addr ) < 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 (need_reuse_addr && setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable) ) < 0)
> {
> if (debug_level)
> fprintf( stderr, "failed to reuse address: %s\n", strerror( errno ) );
> --
> 2.31.1
>
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: Message signed with OpenPGP
URL: <http://www.winehq.org/pipermail/wine-devel/attachments/20211012/c0198661/attachment.sig>
More information about the wine-devel
mailing list