Re: ws2_32: Patch to selectively bind to interfaces while still allowing broadcast packets (try 2)

2011-10-04 Thread Erich Hoover
On Tue, Oct 4, 2011 at 3:30 PM, Marcus Meissner  wrote:
> On Tue, Oct 04, 2011 at 10:51:26AM -0600, Erich Hoover wrote:
> > ... While this feature normally requires root
> > privileges, it can also be enabled by giving wine-preloader the
> > CAP_NET_RAW capability.  ...
> Frankly, no sane distributor will ever do this.

I wouldn't expect them to.  If a user wants this feature then they'd
need to enable it themselves, just like for ICMP or for raw socket
creation.

Erich Hoover
ehoo...@mines.edu




Re: ws2_32: Patch to selectively bind to interfaces while still allowing broadcast packets (try 2)

2011-10-04 Thread Marcus Meissner
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 
> 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;
> +