From 4afccf7c8c016f2470fe06f45391644cf14a3fa5 Mon Sep 17 00:00:00 2001 From: Erich Hoover Date: Tue, 11 Oct 2011 08:20:37 -0600 Subject: server/ws2_32: Support UDP binding of interfaces on systems without IP_PKTINFO. --- dlls/ws2_32/socket_shim.c | 42 +++++++++++++++++++++++++++++++++++++++++- server/sock.c | 13 +++++++++++++ 2 files changed, 54 insertions(+), 1 deletions(-) diff --git a/dlls/ws2_32/socket_shim.c b/dlls/ws2_32/socket_shim.c index e520f83..fd2a0f8 100644 --- a/dlls/ws2_32/socket_shim.c +++ b/dlls/ws2_32/socket_shim.c @@ -42,6 +42,9 @@ #ifdef HAVE_NET_IF_H # include #endif +#ifdef HAVE_NET_IF_DL_H +# include +#endif #ifdef HAVE_ARPA_INET_H # include #endif @@ -77,6 +80,8 @@ #if !defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS) # if defined(IP_PKTINFO) # define IP_IFACEFILTER IP_PKTINFO +# elif defined(IP_RECVIF) +# define IP_IFACEFILTER IP_RECVIF # endif #endif @@ -132,6 +137,14 @@ static int WS2_get_pktiface(struct msghdr *hdr) if (pktinfo) return pktinfo->ipi_ifindex; } +#elif defined(IP_RECVIF) + if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVIF) + { + struct sockaddr_dl *recvif = (struct sockaddr_dl *)CMSG_DATA(cmsg); + + if (recvif) + return recvif->sdl_index; + } #else #error "IP_IFACEFILTER is defined incorrectly." #endif @@ -392,7 +405,34 @@ int WS2_shim_sendmsg( SOCKET s, int fd, struct msghdr *hdr, int flags ) buf = pktbuf; buflen = cmsg->cmsg_len; #else -#error "IP_IFACEFILTER is defined incorrectly." + /* + * Without IP_PKTINFO it is necessary to change the broadcast request + * to an interface-specific broadcast (e.g. 192.168.0.255 instead of + * 255.255.255.255). As a result, packets sent out on this socket + * that are NOT destined to the broadcast address may be routed over + * a different interface (at the discretion of the administrator). + */ + if (hdr->msg_name && hdr->msg_namelen == sizeof(struct sockaddr_in)) + { + struct sockaddr_in *in4 = (struct sockaddr_in *) hdr->msg_name; + + if (in4->sin_addr.s_addr == INADDR_BROADCAST) + { + struct ifreq ifr; + + if (if_indextoname(iface_index, ifr.ifr_name) != NULL + && ioctl(fd, SIOCGIFBRDADDR, &ifr) == 0) + { + in4->sin_addr = ((struct sockaddr_in *) &ifr.ifr_ifru.ifru_broadaddr)->sin_addr; + TRACE("Broadcast to 255.255.255.255 changed to %s.\n", inet_ntoa(in4->sin_addr)); + } + else + ERR("Failed to get broadcast address, packet sent out without interface-specific filter!\n"); + } + else + WARN("Not a broadcast packet, packet sent out without interface-specific filter!\n"); + } + /* else: sendmsg() on udp socket with no address will fail */ #endif } else diff --git a/server/sock.c b/server/sock.c index a7522eb..ef0e334 100644 --- a/server/sock.c +++ b/server/sock.c @@ -44,6 +44,9 @@ #ifdef HAVE_SYS_IOCTL_H #include #endif +#ifdef HAVE_NET_IF_DL_H +# include +#endif #ifdef HAVE_SYS_FILIO_H # include #endif @@ -97,6 +100,8 @@ #if !defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS) # if defined(IP_PKTINFO) # define IP_IFACEFILTER IP_PKTINFO +# elif defined(IP_RECVIF) +# define IP_IFACEFILTER IP_RECVIF # endif #endif @@ -428,6 +433,14 @@ static int accept_read_poll( struct fd *fd ) if (pktinfo) packet_index = pktinfo->ipi_ifindex; } +#elif defined(IP_RECVIF) + if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVIF) + { + struct sockaddr_dl *recvif = (struct sockaddr_dl *)CMSG_DATA(cmsg); + + if (recvif) + packet_index = recvif->sdl_index; + } #else #error "IP_IFACEFILTER is defined incorrectly." #endif -- 1.7.1