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.