On Tue, Oct 20, 2020 at 04:07:41PM +0200, Martijn van Duren wrote:
> When running:
> /usr/local/libexec/nagios/check_ping -vv -6 -H <ip> -c 500,75% -w 250,50%
> in a tight loop at some point I get the following output:
> 
> CMD: /sbin/ping6 -n -c 5 <ip>
> Output: PING <ip> (<ip>): 56 data bytes
> Output: 64 bytes from <ip>: icmp_seq=0 hlim=57 time=1.724 ms
> Output: 64 bytes from <ip>: icmp_seq=1 hlim=57 time=1.612 ms
> Output: 64 bytes from <ip>: icmp_seq=2 hlim=57 time=1.785 ms
> Output: 64 bytes from <ip>: icmp_seq=3 hlim=57 time=1.762 ms
> Output: 64 bytes from <ip>: icmp_seq=4 hlim=57 time=1.708 ms
> Output:
> Output: --- <ip> ping statistics ---
> Output: 5 packets transmitted, 5 packets received, 0.0% packet loss
> Output: round-trip min/avg/max/std-dev = 1.612/1.718/1.785/0.060 ms
> Got stderr: ping6: failed to get receiving hop limit
> PING WARNING - System call sent warnings to stderr Packet loss = 0%, RTA = 
> 1.72 ms|rta=1.718000ms;3000.000000;5000.000000;0.000000 pl=0%;80;100;0
> 3000.000000:80% 5000.000000:100%
> 
> So I have 5 echo requests, 5 echo replies and one unrelated packet not
> related to my ping command. Yet this notice to stderr forces check_ping
> into a warning state.
> 

Oh, got it know. The problem is packets arriving between socket(2) and
whenever we are finished calling all setsockopt(2)s. In this case
IPV6_RECVHOPLIMIT.

We need to drain the socket after we are fully setup.

Can you give this a spin? OK?

diff --git ping.c ping.c
index d198d233921..acfe2ed8e18 100644
--- ping.c
+++ ping.c
@@ -240,6 +240,17 @@ void                        pr_retip6(struct ip6_hdr *, 
u_char *);
 int
 main(int argc, char *argv[])
 {
+       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;
+
        struct addrinfo hints, *res;
        struct itimerval itimer;
        struct sockaddr *from, *dst;
@@ -786,6 +797,44 @@ main(int argc, char *argv[])
        smsghdr.msg_iov = &smsgiov;
        smsghdr.msg_iovlen = 1;
 
+       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;
+
+       /* 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 (;;) {
+               if (seenalrm)
+                       break;
+
+               pfd.fd = s;
+               pfd.events = POLLIN;
+
+               if (poll(&pfd, 1, 0) <= 0)
+                       break;
+
+               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);
 
@@ -805,17 +854,7 @@ main(int argc, char *argv[])
        seeninfo = 0;
 
        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;
-               int                     timeout;
+               int     timeout;
 
                /* signal handling */
                if (seenint)
@@ -864,16 +903,6 @@ main(int argc, char *argv[])
                if (poll(&pfd, 1, timeout) <= 0)
                        continue;
 
-               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;


-- 
I'm not entirely sure you are real.

Reply via email to