From e88291e3875fbbada978b1e95758b101195b918d Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 16 Sep 2019 00:56:33 +0000 Subject: [PATCH] MFC r351318, r351330, r351393, r351398, r351440, r351461, r351548, r352226, r352229 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit r351318: ping: Add tests of the Internet checksum function Submitted by: Ján Sučan Sponsored by: Google LLC (Google Summer of Code 2019) Differential Revision: https://reviews.freebsd.org/D21340 r351330: ping: do reverse DNS lookup of the target address When printing replies, ping will now attempt a reverse DNS lookup of the target. That can be suppressed by using the "-n" option. Curiously, ping has always done reverse lookups in certain error paths, but never in the success path. Submitted by: Ján Sučan Sponsored by: Google LLC (Google Summer of Code 2019) Differential Revision: https://reviews.freebsd.org/D21351 r351393: ping: add a basic functional test Submitted by: Ján Sučan Sponsored by: Google, inc. (Google Summer of Code 2019) Differential Revision: https://reviews.freebsd.org/D21289 r351398: ping: By default, don't reverse lookup IP addresses ping's default is now not to attempt reverse DNS lookups. The -H flag will enable them. This change is not quite a reversion of r351330. That change made the happy path and error path do reverse lookups consistently; this change changes the default for both paths. Submitted by: Ján Sučan Discussed with: cem MFC-With: 351330 Sponsored by: Google LLC (Google Summer of Code 2019) Differential Revision: https://reviews.freebsd.org/D21364 r351440: ping: Fix alignment errors This fixes -Wcast-align errors when compiled with WARNS=6. Submitted by: Ján Sučan Sponsored by: Google LLC (Google Summer of Code 2019) Differential Revision: https://reviews.freebsd.org/D21327 r351461: ping: fix unaligned access to ancillary data Use CMSG_FIRSTHDR rather than assume that an array is correctly aligned. Fixes warnings on sparc64 and powerpcspe. Submitted by: Ján Sučan MFH: 2 weeks Sponsored by: Google LLC (Google Summer of Code 2019) Differential Revision: https://reviews.freebsd.org/D21406 r351548: ping: raise WARNS level to 6 Submitted by: Ján Sučan Sponsored by: Google LLC (Google Summer of Code 2019) Differential Revision: https://reviews.freebsd.org/D21405 r352226: ping: fix a string in an error message r352229: ping: Verify whether a datagram timestamp was actually received. ping(8) uses SO_TIMESTAMP, which attaches a timestamp to each IP datagram at the time it's received by the kernel. Except that occasionally it doesn't. Add a check to see whether such a timestamp was actually set before trying to read it. This fixes segfaults that can happen when the kernel doesn't attach a timestamp. The bug has always existed, but prior to r351461 it manifested as an implausible round-trip-time, not a segfault. Reported by: pho MFC-With: 351461 --- etc/mtree/BSD.tests.dist | 2 + sbin/ping/Makefile | 4 +- sbin/ping/ping.8 | 11 +- sbin/ping/ping.c | 217 +++++++++++++++-------------- sbin/ping/tests/Makefile | 13 ++ sbin/ping/tests/in_cksum_test.c | 146 +++++++++++++++++++ sbin/ping/tests/ping_c1_s56_t1.out | 6 + sbin/ping/tests/ping_test.sh | 55 ++++++++ 8 files changed, 347 insertions(+), 107 deletions(-) create mode 100644 sbin/ping/tests/Makefile create mode 100644 sbin/ping/tests/in_cksum_test.c create mode 100644 sbin/ping/tests/ping_c1_s56_t1.out create mode 100644 sbin/ping/tests/ping_test.sh diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist index fac3e352a5c..2b12a312ba4 100644 --- a/etc/mtree/BSD.tests.dist +++ b/etc/mtree/BSD.tests.dist @@ -428,6 +428,8 @@ files .. .. + ping + .. .. secure lib diff --git a/sbin/ping/Makefile b/sbin/ping/Makefile index 0f8c80d6fde..1f651a7b0b0 100644 --- a/sbin/ping/Makefile +++ b/sbin/ping/Makefile @@ -9,7 +9,6 @@ SRCS= ping.c utils.c MAN= ping.8 BINOWN= root BINMODE=4555 -WARNS?= 3 LIBADD= m .if ${MK_DYNAMICROOT} == "no" @@ -25,4 +24,7 @@ CFLAGS+=-DIPSEC LIBADD+= ipsec .endif +HAS_TESTS= +SUBDIR.${MK_TESTS}+= tests + .include diff --git a/sbin/ping/ping.8 b/sbin/ping/ping.8 index b674d96c67d..b1c427e922c 100644 --- a/sbin/ping/ping.8 +++ b/sbin/ping/ping.8 @@ -28,7 +28,7 @@ .\" @(#)ping.8 8.2 (Berkeley) 12/11/93 .\" $FreeBSD$ .\" -.Dd March 11, 2016 +.Dd August 22, 2019 .Dt PING 8 .Os .Sh NAME @@ -157,6 +157,12 @@ Specify the size of .Tn ICMP payload to start with when sending sweeping pings. The default value is 0. +.It Fl H +Hostname output. +Try to do a reverse DNS lookup when displaying addresses. +This is the opposite of the +.Fl n +option. .It Fl h Ar sweepincrsize Specify the number of bytes to increment the size of .Tn ICMP @@ -220,6 +226,9 @@ MIB variable. .It Fl n Numeric output only. No attempt will be made to lookup symbolic names for host addresses. +This is the opposite of +.Fl H , +and it is the default behavior. .It Fl o Exit successfully after receiving one reply packet. .It Fl P Ar policy diff --git a/sbin/ping/ping.c b/sbin/ping/ping.c index 8fd40488813..febf4cc4737 100644 --- a/sbin/ping/ping.c +++ b/sbin/ping/ping.c @@ -90,6 +90,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -216,10 +217,10 @@ static void finish(void) __dead2; static void pinger(void); static char *pr_addr(struct in_addr); static char *pr_ntime(n_time); -static void pr_icmph(struct icmp *); +static void pr_icmph(struct icmp *, struct ip *, const u_char *const); static void pr_iph(struct ip *); -static void pr_pack(char *, int, struct sockaddr_in *, struct timespec *); -static void pr_retip(struct ip *); +static void pr_pack(char *, ssize_t, struct sockaddr_in *, struct timespec *); +static void pr_retip(struct ip *, const u_char *); static void status(int); static void stopit(int); static void usage(void) __dead2; @@ -231,7 +232,6 @@ main(int argc, char *const *argv) struct in_addr ifaddr; struct timespec last, intvl; struct iovec iov; - struct ip *ip; struct msghdr msg; struct sigaction si_sa; size_t sz; @@ -261,6 +261,8 @@ main(int argc, char *const *argv) cap_rights_t rights; bool cansandbox; + options |= F_NUMERIC; + /* * Do the stuff that we need root priv's for *first*, and * then drop our setuid bit. Save error reporting for @@ -689,7 +691,9 @@ main(int argc, char *const *argv) #endif /*IPSEC*/ if (options & F_HDRINCL) { - ip = (struct ip*)outpackhdr; + struct ip ip; + + memcpy(&ip, outpackhdr, sizeof(ip)); if (!(options & (F_TTL | F_MTTL))) { mib[0] = CTL_NET; mib[1] = PF_INET; @@ -700,15 +704,16 @@ main(int argc, char *const *argv) err(1, "sysctl(net.inet.ip.ttl)"); } setsockopt(ssend, IPPROTO_IP, IP_HDRINCL, &hold, sizeof(hold)); - ip->ip_v = IPVERSION; - ip->ip_hl = sizeof(struct ip) >> 2; - ip->ip_tos = tos; - ip->ip_id = 0; - ip->ip_off = htons(df ? IP_DF : 0); - ip->ip_ttl = ttl; - ip->ip_p = IPPROTO_ICMP; - ip->ip_src.s_addr = source ? sock_in.sin_addr.s_addr : INADDR_ANY; - ip->ip_dst = to->sin_addr; + ip.ip_v = IPVERSION; + ip.ip_hl = sizeof(struct ip) >> 2; + ip.ip_tos = tos; + ip.ip_id = 0; + ip.ip_off = htons(df ? IP_DF : 0); + ip.ip_ttl = ttl; + ip.ip_p = IPPROTO_ICMP; + ip.ip_src.s_addr = source ? sock_in.sin_addr.s_addr : INADDR_ANY; + ip.ip_dst = to->sin_addr; + memcpy(outpackhdr, &ip, sizeof(ip)); } if (options & F_NUMERIC) @@ -724,7 +729,7 @@ main(int argc, char *const *argv) * We must connect(2) our socket before this point. */ if (cansandbox && cap_enter() < 0 && errno != ENOSYS) - err(1, "cap_enter"); + err(1, "caph_enter_casper"); cap_rights_init(&rights, CAP_RECV, CAP_EVENT, CAP_SETSOCKOPT); if (cap_rights_limit(srecv, &rights) < 0 && errno != ENOSYS) @@ -881,6 +886,7 @@ main(int argc, char *const *argv) msg.msg_iovlen = 1; #ifdef SO_TIMESTAMP msg.msg_control = (caddr_t)ctrl; + msg.msg_controllen = sizeof(ctrl); #endif iov.iov_base = packet; iov.iov_len = IP_MAXPACKET; @@ -907,7 +913,8 @@ main(int argc, char *const *argv) while (!finish_up) { struct timespec now, timeout; fd_set rfds; - int cc, n; + int n; + ssize_t cc; check_status(); if ((unsigned)srecv >= FD_SETSIZE) @@ -925,9 +932,7 @@ main(int argc, char *const *argv) if (n == 1) { struct timespec *tv = NULL; #ifdef SO_TIMESTAMP - struct cmsghdr *cmsg = (struct cmsghdr *)&ctrl; - - msg.msg_controllen = sizeof(ctrl); + struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); #endif msg.msg_namelen = sizeof(from); if ((cc = recvmsg(srecv, &msg, 0)) < 0) { @@ -937,7 +942,8 @@ main(int argc, char *const *argv) continue; } #ifdef SO_TIMESTAMP - if (cmsg->cmsg_level == SOL_SOCKET && + if (cmsg != NULL && + cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMP && cmsg->cmsg_len == CMSG_LEN(sizeof *tv)) { /* Copy to avoid alignment problems: */ @@ -1025,18 +1031,17 @@ pinger(void) { struct timespec now; struct tv32 tv32; - struct ip *ip; - struct icmp *icp; + struct icmp icp; int cc, i; u_char *packet; packet = outpack; - icp = (struct icmp *)outpack; - icp->icmp_type = icmp_type; - icp->icmp_code = 0; - icp->icmp_cksum = 0; - icp->icmp_seq = htons(ntransmitted); - icp->icmp_id = ident; /* ID */ + memcpy(&icp, outpack, ICMP_MINLEN + phdr_len); + icp.icmp_type = icmp_type; + icp.icmp_code = 0; + icp.icmp_cksum = 0; + icp.icmp_seq = htons(ntransmitted); + icp.icmp_id = ident; /* ID */ CLR(ntransmitted % mx_dup_ck); @@ -1051,7 +1056,7 @@ pinger(void) 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)) + icp.icmp_otime = htonl((now.tv_sec % (24*60*60)) * 1000 + now.tv_nsec / 1000000); if (timing) bcopy((void *)&tv32, @@ -1059,16 +1064,28 @@ pinger(void) sizeof(tv32)); } + memcpy(outpack, &icp, ICMP_MINLEN + phdr_len); + cc = ICMP_MINLEN + phdr_len + datalen; /* compute ICMP checksum here */ - icp->icmp_cksum = in_cksum((u_char *)icp, cc); + icp.icmp_cksum = in_cksum(outpack, cc); + /* Update icmp_cksum in the raw packet data buffer. */ + memcpy(outpack + offsetof(struct icmp, icmp_cksum), &icp.icmp_cksum, + sizeof(icp.icmp_cksum)); if (options & F_HDRINCL) { + struct ip ip; + cc += sizeof(struct ip); - ip = (struct ip *)outpackhdr; - ip->ip_len = htons(cc); - ip->ip_sum = in_cksum(outpackhdr, cc); + ip.ip_len = htons(cc); + /* Update ip_len in the raw packet data buffer. */ + memcpy(outpackhdr + offsetof(struct ip, ip_len), &ip.ip_len, + sizeof(ip.ip_len)); + ip.ip_sum = in_cksum(outpackhdr, cc); + /* Update ip_sum in the raw packet data buffer. */ + memcpy(outpackhdr + offsetof(struct ip, ip_sum), &ip.ip_sum, + sizeof(ip.ip_sum)); packet = outpackhdr; } i = send(ssend, (char *)packet, cc, 0); @@ -1098,47 +1115,61 @@ 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 timespec *tv) +pr_pack(char *buf, ssize_t cc, struct sockaddr_in *from, struct timespec *tv) { struct in_addr ina; - u_char *cp, *dp; - struct icmp *icp; - struct ip *ip; - const void *tp; + u_char *cp, *dp, l; + struct icmp icp; + struct ip ip; + const u_char *icmp_data_raw; double triptime; int dupflag, hlen, i, j, recv_len; uint16_t seq; static int old_rrlen; static char old_rr[MAX_IPOPTLEN]; + struct ip oip; + u_char oip_header_len; + struct icmp oicmp; + const u_char *oicmp_raw; + + /* + * Get size of IP header of the received packet. The + * information is contained in the lower four bits of the + * first byte. + */ + memcpy(&l, buf, sizeof(l)); + hlen = (l & 0x0f) << 2; + memcpy(&ip, buf, hlen); /* Check the IP header */ - ip = (struct ip *)buf; - hlen = ip->ip_hl << 2; recv_len = cc; if (cc < hlen + ICMP_MINLEN) { if (options & F_VERBOSE) - warn("packet too short (%d bytes) from %s", cc, + warn("packet too short (%zd bytes) from %s", cc, inet_ntoa(from->sin_addr)); return; } +#ifndef icmp_data + icmp_data_raw = buf + hlen + offsetof(struct icmp, icmp_ip); +#else + icmp_data_raw = buf + hlen + offsetof(struct icmp, icmp_data); +#endif + /* Now the ICMP part */ cc -= hlen; - icp = (struct icmp *)(buf + hlen); - if (icp->icmp_type == icmp_type_rsp) { - if (icp->icmp_id != ident) + memcpy(&icp, buf + hlen, MIN((ssize_t)sizeof(icp), cc)); + if (icp.icmp_type == icmp_type_rsp) { + if (icp.icmp_id != ident) return; /* 'Twas not our ECHO */ ++nreceived; triptime = 0.0; if (timing) { struct timespec tv1; struct tv32 tv32; -#ifndef icmp_data - tp = &icp->icmp_ip; -#else - tp = icp->icmp_data; -#endif - tp = (const char *)tp + phdr_len; + const u_char *tp; + + tp = icmp_data_raw + phdr_len; if ((size_t)(cc - ICMP_MINLEN - phdr_len) >= sizeof(tv1)) { @@ -1159,7 +1190,7 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timespec *tv) timing = 0; } - seq = ntohs(icp->icmp_seq); + seq = ntohs(icp.icmp_seq); if (TST(seq % mx_dup_ck)) { ++nrepeats; @@ -1181,10 +1212,9 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timespec *tv) if (options & F_FLOOD) (void)write(STDOUT_FILENO, &BSPACE, 1); else { - (void)printf("%d bytes from %s: icmp_seq=%u", cc, - inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr), - seq); - (void)printf(" ttl=%d", ip->ip_ttl); + (void)printf("%zd bytes from %s: icmp_seq=%u", cc, + pr_addr(from->sin_addr), seq); + (void)printf(" ttl=%d", ip.ip_ttl); if (timing) (void)printf(" time=%.3f ms", triptime); if (dupflag) @@ -1194,12 +1224,12 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timespec *tv) if (options & F_MASK) { /* Just prentend this cast isn't ugly */ (void)printf(" mask=%s", - inet_ntoa(*(struct in_addr *)&(icp->icmp_mask))); + inet_ntoa(*(struct in_addr *)&(icp.icmp_mask))); } if (options & F_TIME) { - (void)printf(" tso=%s", pr_ntime(icp->icmp_otime)); - (void)printf(" tsr=%s", pr_ntime(icp->icmp_rtime)); - (void)printf(" tst=%s", pr_ntime(icp->icmp_ttime)); + (void)printf(" tso=%s", pr_ntime(icp.icmp_otime)); + (void)printf(" tsr=%s", pr_ntime(icp.icmp_rtime)); + (void)printf(" tst=%s", pr_ntime(icp.icmp_ttime)); } if (recv_len != send_len) { (void)printf( @@ -1207,7 +1237,8 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timespec *tv) recv_len, send_len); } /* check the data */ - cp = (u_char*)&icp->icmp_data[phdr_len]; + cp = (u_char*)(buf + hlen + offsetof(struct icmp, + icmp_data) + phdr_len); dp = &outpack[ICMP_MINLEN + phdr_len]; cc -= ICMP_MINLEN + phdr_len; i = 0; @@ -1222,7 +1253,8 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timespec *tv) (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", i, *dp, *cp); (void)printf("\ncp:"); - cp = (u_char*)&icp->icmp_data[0]; + cp = (u_char*)(buf + hlen + + offsetof(struct icmp, icmp_data)); for (i = 0; i < datalen; ++i, ++cp) { if ((i % 16) == 8) (void)printf("\n\t"); @@ -1250,22 +1282,22 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timespec *tv) * as root to avoid leaking information not normally * available to those not running as root. */ -#ifndef icmp_data - struct ip *oip = &icp->icmp_ip; -#else - struct ip *oip = (struct ip *)icp->icmp_data; -#endif - struct icmp *oicmp = (struct icmp *)(oip + 1); + memcpy(&oip_header_len, icmp_data_raw, sizeof(oip_header_len)); + oip_header_len = (oip_header_len & 0x0f) << 2; + memcpy(&oip, icmp_data_raw, oip_header_len); + oicmp_raw = icmp_data_raw + oip_header_len; + memcpy(&oicmp, oicmp_raw, offsetof(struct icmp, icmp_id) + + sizeof(oicmp.icmp_id)); if (((options & F_VERBOSE) && uid == 0) || (!(options & F_QUIET2) && - (oip->ip_dst.s_addr == whereto.sin_addr.s_addr) && - (oip->ip_p == IPPROTO_ICMP) && - (oicmp->icmp_type == ICMP_ECHO) && - (oicmp->icmp_id == ident))) { - (void)printf("%d bytes from %s: ", cc, + (oip.ip_dst.s_addr == whereto.sin_addr.s_addr) && + (oip.ip_p == IPPROTO_ICMP) && + (oicmp.icmp_type == ICMP_ECHO) && + (oicmp.icmp_id == ident))) { + (void)printf("%zd bytes from %s: ", cc, pr_addr(from->sin_addr)); - pr_icmph(icp); + pr_icmph(&icp, &oip, oicmp_raw); } else return; } @@ -1451,7 +1483,7 @@ static char *ttab[] = { * Print a descriptive string about an ICMP header. */ static void -pr_icmph(struct icmp *icp) +pr_icmph(struct icmp *icp, struct ip *oip, const u_char *const oicmp_raw) { switch(icp->icmp_type) { @@ -1489,19 +1521,11 @@ pr_icmph(struct icmp *icp) break; } /* Print returned IP header information */ -#ifndef icmp_data - pr_retip(&icp->icmp_ip); -#else - pr_retip((struct ip *)icp->icmp_data); -#endif + pr_retip(oip, oicmp_raw); break; case ICMP_SOURCEQUENCH: (void)printf("Source Quench\n"); -#ifndef icmp_data - pr_retip(&icp->icmp_ip); -#else - pr_retip((struct ip *)icp->icmp_data); -#endif + pr_retip(oip, oicmp_raw); break; case ICMP_REDIRECT: switch(icp->icmp_code) { @@ -1522,11 +1546,7 @@ pr_icmph(struct icmp *icp) break; } (void)printf("(New addr: %s)\n", inet_ntoa(icp->icmp_gwaddr)); -#ifndef icmp_data - pr_retip(&icp->icmp_ip); -#else - pr_retip((struct ip *)icp->icmp_data); -#endif + pr_retip(oip, oicmp_raw); break; case ICMP_ECHO: (void)printf("Echo Request\n"); @@ -1545,20 +1565,12 @@ pr_icmph(struct icmp *icp) icp->icmp_code); break; } -#ifndef icmp_data - pr_retip(&icp->icmp_ip); -#else - pr_retip((struct ip *)icp->icmp_data); -#endif + pr_retip(oip, oicmp_raw); break; case ICMP_PARAMPROB: (void)printf("Parameter problem: pointer = 0x%02x\n", icp->icmp_hun.ih_pptr); -#ifndef icmp_data - pr_retip(&icp->icmp_ip); -#else - pr_retip((struct ip *)icp->icmp_data); -#endif + pr_retip(oip, oicmp_raw); break; case ICMP_TSTAMP: (void)printf("Timestamp\n"); @@ -1659,14 +1671,9 @@ pr_addr(struct in_addr ina) * Dump some info on a returned (via ICMP) IP packet. */ static void -pr_retip(struct ip *ip) +pr_retip(struct ip *ip, const u_char *cp) { - u_char *cp; - int hlen; - pr_iph(ip); - hlen = ip->ip_hl << 2; - cp = (u_char *)ip + hlen; if (ip->ip_p == 6) (void)printf("TCP: from port %u, to port %u (decimal)\n", diff --git a/sbin/ping/tests/Makefile b/sbin/ping/tests/Makefile new file mode 100644 index 00000000000..678641562d9 --- /dev/null +++ b/sbin/ping/tests/Makefile @@ -0,0 +1,13 @@ +# $FreeBSD$ + +WARNS?= 6 + +ATF_TESTS_C+= in_cksum_test +SRCS.in_cksum_test= in_cksum_test.c ../utils.c + +PACKAGE= tests + +ATF_TESTS_SH+= ping_test +${PACKAGE}FILES+= ping_c1_s56_t1.out + +.include diff --git a/sbin/ping/tests/in_cksum_test.c b/sbin/ping/tests/in_cksum_test.c new file mode 100644 index 00000000000..fc266545b43 --- /dev/null +++ b/sbin/ping/tests/in_cksum_test.c @@ -0,0 +1,146 @@ +/*- + * 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include + +#include "../utils.h" + +/* + * Test cases. + */ + +ATF_TC_WITHOUT_HEAD(aligned_even_length_big_endian); +ATF_TC_BODY(aligned_even_length_big_endian, tc) +{ + u_char data[] __aligned(sizeof(u_short)) = + {0x12, 0x34, 0x56, 0x78}; + u_short sum; + + sum = in_cksum(data, nitems(data)); + ATF_REQUIRE(sum == 0x5397); +} + +ATF_TC_WITHOUT_HEAD(aligned_odd_length_big_endian); +ATF_TC_BODY(aligned_odd_length_big_endian, tc) +{ + u_char data[] __aligned(sizeof(u_short)) = + {0x12, 0x34, 0x56, 0x78, 0x9a}; + u_short sum; + + sum = in_cksum(data, nitems(data)); + ATF_REQUIRE(sum == 0x52fd); +} + +ATF_TC_WITHOUT_HEAD(aligned_even_length_little_endian); +ATF_TC_BODY(aligned_even_length_little_endian, tc) +{ + u_char data[] __aligned(sizeof(u_short)) = + {0x34, 0x12, 0x78, 0x56}; + u_short sum; + + sum = in_cksum(data, nitems(data)); + ATF_REQUIRE_MSG(sum == 0x9753, "%d", sum); +} + +ATF_TC_WITHOUT_HEAD(aligned_odd_length_little_endian); +ATF_TC_BODY(aligned_odd_length_little_endian, tc) +{ + u_char data[] __aligned(sizeof(u_short)) = + {0x34, 0x12, 0x78, 0x56, 0x00, 0x9a}; + u_short sum; + + sum = in_cksum(data, nitems(data)); + ATF_REQUIRE(sum == 0xfd52); +} + +ATF_TC_WITHOUT_HEAD(unaligned_even_length_big_endian); +ATF_TC_BODY(unaligned_even_length_big_endian, tc) +{ + u_char data[] __aligned(sizeof(u_short)) = + {0x00, 0x12, 0x34, 0x56, 0x78}; + u_short sum; + + sum = in_cksum(data + 1, nitems(data) - 1); + ATF_REQUIRE(sum == 0x5397); +} + +ATF_TC_WITHOUT_HEAD(unaligned_odd_length_big_endian); +ATF_TC_BODY(unaligned_odd_length_big_endian, tc) +{ + u_char data[] __aligned(sizeof(u_short)) = + {0x00, 0x12, 0x34, 0x56, 0x78, 0x9a}; + u_short sum; + + sum = in_cksum(data + 1, nitems(data) - 1); + ATF_REQUIRE(sum == 0x52fd); +} + +ATF_TC_WITHOUT_HEAD(unaligned_even_length_little_endian); +ATF_TC_BODY(unaligned_even_length_little_endian, tc) +{ + u_char data[] __aligned(sizeof(u_short)) = + {0x00, 0x34, 0x12, 0x78, 0x56}; + u_short sum; + + sum = in_cksum(data + 1, nitems(data) - 1); + ATF_REQUIRE_MSG(sum == 0x9753, "%d", sum); +} + +ATF_TC_WITHOUT_HEAD(unaligned_odd_length_little_endian); +ATF_TC_BODY(unaligned_odd_length_little_endian, tc) +{ + u_char data[] __aligned(sizeof(u_short)) = + {0x00, 0x34, 0x12, 0x78, 0x56, 0x00, 0x9a}; + u_short sum; + + sum = in_cksum(data + 1, nitems(data) - 1); + ATF_REQUIRE(sum == 0xfd52); +} + +/* + * Main. + */ + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, aligned_even_length_big_endian); + ATF_TP_ADD_TC(tp, aligned_odd_length_big_endian); + ATF_TP_ADD_TC(tp, aligned_even_length_little_endian); + ATF_TP_ADD_TC(tp, aligned_odd_length_little_endian); + ATF_TP_ADD_TC(tp, unaligned_even_length_big_endian); + ATF_TP_ADD_TC(tp, unaligned_odd_length_big_endian); + ATF_TP_ADD_TC(tp, unaligned_even_length_little_endian); + ATF_TP_ADD_TC(tp, unaligned_odd_length_little_endian); + + return (atf_no_error()); +} diff --git a/sbin/ping/tests/ping_c1_s56_t1.out b/sbin/ping/tests/ping_c1_s56_t1.out new file mode 100644 index 00000000000..24eca478c96 --- /dev/null +++ b/sbin/ping/tests/ping_c1_s56_t1.out @@ -0,0 +1,6 @@ +PING localhost: 56 data bytes +64 bytes from: icmp_seq=0 ttl= time= ms + +--- localhost ping statistics --- +1 packets transmitted, 1 packets received, 0.0% packet loss +round-trip min/avg/max/stddev = /// ms diff --git a/sbin/ping/tests/ping_test.sh b/sbin/ping/tests/ping_test.sh new file mode 100644 index 00000000000..3c792453d4f --- /dev/null +++ b/sbin/ping/tests/ping_test.sh @@ -0,0 +1,55 @@ +# +# 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$ + +atf_test_case ping_c1_s56_t1 +ping_c1_s56_t1_head() { + atf_set "descr" "Stop after receiving 1 ECHO_RESPONSE packet" +} +ping_c1_s56_t1_body() { + if ! getaddrinfo -f inet localhost 1>/dev/null 2>&1; then + atf_skip "IPv4 is not configured" + fi + atf_check -s exit:0 -o save:std.out -e empty \ + ping -c 1 -s 56 -t 1 localhost + check_ping_statistics std.out $(atf_get_srcdir)/ping_c1_s56_t1.out +} + +atf_init_test_cases() { + atf_add_test_case ping_c1_s56_t1 +} + +check_ping_statistics() { + sed -e 's/0.[0-9]\{3\}//g' \ + -e 's/[1-9][0-9]*.[0-9]\{3\}//g' \ + -e 's/localhost ([0-9]\{1,3\}\(\.[0-9]\{1,3\}\)\{1,3\})/localhost/' \ + -e 's/from [0-9]\{1,3\}\(\.[0-9]\{1,3\}\)\{1,3\}/from/' \ + -e 's/ttl=[0-9][0-9]*/ttl=/' \ + "$1" >"$1".filtered + atf_check -s exit:0 diff -u "$1".filtered "$2" +} -- 2.45.0