From 3bf4cdb73bb197b51310633f7abb72aecaf695ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Sat, 24 Feb 2024 16:51:04 +0100 Subject: [PATCH] network/ping: update to freebsd-current * our ip modules don't support connect()/send(). Just use sendto(). * ping6 disappears, ping supports -4 or -6 to force IPv4 or IPv6 Change-Id: I1e982e354cc75d3a314c5bbbfffa0373e8f4d9af Reviewed-on: https://review.haiku-os.org/c/haiku/+/7427 Reviewed-by: waddlesplash --- build/jam/images/definitions/minimum | 2 +- headers/posix/netinet/ip_icmp.h | 2 + src/bin/network/Jamfile | 1 - src/bin/network/ping/Jamfile | 9 +- src/bin/network/ping/main.c | 310 ++++ src/bin/network/ping/main.h | 79 + src/bin/network/ping/ping.c | 2120 ++++++++++++++--------- src/bin/network/ping/ping.h | 34 + src/bin/network/{ping6 => ping}/ping6.c | 1533 ++++++++-------- src/bin/network/ping/ping6.h | 34 + src/bin/network/ping/utils.c | 84 + src/bin/network/ping/utils.h | 36 + src/bin/network/ping6/Jamfile | 7 - src/data/package_infos/generic/haiku | 1 - 14 files changed, 2706 insertions(+), 1546 deletions(-) create mode 100644 src/bin/network/ping/main.c create mode 100644 src/bin/network/ping/main.h create mode 100644 src/bin/network/ping/ping.h rename src/bin/network/{ping6 => ping}/ping6.c (66%) create mode 100644 src/bin/network/ping/ping6.h create mode 100644 src/bin/network/ping/utils.c create mode 100644 src/bin/network/ping/utils.h delete mode 100644 src/bin/network/ping6/Jamfile diff --git a/build/jam/images/definitions/minimum b/build/jam/images/definitions/minimum index 7d805b86d7..07383a3f23 100644 --- a/build/jam/images/definitions/minimum +++ b/build/jam/images/definitions/minimum @@ -19,7 +19,7 @@ SYSTEM_BIN = [ FFilterByBuildFeatures modifiers mount mountvolume netstat notify open - package package_repo passwd pc ping ping6 pkgman prio profile ps + package package_repo passwd pc ping pkgman prio profile ps query quit ramdisk rc reindex release renice resattr resizefs rmattr rmindex roster route diff --git a/headers/posix/netinet/ip_icmp.h b/headers/posix/netinet/ip_icmp.h index a3b6e5174a..778ea226dd 100644 --- a/headers/posix/netinet/ip_icmp.h +++ b/headers/posix/netinet/ip_icmp.h @@ -84,6 +84,8 @@ struct icmp { #define icmp_data icmp_dun.id_data #define ICMP_MINLEN 8 /* absolute minimum length */ +#define ICMP_TSLEN (8 + 3 * sizeof (uint32_t)) /* timestamp */ +#define ICMP_MASKLEN 12 /* address mask */ #define ICMP_ADVLENMIN (8 + sizeof(struct ip) + 8) #define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) diff --git a/src/bin/network/Jamfile b/src/bin/network/Jamfile index 2b27735212..8c9b879695 100644 --- a/src/bin/network/Jamfile +++ b/src/bin/network/Jamfile @@ -12,7 +12,6 @@ SubInclude HAIKU_TOP src bin network netstat ; SubInclude HAIKU_TOP src bin network pppconfig ; SubInclude HAIKU_TOP src bin network ppp_up ; SubInclude HAIKU_TOP src bin network ping ; -SubInclude HAIKU_TOP src bin network ping6 ; SubInclude HAIKU_TOP src bin network route ; SubInclude HAIKU_TOP src bin network telnet ; SubInclude HAIKU_TOP src bin network telnetd ; diff --git a/src/bin/network/ping/Jamfile b/src/bin/network/ping/Jamfile index dd8686b55b..7a343c83cc 100644 --- a/src/bin/network/ping/Jamfile +++ b/src/bin/network/ping/Jamfile @@ -1,8 +1,15 @@ SubDir HAIKU_TOP src bin network ping ; +SubDirSysHdrs $(HAIKU_TOP) headers compatibility bsd ; + +DEFINES += INET INET6 ; + BinCommand ping : + main.c ping.c - : $(TARGET_NETWORK_LIBS) $(TARGET_SELECT_UNAME_ETC_LIB) ; + ping6.c + utils.c + : $(TARGET_NETWORK_LIBS) $(TARGET_SELECT_UNAME_ETC_LIB) libbsd.so ; # Installation -- in the test directory for the time being HaikuInstall install-networking diff --git a/src/bin/network/ping/main.c b/src/bin/network/ping/main.c new file mode 100644 index 0000000000..905fd9c334 --- /dev/null +++ b/src/bin/network/ping/main.c @@ -0,0 +1,310 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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 +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "main.h" +#ifdef INET +#include "ping.h" +#endif +#ifdef INET6 +#include "ping6.h" +#endif + +#if defined(INET) && defined(INET6) +#define OPTSTR PING6OPTS PING4OPTS +#elif defined(INET) +#define OPTSTR PING4OPTS +#elif defined(INET6) +#define OPTSTR PING6OPTS +#else +#error At least one of INET and INET6 is required +#endif + +#ifdef __HAIKU__ +#define optreset optind +#define feature_present(x) true +#ifndef restrict +#define restrict +#endif +#endif + +/* various options */ +u_int options; + +char *hostname; + +/* counters */ +long nreceived; /* # of packets we got back */ +long nrepeats; /* number of duplicates */ +long ntransmitted; /* sequence # for outbound packets = #sent */ +long nrcvtimeout = 0; /* # of packets we got back after waittime */ + +/* nonzero if we've been told to finish up */ +volatile sig_atomic_t seenint; +volatile sig_atomic_t seeninfo; + +/* timing */ +int timing; /* flag to do timing */ +double tmin = 999999999.0; /* minimum round trip time */ +double tmax = 0.0; /* maximum round trip time */ +double tsum = 0.0; /* sum of all times, for doing average */ +double tsumsq = 0.0; /* sum of all times squared, for std. dev. */ + +int +main(int argc, char *argv[]) +{ +#if defined(INET) + struct in_addr a; +#endif +#if defined(INET6) + struct in6_addr a6; +#endif +#if defined(INET) && defined(INET6) + struct addrinfo hints, *res, *ai; + const char *target; + int error; +#endif + int opt; + +#ifdef INET6 + if (strcmp(getprogname(), "ping6") == 0) + return ping6(argc, argv); +#endif + + while ((opt = getopt(argc, argv, ":" OPTSTR)) != -1) { + switch (opt) { +#ifdef INET + case '4': + goto ping4; +#endif +#ifdef INET6 + case '6': + goto ping6; +#endif + case 'S': + /* + * If -S is given with a numeric parameter, + * force use of the corresponding version. + */ +#ifdef INET + if (inet_pton(AF_INET, optarg, &a) == 1) + goto ping4; +#endif +#ifdef INET6 + if (inet_pton(AF_INET6, optarg, &a6) == 1) + goto ping6; +#endif + break; + default: + break; + } + } + + /* + * For IPv4, only one positional argument, the target, is allowed. + * For IPv6, multiple positional argument are allowed; the last + * one is the target, and preceding ones are intermediate hops. + * This nuance is lost here, but the only case where it matters is + * an error. + */ + if (optind >= argc) + usage(); + +#if defined(INET) && defined(INET6) + target = argv[argc - 1]; + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_RAW; + if (feature_present("inet") && !feature_present("inet6")) + hints.ai_family = AF_INET; + if (feature_present("inet6") && !feature_present("inet")) + hints.ai_family = AF_INET6; + else + hints.ai_family = AF_UNSPEC; + error = getaddrinfo(target, NULL, &hints, &res); + if (res == NULL) + errx(EX_NOHOST, "cannot resolve %s: %s", + target, gai_strerror(error)); + for (ai = res; ai != NULL; ai = ai->ai_next) { + if (ai->ai_family == AF_INET) { + freeaddrinfo(res); + goto ping4; + } + if (ai->ai_family == AF_INET6) { + freeaddrinfo(res); + goto ping6; + } + } + freeaddrinfo(res); + errx(EX_NOHOST, "cannot resolve %s", target); +#endif +#ifdef INET +ping4: + optreset = 1; + optind = 1; + return ping(argc, argv); +#endif +#ifdef INET6 +ping6: + optreset = 1; + optind = 1; + return ping6(argc, argv); +#endif +} + +/* + * onsignal -- + * Set the global bit that causes the main loop to quit. + */ +void +onsignal(int sig) +{ + switch (sig) { + case SIGALRM: + case SIGINT: + /* + * 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); + seenint++; + break; +#ifndef __HAIKU__ + case SIGINFO: + seeninfo++; + break; +#endif + } +} + +/* + * pr_summary -- + * Print out summary statistics to the given output stream. + */ +void +pr_summary(FILE * restrict stream) +{ + fprintf(stream, "\n--- %s ping statistics ---\n", hostname); + fprintf(stream, "%ld packets transmitted, ", ntransmitted); + fprintf(stream, "%ld packets received, ", nreceived); + if (nrepeats) + fprintf(stream, "+%ld duplicates, ", nrepeats); + if (ntransmitted) { + if (nreceived > ntransmitted) + fprintf(stream, "-- somebody's duplicating packets!"); + else + fprintf(stream, "%.1f%% packet loss", + ((((double)ntransmitted - nreceived) * 100.0) / + ntransmitted)); + } + if (nrcvtimeout) + fprintf(stream, ", %ld packets out of wait time", nrcvtimeout); + fputc('\n', stream); + if (nreceived && timing) { + /* Only display average to microseconds */ + double num = nreceived + nrepeats; + double avg = tsum / num; + double stddev = sqrt(fmax(0, tsumsq / num - avg * avg)); + fprintf(stream, + "round-trip min/avg/max/stddev = %.3f/%.3f/%.3f/%.3f ms\n", + tmin, avg, tmax, stddev); + } + fflush(stream); +} + +void +usage(void) +{ + (void)fprintf(stderr, + "usage:\n" +#ifdef INET + "\tping [-4AaDdfHnoQqRrv] [-C pcp] [-c count] " + "[-G sweepmaxsize]\n" + "\t [-g sweepminsize] [-h sweepincrsize] [-i wait] " + "[-l preload]\n" + "\t [-M mask | time] [-m ttl] " +#ifdef IPSEC + "[-P policy] " +#endif + "[-p pattern] [-S src_addr] \n" + "\t [-s packetsize] [-t timeout] [-W waittime] [-z tos] " + "IPv4-host\n" + "\tping [-4AaDdfHLnoQqRrv] [-C pcp] [-c count] [-I iface] " + "[-i wait]\n" + "\t [-l preload] [-M mask | time] [-m ttl] " +#ifdef IPSEC + "[-P policy] " +#endif + "[-p pattern]\n" + "\t [-S src_addr] [-s packetsize] [-T ttl] [-t timeout] [-W waittime]\n" + "\t [-z tos] IPv4-mcast-group\n" +#endif /* INET */ +#ifdef INET6 + "\tping [-6AaDd" +#if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC) + "E" +#endif + "fHnNoOq" +#ifdef IPV6_USE_MIN_MTU + "u" +#endif + "vyY" +#if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC) + "Z" +#endif + "] " + "[-b bufsiz] [-C pcp] [-c count] [-e gateway]\n" + "\t [-I interface] [-i wait] [-k addrtype] [-l preload] " + "[-m hoplimit]\n" + "\t [-p pattern]" +#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) + " [-P policy]" +#endif + " [-S sourceaddr] [-s packetsize] [-t timeout]\n" + "\t [-W waittime] [-z tclass] [IPv6-hops ...] IPv6-host\n" +#endif /* INET6 */ + ); + + exit(1); +} diff --git a/src/bin/network/ping/main.h b/src/bin/network/ping/main.h new file mode 100644 index 0000000000..9a883b61a3 --- /dev/null +++ b/src/bin/network/ping/main.h @@ -0,0 +1,79 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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. + */ + +#ifndef MAIN_H +#define MAIN_H 1 + +#ifdef IPSEC +#include +#endif /*IPSEC*/ + +#if defined(INET) && defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) + #define PING4ADDOPTS "P:" +#else + #define PING4ADDOPTS +#endif +#define PING4OPTS ".::4AaC:c:DdfG:g:Hh:I:i:Ll:M:m:nop:QqRrS:s:T:t:vW:z:" PING4ADDOPTS + +#if defined(INET6) && defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) + #define PING6ADDOPTS "P:" +#elif defined(INET6) && defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC) + #define PING6ADDOPTS "ZE" +#else + #define PING6ADDOPTS +#endif +#define PING6OPTS ".::6Aab:C:c:Dde:fHI:i:k:l:m:nNoOp:qS:s:t:uvyYW:z:" PING6ADDOPTS + +/* various options */ +extern u_int options; +#define F_HOSTNAME 0x0004 + +extern char *hostname; + +/* counters */ +extern long nreceived; /* # of packets we got back */ +extern long nrepeats; /* number of duplicates */ +extern long ntransmitted; /* sequence # for outbound packets = #sent */ +extern long nrcvtimeout; /* # of packets we got back after waittime */ + +/* nonzero if we've been told to finish up */ +extern volatile sig_atomic_t seenint; +extern volatile sig_atomic_t seeninfo; + +/* timing */ +extern int timing; /* flag to do timing */ +extern double tmin; /* minimum round trip time */ +extern double tmax; /* maximum round trip time */ +extern double tsum; /* sum of all times, for doing average */ +extern double tsumsq; /* sum of all times squared, for std. dev. */ + +void onsignal(int); +void pr_summary(FILE * __restrict); +void usage(void) __dead2; + +#endif diff --git a/src/bin/network/ping/ping.c b/src/bin/network/ping/ping.c index a028bec8d7..7763f162cc 100644 --- a/src/bin/network/ping/ping.c +++ b/src/bin/network/ping/ping.c @@ -1,4 +1,6 @@ -/* +/*- + * SPDX-License-Identifier: BSD-3-Clause + * * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * @@ -13,11 +15,7 @@ * 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. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 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. * @@ -37,7 +35,7 @@ /* * P I N G . C * - * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility, + * Using the Internet Control Message Protocol (ICMP) "ECHO" facility, * measure round-trip-delays and packet loss across network paths. * * Author - @@ -52,33 +50,65 @@ * This program has to run SUID to ROOT to access the ICMP socket. */ -#include - -#include +#include /* NB: we rely on this for */ +#ifndef __HAIKU__ +#include +#endif #include +#ifndef __HAIKU__ +#include +#endif #include +#include #include -#include "netinet/ip.h" -#include "netinet/ip_icmp.h" +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define DEFDATALEN (64 - 8) /* default data length */ -#define MAXIPLEN 60 -#define MAXICMPLEN 76 -#define MAXPAYLOAD (IP_MAXPACKET - MAXIPLEN - 8) /* max ICMP payload size */ -#define MAXWAIT_DEFAULT 10 /* secs to wait for response */ -#define NROUTES 9 /* number of record route slots */ +#ifndef __HAIKU__ +#include +#include +#endif + +#ifdef IPSEC +#include +#endif /*IPSEC*/ + +#ifndef __HAIKU__ +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "main.h" +#include "ping.h" +#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) +#define TS_LEN (ICMP_TSLEN - ICMP_MINLEN) +#define DEFDATALEN 56 /* default data length */ +#define FLOOD_BACKOFF 20000 /* usecs to back off if F_FLOOD mode */ + /* runs out of buffer space */ +#define MAXIPLEN (sizeof(struct ip) + MAX_IPOPTLEN) +#define MAXICMPLEN (ICMP_ADVLENMIN + MAX_IPOPTLEN) +#define MAXWAIT 10000 /* max ms to wait for response */ +#define MAXALARM (60 * 60) /* max seconds for alarm timeout */ +#define MAXTOS 255 #define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ #define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ @@ -86,26 +116,40 @@ #define CLR(bit) (A(bit) &= (~B(bit))) #define TST(bit) (A(bit) & B(bit)) -/* various options */ -int options; -#define F_FLOOD 0x001 -#define F_INTERVAL 0x002 -#define F_NUMERIC 0x004 -#define F_PINGFILLED 0x008 -#define F_QUIET 0x010 -#define F_RROUTE 0x020 -#define F_SO_DEBUG 0x040 -#define F_SO_DONTROUTE 0x080 -#define F_VERBOSE 0x100 -#define F_SADDR 0x200 -#define F_HDRINCL 0x400 -#define F_TTL 0x800 +struct tv32 { + int32_t tv32_sec; + int32_t tv32_nsec; +}; -/* multicast options */ -int moptions; -#define MULTICAST_NOLOOP 0x001 -#define MULTICAST_TTL 0x002 -#define MULTICAST_IF 0x004 +/* various options */ +#define F_FLOOD 0x0001 +#define F_INTERVAL 0x0002 +#define F_PINGFILLED 0x0008 +#define F_QUIET 0x0010 +#define F_RROUTE 0x0020 +#define F_SO_DEBUG 0x0040 +#define F_SO_DONTROUTE 0x0080 +#define F_VERBOSE 0x0100 +#define F_QUIET2 0x0200 +#define F_NOLOOP 0x0400 +#define F_MTTL 0x0800 +#define F_MIF 0x1000 +#define F_AUDIBLE 0x2000 +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC +#define F_POLICY 0x4000 +#endif /*IPSEC_POLICY_IPSEC*/ +#endif /*IPSEC*/ +#define F_TTL 0x8000 +#define F_MISSED 0x10000 +#define F_ONCE 0x20000 +#define F_HDRINCL 0x40000 +#define F_MASK 0x80000 +#define F_TIME 0x100000 +#define F_SWEEP 0x200000 +#define F_WAITTIME 0x400000 +#define F_IP_VLAN_PCP 0x800000 +#define F_DOT 0x1000000 /* * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum @@ -113,168 +157,310 @@ int moptions; * to 8192 for complete accuracy... */ #define MAX_DUP_CHK (8 * 128) -int mx_dup_ck = MAX_DUP_CHK; -char rcvd_tbl[MAX_DUP_CHK / 8]; +static int mx_dup_ck = MAX_DUP_CHK; +static char rcvd_tbl[MAX_DUP_CHK / 8]; -struct sockaddr whereto; /* who to ping */ -struct sockaddr_in whence; /* Which interface we come from */ -int datalen = DEFDATALEN; -int s; /* socket file descriptor */ -u_char outpackhdr[IP_MAXPACKET]; /* Max packet size = 65535 */ -u_char *outpack = outpackhdr+sizeof(struct ip); -char BSPACE = '\b'; /* characters written for flood */ -char DOT = '.'; -char *hostname; -int ident; /* process id to identify our packets */ +static struct sockaddr_in whereto; /* who to ping */ +static int datalen = DEFDATALEN; +static int maxpayload; +static int ssend; /* send socket file descriptor */ +static int srecv; /* receive socket file descriptor */ +static u_char outpackhdr[IP_MAXPACKET], *outpack; +static char BBELL = '\a'; /* characters written for MISSED and AUDIBLE */ +static char BSPACE = '\b'; /* characters written for flood */ +static const char *DOT = "."; +static size_t DOTlen = 1; +static size_t DOTidx = 0; +static char *shostname; +static int ident; /* process id to identify our packets */ +static int uid; /* cached uid for micro-optimization */ +static u_char icmp_type = ICMP_ECHO; +static u_char icmp_type_rsp = ICMP_ECHOREPLY; +static int phdr_len = 0; +static int send_len; /* counters */ -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 */ -double interval = 1; /* interval between packets */ +static long nmissedmax; /* max value of ntransmitted - nreceived - 1 */ +static long npackets; /* max packets to transmit */ +static long snpackets; /* max packets to transmit in one sweep */ +static long sntransmitted; /* # of packets we sent in this sweep */ +static int sweepmax; /* max value of payload in sweep */ +static int sweepmin = 0; /* start value of payload in sweep */ +static int sweepincr = 1; /* payload increment in sweep */ +static int interval = 1000; /* interval between packets, ms */ +static int waittime = MAXWAIT; /* timeout for each packet */ -/* timing */ -int timing; /* flag to do timing */ -int maxwait = MAXWAIT_DEFAULT; /* max seconds to wait for response */ -uint64 tmin = 999999999; /* minimum round trip time in millisec */ -uint64 tmax = 0; /* maximum round trip time in millisec */ -uint64 tsum = 0; /* sum of all times in millisec, for doing average */ -uint64 tsumsq = 0; /* sum of all times squared, for std. dev. */ - -#ifdef SIGINFO -int reset_kerninfo; +#ifndef __HAIKU__ +static cap_channel_t *capdns; #endif -#define DEFAULT_BUFSPACE 60*1024 /* default read buffer size */ -int bufspace = DEFAULT_BUFSPACE; +static void fill(char *, char *); +#ifndef __HAIKU__ +static cap_channel_t *capdns_setup(void); +#endif +static void pinger(void); +static char *pr_addr(struct in_addr); +static char *pr_ntime(n_time); +static void pr_icmph(struct icmp *, struct ip *, const u_char *const); +static void pr_iph(struct ip *, const u_char *); +static void pr_pack(char *, ssize_t, struct sockaddr_in *, struct timespec *); -void fill(char *, char *); -void catcher(int); -void prtsig(int); -void finish(int); -void summary(int); -int compute_in_cksum (u_short *, int); -void pinger(void); -char *pr_addr (in_addr_t); -int check_icmph (struct ip *); -void pr_icmph (struct icmp *); -void pr_pack (char *, int, struct sockaddr_in *); -void pr_retip (struct ip *); -void pr_iph(struct ip *ip); -uint64 qsqrt (uint64); -void usage(void); - - -static void err(int exitval, char *where) +int +ping(int argc, char *const *argv) { - printf("error: %s: error %d [%s]\n", where, errno, strerror(errno)); - exit(exitval); -} - -static void errx(int exitval, char *fmt_string, char *value) -{ - printf("error: "); - printf(fmt_string, value); - printf("\n"); - exit(exitval); -} - -int main(int argc, char **argv) -{ - struct timeval timeout; + struct sockaddr_in from, sock_in; + struct in_addr ifaddr; + struct timespec last, intvl; + struct iovec iov; + struct msghdr msg; + struct sigaction si_sa; + size_t sz; +#ifdef __HAIKU__ +#define __aligned(x) __attribute__((__aligned__(x))) +#endif + u_char *datap, packet[IP_MAXPACKET] __aligned(4); + const char *errstr; + char *ep, *source, *target, *payload; struct hostent *hp; - struct sockaddr_in *to; - struct protoent *proto; - struct in_addr saddr; - int i; - int ch, hold = 1, packlen, preload; - int maxsize, fdmasks; - socklen_t maxsizelen; - u_char *datap, *packet; - char *target, hnamebuf[MAXHOSTNAMELEN]; - u_char ttl = MAXTTL, loop = 1, df = 0; - int tos = 0; -#ifdef IP_OPTIONS - char rspace[3 + 4 * NROUTES + 1]; /* record route space */ +#ifdef IPSEC_POLICY_IPSEC + char *policy_in, *policy_out; #endif - fd_set *fdmaskp; + struct sockaddr_in *to; + double t; + u_long alarmtimeout; + long long ltmp; + int almost_done, ch, df, hold, i, icmp_len, mib[4], preload; + int ssend_errno, srecv_errno, tos, ttl, pcp; + char ctrl[CMSG_SPACE(sizeof(struct timespec))]; + char hnamebuf[MAXHOSTNAMELEN], snamebuf[MAXHOSTNAMELEN]; +#ifdef IP_OPTIONS + char rspace[MAX_IPOPTLEN]; /* record route space */ +#endif + unsigned char loop, mttl; - if (!(proto = getprotobyname("icmp"))) - err(1, "unknown protocol icmp"); - if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) - err(1, "socket"); + payload = source = NULL; +#ifdef IPSEC_POLICY_IPSEC + policy_in = policy_out = NULL; +#endif +#ifndef __HAIKU__ + cap_rights_t rights; +#endif - /* revoke privs */ -// seteuid(getuid()); -// setuid(getuid()); + /* + * Do the stuff that we need root priv's for *first*, and + * then drop our setuid bit. Save error reporting for + * after arg parsing. + * + * Historicaly ping was using one socket 's' for sending and for + * receiving. After capsicum(4) related changes we use two + * sockets. It was done for special ping use case - when user + * issue ping on multicast or broadcast address replies come + * from different addresses, not from the address we + * connect(2)'ed to, and send socket do not receive those + * packets. + */ + ssend = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + ssend_errno = errno; + srecv = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + srecv_errno = errno; - preload = 0; - datap = &outpack[8 + sizeof(uint64)]; - while ((ch = getopt(argc, argv, "DI:LRS:c:dfh:i:l:np:qrs:T:t:vw:")) != -1) + if (setuid(getuid()) != 0) + err(EX_NOPERM, "setuid() failed"); + uid = getuid(); + + if (ssend < 0) { + errno = ssend_errno; + err(EX_OSERR, "ssend socket"); + } + + if (srecv < 0) { + errno = srecv_errno; + err(EX_OSERR, "srecv socket"); + } + + alarmtimeout = df = preload = tos = pcp = 0; + + outpack = outpackhdr + sizeof(struct ip); + while ((ch = getopt(argc, argv, PING4OPTS)) != -1) { switch(ch) { + case '.': + options |= F_DOT; + if (optarg != NULL) { + DOT = optarg; + DOTlen = strlen(optarg); + } + break; + case '4': + /* This option is processed in main(). */ + break; + case 'A': + options |= F_MISSED; + break; + case 'a': + options |= F_AUDIBLE; + break; + case 'C': +#ifndef __HAIKU__ + options |= F_IP_VLAN_PCP; + ltmp = strtonum(optarg, -1, 7, &errstr); + if (errstr != NULL) + errx(EX_USAGE, "invalid PCP: `%s'", optarg); + pcp = ltmp; +#else + errx(EX_UNAVAILABLE, "VLAN PCP not available"); +#endif + break; case 'c': - npackets = strtol(optarg, NULL, 0); - if (npackets <= 0) - errx(1, "bad number of packets to transmit: %s", + ltmp = strtonum(optarg, 1, LONG_MAX, &errstr); + if (errstr != NULL) + errx(EX_USAGE, + "invalid count of packets to transmit: `%s'", optarg); + npackets = (long)ltmp; break; case 'D': options |= F_HDRINCL; - df = -1; + df = 1; break; case 'd': options |= F_SO_DEBUG; break; case 'f': - if (getuid()) - errx(1, "%s", strerror(EPERM)); + if (uid) { + errno = EPERM; + err(EX_NOPERM, "-f flag"); + } options |= F_FLOOD; + options |= F_DOT; setbuf(stdout, (char *)NULL); break; - case 'I': - case 'S': /* deprecated */ - if (inet_aton(optarg, &saddr) == 0) { - if ((hp = gethostbyname(optarg)) == NULL) - errx(1, "bad interface address: %s", - optarg); - memcpy(&saddr, hp->h_addr, sizeof(saddr)); + case 'G': /* Maximum packet size for ping sweep */ + ltmp = strtonum(optarg, 1, INT_MAX, &errstr); + if (errstr != NULL) { + errx(EX_USAGE, "invalid packet size: `%s'", + optarg); } - options |= F_SADDR; + sweepmax = (int)ltmp; + if (uid != 0 && sweepmax > DEFDATALEN) { + errc(EX_NOPERM, EPERM, + "packet size too large: %d > %u", + sweepmax, DEFDATALEN); + } + options |= F_SWEEP; + break; + case 'g': /* Minimum packet size for ping sweep */ + ltmp = strtonum(optarg, 1, INT_MAX, &errstr); + if (errstr != NULL) { + errx(EX_USAGE, "invalid packet size: `%s'", + optarg); + } + sweepmin = (int)ltmp; + if (uid != 0 && sweepmin > DEFDATALEN) { + errc(EX_NOPERM, EPERM, + "packet size too large: %d > %u", + sweepmin, DEFDATALEN); + } + options |= F_SWEEP; + break; + case 'H': + options |= F_HOSTNAME; + break; + case 'h': /* Packet size increment for ping sweep */ + ltmp = strtonum(optarg, 1, INT_MAX, &errstr); + if (errstr != NULL) { + errx(EX_USAGE, "invalid packet size: `%s'", + optarg); + } + sweepincr = (int)ltmp; + if (uid != 0 && sweepincr > DEFDATALEN) { + errc(EX_NOPERM, EPERM, + "packet size too large: %d > %u", + sweepincr, DEFDATALEN); + } + options |= F_SWEEP; + break; + case 'I': /* multicast interface */ + if (inet_aton(optarg, &ifaddr) == 0) + errx(EX_USAGE, + "invalid multicast interface: `%s'", + optarg); + options |= F_MIF; break; case 'i': /* wait between sending packets */ - interval = strtod(optarg, NULL); - - if (interval <= 0 || interval >= INT_MAX) - errx(1, "bad timing interval: %s", optarg); - - if (interval < 1) - if (getuid()) - errx(1, "%s: only root may use interval < 1s", strerror(EPERM)); - - if (interval < 0.01) - interval = 0.01; - + t = strtod(optarg, &ep) * 1000.0; + if (*ep || ep == optarg || t > (double)INT_MAX) + errx(EX_USAGE, "invalid timing interval: `%s'", + optarg); options |= F_INTERVAL; + interval = (int)t; + if (uid && interval < 1000) { + errno = EPERM; + err(EX_NOPERM, "-i interval too short"); + } break; case 'L': - moptions |= MULTICAST_NOLOOP; + options |= F_NOLOOP; loop = 0; break; case 'l': - if (getuid()) - errx(1, "%s", strerror(EPERM)); - preload = strtol(optarg, NULL, 0); - if (preload < 0) - errx(1, "bad preload value: %s", optarg); + ltmp = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) + errx(EX_USAGE, + "invalid preload value: `%s'", optarg); + if (uid) { + errno = EPERM; + err(EX_NOPERM, "-l flag"); + } + preload = (int)ltmp; + break; + case 'M': + switch(optarg[0]) { + case 'M': + case 'm': + options |= F_MASK; + break; + case 'T': + case 't': + options |= F_TIME; + break; + default: + errx(EX_USAGE, "invalid message: `%c'", optarg[0]); + break; + } + break; + case 'm': /* TTL */ + ltmp = strtonum(optarg, 0, MAXTTL, &errstr); + if (errstr != NULL) + errx(EX_USAGE, "invalid TTL: `%s'", optarg); + ttl = (int)ltmp; + options |= F_TTL; break; case 'n': - options |= F_NUMERIC; + options &= ~F_HOSTNAME; break; + case 'o': + options |= F_ONCE; + break; +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC + case 'P': + options |= F_POLICY; + if (!strncmp("in", optarg, 2)) + policy_in = strdup(optarg); + else if (!strncmp("out", optarg, 3)) + policy_out = strdup(optarg); + else + errx(1, "invalid security policy"); + break; +#endif /*IPSEC_POLICY_IPSEC*/ +#endif /*IPSEC*/ case 'p': /* fill buffer with user pattern */ options |= F_PINGFILLED; - fill((char *)datap, optarg); - break; + payload = optarg; + break; + case 'Q': + options |= F_QUIET2; + break; case 'q': options |= F_QUIET; break; @@ -284,339 +470,660 @@ int main(int argc, char **argv) case 'r': options |= F_SO_DONTROUTE; break; - case 's': /* size of packet to send */ - datalen = strtol(optarg, NULL, 0); - if (datalen <= 0) - errx(1, "bad packet size: %s", optarg); - if (datalen > MAXPAYLOAD) - errx(1, "packet size too large: %s", optarg); + case 'S': + source = optarg; break; - case 'T': - options |= F_HDRINCL; - tos = strtoul(optarg, NULL, 0); - if (tos > 0xFF) - errx(1, "bad tos value: %s", optarg); + case 's': /* size of packet to send */ + ltmp = strtonum(optarg, 0, INT_MAX, &errstr); + if (errstr != NULL) + errx(EX_USAGE, "invalid packet size: `%s'", + optarg); + datalen = (int)ltmp; + if (uid != 0 && datalen > DEFDATALEN) { + errno = EPERM; + err(EX_NOPERM, + "packet size too large: %d > %u", + datalen, DEFDATALEN); + } + break; + case 'T': /* multicast TTL */ + ltmp = strtonum(optarg, 0, MAXTTL, &errstr); + if (errstr != NULL) + errx(EX_USAGE, "invalid multicast TTL: `%s'", + optarg); + mttl = (unsigned char)ltmp; + options |= F_MTTL; break; case 't': - options |= F_TTL; - ttl = strtol(optarg, NULL, 0); - if (ttl <= 0) - errx(1, "bad ttl value: %s", optarg); - if (ttl > 255) - errx(1, "ttl value too large: %s", optarg); + alarmtimeout = strtoul(optarg, &ep, 0); + if ((alarmtimeout < 1) || (alarmtimeout == ULONG_MAX)) + errx(EX_USAGE, "invalid timeout: `%s'", + optarg); + if (alarmtimeout > MAXALARM) + errx(EX_USAGE, "invalid timeout: `%s' > %d", + optarg, MAXALARM); + { + struct itimerval itv; + + timerclear(&itv.it_interval); + timerclear(&itv.it_value); + itv.it_value.tv_sec = (time_t)alarmtimeout; + if (setitimer(ITIMER_REAL, &itv, NULL) != 0) + err(1, "setitimer"); + } break; case 'v': options |= F_VERBOSE; break; - case 'w': - maxwait = strtol(optarg, NULL, 0); - if (maxwait <= 0) - errx(1, "bad maxwait value: %s", optarg); + case 'W': /* wait ms for answer */ + t = strtod(optarg, &ep); + if (*ep || ep == optarg || t > (double)INT_MAX) + errx(EX_USAGE, "invalid timing interval: `%s'", + optarg); + options |= F_WAITTIME; + waittime = (int)t; + break; + case 'z': + options |= F_HDRINCL; + ltmp = strtol(optarg, &ep, 0); + if (*ep || ep == optarg || ltmp > MAXTOS || ltmp < 0) + errx(EX_USAGE, "invalid TOS: `%s'", optarg); + tos = ltmp; break; default: usage(); } - argc -= optind; - argv += optind; + } - if (argc != 1) + if (argc - optind != 1) usage(); + target = argv[optind]; - target = *argv; + switch (options & (F_MASK|F_TIME)) { + case 0: break; + case F_MASK: + icmp_type = ICMP_MASKREQ; + icmp_type_rsp = ICMP_MASKREPLY; + phdr_len = MASK_LEN; + if (!(options & F_QUIET)) + (void)printf("ICMP_MASKREQ\n"); + break; + case F_TIME: + icmp_type = ICMP_TSTAMP; + icmp_type_rsp = ICMP_TSTAMPREPLY; + phdr_len = TS_LEN; + if (!(options & F_QUIET)) + (void)printf("ICMP_TSTAMP\n"); + break; + default: + errx(EX_USAGE, "ICMP_TSTAMP and ICMP_MASKREQ are exclusive."); + break; + } + icmp_len = sizeof(struct ip) + ICMP_MINLEN + phdr_len; + if (options & F_RROUTE) + icmp_len += MAX_IPOPTLEN; + maxpayload = IP_MAXPACKET - icmp_len; + if (datalen > maxpayload) + errx(EX_USAGE, "packet size too large: %d > %d", datalen, + maxpayload); + send_len = icmp_len + datalen; + datap = &outpack[ICMP_MINLEN + phdr_len + TIMEVAL_LEN]; + if (options & F_PINGFILLED) { + fill((char *)datap, payload); + } +#ifndef __HAIKU__ + capdns = capdns_setup(); +#else +#define cap_gethostbyname2(x, y, z) gethostbyname(y); +#endif + if (source) { + bzero((char *)&sock_in, sizeof(sock_in)); + sock_in.sin_family = AF_INET; + if (inet_aton(source, &sock_in.sin_addr) != 0) { + shostname = source; + } else { + hp = cap_gethostbyname2(capdns, source, AF_INET); + if (!hp) + errx(EX_NOHOST, "cannot resolve %s: %s", + source, hstrerror(h_errno)); - memset(&whereto, 0, sizeof(struct sockaddr)); - to = (struct sockaddr_in *)&whereto; - to->sin_len = sizeof(struct sockaddr_in); + sock_in.sin_len = sizeof sock_in; + if ((unsigned)hp->h_length > sizeof(sock_in.sin_addr) || + hp->h_length < 0) + errx(1, "gethostbyname2: illegal address"); + memcpy(&sock_in.sin_addr, hp->h_addr_list[0], + sizeof(sock_in.sin_addr)); + (void)strncpy(snamebuf, hp->h_name, + sizeof(snamebuf) - 1); + snamebuf[sizeof(snamebuf) - 1] = '\0'; + shostname = snamebuf; + } + if (bind(ssend, (struct sockaddr *)&sock_in, sizeof sock_in) == + -1) + err(1, "bind"); + } + + bzero(&whereto, sizeof(whereto)); + to = &whereto; to->sin_family = AF_INET; - if (inet_aton(target, &to->sin_addr) != 0) + to->sin_len = sizeof *to; + if (inet_aton(target, &to->sin_addr) != 0) { hostname = target; - else { - hp = gethostbyname(target); + } else { + hp = cap_gethostbyname2(capdns, target, AF_INET); if (!hp) - errx(1, "unknown host: %s", target); - to->sin_family = hp->h_addrtype; - memcpy(&to->sin_addr, hp->h_addr, hp->h_length); - (void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf)); + errx(EX_NOHOST, "cannot resolve %s: %s", + target, hstrerror(h_errno)); + + if ((unsigned)hp->h_length > sizeof(to->sin_addr)) + errx(1, "gethostbyname2 returned an illegal address"); + memcpy(&to->sin_addr, hp->h_addr_list[0], sizeof to->sin_addr); + (void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1); + hnamebuf[sizeof(hnamebuf) - 1] = '\0'; hostname = hnamebuf; } - if (options & F_FLOOD && options & F_INTERVAL) - err(1, "-f and -i options are incompatible"); + /* From now on we will use only reverse DNS lookups. */ +#ifdef WITH_CASPER + if (capdns != NULL) { + const char *types[1]; - if (datalen >= (int) sizeof(uint64)) /* can we time transfer */ + types[0] = "ADDR2NAME"; + if (cap_dns_type_limit(capdns, types, 1) < 0) + err(1, "unable to limit access to system.dns service"); + } +#endif +#ifndef __HAIKU__ +// unsupported on Haiku + if (connect(ssend, (struct sockaddr *)&whereto, sizeof(whereto)) != 0) + err(1, "connect"); +#endif + + if (options & F_FLOOD && options & F_INTERVAL) + errx(EX_USAGE, "-f and -i: incompatible options"); + + if (options & F_FLOOD && IN_MULTICAST(ntohl(to->sin_addr.s_addr))) + errx(EX_USAGE, + "-f flag cannot be used with multicast destination"); + if (options & (F_MIF | F_NOLOOP | F_MTTL) + && !IN_MULTICAST(ntohl(to->sin_addr.s_addr))) + errx(EX_USAGE, + "-I, -L, -T flags cannot be used with unicast destination"); + + if (datalen >= TIMEVAL_LEN) /* can we time transfer */ timing = 1; - packlen = datalen + MAXIPLEN + MAXICMPLEN; - if (!(packet = (u_char *)malloc((u_int)packlen))) - err(1, "malloc"); - if (!(options & F_PINGFILLED)) - for (i = sizeof(bigtime_t); i < datalen; ++i) + + if ((options & (F_PINGFILLED | F_SWEEP)) == 0) + for (i = TIMEVAL_LEN; i < datalen; ++i) *datap++ = i; ident = getpid() & 0xFFFF; - if (options & F_SADDR) { - if (IN_MULTICAST(ntohl(to->sin_addr.s_addr))) - moptions |= MULTICAST_IF; - else { - memset(&whence, 0, sizeof(whence)); - whence.sin_len = sizeof(whence); - whence.sin_family = AF_INET; - memcpy(&whence.sin_addr.s_addr, &saddr, sizeof(saddr)); - if (bind(s, (struct sockaddr*)&whence, - sizeof(whence)) < 0) - err(1, "bind"); + hold = 1; + if (options & F_SO_DEBUG) { + (void)setsockopt(ssend, SOL_SOCKET, SO_DEBUG, (char *)&hold, + sizeof(hold)); + (void)setsockopt(srecv, SOL_SOCKET, SO_DEBUG, (char *)&hold, + sizeof(hold)); + } + if (options & F_SO_DONTROUTE) + (void)setsockopt(ssend, SOL_SOCKET, SO_DONTROUTE, (char *)&hold, + sizeof(hold)); +#ifndef __HAIKU__ + if (options & F_IP_VLAN_PCP) { + (void)setsockopt(ssend, IPPROTO_IP, IP_VLAN_PCP, (char *)&pcp, + sizeof(pcp)); + } +#endif +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC + if (options & F_POLICY) { + char *buf; + if (policy_in != NULL) { + buf = ipsec_set_policy(policy_in, strlen(policy_in)); + if (buf == NULL) + errx(EX_CONFIG, "%s", ipsec_strerror()); + if (setsockopt(srecv, IPPROTO_IP, IP_IPSEC_POLICY, + buf, ipsec_get_policylen(buf)) < 0) + err(EX_CONFIG, + "ipsec policy cannot be configured"); + free(buf); + } + + if (policy_out != NULL) { + buf = ipsec_set_policy(policy_out, strlen(policy_out)); + if (buf == NULL) + errx(EX_CONFIG, "%s", ipsec_strerror()); + if (setsockopt(ssend, IPPROTO_IP, IP_IPSEC_POLICY, + buf, ipsec_get_policylen(buf)) < 0) + err(EX_CONFIG, + "ipsec policy cannot be configured"); + free(buf); } } - - if (options & F_SO_DEBUG) - (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold, - sizeof(hold)); - if (options & F_SO_DONTROUTE) - (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold, - sizeof(hold)); - - if (options & F_TTL) { - if (IN_MULTICAST(ntohl(to->sin_addr.s_addr))) - moptions |= MULTICAST_TTL; - else - options |= F_HDRINCL; - } - - if (options & F_RROUTE && options & F_HDRINCL) - err(1, "-R option and -D or -T, or -t to unicast destinations" - " are incompatible"); +#endif /*IPSEC_POLICY_IPSEC*/ +#endif /*IPSEC*/ if (options & F_HDRINCL) { - struct ip *ip = (struct ip*)outpackhdr; + struct ip ip; - setsockopt(s, 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 = proto->p_proto; - ip->ip_src.s_addr = INADDR_ANY; - ip->ip_dst = to->sin_addr; - } +#ifndef __HAIKU__ + memcpy(&ip, outpackhdr, sizeof(ip)); + if (!(options & (F_TTL | F_MTTL))) { + mib[0] = CTL_NET; + mib[1] = PF_INET; + mib[2] = IPPROTO_IP; + mib[3] = IPCTL_DEFTTL; + sz = sizeof(ttl); + if (sysctl(mib, 4, &ttl, &sz, NULL, 0) == -1) + err(1, "sysctl(net.inet.ip.ttl)"); + } +#endif + 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; + memcpy(outpackhdr, &ip, sizeof(ip)); + } + +#ifndef __HAIKU__ + /* + * Here we enter capability mode. Further down access to global + * namespaces (e.g filesystem) is restricted (see capsicum(4)). + * We must connect(2) our socket before this point. + */ + caph_cache_catpages(); + if (caph_enter_casper() < 0) + err(1, "caph_enter_casper"); + + cap_rights_init(&rights, CAP_RECV, CAP_EVENT, CAP_SETSOCKOPT); + if (caph_rights_limit(srecv, &rights) < 0) + err(1, "cap_rights_limit srecv"); + cap_rights_init(&rights, CAP_SEND, CAP_SETSOCKOPT); + if (caph_rights_limit(ssend, &rights) < 0) + err(1, "cap_rights_limit ssend"); +#endif /* record route option */ if (options & F_RROUTE) { - if (IN_MULTICAST(ntohl(to->sin_addr.s_addr))) - err(1, "record route not valid to multicast destinations"); #ifdef IP_OPTIONS + bzero(rspace, sizeof(rspace)); rspace[IPOPT_OPTVAL] = IPOPT_RR; - rspace[IPOPT_OLEN] = sizeof(rspace)-1; + rspace[IPOPT_OLEN] = sizeof(rspace) - 1; rspace[IPOPT_OFFSET] = IPOPT_MINOFF; - if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace, - sizeof(rspace)) < 0) { - perror("ping: record route"); - exit(1); - } + rspace[sizeof(rspace) - 1] = IPOPT_EOL; + if (setsockopt(ssend, IPPROTO_IP, IP_OPTIONS, rspace, + sizeof(rspace)) < 0) + err(EX_OSERR, "setsockopt IP_OPTIONS"); #else - err(1, "record route not available in this implementation"); + errx(EX_UNAVAILABLE, + "record route not available in this implementation"); #endif /* IP_OPTIONS */ } - if ((moptions & MULTICAST_NOLOOP) && - setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, - sizeof(loop)) < 0) - err(1, "setsockopt IP_MULTICAST_LOOP"); - if ((moptions & MULTICAST_TTL) && - setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, - sizeof(ttl)) < 0) - err(1, "setsockopt IP_MULTICAST_TTL"); - if ((moptions & MULTICAST_IF) && - setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &saddr, - sizeof(saddr)) < 0) - err(1, "setsockopt IP_MULTICAST_IF"); + if (options & F_TTL) { + if (setsockopt(ssend, IPPROTO_IP, IP_TTL, &ttl, + sizeof(ttl)) < 0) { + err(EX_OSERR, "setsockopt IP_TTL"); + } + } + if (options & F_NOLOOP) { + if (setsockopt(ssend, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, + sizeof(loop)) < 0) { + err(EX_OSERR, "setsockopt IP_MULTICAST_LOOP"); + } + } + if (options & F_MTTL) { + if (setsockopt(ssend, IPPROTO_IP, IP_MULTICAST_TTL, &mttl, + sizeof(mttl)) < 0) { + err(EX_OSERR, "setsockopt IP_MULTICAST_TTL"); + } + } + if (options & F_MIF) { + if (setsockopt(ssend, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr, + sizeof(ifaddr)) < 0) { + err(EX_OSERR, "setsockopt IP_MULTICAST_IF"); + } + } +#ifdef 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) { + if (sweepmin > sweepmax) + errx(EX_USAGE, + "Maximum packet size must be no less than the minimum packet size"); + + if (sweepmax > maxpayload - TIMEVAL_LEN) + errx(EX_USAGE, "Invalid sweep maximum"); + + if (datalen != DEFDATALEN) + errx(EX_USAGE, + "Packet size and ping sweep are mutually exclusive"); + + if (npackets > 0) { + snpackets = npackets; + npackets = 0; + } else + snpackets = 1; + datalen = sweepmin; + send_len = icmp_len + sweepmin; + } + if (options & F_SWEEP && !sweepmax) + errx(EX_USAGE, "Maximum sweep size must be specified"); - /* - * When trying to send large packets, you must increase the - * size of both the send and receive buffers... - */ - maxsizelen = sizeof maxsize; - if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &maxsize, &maxsizelen) < 0) - err(1, "getsockopt"); - if (maxsize < packlen && - setsockopt(s, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(maxsize)) < 0) - err(1, "setsockopt"); /* * When pinging the broadcast address, you can get a lot of answers. * Doing something so evil is useful if you are trying to stress the * ethernet, or just want to fill the arp cache to get some stuff for - * /etc/ethers. + * /etc/ethers. But beware: RFC 1122 allows hosts to ignore broadcast + * or multicast pings if they wish. */ - while (setsockopt(s, SOL_SOCKET, SO_RCVBUF, - (void*)&bufspace, sizeof(bufspace)) < 0) { - if ((bufspace -= 1024) <= 0) - err(1, "Cannot set the receive buffer size"); - } - if (bufspace < DEFAULT_BUFSPACE) - printf("Could only allocate a receive buffer of %i bytes (default %i)\n", - bufspace, DEFAULT_BUFSPACE); - if (to->sin_family == AF_INET) - (void)printf("PING %s (%s): %d data bytes\n", hostname, - inet_ntoa(*(struct in_addr *)&to->sin_addr.s_addr), - datalen); - else - (void)printf("PING %s: %d data bytes\n", hostname, datalen); - - (void)signal(SIGINT, finish); - (void)signal(SIGALRM, catcher); -#ifdef SIGINFO - (void)signal(SIGINFO, prtsig); + /* + * XXX receive buffer needs undetermined space for mbuf overhead + * as well. + */ + hold = IP_MAXPACKET + 128; + (void)setsockopt(srecv, SOL_SOCKET, SO_RCVBUF, (char *)&hold, + sizeof(hold)); + /* CAP_SETSOCKOPT removed */ +#ifndef __HAIKU__ + cap_rights_init(&rights, CAP_RECV, CAP_EVENT); + if (caph_rights_limit(srecv, &rights) < 0) + err(1, "cap_rights_limit srecv setsockopt"); +#endif + if (uid == 0) + (void)setsockopt(ssend, SOL_SOCKET, SO_SNDBUF, (char *)&hold, + sizeof(hold)); + /* CAP_SETSOCKOPT removed */ +#ifndef __HAIKU__ + cap_rights_init(&rights, CAP_SEND); + if (caph_rights_limit(ssend, &rights) < 0) + err(1, "cap_rights_limit ssend setsockopt"); #endif - while (preload--) /* fire off them quickies */ - pinger(); + if (to->sin_family == AF_INET) { + (void)printf("PING %s (%s)", hostname, + inet_ntoa(to->sin_addr)); + if (source) + (void)printf(" from %s", shostname); + if (sweepmax) + (void)printf(": (%d ... %d) data bytes\n", + sweepmin, sweepmax); + else + (void)printf(": %d data bytes\n", datalen); - if ((options & F_FLOOD) == 0) - catcher(0); /* start things going */ + } else { + if (sweepmax) + (void)printf("PING %s: (%d ... %d) data bytes\n", + hostname, sweepmin, sweepmax); + else + (void)printf("PING %s: %d data bytes\n", hostname, datalen); + } - fdmasks = _howmany(s+1, NFDBITS) * sizeof(fd_mask); - if ((fdmaskp = (fd_set *)malloc(fdmasks)) == NULL) - err(1, "malloc"); + /* + * Use sigaction() instead of signal() to get unambiguous semantics, + * in particular with SA_RESTART not set. + */ - for (;;) { - struct sockaddr_in from; - int cc; - socklen_t fromlen; - sigset_t omask, nmask; + 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; +#ifndef __HAIKU__ + if (sigaction(SIGINFO, &si_sa, 0) == -1) + err(EX_OSERR, "sigaction SIGINFO"); + seeninfo = 0; +#endif + if (alarmtimeout > 0) { + if (sigaction(SIGALRM, &si_sa, 0) == -1) + err(EX_OSERR, "sigaction SIGALRM"); + } - if (options & F_FLOOD) { + bzero(&msg, sizeof(msg)); + msg.msg_name = (caddr_t)&from; + msg.msg_iov = &iov; + 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; + + if (preload == 0) + pinger(); /* send the first ping */ + else { + if (npackets != 0 && preload > npackets) + preload = npackets; + while (preload--) /* fire off them quickies */ pinger(); - timeout.tv_sec = 0; - timeout.tv_usec = 10000; - memset(fdmaskp, 0, fdmasks); - FD_SET(s, fdmaskp); - if (select(s + 1, (fd_set *)fdmaskp, (fd_set *)NULL, - (fd_set *)NULL, &timeout) < 1) - continue; - } - fromlen = sizeof(from); - if ((cc = recvfrom(s, (char *)packet, packlen, 0, - (struct sockaddr *)&from, &fromlen)) < 0) { - if (errno == EINTR) - continue; - perror("ping: recvfrom"); + } + (void)clock_gettime(CLOCK_MONOTONIC, &last); + + if (options & F_FLOOD) { + intvl.tv_sec = 0; + intvl.tv_nsec = 10000000; + } else { + intvl.tv_sec = interval / 1000; + intvl.tv_nsec = interval % 1000 * 1000000; + } + + almost_done = 0; + while (seenint == 0) { + struct timespec now, timeout; + fd_set rfds; + int n; + ssize_t cc; + + /* signal handling */ + if (seeninfo) { + pr_summary(stderr); + seeninfo = 0; continue; } - sigemptyset(&nmask); - sigaddset(&nmask, SIGALRM); - sigprocmask(SIG_BLOCK, &nmask, &omask); - pr_pack((char *)packet, cc, &from); - sigprocmask(SIG_SETMASK, &omask, NULL); - if (npackets && nreceived >= npackets) - break; + if ((unsigned)srecv >= FD_SETSIZE) + errx(EX_OSERR, "descriptor too large"); + FD_ZERO(&rfds); + FD_SET(srecv, &rfds); + (void)clock_gettime(CLOCK_MONOTONIC, &now); + timespecadd(&last, &intvl, &timeout); + timespecsub(&timeout, &now, &timeout); + if (timeout.tv_sec < 0) + timespecclear(&timeout); + + n = pselect(srecv + 1, &rfds, NULL, NULL, &timeout, NULL); + if (n < 0) + continue; /* EINTR */ + if (n == 1) { + struct timespec *tv = NULL; +#ifdef SO_TIMESTAMP + struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); +#endif + msg.msg_namelen = sizeof(from); + if ((cc = recvmsg(srecv, &msg, 0)) < 0) { + if (errno == EINTR) + continue; + warn("recvmsg"); + continue; + } + /* If we have a 0 byte read from recvfrom continue */ + if (cc == 0) + continue; +#ifdef SO_TIMESTAMP + 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: */ + memcpy(&now, CMSG_DATA(cmsg), sizeof(now)); + tv = &now; + } +#endif + if (tv == NULL) { + (void)clock_gettime(CLOCK_MONOTONIC, &now); + tv = &now; + } + pr_pack((char *)packet, cc, &from, tv); + if ((options & F_ONCE && nreceived) || + (npackets && nreceived >= npackets)) + break; + } + if (n == 0 || (options & F_FLOOD)) { + if (sweepmax && sntransmitted == snpackets) { + if (datalen + sweepincr > sweepmax) + break; + for (i = 0; i < sweepincr; i++) + *datap++ = i; + datalen += sweepincr; + send_len = icmp_len + datalen; + sntransmitted = 0; + } + if (!npackets || ntransmitted < npackets) + pinger(); + else { + if (almost_done) + break; + almost_done = 1; + /* + * If we're not transmitting any more packets, + * change the timer to wait two round-trip times + * if we've received any packets or (waittime) + * milliseconds if we haven't. + */ + intvl.tv_nsec = 0; + if (nreceived) { + intvl.tv_sec = 2 * tmax / 1000; + if (intvl.tv_sec == 0) + intvl.tv_sec = 1; + } else { + intvl.tv_sec = waittime / 1000; + intvl.tv_nsec = + waittime % 1000 * 1000000; + } + } + (void)clock_gettime(CLOCK_MONOTONIC, &last); + if (ntransmitted - nreceived - 1 > nmissedmax) { + nmissedmax = ntransmitted - nreceived - 1; + if (options & F_MISSED) + (void)write(STDOUT_FILENO, &BBELL, 1); + } + } } - free(fdmaskp); - finish(0); - /* NOTREACHED */ - exit(0); /* Make the compiler happy */ -} + pr_summary(stdout); -/* - * catcher -- - * This routine causes another PING to be transmitted, and then - * schedules another SIGALRM for 1 second from now. - * - * bug -- - * Our sense of time will slowly skew (i.e., packets will not be - * launched exactly at 1-second intervals). This does not affect the - * quality of the delay and loss statistics. - */ -void catcher(int sig) -{ - int waittime; - int save_errno = errno; - - pinger(); - (void)signal(SIGALRM, catcher); - - if (!npackets || ntransmitted < npackets) - (void)alarm((uint)interval); - else { - if (nreceived) { - waittime = 2 * tmax / 1000000; - if (!waittime) - waittime = 1; - } else - waittime = maxwait; - (void)signal(SIGALRM, finish); - (void)alarm((uint)waittime); - } - errno = save_errno; -} - -/* - * Print statistics when SIGINFO is received. - * XXX not race safe - */ -void prtsig(int sig) -{ - int save_errno = errno; - - summary(0); - errno = save_errno; + exit(nreceived ? 0 : 2); } /* * 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, - * and the sequence number is an ascending integer. The first 8 bytes - * of the data portion are used to hold a UNIX "timeval" struct in VAX - * byte-order, to compute the round-trip time. + * and the sequence number is an ascending integer. The first TIMEVAL_LEN + * bytes of the data portion are used to hold a UNIX "timespec" struct in + * host byte-order, to compute the round-trip time. */ -void pinger(void) +static void +pinger(void) { - struct icmp *icp; - int cc; - int i; - char *packet = outpack; + struct timespec now; + struct tv32 tv32; + struct icmp icp; + int cc, i; + u_char *packet; - icp = (struct icmp *)outpack; - icp->icmp_type = ICMP_ECHO; - icp->icmp_code = 0; - icp->icmp_cksum = 0; - icp->icmp_seq = htons(ntransmitted++); - icp->icmp_id = ident; /* ID */ + packet = outpack; + 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(ntohs(icp->icmp_seq) % mx_dup_ck); + CLR(ntransmitted % mx_dup_ck); - if (timing) { - bigtime_t tm = real_time_clock_usecs(); - memcpy(&outpack[8], &tm, sizeof(tm)); + if ((options & F_TIME) || timing) { + (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_nsec / 1000000); + if (timing) + bcopy((void *)&tv32, + (void *)&outpack[ICMP_MINLEN + phdr_len], + sizeof(tv32)); } - cc = datalen + 8; /* skips ICMP portion */ + memcpy(outpack, &icp, ICMP_MINLEN + phdr_len); + + cc = ICMP_MINLEN + phdr_len + datalen; /* compute ICMP checksum here */ - icp->icmp_cksum = compute_in_cksum((u_short *)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 = (struct ip*)outpackhdr; + struct ip ip; - packet = (char*)ip; cc += sizeof(struct ip); - ip->ip_len = htons(cc); - ip->ip_sum = compute_in_cksum((u_short *)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 = sendto(s, (char *)packet, cc, 0, &whereto, - sizeof(struct sockaddr)); - +#ifndef __HAIKU__ + i = send(ssend, (char *)packet, cc, 0); +#else + i = sendto(ssend, (char *)packet, cc, 0, &whereto, + sizeof(struct sockaddr)); +#endif if (i < 0 || i != cc) { - if (i < 0) - perror("ping: sendto"); - (void)printf("ping: wrote %s %d chars, ret=%d\n", - hostname, cc, i); + if (i < 0) { + if (options & F_FLOOD && errno == ENOBUFS) { + usleep(FLOOD_BACKOFF); + return; + } + warn("sendto"); + } else { + warn("%s: partial write: %d of %d bytes", + hostname, i, cc); + } } - if (!(options & F_QUIET) && options & F_FLOOD) - (void)write(STDOUT_FILENO, &DOT, 1); + ntransmitted++; + sntransmitted++; + if (!(options & F_QUIET) && options & F_DOT) + (void)write(STDOUT_FILENO, &DOT[DOTidx++ % DOTlen], 1); } /* @@ -626,112 +1133,242 @@ void pinger(void) * which arrive ('tis only fair). This permits multiple copies of this * program to be run without having intermingled output (or statistics!). */ -void pr_pack(char *buf, int cc, struct sockaddr_in *from) +static void +pr_pack(char *buf, ssize_t cc, struct sockaddr_in *from, struct timespec *tv) { - struct icmp *icp; - in_addr_t l; - u_int i, j; - u_char *cp, *dp; + struct in_addr ina; + u_char *cp, *dp, l; + struct icmp icp; + struct ip ip; + const u_char *icmp_data_raw; + ssize_t icmp_data_raw_len; + double triptime; + int dupflag, i, j, recv_len; + int8_t hlen; + uint16_t seq; static int old_rrlen; static char old_rr[MAX_IPOPTLEN]; - struct ip *ip, *ip2; -// struct timeval tv, tp; - char *pkttime; - uint64 triptime = 0; - int hlen, hlen2, dupflag; + struct ip oip; + u_char oip_header_len; + struct icmp oicmp; + const u_char *oicmp_raw; -// (void)gettimeofday(&tv, (struct timezone *)NULL); + /* + * Get size of IP header of the received packet. + * The header length is contained in the lower four bits of the first + * byte and represents the number of 4 byte octets the header takes up. + * + * The IHL minimum value is 5 (20 bytes) and its maximum value is 15 + * (60 bytes). + */ + memcpy(&l, buf, sizeof(l)); + hlen = (l & 0x0f) << 2; - /* Check the IP header */ - ip = (struct ip *)buf; - hlen = ip->ip_hl << 2; - if (cc < hlen + ICMP_MINLEN) { + /* Reject IP packets with a short header */ + if (hlen < (int8_t) sizeof(struct ip)) { if (options & F_VERBOSE) - printf("packet too short (%d bytes) from %s\n", cc, - inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr)); + warn("IHL too short (%d bytes) from %s", hlen, + inet_ntoa(from->sin_addr)); return; } + memcpy(&ip, buf, sizeof(struct ip)); + + /* Check packet has enough data to carry a valid ICMP header */ + recv_len = cc; + if (cc < hlen + ICMP_MINLEN) { + if (options & F_VERBOSE) + warn("packet too short (%zd bytes) from %s", cc, + inet_ntoa(from->sin_addr)); + return; + } + + icmp_data_raw_len = cc - (hlen + offsetof(struct icmp, icmp_data)); + icmp_data_raw = buf + hlen + offsetof(struct icmp, icmp_data); + /* Now the ICMP part */ cc -= hlen; - icp = (struct icmp *)(buf + hlen); - if (icp->icmp_type == ICMP_ECHOREPLY) { - 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) { - bigtime_t tvi; + struct timespec tv1; + struct tv32 tv32; + const u_char *tp; -#ifndef icmp_data - pkttime = (char *)&icp->icmp_ip; -#else - pkttime = (char *)icp->icmp_data; -#endif - memcpy(&tvi, pkttime, sizeof tvi); - triptime = real_time_clock_usecs() - tvi; - tsum += triptime; - tsumsq += triptime * triptime; - if (triptime < tmin) - tmin = triptime; - if (triptime > tmax) - tmax = triptime; + tp = icmp_data_raw + phdr_len; + + if ((size_t)(cc - ICMP_MINLEN - phdr_len) >= + sizeof(tv1)) { + /* Copy to avoid alignment problems: */ + memcpy(&tv32, tp, sizeof(tv32)); + tv1.tv_sec = ntohl(tv32.tv32_sec); + tv1.tv_nsec = ntohl(tv32.tv32_nsec); + timespecsub(tv, &tv1, tv); + triptime = ((double)tv->tv_sec) * 1000.0 + + ((double)tv->tv_nsec) / 1000000.0; + if (triptime < 0) { + warnx("time of day goes back (%.3f ms)," + " clamping time to 0", + triptime); + triptime = 0; + } + tsum += triptime; + tsumsq += triptime * triptime; + if (triptime < tmin) + tmin = triptime; + if (triptime > tmax) + tmax = triptime; + } else + timing = 0; } - if (TST(ntohs(icp->icmp_seq) % mx_dup_ck)) { + seq = ntohs(icp.icmp_seq); + + if (TST(seq % mx_dup_ck)) { ++nrepeats; --nreceived; dupflag = 1; } else { - SET(ntohs(icp->icmp_seq) % mx_dup_ck); + SET(seq % mx_dup_ck); dupflag = 0; } if (options & F_QUIET) return; - if (options & F_FLOOD) + if (options & F_WAITTIME && triptime > waittime) { + ++nrcvtimeout; + return; + } + + if (options & F_DOT) (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), - ntohs(icp->icmp_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=%d.%03d ms", - (int)(triptime / 1000), - (int)(triptime % 1000)); + (void)printf(" time=%.3f ms", triptime); if (dupflag) (void)printf(" (DUP!)"); + if (options & F_AUDIBLE) + (void)write(STDOUT_FILENO, &BBELL, 1); + if (options & F_MASK) { + /* Just prentend this cast isn't ugly */ + (void)printf(" mask=%s", + 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)); + } + if (recv_len != send_len) { + (void)printf( + "\nwrong total length %d instead of %d", + recv_len, send_len); + } /* check the data */ - cp = (u_char*)&icp->icmp_data[sizeof(bigtime_t)]; - dp = &outpack[8 + sizeof(bigtime_t)]; - for (i = 8 + sizeof(bigtime_t); (int) i < datalen; - ++i, ++cp, ++dp) { + 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; + if (timing) { /* don't check variable timestamp */ + cp += TIMEVAL_LEN; + dp += TIMEVAL_LEN; + cc -= TIMEVAL_LEN; + i += TIMEVAL_LEN; + } + for (; i < datalen && cc > 0; ++i, ++cp, ++dp, --cc) { if (*cp != *dp) { (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", i, *dp, *cp); - cp = (u_char*)&icp->icmp_data[0]; - for (i = 8; (int) i < datalen; ++i, ++cp) { - if ((i % 32) == 8) + (void)printf("\ncp:"); + 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"); - (void)printf("%x ", *cp); + (void)printf(" %2x", *cp); + } + (void)printf("\ndp:"); + cp = &outpack[ICMP_MINLEN]; + for (i = 0; i < datalen; ++i, ++cp) { + if ((i % 16) == 8) + (void)printf("\n\t"); + (void)printf(" %2x", *cp); } break; } } } } else { - /* We've got something other than an ECHOREPLY */ - if (!(options & F_VERBOSE)) + /* + * We've got something other than an ECHOREPLY. + * See if it's a reply to something that we sent. + * We can compare IP destination, protocol, + * and ICMP type and ID. + * + * Only print all the error messages if we are running + * as root to avoid leaking information not normally + * available to those not running as root. + */ + + /* + * If we don't have enough bytes for a quoted IP header and an + * ICMP header then stop. + */ + if (icmp_data_raw_len < + (ssize_t)(sizeof(struct ip) + sizeof(struct icmp))) { + if (options & F_VERBOSE) + warnx("quoted data too short (%zd bytes) from %s", + icmp_data_raw_len, inet_ntoa(from->sin_addr)); return; - ip2 = (struct ip *) (buf + hlen + sizeof (struct icmp)); - hlen2 = ip2->ip_hl << 2; - if (cc >= hlen2 + 8 && check_icmph((struct ip *)(icp + - sizeof (struct icmp))) != 1) + } + + memcpy(&oip_header_len, icmp_data_raw, sizeof(oip_header_len)); + oip_header_len = (oip_header_len & 0x0f) << 2; + + /* Reject IP packets with a short header */ + if (oip_header_len < sizeof(struct ip)) { + if (options & F_VERBOSE) + warnx("inner IHL too short (%d bytes) from %s", + oip_header_len, inet_ntoa(from->sin_addr)); return; - (void)printf("%d bytes from %s: ", cc, - pr_addr(from->sin_addr.s_addr)); - pr_icmph(icp); + } + + /* + * Check against the actual IHL length, to protect against + * quoated packets carrying IP options. + */ + if (icmp_data_raw_len < + (ssize_t)(oip_header_len + sizeof(struct icmp))) { + if (options & F_VERBOSE) + warnx("inner packet too short (%zd bytes) from %s", + icmp_data_raw_len, inet_ntoa(from->sin_addr)); + return; + } + + memcpy(&oip, icmp_data_raw, sizeof(struct ip)); + oicmp_raw = icmp_data_raw + oip_header_len; + memcpy(&oicmp, oicmp_raw, sizeof(struct icmp)); + + 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("%zd bytes from %s: ", cc, + pr_addr(from->sin_addr)); + pr_icmph(&icp, &oip, icmp_data_raw); + } else + return; } /* Display any IP options */ @@ -743,223 +1380,94 @@ void pr_pack(char *buf, int cc, struct sockaddr_in *from) hlen = 0; break; case IPOPT_LSRR: - (void)printf("\nLSRR: "); + case IPOPT_SSRR: + (void)printf(*cp == IPOPT_LSRR ? + "\nLSRR: " : "\nSSRR: "); + j = cp[IPOPT_OLEN] - IPOPT_MINOFF + 1; hlen -= 2; - j = *++cp; - ++cp; - i = 0; - if (j > IPOPT_MINOFF) { + cp += 2; + if (j >= INADDR_LEN && + j <= hlen - (int)sizeof(struct ip)) { for (;;) { - l = *++cp; - l = (l<<8) + *++cp; - l = (l<<8) + *++cp; - l = (l<<8) + *++cp; - if (l == 0) + bcopy(++cp, &ina.s_addr, INADDR_LEN); + if (ina.s_addr == 0) (void)printf("\t0.0.0.0"); else (void)printf("\t%s", - pr_addr(ntohl(l))); - hlen -= 4; - j -= 4; - i += 4; - if (j <= IPOPT_MINOFF) + pr_addr(ina)); + hlen -= INADDR_LEN; + cp += INADDR_LEN - 1; + j -= INADDR_LEN; + if (j < INADDR_LEN) break; - if (i >= MAX_IPOPTLEN) { - (void)printf("\t(truncated route)"); - break; - } (void)putchar('\n'); } - } + } else + (void)printf("\t(truncated route)"); break; case IPOPT_RR: - j = *++cp; /* get length */ - i = *++cp; /* and pointer */ + j = cp[IPOPT_OLEN]; /* get length */ + i = cp[IPOPT_OFFSET]; /* and pointer */ hlen -= 2; + cp += 2; if (i > j) i = j; - i -= IPOPT_MINOFF; - if (i <= 0) + i = i - IPOPT_MINOFF + 1; + if (i < 0 || i > (hlen - (int)sizeof(struct ip))) { + old_rrlen = 0; continue; - if ((int) i == old_rrlen - && cp == (u_char *) buf + sizeof(struct ip) + 2 - && !memcmp(cp, old_rr, i) - && !(options & F_FLOOD)) { + } + if (i == old_rrlen + && !bcmp((char *)cp, old_rr, i) + && !(options & F_DOT)) { (void)printf("\t(same route)"); - i = ((i + 3) / 4) * 4; hlen -= i; cp += i; break; } - if (i < MAX_IPOPTLEN) { - old_rrlen = i; - memcpy(old_rr, cp, i); - } else - old_rrlen = 0; - + old_rrlen = i; + bcopy((char *)cp, old_rr, i); (void)printf("\nRR: "); - j = 0; - for (;;) { - l = *++cp; - l = (l<<8) + *++cp; - l = (l<<8) + *++cp; - l = (l<<8) + *++cp; - if (l == 0) - (void)printf("\t0.0.0.0"); - else - (void)printf("\t%s", pr_addr(ntohl(l))); - hlen -= 4; - i -= 4; - j += 4; - if (i <= 0) - break; - if (j >= MAX_IPOPTLEN) { - (void)printf("\t(truncated route)"); - break; + if (i >= INADDR_LEN && + i <= hlen - (int)sizeof(struct ip)) { + for (;;) { + bcopy(++cp, &ina.s_addr, INADDR_LEN); + if (ina.s_addr == 0) + (void)printf("\t0.0.0.0"); + else + (void)printf("\t%s", + pr_addr(ina)); + hlen -= INADDR_LEN; + cp += INADDR_LEN - 1; + i -= INADDR_LEN; + if (i < INADDR_LEN) + break; + (void)putchar('\n'); } - (void)putchar('\n'); - } + } else + (void)printf("\t(truncated route)"); break; case IPOPT_NOP: (void)printf("\nNOP"); break; default: (void)printf("\nunknown option %x", *cp); - hlen = hlen + cp[1] - 1; - cp = cp + cp[1] - 1; break; } - if (!(options & F_FLOOD)) { + if (!(options & F_DOT)) { (void)putchar('\n'); (void)fflush(stdout); } } -/* - * compute_in_cksum -- - * Checksum routine for Internet Protocol family headers (C Version) - */ -int -compute_in_cksum(addr, len) - u_short *addr; - int len; -{ - int nleft = len; - u_short *w = addr; - int sum = 0; - u_short answer = 0; - - /* - * 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) { - *(u_char *)(&answer) = *(u_char *)w ; - sum += answer; - } - - /* 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); -} - -void summary(int header) -{ - (void)putchar('\r'); - (void)fflush(stdout); - - if (header) - (void)printf("--- %s ping statistics ---\n", hostname); - - (void)printf("%ld packets transmitted, ", ntransmitted); - (void)printf("%ld packets received, ", nreceived); - if (nrepeats) - (void)printf("%ld duplicates, ", nrepeats); - if (ntransmitted) { - if (nreceived > ntransmitted) - (void)printf("-- somebody's printing up packets!"); - else - (void)printf("%d%% packet loss", - (int) (((ntransmitted - nreceived) * 100) / - ntransmitted)); - } - (void)putchar('\n'); - if (nreceived && timing) { - uint64 num = nreceived + nrepeats; - uint64 avg = tsum / num; - uint64 dev = qsqrt(tsumsq / num - avg * avg); - (void)printf("round-trip min/avg/max/std-dev = " - "%d.%03d/%d.%03d/%d.%03d/%d.%03d ms\n", - (int)(tmin / 1000), (int)(tmin % 1000), - (int)(avg / 1000), (int)(avg % 1000), - (int)(tmax / 1000), (int)(tmax % 1000), - (int)(dev / 1000), (int)(dev % 1000)); - } -} - -uint64 qsqrt(uint64 qdev) -{ - int64 y, x = 1; - - if (!qdev) - return(0); - - do { /* newton was a stinker */ - y = x; - x = qdev / x; - x += y; - x /= 2; - } while ((x - y) > 1 || (x - y) < -1); - - return (uint64) x; -} - -/* - * finish -- - * Print out statistics, and give up. - */ -void finish(int sig) -{ - (void)signal(SIGINT, SIG_IGN); - (void)signal(SIGALRM, SIG_IGN); - - summary(1); - exit(nreceived ? 0 : 1); -} - -#ifdef notdef -static char *ttab[] = { - "Echo Reply", /* ip + seq + udata */ - "Dest Unreachable", /* net, host, proto, port, frag, sr + IP */ - "Source Quench", /* IP */ - "Redirect", /* redirect type, gateway, + IP */ - "Echo", - "Time Exceeded", /* transit, frag reassem + IP */ - "Parameter Problem", /* pointer + IP */ - "Timestamp", /* id + seq + three timestamps */ - "Timestamp Reply", /* " */ - "Info Request", /* id + sq */ - "Info Reply" /* " */ -}; -#endif - /* * pr_icmph -- * Print a descriptive string about an ICMP header. */ -void -pr_icmph(icp) - struct icmp *icp; +static void +pr_icmph(struct icmp *icp, struct ip *oip, const u_char *const oicmp_raw) { + switch(icp->icmp_type) { case ICMP_ECHOREPLY: (void)printf("Echo Reply\n"); @@ -980,64 +1488,26 @@ pr_icmph(icp) (void)printf("Destination Port Unreachable\n"); break; case ICMP_UNREACH_NEEDFRAG: - if (icp->icmp_nextmtu != 0) - (void)printf("frag needed and DF set (MTU %d)\n", + (void)printf("frag needed and DF set (MTU %d)\n", ntohs(icp->icmp_nextmtu)); - else - (void)printf("frag needed and DF set\n"); break; case ICMP_UNREACH_SRCFAIL: (void)printf("Source Route Failed\n"); break; - case ICMP_UNREACH_NET_UNKNOWN: - (void)printf("Network Unknown\n"); - break; - case ICMP_UNREACH_HOST_UNKNOWN: - (void)printf("Host Unknown\n"); - break; - case ICMP_UNREACH_ISOLATED: - (void)printf("Source Isolated\n"); - break; - case ICMP_UNREACH_NET_PROHIB: - (void)printf("Dest. Net Administratively Prohibited\n"); - break; - case ICMP_UNREACH_HOST_PROHIB: - (void)printf("Dest. Host Administratively Prohibited\n"); - break; - case ICMP_UNREACH_TOSNET: - (void)printf("Destination Net Unreachable for TOS\n"); - break; - case ICMP_UNREACH_TOSHOST: - (void)printf("Desination Host Unreachable for TOS\n"); - break; case ICMP_UNREACH_FILTER_PROHIB: - (void)printf("Route administratively prohibited\n"); - break; - case ICMP_UNREACH_HOST_PRECEDENCE: - (void)printf("Host Precedence Violation\n"); - break; - case ICMP_UNREACH_PRECEDENCE_CUTOFF: - (void)printf("Precedence Cutoff\n"); + (void)printf("Communication prohibited by filter\n"); break; default: - (void)printf("Dest Unreachable, Unknown Code: %d\n", + (void)printf("Dest Unreachable, Bad Code: %d\n", icp->icmp_code); break; } /* Print returned IP header information */ -#ifndef icmp_data - pr_retip(&icp->icmp_ip); -#else - pr_retip((struct ip *)icp->icmp_data); -#endif + pr_iph(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_iph(oip, oicmp_raw); break; case ICMP_REDIRECT: switch(icp->icmp_code) { @@ -1054,34 +1524,16 @@ pr_icmph(icp) (void)printf("Redirect Type of Service and Host"); break; default: - (void)printf("Redirect, Unknown Code: %d", icp->icmp_code); + (void)printf("Redirect, Bad Code: %d", icp->icmp_code); 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 + (void)printf("(New addr: %s)\n", inet_ntoa(icp->icmp_gwaddr)); + pr_iph(oip, oicmp_raw); break; case ICMP_ECHO: (void)printf("Echo Request\n"); /* XXX ID + Seq + Data */ break; -// case ICMP_ROUTERADVERT: - /* RFC1256 */ -/* - (void)printf("Router Discovery Advertisement\n"); - (void)printf("(%d entries, lifetime %d seconds)\n", - icp->icmp_num_addrs, ntohs(icp->icmp_lifetime)); - break; -*/ -// case ICMP_ROUTERSOLICIT: - /* RFC1256 */ -/* (void)printf("Router Discovery Solicitation\n"); - break; -*/ case ICMP_TIMXCEED: switch(icp->icmp_code) { case ICMP_TIMXCEED_INTRANS: @@ -1091,33 +1543,16 @@ pr_icmph(icp) (void)printf("Frag reassembly time exceeded\n"); break; default: - (void)printf("Time exceeded, Unknown Code: %d\n", + (void)printf("Time exceeded, Bad Code: %d\n", icp->icmp_code); break; } -#ifndef icmp_data - pr_retip(&icp->icmp_ip); -#else - pr_retip((struct ip *)icp->icmp_data); -#endif + pr_iph(oip, oicmp_raw); break; case ICMP_PARAMPROB: - switch(icp->icmp_code) { - case ICMP_PARAMPROB_OPTABSENT: - (void)printf( - "Parameter problem, required option absent: pointer = 0x%02x\n", - ntohs(icp->icmp_hun.ih_pptr)); - break; - default: - (void)printf("Parameter problem: pointer = 0x%02x\n", - ntohs(icp->icmp_hun.ih_pptr)); - break; - } -#ifndef icmp_data - pr_retip(&icp->icmp_ip); -#else - pr_retip((struct ip *)icp->icmp_data); -#endif + (void)printf("Parameter problem: pointer = 0x%02x\n", + icp->icmp_hun.ih_pptr); + pr_iph(oip, oicmp_raw); break; case ICMP_TSTAMP: (void)printf("Timestamp\n"); @@ -1135,19 +1570,20 @@ pr_icmph(icp) (void)printf("Information Reply\n"); /* XXX ID + Seq */ break; -#ifdef ICMP_MASKREQ case ICMP_MASKREQ: (void)printf("Address Mask Request\n"); break; -#endif -#ifdef ICMP_MASKREPLY case ICMP_MASKREPLY: - (void)printf("Address Mask Reply (Mask 0x%08ld)\n", - (long)ntohl(icp->icmp_mask)); + (void)printf("Address Mask Reply\n"); + break; + case ICMP_ROUTERADVERT: + (void)printf("Router Advertisement\n"); + break; + case ICMP_ROUTERSOLICIT: + (void)printf("Router Solicitation\n"); break; -#endif default: - (void)printf("Unknown ICMP type: %u\n", icp->icmp_type); + (void)printf("Bad ICMP type: %d\n", icp->icmp_type); } } @@ -1155,25 +1591,40 @@ pr_icmph(icp) * pr_iph -- * Print an IP header with options. */ -void pr_iph(struct ip *ip) +static void +pr_iph(struct ip *ip, const u_char *cp) { + struct in_addr dst_ina, src_ina; int hlen; - u_char *cp; hlen = ip->ip_hl << 2; - cp = (u_char *)ip + 20; /* point to options */ + cp = cp + sizeof(struct ip); /* point to options */ - (void)printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst Data\n"); + memcpy(&src_ina, &ip->ip_src.s_addr, sizeof(src_ina)); + memcpy(&dst_ina, &ip->ip_dst.s_addr, sizeof(dst_ina)); + + (void)printf("Vr HL TOS Len ID Flg off TTL Pro cks %*s %*s", + (int)strlen(inet_ntoa(src_ina)), "Src", + (int)strlen(inet_ntoa(dst_ina)), "Dst"); + if (hlen > (int)sizeof(struct ip)) + (void)printf(" Opts"); + (void)putchar('\n'); (void)printf(" %1x %1x %02x %04x %04x", - ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id); - (void)printf(" %1x %04x", ((ip->ip_off) & 0xe000) >> 13, - (ip->ip_off) & 0x1fff); - (void)printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum); - (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr)); - (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr)); - /* dump and option bytes */ - while (hlen-- > 20) { - (void)printf("%02x", *cp++); + ip->ip_v, ip->ip_hl, ip->ip_tos, ntohs(ip->ip_len), + ntohs(ip->ip_id)); + (void)printf(" %1x %04x", + (ntohs(ip->ip_off) & 0xe000) >> 13, + ntohs(ip->ip_off) & 0x1fff); + (void)printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p, + ntohs(ip->ip_sum)); + (void)printf(" %s", inet_ntoa(src_ina)); + (void)printf(" %s", inet_ntoa(dst_ina)); + /* dump any option bytes */ + if (hlen > (int)sizeof(struct ip)) { + (void)printf(" "); + while (hlen-- > (int)sizeof(struct ip)) { + (void)printf("%02x", *cp++); + } } (void)putchar('\n'); } @@ -1183,56 +1634,57 @@ void pr_iph(struct ip *ip) * Return an ascii host address as a dotted quad and optionally with * a hostname. */ -char * -pr_addr(a) - in_addr_t a; +static char * +pr_addr(struct in_addr ina) { struct hostent *hp; - struct in_addr in; - static char buf[16+3+MAXHOSTNAMELEN]; + static char buf[16 + 3 + MAXHOSTNAMELEN]; - in.s_addr = a; - if ((options & F_NUMERIC) || - !(hp = gethostbyaddr((char *)&in.s_addr, sizeof(in.s_addr), AF_INET))) - (void)snprintf(buf, sizeof buf, "%s", inet_ntoa(in)); - else - (void)snprintf(buf, sizeof buf, "%s (%s)", hp->h_name, - inet_ntoa(in)); + if (!(options & F_HOSTNAME)) + return inet_ntoa(ina); + +#ifdef __HAIKU__ +#define cap_gethostbyaddr(w, x, y, z) gethostbyaddr(x, y, z) +#endif + hp = cap_gethostbyaddr(capdns, (char *)&ina, sizeof(ina), AF_INET); + + if (hp == NULL) + return inet_ntoa(ina); + + (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name, + inet_ntoa(ina)); return(buf); } -/* - * pr_retip -- - * Dump some info on a returned (via ICMP) IP packet. - */ -void pr_retip(struct ip *ip) +static char * +pr_ntime(n_time timestamp) { - int hlen; - u_char *cp; + static char buf[11]; + int hour, min, sec; - pr_iph(ip); - hlen = ip->ip_hl << 2; - cp = (u_char *)ip + hlen; + sec = ntohl(timestamp) / 1000; + hour = sec / 60 / 60; + min = (sec % (60 * 60)) / 60; + sec = (sec % (60 * 60)) % 60; - if (ip->ip_p == 6) - (void)printf("TCP: from port %u, to port %u (decimal)\n", - (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); - else if (ip->ip_p == 17) - (void)printf("UDP: from port %u, to port %u (decimal)\n", - (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); + (void)snprintf(buf, sizeof(buf), "%02d:%02d:%02d", hour, min, sec); + + return (buf); } -void -fill(bp, patp) - char *bp, *patp; +static void +fill(char *bp, char *patp) { - int ii, jj, kk; - int pat[16]; char *cp; + int pat[16]; + u_int ii, jj, kk; - for (cp = patp; *cp; cp++) + for (cp = patp; *cp; cp++) { if (!isxdigit(*cp)) - err(1, "patterns must be specified as hex digits"); + errx(EX_USAGE, + "patterns must be specified as hex digits"); + + } ii = sscanf(patp, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6], @@ -1240,9 +1692,7 @@ fill(bp, patp) &pat[13], &pat[14], &pat[15]); if (ii > 0) - for (kk = 0; - kk <= (int) (MAXPAYLOAD - (8 + sizeof(uint64) + ii)); - kk += ii) + for (kk = 0; kk <= maxpayload - (TIMEVAL_LEN + ii); kk += ii) for (jj = 0; jj < ii; ++jj) bp[jj + kk] = pat[jj]; if (!(options & F_QUIET)) { @@ -1253,46 +1703,32 @@ fill(bp, patp) } } -/* - * when we get types of ICMP message with parts of the orig. datagram - * we want to try to assure ourselves that it is from this instance - * of ping, and not say, a refused finger connection or something - */ -int -check_icmph(iph) - struct ip *iph; +#ifndef __HAIKU__ +static cap_channel_t * +capdns_setup(void) { - struct icmp *icmph; - - /* only allow IP version 4 */ - if (iph->ip_v != 4) - return 0; - - /* Only allow ICMP */ - if (iph->ip_p != IPPROTO_ICMP) - return 0; - - icmph = (struct icmp *) (iph + (4 * iph->ip_hl)); - - /* make sure it is in response to an ECHO request */ - if (icmph->icmp_type != 8) - return 0; - - /* ok, make sure it has the right id on it */ - if (icmph->icmp_hun.ih_idseq.icd_id != ident) - return 0; - - return 1; -} - -void -usage() -{ - extern const char *__progname; - - (void)fprintf(stderr, - "usage: %s [-DdfLnqRrv] [-c count] [-I ifaddr] [-i wait]\n" - "\t[-l preload] [-p pattern] [-s packetsize] [-t ttl]" - " [-w maxwait] host\n", __progname); - exit(1); + 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"); + capdnsloc = cap_service_open(capcas, "system.dns"); + /* Casper capability no longer needed. */ + 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) + err(1, "unable to limit access to system.dns service"); + 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); } +#endif diff --git a/src/bin/network/ping/ping.h b/src/bin/network/ping/ping.h new file mode 100644 index 0000000000..34a15a2da5 --- /dev/null +++ b/src/bin/network/ping/ping.h @@ -0,0 +1,34 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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. + */ + +#ifndef PING_H +#define PING_H 1 + +int ping(int argc, char *const *argv); + +#endif diff --git a/src/bin/network/ping6/ping6.c b/src/bin/network/ping/ping6.c similarity index 66% rename from src/bin/network/ping6/ping6.c rename to src/bin/network/ping/ping6.c index 520047bfa8..05da79bd34 100644 --- a/src/bin/network/ping6/ping6.c +++ b/src/bin/network/ping/ping6.c @@ -1,4 +1,8 @@ -/* +/* $KAME: ping6.c,v 1.169 2003/07/25 06:01:47 itojun Exp $ */ + +/*- + * SPDX-License-Identifier: BSD-3-Clause + * * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * @@ -27,6 +31,8 @@ * SUCH DAMAGE. */ +/* BSDI ping.c,v 2.3 1996/01/21 17:56:50 jch Exp */ + /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. @@ -42,11 +48,7 @@ * 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. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 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. * @@ -78,7 +80,6 @@ * More statistics could always be gathered. * This program has to run SUID to ROOT to access the ICMP socket. */ - /* * NOTE: * USE_SIN6_SCOPE_ID assumes that sin6_scope_id has the same semantics @@ -86,18 +87,13 @@ * while IPV6_PKTINFO specifies *interface*. Link is defined as collection of * network attached to 1 or more interfaces) */ -#define USE_SIN6_SCOPE_ID 1 - -#define USE_RFC2292BIS 1 -#define HAVE_POLL_H 1 -#define CMSG_SENDING_UNSUPPORTED 1 -#undef IPSEC -#undef IPV6_OPTIONS #include +#ifndef __HAIKU__ +#include +#endif #include #include -#include #include #include @@ -109,42 +105,55 @@ #include #include +#ifndef __HAIKU__ +#include +#include +#include +#endif + #include #include #include #include -#include #include #include #include #include +#include +#include #include -#ifdef HAVE_POLL_H -#include -#endif #ifdef IPSEC #include #include #endif +#ifndef __HAIKU__ +#include +#endif + +#include "main.h" +#include "ping6.h" + struct tv32 { u_int32_t tv32_sec; - u_int32_t tv32_usec; + u_int32_t tv32_nsec; }; -#define IP6LEN 40 -#define MAXPACKETLEN (IPV6_MAXPACKET - IP6LEN) +#define MAXPACKETLEN 131072 +#define IP6LEN 40 #define ICMP6ECHOLEN 8 /* icmp echo header len excluding time */ -#define ICMP6ECHOTMLEN sizeof(struct tv32) +#define ICMP6ECHOTMLEN sizeof(struct tv32) #define ICMP6_NIQLEN (ICMP6ECHOLEN + 8) -# define CONTROLLEN 10240 /* ancillary data buffer size RFC3542 20.1 */ +# define CONTROLLEN 10240 /* ancillary data buffer size RFC3542 20.1 */ /* FQDN case, 64 bits of nonce + 32 bits ttl */ #define ICMP6_NIRLEN (ICMP6ECHOLEN + 12) #define EXTRA 256 /* for AH and various other headers. weird. */ #define DEFDATALEN ICMP6ECHOTMLEN #define MAXDATALEN MAXPACKETLEN - IP6LEN - ICMP6ECHOLEN #define NROUTES 9 /* number of record route slots */ +#define MAXWAIT 10000 /* max ms to wait for response */ +#define MAXALARM (60 * 60) /* max seconds for alarm timeout */ #define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ #define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ @@ -171,7 +180,6 @@ struct tv32 { #define F_FQDN 0x1000 #define F_INTERFACE 0x2000 #define F_SRCADDR 0x4000 -#define F_HOSTNAME 0x10000 #define F_FQDNOLD 0x20000 #define F_NIGROUP 0x40000 #define F_SUPTYPES 0x80000 @@ -179,8 +187,10 @@ struct tv32 { #define F_ONCE 0x200000 #define F_AUDIBLE 0x400000 #define F_MISSED 0x800000 +#define F_DONTFRAG 0x1000000 #define F_NOUSERDATA (F_NODEADDR | F_FQDN | F_FQDNOLD | F_SUPTYPES) -u_int options; +#define F_WAITTIME 0x2000000 +#define F_DOT 0x4000000 #define IN6LEN sizeof(struct in6_addr) #define SA6LEN sizeof(struct sockaddr_in6) @@ -194,150 +204,146 @@ u_int options; * to 8192 for complete accuracy... */ #define MAX_DUP_CHK (8 * 8192) -int mx_dup_ck = MAX_DUP_CHK; -char rcvd_tbl[MAX_DUP_CHK / 8]; +static int mx_dup_ck = MAX_DUP_CHK; +static char rcvd_tbl[MAX_DUP_CHK / 8]; -struct addrinfo *res; -struct sockaddr_in6 dst; /* who to ping6 */ -struct sockaddr_in6 src; /* src addr of this packet */ -socklen_t srclen; -int datalen = DEFDATALEN; -int s; /* socket file descriptor */ -u_char outpack[MAXPACKETLEN]; -char BSPACE = '\b'; /* characters written for flood */ -char BBELL = '\a'; /* characters written for AUDIBLE */ -char DOT = '.'; -char *hostname; -int ident; /* process id to identify our packets */ -u_int8_t nonce[8]; /* nonce field for node information */ -int hoplimit = -1; /* hoplimit */ -int pathmtu = 0; /* path MTU for the destination. 0 = unspec. */ +static struct sockaddr_in6 dst; /* who to ping6 */ +static struct sockaddr_in6 src; /* src addr of this packet */ +static socklen_t srclen; +static size_t datalen = DEFDATALEN; +static int ssend; /* send socket file descriptor */ +static int srecv; /* receive socket file descriptor */ +static u_char outpack[MAXPACKETLEN]; +static char BSPACE = '\b'; /* characters written for flood */ +static char BBELL = '\a'; /* characters written for AUDIBLE */ +static const char *DOT = "."; +static size_t DOTlen = 1; +static size_t DOTidx = 0; +static int ident; /* process id to identify our packets */ +static u_int8_t nonce[8]; /* nonce field for node information */ +static int hoplimit = -1; /* hoplimit */ +static int tclass = -1; /* traffic class */ +static int pcp = -2; /* vlan priority code point */ +static u_char *packet = NULL; +#ifndef __HAIKU__ +static cap_channel_t *capdns; +#endif /* counters */ -long nmissedmax; /* max value of ntransmitted - nreceived - 1 */ -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 */ - -/* timing */ -int timing; /* flag to do timing */ -double tmin = 999999999.0; /* minimum round trip time */ -double tmax = 0.0; /* maximum round trip time */ -double tsum = 0.0; /* sum of all times, for doing average */ -double tsumsq = 0.0; /* sum of all times squared, for std. dev. */ +static long nmissedmax; /* max value of ntransmitted - nreceived - 1 */ +static long npackets; /* max packets to transmit */ +static long ntransmitfailures; /* number of transmit failures */ +static int interval = 1000; /* interval between packets in ms */ +static int waittime = MAXWAIT; /* timeout for each packet */ /* for node addresses */ -u_short naflags; +static u_short naflags; /* for ancillary data(advanced API) */ -struct msghdr smsghdr; -struct iovec smsgiov; -char *scmsg = 0; +static struct msghdr smsghdr; +static struct iovec smsgiov; +static char *scmsg = 0; -volatile sig_atomic_t seenalrm; -volatile sig_atomic_t seenint; -#ifdef SIGINFO -volatile sig_atomic_t seeninfo; +#ifndef __HAIKU__ +static cap_channel_t *capdns_setup(void); +#endif +static void fill(char *, char *); +static int get_hoplim(struct msghdr *); +static int get_pathmtu(struct msghdr *); +static struct in6_pktinfo *get_rcvpktinfo(struct msghdr *); +static size_t pingerlen(void); +static int pinger(void); +static const char *pr_addr(struct sockaddr *, int); +static void pr_icmph(struct icmp6_hdr *, u_char *); +static void pr_iph(struct ip6_hdr *); +static void pr_suptypes(struct icmp6_nodeinfo *, size_t); +static void pr_nodeaddr(struct icmp6_nodeinfo *, int); +static int myechoreply(const struct icmp6_hdr *); +static int mynireply(const struct icmp6_nodeinfo *); +static const char *dnsdecode(const u_char *, const u_char *, const u_char *, + char *, size_t); +static void pr_pack(u_char *, int, struct msghdr *); +static void pr_exthdrs(struct msghdr *); +static void pr_ip6opt(void *, size_t); +static void pr_rthdr(void *, size_t); +static int pr_bitrange(u_int32_t, int, int); +static void pr_retip(struct ip6_hdr *, u_char *); +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC +static int setpolicy(int, char *); +#endif +#endif +#ifndef __HAIKU__ +static char *nigroup(char *, int); #endif - -int main(int, char *[]); -void fill(char *, char *); -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); -const char *pr_addr(struct sockaddr *, int); -void pr_icmph(struct icmp6_hdr *, u_char *); -void pr_iph(struct ip6_hdr *); -void pr_suptypes(struct icmp6_nodeinfo *, size_t); -void pr_nodeaddr(struct icmp6_nodeinfo *, int); -int myechoreply(const struct icmp6_hdr *); -int mynireply(const struct icmp6_nodeinfo *); -char *dnsdecode(const u_char **, const u_char *, const u_char *, - char *, size_t); -void pr_pack(u_char *, int, struct msghdr *); -void pr_exthdrs(struct msghdr *); -void pr_ip6opt(void *, size_t); -void pr_rthdr(void *, size_t); -int pr_bitrange(u_int32_t, int, int); -void pr_retip(struct ip6_hdr *, u_char *); -void summary(void); -void tvsub(struct timeval *, struct timeval *); -int setpolicy(int, char *); -char *nigroup(char *); -void usage(void); - int -main(argc, argv) - int argc; - char *argv[]; +ping6(int argc, char *argv[]) { - struct itimerval itimer; - struct sockaddr_in6 from; -#ifndef HAVE_ARC4RANDOM - struct timeval seed; -#endif -#ifdef HAVE_POLL_H - int timeout; -#else - struct timeval timeout, *tv; -#endif - struct addrinfo hints; -#ifdef HAVE_POLL_H - struct pollfd fdmaskp[1]; -#else - fd_set *fdmaskp; - int fdmasks; -#endif + struct timespec last, intvl; + struct sockaddr_in6 from, *sin6; + struct addrinfo hints, *res; + struct sigaction si_sa; int cc, i; - int ch, hold, packlen, preload, optval, ret_ga; - u_char *datap, *packet; - char *e, *target, *ifname = NULL; + int almost_done, ch, hold, packlen, preload, optval, error; + int nig_oldmcprefix = -1; + u_char *datap; + char *e, *target, *ifname = NULL, *gateway = NULL; int ip6optlen = 0; struct cmsghdr *scmsgp = NULL; - struct cmsghdr *cm; + /* For control (ancillary) data received from recvmsg() */ + u_char cm[CONTROLLEN]; #if defined(SO_SNDBUF) && defined(SO_RCVBUF) u_long lsockbufsize; int sockbufsize = 0; #endif int usepktinfo = 0; - struct in6_pktinfo *pktinfo = NULL; + struct in6_pktinfo pktinfo; + char *cmsg_pktinfo = NULL; + struct ip6_rthdr *rthdr = NULL; #ifdef IPSEC_POLICY_IPSEC char *policy_in = NULL; char *policy_out = NULL; #endif - double intval; + double t; + u_long alarmtimeout; + size_t rthlen; #ifdef IPV6_USE_MIN_MTU int mflag = 0; #endif +#ifndef __HAIKU__ + cap_rights_t rights_srecv; + cap_rights_t rights_ssend; + cap_rights_t rights_stdin; +#endif /* just to be sure */ memset(&smsghdr, 0, sizeof(smsghdr)); memset(&smsgiov, 0, sizeof(smsgiov)); + memset(&pktinfo, 0, sizeof(pktinfo)); - preload = 0; + intvl.tv_sec = interval / 1000; + intvl.tv_nsec = interval % 1000 * 1000000; + + alarmtimeout = preload = 0; datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN]; -#ifndef IPSEC -#define ADDOPTS -#else -#ifdef IPSEC_POLICY_IPSEC -#define ADDOPTS "P:" -#else -#define ADDOPTS "AE" -#endif /*IPSEC_POLICY_IPSEC*/ +#ifndef __HAIKU__ + capdns = capdns_setup(); #endif - while ((ch = getopt(argc, argv, - "a:b:c:dfHh:I:i:l:mnop:qrRS:s:tvwW" ADDOPTS)) != -1) { -#undef ADDOPTS + + while ((ch = getopt(argc, argv, PING6OPTS)) != -1) { switch (ch) { - case 'a': + case '.': + options |= F_DOT; + if (optarg != NULL) { + DOT = optarg; + DOTlen = strlen(optarg); + } + break; + case '6': + /* This option is processed in main(). */ + break; + case 'k': { char *cp; @@ -385,21 +391,31 @@ main(argc, argv) errno = 0; e = NULL; lsockbufsize = strtoul(optarg, &e, 10); - sockbufsize = lsockbufsize; + sockbufsize = (int)lsockbufsize; if (errno || !*optarg || *e || - sockbufsize != lsockbufsize) + lsockbufsize > INT_MAX) errx(1, "invalid socket buffer size"); #else errx(1, "-b option ignored: SO_SNDBUF/SO_RCVBUF socket options not supported"); #endif break; + case 'C': /* vlan priority code point */ + pcp = strtol(optarg, &e, 10); + if (*optarg == '\0' || *e != '\0') + errx(1, "illegal vlan pcp %s", optarg); + if (7 < pcp || pcp < -1) + errx(1, "illegal vlan pcp -- %s", optarg); + break; case 'c': npackets = strtol(optarg, &e, 10); if (npackets <= 0 || *optarg == '\0' || *e != '\0') errx(1, "illegal number of packets -- %s", optarg); break; + case 'D': + options |= F_DONTFRAG; + break; case 'd': options |= F_SO_DEBUG; break; @@ -409,17 +425,16 @@ main(argc, argv) errx(1, "Must be superuser to flood ping"); } options |= F_FLOOD; + options |= F_DOT; setbuf(stdout, (char *)NULL); break; -#ifdef undefined - case 'g': + case 'e': gateway = optarg; break; -#endif case 'H': options |= F_HOSTNAME; break; - case 'h': /* hoplimit */ + case 'm': /* hoplimit */ hoplimit = strtol(optarg, &e, 10); if (*optarg == '\0' || *e != '\0') errx(1, "illegal hoplimit %s", optarg); @@ -435,22 +450,22 @@ main(argc, 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 = (time_t)t; + intvl.tv_nsec = + (long)((t - intvl.tv_sec) * 1000000000); + 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_nsec < 1000) { warnx("too small interval, raised to .000001"); - interval.tv_usec = 1; + intvl.tv_nsec = 1000; } options |= F_INTERVAL; break; @@ -463,7 +478,7 @@ main(argc, argv) if (preload < 0 || *optarg == '\0' || *e != '\0') errx(1, "illegal preload value -- %s", optarg); break; - case 'm': + case 'u': #ifdef IPV6_USE_MIN_MTU mflag++; break; @@ -474,11 +489,10 @@ main(argc, argv) case 'n': options &= ~F_HOSTNAME; break; -#ifdef undefined case 'N': options |= F_NIGROUP; + nig_oldmcprefix++; break; -#endif case 'o': options |= F_ONCE; break; @@ -489,10 +503,10 @@ main(argc, argv) case 'q': options |= F_QUIET; break; - case 'r': + case 'a': options |= F_AUDIBLE; break; - case 'R': + case 'A': options |= F_MISSED; break; case 'S': @@ -502,10 +516,13 @@ main(argc, argv) hints.ai_socktype = SOCK_RAW; hints.ai_protocol = IPPROTO_ICMPV6; - ret_ga = getaddrinfo(optarg, NULL, &hints, &res); - if (ret_ga) { +#ifdef __HAIKU__ +#define cap_getaddrinfo(p1,p2,p3,p4,p5) getaddrinfo(p2,p3,p4,p5) +#endif + error = cap_getaddrinfo(capdns, 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 @@ -526,21 +543,55 @@ main(argc, argv) MAXDATALEN); } break; - case 't': + case 'O': options &= ~F_NOUSERDATA; options |= F_SUPTYPES; break; case 'v': options |= F_VERBOSE; break; - case 'w': + case 'y': options &= ~F_NOUSERDATA; options |= F_FQDN; break; - case 'W': + case 'Y': options &= ~F_NOUSERDATA; options |= F_FQDNOLD; break; + case 'W': + t = strtod(optarg, &e); + if (*e || e == optarg || t > (double)INT_MAX) + errx(EX_USAGE, "invalid timing interval: `%s'", + optarg); + options |= F_WAITTIME; + waittime = (int)t; + break; + case 't': + alarmtimeout = strtoul(optarg, &e, 0); + if ((alarmtimeout < 1) || (alarmtimeout == ULONG_MAX)) + errx(EX_USAGE, "invalid timeout: `%s'", + optarg); + if (alarmtimeout > MAXALARM) + errx(EX_USAGE, "invalid timeout: `%s' > %d", + optarg, MAXALARM); + { + struct itimerval itv; + + timerclear(&itv.it_interval); + timerclear(&itv.it_value); + itv.it_value.tv_sec = (time_t)alarmtimeout; + if (setitimer(ITIMER_REAL, &itv, NULL) != 0) + err(1, "setitimer"); + } + break; + case 'z': /* traffic class */ + tclass = strtol(optarg, &e, 10); + if (*optarg == '\0' || *e != '\0') + errx(1, "illegal traffic class %s", optarg); + if (255 < tclass || tclass < -1) + errx(1, + "illegal traffic class -- %s", optarg); + break; #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC case 'P': @@ -555,7 +606,7 @@ main(argc, argv) errx(1, "invalid security policy"); break; #else - case 'A': + case 'Z': options |= F_AUTHHDR; break; case 'E': @@ -577,9 +628,25 @@ main(argc, argv) /*NOTREACHED*/ } -#ifdef undefined +#ifndef __HAIKU__ + if (argc > 1) { +#ifdef IPV6_RECVRTHDR /* 2292bis */ + rthlen = CMSG_SPACE(inet6_rth_space(IPV6_RTHDR_TYPE_0, + argc - 1)); +#else /* RFC2292 */ + rthlen = inet6_rthdr_space(IPV6_RTHDR_TYPE_0, argc - 1); +#endif + if (rthlen == 0) { + errx(1, "too many intermediate hops"); + /*NOTREACHED*/ + } + ip6optlen += rthlen; + } +#endif + +#ifndef __HAIKU__ if (options & F_NIGROUP) { - target = nigroup(argv[argc - 1]); + target = nigroup(argv[argc - 1], nig_oldmcprefix); if (target == NULL) { usage(); /*NOTREACHED*/ @@ -588,91 +655,112 @@ main(argc, argv) #endif target = argv[argc - 1]; - /* getaddrinfo */ + /* cap_getaddrinfo */ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_flags = AI_CANONNAME; hints.ai_family = AF_INET6; 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 = cap_getaddrinfo(capdns, target, NULL, &hints, &res); + if (error) + errx(EX_NOHOST, "cannot resolve %s: %s", + target, gai_strerror(error)); if (res->ai_canonname) - hostname = res->ai_canonname; + hostname = strdup(res->ai_canonname); else hostname = target; if (!res->ai_addr) - errx(1, "getaddrinfo failed"); + errx(EX_NOHOST, "cannot resolve %s", target); (void)memcpy(&dst, res->ai_addr, res->ai_addrlen); - if ((s = socket(res->ai_family, res->ai_socktype, + if ((ssend = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) - err(1, "socket"); + err(1, "socket ssend"); + if ((srecv = socket(res->ai_family, res->ai_socktype, + res->ai_protocol)) < 0) + err(1, "socket srecv"); + freeaddrinfo(res); /* set the source address if specified. */ - if ((options & F_SRCADDR) && - bind(s, (struct sockaddr *)&src, srclen) != 0) { - err(1, "bind"); + if ((options & F_SRCADDR) != 0) { + /* properly fill sin6_scope_id */ + if (IN6_IS_ADDR_LINKLOCAL(&src.sin6_addr) && ( + IN6_IS_ADDR_LINKLOCAL(&dst.sin6_addr) || + IN6_IS_ADDR_MC_LINKLOCAL(&dst.sin6_addr) || + IN6_IS_ADDR_MC_NODELOCAL(&dst.sin6_addr))) { + if (src.sin6_scope_id == 0) + src.sin6_scope_id = dst.sin6_scope_id; + if (dst.sin6_scope_id == 0) + dst.sin6_scope_id = src.sin6_scope_id; + } + if (bind(ssend, (struct sockaddr *)&src, srclen) != 0) + err(1, "bind"); } - -#ifdef undefined +#ifndef __HAIKU__ /* set the gateway (next hop) if specified */ if (gateway) { - struct addrinfo ghints, *gres; - int error; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_RAW; + hints.ai_protocol = IPPROTO_ICMPV6; - memset(&ghints, 0, sizeof(ghints)); - ghints.ai_family = AF_INET6; - ghints.ai_socktype = SOCK_RAW; - ghints.ai_protocol = IPPROTO_ICMPV6; - - error = getaddrinfo(gateway, NULL, &hints, &gres); + error = cap_getaddrinfo(capdns, gateway, NULL, &hints, &res); if (error) { - errx(1, "getaddrinfo for the gateway %s: %s", + errx(1, "cap_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)) { + if (setsockopt(ssend, IPPROTO_IPV6, IPV6_NEXTHOP, + res->ai_addr, res->ai_addrlen)) { err(1, "setsockopt(IPV6_NEXTHOP)"); } - freeaddrinfo(gres); + freeaddrinfo(res); } #endif /* - * let the kerel pass extension headers of incoming packets, + * let the kernel pass extension headers of incoming packets, * for privileged socket options */ if ((options & F_VERBOSE) != 0) { int opton = 1; #ifdef IPV6_RECVHOPOPTS - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &opton, + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &opton, sizeof(opton))) err(1, "setsockopt(IPV6_RECVHOPOPTS)"); +#else /* old adv. API */ + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_HOPOPTS, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_HOPOPTS)"); #endif #ifdef IPV6_RECVDSTOPTS - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTOPTS, &opton, + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_RECVDSTOPTS, &opton, sizeof(opton))) err(1, "setsockopt(IPV6_RECVDSTOPTS)"); +#else /* old adv. API */ + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_DSTOPTS, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_DSTOPTS)"); #endif #ifdef IPV6_RECVRTHDRDSTOPTS - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDRDSTOPTS, &opton, + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_RECVRTHDRDSTOPTS, &opton, sizeof(opton))) err(1, "setsockopt(IPV6_RECVRTHDRDSTOPTS)"); #endif } /* revoke root privilege */ - seteuid(getuid()); - setuid(getuid()); + if (seteuid(getuid()) != 0) + err(1, "seteuid() failed"); + if (setuid(getuid()) != 0) + err(1, "setuid() failed"); if ((options & F_FLOOD) && (options & F_INTERVAL)) errx(1, "-f and -i incompatible options"); @@ -702,40 +790,39 @@ main(argc, argv) *datap++ = i; ident = getpid() & 0xFFFF; -#ifndef HAVE_ARC4RANDOM - gettimeofday(&seed, NULL); - srand((unsigned int)(seed.tv_sec ^ seed.tv_usec ^ (long)ident)); - memset(nonce, 0, sizeof(nonce)); - for (i = 0; i < sizeof(nonce); i += sizeof(int)) - *((int *)&nonce[i]) = rand(); -#else - memset(nonce, 0, sizeof(nonce)); - for (i = 0; i < sizeof(nonce); i += sizeof(u_int32_t)) - *((u_int32_t *)&nonce[i]) = arc4random(); + arc4random_buf(nonce, sizeof(nonce)); + optval = 1; +#ifndef __HAIKU__ + if (options & F_DONTFRAG) + if (setsockopt(ssend, IPPROTO_IPV6, IPV6_DONTFRAG, + &optval, sizeof(optval)) == -1) + err(1, "IPV6_DONTFRAG"); #endif - hold = 1; - if (options & F_SO_DEBUG) - (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold, + if (options & F_SO_DEBUG) { + (void)setsockopt(ssend, SOL_SOCKET, SO_DEBUG, (char *)&hold, sizeof(hold)); + (void)setsockopt(srecv, SOL_SOCKET, SO_DEBUG, (char *)&hold, + sizeof(hold)); + } optval = IPV6_DEFHLIM; if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) - if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + if (setsockopt(ssend, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &optval, sizeof(optval)) == -1) err(1, "IPV6_MULTICAST_HOPS"); #ifdef IPV6_USE_MIN_MTU if (mflag != 1) { optval = mflag > 1 ? 0 : 1; - if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU, + if (setsockopt(ssend, IPPROTO_IPV6, IPV6_USE_MIN_MTU, &optval, sizeof(optval)) == -1) err(1, "setsockopt(IPV6_USE_MIN_MTU)"); } #ifdef IPV6_RECVPATHMTU else { optval = 1; - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPATHMTU, + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_RECVPATHMTU, &optval, sizeof(optval)) == -1) err(1, "setsockopt(IPV6_RECVPATHMTU)"); } @@ -745,27 +832,36 @@ main(argc, argv) #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC if (options & F_POLICY) { - if (setpolicy(s, policy_in) < 0) + if (setpolicy(srecv, policy_in) < 0) errx(1, "%s", ipsec_strerror()); - if (setpolicy(s, policy_out) < 0) + if (setpolicy(ssend, policy_out) < 0) errx(1, "%s", ipsec_strerror()); } #else if (options & F_AUTHHDR) { optval = IPSEC_LEVEL_REQUIRE; #ifdef IPV6_AUTH_TRANS_LEVEL - if (setsockopt(s, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, + if (setsockopt(ssend, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &optval, sizeof(optval)) == -1) err(1, "setsockopt(IPV6_AUTH_TRANS_LEVEL)"); + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, + &optval, sizeof(optval)) == -1) + err(1, "setsockopt(IPV6_AUTH_TRANS_LEVEL)"); #else /* old def */ - if (setsockopt(s, IPPROTO_IPV6, IPV6_AUTH_LEVEL, + if (setsockopt(ssend, IPPROTO_IPV6, IPV6_AUTH_LEVEL, + &optval, sizeof(optval)) == -1) + err(1, "setsockopt(IPV6_AUTH_LEVEL)"); + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &optval, sizeof(optval)) == -1) err(1, "setsockopt(IPV6_AUTH_LEVEL)"); #endif } if (options & F_ENCRYPT) { optval = IPSEC_LEVEL_REQUIRE; - if (setsockopt(s, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, + if (setsockopt(ssend, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, + &optval, sizeof(optval)) == -1) + err(1, "setsockopt(IPV6_ESP_TRANS_LEVEL)"); + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &optval, sizeof(optval)) == -1) err(1, "setsockopt(IPV6_ESP_TRANS_LEVEL)"); } @@ -785,27 +881,31 @@ main(argc, argv) } else { ICMP6_FILTER_SETPASSALL(&filt); } - if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, + if (setsockopt(srecv, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)) < 0) err(1, "setsockopt(ICMP6_FILTER)"); } #endif /*ICMP6_FILTER*/ - /* let the kerel pass extension headers of incoming packets */ + /* let the kernel pass extension headers of incoming packets */ if ((options & F_VERBOSE) != 0) { int opton = 1; #ifdef IPV6_RECVRTHDR - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDR, &opton, + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_RECVRTHDR, &opton, sizeof(opton))) err(1, "setsockopt(IPV6_RECVRTHDR)"); +#else /* old adv. API */ + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_RTHDR, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_RTHDR)"); #endif } /* optval = 1; if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) - if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, + if (setsockopt(ssend, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &optval, sizeof(optval)) == -1) err(1, "IPV6_MULTICAST_LOOP"); */ @@ -819,15 +919,14 @@ main(argc, argv) /* set IP6 packet options */ if (ip6optlen) { - if ((scmsg = (char *)malloc(ip6optlen)) == 0) + if ((scmsg = (char *)malloc(ip6optlen)) == NULL) errx(1, "can't allocate enough memory"); smsghdr.msg_control = (caddr_t)scmsg; smsghdr.msg_controllen = ip6optlen; - scmsgp = (struct cmsghdr *)scmsg; + scmsgp = CMSG_FIRSTHDR(&smsghdr); } if (usepktinfo) { - pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp)); - memset(pktinfo, 0, sizeof(*pktinfo)); + cmsg_pktinfo = CMSG_DATA(scmsgp); scmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); scmsgp->cmsg_level = IPPROTO_IPV6; scmsgp->cmsg_type = IPV6_PKTINFO; @@ -838,7 +937,7 @@ main(argc, argv) if (ifname) { #ifndef USE_SIN6_SCOPE_ID /* pktinfo must have already been allocated */ - if ((pktinfo->ipi6_ifindex = if_nametoindex(ifname)) == 0) + if ((pktinfo.ipi6_ifindex = if_nametoindex(ifname)) == 0) errx(1, "%s: invalid interface name", ifname); #else if ((dst.sin6_scope_id = if_nametoindex(ifname)) == 0) @@ -849,11 +948,68 @@ main(argc, argv) scmsgp->cmsg_len = CMSG_LEN(sizeof(int)); scmsgp->cmsg_level = IPPROTO_IPV6; scmsgp->cmsg_type = IPV6_HOPLIMIT; - *(int *)(CMSG_DATA(scmsgp)) = hoplimit; + memcpy(CMSG_DATA(scmsgp), &hoplimit, sizeof(hoplimit)); scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp); } +#ifndef __HAIKU__ + if (tclass != -1) { + if (setsockopt(ssend, IPPROTO_IPV6, IPV6_TCLASS, + &tclass, sizeof(tclass)) == -1) + err(1, "setsockopt(IPV6_TCLASS)"); + } + + if (pcp != -2) { + if (setsockopt(ssend, IPPROTO_IPV6, IPV6_VLAN_PCP, + &pcp, sizeof(pcp)) == -1) + err(1, "setsockopt(IPV6_VLAN_PCP)"); + } + + if (argc > 1) { /* some intermediate addrs are specified */ + int hops; + int rthdrlen; + + rthdrlen = inet6_rth_space(IPV6_RTHDR_TYPE_0, argc - 1); + scmsgp->cmsg_len = CMSG_LEN(rthdrlen); + scmsgp->cmsg_level = IPPROTO_IPV6; + scmsgp->cmsg_type = IPV6_RTHDR; + rthdr = (struct ip6_rthdr *)CMSG_DATA(scmsgp); + rthdr = inet6_rth_init((void *)rthdr, rthdrlen, + IPV6_RTHDR_TYPE_0, argc - 1); + if (rthdr == NULL) + errx(1, "can't initialize rthdr"); + + for (hops = 0; hops < argc - 1; hops++) { + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + + if ((error = cap_getaddrinfo(capdns, argv[hops], NULL, &hints, + &res))) + errx(1, "%s", gai_strerror(error)); + 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; + if (inet6_rth_add(rthdr, &sin6->sin6_addr)) + errx(1, "can't add an intermediate node"); + freeaddrinfo(res); + } + + scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp); + } +#endif + + /* From now on we will use only reverse DNS lookups. */ +#ifdef WITH_CASPER + if (capdns != NULL) { + const char *types[1]; + + types[0] = "ADDR2NAME"; + if (cap_dns_type_limit(capdns, types, nitems(types)) < 0) + err(1, "unable to limit access to system.dns service"); + } +#endif if (!(options & F_SRCADDR)) { /* * get the source address. XXX since we revoked the root @@ -870,10 +1026,9 @@ main(argc, argv) src.sin6_port = ntohs(DUMMY_PORT); src.sin6_scope_id = dst.sin6_scope_id; -#ifdef USE_RFC2292BIS - if (pktinfo && + if (usepktinfo && setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTINFO, - (void *)pktinfo, sizeof(*pktinfo))) + (void *)&pktinfo, sizeof(pktinfo))) err(1, "UDP setsockopt(IPV6_PKTINFO)"); if (hoplimit != -1 && @@ -886,12 +1041,10 @@ main(argc, argv) (void *)&hoplimit, sizeof(hoplimit))) err(1, "UDP setsockopt(IPV6_MULTICAST_HOPS)"); -#else /* old advanced API */ - if (smsghdr.msg_control && - setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTOPTIONS, - (void *)smsghdr.msg_control, smsghdr.msg_controllen)) - err(1, "UDP setsockopt(IPV6_PKTOPTIONS)"); -#endif + if (rthdr && + setsockopt(dummy, IPPROTO_IPV6, IPV6_RTHDR, + (void *)rthdr, (rthdr->ip6r_len + 1) << 3)) + err(1, "UDP setsockopt(IPV6_RTHDR)"); if (connect(dummy, (struct sockaddr *)&src, len) < 0) err(1, "UDP connect"); @@ -902,14 +1055,45 @@ main(argc, argv) close(dummy); } + /* Save pktinfo in the ancillary data. */ + if (usepktinfo) + memcpy(cmsg_pktinfo, &pktinfo, sizeof(pktinfo)); + +#ifndef __HAIKU__ +// unsupported on Haiku + if (connect(ssend, (struct sockaddr *)&dst, sizeof(dst)) != 0) + err(1, "connect() ssend"); +#endif + +#ifndef __HAIKU__ + caph_cache_catpages(); + if (caph_enter_casper() < 0) + err(1, "caph_enter_casper"); + + cap_rights_init(&rights_stdin); + if (caph_rights_limit(STDIN_FILENO, &rights_stdin) < 0) + err(1, "caph_rights_limit stdin"); + if (caph_limit_stdout() < 0) + err(1, "caph_limit_stdout"); + if (caph_limit_stderr() < 0) + err(1, "caph_limit_stderr"); + + cap_rights_init(&rights_srecv, CAP_RECV, CAP_EVENT, CAP_SETSOCKOPT); + if (caph_rights_limit(srecv, &rights_srecv) < 0) + err(1, "caph_rights_limit srecv"); + cap_rights_init(&rights_ssend, CAP_SEND, CAP_SETSOCKOPT); + if (caph_rights_limit(ssend, &rights_ssend) < 0) + err(1, "caph_rights_limit ssend"); +#endif + #if defined(SO_SNDBUF) && defined(SO_RCVBUF) if (sockbufsize) { - if (datalen > sockbufsize) + if (datalen > (size_t)sockbufsize) warnx("you need -b to increase socket buffer size"); - if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sockbufsize, + if (setsockopt(ssend, SOL_SOCKET, SO_SNDBUF, &sockbufsize, sizeof(sockbufsize)) < 0) err(1, "setsockopt(SO_SNDBUF)"); - if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &sockbufsize, + if (setsockopt(srecv, SOL_SOCKET, SO_RCVBUF, &sockbufsize, sizeof(sockbufsize)) < 0) err(1, "setsockopt(SO_RCVBUF)"); } @@ -923,248 +1107,195 @@ main(argc, argv) * to get some stuff for /etc/ethers. */ hold = 48 * 1024; - setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold, + setsockopt(srecv, SOL_SOCKET, SO_RCVBUF, (char *)&hold, sizeof(hold)); } #endif optval = 1; -//#ifndef USE_SIN6_SCOPE_ID +#ifndef USE_SIN6_SCOPE_ID #ifdef IPV6_RECVPKTINFO - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &optval, + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_RECVPKTINFO, &optval, sizeof(optval)) < 0) warn("setsockopt(IPV6_RECVPKTINFO)"); /* XXX err? */ #else /* old adv. API */ - if (setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &optval, + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_PKTINFO, &optval, sizeof(optval)) < 0) warn("setsockopt(IPV6_PKTINFO)"); /* XXX err? */ #endif -//#endif /* USE_SIN6_SCOPE_ID */ +#endif /* USE_SIN6_SCOPE_ID */ #ifdef IPV6_RECVHOPLIMIT - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &optval, + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &optval, sizeof(optval)) < 0) warn("setsockopt(IPV6_RECVHOPLIMIT)"); /* XXX err? */ #else /* old adv. API */ - if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPLIMIT, &optval, + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_HOPLIMIT, &optval, sizeof(optval)) < 0) warn("setsockopt(IPV6_HOPLIMIT)"); /* XXX err? */ #endif - if (hoplimit != -1 && - setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, - (void *)&hoplimit, sizeof(hoplimit))) - err(1, "setsockopt(IPV6_UNICAST_HOPS)"); +#ifndef __HAIKU__ + cap_rights_clear(&rights_srecv, CAP_SETSOCKOPT); + if (caph_rights_limit(srecv, &rights_srecv) < 0) + err(1, "caph_rights_limit srecv setsockopt"); + cap_rights_clear(&rights_ssend, CAP_SETSOCKOPT); + if (caph_rights_limit(ssend, &rights_ssend) < 0) + err(1, "caph_rights_limit ssend setsockopt"); +#endif - if (hoplimit != -1 && - setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, - (void *)&hoplimit, sizeof(hoplimit))) - err(1, "setsockopt(IPV6_MULTICAST_HOPS)"); - - - printf("PING6(%lu=40+8+%lu bytes) ", (unsigned long)(40 + pingerlen()), + printf("PING(%lu=40+8+%lu bytes) ", (unsigned long)(40 + pingerlen()), (unsigned long)(pingerlen() - 8)); 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(); } + clock_gettime(CLOCK_MONOTONIC, &last); -#ifndef HAVE_POLL_H - fdmasks = howmany(s + 1, NFDBITS) * sizeof(fd_mask); - if ((fdmaskp = malloc(fdmasks)) == NULL) - err(1, "malloc"); -#endif - - seenalrm = seenint = 0; -#ifdef SIGINFO + 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; +#ifndef __HAIKU__ + if (sigaction(SIGINFO, &si_sa, 0) == -1) + err(EX_OSERR, "sigaction SIGINFO"); seeninfo = 0; #endif + if (alarmtimeout > 0) { + if (sigaction(SIGALRM, &si_sa, 0) == -1) + err(EX_OSERR, "sigaction SIGALRM"); + } + if (options & F_FLOOD) { + intvl.tv_sec = 0; + intvl.tv_nsec = 10000000; + } - /* For control (ancillary) data received from recvmsg() */ - cm = (struct cmsghdr *)malloc(CONTROLLEN); - if (cm == NULL) - err(1, "malloc"); - - for (;;) { + almost_done = 0; + while (seenint == 0) { + struct timespec 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) { - onint(SIGINT); - seenint = 0; - continue; - } -#ifdef SIGINFO if (seeninfo) { - summary(); + pr_summary(stderr); seeninfo = 0; continue; } -#endif + FD_ZERO(&rfds); + FD_SET(srecv, &rfds); + clock_gettime(CLOCK_MONOTONIC, &now); + timespecadd(&last, &intvl, &timeout); + timespecsub(&timeout, &now, &timeout); + if (timeout.tv_sec < 0) + timespecclear(&timeout); - 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 = -1; -#else - tv = NULL; -#endif + n = pselect(srecv + 1, &rfds, NULL, NULL, &timeout, NULL); + 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(srecv, &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); + } + } + continue; + } else { + /* + * an ICMPv6 message (probably an echoreply) + * arrived. + */ + pr_pack(packet, cc, &m); + } + if (((options & F_ONCE) != 0 && nreceived > 0) || + (npackets > 0 && nreceived >= npackets)) + break; } -#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; - - /* - * receive control messages only. Process the - * exceptions (currently the only possiblity 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); + if (n == 0 || (options & F_FLOOD)) { + if (npackets == 0 || ntransmitted < npackets) + pinger(); + else { + if (almost_done) + break; + almost_done = 1; + /* + * If we're not transmitting any more packets, + * change the timer to wait two round-trip times + * if we've received any packets or (waittime) + * milliseconds if we haven't. + */ + intvl.tv_nsec = 0; + if (nreceived) { + intvl.tv_sec = 2 * tmax / 1000; + if (intvl.tv_sec == 0) + intvl.tv_sec = 1; + } else { + intvl.tv_sec = waittime / 1000; + intvl.tv_nsec = + waittime % 1000 * 1000000; } } - continue; - } else { - /* - * an ICMPv6 message (probably an echoreply) arrived. - */ - 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); + clock_gettime(CLOCK_MONOTONIC, &last); + if (ntransmitted - nreceived - 1 > nmissedmax) { + nmissedmax = ntransmitted - nreceived - 1; + if (options & F_MISSED) + (void)write(STDOUT_FILENO, &BBELL, 1); + } } } - summary(); - exit(nreceived == 0 ? 2 : 0); -} + sigemptyset(&si_sa.sa_mask); + si_sa.sa_flags = 0; + si_sa.sa_handler = SIG_IGN; + sigaction(SIGINT, &si_sa, 0); + sigaction(SIGALRM, &si_sa, 0); + pr_summary(stdout); -void -onsignal(sig) - int sig; -{ + if(packet != NULL) + free(packet); - switch (sig) { - case SIGALRM: - seenalrm++; - break; - case SIGINT: - seenint++; - break; -#ifdef SIGINFO - case SIGINFO: - seeninfo++; - break; -#endif - } -} - -/* - * retransmit -- - * This routine transmits another ping6. - */ -void -retransmit() -{ - 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); + if (nreceived > 0) + exit(0); + else if (ntransmitted > ntransmitfailures) + exit(2); + else + exit(EX_OSERR); } /* @@ -1172,11 +1303,11 @@ retransmit() * 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 8 bytes - * of the data portion are used to hold a UNIX "timeval" struct in VAX + * of the data portion are used to hold a UNIX "timespec" struct in VAX * byte-order, to compute the round-trip time. */ -size_t -pingerlen() +static size_t +pingerlen(void) { size_t l; @@ -1194,14 +1325,14 @@ pingerlen() return l; } -int -pinger() +static int +pinger(void) { struct icmp6_hdr *icp; struct iovec iov[2]; int i, cc; struct icmp6_nodeinfo *nip; - int seq; + uint16_t seq; if (npackets && ntransmitted >= npackets) return(-1); /* no more transmission */ @@ -1214,6 +1345,8 @@ pinger() CLR(seq % mx_dup_ck); if (options & F_FQDN) { + uint16_t s; + icp->icmp6_type = ICMP6_NI_QUERY; icp->icmp6_code = ICMP6_NI_SUBJ_IPV6; nip->ni_qtype = htons(NI_QTYPE_FQDN); @@ -1221,13 +1354,15 @@ pinger() memcpy(nip->icmp6_ni_nonce, nonce, sizeof(nip->icmp6_ni_nonce)); - *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); + s = htons(seq); + memcpy(nip->icmp6_ni_nonce, &s, sizeof(s)); memcpy(&outpack[ICMP6_NIQLEN], &dst.sin6_addr, sizeof(dst.sin6_addr)); cc = ICMP6_NIQLEN + sizeof(dst.sin6_addr); datalen = 0; } else if (options & F_FQDNOLD) { + uint16_t s; /* packet format in 03 draft - no Subject data on queries */ icp->icmp6_type = ICMP6_NI_QUERY; icp->icmp6_code = 0; /* code field is always 0 */ @@ -1236,11 +1371,14 @@ pinger() memcpy(nip->icmp6_ni_nonce, nonce, sizeof(nip->icmp6_ni_nonce)); - *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); + s = htons(seq); + memcpy(nip->icmp6_ni_nonce, &s, sizeof(s)); cc = ICMP6_NIQLEN; datalen = 0; } else if (options & F_NODEADDR) { + uint16_t s; + icp->icmp6_type = ICMP6_NI_QUERY; icp->icmp6_code = ICMP6_NI_SUBJ_IPV6; nip->ni_qtype = htons(NI_QTYPE_NODEADDR); @@ -1248,13 +1386,16 @@ pinger() memcpy(nip->icmp6_ni_nonce, nonce, sizeof(nip->icmp6_ni_nonce)); - *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); + s = htons(seq); + memcpy(nip->icmp6_ni_nonce, &s, sizeof(s)); memcpy(&outpack[ICMP6_NIQLEN], &dst.sin6_addr, sizeof(dst.sin6_addr)); cc = ICMP6_NIQLEN + sizeof(dst.sin6_addr); datalen = 0; } else if (options & F_SUPTYPES) { + uint16_t s; + icp->icmp6_type = ICMP6_NI_QUERY; icp->icmp6_code = ICMP6_NI_SUBJ_FQDN; /*empty*/ nip->ni_qtype = htons(NI_QTYPE_SUPTYPES); @@ -1263,21 +1404,29 @@ pinger() memcpy(nip->icmp6_ni_nonce, nonce, sizeof(nip->icmp6_ni_nonce)); - *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); + s = htons(seq); + memcpy(nip->icmp6_ni_nonce, &s, sizeof(s)); + cc = ICMP6_NIQLEN; datalen = 0; } else { icp->icmp6_type = ICMP6_ECHO_REQUEST; icp->icmp6_code = 0; icp->icmp6_id = htons(ident); - icp->icmp6_seq = ntohs(seq); + icp->icmp6_seq = htons(seq); if (timing) { - struct timeval tv; - struct tv32 *tv32; - (void)gettimeofday(&tv, NULL); - tv32 = (struct tv32 *)&outpack[ICMP6ECHOLEN]; - tv32->tv32_sec = htonl(tv.tv_sec); - tv32->tv32_usec = htonl(tv.tv_usec); + struct timespec tv; + struct tv32 tv32; + (void)clock_gettime(CLOCK_MONOTONIC, &tv); + /* + * 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(tv.tv_sec); + tv32.tv32_nsec = (uint32_t)htonl(tv.tv_nsec); + memcpy(&outpack[ICMP6ECHOLEN], &tv32, sizeof(tv32)); } cc = ICMP6ECHOLEN + datalen; } @@ -1287,41 +1436,34 @@ pinger() errx(1, "internal error; length mismatch"); #endif +#ifdef __HAIKU__ smsghdr.msg_name = (caddr_t)&dst; smsghdr.msg_namelen = sizeof(dst); +#endif memset(&iov, 0, sizeof(iov)); iov[0].iov_base = (caddr_t)outpack; iov[0].iov_len = cc; smsghdr.msg_iov = iov; smsghdr.msg_iovlen = 1; -#ifdef CMSG_SENDING_UNSUPPORTED - smsghdr.msg_control = NULL; - smsghdr.msg_controllen = 0; -#endif - - i = sendmsg(s, &smsghdr, 0); - - // as smsghdr is a global variable, don't let stray pointer to the stack - // in it after this function returns. - smsghdr.msg_iov = NULL; - smsghdr.msg_iovlen = 0; + i = sendmsg(ssend, &smsghdr, 0); if (i < 0 || i != cc) { - if (i < 0) + if (i < 0) { + ntransmitfailures++; warn("sendmsg"); - (void)printf("ping6: wrote %s %d chars, ret=%d\n", + } + (void)printf("ping: wrote %s %d chars, ret=%d\n", hostname, cc, i); } - if (!(options & F_QUIET) && options & F_FLOOD) - (void)write(STDOUT_FILENO, &DOT, 1); + if (!(options & F_QUIET) && options & F_DOT) + (void)write(STDOUT_FILENO, &DOT[DOTidx++ % DOTlen], 1); return(0); } -int -myechoreply(icp) - const struct icmp6_hdr *icp; +static int +myechoreply(const struct icmp6_hdr *icp) { if (ntohs(icp->icmp6_id) == ident) return 1; @@ -1329,9 +1471,8 @@ myechoreply(icp) return 0; } -int -mynireply(nip) - const struct icmp6_nodeinfo *nip; +static int +mynireply(const struct icmp6_nodeinfo *nip) { if (memcmp(nip->icmp6_ni_nonce + sizeof(u_int16_t), nonce + sizeof(u_int16_t), @@ -1341,13 +1482,26 @@ mynireply(nip) return 0; } -char * -dnsdecode(sp, ep, base, buf, bufsiz) - const u_char **sp; - const u_char *ep; - const u_char *base; /*base for compressed name*/ - char *buf; - size_t bufsiz; +/* + * Decode a name from a DNS message. + * + * Format of the message is described in RFC 1035 subsection 4.1.4. + * + * Arguments: + * sp - Pointer to a DNS pointer octet or to the first octet of a label + * in the message. + * ep - Pointer to the end of the message (one step past the last octet). + * base - Pointer to the beginning of the message. + * buf - Buffer into which the decoded name will be saved. + * bufsiz - Size of the buffer 'buf'. + * + * Return value: + * Pointer to an octet immediately following the ending zero octet + * of the decoded label, or NULL if an error occurred. + */ +static const char * +dnsdecode(const u_char *sp, const u_char *ep, const u_char *base, char *buf, + size_t bufsiz) { int i; const u_char *cp; @@ -1355,14 +1509,14 @@ dnsdecode(sp, ep, base, buf, bufsiz) const u_char *comp; int l; - cp = *sp; + cp = sp; *buf = '\0'; if (cp >= ep) return NULL; while (cp < ep) { i = *cp; - if (i == 0 || cp != *sp) { + if (i == 0 || cp != sp) { if (strlcat((char *)buf, ".", bufsiz) >= bufsiz) return NULL; /*result overrun*/ } @@ -1376,7 +1530,7 @@ dnsdecode(sp, ep, base, buf, bufsiz) return NULL; comp = base + (i & 0x3f); - if (dnsdecode(&comp, cp, base, cresult, + if (dnsdecode(comp, cp, base, cresult, sizeof(cresult)) == NULL) return NULL; if (strlcat(buf, cresult, bufsiz) >= bufsiz) @@ -1388,7 +1542,7 @@ dnsdecode(sp, ep, base, buf, bufsiz) while (i-- > 0 && cp < ep) { l = snprintf(cresult, sizeof(cresult), isprint(*cp) ? "%c" : "\\%03o", *cp & 0xff); - if (l >= sizeof(cresult) || l < 0) + if ((size_t)l >= sizeof(cresult) || l < 0) return NULL; if (strlcat(buf, cresult, bufsiz) >= bufsiz) return NULL; /*result overrun*/ @@ -1400,8 +1554,7 @@ dnsdecode(sp, ep, base, buf, bufsiz) if (i != 0) return NULL; /*not terminated*/ cp++; - *sp = cp; - return buf; + return cp; } /* @@ -1411,11 +1564,8 @@ dnsdecode(sp, ep, base, buf, bufsiz) * which arrive ('tis only fair). This permits multiple copies of this * program to be run without having intermingled output (or statistics!). */ -void -pr_pack(buf, cc, mhdr) - u_char *buf; - int cc; - struct msghdr *mhdr; +static void +pr_pack(u_char *buf, int cc, struct msghdr *mhdr) { #define safeputc(c) printf((isprint((c)) ? "%c" : "\\%03o"), c) struct icmp6_hdr *icp; @@ -1424,10 +1574,11 @@ pr_pack(buf, cc, mhdr) int hoplim; struct sockaddr *from; int fromlen; - u_char *cp = NULL, *dp, *end = buf + cc; + const u_char *cp = NULL; + u_char *dp, *end = buf + cc; struct in6_pktinfo *pktinfo = NULL; - struct timeval tv, tp; - struct tv32 *tpp; + struct timespec tv, tp; + struct tv32 tpp; double triptime = 0; int dupflag; size_t off; @@ -1435,7 +1586,7 @@ pr_pack(buf, cc, mhdr) u_int16_t seq; char dnsname[MAXDNAME + 1]; - (void)gettimeofday(&tv, NULL); + (void)clock_gettime(CLOCK_MONOTONIC, &tv); if (!mhdr || !mhdr->msg_name || mhdr->msg_namelen != sizeof(struct sockaddr_in6) || @@ -1446,7 +1597,7 @@ pr_pack(buf, cc, mhdr) } from = (struct sockaddr *)mhdr->msg_name; fromlen = mhdr->msg_namelen; - if (cc < sizeof(struct icmp6_hdr)) { + if (cc < (int)sizeof(struct icmp6_hdr)) { if (options & F_VERBOSE) warnx("packet too short (%d bytes) from %s", cc, pr_addr(from, fromlen)); @@ -1472,12 +1623,12 @@ pr_pack(buf, cc, mhdr) seq = ntohs(icp->icmp6_seq); ++nreceived; if (timing) { - tpp = (struct tv32 *)(icp + 1); - tp.tv_sec = ntohl(tpp->tv32_sec); - tp.tv_usec = ntohl(tpp->tv32_usec); - tvsub(&tv, &tp); + memcpy(&tpp, icp + 1, sizeof(tpp)); + tp.tv_sec = ntohl(tpp.tv32_sec); + tp.tv_nsec = ntohl(tpp.tv32_nsec); + timespecsub(&tv, &tp, &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) @@ -1498,7 +1649,12 @@ pr_pack(buf, cc, mhdr) if (options & F_QUIET) return; - if (options & F_FLOOD) + if (options & F_WAITTIME && triptime > waittime) { + ++nrcvtimeout; + return; + } + + if (options & F_DOT) (void)write(STDOUT_FILENO, &BSPACE, 1); else { if (options & F_AUDIBLE) @@ -1533,7 +1689,8 @@ pr_pack(buf, cc, mhdr) } } } else if (icp->icmp6_type == ICMP6_NI_REPLY && mynireply(ni)) { - seq = ntohs(*(u_int16_t *)ni->icmp6_ni_nonce); + memcpy(&seq, ni->icmp6_ni_nonce, sizeof(seq)); + seq = ntohs(seq); ++nreceived; if (TST(seq % mx_dup_ck)) { ++nrepeats; @@ -1591,9 +1748,10 @@ pr_pack(buf, cc, mhdr) } else { i = 0; while (cp < end) { - if (dnsdecode((const u_char **)&cp, end, + cp = dnsdecode((const u_char *)cp, end, (const u_char *)(ni + 1), dnsname, - sizeof(dnsname)) == NULL) { + sizeof(dnsname)); + if (cp == NULL) { printf("???"); break; } @@ -1611,6 +1769,7 @@ pr_pack(buf, cc, mhdr) } } if (options & F_VERBOSE) { + u_long t; int32_t ttl; int comma = 0; @@ -1633,7 +1792,8 @@ pr_pack(buf, cc, mhdr) putchar(')'); goto fqdnend; } - ttl = (int32_t)ntohl(*(u_long *)&buf[off+ICMP6ECHOLEN+8]); + memcpy(&t, &buf[off+ICMP6ECHOLEN+8], sizeof(t)); + ttl = (int32_t)ntohl(t); if (comma) printf(","); if (!(ni->ni_flags & NI_FQDN_FLAG_VALIDTTL)) { @@ -1686,7 +1846,7 @@ pr_pack(buf, cc, mhdr) pr_icmph(icp, end); } - if (!(options & F_FLOOD)) { + if (!(options & F_DOT)) { (void)putchar('\n'); if (options & F_VERBOSE) pr_exthdrs(mhdr); @@ -1695,9 +1855,8 @@ pr_pack(buf, cc, mhdr) #undef safeputc } -void -pr_exthdrs(mhdr) - struct msghdr *mhdr; +static void +pr_exthdrs(struct msghdr *mhdr) { ssize_t bufsize; void *bufp; @@ -1712,7 +1871,7 @@ pr_exthdrs(mhdr) bufsize = CONTROLLEN - ((caddr_t)CMSG_DATA(cm) - (caddr_t)bufp); if (bufsize <= 0) - continue; + continue; switch (cm->cmsg_type) { case IPV6_HOPOPTS: printf(" HbH Options: "); @@ -1733,14 +1892,14 @@ pr_exthdrs(mhdr) } } -#if defined USE_RFC2292BIS && defined IPV6_OPTIONS -void +#ifndef __HAIKU__ +static void pr_ip6opt(void *extbuf, size_t bufsize) { struct ip6_hbh *ext; int currentlen; u_int8_t type; - socklen_t extlen, len, origextlen; + socklen_t extlen, len; void *databuf; size_t offset; u_int16_t value2; @@ -1756,7 +1915,6 @@ pr_ip6opt(void *extbuf, size_t bufsize) * subtract the size of a cmsg structure from the buffer size. */ if (bufsize < (extlen + CMSG_SPACE(0))) { - origextlen = extlen; extlen = bufsize - CMSG_SPACE(0); warnx("options truncated, showing only %u (total=%u)", (unsigned int)(extlen / 8 - 1), @@ -1796,20 +1954,17 @@ pr_ip6opt(void *extbuf, size_t bufsize) } return; } -#else /* !USE_RFC2292BIS */ -/* ARGSUSED */ -void +#else +static void pr_ip6opt(void *extbuf, size_t bufsize) { - (void)extbuf; - (void)bufsize; putchar('\n'); return; } -#endif /* USE_RFC2292BIS */ +#endif -#if defined USE_RFC2292BIS && defined IPV6_OPTIONS -void +#ifndef __HAIKU__ +static void pr_rthdr(void *extbuf, size_t bufsize) { struct in6_addr *in6; @@ -1863,24 +2018,17 @@ pr_rthdr(void *extbuf, size_t bufsize) return; } - -#else /* !USE_RFC2292BIS */ -/* ARGSUSED */ -void +#else +static void pr_rthdr(void *extbuf, size_t bufsize) { - (void)extbuf; - (void)bufsize; putchar('\n'); return; } -#endif /* USE_RFC2292BIS */ +#endif -int -pr_bitrange(v, soff, ii) - u_int32_t v; - int soff; - int ii; +static int +pr_bitrange(u_int32_t v, int soff, int ii) { int off; int i; @@ -1925,10 +2073,9 @@ pr_bitrange(v, soff, ii) return ii; } -void -pr_suptypes(ni, nilen) - struct icmp6_nodeinfo *ni; /* ni->qtype must be SUPTYPES */ - size_t nilen; +static void +pr_suptypes(struct icmp6_nodeinfo *ni, size_t nilen) + /* ni->qtype must be SUPTYPES */ { size_t clen; u_int32_t v; @@ -1992,10 +2139,9 @@ pr_suptypes(ni, nilen) } } -void -pr_nodeaddr(ni, nilen) - struct icmp6_nodeinfo *ni; /* ni->qtype must be NODEADDR */ - int nilen; +static void +pr_nodeaddr(struct icmp6_nodeinfo *ni, int nilen) + /* ni->qtype must be NODEADDR */ { u_char *cp = (u_char *)(ni + 1); char ntop_buf[INET6_ADDRSTRLEN]; @@ -2021,18 +2167,20 @@ pr_nodeaddr(ni, nilen) /* * In icmp-name-lookups 05 and later, TTL of each returned address - * is contained in the resposne. We try to detect the version + * is contained in the response. We try to detect the version * by the length of the data, but note that the detection algorithm * is incomplete. We assume the latest draft by default. */ if (nilen % (sizeof(u_int32_t) + sizeof(struct in6_addr)) == 0) withttl = 1; while (nilen > 0) { - u_int32_t ttl; + u_int32_t ttl = 0; if (withttl) { - /* XXX: alignment? */ - ttl = (u_int32_t)ntohl(*(u_int32_t *)cp); + uint32_t t; + + memcpy(&t, cp, sizeof(t)); + ttl = (u_int32_t)ntohl(t); cp += sizeof(u_int32_t); nilen -= sizeof(u_int32_t); } @@ -2059,9 +2207,8 @@ pr_nodeaddr(ni, nilen) } } -int -get_hoplim(mhdr) - struct msghdr *mhdr; +static int +get_hoplim(struct msghdr *mhdr) { struct cmsghdr *cm; @@ -2072,17 +2219,21 @@ get_hoplim(mhdr) if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_HOPLIMIT && - cm->cmsg_len == CMSG_LEN(sizeof(int))) - return(*(int *)CMSG_DATA(cm)); + cm->cmsg_len == CMSG_LEN(sizeof(int))) { + int r; + + memcpy(&r, CMSG_DATA(cm), sizeof(r)); + return(r); + } } return(-1); } -struct in6_pktinfo * -get_rcvpktinfo(mhdr) - struct msghdr *mhdr; +static struct in6_pktinfo * +get_rcvpktinfo(struct msghdr *mhdr) { + static struct in6_pktinfo pi; struct cmsghdr *cm; for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; @@ -2092,20 +2243,21 @@ get_rcvpktinfo(mhdr) if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO && - cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) - return((struct in6_pktinfo *)CMSG_DATA(cm)); + cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) { + memcpy(&pi, CMSG_DATA(cm), sizeof(pi)); + return(&pi); + } } return(NULL); } -int -get_pathmtu(mhdr) - struct msghdr *mhdr; +static int +get_pathmtu(struct msghdr *mhdr) { #ifdef IPV6_RECVPATHMTU struct cmsghdr *cm; - struct ip6_mtuinfo *mtuctl = NULL; + struct ip6_mtuinfo mtuctl; for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { @@ -2115,7 +2267,7 @@ get_pathmtu(mhdr) if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PATHMTU && cm->cmsg_len == CMSG_LEN(sizeof(struct ip6_mtuinfo))) { - mtuctl = (struct ip6_mtuinfo *)CMSG_DATA(cm); + memcpy(&mtuctl, CMSG_DATA(cm), sizeof(mtuctl)); /* * If the notified destination is different from @@ -2125,17 +2277,17 @@ get_pathmtu(mhdr) * have used the default scope zone ID for sending, * in which case the scope ID value is 0. */ - if (!IN6_ARE_ADDR_EQUAL(&mtuctl->ip6m_addr.sin6_addr, + if (!IN6_ARE_ADDR_EQUAL(&mtuctl.ip6m_addr.sin6_addr, &dst.sin6_addr) || - (mtuctl->ip6m_addr.sin6_scope_id && + (mtuctl.ip6m_addr.sin6_scope_id && dst.sin6_scope_id && - mtuctl->ip6m_addr.sin6_scope_id != + mtuctl.ip6m_addr.sin6_scope_id != dst.sin6_scope_id)) { if ((options & F_VERBOSE) != 0) { printf("path MTU for %s is notified. " "(ignored)\n", - pr_addr((struct sockaddr *)&mtuctl->ip6m_addr, - sizeof(mtuctl->ip6m_addr))); + pr_addr((struct sockaddr *)&mtuctl.ip6m_addr, + sizeof(mtuctl.ip6m_addr))); } return(0); } @@ -2144,85 +2296,17 @@ get_pathmtu(mhdr) * Ignore an invalid MTU. XXX: can we just believe * the kernel check? */ - if (mtuctl->ip6m_mtu < IPV6_MMTU) + if (mtuctl.ip6m_mtu < IPV6_MMTU) return(0); /* notification for our destination. return the MTU. */ - return((int)mtuctl->ip6m_mtu); + return((int)mtuctl.ip6m_mtu); } } #endif return(0); } -/* - * tvsub -- - * Subtract 2 timeval structs: out = out - in. Out is assumed to - * be >= in. - */ -void -tvsub(out, in) - struct timeval *out, *in; -{ - if ((out->tv_usec -= in->tv_usec) < 0) { - --out->tv_sec; - out->tv_usec += 1000000; - } - out->tv_sec -= in->tv_sec; -} - -/* - * onint -- - * SIGINT handler. - */ -/* ARGSUSED */ -void -onint(notused) - int notused; -{ - summary(); - - (void)signal(SIGINT, SIG_DFL); - (void)kill(getpid(), SIGINT); - - /* NOTREACHED */ - exit(1); -} - -/* - * summary -- - * Print out statistics. - */ -void -summary() -{ - (void)printf("\n--- %s ping6 statistics ---\n", hostname); - (void)printf("%ld packets transmitted, ", ntransmitted); - (void)printf("%ld packets received, ", nreceived); - if (nrepeats) - (void)printf("+%ld duplicates, ", nrepeats); - if (ntransmitted) { - if (nreceived > ntransmitted) - (void)printf("-- somebody's duplicating packets!"); - else - (void)printf("%.1f%% packet loss", - ((((double)ntransmitted - nreceived) * 100.0) / - ntransmitted)); - } - (void)putchar('\n'); - if (nreceived && timing) { - /* Only display average to microseconds */ - double num = nreceived + nrepeats; - double avg = tsum / num; - double dev = sqrt(tsumsq / num - avg * avg); - (void)printf( - "round-trip min/avg/max/std-dev = %.3f/%.3f/%.3f/%.3f ms\n", - tmin, avg, tmax, dev); - (void)fflush(stdout); - } - (void)fflush(stdout); -} - /*subject type*/ static const char *niqcode[] = { "IPv6 address", @@ -2240,10 +2324,8 @@ static const char *nircode[] = { * pr_icmph -- * Print a descriptive string about an ICMP header. */ -void -pr_icmph(icp, end) - struct icmp6_hdr *icp; - u_char *end; +static void +pr_icmph(struct icmp6_hdr *icp, u_char *end) { char ntop_buf[INET6_ADDRSTRLEN]; struct nd_redirect *red; @@ -2410,8 +2492,9 @@ pr_icmph(icp, end) } printf(", subject=%s", niqcode[ni->ni_code]); cp = (const u_char *)(ni + 1); - if (dnsdecode(&cp, end, NULL, dnsname, - sizeof(dnsname)) != NULL) + cp = dnsdecode(cp, end, NULL, dnsname, + sizeof(dnsname)); + if (cp != NULL) printf("(%s)", dnsname); else printf("(invalid)"); @@ -2457,7 +2540,7 @@ pr_icmph(icp, end) break; } if (options & F_VERBOSE) { - if (ni->ni_code > sizeof(nircode) / sizeof(nircode[0])) + if (ni->ni_code > nitems(nircode)) printf(", invalid"); else printf(", %s", nircode[ni->ni_code]); @@ -2472,9 +2555,8 @@ pr_icmph(icp, end) * pr_iph -- * Print an IP6 header. */ -void -pr_iph(ip6) - struct ip6_hdr *ip6; +static void +pr_iph(struct ip6_hdr *ip6) { u_int32_t flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; u_int8_t tc; @@ -2501,18 +2583,20 @@ pr_iph(ip6) * Return an ascii host address as a dotted quad and optionally with * a hostname. */ -const char * -pr_addr(addr, addrlen) - struct sockaddr *addr; - int addrlen; +static const char * +pr_addr(struct sockaddr *addr, int addrlen) { static char buf[NI_MAXHOST]; int flag = 0; - if ((options & F_HOSTNAME) == 0) + if (!(options & F_HOSTNAME)) flag |= NI_NUMERICHOST; - if (getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, flag) == 0) +#ifdef __HAIKU__ +#define cap_getnameinfo(p1,p2,p3,p4,p5,p6,p7,p8) getnameinfo(p2,p3,p4,p5,p6,p7,p8) +#endif + if (cap_getnameinfo(capdns, addr, addrlen, buf, sizeof(buf), NULL, 0, + flag) == 0) return (buf); else return "?"; @@ -2522,15 +2606,13 @@ pr_addr(addr, addrlen) * pr_retip -- * Dump some info on a returned (via ICMPv6) IPv6 packet. */ -void -pr_retip(ip6, end) - struct ip6_hdr *ip6; - u_char *end; +static void +pr_retip(struct ip6_hdr *ip6, u_char *end) { u_char *cp = (u_char *)ip6, nh; int hlen; - if (end - (u_char *)ip6 < sizeof(*ip6)) { + if ((size_t)(end - (u_char *)ip6) < sizeof(*ip6)) { printf("IP6"); goto trunc; } @@ -2540,6 +2622,10 @@ pr_retip(ip6, end) nh = ip6->ip6_nxt; cp += hlen; while (end - cp >= 8) { +#ifdef IPSEC + struct ah ah; +#endif + switch (nh) { case IPPROTO_HOPOPTS: printf("HBH "); @@ -2564,8 +2650,9 @@ pr_retip(ip6, end) #ifdef IPSEC case IPPROTO_AH: printf("AH "); - hlen = (((struct ah *)cp)->ah_len+2) << 2; - nh = ((struct ah *)cp)->ah_nxt; + memcpy(&ah, cp, sizeof(ah)); + hlen = (ah.ah_len+2) << 2; + nh = ah.ah_nxt; break; #endif case IPPROTO_ICMPV6: @@ -2604,9 +2691,8 @@ pr_retip(ip6, end) return; } -void -fill(bp, patp) - char *bp, *patp; +static void +fill(char *bp, char *patp) { int ii, jj, kk; int pat[16]; @@ -2624,7 +2710,7 @@ fill(bp, patp) /* xxx */ if (ii > 0) for (kk = 0; - kk <= MAXDATALEN - (8 + sizeof(struct tv32) + ii); + (size_t)kk <= MAXDATALEN - 8 + sizeof(struct tv32) + ii; kk += ii) for (jj = 0; jj < ii; ++jj) bp[jj + kk] = pat[jj]; @@ -2638,10 +2724,8 @@ fill(bp, patp) #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC -int -setpolicy(so, policy) - int so; - char *policy; +static int +setpolicy(int so __unused, char *policy) { char *buf; @@ -2651,7 +2735,7 @@ setpolicy(so, policy) buf = ipsec_set_policy(policy, strlen(policy)); if (buf == NULL) errx(1, "%s", ipsec_strerror()); - if (setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, buf, + if (setsockopt(ssend, IPPROTO_IPV6, IPV6_IPSEC_POLICY, buf, ipsec_get_policylen(buf)) < 0) warnx("Unable to set IPsec policy"); free(buf); @@ -2661,30 +2745,93 @@ setpolicy(so, policy) #endif #endif -void -usage() +#ifndef __HAIKU__ +static char * +nigroup(char *name, int nig_oldmcprefix) { - (void)fprintf(stderr, -#if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC) - "A" -#endif - "usage: ping6 [-" - "d" -#if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC) - "E" -#endif - "fH" -#ifdef IPV6_USE_MIN_MTU - "m" -#endif - "noqrRtvwW] " - "[-a addrtype] [-b bufsiz] [-c count]\n" - " [-h hoplimit] [-I interface] [-i wait] [-l preload]" -#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) - " [-P policy]" -#endif - "\n" - " [-p pattern] [-S sourceaddr] [-s packetsize] " - "[hops ...] host\n"); - exit(1); + char *p; + char *q; + MD5_CTX ctxt; + u_int8_t digest[16]; + u_int8_t c; + size_t l; + char hbuf[NI_MAXHOST]; + struct in6_addr in6; + int valid; + + p = strchr(name, '.'); + if (!p) + p = name + strlen(name); + l = p - name; + if (l > 63 || l > sizeof(hbuf) - 1) + return NULL; /*label too long*/ + strncpy(hbuf, name, l); + hbuf[(int)l] = '\0'; + + for (q = name; *q; q++) { + if (isupper(*(unsigned char *)q)) + *q = tolower(*(unsigned char *)q); + } + + /* generate 16 bytes of pseudo-random value. */ + memset(&ctxt, 0, sizeof(ctxt)); + MD5Init(&ctxt); + c = l & 0xff; + MD5Update(&ctxt, &c, sizeof(c)); + MD5Update(&ctxt, (unsigned char *)name, l); + MD5Final(digest, &ctxt); + + if (nig_oldmcprefix) { + /* draft-ietf-ipngwg-icmp-name-lookup */ + valid = inet_pton(AF_INET6, "ff02::2:0000:0000", &in6); + } else { + /* RFC 4620 */ + valid = inet_pton(AF_INET6, "ff02::2:ff00:0000", &in6); + } + if (valid != 1) + return NULL; /*XXX*/ + + if (nig_oldmcprefix) { + /* draft-ietf-ipngwg-icmp-name-lookup */ + bcopy(digest, &in6.s6_addr[12], 4); + } else { + /* RFC 4620 */ + bcopy(digest, &in6.s6_addr[13], 3); + } + + if (inet_ntop(AF_INET6, &in6, hbuf, sizeof(hbuf)) == NULL) + return NULL; + + return strdup(hbuf); } +#endif + +#ifndef __HAIKU__ +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"); + capdnsloc = cap_service_open(capcas, "system.dns"); + /* Casper capability no longer needed. */ + 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, nitems(types)) < 0) + err(1, "unable to limit access to system.dns service"); + families[0] = AF_INET6; + if (cap_dns_family_limit(capdnsloc, families, nitems(families)) < 0) + err(1, "unable to limit access to system.dns service"); +#endif + return (capdnsloc); +} +#endif diff --git a/src/bin/network/ping/ping6.h b/src/bin/network/ping/ping6.h new file mode 100644 index 0000000000..b0d75e6a4c --- /dev/null +++ b/src/bin/network/ping/ping6.h @@ -0,0 +1,34 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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. + */ + +#ifndef PING6_H +#define PING6_H 1 + +int ping6(int argc, char *argv[]); + +#endif diff --git a/src/bin/network/ping/utils.c b/src/bin/network/ping/utils.c new file mode 100644 index 0000000000..e723f690be --- /dev/null +++ b/src/bin/network/ping/utils.c @@ -0,0 +1,84 @@ +/*- + * 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. + */ + +#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/src/bin/network/ping/utils.h b/src/bin/network/ping/utils.h new file mode 100644 index 0000000000..758cac3c9e --- /dev/null +++ b/src/bin/network/ping/utils.h @@ -0,0 +1,36 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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. + */ + +#ifndef UTILS_H +#define UTILS_H 1 + +#include + +u_short in_cksum(u_char *, int); + +#endif diff --git a/src/bin/network/ping6/Jamfile b/src/bin/network/ping6/Jamfile deleted file mode 100644 index ca1a46b8d4..0000000000 --- a/src/bin/network/ping6/Jamfile +++ /dev/null @@ -1,7 +0,0 @@ -SubDir HAIKU_TOP src bin network ping6 ; - -UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility bsd ] : true ; - -BinCommand ping6 : - ping6.c - : libbsd.so $(TARGET_NETWORK_LIBS) $(TARGET_SELECT_UNAME_ETC_LIB) ; diff --git a/src/data/package_infos/generic/haiku b/src/data/package_infos/generic/haiku index 05f9ec692c..795f005962 100644 --- a/src/data/package_infos/generic/haiku +++ b/src/data/package_infos/generic/haiku @@ -36,7 +36,6 @@ provides { cmd:passwd cmd:pidof cmd:ping - cmd:ping6 cmd:prio cmd:ps cmd:renice