summaryrefslogtreecommitdiffstats
path: root/sbin/ping6
diff options
context:
space:
mode:
authorhrs <hrs@FreeBSD.org>2014-09-20 19:54:19 +0000
committerhrs <hrs@FreeBSD.org>2014-09-20 19:54:19 +0000
commitb5317f446c89bf8c463168131bc2a5d1cc72ac73 (patch)
treec695dc0c6df36fa5623eafb2de5920a2f8a90a12 /sbin/ping6
parent44e120581bb41cd1af0e55ad630b69e1385343f9 (diff)
downloadFreeBSD-src-b5317f446c89bf8c463168131bc2a5d1cc72ac73.zip
FreeBSD-src-b5317f446c89bf8c463168131bc2a5d1cc72ac73.tar.gz
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
Diffstat (limited to 'sbin/ping6')
-rw-r--r--sbin/ping6/Makefile2
-rw-r--r--sbin/ping6/ping6.c396
2 files changed, 166 insertions, 232 deletions
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sysexits.h>
#include <unistd.h>
-#ifdef HAVE_POLL_H
-#include <poll.h>
-#endif
#ifdef IPSEC
#include <netipsec/ah.h>
@@ -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);
}
/*
OpenPOWER on IntegriCloud