From 64439b24672e81115a23268d8cf5f8fb783da702 Mon Sep 17 00:00:00 2001 From: Florian Obser Date: Wed, 21 Oct 2020 11:11:59 +0000 Subject: ICMP raw sockets start to receive packets as soon as they are created by socket(2). They also receive all ICMP packets on the system, for example from parallel running ping(8)s. After creating the raw socket ping(8) sets various socket options with setsockopt(2) and assumes that they apply to all packets it later processes. For example ping6(8) uses setsockopt(IPV6_RECVHOPLIMIT) to print the IPv6 hop count. Packets received between the socket(2) and setsockopt(2) call however do not have the hoplimit information and ping6(8) prints a wrong and missleading warning. To avoid this we have to drain our socket of packets we received before we were fully setup. Problem reported and testing by martijn Input deraadt OK benno --- sbin/ping/ping.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) (limited to 'sbin') diff --git a/sbin/ping/ping.c b/sbin/ping/ping.c index d198d233921..2af4ded0b6b 100644 --- a/sbin/ping/ping.c +++ b/sbin/ping/ping.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ping.c,v 1.241 2020/09/21 12:19:08 mglocker Exp $ */ +/* $OpenBSD: ping.c,v 1.242 2020/10/21 11:11:58 florian Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -786,6 +786,55 @@ main(int argc, char *argv[]) smsghdr.msg_iov = &smsgiov; smsghdr.msg_iovlen = 1; + /* Drain our socket. */ + (void)signal(SIGALRM, onsignal); + memset(&itimer, 0, sizeof(itimer)); + itimer.it_value.tv_sec = 1; /* make sure we don't get stuck */ + (void)setitimer(ITIMER_REAL, &itimer, NULL); + for (;;) { + struct msghdr m; + union { + struct cmsghdr hdr; + u_char buf[CMSG_SPACE(1024)]; + } cmsgbuf; + struct iovec iov[1]; + struct pollfd pfd; + struct sockaddr_in peer4; + struct sockaddr_in6 peer6; + ssize_t cc; + + if (seenalrm) + break; + + pfd.fd = s; + pfd.events = POLLIN; + + if (poll(&pfd, 1, 0) <= 0) + break; + + if (v6flag) { + m.msg_name = &peer6; + m.msg_namelen = sizeof(peer6); + } else { + m.msg_name = &peer4; + m.msg_namelen = sizeof(peer4); + } + memset(&iov, 0, sizeof(iov)); + iov[0].iov_base = (caddr_t)packet; + iov[0].iov_len = packlen; + + m.msg_iov = iov; + m.msg_iovlen = 1; + m.msg_control = (caddr_t)&cmsgbuf.buf; + m.msg_controllen = sizeof(cmsgbuf.buf); + + cc = recvmsg(s, &m, 0); + if (cc == -1 && errno != EINTR) + break; + } + memset(&itimer, 0, sizeof(itimer)); + (void)setitimer(ITIMER_REAL, &itimer, NULL); + while (preload--) /* Fire off them quickies. */ pinger(s); -- cgit v1.2.3