--- ntp-4.2.2p1/ntpd/ntp_io.c.bcast 2007-05-11 13:41:48.000000000 +0200 +++ ntp-4.2.2p1/ntpd/ntp_io.c 2007-05-11 13:45:26.000000000 +0200 @@ -114,6 +114,8 @@ int wildipv4 = -1; /* Index into inter_list for IPv4 wildcard */ int wildipv6 = -1; /* Index into inter_list for IPv6 wildcard */ +static int pktinfo_status = 0; /* is IP_PKTINFO on wildipv4 iface enabled? */ + #ifdef REFCLOCK /* * Refclock stuff. We keep a chain of structures with data concerning @@ -880,6 +882,18 @@ } } +static void +set_pktinfo(int flag) +{ + if (wildipv4 < 0) + return; + if (setsockopt(inter_list[wildipv4].fd, SOL_IP, IP_PKTINFO, &flag, sizeof (flag))) { + if (debug > 1) + printf("setsockopt(IP_PKTINFO) failed: %s\n", strerror(errno)); + } else + pktinfo_status = flag; +} + /* * This is just a wrapper around an internal function so we can * make other changes as necessary later on @@ -1307,6 +1321,7 @@ #else netsyslog(LOG_ERR, "io_setbclient: Broadcast Client disabled by build"); #endif + set_pktinfo(1); } /* @@ -1326,6 +1341,7 @@ lstatus = socket_broadcast_disable(&inter_list[i], i, &inter_list[i].sin); } #endif + set_pktinfo(0); } void @@ -2236,7 +2252,58 @@ rb = get_free_recv_buffer(); - if (rb == NULL || itf->ignore_packets == ISC_TRUE) + if (pktinfo_status && itf->ifindex == wildipv4 && rb != NULL + && itf->ignore_packets == ISC_TRUE) { + struct msghdr msg; + struct iovec iov; + struct cmsghdr *cmsg; + struct in_pktinfo *pktinfo = NULL; + char control[sizeof (struct cmsghdr) + sizeof (struct in_pktinfo) + 8]; + +#ifdef DEBUG + if (debug > 3) { + printf("checking for broadcast on 255.255.255.255\n"); + } +#endif + iov.iov_base = (void *) &rb->recv_space; + iov.iov_len = sizeof (rb->recv_space); + msg.msg_name = (void *) &rb->recv_srcadr; + msg.msg_namelen = sizeof (rb->recv_srcadr); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = (void *) &control; + msg.msg_controllen = sizeof (control); + msg.msg_flags = 0; + rb->recv_length = recvmsg(fd, &msg, 0); + + if (rb->recv_length <= 0) + goto packet_read; + + if ((cmsg = CMSG_FIRSTHDR(&msg))) + do { + if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) { + pktinfo = (struct in_pktinfo *) CMSG_DATA(cmsg); + } + } while ((cmsg = CMSG_NXTHDR(&msg, cmsg))); + + if (pktinfo && pktinfo->ipi_addr.s_addr == INADDR_BROADCAST) { +#ifdef DEBUG + if (debug > 3) { + printf("INADDR_BROADCAST\n"); + } +#endif + goto packet_read; + } +#ifdef DEBUG + if (debug > 3) + printf("%s on (%lu) fd=%d from %s\n", "ignore", + free_recvbuffs(), fd, stoa(&rb->recv_srcadr)); +#endif + packets_ignored++; + freerecvbuf(rb); + return (rb->recv_length); + } + else if (rb == NULL || itf->ignore_packets == ISC_TRUE) { char buf[RX_BUFF_SIZE]; struct sockaddr_storage from; @@ -2266,6 +2333,7 @@ sizeof(rb->recv_space), 0, (struct sockaddr *)&rb->recv_srcadr, &fromlen); +packet_read: if (rb->recv_length == 0|| (rb->recv_length == -1 && (errno==EWOULDBLOCK #ifdef EAGAIN