[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