From 0f5c99fa9aaeda57d7b0ea2c05c0df8ff424cca5 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 15 Sep 2019 16:53:02 +0000 Subject: [PATCH] MFC r350994, r350998, r351030, r351033, r351171, r351223, r351226, r351424 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit r350994: ping: fix data type of a variable for a packet sequence number Submitted by: Ján Sučan Sponsored by: Google, inc. (Google Summer of Code 2019) Differential Revision: https://reviews.freebsd.org/D21244 r350998: ping: use the monotonic clock to measure durations Submitted by: Ján Sučan Sponsored by: Google, inc. (Google Summer of Code 2019) Differential Revision: https://reviews.freebsd.org/D21245 r351030: ping: fix triptime calculation after r350998 That revision changed the internal clock to the monotonic, but neglected to change the datagram's timestamp source. Reported by: Oliver Hartmann, Michael Butler Reviewed by: Ján Sučan , allanjude MFC-With: r350998 Differential Revision: https://reviews.freebsd.org/D21258 r351033: ping: Make in_cksum() operate on u_char buffer This fixes -Wcast-align errors for in_cksum() calls when compiled with WARNS=6. Submitted by: Ján Sučan Sponsored by: Google, inc. (Google Summer of Code 2019) Differential Revision: https://reviews.freebsd.org/D21261 r351171: ping: Move in_cksum() to a separate source file This is a preparation step for adding ATF tests of in_cksum(), which has been modified to operate on unaligned data. ping.o cannot be linked to the test executable because both of them contain 'main' symbol. Submitted by: Ján Sučan Sponsored by: Google, inc. (Google Summer of Code 2019) Differential Revision: https://reviews.freebsd.org/D21288 r351223: ping: fix -Wformat-truncating warning with GCC Increase buffer size for the string representation of n_time ICMP timestamp is a 32-bit number. In pr_ntime(), number of minutes and seconds is always 2 characters wide. Max. number of hours is 4 characters wide. The buffer size should be at least: 4 + 2 + 2 + 1 (':') + 1 (':') + 1 ('\0') = 11 Submitted by: Ján Sučan Sponsored by: Google, inc. (Google Summer of Code 2019) Differential Revision: https://reviews.freebsd.org/D21325 r351226: Fix uninitialized variable warnings when MK_CASPER=no Submitted by: Ján Sučan Sponsored by: Google, inc. (Google Summer of Code 2019) Differential Revision: https://reviews.freebsd.org/D21322 r351424: ping: fix include guard symbol name to reflect the header file name Submitted by: Ján Sučan MFC-With: 351171 Sponsored by: Google LLC (Google Summer of Code 2019) Differential Revision: https://reviews.freebsd.org/D21374 --- sbin/ping/Makefile | 1 + sbin/ping/ping.c | 167 ++++++++++++++++----------------------------- sbin/ping/utils.c | 98 ++++++++++++++++++++++++++ sbin/ping/utils.h | 38 +++++++++++ 4 files changed, 195 insertions(+), 109 deletions(-) create mode 100644 sbin/ping/utils.c create mode 100644 sbin/ping/utils.h diff --git a/sbin/ping/Makefile b/sbin/ping/Makefile index 8308528ad2e..0f8c80d6fde 100644 --- a/sbin/ping/Makefile +++ b/sbin/ping/Makefile @@ -5,6 +5,7 @@ PACKAGE=runtime PROG= ping +SRCS= ping.c utils.c MAN= ping.8 BINOWN= root BINMODE=4555 diff --git a/sbin/ping/ping.c b/sbin/ping/ping.c index 0497cbe0516..8fd40488813 100644 --- a/sbin/ping/ping.c +++ b/sbin/ping/ping.c @@ -95,8 +95,11 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include +#include "utils.h" + #define INADDR_LEN ((int)sizeof(in_addr_t)) #define TIMEVAL_LEN ((int)sizeof(struct tv32)) #define MASK_LEN (ICMP_MASKLEN - ICMP_MINLEN) @@ -118,7 +121,7 @@ __FBSDID("$FreeBSD$"); struct tv32 { int32_t tv32_sec; - int32_t tv32_usec; + int32_t tv32_nsec; }; /* various options */ @@ -207,7 +210,6 @@ static volatile sig_atomic_t siginfo_p; static cap_channel_t *capdns; static void fill(char *, char *); -static u_short in_cksum(u_short *, int); static cap_channel_t *capdns_setup(void); static void check_status(void); static void finish(void) __dead2; @@ -216,11 +218,10 @@ static char *pr_addr(struct in_addr); static char *pr_ntime(n_time); static void pr_icmph(struct icmp *); static void pr_iph(struct ip *); -static void pr_pack(char *, int, struct sockaddr_in *, struct timeval *); +static void pr_pack(char *, int, struct sockaddr_in *, struct timespec *); static void pr_retip(struct ip *); static void status(int); static void stopit(int); -static void tvsub(struct timeval *, const struct timeval *); static void usage(void) __dead2; int @@ -228,7 +229,7 @@ main(int argc, char *const *argv) { struct sockaddr_in from, sock_in; struct in_addr ifaddr; - struct timeval last, intvl; + struct timespec last, intvl; struct iovec iov; struct ip *ip; struct msghdr msg; @@ -246,7 +247,7 @@ main(int argc, char *const *argv) long ltmp; int almost_done, ch, df, hold, i, icmp_len, mib[4], preload; int ssend_errno, srecv_errno, tos, ttl; - char ctrl[CMSG_SPACE(sizeof(struct timeval))]; + char ctrl[CMSG_SPACE(sizeof(struct timespec))]; char hnamebuf[MAXHOSTNAMELEN], snamebuf[MAXHOSTNAMELEN]; #ifdef IP_OPTIONS char rspace[MAX_IPOPTLEN]; /* record route space */ @@ -616,6 +617,7 @@ main(int argc, char *const *argv) } /* From now on we will use only reverse DNS lookups. */ +#ifdef WITH_CASPER if (capdns != NULL) { const char *types[1]; @@ -623,7 +625,7 @@ main(int argc, char *const *argv) if (cap_dns_type_limit(capdns, types, 1) < 0) err(1, "unable to limit access to system.dns service"); } - +#endif if (connect(ssend, (struct sockaddr *)&whereto, sizeof(whereto)) != 0) err(1, "connect"); @@ -774,9 +776,15 @@ main(int argc, char *const *argv) } } #ifdef SO_TIMESTAMP - { int on = 1; - if (setsockopt(srecv, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)) < 0) - err(EX_OSERR, "setsockopt SO_TIMESTAMP"); + { + int on = 1; + int ts_clock = SO_TS_MONOTONIC; + if (setsockopt(srecv, SOL_SOCKET, SO_TIMESTAMP, &on, + sizeof(on)) < 0) + err(EX_OSERR, "setsockopt SO_TIMESTAMP"); + if (setsockopt(srecv, SOL_SOCKET, SO_TS_CLOCK, &ts_clock, + sizeof(ts_clock)) < 0) + err(EX_OSERR, "setsockopt SO_TS_CLOCK"); } #endif if (sweepmax) { @@ -885,19 +893,19 @@ main(int argc, char *const *argv) while (preload--) /* fire off them quickies */ pinger(); } - (void)gettimeofday(&last, NULL); + (void)clock_gettime(CLOCK_MONOTONIC, &last); if (options & F_FLOOD) { intvl.tv_sec = 0; - intvl.tv_usec = 10000; + intvl.tv_nsec = 10000000; } else { intvl.tv_sec = interval / 1000; - intvl.tv_usec = interval % 1000 * 1000; + intvl.tv_nsec = interval % 1000 * 1000000; } almost_done = 0; while (!finish_up) { - struct timeval now, timeout; + struct timespec now, timeout; fd_set rfds; int cc, n; @@ -906,24 +914,16 @@ main(int argc, char *const *argv) errx(EX_OSERR, "descriptor too large"); FD_ZERO(&rfds); FD_SET(srecv, &rfds); - (void)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--; - } - while (timeout.tv_usec >= 1000000) { - timeout.tv_usec -= 1000000; - timeout.tv_sec++; - } + (void)clock_gettime(CLOCK_MONOTONIC, &now); + timespecadd(&last, &intvl, &timeout); + timespecsub(&timeout, &now, &timeout); if (timeout.tv_sec < 0) - timerclear(&timeout); - n = select(srecv + 1, &rfds, NULL, NULL, &timeout); + timespecclear(&timeout); + n = pselect(srecv + 1, &rfds, NULL, NULL, &timeout, NULL); if (n < 0) continue; /* Must be EINTR. */ if (n == 1) { - struct timeval *tv = NULL; + struct timespec *tv = NULL; #ifdef SO_TIMESTAMP struct cmsghdr *cmsg = (struct cmsghdr *)&ctrl; @@ -946,7 +946,7 @@ main(int argc, char *const *argv) } #endif if (tv == NULL) { - (void)gettimeofday(&now, NULL); + (void)clock_gettime(CLOCK_MONOTONIC, &now); tv = &now; } pr_pack((char *)packet, cc, &from, tv); @@ -970,17 +970,17 @@ main(int argc, char *const *argv) if (almost_done) break; almost_done = 1; - intvl.tv_usec = 0; + intvl.tv_nsec = 0; if (nreceived) { intvl.tv_sec = 2 * tmax / 1000; if (!intvl.tv_sec) intvl.tv_sec = 1; } else { intvl.tv_sec = waittime / 1000; - intvl.tv_usec = waittime % 1000 * 1000; + intvl.tv_nsec = waittime % 1000 * 1000000; } } - (void)gettimeofday(&last, NULL); + (void)clock_gettime(CLOCK_MONOTONIC, &last); if (ntransmitted - nreceived - 1 > nmissedmax) { nmissedmax = ntransmitted - nreceived - 1; if (options & F_MISSED) @@ -1017,13 +1017,13 @@ stopit(int sig __unused) * 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, * and the sequence number is an ascending integer. The first TIMEVAL_LEN - * bytes of the data portion are used to hold a UNIX "timeval" struct in + * bytes of the data portion are used to hold a UNIX "timespec" struct in * host byte-order, to compute the round-trip time. */ static void pinger(void) { - struct timeval now; + struct timespec now; struct tv32 tv32; struct ip *ip; struct icmp *icp; @@ -1041,13 +1041,18 @@ pinger(void) CLR(ntransmitted % mx_dup_ck); if ((options & F_TIME) || timing) { - (void)gettimeofday(&now, NULL); - - tv32.tv32_sec = htonl(now.tv_sec); - tv32.tv32_usec = htonl(now.tv_usec); + (void)clock_gettime(CLOCK_MONOTONIC, &now); + /* + * Truncate seconds down to 32 bits in order + * to fit the timestamp within 8 bytes of the + * packet. We're only concerned with + * durations, not absolute times. + */ + tv32.tv32_sec = (uint32_t)htonl(now.tv_sec); + tv32.tv32_nsec = (uint32_t)htonl(now.tv_nsec); if (options & F_TIME) icp->icmp_otime = htonl((now.tv_sec % (24*60*60)) - * 1000 + now.tv_usec / 1000); + * 1000 + now.tv_nsec / 1000000); if (timing) bcopy((void *)&tv32, (void *)&outpack[ICMP_MINLEN + phdr_len], @@ -1057,13 +1062,13 @@ pinger(void) cc = ICMP_MINLEN + phdr_len + datalen; /* compute ICMP checksum here */ - icp->icmp_cksum = in_cksum((u_short *)icp, cc); + icp->icmp_cksum = in_cksum((u_char *)icp, cc); if (options & F_HDRINCL) { cc += sizeof(struct ip); ip = (struct ip *)outpackhdr; ip->ip_len = htons(cc); - ip->ip_sum = in_cksum((u_short *)outpackhdr, cc); + ip->ip_sum = in_cksum(outpackhdr, cc); packet = outpackhdr; } i = send(ssend, (char *)packet, cc, 0); @@ -1093,7 +1098,7 @@ pinger(void) * program to be run without having intermingled output (or statistics!). */ static void -pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv) +pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timespec *tv) { struct in_addr ina; u_char *cp, *dp; @@ -1101,7 +1106,8 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv) struct ip *ip; const void *tp; double triptime; - int dupflag, hlen, i, j, recv_len, seq; + int dupflag, hlen, i, j, recv_len; + uint16_t seq; static int old_rrlen; static char old_rr[MAX_IPOPTLEN]; @@ -1125,7 +1131,7 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv) ++nreceived; triptime = 0.0; if (timing) { - struct timeval tv1; + struct timespec tv1; struct tv32 tv32; #ifndef icmp_data tp = &icp->icmp_ip; @@ -1139,10 +1145,10 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv) /* Copy to avoid alignment problems: */ memcpy(&tv32, tp, sizeof(tv32)); tv1.tv_sec = ntohl(tv32.tv32_sec); - tv1.tv_usec = ntohl(tv32.tv32_usec); - tvsub(tv, &tv1); + tv1.tv_nsec = ntohl(tv32.tv32_nsec); + timespecsub(tv, &tv1, tv); triptime = ((double)tv->tv_sec) * 1000.0 + - ((double)tv->tv_usec) / 1000.0; + ((double)tv->tv_nsec) / 1000000.0; tsum += triptime; tsumsq += triptime * triptime; if (triptime < tmin) @@ -1353,65 +1359,6 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv) } } -/* - * in_cksum -- - * Checksum routine for Internet Protocol family headers (C Version) - */ -u_short -in_cksum(u_short *addr, int len) -{ - int nleft, sum; - u_short *w; - union { - u_short us; - u_char uc[2]; - } last; - u_short answer; - - nleft = len; - sum = 0; - w = addr; - - /* - * Our algorithm is simple, using a 32 bit accumulator (sum), we add - * sequential 16 bit words to it, and at the end, fold back all the - * carry bits from the top 16 bits into the lower 16 bits. - */ - while (nleft > 1) { - sum += *w++; - nleft -= 2; - } - - /* mop up an odd byte, if necessary */ - if (nleft == 1) { - last.uc[0] = *(u_char *)w; - last.uc[1] = 0; - sum += last.us; - } - - /* add back carry outs from top 16 bits to low 16 bits */ - sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ - sum += (sum >> 16); /* add carry */ - answer = ~sum; /* truncate to 16 bits */ - return(answer); -} - -/* - * tvsub -- - * Subtract 2 timeval structs: out = out - in. Out is assumed to - * be >= in. - */ -static void -tvsub(struct timeval *out, const struct timeval *in) -{ - - if ((out->tv_usec -= in->tv_usec) < 0) { - --out->tv_sec; - out->tv_usec += 1000000; - } - out->tv_sec -= in->tv_sec; -} - /* * status -- * Print out statistics when SIGINFO is received. @@ -1732,7 +1679,7 @@ pr_retip(struct ip *ip) static char * pr_ntime(n_time timestamp) { - static char buf[10]; + static char buf[11]; int hour, min, sec; sec = ntohl(timestamp) / 1000; @@ -1780,9 +1727,10 @@ static cap_channel_t * capdns_setup(void) { cap_channel_t *capcas, *capdnsloc; +#ifdef WITH_CASPER const char *types[2]; int families[1]; - +#endif capcas = cap_init(); if (capcas == NULL) err(1, "unable to create casper process"); @@ -1791,6 +1739,7 @@ capdns_setup(void) cap_close(capcas); if (capdnsloc == NULL) err(1, "unable to open system.dns service"); +#ifdef WITH_CASPER types[0] = "NAME2ADDR"; types[1] = "ADDR2NAME"; if (cap_dns_type_limit(capdnsloc, types, 2) < 0) @@ -1798,7 +1747,7 @@ capdns_setup(void) families[0] = AF_INET; if (cap_dns_family_limit(capdnsloc, families, 1) < 0) err(1, "unable to limit access to system.dns service"); - +#endif return (capdnsloc); } diff --git a/sbin/ping/utils.c b/sbin/ping/utils.c new file mode 100644 index 00000000000..1df233995bf --- /dev/null +++ b/sbin/ping/utils.c @@ -0,0 +1,98 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Muuss. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93"; +#endif /* not lint */ +#endif +#include +__FBSDID("$FreeBSD$"); + +#include + +#include "utils.h" + +/* + * in_cksum -- + * Checksum routine for Internet Protocol family headers (C Version) + */ +u_short +in_cksum(u_char *addr, int len) +{ + int nleft, sum; + u_char *w; + union { + u_short us; + u_char uc[2]; + } last; + u_short answer; + + nleft = len; + sum = 0; + w = addr; + + /* + * Our algorithm is simple, using a 32 bit accumulator (sum), we add + * sequential 16 bit words to it, and at the end, fold back all the + * carry bits from the top 16 bits into the lower 16 bits. + */ + while (nleft > 1) { + u_short data; + + memcpy(&data, w, sizeof(data)); + sum += data; + w += sizeof(data); + nleft -= sizeof(data); + } + + /* mop up an odd byte, if necessary */ + if (nleft == 1) { + last.uc[0] = *w; + last.uc[1] = 0; + sum += last.us; + } + + /* add back carry outs from top 16 bits to low 16 bits */ + sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ + sum += (sum >> 16); /* add carry */ + answer = ~sum; /* truncate to 16 bits */ + return(answer); +} diff --git a/sbin/ping/utils.h b/sbin/ping/utils.h new file mode 100644 index 00000000000..cb56e587a36 --- /dev/null +++ b/sbin/ping/utils.h @@ -0,0 +1,38 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (C) 2019 Jan Sucan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef UTILS_H +#define UTILS_H 1 + +#include + +u_short in_cksum(u_char *, int); + +#endif -- 2.45.0