summaryrefslogtreecommitdiff
path: root/sbin/ping
diff options
context:
space:
mode:
authorFlorian Obser <florian@cvs.openbsd.org>2020-10-21 11:11:59 +0000
committerFlorian Obser <florian@cvs.openbsd.org>2020-10-21 11:11:59 +0000
commit64439b24672e81115a23268d8cf5f8fb783da702 (patch)
tree23c4d61fecc44228b59f7d756b8f21d5d359e8b1 /sbin/ping
parentac39114dfc73a149e488f5d6c4f23284f8cb454d (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
Diffstat (limited to 'sbin/ping')
-rw-r--r--sbin/ping/ping.c51
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);