diff options
author | 2016-09-17 18:42:10 +0000 | |
---|---|---|
committer | 2016-09-17 18:42:10 +0000 | |
commit | d2d8382b998ab14503e5cbfec3e708fffc444bb4 (patch) | |
tree | 6bad87312f17d89f418520cfb7948ba9d804d7c8 | |
parent | unhook ping6 from the build (diff) | |
download | wireguard-openbsd-d2d8382b998ab14503e5cbfec3e708fffc444bb4.tar.xz wireguard-openbsd-d2d8382b998ab14503e5cbfec3e708fffc444bb4.zip |
... and we have unification.
"Das tritt nach meiner Kenntnis... ist das sofort... unverzueglich..."
-rw-r--r-- | sbin/ping6/Makefile | 5 | ||||
-rw-r--r-- | sbin/ping6/ping6.8 | 345 | ||||
-rw-r--r-- | sbin/ping6/ping6.c | 1497 |
3 files changed, 0 insertions, 1847 deletions
diff --git a/sbin/ping6/Makefile b/sbin/ping6/Makefile deleted file mode 100644 index b3d111012e5..00000000000 --- a/sbin/ping6/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# $OpenBSD: Makefile,v 1.12 2016/09/17 15:03:39 florian Exp $ - -MAN= ping6.8 - -.include <bsd.prog.mk> diff --git a/sbin/ping6/ping6.8 b/sbin/ping6/ping6.8 deleted file mode 100644 index 03d49649331..00000000000 --- a/sbin/ping6/ping6.8 +++ /dev/null @@ -1,345 +0,0 @@ -.\" $OpenBSD: ping6.8,v 1.64 2016/09/03 16:22:26 akfaew Exp $ -.\" $KAME: ping6.8,v 1.57 2002/05/26 13:18:25 itojun Exp $ -.\" -.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. -.\" 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. -.\" 3. Neither the name of the project 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 PROJECT 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 PROJECT 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. -.\" -.Dd $Mdocdate: September 3 2016 $ -.Dt PING6 8 -.Os -.Sh NAME -.Nm ping6 -.Nd send ICMPv6 ECHO_REQUEST packets to network hosts -.Sh SYNOPSIS -.Nm ping6 -.Op Fl dEefHLmnqv -.Op Fl c Ar count -.Op Fl h Ar hoplimit -.Op Fl I Ar sourceaddr -.Op Fl i Ar wait -.Op Fl l Ar preload -.Op Fl p Ar pattern -.Op Fl s Ar packetsize -.Op Fl V Ar rtable -.Op Fl w Ar maxwait -.Ar host -.Sh DESCRIPTION -.Nm -uses the -ICMPv6 -protocol's mandatory -.Dv ICMP6_ECHO_REQUEST -datagram to elicit an -.Dv ICMP6_ECHO_REPLY -from a host or gateway. -.Dv ICMP6_ECHO_REQUEST -datagrams -.Pq Dq pings -have an IPv6 header, -followed by an -ICMPv6 -header formatted as documented in RFC 4443. -The options are as follows: -.Bl -tag -width Ds -.It Fl c Ar count -Stop after sending -.Pq and receiving -.Ar count -.Dv ECHO_RESPONSE -packets. -If -.Ar count -is 0, send an unlimited number of packets. -.It Fl d -Set the -.Dv SO_DEBUG -option on the socket being used. -.It Fl E -Emit an audible beep (by sending an ASCII BEL character to the -standard error output) when no packet is received before the next -packet is transmitted. -To cater for round-trip times that are longer than the interval -between transmissions, further missing packets cause a bell only -if the maximum number of unreceived packets has increased. -This option is disabled for flood pings. -.It Fl e -Emit an audible beep (by sending an ASCII BEL character to the -standard error output) after each non-duplicate response is received. -This option is disabled for flood pings. -.It Fl f -Flood ping. -Outputs packets as fast as they come back or one hundred times per second, -whichever is more. -For every -.Dv ECHO_REQUEST -sent a period -.Pq Sq \&. -is printed, while for every -.Dv ECHO_REPLY -received a backspace is printed. -This provides a rapid display of how many packets are being dropped. -Only the super-user may use this option. -.Bf -emphasis -This can be very hard on a network and should be used with caution. -.Ef -.It Fl H -Try reverse lookups for addresses. -.It Fl h Ar hoplimit -Set the IPv6 hoplimit. -.It Fl I Ar sourceaddr -Specifies the source address of request packets. -The source address must be one of the unicast addresses of the sending node, -and must be numeric. -.It Fl i Ar wait -Wait -.Ar wait -seconds -.Em between sending each packet . -The default is to wait for one second between each packet. -This option is incompatible with the -.Fl f -option. -.It Fl L -Disable the loopback, so the transmitting host doesn't see ICMP -requests. -For multicast pings. -.It Fl l Ar preload -If -.Ar preload -is specified, -.Nm -sends that many packets as fast as possible before falling into its normal -mode of behavior. -Only the super-user may use this option. -.It Fl m -By default, -.Nm -asks the kernel to fragment packets to fit into the minimum IPv6 MTU. -.Fl m -will suppress the behavior in the following two levels: -when the option is specified once, the behavior will be disabled for -unicast packets. -When the option is specified more than once, it will be disabled for both -unicast and multicast packets. -.It Fl n -Numeric output only. -No attempt will be made to look up symbolic names from addresses in the reply. -.It Fl p Ar pattern -Up to 16 -.Dq pad -bytes may be specified to fill out the packet sent. -This is useful for diagnosing data-dependent problems in a network. -For example, -.Dq -p ff -will cause the packet sent to be filled with all -ones. -.\" new ipsec -.\".It Fl P Ar policy -.\".Ar policy -.\"specifies IPsec policy to be used for the probe. -.It Fl q -Quiet output. -Nothing is displayed except the summary lines at startup time and -when finished. -.\".It Fl R -.\"Make the kernel believe that the target -.\".Ar host -.\".Po -.\"or the first -.\".Ar hop -.\"if you specify -.\".Ar hops -.\".Pc -.\"is reachable, by injecting upper-layer reachability confirmation hint. -.\"The option is meaningful only if the target -.\".Ar host -.\".Pq or the first hop -.\"is a neighbor. -.It Fl s Ar packetsize -Specifies the number of data bytes to be sent. -The default is 24, -which translates into 32 ICMP data bytes -when combined with the 8 bytes of ICMP header data. -The maximum packet size is 65527. -.It Fl V Ar rtable -Set the routing table to be used for outgoing packets. -.It Fl v -Verbose output. -All ICMP packets -that are received are listed. -.It Fl w Ar maxwait -Specifies the maximum number of seconds to wait for responses -after the last request has been sent. -The default is 10. -.El -.Pp -When using -.Nm -for fault isolation, it should first be run on the local host, to verify -that the local network interface is up and running. -Then hosts and gateways further and further away can be -.Dq pinged . -Round-trip times and packet loss statistics are computed. -If duplicate packets are received, they are not included in the packet -loss calculation, although the round trip time of these packets is used -in calculating the round-trip time statistics. -When the specified number of packets have been sent -.Pq and received -or if the program is terminated with a -.Dv SIGINT , -a brief summary is displayed, showing the number of packets sent and -received, and the minimum, maximum, mean, and standard deviation of -the round-trip times. -.Pp -This program is intended for use in network testing, measurement, and -management. -Because of the load it can impose on the network, it is unwise to use -.Nm -during normal operations or from automated scripts. -.\" .Sh ICMP PACKET DETAILS -.\" An IP header without options is 20 bytes. -.\" An -.\" .Tn ICMP -.\" .Tn ECHO_REQUEST -.\" packet contains an additional 8 bytes worth of -.\" .Tn ICMP -.\" header followed by an arbitrary amount of data. -.\" When a -.\" .Ar packetsize -.\" is given, this indicated the size of this extra piece of data -.\" .Pq the default is 56 . -.\" Thus the amount of data received inside of an IP packet of type -.\" .Tn ICMP -.\" .Tn ECHO_REPLY -.\" will always be 8 bytes more than the requested data space -.\" .Pq the Tn ICMP header . -.\" .Pp -.\" If the data space is at least eight bytes large, -.\" .Nm -.\" uses the first eight bytes of this space to include a timestamp which -.\" it uses in the computation of round trip times. -.\" If less than eight bytes of pad are specified, no round trip times are -.\" given. -.Sh DUPLICATE AND DAMAGED PACKETS -.Nm -will report duplicate and damaged packets. -Duplicate packets should never occur when pinging a unicast address, -and seem to be caused by -inappropriate link-level retransmissions. -Duplicates may occur in many situations and are rarely -.Pq if ever -a good sign, although the presence of low levels of duplicates may not -always be cause for alarm. -Duplicates are expected when pinging a broadcast or multicast address, -since they are not really duplicates but replies from different hosts -to the same request. -.Pp -Damaged packets are obviously serious cause for alarm and often -indicate broken hardware somewhere in the -.Nm -packet's path -.Pq in the network or in the hosts . -.Sh TRYING DIFFERENT DATA PATTERNS -The -(inter)network -layer should never treat packets differently depending on the data -contained in the data portion. -Unfortunately, data-dependent problems have been known to sneak into -networks and remain undetected for long periods of time. -In many cases the particular pattern that will have problems is something -that does not have sufficient -.Dq transitions , -such as all ones or all zeros, or a pattern right at the edge, such as -almost all zeros. -It is not -necessarily enough to specify a data pattern of all zeros (for example) -on the command line because the pattern that is of interest is -at the data link level, and the relationship between what is typed and -what the controllers transmit can be complicated. -.Pp -This means that if there is a data-dependent problem, -a lot of testing will probably have to be done to find it. -It may be possible to find a file that either cannot -be sent across the network or that takes much longer to transfer than -other similar length files. -This file can then be examined for repeated patterns that can be tested -using the -.Fl p -option. -.Sh EXIT STATUS -.Nm -exits 0 if at least one reply is received, -and \*(Gt0 if no reply is received or an error occurred. -.Sh EXAMPLES -Normally, -.Nm -works just like -.Xr ping 8 -would work; the following will send ICMPv6 echo requests to dst.foo.com: -.Bd -literal -offset indent -$ ping6 -n dst.foo.com -.Ed -.Pp -The following will send ICMPv6 echo requests to the link-local all-node -multicast address. -The packet reaches all nodes on the network link attached to the wi0 -interface. -.Bd -literal -offset indent -$ ping6 ff02::1%wi0 -.Ed -.Sh SEE ALSO -.Xr netstat 1 , -.Xr icmp6 4 , -.Xr inet6 4 , -.Xr ip6 4 , -.Xr ifconfig 8 , -.Xr ping 8 , -.Xr route6d 8 , -.Xr traceroute6 8 -.Sh STANDARDS -.Rs -.%A A. Conta -.%A S. Deering -.%A M. Gupta -.%D March 2006 -.%R RFC 4443 -.%T "Internet Control Message Protocol (ICMPv6) for the Internet Protocol Version 6 (IPv6) Specification" -.Re -.Sh HISTORY -The -.Xr ping 8 -command first appeared in -.Bx 4.3 . -The -.Nm -command with IPv6 support first appeared in the WIDE Hydrangea IPv6 -protocol stack kit. -.Sh BUGS -.\" except for bsdi -.Nm -is intentionally separate from -.Xr ping 8 . diff --git a/sbin/ping6/ping6.c b/sbin/ping6/ping6.c deleted file mode 100644 index fee3ae70781..00000000000 --- a/sbin/ping6/ping6.c +++ /dev/null @@ -1,1497 +0,0 @@ -/* $OpenBSD: ping6.c,v 1.222 2016/09/17 09:39:09 florian Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. - * 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. - * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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. - */ - -/* - * 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. - */ - -/* - * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility, - * measure round-trip-delays and packet loss across network paths. - * - * Author - - * Mike Muuss - * U. S. Army Ballistic Research Laboratory - * December, 1983 - * - * Status - - * Public Domain. Distribution Unlimited. - * Bugs - - * More statistics could always be gathered. - * This program has to run SUID to ROOT to access the ICMP socket. - */ - -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/time.h> -#include <sys/uio.h> - -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/ip_icmp.h> -#include <netinet/ip_var.h> -#include <netinet/ip6.h> -#include <netinet/icmp6.h> -#include <netinet/ip_ah.h> -#include <arpa/inet.h> -#include <netdb.h> - -#include <ctype.h> -#include <err.h> -#include <errno.h> -#include <limits.h> -#include <math.h> -#include <poll.h> -#include <signal.h> -#include <siphash.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> - -struct tv64 { - u_int64_t tv64_sec; - u_int64_t tv64_nsec; -}; - -struct payload { - struct tv64 tv64; - u_int8_t mac[SIPHASH_DIGEST_LENGTH]; -}; - -#define ECHOLEN 8 /* icmp echo header len excluding time */ -#define ECHOTMLEN sizeof(struct payload) -#define DEFDATALEN (64 - ECHOLEN) /* default data length */ -#define IP6LEN 40 -#define EXTRA 256 /* for AH and various other headers. weird. */ -#define MAXPAYLOAD6 IPV6_MAXPACKET - IP6LEN - ECHOLEN -#define MAXWAIT_DEFAULT 10 /* secs to wait for response */ - -#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ -#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ -#define SET(bit) (A(bit) |= B(bit)) -#define CLR(bit) (A(bit) &= (~B(bit))) -#define TST(bit) (A(bit) & B(bit)) - -/* various options */ -int options; -#define F_FLOOD 0x0001 -#define F_INTERVAL 0x0002 -#define F_HOSTNAME 0x0004 -#define F_PINGFILLED 0x0008 -#define F_QUIET 0x0010 -/* 0x0020 */ -#define F_SO_DEBUG 0x0040 -/* 0x0080 */ -#define F_VERBOSE 0x0100 -/* 0x0200 */ -/* 0x0400 */ -/* 0x0800 */ -/* 0x1000 */ -#define F_AUD_RECV 0x2000 -#define F_AUD_MISS 0x4000 - -/* multicast options */ -int moptions; -#define MULTICAST_NOLOOP 0x001 - -#define DUMMY_PORT 10101 - -/* - * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum - * number of received sequence numbers we can keep track of. Change 128 - * 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]; - -int datalen = DEFDATALEN; -int maxpayload; -u_char outpackhdr[IP_MAXPACKET+sizeof(struct ip)]; -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 */ - -/* counters */ -int64_t npackets; /* max packets to transmit */ -int64_t nreceived; /* # of packets we got back */ -int64_t nrepeats; /* number of duplicates */ -int64_t ntransmitted; /* sequence # for outbound packets = #sent */ -int64_t nmissedmax = 1; /* max value of ntransmitted - nreceived - 1 */ -struct timeval interval = {1, 0}; /* interval between packets */ - -/* timing */ -int timing = 0; /* flag to do timing */ -int timinginfo = 0; -unsigned int maxwait = MAXWAIT_DEFAULT; /* max seconds to wait for response */ -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. */ - -struct tv64 tv64_offset; -SIPHASH_KEY mac_key; - -struct msghdr smsghdr; -struct iovec smsgiov; - -volatile sig_atomic_t seenalrm; -volatile sig_atomic_t seenint; -volatile sig_atomic_t seeninfo; - -void fill(char *, char *); -void summary(void); -void onsignal(int); -void retransmit(int); -int pinger(int); -const char *pr_addr(struct sockaddr *, socklen_t); -void pr_pack(u_char *, int, struct msghdr *); -__dead void usage(void); - -int get_hoplim(struct msghdr *); -int get_pathmtu(struct msghdr *, struct sockaddr_in6 *); -void pr_icmph6(struct icmp6_hdr *, u_char *); -void pr_iph6(struct ip6_hdr *); -void pr_exthdrs(struct msghdr *); -void pr_ip6opt(void *); -void pr_rthdr(void *); -void pr_retip6(struct ip6_hdr *, u_char *); - -int -main(int argc, char *argv[]) -{ - struct addrinfo hints, *res; - struct itimerval itimer; - struct sockaddr *from, *dst; - struct sockaddr_in6 from6, dst6; - struct cmsghdr *scmsg = NULL; - struct in6_pktinfo *pktinfo = NULL; - struct icmp6_filter filt; - socklen_t maxsizelen; - int64_t preload; - int ch, i, optval = 1, packlen, maxsize, error, s, hoplimit = -1; - int bufspace = IP_MAXPACKET; - u_char *datap, *packet, loop = 1; - char *e, *target, hbuf[NI_MAXHOST], *source = NULL; - const char *errstr; - double intval; - int mflag = 0; - uid_t uid; - u_int rtableid = 0; - - if ((s = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) - err(1, "socket"); - - /* revoke privs */ - uid = getuid(); - if (setresuid(uid, uid, uid) == -1) - err(1, "setresuid"); - - preload = 0; - maxpayload = MAXPAYLOAD6; - datap = &outpack[ECHOLEN + ECHOTMLEN]; - while ((ch = getopt(argc, argv, - "c:dEefHh:I:i:Ll:mNnp:qS:s:V:vw:")) != -1) { - switch (ch) { - case 'c': - npackets = strtonum(optarg, 0, INT64_MAX, &errstr); - if (errstr) - errx(1, - "number of packets to transmit is %s: %s", - errstr, optarg); - break; - case 'd': - options |= F_SO_DEBUG; - break; - case 'E': - options |= F_AUD_MISS; - break; - case 'e': - options |= F_AUD_RECV; - break; - case 'f': - if (getuid()) - errx(1, "%s", strerror(EPERM)); - options |= F_FLOOD; - setvbuf(stdout, NULL, _IONBF, 0); - break; - case 'H': - options |= F_HOSTNAME; - break; - case 'h': /* hoplimit */ - hoplimit = strtonum(optarg, 0, IPV6_MAXHLIM, &errstr); - if (errstr) - errx(1, "hoplimit is %s: %s", errstr, optarg); - break; - case 'I': - case 'S': /* deprecated */ - source = optarg; - break; - case 'i': /* wait between sending packets */ - intval = strtod(optarg, &e); - if (*optarg == '\0' || *e != '\0') - errx(1, "illegal timing interval %s", optarg); - if (intval < 1 && getuid()) { - errx(1, "%s: only root may use interval < 1s", - strerror(EPERM)); - } - interval.tv_sec = (time_t)intval; - interval.tv_usec = - (long)((intval - interval.tv_sec) * 1000000); - if (interval.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 < 10000) { - warnx("too small interval, raised to 0.01"); - interval.tv_usec = 10000; - } - options |= F_INTERVAL; - break; - case 'L': - moptions |= MULTICAST_NOLOOP; - loop = 0; - break; - case 'l': - if (getuid()) - errx(1, "%s", strerror(EPERM)); - preload = strtonum(optarg, 1, INT64_MAX, &errstr); - if (errstr) - errx(1, "preload value is %s: %s", errstr, - optarg); - break; - case 'm': - mflag++; - break; - case 'n': - options &= ~F_HOSTNAME; - break; - case 'p': /* fill buffer with user pattern */ - options |= F_PINGFILLED; - fill((char *)datap, optarg); - break; - case 'q': - options |= F_QUIET; - break; - case 's': /* size of packet to send */ - datalen = strtonum(optarg, 0, maxpayload, &errstr); - if (errstr) - errx(1, "packet size is %s: %s", errstr, - optarg); - break; - case 'V': - rtableid = strtonum(optarg, 0, RT_TABLEID_MAX, &errstr); - if (errstr) - errx(1, "rtable value is %s: %s", errstr, - optarg); - if (setsockopt(s, SOL_SOCKET, SO_RTABLE, &rtableid, - sizeof(rtableid)) == -1) - err(1, "setsockopt SO_RTABLE"); - break; - case 'v': - options |= F_VERBOSE; - break; - case 'w': - maxwait = strtonum(optarg, 1, INT_MAX, &errstr); - if (errstr) - errx(1, "maxwait value is %s: %s", - errstr, optarg); - break; - default: - usage(); - } - } - - argc -= optind; - argv += optind; - - if (argc != 1) - usage(); - - memset(&dst6, 0, sizeof(dst6)); - -#if 0 - if (inet_aton(*argv, &dst4.sin_addr) != 0) { - hostname = *argv; - if ((target = strdup(inet_ntoa(dst4.sin_addr))) == NULL) - err(1, "malloc"); - } else -#endif - target = *argv; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET6; - hints.ai_socktype = SOCK_RAW; - hints.ai_protocol = 0; - hints.ai_flags = AI_CANONNAME; - if ((error = getaddrinfo(target, NULL, &hints, &res))) - errx(1, "%s", gai_strerror(error)); - - switch (res->ai_family) { - case AF_INET6: - if (res->ai_addrlen != sizeof(dst6)) - errx(1, "size of sockaddr mismatch"); - dst = (struct sockaddr *)&dst6; - from = (struct sockaddr *)&from6; - break; - case AF_INET: - default: - errx(1, "unsupported AF: %d", res->ai_family); - break; - } - - memcpy(dst, res->ai_addr, res->ai_addrlen); - - if (!hostname) { - hostname = res->ai_canonname ? strdup(res->ai_canonname) : - target; - if (!hostname) - err(1, "malloc"); - } - - if (res->ai_next) { - if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, - sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) - strlcpy(hbuf, "?", sizeof(hbuf)); - warnx("Warning: %s has multiple " - "addresses; using %s", hostname, hbuf); - } - freeaddrinfo(res); - - if (source) { - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET6; - if ((error = getaddrinfo(source, NULL, &hints, &res))) - errx(1, "%s: %s", source, gai_strerror(error)); - if (res->ai_family != AF_INET6 || res->ai_addrlen != - sizeof(from6)) - errx(1, "invalid source address"); - memcpy(from, res->ai_addr, res->ai_addrlen); - freeaddrinfo(res); - if (bind(s, from, from->sa_len) < 0) - err(1, "bind"); - } else if (options & F_VERBOSE) { - /* - * get the source address. XXX since we revoked the root - * privilege, we cannot use a raw socket for this. - */ - int dummy; - socklen_t len = dst->sa_len; - - if ((dummy = socket(dst->sa_family, SOCK_DGRAM, 0)) < 0) - err(1, "UDP socket"); - - memcpy(from, dst, dst->sa_len); - from6.sin6_port = ntohs(DUMMY_PORT); - - if (pktinfo && - setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTINFO, - (void *)pktinfo, sizeof(*pktinfo))) - err(1, "UDP setsockopt(IPV6_PKTINFO)"); - - if (hoplimit != -1 && - setsockopt(dummy, IPPROTO_IPV6, IPV6_UNICAST_HOPS, - (void *)&hoplimit, sizeof(hoplimit))) - err(1, "UDP setsockopt(IPV6_UNICAST_HOPS)"); - - if (hoplimit != -1 && - setsockopt(dummy, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, - (void *)&hoplimit, sizeof(hoplimit))) - err(1, "UDP setsockopt(IPV6_MULTICAST_HOPS)"); - - if (rtableid > 0 && - setsockopt(dummy, SOL_SOCKET, SO_RTABLE, &rtableid, - sizeof(rtableid)) < 0) - err(1, "setsockopt(SO_RTABLE)"); - - if (connect(dummy, from, len) < 0) - err(1, "UDP connect"); - - if (getsockname(dummy, from, &len) < 0) - err(1, "getsockname"); - - close(dummy); - } - - if (options & F_SO_DEBUG) - (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, &optval, - sizeof(optval)); - - if ((options & F_FLOOD) && (options & F_INTERVAL)) - errx(1, "-f and -i options are incompatible"); - - if ((options & F_FLOOD) && (options & (F_AUD_RECV | F_AUD_MISS))) - warnx("No audible output for flood pings"); - - if (datalen >= sizeof(struct payload)) /* can we time transfer */ - timing = 1; - - /* in F_VERBOSE case, we may get non-echoreply packets*/ - if (options & F_VERBOSE && datalen < 2048) - packlen = 2048 + IP6LEN + ECHOLEN + EXTRA; /* XXX 2048? */ - else - packlen = datalen + IP6LEN + ECHOLEN + EXTRA; - - if (!(packet = malloc(packlen))) - err(1, "malloc"); - - if (!(options & F_PINGFILLED)) - for (i = ECHOTMLEN; i < datalen; ++i) - *datap++ = i; - - ident = getpid() & 0xFFFF; - - /* - * 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. - */ - 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 < IP_MAXPACKET) - warnx("Could only allocate a receive buffer of %d bytes " - "(default %d)", bufspace, IP_MAXPACKET); - - /* - * let the kernel pass extension headers of incoming packets, - * for privileged socket options - */ - if ((options & F_VERBOSE) != 0) { - int opton = 1; - - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &opton, - (socklen_t)sizeof(opton))) - err(1, "setsockopt(IPV6_RECVHOPOPTS)"); - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTOPTS, &opton, - (socklen_t)sizeof(opton))) - err(1, "setsockopt(IPV6_RECVDSTOPTS)"); - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDR, &opton, - sizeof(opton))) - err(1, "setsockopt(IPV6_RECVRTHDR)"); - ICMP6_FILTER_SETPASSALL(&filt); - } else { - ICMP6_FILTER_SETBLOCKALL(&filt); - ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt); - } - - if ((moptions & MULTICAST_NOLOOP) && - setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop, - sizeof(loop)) < 0) - err(1, "setsockopt IP6_MULTICAST_LOOP"); - - optval = IPV6_DEFHLIM; - if (IN6_IS_ADDR_MULTICAST(&dst6.sin6_addr)) - if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, - &optval, (socklen_t)sizeof(optval)) == -1) - err(1, "IPV6_MULTICAST_HOPS"); - if (mflag != 1) { - optval = mflag > 1 ? 0 : 1; - - if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU, - &optval, (socklen_t)sizeof(optval)) == -1) - err(1, "setsockopt(IPV6_USE_MIN_MTU)"); - } else { - optval = 1; - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPATHMTU, - &optval, sizeof(optval)) == -1) - err(1, "setsockopt(IPV6_RECVPATHMTU)"); - } - - if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, - (socklen_t)sizeof(filt)) < 0) - err(1, "setsockopt(ICMP6_FILTER)"); - - if (hoplimit != -1) { - /* set IP6 packet options */ - if ((scmsg = malloc( CMSG_SPACE(sizeof(int)))) == NULL) - err(1, "malloc"); - smsghdr.msg_control = (caddr_t)scmsg; - smsghdr.msg_controllen = CMSG_SPACE(sizeof(int)); - - scmsg->cmsg_len = CMSG_LEN(sizeof(int)); - scmsg->cmsg_level = IPPROTO_IPV6; - scmsg->cmsg_type = IPV6_HOPLIMIT; - *(int *)(CMSG_DATA(scmsg)) = hoplimit; - } - - optval = 1; - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &optval, - (socklen_t)sizeof(optval)) < 0) - warn("setsockopt(IPV6_RECVPKTINFO)"); /* XXX err? */ - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &optval, - (socklen_t)sizeof(optval)) < 0) - warn("setsockopt(IPV6_RECVHOPLIMIT)"); /* XXX err? */ - - if (options & F_HOSTNAME) { - if (pledge("stdio inet dns", NULL) == -1) - err(1, "pledge"); - } else { - if (pledge("stdio inet", NULL) == -1) - err(1, "pledge"); - } - - arc4random_buf(&tv64_offset, sizeof(tv64_offset)); - arc4random_buf(&mac_key, sizeof(mac_key)); - - printf("PING6 %s (", hostname); - if (options & F_VERBOSE) - printf("%s --> ", pr_addr(from, from->sa_len)); - printf("%s): %d data bytes\n", pr_addr(dst, dst->sa_len), datalen); - - smsghdr.msg_name = dst; - smsghdr.msg_namelen = dst->sa_len; - smsgiov.iov_base = (caddr_t)outpack; - smsghdr.msg_iov = &smsgiov; - smsghdr.msg_iovlen = 1; - - while (preload--) /* Fire off them quickies. */ - pinger(s); - - (void)signal(SIGINT, onsignal); - (void)signal(SIGINFO, onsignal); - - 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(s); - } - - seenalrm = seenint = 0; - seeninfo = 0; - - for (;;) { - struct msghdr m; - union { - struct cmsghdr hdr; - u_char buf[CMSG_SPACE(1024)]; - } cmsgbuf; - struct iovec iov[1]; - struct pollfd pfd; - struct sockaddr_in6 peer; - ssize_t cc; - int timeout; - - /* signal handling */ - if (seenint) - break; - if (seenalrm) { - retransmit(s); - seenalrm = 0; - if (ntransmitted - nreceived - 1 > nmissedmax) { - nmissedmax = ntransmitted - nreceived - 1; - if (!(options & F_FLOOD) && - (options & F_AUD_MISS)) - (void)fputc('\a', stderr); - } - continue; - } - if (seeninfo) { - summary(); - seeninfo = 0; - continue; - } - - if (options & F_FLOOD) { - (void)pinger(s); - timeout = 10; - } else - timeout = INFTIM; - - pfd.fd = s; - pfd.events = POLLIN; - - if (poll(&pfd, 1, timeout) <= 0) - continue; - - m.msg_name = &peer; - m.msg_namelen = sizeof(peer); - 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; - m.msg_control = (caddr_t)&cmsgbuf.buf; - m.msg_controllen = sizeof(cmsgbuf.buf); - - cc = recvmsg(s, &m, 0); - if (cc < 0) { - if (errno != EINTR) { - warn("recvmsg"); - sleep(1); - } - continue; - } else if (cc == 0) { - int mtu; - - /* - * receive control messages only. Process the - * exceptions (currently the only possibility is - * a path MTU notification.) - */ - if ((mtu = get_pathmtu(&m, &dst6)) > 0) { - if ((options & F_VERBOSE) != 0) { - printf("new path MTU (%d) is " - "notified\n", mtu); - } - } - continue; - } else - pr_pack(packet, cc, &m); - - if (npackets && nreceived >= npackets) - break; - } - summary(); - exit(nreceived == 0); -} - -void -onsignal(int sig) -{ - switch (sig) { - case SIGALRM: - seenalrm++; - break; - case SIGINT: - seenint++; - break; - case SIGINFO: - seeninfo++; - break; - } -} - -void -fill(char *bp, char *patp) -{ - int ii, jj, kk; - int pat[16]; - char *cp; - - for (cp = patp; *cp; cp++) - if (!isxdigit((unsigned char)*cp)) - errx(1, "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], - &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12], - &pat[13], &pat[14], &pat[15]); - - if (ii > 0) - for (kk = 0; - kk <= maxpayload - (ECHOLEN + ECHOTMLEN + ii); - kk += ii) - for (jj = 0; jj < ii; ++jj) - bp[jj + kk] = pat[jj]; - if (!(options & F_QUIET)) { - (void)printf("PATTERN: 0x"); - for (jj = 0; jj < ii; ++jj) - (void)printf("%02x", bp[jj] & 0xFF); - (void)printf("\n"); - } -} - -void -summary(void) -{ - printf("\n--- %s ping6 statistics ---\n", hostname); - printf("%lld packets transmitted, ", ntransmitted); - printf("%lld packets received, ", nreceived); - - if (nrepeats) - printf("%lld duplicates, ", nrepeats); - if (ntransmitted) { - if (nreceived > ntransmitted) - printf("-- somebody's duplicating packets!"); - else - printf("%.1f%% packet loss", - ((((double)ntransmitted - nreceived) * 100) / - ntransmitted)); - } - printf("\n"); - if (timinginfo) { - /* Only display average to microseconds */ - double num = nreceived + nrepeats; - double avg = tsum / num; - double dev = sqrt(fmax(0, tsumsq / num - avg * avg)); - printf("round-trip min/avg/max/std-dev = %.3f/%.3f/%.3f/%.3f ms\n", - tmin, avg, tmax, dev); - } -} - -/* - * pr_addr -- - * Return address in numeric form or a host name - */ -const char * -pr_addr(struct sockaddr *addr, socklen_t addrlen) -{ - static char buf[NI_MAXHOST]; - int flag = 0; - - if ((options & F_HOSTNAME) == 0) - flag |= NI_NUMERICHOST; - - if (getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, flag) == 0) - return (buf); - else - return "?"; -} - -/* - * retransmit -- - * This routine transmits another ping6. - */ -void -retransmit(int s) -{ - struct itimerval itimer; - static int last_time = 0; - - if (last_time) { - seenint = 1; /* break out of ping event loop */ - return; - } - - if (pinger(s) == 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 - * maxwait seconds if we haven't. - */ - 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)setitimer(ITIMER_REAL, &itimer, NULL); - - /* When the alarm goes off we are done. */ - last_time = 1; -} - -/* - * 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. - */ -int -pinger(int s) -{ - struct icmp6_hdr *icp; - int cc, i; - u_int16_t seq; - - if (npackets && ntransmitted >= npackets) - return(-1); /* no more transmission */ - - seq = htons(ntransmitted++); - - icp = (struct icmp6_hdr *)outpack; - memset(icp, 0, sizeof(*icp)); - icp->icmp6_cksum = 0; - icp->icmp6_type = ICMP6_ECHO_REQUEST; - icp->icmp6_code = 0; - icp->icmp6_id = htons(ident); - icp->icmp6_seq = seq; - - CLR(ntohs(seq) % mx_dup_ck); - - if (timing) { - SIPHASH_CTX ctx; - struct timespec ts; - struct payload payload; - struct tv64 *tv64 = &payload.tv64; - - if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) - err(1, "clock_gettime(CLOCK_MONOTONIC)"); - tv64->tv64_sec = htobe64((u_int64_t)ts.tv_sec + - tv64_offset.tv64_sec); - tv64->tv64_nsec = htobe64((u_int64_t)ts.tv_nsec + - tv64_offset.tv64_nsec); - - SipHash24_Init(&ctx, &mac_key); - SipHash24_Update(&ctx, tv64, sizeof(*tv64)); - SipHash24_Update(&ctx, &ident, sizeof(ident)); - SipHash24_Update(&ctx, &seq, sizeof(seq)); - SipHash24_Final(&payload.mac, &ctx); - - memcpy(&outpack[ECHOLEN], &payload, sizeof(payload)); - } - - cc = ECHOLEN + datalen; - - smsgiov.iov_len = cc; - - i = sendmsg(s, &smsghdr, 0); - - if (i < 0 || i != cc) { - if (i < 0) - warn("sendmsg"); - printf("ping6: wrote %s %d chars, ret=%d\n", hostname, cc, i); - } - if (!(options & F_QUIET) && options & F_FLOOD) - (void)write(STDOUT_FILENO, &DOT, 1); - - return (0); -} - -/* - * pr_pack -- - * Print out the packet, if it came from us. This logic is necessary - * because ALL readers of the ICMP socket get a copy of ALL ICMP packets - * which arrive ('tis only fair). This permits multiple copies of this - * program to be run without having intermingled output (or statistics!). - */ -void -pr_pack(u_char *buf, int cc, struct msghdr *mhdr) -{ - struct icmp6_hdr *icp; - struct timespec ts, tp; - struct payload payload; - struct sockaddr *from; - socklen_t fromlen; - double triptime = 0; - int i, dupflag; - int hoplim; - u_int16_t seq; - u_char *cp = NULL, *dp, *end = buf + cc; - - if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) - err(1, "clock_gettime(CLOCK_MONOTONIC)"); - - if (!mhdr || !mhdr->msg_name || - mhdr->msg_namelen != sizeof(struct sockaddr_in6) || - ((struct sockaddr *)mhdr->msg_name)->sa_family != AF_INET6) { - if (options & F_VERBOSE) - warnx("invalid peername"); - return; - } - from = (struct sockaddr *)mhdr->msg_name; - fromlen = mhdr->msg_namelen; - if (cc < sizeof(struct icmp6_hdr)) { - if (options & F_VERBOSE) - warnx("packet too short (%d bytes) from %s", cc, - pr_addr(from, fromlen)); - return; - } - icp = (struct icmp6_hdr *)buf; - - if ((hoplim = get_hoplim(mhdr)) == -1) { - warnx("failed to get receiving hop limit"); - return; - } - - if (icp->icmp6_type == ICMP6_ECHO_REPLY) { - if (ntohs(icp->icmp6_id) != ident) - return; /* 'Twas not our ECHO */ - seq = icp->icmp6_seq; - ++nreceived; - if (cc >= ECHOLEN + ECHOTMLEN) { - SIPHASH_CTX ctx; - struct tv64 *tv64; - u_int8_t mac[SIPHASH_DIGEST_LENGTH]; - - memcpy(&payload, icp + 1, sizeof(payload)); - tv64 = &payload.tv64; - - SipHash24_Init(&ctx, &mac_key); - SipHash24_Update(&ctx, tv64, sizeof(*tv64)); - SipHash24_Update(&ctx, &ident, sizeof(ident)); - SipHash24_Update(&ctx, &seq, sizeof(seq)); - SipHash24_Final(mac, &ctx); - - if (timingsafe_memcmp(mac, &payload.mac, - sizeof(mac)) != 0) { - (void)printf("signature mismatch!\n"); - return; - } - timinginfo=1; - - tp.tv_sec = betoh64(tv64->tv64_sec) - - tv64_offset.tv64_sec; - tp.tv_nsec = betoh64(tv64->tv64_nsec) - - tv64_offset.tv64_nsec; - - timespecsub(&ts, &tp, &ts); - triptime = ((double)ts.tv_sec) * 1000.0 + - ((double)ts.tv_nsec) / 1000000.0; - tsum += triptime; - tsumsq += triptime * triptime; - if (triptime < tmin) - tmin = triptime; - if (triptime > tmax) - tmax = triptime; - } - - if (TST(ntohs(seq) % mx_dup_ck)) { - ++nrepeats; - --nreceived; - dupflag = 1; - } else { - SET(ntohs(seq) % mx_dup_ck); - dupflag = 0; - } - - if (options & F_QUIET) - return; - - if (options & F_FLOOD) - (void)write(STDOUT_FILENO, &BSPACE, 1); - else { - (void)printf("%d bytes from %s: icmp_seq=%u", cc, - pr_addr(from, fromlen), ntohs(seq)); - (void)printf(" hlim=%d", hoplim); - if (cc >= ECHOLEN + ECHOTMLEN) - (void)printf(" time=%.3f ms", triptime); - if (dupflag) - (void)printf(" (DUP!)"); - /* check the data */ - if (cc - ECHOLEN < datalen) - (void)printf(" (TRUNC!)"); - cp = buf + ECHOLEN + ECHOTMLEN; - dp = &outpack[ECHOLEN + ECHOTMLEN]; - for (i = ECHOLEN + ECHOTMLEN; - i < cc && i < datalen; - ++i, ++cp, ++dp) { - if (*cp != *dp) { - (void)printf("\nwrong data byte #%d " - "should be 0x%x but was 0x%x", - i - ECHOLEN, *dp, *cp); - cp = buf + ECHOLEN; - for (i = ECHOLEN; i < cc && i < datalen; - ++i, ++cp) { - if ((i % 32) == 8) - (void)printf("\n\t"); - (void)printf("%x ", *cp); - } - break; - } - } - } - } else { - /* We've got something other than an ECHOREPLY */ - if (!(options & F_VERBOSE)) - return; - (void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen)); - pr_icmph6(icp, end); - } - - if (!(options & F_FLOOD)) { - (void)putchar('\n'); - if (options & F_VERBOSE) - pr_exthdrs(mhdr); - (void)fflush(stdout); - if (options & F_AUD_RECV) - (void)fputc('\a', stderr); - } -} - -void -pr_exthdrs(struct msghdr *mhdr) -{ - struct cmsghdr *cm; - - for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; - cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { - if (cm->cmsg_level != IPPROTO_IPV6) - continue; - - switch (cm->cmsg_type) { - case IPV6_HOPOPTS: - printf(" HbH Options: "); - pr_ip6opt(CMSG_DATA(cm)); - break; - case IPV6_DSTOPTS: - case IPV6_RTHDRDSTOPTS: - printf(" Dst Options: "); - pr_ip6opt(CMSG_DATA(cm)); - break; - case IPV6_RTHDR: - printf(" Routing: "); - pr_rthdr(CMSG_DATA(cm)); - break; - } - } -} - -void -pr_ip6opt(void *extbuf) -{ - struct ip6_hbh *ext; - int currentlen; - u_int8_t type; - size_t extlen; - socklen_t len; - void *databuf; - u_int16_t value2; - u_int32_t value4; - - ext = (struct ip6_hbh *)extbuf; - extlen = (ext->ip6h_len + 1) * 8; - printf("nxt %u, len %u (%lu bytes)\n", ext->ip6h_nxt, - (unsigned int)ext->ip6h_len, (unsigned long)extlen); - - currentlen = 0; - while (1) { - currentlen = inet6_opt_next(extbuf, extlen, currentlen, - &type, &len, &databuf); - if (currentlen == -1) - break; - switch (type) { - /* - * Note that inet6_opt_next automatically skips any padding - * options. - */ - case IP6OPT_JUMBO: - inet6_opt_get_val(databuf, 0, &value4, sizeof(value4)); - printf(" Jumbo Payload Opt: Length %u\n", - (u_int32_t)ntohl(value4)); - break; - case IP6OPT_ROUTER_ALERT: - inet6_opt_get_val(databuf, 0, &value2, sizeof(value2)); - printf(" Router Alert Opt: Type %u\n", - ntohs(value2)); - break; - default: - printf(" Received Opt %u len %lu\n", - type, (unsigned long)len); - break; - } - } - return; -} - -void -pr_rthdr(void *extbuf) -{ - struct in6_addr *in6; - char ntopbuf[INET6_ADDRSTRLEN]; - struct ip6_rthdr *rh = (struct ip6_rthdr *)extbuf; - int i, segments; - - /* print fixed part of the header */ - printf("nxt %u, len %u (%d bytes), type %u, ", rh->ip6r_nxt, - rh->ip6r_len, (rh->ip6r_len + 1) << 3, rh->ip6r_type); - if ((segments = inet6_rth_segments(extbuf)) >= 0) - printf("%d segments, ", segments); - else - printf("segments unknown, "); - printf("%d left\n", rh->ip6r_segleft); - - for (i = 0; i < segments; i++) { - in6 = inet6_rth_getaddr(extbuf, i); - if (in6 == NULL) - printf(" [%d]<NULL>\n", i); - else { - if (!inet_ntop(AF_INET6, in6, ntopbuf, - sizeof(ntopbuf))) - strncpy(ntopbuf, "?", sizeof(ntopbuf)); - printf(" [%d]%s\n", i, ntopbuf); - } - } - - return; - -} - -int -get_hoplim(struct msghdr *mhdr) -{ - struct cmsghdr *cm; - - for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; - cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { - if (cm->cmsg_len == 0) - return(-1); - - if (cm->cmsg_level == IPPROTO_IPV6 && - cm->cmsg_type == IPV6_HOPLIMIT && - cm->cmsg_len == CMSG_LEN(sizeof(int))) - return(*(int *)CMSG_DATA(cm)); - } - - return(-1); -} - -int -get_pathmtu(struct msghdr *mhdr, struct sockaddr_in6 *dst) -{ - struct cmsghdr *cm; - struct ip6_mtuinfo *mtuctl = NULL; - - for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; - cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { - if (cm->cmsg_len == 0) - return(0); - - 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); - - /* - * If the notified destination is different from - * the one we are pinging, just ignore the info. - * We check the scope ID only when both notified value - * and our own value have non-0 values, because we may - * 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, - &dst->sin6_addr) || - (mtuctl->ip6m_addr.sin6_scope_id && - dst->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))); - } - return(0); - } - - /* - * Ignore an invalid MTU. XXX: can we just believe - * the kernel check? - */ - if (mtuctl->ip6m_mtu < IPV6_MMTU) - return(0); - - /* notification for our destination. return the MTU. */ - return((int)mtuctl->ip6m_mtu); - } - } - return(0); -} - -/* - * pr_icmph6 -- - * Print a descriptive string about an ICMP header. - */ -void -pr_icmph6(struct icmp6_hdr *icp, u_char *end) -{ - char ntop_buf[INET6_ADDRSTRLEN]; - struct nd_redirect *red; - - switch (icp->icmp6_type) { - case ICMP6_DST_UNREACH: - switch (icp->icmp6_code) { - case ICMP6_DST_UNREACH_NOROUTE: - (void)printf("No Route to Destination\n"); - break; - case ICMP6_DST_UNREACH_ADMIN: - (void)printf("Destination Administratively " - "Unreachable\n"); - break; - case ICMP6_DST_UNREACH_BEYONDSCOPE: - (void)printf("Destination Unreachable Beyond Scope\n"); - break; - case ICMP6_DST_UNREACH_ADDR: - (void)printf("Destination Host Unreachable\n"); - break; - case ICMP6_DST_UNREACH_NOPORT: - (void)printf("Destination Port Unreachable\n"); - break; - default: - (void)printf("Destination Unreachable, Bad Code: %d\n", - icp->icmp6_code); - break; - } - /* Print returned IP header information */ - pr_retip6((struct ip6_hdr *)(icp + 1), end); - break; - case ICMP6_PACKET_TOO_BIG: - (void)printf("Packet too big mtu = %d\n", - (int)ntohl(icp->icmp6_mtu)); - pr_retip6((struct ip6_hdr *)(icp + 1), end); - break; - case ICMP6_TIME_EXCEEDED: - switch (icp->icmp6_code) { - case ICMP6_TIME_EXCEED_TRANSIT: - (void)printf("Time to live exceeded\n"); - break; - case ICMP6_TIME_EXCEED_REASSEMBLY: - (void)printf("Frag reassembly time exceeded\n"); - break; - default: - (void)printf("Time exceeded, Bad Code: %d\n", - icp->icmp6_code); - break; - } - pr_retip6((struct ip6_hdr *)(icp + 1), end); - break; - case ICMP6_PARAM_PROB: - (void)printf("Parameter problem: "); - switch (icp->icmp6_code) { - case ICMP6_PARAMPROB_HEADER: - (void)printf("Erroneous Header "); - break; - case ICMP6_PARAMPROB_NEXTHEADER: - (void)printf("Unknown Nextheader "); - break; - case ICMP6_PARAMPROB_OPTION: - (void)printf("Unrecognized Option "); - break; - default: - (void)printf("Bad code(%d) ", icp->icmp6_code); - break; - } - (void)printf("pointer = 0x%02x\n", - (u_int32_t)ntohl(icp->icmp6_pptr)); - pr_retip6((struct ip6_hdr *)(icp + 1), end); - break; - case ICMP6_ECHO_REQUEST: - (void)printf("Echo Request"); - /* XXX ID + Seq + Data */ - break; - case ICMP6_ECHO_REPLY: - (void)printf("Echo Reply"); - /* XXX ID + Seq + Data */ - break; - case ICMP6_MEMBERSHIP_QUERY: - (void)printf("Listener Query"); - break; - case ICMP6_MEMBERSHIP_REPORT: - (void)printf("Listener Report"); - break; - case ICMP6_MEMBERSHIP_REDUCTION: - (void)printf("Listener Done"); - break; - case ND_ROUTER_SOLICIT: - (void)printf("Router Solicitation"); - break; - case ND_ROUTER_ADVERT: - (void)printf("Router Advertisement"); - break; - case ND_NEIGHBOR_SOLICIT: - (void)printf("Neighbor Solicitation"); - break; - case ND_NEIGHBOR_ADVERT: - (void)printf("Neighbor Advertisement"); - break; - case ND_REDIRECT: - red = (struct nd_redirect *)icp; - (void)printf("Redirect\n"); - if (!inet_ntop(AF_INET6, &red->nd_rd_dst, ntop_buf, - sizeof(ntop_buf))) - strncpy(ntop_buf, "?", sizeof(ntop_buf)); - (void)printf("Destination: %s", ntop_buf); - if (!inet_ntop(AF_INET6, &red->nd_rd_target, ntop_buf, - sizeof(ntop_buf))) - strncpy(ntop_buf, "?", sizeof(ntop_buf)); - (void)printf(" New Target: %s", ntop_buf); - break; - default: - (void)printf("Bad ICMP type: %d", icp->icmp6_type); - } -} - -/* - * pr_iph6 -- - * Print an IP6 header. - */ -void -pr_iph6(struct ip6_hdr *ip6) -{ - u_int32_t flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; - u_int8_t tc; - char ntop_buf[INET6_ADDRSTRLEN]; - - tc = *(&ip6->ip6_vfc + 1); /* XXX */ - tc = (tc >> 4) & 0x0f; - tc |= (ip6->ip6_vfc << 4); - - printf("Vr TC Flow Plen Nxt Hlim\n"); - printf(" %1x %02x %05x %04x %02x %02x\n", - (ip6->ip6_vfc & IPV6_VERSION_MASK) >> 4, tc, (u_int32_t)ntohl(flow), - ntohs(ip6->ip6_plen), ip6->ip6_nxt, ip6->ip6_hlim); - if (!inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf, sizeof(ntop_buf))) - strncpy(ntop_buf, "?", sizeof(ntop_buf)); - printf("%s->", ntop_buf); - if (!inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf, sizeof(ntop_buf))) - strncpy(ntop_buf, "?", sizeof(ntop_buf)); - printf("%s\n", ntop_buf); -} - -/* - * pr_retip6 -- - * Dump some info on a returned (via ICMPv6) IPv6 packet. - */ -void -pr_retip6(struct ip6_hdr *ip6, u_char *end) -{ - u_char *cp = (u_char *)ip6, nh; - int hlen; - - if (end - (u_char *)ip6 < sizeof(*ip6)) { - printf("IP6"); - goto trunc; - } - pr_iph6(ip6); - hlen = sizeof(*ip6); - - nh = ip6->ip6_nxt; - cp += hlen; - while (end - cp >= 8) { - switch (nh) { - case IPPROTO_HOPOPTS: - printf("HBH "); - hlen = (((struct ip6_hbh *)cp)->ip6h_len+1) << 3; - nh = ((struct ip6_hbh *)cp)->ip6h_nxt; - break; - case IPPROTO_DSTOPTS: - printf("DSTOPT "); - hlen = (((struct ip6_dest *)cp)->ip6d_len+1) << 3; - nh = ((struct ip6_dest *)cp)->ip6d_nxt; - break; - case IPPROTO_FRAGMENT: - printf("FRAG "); - hlen = sizeof(struct ip6_frag); - nh = ((struct ip6_frag *)cp)->ip6f_nxt; - break; - case IPPROTO_ROUTING: - printf("RTHDR "); - hlen = (((struct ip6_rthdr *)cp)->ip6r_len+1) << 3; - nh = ((struct ip6_rthdr *)cp)->ip6r_nxt; - break; - case IPPROTO_AH: - printf("AH "); - hlen = (((struct ah *)cp)->ah_hl+2) << 2; - nh = ((struct ah *)cp)->ah_nh; - break; - case IPPROTO_ICMPV6: - printf("ICMP6: type = %d, code = %d\n", - *cp, *(cp + 1)); - return; - case IPPROTO_ESP: - printf("ESP\n"); - return; - case IPPROTO_TCP: - printf("TCP: from port %u, to port %u (decimal)\n", - (*cp * 256 + *(cp + 1)), - (*(cp + 2) * 256 + *(cp + 3))); - return; - case IPPROTO_UDP: - printf("UDP: from port %u, to port %u (decimal)\n", - (*cp * 256 + *(cp + 1)), - (*(cp + 2) * 256 + *(cp + 3))); - return; - default: - printf("Unknown Header(%d)\n", nh); - return; - } - - if ((cp += hlen) >= end) - goto trunc; - } - if (end - cp < 8) - goto trunc; - - putchar('\n'); - return; - - trunc: - printf("...\n"); - return; -} - -__dead void -usage(void) -{ - (void)fprintf(stderr, - "usage: ping6 [-dEefHLmnqv] [-c count] [-h hoplimit] " - "[-I sourceaddr]\n\t[-i wait] [-l preload] [-p pattern] " - "[-s packetsize] [-V rtable]\n\t[-w maxwait] host\n"); - exit(1); -} |