From 78c125f954893b3a828f258e37f31aec204e8c45 Mon Sep 17 00:00:00 2001 From: Erich Hoover Date: Sat, 8 May 2010 16:14:00 -0600 Subject: server: Ensure Async ReadFile does not wake up on packets with an interface mismatch. --- server/sock.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 64 insertions(+), 3 deletions(-) diff --git a/server/sock.c b/server/sock.c index e0d2706..98585d5 100644 --- a/server/sock.c +++ b/server/sock.c @@ -38,6 +38,9 @@ #ifdef HAVE_SYS_SOCKET_H # include #endif +#ifdef HAVE_NETINET_IN_H +# include +#endif #ifdef HAVE_SYS_IOCTL_H #include #endif @@ -89,6 +92,10 @@ /* Constants for WSAIoctl() */ #define WSA_FLAG_OVERLAPPED 0x01 +#if defined(HAVE_NETINET_IN_H) && !defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS) +# define USE_IP_PKTINFO_FILTER +#endif + struct sock { struct object obj; /* object header */ @@ -322,6 +329,57 @@ static inline int sock_error( struct fd *fd ) return optval; } +/* Test for IP_PKTINFO filtered packets that are requested using + * ReadFile instead of WSARecv. If the packet does not match + * for this socket's interface then throw it away. + */ +static int accept_read_poll( struct fd *fd ) +{ +#ifdef USE_IP_PKTINFO_FILTER + struct sock *sock = get_fd_user( fd ); + unsigned int check_iface, optlen; + int handle = get_unix_fd ( fd ); + struct msghdr hdr; + char pktbuf[512]; + + memset(&hdr, 0, sizeof(struct msghdr)); + hdr.msg_control = pktbuf; + hdr.msg_controllen = sizeof(pktbuf); + hdr.msg_flags = 0; + + check_iface = 0; + optlen = sizeof(check_iface); + getsockopt(handle, IPPROTO_IP, IP_PKTINFO, (void *) &check_iface, &optlen); + if (check_iface) + { + /* Peek at the packet to check its interface */ + if ( recvmsg(handle, &hdr, MSG_PEEK|MSG_DONTWAIT) != -1 ) + { + int iface_index = sock->iface_index; + struct in_pktinfo *pktinfo = NULL; + struct cmsghdr *cmsg; + + for (cmsg = CMSG_FIRSTHDR(&hdr); cmsg != NULL; + cmsg = CMSG_NXTHDR(&hdr, cmsg)) + { + if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) + pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg); + } + if (pktinfo && pktinfo->ipi_ifindex != iface_index) + { + if ( recvmsg(handle, &hdr, MSG_DONTWAIT) != -1 ) + return FALSE; + else + fprintf(stderr, "Failed to throw away packet with interface mismatch! %m\n"); + } + } + else + fprintf(stderr, "Failed to peek at message header! %m\n"); + } +#endif /* USE_IP_PKTINFO_FILTER */ + return TRUE; +} + static void sock_poll_event( struct fd *fd, int event ) { struct sock *sock = get_fd_user( fd ); @@ -414,9 +472,12 @@ static void sock_poll_event( struct fd *fd, int event ) } else if ( event & POLLIN ) /* POLLIN for non-stream socket */ { - sock->pmask |= FD_READ; - sock->hmask |= (FD_READ|FD_CLOSE); - sock->errors[FD_READ_BIT] = 0; + if (accept_read_poll(fd)) + { + sock->pmask |= FD_READ; + sock->hmask |= (FD_READ|FD_CLOSE); + sock->errors[FD_READ_BIT] = 0; + } if (debug_level) fprintf(stderr, "socket %p is readable\n", sock ); -- 1.7.0.4