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 > >