diff options
author | Florian Obser <florian@cvs.openbsd.org> | 2020-10-21 11:11:59 +0000 |
---|---|---|
committer | Florian Obser <florian@cvs.openbsd.org> | 2020-10-21 11:11:59 +0000 |
commit | 64439b24672e81115a23268d8cf5f8fb783da702 (patch) | |
tree | 23c4d61fecc44228b59f7d756b8f21d5d359e8b1 | |
parent | ac39114dfc73a149e488f5d6c4f23284f8cb454d (diff) |
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
-rw-r--r-- | sbin/ping/ping.c | 51 |
1 files changed, 50 insertions, 1 deletions
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); |