On Tue, Oct 04, 2011 at 10:51:26AM -0600, Erich Hoover wrote:
> Real Name:
>     Erich Hoover
> 
> Description:
>     I know it's been quite a while, but I'm back with another solution
> for Bug #7929.  This patch uses SO_BINDTODEVICE in order to bind a
> socket to a specific interface while still allowing broadcast packets
> (a Linux-only feature).  While this feature normally requires root
> privileges, it can also be enabled by giving wine-preloader the
> CAP_NET_RAW capability.  Should insufficient permissions be available,
> the patch outputs an appropriate error message notifying the user that
> broadcast packets will not function properly.

Frankly, no sane distributor will ever do this.

Ciao, Marcus
 
> Changelog:
>     ws2_32: Patch to selectively bind to interfaces while still
> allowing broadcast packets.

> From f4c904b9b21da7664eff33be918da71795db01af Mon Sep 17 00:00:00 2001
> From: Erich Hoover <ehoo...@mines.edu>
> Date: Tue, 4 Oct 2011 10:43:06 -0600
> Subject: ws2_32: Selectively bind UDP sockets to interfaces while still 
> allowing broadcast packets.
> 
> ---
>  dlls/ws2_32/socket.c |   94 
> ++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 94 insertions(+), 0 deletions(-)
> 
> diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c
> index f0313fc..174ec15 100644
> --- a/dlls/ws2_32/socket.c
> +++ b/dlls/ws2_32/socket.c
> @@ -2101,6 +2101,94 @@ static int WINAPI WS2_WSARecvMsg( SOCKET s, LPWSAMSG 
> msg, LPDWORD lpNumberOfByte
>  }
>  
>  /***********************************************************************
> + *               interface_bind         (INTERNAL)
> + *
> + * Bind the given socket exclusively to a specific interface.
> + */
> +static int interface_bind( int fd, struct sockaddr *addr )
> +{
> +    struct sockaddr_in *in_sock = (struct sockaddr_in *) addr;
> +    PIP_ADAPTER_INFO adapters = NULL, adapter;
> +    unsigned int sock_type = 0, optlen;
> +    int ret = FALSE;
> +    DWORD adap_size;
> +
> +    if (in_sock->sin_addr.s_addr == htonl(WS_INADDR_ANY))
> +    {
> +        /* Not binding to specific interface, use default route */
> +        goto cleanup;
> +    }
> +    optlen = sizeof(sock_type);
> +    if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &sock_type, &optlen) == -1
> +        || sock_type != SOCK_DGRAM)
> +    {
> +        /* Not a UDP socket, interface-specific bind is irrelevant. */
> +        goto cleanup;
> +    }
> +    /* Obtain the size of the IPv4 adapter list and allocate structure 
> memory */
> +    if (GetAdaptersInfo(NULL, &adap_size) != ERROR_BUFFER_OVERFLOW)
> +    {
> +        ERR("Failed to get the size of the adapter list, "
> +            "bound broadcast packets will not work on this socket.\n");
> +        goto cleanup;
> +    }
> +    adapters = HeapAlloc(GetProcessHeap(), 0, adap_size);
> +    if (adapters == NULL)
> +    {
> +        ERR("Failed to allocate the adapter list, "
> +            "bound broadcast packets will not work on this socket.\n");
> +        goto cleanup;
> +    }
> +    /* Obtain the IPv4 adapter list */
> +    if (GetAdaptersInfo(adapters, &adap_size) != NO_ERROR)
> +    {
> +        ERR("Failed to obtain the adapter list, "
> +            "bound broadcast packets will not work on this socket.\n");
> +        goto cleanup;
> +    }
> +    /* Search the IPv4 adapter list for the appropriate binding IP */
> +    for (adapter = adapters; adapter != NULL; adapter = adapter->Next)
> +    {
> +        char *ip = adapter->IpAddressList.IpAddress.String;
> +        in_addr_t adapter_addr = (in_addr_t) inet_addr(ip);
> +
> +        if (in_sock->sin_addr.s_addr == adapter_addr)
> +        {
> +#ifdef SO_BINDTODEVICE
> +            struct ifreq ifr;
> +
> +            memset(&ifr, 0, sizeof(ifr));
> +            lstrcpynA(ifr.ifr_name, adapter->AdapterName, 
> sizeof(ifr.ifr_name));
> +            if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void*)&ifr, 
> sizeof(ifr)) == 0)
> +            {
> +                /* Success! All packets sent on this socket will go through 
> the
> +                 * specified interface. */
> +                TRACE("Bound to interface '%s' (corresponds to local address 
> %s).\n",
> +                      adapter->AdapterName, inet_ntoa(in_sock->sin_addr));
> +                ret = TRUE;
> +                break;
> +            }
> +
> +            /* If we are unable to bind to a specific interface then notify 
> the
> +             * user that broadcast packets will not work for this socket. The
> +             * user can correct this by giving CAP_NET_RAW access to the
> +             * wine-preloader binary. */
> +            ERR("SO_BINDTODEVICE failed (requires CAP_NET_RAW), "
> +                "broadcast packets will not work on this socket.\n");
> +#else  /* SO_BINDTODEVICE */
> +            WARN("SO_BINDTODEVICE is unsupported on this platform, "
> +                "broadcast packets will not work on this socket.\n");
> +#endif /* SO_BINDTODEVICE */
> +            break;
> +        }
> +    }
> +
> +cleanup:
> +    HeapFree(GetProcessHeap(), 0, adapters);
> +    return ret;
> +}
> +
> +/***********************************************************************
>   *           bind                    (WS2_32.2)
>   */
>  int WINAPI WS_bind(SOCKET s, const struct WS_sockaddr* name, int namelen)
> @@ -2151,6 +2239,12 @@ int WINAPI WS_bind(SOCKET s, const struct WS_sockaddr* 
> name, int namelen)
>                               "INADDR_ANY instead.\n");
>                          in4->sin_addr.s_addr = htonl(WS_INADDR_ANY);
>                      }
> +                    else if (interface_bind(fd, &uaddr.addr))
> +                    {
> +                        /* Bound to a specific interface, change the binding
> +                         * address so that broadcast packets work properly */
> +                        in4->sin_addr.s_addr = htonl(WS_INADDR_ANY);
> +                    }
>                  }
>                  if (bind(fd, &uaddr.addr, uaddrlen) < 0)
>                  {
> -- 
> 1.7.1
> 

> 



Reply via email to