From b5317f446c89bf8c463168131bc2a5d1cc72ac73 Mon Sep 17 00:00:00 2001 From: hrs Date: Sat, 20 Sep 2014 19:54:19 +0000 Subject: Fix a problem that reply packets are not received when -i T option is set and (T < RTT). - Use select(2) for timeout instead of interval timer. Remove poll(2) support. - Use sigaction(2) instead of signal(3). - Exit in SIGINT handler when two signals are received and doing reverse DNS lookup as ping(8) does. - Remove redundant variables used for getaddrinfo(3). PR: 151023 --- sbin/ping6/Makefile | 2 +- sbin/ping6/ping6.c | 396 ++++++++++++++++++++++------------------------------ 2 files changed, 166 insertions(+), 232 deletions(-) (limited to 'sbin/ping6') diff --git a/sbin/ping6/Makefile b/sbin/ping6/Makefile index 89e7fbe..7f3a008 100644 --- a/sbin/ping6/Makefile +++ b/sbin/ping6/Makefile @@ -4,7 +4,7 @@ PROG= ping6 MAN= ping6.8 CFLAGS+=-DIPSEC -DKAME_SCOPEID -DUSE_RFC2292BIS \ - -DHAVE_POLL_H -DHAVE_ARC4RANDOM + -DHAVE_ARC4RANDOM WARNS?= 2 BINOWN= root diff --git a/sbin/ping6/ping6.c b/sbin/ping6/ping6.c index 01e29a1..14f689d 100644 --- a/sbin/ping6/ping6.c +++ b/sbin/ping6/ping6.c @@ -125,10 +125,8 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include -#ifdef HAVE_POLL_H -#include -#endif #ifdef IPSEC #include @@ -207,7 +205,6 @@ u_int options; int mx_dup_ck = MAX_DUP_CHK; char rcvd_tbl[MAX_DUP_CHK / 8]; -struct addrinfo *res = NULL; struct sockaddr_in6 dst; /* who to ping6 */ struct sockaddr_in6 src; /* src addr of this packet */ socklen_t srclen; @@ -223,12 +220,6 @@ u_int8_t nonce[8]; /* nonce field for node information */ int hoplimit = -1; /* hoplimit */ int pathmtu = 0; /* path MTU for the destination. 0 = unspec. */ u_char *packet = NULL; -#ifdef HAVE_POLL_H -struct pollfd fdmaskp[1]; -#else -fd_set *fdmaskp = NULL; -int fdmasks; -#endif /* counters */ long nmissedmax; /* max value of ntransmitted - nreceived - 1 */ @@ -236,7 +227,7 @@ long npackets; /* max packets to transmit */ long nreceived; /* # of packets we got back */ long nrepeats; /* number of duplicates */ long ntransmitted; /* sequence # for outbound packets = #sent */ -struct timeval interval = {1, 0}; /* interval between packets */ +int interval = 1000; /* interval between packets in ms */ /* timing */ int timing; /* flag to do timing */ @@ -253,7 +244,6 @@ struct msghdr smsghdr; struct iovec smsgiov; char *scmsg = 0; -volatile sig_atomic_t seenalrm; volatile sig_atomic_t seenint; #ifdef SIGINFO volatile sig_atomic_t seeninfo; @@ -265,7 +255,6 @@ int get_hoplim(struct msghdr *); int get_pathmtu(struct msghdr *); struct in6_pktinfo *get_rcvpktinfo(struct msghdr *); void onsignal(int); -void retransmit(void); void onint(int); size_t pingerlen(void); int pinger(void); @@ -293,19 +282,15 @@ void usage(void); int main(int argc, char *argv[]) { - struct itimerval itimer; - struct sockaddr_in6 from; + struct timeval last, intvl; + struct sockaddr_in6 from, *sin6; #ifndef HAVE_ARC4RANDOM struct timeval seed; #endif -#ifdef HAVE_POLL_H - int timeout; -#else - struct timeval timeout, *tv; -#endif - struct addrinfo hints; + struct addrinfo hints, *res; + struct sigaction si_sa; int cc, i; - int ch, hold, packlen, preload, optval, ret_ga; + int almost_done, ch, hold, packlen, preload, optval, error; int nig_oldmcprefix = -1; u_char *datap; char *e, *target, *ifname = NULL, *gateway = NULL; @@ -326,7 +311,7 @@ main(int argc, char *argv[]) char *policy_in = NULL; char *policy_out = NULL; #endif - double intval; + double t; size_t rthlen; #ifdef IPV6_USE_MIN_MTU int mflag = 0; @@ -450,22 +435,22 @@ main(int argc, char *argv[]) #endif break; case 'i': /* wait between sending packets */ - intval = strtod(optarg, &e); + t = strtod(optarg, &e); if (*optarg == '\0' || *e != '\0') errx(1, "illegal timing interval %s", optarg); - if (intval < 1 && getuid()) { + if (t < 1 && getuid()) { errx(1, "%s: only root may use interval < 1s", strerror(EPERM)); } - interval.tv_sec = (long)intval; - interval.tv_usec = - (long)((intval - interval.tv_sec) * 1000000); - if (interval.tv_sec < 0) + intvl.tv_sec = (long)t; + intvl.tv_usec = + (long)((t - intvl.tv_sec) * 1000000); + if (intvl.tv_sec < 0) errx(1, "illegal timing interval %s", optarg); /* less than 1/hz does not make sense */ - if (interval.tv_sec == 0 && interval.tv_usec < 1) { + if (intvl.tv_sec == 0 && intvl.tv_usec < 1) { warnx("too small interval, raised to .000001"); - interval.tv_usec = 1; + intvl.tv_usec = 1; } options |= F_INTERVAL; break; @@ -516,10 +501,10 @@ main(int argc, char *argv[]) hints.ai_socktype = SOCK_RAW; hints.ai_protocol = IPPROTO_ICMPV6; - ret_ga = getaddrinfo(optarg, NULL, &hints, &res); - if (ret_ga) { + error = getaddrinfo(optarg, NULL, &hints, &res); + if (error) { errx(1, "invalid source address: %s", - gai_strerror(ret_ga)); + gai_strerror(error)); } /* * res->ai_family must be AF_INET6 and res->ai_addrlen @@ -622,9 +607,9 @@ main(int argc, char *argv[]) hints.ai_socktype = SOCK_RAW; hints.ai_protocol = IPPROTO_ICMPV6; - ret_ga = getaddrinfo(target, NULL, &hints, &res); - if (ret_ga) - errx(1, "%s", gai_strerror(ret_ga)); + error = getaddrinfo(target, NULL, &hints, &res); + if (error) + errx(1, "%s", gai_strerror(error)); if (res->ai_canonname) hostname = res->ai_canonname; else @@ -647,28 +632,25 @@ main(int argc, char *argv[]) /* set the gateway (next hop) if specified */ if (gateway) { - struct addrinfo ghints, *gres; - int error; - - memset(&ghints, 0, sizeof(ghints)); - ghints.ai_family = AF_INET6; - ghints.ai_socktype = SOCK_RAW; - ghints.ai_protocol = IPPROTO_ICMPV6; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_RAW; + hints.ai_protocol = IPPROTO_ICMPV6; - error = getaddrinfo(gateway, NULL, &hints, &gres); + error = getaddrinfo(gateway, NULL, &hints, &res); if (error) { errx(1, "getaddrinfo for the gateway %s: %s", gateway, gai_strerror(error)); } - if (gres->ai_next && (options & F_VERBOSE)) + if (res->ai_next && (options & F_VERBOSE)) warnx("gateway resolves to multiple addresses"); if (setsockopt(s, IPPROTO_IPV6, IPV6_NEXTHOP, - gres->ai_addr, gres->ai_addrlen)) { + res->ai_addr, res->ai_addrlen)) { err(1, "setsockopt(IPV6_NEXTHOP)"); } - freeaddrinfo(gres); + freeaddrinfo(res); } /* @@ -898,7 +880,7 @@ main(int argc, char *argv[]) } if (argc > 1) { /* some intermediate addrs are specified */ - int hops, error; + int hops; #ifdef USE_RFC2292BIS int rthdrlen; #endif @@ -920,26 +902,25 @@ main(int argc, char *argv[]) #endif /* USE_RFC2292BIS */ for (hops = 0; hops < argc - 1; hops++) { - struct addrinfo *iaip; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; if ((error = getaddrinfo(argv[hops], NULL, &hints, - &iaip))) + &res))) errx(1, "%s", gai_strerror(error)); - if (SIN6(iaip->ai_addr)->sin6_family != AF_INET6) + if (res->ai_addr->sa_family != AF_INET6) errx(1, "bad addr family of an intermediate addr"); - + sin6 = (struct sockaddr_in6 *)(void *)res->ai_addr; #ifdef USE_RFC2292BIS - if (inet6_rth_add(rthdr, - &(SIN6(iaip->ai_addr))->sin6_addr)) + if (inet6_rth_add(rthdr, &sin6->sin6_addr)) errx(1, "can't add an intermediate node"); #else /* old advanced API */ - if (inet6_rthdr_add(scmsgp, - &(SIN6(iaip->ai_addr))->sin6_addr, + if (inet6_rthdr_add(scmsg, &sin6->sin6_addr, IPV6_RTHDR_LOOSE)) errx(1, "can't add an intermediate node"); #endif /* USE_RFC2292BIS */ - freeaddrinfo(iaip); + freeaddrinfo(res); } #ifndef USE_RFC2292BIS @@ -1055,52 +1036,46 @@ main(int argc, char *argv[]) printf("%s --> ", pr_addr((struct sockaddr *)&src, sizeof(src))); printf("%s\n", pr_addr((struct sockaddr *)&dst, sizeof(dst))); - while (preload--) /* Fire off them quickies. */ - (void)pinger(); - - (void)signal(SIGINT, onsignal); -#ifdef SIGINFO - (void)signal(SIGINFO, onsignal); -#endif - - if ((options & F_FLOOD) == 0) { - (void)signal(SIGALRM, onsignal); - itimer.it_interval = interval; - itimer.it_value = interval; - (void)setitimer(ITIMER_REAL, &itimer, NULL); - if (ntransmitted == 0) - retransmit(); + if (preload == 0) + pinger(); + else { + if (npackets != 0 && preload > npackets) + preload = npackets; + while (preload--) + pinger(); } - -#ifndef HAVE_POLL_H - fdmasks = howmany(s + 1, NFDBITS) * sizeof(fd_mask); - if ((fdmaskp = malloc(fdmasks)) == NULL) - err(1, "malloc"); -#endif - - seenalrm = seenint = 0; + gettimeofday(&last, NULL); + + sigemptyset(&si_sa.sa_mask); + si_sa.sa_flags = 0; + si_sa.sa_handler = onsignal; + if (sigaction(SIGINT, &si_sa, 0) == -1) + err(EX_OSERR, "sigaction SIGINT"); + seenint = 0; #ifdef SIGINFO + if (sigaction(SIGINFO, &si_sa, 0) == -1) + err(EX_OSERR, "sigaction SIGINFO"); seeninfo = 0; #endif + if (options & F_FLOOD) { + intvl.tv_sec = 0; + intvl.tv_usec = 10000; + } else if ((options & F_INTERVAL) == 0) { + intvl.tv_sec = interval / 1000; + intvl.tv_usec = interval % 1000 * 1000; + } - for (;;) { + almost_done = 0; + while (seenint == 0) { + struct timeval now, timeout; struct msghdr m; struct iovec iov[2]; + fd_set rfds; + int n; /* signal handling */ - if (seenalrm) { - /* last packet sent, timeout reached? */ - if (npackets && ntransmitted >= npackets) - break; - retransmit(); - seenalrm = 0; - continue; - } - if (seenint) { + if (seenint) onint(SIGINT); - seenint = 0; - continue; - } #ifdef SIGINFO if (seeninfo) { summary(); @@ -1108,93 +1083,104 @@ main(int argc, char *argv[]) continue; } #endif - - if (options & F_FLOOD) { - (void)pinger(); -#ifdef HAVE_POLL_H - timeout = 10; -#else - timeout.tv_sec = 0; - timeout.tv_usec = 10000; - tv = &timeout; -#endif - } else { -#ifdef HAVE_POLL_H - timeout = INFTIM; -#else - tv = NULL; -#endif + FD_ZERO(&rfds); + FD_SET(s, &rfds); + gettimeofday(&now, NULL); + timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec; + timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec; + while (timeout.tv_usec < 0) { + timeout.tv_usec += 1000000; + timeout.tv_sec--; } -#ifdef HAVE_POLL_H - fdmaskp[0].fd = s; - fdmaskp[0].events = POLLIN; - cc = poll(fdmaskp, 1, timeout); -#else - memset(fdmaskp, 0, fdmasks); - FD_SET(s, fdmaskp); - cc = select(s + 1, fdmaskp, NULL, NULL, tv); -#endif - if (cc < 0) { - if (errno != EINTR) { -#ifdef HAVE_POLL_H - warn("poll"); -#else - warn("select"); -#endif - sleep(1); - } - continue; - } else if (cc == 0) - continue; - - m.msg_name = (caddr_t)&from; - m.msg_namelen = sizeof(from); - 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; - memset(cm, 0, CONTROLLEN); - m.msg_control = (void *)cm; - m.msg_controllen = CONTROLLEN; - - cc = recvmsg(s, &m, 0); - if (cc < 0) { - if (errno != EINTR) { - warn("recvmsg"); - sleep(1); - } - continue; - } else if (cc == 0) { - int mtu; + while (timeout.tv_usec > 1000000) { + timeout.tv_usec -= 1000000; + timeout.tv_sec++; + } + if (timeout.tv_sec < 0) + timeout.tv_sec = timeout.tv_usec = 0; + + n = select(s + 1, &rfds, NULL, NULL, &timeout); + if (n < 0) + continue; /* EINTR */ + if (n == 1) { + m.msg_name = (caddr_t)&from; + m.msg_namelen = sizeof(from); + 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; + memset(cm, 0, CONTROLLEN); + m.msg_control = (void *)cm; + m.msg_controllen = CONTROLLEN; + + cc = recvmsg(s, &m, 0); + if (cc < 0) { + if (errno != EINTR) { + warn("recvmsg"); + sleep(1); + } + continue; + } else if (cc == 0) { + int mtu; - /* - * receive control messages only. Process the - * exceptions (currently the only possibility is - * a path MTU notification.) - */ - if ((mtu = get_pathmtu(&m)) > 0) { - if ((options & F_VERBOSE) != 0) { - printf("new path MTU (%d) is " - "notified\n", mtu); + /* + * receive control messages only. Process the + * exceptions (currently the only possibility is + * a path MTU notification.) + */ + if ((mtu = get_pathmtu(&m)) > 0) { + if ((options & F_VERBOSE) != 0) { + printf("new path MTU (%d) is " + "notified\n", mtu); + } } + continue; + } else { + /* + * an ICMPv6 message (probably an echoreply) + * arrived. + */ + pr_pack(packet, cc, &m); } - continue; - } else { + if (((options & F_ONCE) != 0 && nreceived > 0) || + (npackets > 0 && nreceived >= npackets)) + break; + } + if (n == 0 || (options & F_FLOOD)) { + if (npackets == 0 || ntransmitted < npackets) + pinger(); + else { + if (almost_done) + break; + almost_done = 1; /* - * an ICMPv6 message (probably an echoreply) arrived. + * If we're not transmitting any more packets, + * change the timer to wait two round-trip times + * if we've received any packets or ten seconds + * if we haven't. */ - pr_pack(packet, cc, &m); - } - if (((options & F_ONCE) != 0 && nreceived > 0) || - (npackets > 0 && nreceived >= npackets)) - break; - if (ntransmitted - nreceived - 1 > nmissedmax) { - nmissedmax = ntransmitted - nreceived - 1; - if (options & F_MISSED) - (void)write(STDOUT_FILENO, &BBELL, 1); +#define MAXWAIT 10 + intvl.tv_usec = 0; + if (nreceived) { + intvl.tv_sec = 2 * tmax / 1000; + if (intvl.tv_sec == 0) + intvl.tv_sec = 1; + } else + intvl.tv_sec = MAXWAIT; + } + gettimeofday(&last, NULL); + if (ntransmitted - nreceived - 1 > nmissedmax) { + nmissedmax = ntransmitted - nreceived - 1; + if (options & F_MISSED) + (void)write(STDOUT_FILENO, &BBELL, 1); + } } } + sigemptyset(&si_sa.sa_mask); + si_sa.sa_flags = 0; + si_sa.sa_handler = SIG_IGN; + sigaction(SIGINT, &si_sa, 0); summary(); if (res != NULL) @@ -1203,11 +1189,6 @@ main(int argc, char *argv[]) if(packet != NULL) free(packet); -#ifndef HAVE_POLL_H - if(fdmaskp != NULL) - free(fdmaskp); -#endif - exit(nreceived == 0 ? 2 : 0); } @@ -1216,9 +1197,6 @@ onsignal(int sig) { switch (sig) { - case SIGALRM: - seenalrm++; - break; case SIGINT: seenint++; break; @@ -1231,38 +1209,6 @@ onsignal(int sig) } /* - * retransmit -- - * This routine transmits another ping6. - */ -void -retransmit(void) -{ - struct itimerval itimer; - - if (pinger() == 0) - return; - - /* - * If we're not transmitting any more packets, change the timer - * to wait two round-trip times if we've received any packets or - * ten seconds if we haven't. - */ -#define MAXWAIT 10 - if (nreceived) { - itimer.it_value.tv_sec = 2 * tmax / 1000; - if (itimer.it_value.tv_sec == 0) - itimer.it_value.tv_sec = 1; - } else - itimer.it_value.tv_sec = MAXWAIT; - itimer.it_interval.tv_sec = 0; - itimer.it_interval.tv_usec = 0; - itimer.it_value.tv_usec = 0; - - (void)signal(SIGALRM, onsignal); - (void)setitimer(ITIMER_REAL, &itimer, NULL); -} - -/* * pinger -- * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet * will be added on by the kernel. The ID field is our UNIX process ID, @@ -2241,24 +2187,12 @@ tvsub(struct timeval *out, struct timeval *in) void onint(int notused __unused) { - summary(); - - if (res != NULL) - freeaddrinfo(res); - - if(packet != NULL) - free(packet); - -#ifndef HAVE_POLL_H - if(fdmaskp != NULL) - free(fdmaskp); -#endif - - (void)signal(SIGINT, SIG_DFL); - (void)kill(getpid(), SIGINT); - - /* NOTREACHED */ - exit(1); + /* + * When doing reverse DNS lookups, the seenint flag might not + * be noticed for a while. Just exit if we get a second SIGINT. + */ + if ((options & F_HOSTNAME) && seenint != 0) + _exit(nreceived ? 0 : 2); } /* -- cgit v1.1