1121472Sume/* $KAME: ping6.c,v 1.169 2003/07/25 06:01:47 itojun Exp $ */ 262627Skris 355163Sshin/* 455163Sshin * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 555163Sshin * All rights reserved. 655163Sshin * 755163Sshin * Redistribution and use in source and binary forms, with or without 855163Sshin * modification, are permitted provided that the following conditions 955163Sshin * are met: 1055163Sshin * 1. Redistributions of source code must retain the above copyright 1155163Sshin * notice, this list of conditions and the following disclaimer. 1255163Sshin * 2. Redistributions in binary form must reproduce the above copyright 1355163Sshin * notice, this list of conditions and the following disclaimer in the 1455163Sshin * documentation and/or other materials provided with the distribution. 1555163Sshin * 3. Neither the name of the project nor the names of its contributors 1655163Sshin * may be used to endorse or promote products derived from this software 1755163Sshin * without specific prior written permission. 1855163Sshin * 1955163Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2055163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2155163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2255163Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2355163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2455163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2555163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2655163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2755163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2855163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2955163Sshin * SUCH DAMAGE. 3055163Sshin */ 3155163Sshin 3255163Sshin/* BSDI ping.c,v 2.3 1996/01/21 17:56:50 jch Exp */ 3355163Sshin 3455163Sshin/* 3555163Sshin * Copyright (c) 1989, 1993 3655163Sshin * The Regents of the University of California. All rights reserved. 3755163Sshin * 3855163Sshin * This code is derived from software contributed to Berkeley by 3955163Sshin * Mike Muuss. 4055163Sshin * 4155163Sshin * Redistribution and use in source and binary forms, with or without 4255163Sshin * modification, are permitted provided that the following conditions 4355163Sshin * are met: 4455163Sshin * 1. Redistributions of source code must retain the above copyright 4555163Sshin * notice, this list of conditions and the following disclaimer. 4655163Sshin * 2. Redistributions in binary form must reproduce the above copyright 4755163Sshin * notice, this list of conditions and the following disclaimer in the 4855163Sshin * documentation and/or other materials provided with the distribution. 4955163Sshin * 4. Neither the name of the University nor the names of its contributors 5055163Sshin * may be used to endorse or promote products derived from this software 5155163Sshin * without specific prior written permission. 5255163Sshin * 5355163Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5455163Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5555163Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5655163Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5755163Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5855163Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5955163Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 6055163Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 6155163Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 6255163Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6355163Sshin * SUCH DAMAGE. 6455163Sshin */ 6555163Sshin 6655163Sshin#ifndef lint 67139920Strhodesstatic const char copyright[] = 6855163Sshin"@(#) Copyright (c) 1989, 1993\n\ 6955163Sshin The Regents of the University of California. All rights reserved.\n"; 7055163Sshin#endif /* not lint */ 7155163Sshin 7255163Sshin#ifndef lint 7355163Sshin#if 0 7455163Sshinstatic char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93"; 7555163Sshin#endif 7655163Sshin#endif /* not lint */ 7755163Sshin 78216561Scharnier#include <sys/cdefs.h> 79216561Scharnier__FBSDID("$FreeBSD$"); 80216561Scharnier 8155163Sshin/* 8255163Sshin * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility, 8355163Sshin * measure round-trip-delays and packet loss across network paths. 8455163Sshin * 8555163Sshin * Author - 8655163Sshin * Mike Muuss 8755163Sshin * U. S. Army Ballistic Research Laboratory 8855163Sshin * December, 1983 8955163Sshin * 9055163Sshin * Status - 9155163Sshin * Public Domain. Distribution Unlimited. 9255163Sshin * Bugs - 9355163Sshin * More statistics could always be gathered. 9455163Sshin * This program has to run SUID to ROOT to access the ICMP socket. 9555163Sshin */ 9655163Sshin/* 9755163Sshin * NOTE: 9855163Sshin * USE_SIN6_SCOPE_ID assumes that sin6_scope_id has the same semantics 9978064Sume * as IPV6_PKTINFO. Some people object it (sin6_scope_id specifies *link* 10078064Sume * while IPV6_PKTINFO specifies *interface*. Link is defined as collection of 10155163Sshin * network attached to 1 or more interfaces) 10255163Sshin */ 10355163Sshin 10455163Sshin#include <sys/param.h> 10555163Sshin#include <sys/uio.h> 10655163Sshin#include <sys/socket.h> 10755163Sshin#include <sys/time.h> 10855163Sshin 10955163Sshin#include <net/if.h> 11055163Sshin#include <net/route.h> 11155163Sshin 11255163Sshin#include <netinet/in.h> 11355163Sshin#include <netinet/ip6.h> 11455163Sshin#include <netinet/icmp6.h> 11555163Sshin#include <arpa/inet.h> 11678064Sume#include <arpa/nameser.h> 11755163Sshin#include <netdb.h> 11855163Sshin 11955163Sshin#include <ctype.h> 12055163Sshin#include <err.h> 12155163Sshin#include <errno.h> 12255163Sshin#include <fcntl.h> 12378064Sume#include <math.h> 12455163Sshin#include <signal.h> 12555163Sshin#include <stdio.h> 12655163Sshin#include <stdlib.h> 12755163Sshin#include <string.h> 12855163Sshin#include <unistd.h> 129121472Sume#ifdef HAVE_POLL_H 130121472Sume#include <poll.h> 131121472Sume#endif 13255163Sshin 13355163Sshin#ifdef IPSEC 134171135Sgnn#include <netipsec/ah.h> 135171135Sgnn#include <netipsec/ipsec.h> 13655163Sshin#endif 13755163Sshin 13862627Skris#include <md5.h> 13962627Skris 140121472Sumestruct tv32 { 141121472Sume u_int32_t tv32_sec; 142121472Sume u_int32_t tv32_usec; 143121472Sume}; 144121472Sume 14562627Skris#define MAXPACKETLEN 131072 14655163Sshin#define IP6LEN 40 147121472Sume#define ICMP6ECHOLEN 8 /* icmp echo header len excluding time */ 148121472Sume#define ICMP6ECHOTMLEN sizeof(struct tv32) 14962627Skris#define ICMP6_NIQLEN (ICMP6ECHOLEN + 8) 150168866Smtm# define CONTROLLEN 10240 /* ancillary data buffer size RFC3542 20.1 */ 15178064Sume/* FQDN case, 64 bits of nonce + 32 bits ttl */ 15278064Sume#define ICMP6_NIRLEN (ICMP6ECHOLEN + 12) 15355163Sshin#define EXTRA 256 /* for AH and various other headers. weird. */ 15455163Sshin#define DEFDATALEN ICMP6ECHOTMLEN 15562627Skris#define MAXDATALEN MAXPACKETLEN - IP6LEN - ICMP6ECHOLEN 15655163Sshin#define NROUTES 9 /* number of record route slots */ 15755163Sshin 15855163Sshin#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ 15955163Sshin#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ 16055163Sshin#define SET(bit) (A(bit) |= B(bit)) 16155163Sshin#define CLR(bit) (A(bit) &= (~B(bit))) 16255163Sshin#define TST(bit) (A(bit) & B(bit)) 16355163Sshin 16455163Sshin#define F_FLOOD 0x0001 16555163Sshin#define F_INTERVAL 0x0002 16655163Sshin#define F_PINGFILLED 0x0008 16755163Sshin#define F_QUIET 0x0010 16855163Sshin#define F_RROUTE 0x0020 16955163Sshin#define F_SO_DEBUG 0x0040 17055163Sshin#define F_VERBOSE 0x0100 17155163Sshin#ifdef IPSEC 17255163Sshin#ifdef IPSEC_POLICY_IPSEC 17362627Skris#define F_POLICY 0x0400 17455163Sshin#else 17562627Skris#define F_AUTHHDR 0x0200 17662627Skris#define F_ENCRYPT 0x0400 17755163Sshin#endif /*IPSEC_POLICY_IPSEC*/ 17855163Sshin#endif /*IPSEC*/ 17962627Skris#define F_NODEADDR 0x0800 18062627Skris#define F_FQDN 0x1000 18162627Skris#define F_INTERFACE 0x2000 18262627Skris#define F_SRCADDR 0x4000 18362627Skris#define F_HOSTNAME 0x10000 18462627Skris#define F_FQDNOLD 0x20000 18562627Skris#define F_NIGROUP 0x40000 18678064Sume#define F_SUPTYPES 0x80000 18778064Sume#define F_NOMINMTU 0x100000 188173765Sdd#define F_ONCE 0x200000 189182195Smatteo#define F_AUDIBLE 0x400000 190182276Smatteo#define F_MISSED 0x800000 191206889Smaxim#define F_DONTFRAG 0x1000000 19278064Sume#define F_NOUSERDATA (F_NODEADDR | F_FQDN | F_FQDNOLD | F_SUPTYPES) 19355163Sshinu_int options; 19455163Sshin 19562627Skris#define IN6LEN sizeof(struct in6_addr) 19662627Skris#define SA6LEN sizeof(struct sockaddr_in6) 19778064Sume#define DUMMY_PORT 10101 19855163Sshin 19978064Sume#define SIN6(s) ((struct sockaddr_in6 *)(s)) 20055163Sshin 20155163Sshin/* 20255163Sshin * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum 20355163Sshin * number of received sequence numbers we can keep track of. Change 128 20455163Sshin * to 8192 for complete accuracy... 20555163Sshin */ 20655163Sshin#define MAX_DUP_CHK (8 * 8192) 20755163Sshinint mx_dup_ck = MAX_DUP_CHK; 20855163Sshinchar rcvd_tbl[MAX_DUP_CHK / 8]; 20955163Sshin 210209236Sbrucecstruct addrinfo *res = NULL; 21178064Sumestruct sockaddr_in6 dst; /* who to ping6 */ 21278064Sumestruct sockaddr_in6 src; /* src addr of this packet */ 213121472Sumesocklen_t srclen; 21455163Sshinint datalen = DEFDATALEN; 21555163Sshinint s; /* socket file descriptor */ 21655163Sshinu_char outpack[MAXPACKETLEN]; 21755163Sshinchar BSPACE = '\b'; /* characters written for flood */ 218182195Smatteochar BBELL = '\a'; /* characters written for AUDIBLE */ 21955163Sshinchar DOT = '.'; 22055163Sshinchar *hostname; 22155163Sshinint ident; /* process id to identify our packets */ 22278064Sumeu_int8_t nonce[8]; /* nonce field for node information */ 22378064Sumeint hoplimit = -1; /* hoplimit */ 22478064Sumeint pathmtu = 0; /* path MTU for the destination. 0 = unspec. */ 225209236Sbrucecu_char *packet = NULL; 226209236Sbrucec#ifdef HAVE_POLL_H 227209236Sbrucecstruct pollfd fdmaskp[1]; 228209236Sbrucec#else 229209236Sbrucecfd_set *fdmaskp = NULL; 230209236Sbrucecint fdmasks; 231209236Sbrucec#endif 23255163Sshin 23355163Sshin/* counters */ 234182276Smatteolong nmissedmax; /* max value of ntransmitted - nreceived - 1 */ 23555163Sshinlong npackets; /* max packets to transmit */ 23655163Sshinlong nreceived; /* # of packets we got back */ 23755163Sshinlong nrepeats; /* number of duplicates */ 23855163Sshinlong ntransmitted; /* sequence # for outbound packets = #sent */ 23978064Sumestruct timeval interval = {1, 0}; /* interval between packets */ 24055163Sshin 24155163Sshin/* timing */ 24255163Sshinint timing; /* flag to do timing */ 24355163Sshindouble tmin = 999999999.0; /* minimum round trip time */ 24455163Sshindouble tmax = 0.0; /* maximum round trip time */ 24555163Sshindouble tsum = 0.0; /* sum of all times, for doing average */ 24678064Sumedouble tsumsq = 0.0; /* sum of all times squared, for std. dev. */ 24755163Sshin 24855163Sshin/* for node addresses */ 24955163Sshinu_short naflags; 25055163Sshin 25155163Sshin/* for ancillary data(advanced API) */ 25255163Sshinstruct msghdr smsghdr; 25355163Sshinstruct iovec smsgiov; 25455163Sshinchar *scmsg = 0; 25555163Sshin 25678064Sumevolatile sig_atomic_t seenalrm; 25778064Sumevolatile sig_atomic_t seenint; 25878064Sume#ifdef SIGINFO 25978064Sumevolatile sig_atomic_t seeninfo; 26078064Sume#endif 26178064Sume 262121472Sumeint main(int, char *[]); 26392883Simpvoid fill(char *, char *); 26492883Simpint get_hoplim(struct msghdr *); 26592883Simpint get_pathmtu(struct msghdr *); 26692883Simpstruct in6_pktinfo *get_rcvpktinfo(struct msghdr *); 26792883Simpvoid onsignal(int); 26892883Simpvoid retransmit(void); 26992883Simpvoid onint(int); 27092883Simpsize_t pingerlen(void); 27192883Simpint pinger(void); 27292883Simpconst char *pr_addr(struct sockaddr *, int); 27392883Simpvoid pr_icmph(struct icmp6_hdr *, u_char *); 27492883Simpvoid pr_iph(struct ip6_hdr *); 27592883Simpvoid pr_suptypes(struct icmp6_nodeinfo *, size_t); 27692883Simpvoid pr_nodeaddr(struct icmp6_nodeinfo *, int); 27792883Simpint myechoreply(const struct icmp6_hdr *); 27892883Simpint mynireply(const struct icmp6_nodeinfo *); 27992883Simpchar *dnsdecode(const u_char **, const u_char *, const u_char *, 280121472Sume char *, size_t); 28192883Simpvoid pr_pack(u_char *, int, struct msghdr *); 28292883Simpvoid pr_exthdrs(struct msghdr *); 283168866Smtmvoid pr_ip6opt(void *, size_t); 284168866Smtmvoid pr_rthdr(void *, size_t); 28592883Simpint pr_bitrange(u_int32_t, int, int); 28692883Simpvoid pr_retip(struct ip6_hdr *, u_char *); 28792883Simpvoid summary(void); 28892883Simpvoid tvsub(struct timeval *, struct timeval *); 28992883Simpint setpolicy(int, char *); 290252021Shrschar *nigroup(char *, int); 29192883Simpvoid usage(void); 29255163Sshin 29355163Sshinint 294216561Scharniermain(int argc, char *argv[]) 29555163Sshin{ 29655163Sshin struct itimerval itimer; 29755163Sshin struct sockaddr_in6 from; 298121472Sume#ifndef HAVE_ARC4RANDOM 299121472Sume struct timeval seed; 300121472Sume#endif 301121472Sume#ifdef HAVE_POLL_H 302121472Sume int timeout; 303121472Sume#else 30478064Sume struct timeval timeout, *tv; 305121472Sume#endif 30655163Sshin struct addrinfo hints; 30792806Sobrien int cc, i; 308121472Sume int ch, hold, packlen, preload, optval, ret_ga; 309252021Shrs int nig_oldmcprefix = -1; 310209236Sbrucec u_char *datap; 311121472Sume char *e, *target, *ifname = NULL, *gateway = NULL; 31255163Sshin int ip6optlen = 0; 31355163Sshin struct cmsghdr *scmsgp = NULL; 314209236Sbrucec /* For control (ancillary) data received from recvmsg() */ 315209236Sbrucec struct cmsghdr cm[CONTROLLEN]; 316121472Sume#if defined(SO_SNDBUF) && defined(SO_RCVBUF) 317121472Sume u_long lsockbufsize; 31855163Sshin int sockbufsize = 0; 319121472Sume#endif 32062627Skris int usepktinfo = 0; 32162627Skris struct in6_pktinfo *pktinfo = NULL; 32262627Skris#ifdef USE_RFC2292BIS 32362627Skris struct ip6_rthdr *rthdr = NULL; 32462627Skris#endif 32555163Sshin#ifdef IPSEC_POLICY_IPSEC 32655163Sshin char *policy_in = NULL; 32755163Sshin char *policy_out = NULL; 32855163Sshin#endif 32978064Sume double intval; 33078064Sume size_t rthlen; 331121472Sume#ifdef IPV6_USE_MIN_MTU 332121472Sume int mflag = 0; 333121472Sume#endif 33455163Sshin 33555163Sshin /* just to be sure */ 336107652Ssuz memset(&smsghdr, 0, sizeof(smsghdr)); 337107652Ssuz memset(&smsgiov, 0, sizeof(smsgiov)); 33855163Sshin 33955163Sshin preload = 0; 34055163Sshin datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN]; 34155163Sshin#ifndef IPSEC 34278064Sume#define ADDOPTS 34355163Sshin#else 34455163Sshin#ifdef IPSEC_POLICY_IPSEC 34578064Sume#define ADDOPTS "P:" 34655163Sshin#else 34778064Sume#define ADDOPTS "AE" 34855163Sshin#endif /*IPSEC_POLICY_IPSEC*/ 34955163Sshin#endif 35078064Sume while ((ch = getopt(argc, argv, 351206889Smaxim "a:b:c:DdfHg:h:I:i:l:mnNop:qrRS:s:tvwW" ADDOPTS)) != -1) { 35278064Sume#undef ADDOPTS 35378064Sume switch (ch) { 35478064Sume case 'a': 35578064Sume { 35678064Sume char *cp; 35755163Sshin 35878064Sume options &= ~F_NOUSERDATA; 35978064Sume options |= F_NODEADDR; 36078064Sume for (cp = optarg; *cp != '\0'; cp++) { 36178064Sume switch (*cp) { 36278064Sume case 'a': 36378064Sume naflags |= NI_NODEADDR_FLAG_ALL; 36478064Sume break; 36578064Sume case 'c': 36678064Sume case 'C': 36778064Sume naflags |= NI_NODEADDR_FLAG_COMPAT; 36878064Sume break; 36978064Sume case 'l': 37078064Sume case 'L': 37178064Sume naflags |= NI_NODEADDR_FLAG_LINKLOCAL; 37278064Sume break; 37378064Sume case 's': 37478064Sume case 'S': 37578064Sume naflags |= NI_NODEADDR_FLAG_SITELOCAL; 37678064Sume break; 37778064Sume case 'g': 37878064Sume case 'G': 37978064Sume naflags |= NI_NODEADDR_FLAG_GLOBAL; 38078064Sume break; 38178064Sume case 'A': /* experimental. not in the spec */ 38278064Sume#ifdef NI_NODEADDR_FLAG_ANYCAST 38378064Sume naflags |= NI_NODEADDR_FLAG_ANYCAST; 38478064Sume break; 38578064Sume#else 38678064Sume errx(1, 38778064Sume"-a A is not supported on the platform"); 38878064Sume /*NOTREACHED*/ 38978064Sume#endif 39078064Sume default: 39178064Sume usage(); 39278064Sume /*NOTREACHED*/ 39378064Sume } 39478064Sume } 39578064Sume break; 39678064Sume } 39778064Sume case 'b': 39855163Sshin#if defined(SO_SNDBUF) && defined(SO_RCVBUF) 399121472Sume errno = 0; 400121472Sume e = NULL; 401121472Sume lsockbufsize = strtoul(optarg, &e, 10); 402121472Sume sockbufsize = lsockbufsize; 403121472Sume if (errno || !*optarg || *e || 404121472Sume sockbufsize != lsockbufsize) 405121472Sume errx(1, "invalid socket buffer size"); 40655163Sshin#else 40787668Scharnier errx(1, 40855163Sshin"-b option ignored: SO_SNDBUF/SO_RCVBUF socket options not supported"); 40955163Sshin#endif 41055163Sshin break; 41155163Sshin case 'c': 41255163Sshin npackets = strtol(optarg, &e, 10); 41355163Sshin if (npackets <= 0 || *optarg == '\0' || *e != '\0') 41455163Sshin errx(1, 41555163Sshin "illegal number of packets -- %s", optarg); 41655163Sshin break; 417206889Smaxim case 'D': 418206889Smaxim options |= F_DONTFRAG; 419206889Smaxim break; 42055163Sshin case 'd': 42155163Sshin options |= F_SO_DEBUG; 42255163Sshin break; 42355163Sshin case 'f': 424121472Sume if (getuid()) { 425121472Sume errno = EPERM; 426121472Sume errx(1, "Must be superuser to flood ping"); 427121472Sume } 42855163Sshin options |= F_FLOOD; 42955163Sshin setbuf(stdout, (char *)NULL); 43055163Sshin break; 431121472Sume case 'g': 432121472Sume gateway = optarg; 433121472Sume break; 43462627Skris case 'H': 43562627Skris options |= F_HOSTNAME; 43662627Skris break; 43755163Sshin case 'h': /* hoplimit */ 43855163Sshin hoplimit = strtol(optarg, &e, 10); 439121472Sume if (*optarg == '\0' || *e != '\0') 440121472Sume errx(1, "illegal hoplimit %s", optarg); 44155163Sshin if (255 < hoplimit || hoplimit < -1) 44255163Sshin errx(1, 44355163Sshin "illegal hoplimit -- %s", optarg); 44455163Sshin break; 44555163Sshin case 'I': 44655163Sshin ifname = optarg; 44755163Sshin options |= F_INTERFACE; 44862627Skris#ifndef USE_SIN6_SCOPE_ID 44962627Skris usepktinfo++; 45062627Skris#endif 45155163Sshin break; 45255163Sshin case 'i': /* wait between sending packets */ 45378064Sume intval = strtod(optarg, &e); 45478064Sume if (*optarg == '\0' || *e != '\0') 45578064Sume errx(1, "illegal timing interval %s", optarg); 45678064Sume if (intval < 1 && getuid()) { 45778064Sume errx(1, "%s: only root may use interval < 1s", 45878064Sume strerror(EPERM)); 45978064Sume } 46078064Sume interval.tv_sec = (long)intval; 46178064Sume interval.tv_usec = 46278064Sume (long)((intval - interval.tv_sec) * 1000000); 46378064Sume if (interval.tv_sec < 0) 46478064Sume errx(1, "illegal timing interval %s", optarg); 46578064Sume /* less than 1/hz does not make sense */ 466176549Ssilby if (interval.tv_sec == 0 && interval.tv_usec < 1) { 467176549Ssilby warnx("too small interval, raised to .000001"); 468176549Ssilby interval.tv_usec = 1; 46978064Sume } 47055163Sshin options |= F_INTERVAL; 47155163Sshin break; 47255163Sshin case 'l': 473121472Sume if (getuid()) { 474121472Sume errno = EPERM; 475121472Sume errx(1, "Must be superuser to preload"); 476121472Sume } 47755163Sshin preload = strtol(optarg, &e, 10); 47855163Sshin if (preload < 0 || *optarg == '\0' || *e != '\0') 47955163Sshin errx(1, "illegal preload value -- %s", optarg); 48055163Sshin break; 48178064Sume case 'm': 48278064Sume#ifdef IPV6_USE_MIN_MTU 483121472Sume mflag++; 48478064Sume break; 48578064Sume#else 48678064Sume errx(1, "-%c is not supported on this platform", ch); 48778064Sume /*NOTREACHED*/ 48878064Sume#endif 48955163Sshin case 'n': 49078064Sume options &= ~F_HOSTNAME; 49155163Sshin break; 49262627Skris case 'N': 49362627Skris options |= F_NIGROUP; 494252021Shrs nig_oldmcprefix++; 49562627Skris break; 496173765Sdd case 'o': 497173765Sdd options |= F_ONCE; 498173765Sdd break; 49955163Sshin case 'p': /* fill buffer with user pattern */ 50055163Sshin options |= F_PINGFILLED; 50155163Sshin fill((char *)datap, optarg); 50255163Sshin break; 50355163Sshin case 'q': 50455163Sshin options |= F_QUIET; 50555163Sshin break; 506182276Smatteo case 'r': 507182276Smatteo options |= F_AUDIBLE; 508182276Smatteo break; 509182276Smatteo case 'R': 510182276Smatteo options |= F_MISSED; 511182276Smatteo break; 51262627Skris case 'S': 513121472Sume memset(&hints, 0, sizeof(struct addrinfo)); 514121472Sume hints.ai_flags = AI_NUMERICHOST; /* allow hostname? */ 515121472Sume hints.ai_family = AF_INET6; 516121472Sume hints.ai_socktype = SOCK_RAW; 517121472Sume hints.ai_protocol = IPPROTO_ICMPV6; 518121472Sume 519121472Sume ret_ga = getaddrinfo(optarg, NULL, &hints, &res); 520121472Sume if (ret_ga) { 521121472Sume errx(1, "invalid source address: %s", 522121472Sume gai_strerror(ret_ga)); 523121472Sume } 524121472Sume /* 525121472Sume * res->ai_family must be AF_INET6 and res->ai_addrlen 526121472Sume * must be sizeof(src). 527121472Sume */ 528121472Sume memcpy(&src, res->ai_addr, res->ai_addrlen); 529121472Sume srclen = res->ai_addrlen; 530121472Sume freeaddrinfo(res); 531209236Sbrucec res = NULL; 53262627Skris options |= F_SRCADDR; 53362627Skris break; 53455163Sshin case 's': /* size of packet to send */ 53555163Sshin datalen = strtol(optarg, &e, 10); 53655163Sshin if (datalen <= 0 || *optarg == '\0' || *e != '\0') 53755163Sshin errx(1, "illegal datalen value -- %s", optarg); 53878064Sume if (datalen > MAXDATALEN) { 53955163Sshin errx(1, 54055163Sshin "datalen value too large, maximum is %d", 54155163Sshin MAXDATALEN); 54278064Sume } 54355163Sshin break; 54478064Sume case 't': 54578064Sume options &= ~F_NOUSERDATA; 54678064Sume options |= F_SUPTYPES; 54778064Sume break; 54855163Sshin case 'v': 54955163Sshin options |= F_VERBOSE; 55055163Sshin break; 55155163Sshin case 'w': 55278064Sume options &= ~F_NOUSERDATA; 55355163Sshin options |= F_FQDN; 55455163Sshin break; 55562627Skris case 'W': 55678064Sume options &= ~F_NOUSERDATA; 55762627Skris options |= F_FQDNOLD; 55862627Skris break; 55955163Sshin#ifdef IPSEC 56055163Sshin#ifdef IPSEC_POLICY_IPSEC 56155163Sshin case 'P': 56255163Sshin options |= F_POLICY; 56369571Sume if (!strncmp("in", optarg, 2)) { 56469571Sume if ((policy_in = strdup(optarg)) == NULL) 56569571Sume errx(1, "strdup"); 56669571Sume } else if (!strncmp("out", optarg, 3)) { 56769571Sume if ((policy_out = strdup(optarg)) == NULL) 56869571Sume errx(1, "strdup"); 56969571Sume } else 57055163Sshin errx(1, "invalid security policy"); 57155163Sshin break; 57255163Sshin#else 57355163Sshin case 'A': 57455163Sshin options |= F_AUTHHDR; 57555163Sshin break; 57655163Sshin case 'E': 57755163Sshin options |= F_ENCRYPT; 57855163Sshin break; 57955163Sshin#endif /*IPSEC_POLICY_IPSEC*/ 58055163Sshin#endif /*IPSEC*/ 58155163Sshin default: 58255163Sshin usage(); 58362627Skris /*NOTREACHED*/ 58455163Sshin } 58562627Skris } 586121472Sume 58755163Sshin argc -= optind; 58855163Sshin argv += optind; 58955163Sshin 59062627Skris if (argc < 1) { 59155163Sshin usage(); 59262627Skris /*NOTREACHED*/ 59362627Skris } 59455163Sshin 59562627Skris if (argc > 1) { 59678064Sume#ifdef IPV6_RECVRTHDR /* 2292bis */ 59778064Sume rthlen = CMSG_SPACE(inet6_rth_space(IPV6_RTHDR_TYPE_0, 59878064Sume argc - 1)); 59978064Sume#else /* RFC2292 */ 60078064Sume rthlen = inet6_rthdr_space(IPV6_RTHDR_TYPE_0, argc - 1); 60162627Skris#endif 60278064Sume if (rthlen == 0) { 60378064Sume errx(1, "too many intermediate hops"); 60478064Sume /*NOTREACHED*/ 60578064Sume } 60678064Sume ip6optlen += rthlen; 60762627Skris } 60855163Sshin 60962627Skris if (options & F_NIGROUP) { 610252021Shrs target = nigroup(argv[argc - 1], nig_oldmcprefix); 61162627Skris if (target == NULL) { 61262627Skris usage(); 61362627Skris /*NOTREACHED*/ 61462627Skris } 61562627Skris } else 61662627Skris target = argv[argc - 1]; 61755163Sshin 61855163Sshin /* getaddrinfo */ 619121472Sume memset(&hints, 0, sizeof(struct addrinfo)); 62078064Sume hints.ai_flags = AI_CANONNAME; 62155163Sshin hints.ai_family = AF_INET6; 62255163Sshin hints.ai_socktype = SOCK_RAW; 62355163Sshin hints.ai_protocol = IPPROTO_ICMPV6; 62455163Sshin 62555163Sshin ret_ga = getaddrinfo(target, NULL, &hints, &res); 62687668Scharnier if (ret_ga) 62787668Scharnier errx(1, "%s", gai_strerror(ret_ga)); 62855163Sshin if (res->ai_canonname) 62955163Sshin hostname = res->ai_canonname; 63055163Sshin else 63155163Sshin hostname = target; 63278064Sume 63355163Sshin if (!res->ai_addr) 63455163Sshin errx(1, "getaddrinfo failed"); 63555163Sshin 63655163Sshin (void)memcpy(&dst, res->ai_addr, res->ai_addrlen); 63755163Sshin 63878064Sume if ((s = socket(res->ai_family, res->ai_socktype, 63978064Sume res->ai_protocol)) < 0) 64078064Sume err(1, "socket"); 64178064Sume 642121472Sume /* set the source address if specified. */ 643121472Sume if ((options & F_SRCADDR) && 644121472Sume bind(s, (struct sockaddr *)&src, srclen) != 0) { 645121472Sume err(1, "bind"); 646121472Sume } 647121472Sume 648121472Sume /* set the gateway (next hop) if specified */ 649121472Sume if (gateway) { 650121472Sume struct addrinfo ghints, *gres; 651121472Sume int error; 652121472Sume 653121472Sume memset(&ghints, 0, sizeof(ghints)); 654121472Sume ghints.ai_family = AF_INET6; 655121472Sume ghints.ai_socktype = SOCK_RAW; 656121472Sume ghints.ai_protocol = IPPROTO_ICMPV6; 657121472Sume 658121472Sume error = getaddrinfo(gateway, NULL, &hints, &gres); 659121472Sume if (error) { 660121472Sume errx(1, "getaddrinfo for the gateway %s: %s", 661121472Sume gateway, gai_strerror(error)); 662121472Sume } 663121472Sume if (gres->ai_next && (options & F_VERBOSE)) 664121472Sume warnx("gateway resolves to multiple addresses"); 665121472Sume 666121472Sume if (setsockopt(s, IPPROTO_IPV6, IPV6_NEXTHOP, 667121472Sume gres->ai_addr, gres->ai_addrlen)) { 668121472Sume err(1, "setsockopt(IPV6_NEXTHOP)"); 669121472Sume } 670121472Sume 671121472Sume freeaddrinfo(gres); 672121472Sume } 673121472Sume 67478064Sume /* 67578064Sume * let the kerel pass extension headers of incoming packets, 67678064Sume * for privileged socket options 67778064Sume */ 67878064Sume if ((options & F_VERBOSE) != 0) { 67978064Sume int opton = 1; 68078064Sume 68178064Sume#ifdef IPV6_RECVHOPOPTS 68278064Sume if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &opton, 68378064Sume sizeof(opton))) 68478064Sume err(1, "setsockopt(IPV6_RECVHOPOPTS)"); 68578064Sume#else /* old adv. API */ 68678064Sume if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPOPTS, &opton, 68778064Sume sizeof(opton))) 68878064Sume err(1, "setsockopt(IPV6_HOPOPTS)"); 68978064Sume#endif 69078064Sume#ifdef IPV6_RECVDSTOPTS 69178064Sume if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTOPTS, &opton, 69278064Sume sizeof(opton))) 69378064Sume err(1, "setsockopt(IPV6_RECVDSTOPTS)"); 69478064Sume#else /* old adv. API */ 69578064Sume if (setsockopt(s, IPPROTO_IPV6, IPV6_DSTOPTS, &opton, 69678064Sume sizeof(opton))) 69778064Sume err(1, "setsockopt(IPV6_DSTOPTS)"); 69878064Sume#endif 69978064Sume#ifdef IPV6_RECVRTHDRDSTOPTS 70078064Sume if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDRDSTOPTS, &opton, 70178064Sume sizeof(opton))) 70278064Sume err(1, "setsockopt(IPV6_RECVRTHDRDSTOPTS)"); 70378064Sume#endif 70478064Sume } 70578064Sume 70678064Sume /* revoke root privilege */ 70778064Sume seteuid(getuid()); 70878064Sume setuid(getuid()); 70978064Sume 710121472Sume if ((options & F_FLOOD) && (options & F_INTERVAL)) 71155163Sshin errx(1, "-f and -i incompatible options"); 71255163Sshin 71378064Sume if ((options & F_NOUSERDATA) == 0) { 714121472Sume if (datalen >= sizeof(struct tv32)) { 71578064Sume /* we can time transfer */ 71678064Sume timing = 1; 71778064Sume } else 71878064Sume timing = 0; 71978064Sume /* in F_VERBOSE case, we may get non-echoreply packets*/ 72078064Sume if (options & F_VERBOSE) 72178064Sume packlen = 2048 + IP6LEN + ICMP6ECHOLEN + EXTRA; 72278064Sume else 72378064Sume packlen = datalen + IP6LEN + ICMP6ECHOLEN + EXTRA; 72478064Sume } else { 72578064Sume /* suppress timing for node information query */ 72678064Sume timing = 0; 72778064Sume datalen = 2048; 72878064Sume packlen = 2048 + IP6LEN + ICMP6ECHOLEN + EXTRA; 72978064Sume } 73078064Sume 73155163Sshin if (!(packet = (u_char *)malloc((u_int)packlen))) 732121472Sume err(1, "Unable to allocate packet"); 73355163Sshin if (!(options & F_PINGFILLED)) 73478064Sume for (i = ICMP6ECHOLEN; i < packlen; ++i) 73555163Sshin *datap++ = i; 73655163Sshin 73755163Sshin ident = getpid() & 0xFFFF; 738121472Sume#ifndef HAVE_ARC4RANDOM 739121472Sume gettimeofday(&seed, NULL); 740121472Sume srand((unsigned int)(seed.tv_sec ^ seed.tv_usec ^ (long)ident)); 74178064Sume memset(nonce, 0, sizeof(nonce)); 74278064Sume for (i = 0; i < sizeof(nonce); i += sizeof(int)) 74378064Sume *((int *)&nonce[i]) = rand(); 74478064Sume#else 74578064Sume memset(nonce, 0, sizeof(nonce)); 74678064Sume for (i = 0; i < sizeof(nonce); i += sizeof(u_int32_t)) 74778064Sume *((u_int32_t *)&nonce[i]) = arc4random(); 74878064Sume#endif 749206889Smaxim optval = 1; 750206889Smaxim if (options & F_DONTFRAG) 751206889Smaxim if (setsockopt(s, IPPROTO_IPV6, IPV6_DONTFRAG, 752206889Smaxim &optval, sizeof(optval)) == -1) 753206889Smaxim err(1, "IPV6_DONTFRAG"); 75455163Sshin hold = 1; 75555163Sshin 75655163Sshin if (options & F_SO_DEBUG) 75755163Sshin (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold, 75855163Sshin sizeof(hold)); 75955163Sshin optval = IPV6_DEFHLIM; 76055163Sshin if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) 76155163Sshin if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 76278064Sume &optval, sizeof(optval)) == -1) 76355163Sshin err(1, "IPV6_MULTICAST_HOPS"); 76478064Sume#ifdef IPV6_USE_MIN_MTU 765121472Sume if (mflag != 1) { 766121472Sume optval = mflag > 1 ? 0 : 1; 767121472Sume 76878064Sume if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU, 76978064Sume &optval, sizeof(optval)) == -1) 77078064Sume err(1, "setsockopt(IPV6_USE_MIN_MTU)"); 77178064Sume } 77278064Sume#ifdef IPV6_RECVPATHMTU 77378064Sume else { 77478064Sume optval = 1; 77578064Sume if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPATHMTU, 77678064Sume &optval, sizeof(optval)) == -1) 77778064Sume err(1, "setsockopt(IPV6_RECVPATHMTU)"); 77878064Sume } 77978064Sume#endif /* IPV6_RECVPATHMTU */ 78078064Sume#endif /* IPV6_USE_MIN_MTU */ 78155163Sshin 78255163Sshin#ifdef IPSEC 78355163Sshin#ifdef IPSEC_POLICY_IPSEC 78455163Sshin if (options & F_POLICY) { 78555163Sshin if (setpolicy(s, policy_in) < 0) 78664277Skris errx(1, "%s", ipsec_strerror()); 78755163Sshin if (setpolicy(s, policy_out) < 0) 78864277Skris errx(1, "%s", ipsec_strerror()); 78955163Sshin } 79055163Sshin#else 79155163Sshin if (options & F_AUTHHDR) { 79255163Sshin optval = IPSEC_LEVEL_REQUIRE; 79355163Sshin#ifdef IPV6_AUTH_TRANS_LEVEL 79455163Sshin if (setsockopt(s, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, 79578064Sume &optval, sizeof(optval)) == -1) 79655163Sshin err(1, "setsockopt(IPV6_AUTH_TRANS_LEVEL)"); 79755163Sshin#else /* old def */ 79855163Sshin if (setsockopt(s, IPPROTO_IPV6, IPV6_AUTH_LEVEL, 79978064Sume &optval, sizeof(optval)) == -1) 80055163Sshin err(1, "setsockopt(IPV6_AUTH_LEVEL)"); 80155163Sshin#endif 80255163Sshin } 80355163Sshin if (options & F_ENCRYPT) { 80455163Sshin optval = IPSEC_LEVEL_REQUIRE; 80555163Sshin if (setsockopt(s, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, 80678064Sume &optval, sizeof(optval)) == -1) 80755163Sshin err(1, "setsockopt(IPV6_ESP_TRANS_LEVEL)"); 80855163Sshin } 80955163Sshin#endif /*IPSEC_POLICY_IPSEC*/ 81055163Sshin#endif 81155163Sshin 81255163Sshin#ifdef ICMP6_FILTER 81355163Sshin { 81455163Sshin struct icmp6_filter filt; 81555163Sshin if (!(options & F_VERBOSE)) { 81655163Sshin ICMP6_FILTER_SETBLOCKALL(&filt); 81762627Skris if ((options & F_FQDN) || (options & F_FQDNOLD) || 81878064Sume (options & F_NODEADDR) || (options & F_SUPTYPES)) 81955163Sshin ICMP6_FILTER_SETPASS(ICMP6_NI_REPLY, &filt); 82055163Sshin else 82155163Sshin ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt); 82255163Sshin } else { 82355163Sshin ICMP6_FILTER_SETPASSALL(&filt); 82455163Sshin } 82555163Sshin if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, 82678064Sume sizeof(filt)) < 0) 82755163Sshin err(1, "setsockopt(ICMP6_FILTER)"); 82855163Sshin } 82955163Sshin#endif /*ICMP6_FILTER*/ 83055163Sshin 83162627Skris /* let the kerel pass extension headers of incoming packets */ 83262627Skris if ((options & F_VERBOSE) != 0) { 83362627Skris int opton = 1; 83462627Skris 83562627Skris#ifdef IPV6_RECVRTHDR 83662627Skris if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDR, &opton, 83778064Sume sizeof(opton))) 83862627Skris err(1, "setsockopt(IPV6_RECVRTHDR)"); 83962627Skris#else /* old adv. API */ 84062627Skris if (setsockopt(s, IPPROTO_IPV6, IPV6_RTHDR, &opton, 84178064Sume sizeof(opton))) 84262627Skris err(1, "setsockopt(IPV6_RTHDR)"); 84362627Skris#endif 84462627Skris } 84562627Skris 84655163Sshin/* 84755163Sshin optval = 1; 84855163Sshin if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) 84955163Sshin if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 85078064Sume &optval, sizeof(optval)) == -1) 85155163Sshin err(1, "IPV6_MULTICAST_LOOP"); 85255163Sshin*/ 85355163Sshin 85462627Skris /* Specify the outgoing interface and/or the source address */ 85562627Skris if (usepktinfo) 85655163Sshin ip6optlen += CMSG_SPACE(sizeof(struct in6_pktinfo)); 85755163Sshin 85855163Sshin if (hoplimit != -1) 85955163Sshin ip6optlen += CMSG_SPACE(sizeof(int)); 86055163Sshin 86155163Sshin /* set IP6 packet options */ 86255163Sshin if (ip6optlen) { 86355163Sshin if ((scmsg = (char *)malloc(ip6optlen)) == 0) 86455163Sshin errx(1, "can't allocate enough memory"); 86555163Sshin smsghdr.msg_control = (caddr_t)scmsg; 86655163Sshin smsghdr.msg_controllen = ip6optlen; 86755163Sshin scmsgp = (struct cmsghdr *)scmsg; 86855163Sshin } 86962627Skris if (usepktinfo) { 87062627Skris pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp)); 87162627Skris memset(pktinfo, 0, sizeof(*pktinfo)); 87255163Sshin scmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 87355163Sshin scmsgp->cmsg_level = IPPROTO_IPV6; 87455163Sshin scmsgp->cmsg_type = IPV6_PKTINFO; 87562627Skris scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp); 87662627Skris } 87755163Sshin 87862627Skris /* set the outgoing interface */ 87962627Skris if (ifname) { 88062627Skris#ifndef USE_SIN6_SCOPE_ID 88162627Skris /* pktinfo must have already been allocated */ 88262627Skris if ((pktinfo->ipi6_ifindex = if_nametoindex(ifname)) == 0) 88378064Sume errx(1, "%s: invalid interface name", ifname); 88455163Sshin#else 88555163Sshin if ((dst.sin6_scope_id = if_nametoindex(ifname)) == 0) 88655163Sshin errx(1, "%s: invalid interface name", ifname); 88755163Sshin#endif 88855163Sshin } 88955163Sshin if (hoplimit != -1) { 89055163Sshin scmsgp->cmsg_len = CMSG_LEN(sizeof(int)); 89155163Sshin scmsgp->cmsg_level = IPPROTO_IPV6; 89255163Sshin scmsgp->cmsg_type = IPV6_HOPLIMIT; 89355163Sshin *(int *)(CMSG_DATA(scmsgp)) = hoplimit; 89455163Sshin 89555163Sshin scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp); 89655163Sshin } 89762627Skris 89855163Sshin if (argc > 1) { /* some intermediate addrs are specified */ 89955163Sshin int hops, error; 90062627Skris#ifdef USE_RFC2292BIS 90162627Skris int rthdrlen; 90262627Skris#endif 90355163Sshin 90462627Skris#ifdef USE_RFC2292BIS 90562627Skris rthdrlen = inet6_rth_space(IPV6_RTHDR_TYPE_0, argc - 1); 90662627Skris scmsgp->cmsg_len = CMSG_LEN(rthdrlen); 90762627Skris scmsgp->cmsg_level = IPPROTO_IPV6; 90862627Skris scmsgp->cmsg_type = IPV6_RTHDR; 90962627Skris rthdr = (struct ip6_rthdr *)CMSG_DATA(scmsgp); 91062627Skris rthdr = inet6_rth_init((void *)rthdr, rthdrlen, 91178064Sume IPV6_RTHDR_TYPE_0, argc - 1); 91262627Skris if (rthdr == NULL) 91362627Skris errx(1, "can't initialize rthdr"); 91462627Skris#else /* old advanced API */ 91555163Sshin if ((scmsgp = (struct cmsghdr *)inet6_rthdr_init(scmsgp, 91678064Sume IPV6_RTHDR_TYPE_0)) == 0) 91755163Sshin errx(1, "can't initialize rthdr"); 91862627Skris#endif /* USE_RFC2292BIS */ 91955163Sshin 92055163Sshin for (hops = 0; hops < argc - 1; hops++) { 92155163Sshin struct addrinfo *iaip; 92255163Sshin 92378064Sume if ((error = getaddrinfo(argv[hops], NULL, &hints, 92478064Sume &iaip))) 92564277Skris errx(1, "%s", gai_strerror(error)); 92678064Sume if (SIN6(iaip->ai_addr)->sin6_family != AF_INET6) 92755163Sshin errx(1, 92878064Sume "bad addr family of an intermediate addr"); 92955163Sshin 93062627Skris#ifdef USE_RFC2292BIS 93162627Skris if (inet6_rth_add(rthdr, 93278064Sume &(SIN6(iaip->ai_addr))->sin6_addr)) 93362627Skris errx(1, "can't add an intermediate node"); 93462627Skris#else /* old advanced API */ 93555163Sshin if (inet6_rthdr_add(scmsgp, 93678064Sume &(SIN6(iaip->ai_addr))->sin6_addr, 93778064Sume IPV6_RTHDR_LOOSE)) 93855163Sshin errx(1, "can't add an intermediate node"); 93962627Skris#endif /* USE_RFC2292BIS */ 94078064Sume freeaddrinfo(iaip); 94155163Sshin } 94255163Sshin 94362627Skris#ifndef USE_RFC2292BIS 94455163Sshin if (inet6_rthdr_lasthop(scmsgp, IPV6_RTHDR_LOOSE)) 94555163Sshin errx(1, "can't set the last flag"); 94662627Skris#endif 94755163Sshin 94855163Sshin scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp); 94955163Sshin } 95055163Sshin 951121472Sume if (!(options & F_SRCADDR)) { 95255163Sshin /* 953121472Sume * get the source address. XXX since we revoked the root 954121472Sume * privilege, we cannot use a raw socket for this. 95555163Sshin */ 956121472Sume int dummy; 957121472Sume socklen_t len = sizeof(src); 95878064Sume 95955163Sshin if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 96055163Sshin err(1, "UDP socket"); 96155163Sshin 96255163Sshin src.sin6_family = AF_INET6; 96355163Sshin src.sin6_addr = dst.sin6_addr; 96455163Sshin src.sin6_port = ntohs(DUMMY_PORT); 96555163Sshin src.sin6_scope_id = dst.sin6_scope_id; 96655163Sshin 96762627Skris#ifdef USE_RFC2292BIS 96862627Skris if (pktinfo && 96962627Skris setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTINFO, 97078064Sume (void *)pktinfo, sizeof(*pktinfo))) 97162627Skris err(1, "UDP setsockopt(IPV6_PKTINFO)"); 97262627Skris 97362627Skris if (hoplimit != -1 && 974121472Sume setsockopt(dummy, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 97578064Sume (void *)&hoplimit, sizeof(hoplimit))) 976121472Sume err(1, "UDP setsockopt(IPV6_UNICAST_HOPS)"); 97762627Skris 978121472Sume if (hoplimit != -1 && 979121472Sume setsockopt(dummy, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 980121472Sume (void *)&hoplimit, sizeof(hoplimit))) 981121472Sume err(1, "UDP setsockopt(IPV6_MULTICAST_HOPS)"); 982121472Sume 98362627Skris if (rthdr && 98462627Skris setsockopt(dummy, IPPROTO_IPV6, IPV6_RTHDR, 98578064Sume (void *)rthdr, (rthdr->ip6r_len + 1) << 3)) 98662627Skris err(1, "UDP setsockopt(IPV6_RTHDR)"); 98762627Skris#else /* old advanced API */ 98862627Skris if (smsghdr.msg_control && 98962627Skris setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTOPTIONS, 99078064Sume (void *)smsghdr.msg_control, smsghdr.msg_controllen)) 99162627Skris err(1, "UDP setsockopt(IPV6_PKTOPTIONS)"); 99255163Sshin#endif 99378064Sume 99455163Sshin if (connect(dummy, (struct sockaddr *)&src, len) < 0) 99555163Sshin err(1, "UDP connect"); 99678064Sume 99755163Sshin if (getsockname(dummy, (struct sockaddr *)&src, &len) < 0) 99855163Sshin err(1, "getsockname"); 99955163Sshin 100055163Sshin close(dummy); 100155163Sshin } 100255163Sshin 100355163Sshin#if defined(SO_SNDBUF) && defined(SO_RCVBUF) 100455163Sshin if (sockbufsize) { 100555163Sshin if (datalen > sockbufsize) 100662627Skris warnx("you need -b to increase socket buffer size"); 100755163Sshin if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sockbufsize, 100878064Sume sizeof(sockbufsize)) < 0) 100955163Sshin err(1, "setsockopt(SO_SNDBUF)"); 101055163Sshin if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &sockbufsize, 101178064Sume sizeof(sockbufsize)) < 0) 101255163Sshin err(1, "setsockopt(SO_RCVBUF)"); 101355163Sshin } 101455163Sshin else { 101555163Sshin if (datalen > 8 * 1024) /*XXX*/ 101655163Sshin warnx("you need -b to increase socket buffer size"); 101755163Sshin /* 101855163Sshin * When pinging the broadcast address, you can get a lot of 101955163Sshin * answers. Doing something so evil is useful if you are trying 102055163Sshin * to stress the ethernet, or just want to fill the arp cache 102155163Sshin * to get some stuff for /etc/ethers. 102255163Sshin */ 102355163Sshin hold = 48 * 1024; 102478064Sume setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold, 102578064Sume sizeof(hold)); 102655163Sshin } 102755163Sshin#endif 102855163Sshin 102955163Sshin optval = 1; 103055163Sshin#ifndef USE_SIN6_SCOPE_ID 103162627Skris#ifdef IPV6_RECVPKTINFO 103262627Skris if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &optval, 103378064Sume sizeof(optval)) < 0) 103462627Skris warn("setsockopt(IPV6_RECVPKTINFO)"); /* XXX err? */ 103562627Skris#else /* old adv. API */ 103662627Skris if (setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &optval, 103778064Sume sizeof(optval)) < 0) 103862627Skris warn("setsockopt(IPV6_PKTINFO)"); /* XXX err? */ 103955163Sshin#endif 104062627Skris#endif /* USE_SIN6_SCOPE_ID */ 104162627Skris#ifdef IPV6_RECVHOPLIMIT 104262627Skris if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &optval, 104378064Sume sizeof(optval)) < 0) 104462627Skris warn("setsockopt(IPV6_RECVHOPLIMIT)"); /* XXX err? */ 104562627Skris#else /* old adv. API */ 104662627Skris if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPLIMIT, &optval, 104778064Sume sizeof(optval)) < 0) 104862627Skris warn("setsockopt(IPV6_HOPLIMIT)"); /* XXX err? */ 104962627Skris#endif 105055163Sshin 105178064Sume printf("PING6(%lu=40+8+%lu bytes) ", (unsigned long)(40 + pingerlen()), 105278064Sume (unsigned long)(pingerlen() - 8)); 105378064Sume printf("%s --> ", pr_addr((struct sockaddr *)&src, sizeof(src))); 105478064Sume printf("%s\n", pr_addr((struct sockaddr *)&dst, sizeof(dst))); 105555163Sshin 105655163Sshin while (preload--) /* Fire off them quickies. */ 105778984Sume (void)pinger(); 105855163Sshin 105978064Sume (void)signal(SIGINT, onsignal); 106078064Sume#ifdef SIGINFO 106178064Sume (void)signal(SIGINFO, onsignal); 106278064Sume#endif 106355163Sshin 106455163Sshin if ((options & F_FLOOD) == 0) { 106578064Sume (void)signal(SIGALRM, onsignal); 106678064Sume itimer.it_interval = interval; 106778064Sume itimer.it_value = interval; 106855163Sshin (void)setitimer(ITIMER_REAL, &itimer, NULL); 1069132656Ssuz if (ntransmitted == 0) 107089394Sru retransmit(); 107155163Sshin } 107255163Sshin 1073121472Sume#ifndef HAVE_POLL_H 107478064Sume fdmasks = howmany(s + 1, NFDBITS) * sizeof(fd_mask); 107566811Skris if ((fdmaskp = malloc(fdmasks)) == NULL) 107666811Skris err(1, "malloc"); 1077121472Sume#endif 107866811Skris 1079121472Sume seenalrm = seenint = 0; 108078064Sume#ifdef SIGINFO 108178064Sume seeninfo = 0; 108278064Sume#endif 108378064Sume 108455163Sshin for (;;) { 108555163Sshin struct msghdr m; 108655163Sshin struct iovec iov[2]; 108755163Sshin 108878064Sume /* signal handling */ 108978064Sume if (seenalrm) { 1090179356Sbz /* last packet sent, timeout reached? */ 1091179356Sbz if (npackets && ntransmitted >= npackets) 1092179356Sbz break; 109378064Sume retransmit(); 109478064Sume seenalrm = 0; 109578064Sume continue; 109678064Sume } 109778064Sume if (seenint) { 109878064Sume onint(SIGINT); 109978064Sume seenint = 0; 110078064Sume continue; 110178064Sume } 110278064Sume#ifdef SIGINFO 110378064Sume if (seeninfo) { 110478064Sume summary(); 110578064Sume seeninfo = 0; 110678064Sume continue; 110778064Sume } 110878064Sume#endif 110978064Sume 111055163Sshin if (options & F_FLOOD) { 111178984Sume (void)pinger(); 1112121472Sume#ifdef HAVE_POLL_H 1113121472Sume timeout = 10; 1114121472Sume#else 111566811Skris timeout.tv_sec = 0; 111666811Skris timeout.tv_usec = 10000; 111778064Sume tv = &timeout; 1118121472Sume#endif 1119121472Sume } else { 1120121472Sume#ifdef HAVE_POLL_H 1121121472Sume timeout = INFTIM; 1122121472Sume#else 112378064Sume tv = NULL; 1124121472Sume#endif 1125121472Sume } 1126121472Sume#ifdef HAVE_POLL_H 1127121472Sume fdmaskp[0].fd = s; 1128121472Sume fdmaskp[0].events = POLLIN; 1129121472Sume cc = poll(fdmaskp, 1, timeout); 1130121472Sume#else 113178064Sume memset(fdmaskp, 0, fdmasks); 113278064Sume FD_SET(s, fdmaskp); 113378064Sume cc = select(s + 1, fdmaskp, NULL, NULL, tv); 1134121472Sume#endif 113578064Sume if (cc < 0) { 113678064Sume if (errno != EINTR) { 1137121472Sume#ifdef HAVE_POLL_H 1138121472Sume warn("poll"); 1139121472Sume#else 114078064Sume warn("select"); 1141121472Sume#endif 114278064Sume sleep(1); 114378064Sume } 114478064Sume continue; 114578064Sume } else if (cc == 0) 114678064Sume continue; 114778064Sume 114855163Sshin m.msg_name = (caddr_t)&from; 114955163Sshin m.msg_namelen = sizeof(from); 115055163Sshin memset(&iov, 0, sizeof(iov)); 115155163Sshin iov[0].iov_base = (caddr_t)packet; 115255163Sshin iov[0].iov_len = packlen; 115355163Sshin m.msg_iov = iov; 115455163Sshin m.msg_iovlen = 1; 1155168866Smtm memset(cm, 0, CONTROLLEN); 1156168866Smtm m.msg_control = (void *)cm; 1157168866Smtm m.msg_controllen = CONTROLLEN; 115855163Sshin 115978064Sume cc = recvmsg(s, &m, 0); 116078064Sume if (cc < 0) { 116178064Sume if (errno != EINTR) { 116278064Sume warn("recvmsg"); 116378064Sume sleep(1); 116478064Sume } 116555163Sshin continue; 116678064Sume } else if (cc == 0) { 116778064Sume int mtu; 116878064Sume 116978064Sume /* 117078064Sume * receive control messages only. Process the 117178064Sume * exceptions (currently the only possiblity is 117278064Sume * a path MTU notification.) 117378064Sume */ 117478064Sume if ((mtu = get_pathmtu(&m)) > 0) { 117578064Sume if ((options & F_VERBOSE) != 0) { 117678064Sume printf("new path MTU (%d) is " 117778064Sume "notified\n", mtu); 117878064Sume } 117978064Sume } 118078064Sume continue; 118178064Sume } else { 118278064Sume /* 118378064Sume * an ICMPv6 message (probably an echoreply) arrived. 118478064Sume */ 118578064Sume pr_pack(packet, cc, &m); 118655163Sshin } 1187173765Sdd if (((options & F_ONCE) != 0 && nreceived > 0) || 1188173765Sdd (npackets > 0 && nreceived >= npackets)) 118955163Sshin break; 1190182276Smatteo if (ntransmitted - nreceived - 1 > nmissedmax) { 1191182276Smatteo nmissedmax = ntransmitted - nreceived - 1; 1192182276Smatteo if (options & F_MISSED) 1193182276Smatteo (void)write(STDOUT_FILENO, &BBELL, 1); 1194182276Smatteo } 119555163Sshin } 119655163Sshin summary(); 1197209236Sbrucec 1198209236Sbrucec if (res != NULL) 1199209236Sbrucec freeaddrinfo(res); 1200209236Sbrucec 1201209236Sbrucec if(packet != NULL) 1202209236Sbrucec free(packet); 1203209236Sbrucec 1204209236Sbrucec#ifndef HAVE_POLL_H 1205209236Sbrucec if(fdmaskp != NULL) 1206209236Sbrucec free(fdmaskp); 1207209236Sbrucec#endif 1208209236Sbrucec 1209179356Sbz exit(nreceived == 0 ? 2 : 0); 121055163Sshin} 121155163Sshin 121278064Sumevoid 1213216561Scharnieronsignal(int sig) 121478064Sume{ 1215121472Sume 121678064Sume switch (sig) { 121778064Sume case SIGALRM: 121878064Sume seenalrm++; 121978064Sume break; 122078064Sume case SIGINT: 122178064Sume seenint++; 122278064Sume break; 122378064Sume#ifdef SIGINFO 122478064Sume case SIGINFO: 122578064Sume seeninfo++; 122678064Sume break; 122778064Sume#endif 122878064Sume } 122978064Sume} 123078064Sume 123155163Sshin/* 123278064Sume * retransmit -- 123355163Sshin * This routine transmits another ping6. 123455163Sshin */ 123555163Sshinvoid 1236216561Scharnierretransmit(void) 123755163Sshin{ 123855163Sshin struct itimerval itimer; 123955163Sshin 124078984Sume if (pinger() == 0) 124155163Sshin return; 124255163Sshin 124355163Sshin /* 124455163Sshin * If we're not transmitting any more packets, change the timer 124555163Sshin * to wait two round-trip times if we've received any packets or 124655163Sshin * ten seconds if we haven't. 124755163Sshin */ 124855163Sshin#define MAXWAIT 10 124955163Sshin if (nreceived) { 125055163Sshin itimer.it_value.tv_sec = 2 * tmax / 1000; 125155163Sshin if (itimer.it_value.tv_sec == 0) 125255163Sshin itimer.it_value.tv_sec = 1; 125355163Sshin } else 125455163Sshin itimer.it_value.tv_sec = MAXWAIT; 125555163Sshin itimer.it_interval.tv_sec = 0; 125655163Sshin itimer.it_interval.tv_usec = 0; 125755163Sshin itimer.it_value.tv_usec = 0; 125855163Sshin 1259179356Sbz (void)signal(SIGALRM, onsignal); 126055163Sshin (void)setitimer(ITIMER_REAL, &itimer, NULL); 126155163Sshin} 126255163Sshin 126355163Sshin/* 126455163Sshin * pinger -- 126555163Sshin * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet 126655163Sshin * will be added on by the kernel. The ID field is our UNIX process ID, 126755163Sshin * and the sequence number is an ascending integer. The first 8 bytes 126855163Sshin * of the data portion are used to hold a UNIX "timeval" struct in VAX 126955163Sshin * byte-order, to compute the round-trip time. 127055163Sshin */ 127178064Sumesize_t 1272216561Scharnierpingerlen(void) 127378064Sume{ 127478064Sume size_t l; 127578064Sume 127678064Sume if (options & F_FQDN) 127778064Sume l = ICMP6_NIQLEN + sizeof(dst.sin6_addr); 127878064Sume else if (options & F_FQDNOLD) 127978064Sume l = ICMP6_NIQLEN; 128078064Sume else if (options & F_NODEADDR) 128178064Sume l = ICMP6_NIQLEN + sizeof(dst.sin6_addr); 128278064Sume else if (options & F_SUPTYPES) 128378064Sume l = ICMP6_NIQLEN; 128478064Sume else 128578064Sume l = ICMP6ECHOLEN + datalen; 128678064Sume 128778064Sume return l; 128878064Sume} 128978064Sume 129078984Sumeint 1291216561Scharnierpinger(void) 129255163Sshin{ 129355163Sshin struct icmp6_hdr *icp; 129455163Sshin struct iovec iov[2]; 129555163Sshin int i, cc; 129678064Sume struct icmp6_nodeinfo *nip; 129778064Sume int seq; 129855163Sshin 129978984Sume if (npackets && ntransmitted >= npackets) 130078984Sume return(-1); /* no more transmission */ 130178984Sume 130255163Sshin icp = (struct icmp6_hdr *)outpack; 130378064Sume nip = (struct icmp6_nodeinfo *)outpack; 130462627Skris memset(icp, 0, sizeof(*icp)); 130555163Sshin icp->icmp6_cksum = 0; 130678064Sume seq = ntransmitted++; 130778064Sume CLR(seq % mx_dup_ck); 130855163Sshin 130955163Sshin if (options & F_FQDN) { 131055163Sshin icp->icmp6_type = ICMP6_NI_QUERY; 131162627Skris icp->icmp6_code = ICMP6_NI_SUBJ_IPV6; 131278064Sume nip->ni_qtype = htons(NI_QTYPE_FQDN); 131378064Sume nip->ni_flags = htons(0); 131478064Sume 131578064Sume memcpy(nip->icmp6_ni_nonce, nonce, 131678064Sume sizeof(nip->icmp6_ni_nonce)); 131778064Sume *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); 131878064Sume 131962627Skris memcpy(&outpack[ICMP6_NIQLEN], &dst.sin6_addr, 132062627Skris sizeof(dst.sin6_addr)); 132162627Skris cc = ICMP6_NIQLEN + sizeof(dst.sin6_addr); 132262627Skris datalen = 0; 132362627Skris } else if (options & F_FQDNOLD) { 132462627Skris /* packet format in 03 draft - no Subject data on queries */ 132562627Skris icp->icmp6_type = ICMP6_NI_QUERY; 132678064Sume icp->icmp6_code = 0; /* code field is always 0 */ 132778064Sume nip->ni_qtype = htons(NI_QTYPE_FQDN); 132878064Sume nip->ni_flags = htons(0); 132978064Sume 133078064Sume memcpy(nip->icmp6_ni_nonce, nonce, 133178064Sume sizeof(nip->icmp6_ni_nonce)); 133278064Sume *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); 133378064Sume 133455163Sshin cc = ICMP6_NIQLEN; 133555163Sshin datalen = 0; 133655163Sshin } else if (options & F_NODEADDR) { 133755163Sshin icp->icmp6_type = ICMP6_NI_QUERY; 133862627Skris icp->icmp6_code = ICMP6_NI_SUBJ_IPV6; 133978064Sume nip->ni_qtype = htons(NI_QTYPE_NODEADDR); 134078064Sume nip->ni_flags = naflags; 134178064Sume 134278064Sume memcpy(nip->icmp6_ni_nonce, nonce, 134378064Sume sizeof(nip->icmp6_ni_nonce)); 134478064Sume *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); 134578064Sume 134662627Skris memcpy(&outpack[ICMP6_NIQLEN], &dst.sin6_addr, 134762627Skris sizeof(dst.sin6_addr)); 134862627Skris cc = ICMP6_NIQLEN + sizeof(dst.sin6_addr); 134955163Sshin datalen = 0; 135078064Sume } else if (options & F_SUPTYPES) { 135178064Sume icp->icmp6_type = ICMP6_NI_QUERY; 135278064Sume icp->icmp6_code = ICMP6_NI_SUBJ_FQDN; /*empty*/ 135378064Sume nip->ni_qtype = htons(NI_QTYPE_SUPTYPES); 135478064Sume /* we support compressed bitmap */ 135578064Sume nip->ni_flags = NI_SUPTYPE_FLAG_COMPRESS; 135678064Sume 135778064Sume memcpy(nip->icmp6_ni_nonce, nonce, 135878064Sume sizeof(nip->icmp6_ni_nonce)); 135978064Sume *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); 136078064Sume cc = ICMP6_NIQLEN; 136178064Sume datalen = 0; 136278064Sume } else { 136355163Sshin icp->icmp6_type = ICMP6_ECHO_REQUEST; 136478064Sume icp->icmp6_code = 0; 136578064Sume icp->icmp6_id = htons(ident); 136678064Sume icp->icmp6_seq = ntohs(seq); 1367121472Sume if (timing) { 1368121472Sume struct timeval tv; 1369121472Sume struct tv32 *tv32; 1370121472Sume (void)gettimeofday(&tv, NULL); 1371121472Sume tv32 = (struct tv32 *)&outpack[ICMP6ECHOLEN]; 1372121472Sume tv32->tv32_sec = htonl(tv.tv_sec); 1373121472Sume tv32->tv32_usec = htonl(tv.tv_usec); 1374121472Sume } 137555163Sshin cc = ICMP6ECHOLEN + datalen; 137655163Sshin } 137755163Sshin 137878064Sume#ifdef DIAGNOSTIC 137978064Sume if (pingerlen() != cc) 138078064Sume errx(1, "internal error; length mismatch"); 138178064Sume#endif 138278064Sume 138355163Sshin smsghdr.msg_name = (caddr_t)&dst; 138455163Sshin smsghdr.msg_namelen = sizeof(dst); 138555163Sshin memset(&iov, 0, sizeof(iov)); 138655163Sshin iov[0].iov_base = (caddr_t)outpack; 138755163Sshin iov[0].iov_len = cc; 138855163Sshin smsghdr.msg_iov = iov; 138955163Sshin smsghdr.msg_iovlen = 1; 139055163Sshin 139155163Sshin i = sendmsg(s, &smsghdr, 0); 139255163Sshin 139355163Sshin if (i < 0 || i != cc) { 139455163Sshin if (i < 0) 139555163Sshin warn("sendmsg"); 139655163Sshin (void)printf("ping6: wrote %s %d chars, ret=%d\n", 139755163Sshin hostname, cc, i); 139855163Sshin } 139955163Sshin if (!(options & F_QUIET) && options & F_FLOOD) 140055163Sshin (void)write(STDOUT_FILENO, &DOT, 1); 140178984Sume 140278984Sume return(0); 140355163Sshin} 140455163Sshin 140578064Sumeint 1406216561Scharniermyechoreply(const struct icmp6_hdr *icp) 140778064Sume{ 140878064Sume if (ntohs(icp->icmp6_id) == ident) 140978064Sume return 1; 141078064Sume else 141178064Sume return 0; 141278064Sume} 141378064Sume 141478064Sumeint 1415216561Scharniermynireply(const struct icmp6_nodeinfo *nip) 141678064Sume{ 141778064Sume if (memcmp(nip->icmp6_ni_nonce + sizeof(u_int16_t), 141878064Sume nonce + sizeof(u_int16_t), 141978064Sume sizeof(nonce) - sizeof(u_int16_t)) == 0) 142078064Sume return 1; 142178064Sume else 142278064Sume return 0; 142378064Sume} 142478064Sume 142578064Sumechar * 1426216561Scharnierdnsdecode(const u_char **sp, const u_char *ep, const u_char *base, char *buf, 1427216561Scharnier size_t bufsiz) 1428216561Scharnier /*base for compressed name*/ 142978064Sume{ 143078064Sume int i; 143178064Sume const u_char *cp; 143278064Sume char cresult[MAXDNAME + 1]; 143378064Sume const u_char *comp; 143478064Sume int l; 143578064Sume 143678064Sume cp = *sp; 143778064Sume *buf = '\0'; 143878064Sume 143978064Sume if (cp >= ep) 144078064Sume return NULL; 144178064Sume while (cp < ep) { 144278064Sume i = *cp; 144378064Sume if (i == 0 || cp != *sp) { 1444121472Sume if (strlcat((char *)buf, ".", bufsiz) >= bufsiz) 144578064Sume return NULL; /*result overrun*/ 144678064Sume } 144778064Sume if (i == 0) 144878064Sume break; 144978064Sume cp++; 145078064Sume 145178064Sume if ((i & 0xc0) == 0xc0 && cp - base > (i & 0x3f)) { 145278064Sume /* DNS compression */ 145378064Sume if (!base) 145478064Sume return NULL; 145578064Sume 145678064Sume comp = base + (i & 0x3f); 145778064Sume if (dnsdecode(&comp, cp, base, cresult, 145878064Sume sizeof(cresult)) == NULL) 145978064Sume return NULL; 146078064Sume if (strlcat(buf, cresult, bufsiz) >= bufsiz) 146178064Sume return NULL; /*result overrun*/ 146278064Sume break; 146378064Sume } else if ((i & 0x3f) == i) { 146478064Sume if (i > ep - cp) 146578064Sume return NULL; /*source overrun*/ 146678064Sume while (i-- > 0 && cp < ep) { 146778064Sume l = snprintf(cresult, sizeof(cresult), 146878064Sume isprint(*cp) ? "%c" : "\\%03o", *cp & 0xff); 1469121472Sume if (l >= sizeof(cresult) || l < 0) 147078064Sume return NULL; 147178064Sume if (strlcat(buf, cresult, bufsiz) >= bufsiz) 147278064Sume return NULL; /*result overrun*/ 147378064Sume cp++; 147478064Sume } 147578064Sume } else 147678064Sume return NULL; /*invalid label*/ 147778064Sume } 147878064Sume if (i != 0) 147978064Sume return NULL; /*not terminated*/ 148078064Sume cp++; 148178064Sume *sp = cp; 148278064Sume return buf; 148378064Sume} 148478064Sume 148555163Sshin/* 148655163Sshin * pr_pack -- 148755163Sshin * Print out the packet, if it came from us. This logic is necessary 148855163Sshin * because ALL readers of the ICMP socket get a copy of ALL ICMP packets 148955163Sshin * which arrive ('tis only fair). This permits multiple copies of this 149055163Sshin * program to be run without having intermingled output (or statistics!). 149155163Sshin */ 149255163Sshinvoid 1493216561Scharnierpr_pack(u_char *buf, int cc, struct msghdr *mhdr) 149455163Sshin{ 149562627Skris#define safeputc(c) printf((isprint((c)) ? "%c" : "\\%03o"), c) 149655163Sshin struct icmp6_hdr *icp; 149778064Sume struct icmp6_nodeinfo *ni; 149855163Sshin int i; 149955163Sshin int hoplim; 150078064Sume struct sockaddr *from; 150178064Sume int fromlen; 150255163Sshin u_char *cp = NULL, *dp, *end = buf + cc; 150362627Skris struct in6_pktinfo *pktinfo = NULL; 1504121472Sume struct timeval tv, tp; 1505121472Sume struct tv32 *tpp; 150655163Sshin double triptime = 0; 150755163Sshin int dupflag; 150855163Sshin size_t off; 150962627Skris int oldfqdn; 151078064Sume u_int16_t seq; 151178064Sume char dnsname[MAXDNAME + 1]; 151255163Sshin 151355163Sshin (void)gettimeofday(&tv, NULL); 151455163Sshin 151578064Sume if (!mhdr || !mhdr->msg_name || 151678064Sume mhdr->msg_namelen != sizeof(struct sockaddr_in6) || 151778064Sume ((struct sockaddr *)mhdr->msg_name)->sa_family != AF_INET6) { 151878064Sume if (options & F_VERBOSE) 1519121472Sume warnx("invalid peername"); 152078064Sume return; 152178064Sume } 152278064Sume from = (struct sockaddr *)mhdr->msg_name; 152378064Sume fromlen = mhdr->msg_namelen; 152455163Sshin if (cc < sizeof(struct icmp6_hdr)) { 152555163Sshin if (options & F_VERBOSE) 152687668Scharnier warnx("packet too short (%d bytes) from %s", cc, 152778064Sume pr_addr(from, fromlen)); 152855163Sshin return; 152955163Sshin } 1530168866Smtm if (((mhdr->msg_flags & MSG_CTRUNC) != 0) && 1531168866Smtm (options & F_VERBOSE) != 0) 1532168866Smtm warnx("some control data discarded, insufficient buffer size"); 153355163Sshin icp = (struct icmp6_hdr *)buf; 153478064Sume ni = (struct icmp6_nodeinfo *)buf; 153555163Sshin off = 0; 153655163Sshin 153755163Sshin if ((hoplim = get_hoplim(mhdr)) == -1) { 153855163Sshin warnx("failed to get receiving hop limit"); 153955163Sshin return; 154055163Sshin } 154162627Skris if ((pktinfo = get_rcvpktinfo(mhdr)) == NULL) { 154287668Scharnier warnx("failed to get receiving packet information"); 154362627Skris return; 154462627Skris } 154555163Sshin 154678064Sume if (icp->icmp6_type == ICMP6_ECHO_REPLY && myechoreply(icp)) { 154778064Sume seq = ntohs(icp->icmp6_seq); 154855163Sshin ++nreceived; 154955163Sshin if (timing) { 1550121472Sume tpp = (struct tv32 *)(icp + 1); 1551121472Sume tp.tv_sec = ntohl(tpp->tv32_sec); 1552121472Sume tp.tv_usec = ntohl(tpp->tv32_usec); 1553121472Sume tvsub(&tv, &tp); 155455163Sshin triptime = ((double)tv.tv_sec) * 1000.0 + 155555163Sshin ((double)tv.tv_usec) / 1000.0; 155655163Sshin tsum += triptime; 155778064Sume tsumsq += triptime * triptime; 155855163Sshin if (triptime < tmin) 155955163Sshin tmin = triptime; 156055163Sshin if (triptime > tmax) 156155163Sshin tmax = triptime; 156255163Sshin } 156355163Sshin 156478064Sume if (TST(seq % mx_dup_ck)) { 156555163Sshin ++nrepeats; 156655163Sshin --nreceived; 156755163Sshin dupflag = 1; 156855163Sshin } else { 156978064Sume SET(seq % mx_dup_ck); 157055163Sshin dupflag = 0; 157155163Sshin } 157255163Sshin 157355163Sshin if (options & F_QUIET) 157455163Sshin return; 157555163Sshin 157655163Sshin if (options & F_FLOOD) 157755163Sshin (void)write(STDOUT_FILENO, &BSPACE, 1); 157855163Sshin else { 1579182195Smatteo if (options & F_AUDIBLE) 1580182195Smatteo (void)write(STDOUT_FILENO, &BBELL, 1); 158155163Sshin (void)printf("%d bytes from %s, icmp_seq=%u", cc, 158278064Sume pr_addr(from, fromlen), seq); 158355163Sshin (void)printf(" hlim=%d", hoplim); 158462627Skris if ((options & F_VERBOSE) != 0) { 158562627Skris struct sockaddr_in6 dstsa; 158662627Skris 158762627Skris memset(&dstsa, 0, sizeof(dstsa)); 158862627Skris dstsa.sin6_family = AF_INET6; 158962627Skris dstsa.sin6_len = sizeof(dstsa); 159062627Skris dstsa.sin6_scope_id = pktinfo->ipi6_ifindex; 159162627Skris dstsa.sin6_addr = pktinfo->ipi6_addr; 159278064Sume (void)printf(" dst=%s", 159378064Sume pr_addr((struct sockaddr *)&dstsa, 159478064Sume sizeof(dstsa))); 159562627Skris } 159655163Sshin if (timing) 1597117824Smaxim (void)printf(" time=%.3f ms", triptime); 159855163Sshin if (dupflag) 159955163Sshin (void)printf("(DUP!)"); 160055163Sshin /* check the data */ 160155163Sshin cp = buf + off + ICMP6ECHOLEN + ICMP6ECHOTMLEN; 160255163Sshin dp = outpack + ICMP6ECHOLEN + ICMP6ECHOTMLEN; 160355163Sshin for (i = 8; cp < end; ++i, ++cp, ++dp) { 160455163Sshin if (*cp != *dp) { 160555163Sshin (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", i, *dp, *cp); 160655163Sshin break; 160755163Sshin } 160855163Sshin } 160955163Sshin } 161078064Sume } else if (icp->icmp6_type == ICMP6_NI_REPLY && mynireply(ni)) { 161178064Sume seq = ntohs(*(u_int16_t *)ni->icmp6_ni_nonce); 161278064Sume ++nreceived; 161378064Sume if (TST(seq % mx_dup_ck)) { 161478064Sume ++nrepeats; 161578064Sume --nreceived; 161678064Sume dupflag = 1; 161778064Sume } else { 161878064Sume SET(seq % mx_dup_ck); 161978064Sume dupflag = 0; 162078064Sume } 162155163Sshin 162278064Sume if (options & F_QUIET) 162378064Sume return; 162455163Sshin 162578064Sume (void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen)); 162678064Sume 162778064Sume switch (ntohs(ni->ni_code)) { 162878064Sume case ICMP6_NI_SUCCESS: 162978064Sume break; 163078064Sume case ICMP6_NI_REFUSED: 163178064Sume printf("refused, type 0x%x", ntohs(ni->ni_type)); 163278064Sume goto fqdnend; 163378064Sume case ICMP6_NI_UNKNOWN: 163478064Sume printf("unknown, type 0x%x", ntohs(ni->ni_type)); 163578064Sume goto fqdnend; 163678064Sume default: 163778064Sume printf("unknown code 0x%x, type 0x%x", 163878064Sume ntohs(ni->ni_code), ntohs(ni->ni_type)); 163978064Sume goto fqdnend; 164078064Sume } 164178064Sume 164278064Sume switch (ntohs(ni->ni_qtype)) { 164378064Sume case NI_QTYPE_NOOP: 164478064Sume printf("NodeInfo NOOP"); 164578064Sume break; 164678064Sume case NI_QTYPE_SUPTYPES: 164778064Sume pr_suptypes(ni, end - (u_char *)ni); 164878064Sume break; 164978064Sume case NI_QTYPE_NODEADDR: 165078064Sume pr_nodeaddr(ni, end - (u_char *)ni); 165178064Sume break; 165278064Sume case NI_QTYPE_FQDN: 165378064Sume default: /* XXX: for backward compatibility */ 165462627Skris cp = (u_char *)ni + ICMP6_NIRLEN; 165562627Skris if (buf[off + ICMP6_NIRLEN] == 165662627Skris cc - off - ICMP6_NIRLEN - 1) 165762627Skris oldfqdn = 1; 165862627Skris else 165962627Skris oldfqdn = 0; 166062627Skris if (oldfqdn) { 166178064Sume cp++; /* skip length */ 166262627Skris while (cp < end) { 166362627Skris safeputc(*cp & 0xff); 166462627Skris cp++; 166562627Skris } 166662627Skris } else { 166778064Sume i = 0; 166862627Skris while (cp < end) { 166978064Sume if (dnsdecode((const u_char **)&cp, end, 167078064Sume (const u_char *)(ni + 1), dnsname, 167178064Sume sizeof(dnsname)) == NULL) { 167278064Sume printf("???"); 167362627Skris break; 167462627Skris } 167578064Sume /* 167678064Sume * name-lookup special handling for 167778064Sume * truncated name 167878064Sume */ 167978064Sume if (cp + 1 <= end && !*cp && 168078064Sume strlen(dnsname) > 0) { 168178064Sume dnsname[strlen(dnsname) - 1] = '\0'; 168278064Sume cp++; 168378064Sume } 168478064Sume printf("%s%s", i > 0 ? "," : "", 168578064Sume dnsname); 168662627Skris } 168762627Skris } 168862627Skris if (options & F_VERBOSE) { 168962627Skris int32_t ttl; 169062627Skris int comma = 0; 169155163Sshin 169262627Skris (void)printf(" ("); /*)*/ 169355163Sshin 169478064Sume switch (ni->ni_code) { 169562627Skris case ICMP6_NI_REFUSED: 169662627Skris (void)printf("refused"); 169762627Skris comma++; 169862627Skris break; 169962627Skris case ICMP6_NI_UNKNOWN: 170087668Scharnier (void)printf("unknown qtype"); 170162627Skris comma++; 170262627Skris break; 170362627Skris } 170455163Sshin 170562627Skris if ((end - (u_char *)ni) < ICMP6_NIRLEN) { 170678064Sume /* case of refusion, unknown */ 170778064Sume /*(*/ 170878064Sume putchar(')'); 170962627Skris goto fqdnend; 171062627Skris } 171162627Skris ttl = (int32_t)ntohl(*(u_long *)&buf[off+ICMP6ECHOLEN+8]); 171262627Skris if (comma) 171362627Skris printf(","); 171478064Sume if (!(ni->ni_flags & NI_FQDN_FLAG_VALIDTTL)) { 171562627Skris (void)printf("TTL=%d:meaningless", 171678064Sume (int)ttl); 171778064Sume } else { 171862627Skris if (ttl < 0) { 171962627Skris (void)printf("TTL=%d:invalid", 172078064Sume ttl); 172162627Skris } else 172262627Skris (void)printf("TTL=%d", ttl); 172362627Skris } 172462627Skris comma++; 172555163Sshin 172662627Skris if (oldfqdn) { 172762627Skris if (comma) 172862627Skris printf(","); 172962627Skris printf("03 draft"); 173062627Skris comma++; 173162627Skris } else { 173262627Skris cp = (u_char *)ni + ICMP6_NIRLEN; 173362627Skris if (cp == end) { 173462627Skris if (comma) 173562627Skris printf(","); 173662627Skris printf("no name"); 173762627Skris comma++; 173862627Skris } 173962627Skris } 174062627Skris 174162627Skris if (buf[off + ICMP6_NIRLEN] != 174262627Skris cc - off - ICMP6_NIRLEN - 1 && oldfqdn) { 174362627Skris if (comma) 174462627Skris printf(","); 174562627Skris (void)printf("invalid namelen:%d/%lu", 174678064Sume buf[off + ICMP6_NIRLEN], 174778064Sume (u_long)cc - off - ICMP6_NIRLEN - 1); 174862627Skris comma++; 174962627Skris } 175062627Skris /*(*/ 175162627Skris putchar(')'); 175262627Skris } 175378064Sume fqdnend: 175462627Skris ; 175555163Sshin } 175655163Sshin } else { 175755163Sshin /* We've got something other than an ECHOREPLY */ 175855163Sshin if (!(options & F_VERBOSE)) 175955163Sshin return; 176078064Sume (void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen)); 176155163Sshin pr_icmph(icp, end); 176255163Sshin } 176355163Sshin 176455163Sshin if (!(options & F_FLOOD)) { 176555163Sshin (void)putchar('\n'); 176662627Skris if (options & F_VERBOSE) 176762627Skris pr_exthdrs(mhdr); 176855163Sshin (void)fflush(stdout); 176955163Sshin } 177062627Skris#undef safeputc 177155163Sshin} 177255163Sshin 177355163Sshinvoid 1774216561Scharnierpr_exthdrs(struct msghdr *mhdr) 177562627Skris{ 1776168866Smtm ssize_t bufsize; 1777168866Smtm void *bufp; 177862627Skris struct cmsghdr *cm; 177962627Skris 1780168866Smtm bufsize = 0; 1781168866Smtm bufp = mhdr->msg_control; 178262627Skris for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; 178362627Skris cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { 178462627Skris if (cm->cmsg_level != IPPROTO_IPV6) 178562627Skris continue; 178662627Skris 1787168866Smtm bufsize = CONTROLLEN - ((caddr_t)CMSG_DATA(cm) - (caddr_t)bufp); 1788168866Smtm if (bufsize <= 0) 1789168866Smtm continue; 179078064Sume switch (cm->cmsg_type) { 179162627Skris case IPV6_HOPOPTS: 179262627Skris printf(" HbH Options: "); 1793168866Smtm pr_ip6opt(CMSG_DATA(cm), (size_t)bufsize); 179462627Skris break; 179562627Skris case IPV6_DSTOPTS: 179662627Skris#ifdef IPV6_RTHDRDSTOPTS 179762627Skris case IPV6_RTHDRDSTOPTS: 179862627Skris#endif 179962627Skris printf(" Dst Options: "); 1800168866Smtm pr_ip6opt(CMSG_DATA(cm), (size_t)bufsize); 180162627Skris break; 180262627Skris case IPV6_RTHDR: 180362627Skris printf(" Routing: "); 1804168866Smtm pr_rthdr(CMSG_DATA(cm), (size_t)bufsize); 180562627Skris break; 180662627Skris } 180762627Skris } 180862627Skris} 180962627Skris 181062627Skris#ifdef USE_RFC2292BIS 181162627Skrisvoid 1812168866Smtmpr_ip6opt(void *extbuf, size_t bufsize) 181362627Skris{ 181462627Skris struct ip6_hbh *ext; 181562627Skris int currentlen; 181662627Skris u_int8_t type; 1817231812Seadler socklen_t extlen, len; 181862627Skris void *databuf; 181962627Skris size_t offset; 182062627Skris u_int16_t value2; 182162627Skris u_int32_t value4; 182262627Skris 182362627Skris ext = (struct ip6_hbh *)extbuf; 182462627Skris extlen = (ext->ip6h_len + 1) * 8; 182578064Sume printf("nxt %u, len %u (%lu bytes)\n", ext->ip6h_nxt, 182678064Sume (unsigned int)ext->ip6h_len, (unsigned long)extlen); 182762627Skris 1828168866Smtm /* 1829168866Smtm * Bounds checking on the ancillary data buffer: 1830168866Smtm * subtract the size of a cmsg structure from the buffer size. 1831168866Smtm */ 1832168866Smtm if (bufsize < (extlen + CMSG_SPACE(0))) { 1833168866Smtm extlen = bufsize - CMSG_SPACE(0); 1834168866Smtm warnx("options truncated, showing only %u (total=%u)", 1835168866Smtm (unsigned int)(extlen / 8 - 1), 1836168866Smtm (unsigned int)(ext->ip6h_len)); 1837168866Smtm } 1838168866Smtm 183962627Skris currentlen = 0; 184062627Skris while (1) { 184162627Skris currentlen = inet6_opt_next(extbuf, extlen, currentlen, 184278064Sume &type, &len, &databuf); 184362627Skris if (currentlen == -1) 184462627Skris break; 184562627Skris switch (type) { 184662627Skris /* 184762627Skris * Note that inet6_opt_next automatically skips any padding 184862627Skris * optins. 184962627Skris */ 185062627Skris case IP6OPT_JUMBO: 185162627Skris offset = 0; 185262627Skris offset = inet6_opt_get_val(databuf, offset, 185378064Sume &value4, sizeof(value4)); 185462627Skris printf(" Jumbo Payload Opt: Length %u\n", 185578064Sume (u_int32_t)ntohl(value4)); 185662627Skris break; 185762627Skris case IP6OPT_ROUTER_ALERT: 185862627Skris offset = 0; 185962627Skris offset = inet6_opt_get_val(databuf, offset, 186062627Skris &value2, sizeof(value2)); 186162627Skris printf(" Router Alert Opt: Type %u\n", 186278064Sume ntohs(value2)); 186362627Skris break; 186462627Skris default: 186578064Sume printf(" Received Opt %u len %lu\n", 186678064Sume type, (unsigned long)len); 186762627Skris break; 186862627Skris } 186962627Skris } 187062627Skris return; 187162627Skris} 187262627Skris#else /* !USE_RFC2292BIS */ 187362627Skris/* ARGSUSED */ 187462627Skrisvoid 1875168866Smtmpr_ip6opt(void *extbuf, size_t bufsize __unused) 187662627Skris{ 187762627Skris putchar('\n'); 187862627Skris return; 187962627Skris} 188062627Skris#endif /* USE_RFC2292BIS */ 188162627Skris 188262627Skris#ifdef USE_RFC2292BIS 188362627Skrisvoid 1884168866Smtmpr_rthdr(void *extbuf, size_t bufsize) 188562627Skris{ 188662627Skris struct in6_addr *in6; 188762627Skris char ntopbuf[INET6_ADDRSTRLEN]; 188862627Skris struct ip6_rthdr *rh = (struct ip6_rthdr *)extbuf; 1889168866Smtm int i, segments, origsegs, rthsize, size0, size1; 189062627Skris 189162627Skris /* print fixed part of the header */ 189262627Skris printf("nxt %u, len %u (%d bytes), type %u, ", rh->ip6r_nxt, 189378064Sume rh->ip6r_len, (rh->ip6r_len + 1) << 3, rh->ip6r_type); 1894168866Smtm if ((segments = inet6_rth_segments(extbuf)) >= 0) { 189562627Skris printf("%d segments, ", segments); 1896168866Smtm printf("%d left\n", rh->ip6r_segleft); 1897168866Smtm } else { 189862627Skris printf("segments unknown, "); 1899168866Smtm printf("%d left\n", rh->ip6r_segleft); 1900168866Smtm return; 1901168866Smtm } 190262627Skris 1903168866Smtm /* 1904168866Smtm * Bounds checking on the ancillary data buffer. When calculating 1905168866Smtm * the number of items to show keep in mind: 1906168866Smtm * - The size of the cmsg structure 1907168866Smtm * - The size of one segment (the size of a Type 0 routing header) 1908168866Smtm * - When dividing add a fudge factor of one in case the 1909168866Smtm * dividend is not evenly divisible by the divisor 1910168866Smtm */ 1911168866Smtm rthsize = (rh->ip6r_len + 1) * 8; 1912168866Smtm if (bufsize < (rthsize + CMSG_SPACE(0))) { 1913168866Smtm origsegs = segments; 1914168866Smtm size0 = inet6_rth_space(IPV6_RTHDR_TYPE_0, 0); 1915168866Smtm size1 = inet6_rth_space(IPV6_RTHDR_TYPE_0, 1); 1916168866Smtm segments -= (rthsize - (bufsize - CMSG_SPACE(0))) / 1917168866Smtm (size1 - size0) + 1; 1918168866Smtm warnx("segments truncated, showing only %d (total=%d)", 1919168866Smtm segments, origsegs); 1920168866Smtm } 1921168866Smtm 192262627Skris for (i = 0; i < segments; i++) { 192362627Skris in6 = inet6_rth_getaddr(extbuf, i); 192462627Skris if (in6 == NULL) 192562627Skris printf(" [%d]<NULL>\n", i); 192678064Sume else { 192778064Sume if (!inet_ntop(AF_INET6, in6, ntopbuf, 192878064Sume sizeof(ntopbuf))) 1929121472Sume strlcpy(ntopbuf, "?", sizeof(ntopbuf)); 193078064Sume printf(" [%d]%s\n", i, ntopbuf); 193178064Sume } 193262627Skris } 193362627Skris 193462627Skris return; 193578064Sume 193662627Skris} 193778064Sume 193862627Skris#else /* !USE_RFC2292BIS */ 193962627Skris/* ARGSUSED */ 194062627Skrisvoid 1941168866Smtmpr_rthdr(void *extbuf, size_t bufsize __unused) 194262627Skris{ 194362627Skris putchar('\n'); 194462627Skris return; 194562627Skris} 194662627Skris#endif /* USE_RFC2292BIS */ 194762627Skris 194878064Sumeint 1949216561Scharnierpr_bitrange(u_int32_t v, int soff, int ii) 195078064Sume{ 195178064Sume int off; 195278064Sume int i; 195362627Skris 195478064Sume off = 0; 195578064Sume while (off < 32) { 195678064Sume /* shift till we have 0x01 */ 195778064Sume if ((v & 0x01) == 0) { 195878064Sume if (ii > 1) 1959121472Sume printf("-%u", soff + off - 1); 196078064Sume ii = 0; 196178064Sume switch (v & 0x0f) { 196278064Sume case 0x00: 196378064Sume v >>= 4; 196478064Sume off += 4; 196578064Sume continue; 196678064Sume case 0x08: 196778064Sume v >>= 3; 196878064Sume off += 3; 196978064Sume continue; 197078064Sume case 0x04: case 0x0c: 197178064Sume v >>= 2; 197278064Sume off += 2; 197378064Sume continue; 197478064Sume default: 197578064Sume v >>= 1; 197678064Sume off += 1; 197778064Sume continue; 197878064Sume } 197978064Sume } 198078064Sume 198178064Sume /* we have 0x01 with us */ 198278064Sume for (i = 0; i < 32 - off; i++) { 198378064Sume if ((v & (0x01 << i)) == 0) 198478064Sume break; 198578064Sume } 198678064Sume if (!ii) 1987121472Sume printf(" %u", soff + off); 198878064Sume ii += i; 198978064Sume v >>= i; off += i; 199078064Sume } 199178064Sume return ii; 199278064Sume} 199378064Sume 199462627Skrisvoid 1995216561Scharnierpr_suptypes(struct icmp6_nodeinfo *ni, size_t nilen) 1996216561Scharnier /* ni->qtype must be SUPTYPES */ 199778064Sume{ 199878064Sume size_t clen; 199978064Sume u_int32_t v; 200078064Sume const u_char *cp, *end; 200178064Sume u_int16_t cur; 200278064Sume struct cbit { 200378064Sume u_int16_t words; /*32bit count*/ 200478064Sume u_int16_t skip; 200578064Sume } cbit; 200678064Sume#define MAXQTYPES (1 << 16) 200778064Sume size_t off; 200878064Sume int b; 200978064Sume 201078064Sume cp = (u_char *)(ni + 1); 201178064Sume end = ((u_char *)ni) + nilen; 201278064Sume cur = 0; 201378064Sume b = 0; 201478064Sume 201578064Sume printf("NodeInfo Supported Qtypes"); 201678064Sume if (options & F_VERBOSE) { 201778064Sume if (ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) 201878064Sume printf(", compressed bitmap"); 201978064Sume else 202078064Sume printf(", raw bitmap"); 202178064Sume } 202278064Sume 202378064Sume while (cp < end) { 202478064Sume clen = (size_t)(end - cp); 202578064Sume if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) == 0) { 202678064Sume if (clen == 0 || clen > MAXQTYPES / 8 || 202778064Sume clen % sizeof(v)) { 202878064Sume printf("???"); 202978064Sume return; 203078064Sume } 203178064Sume } else { 203278064Sume if (clen < sizeof(cbit) || clen % sizeof(v)) 203378064Sume return; 203478064Sume memcpy(&cbit, cp, sizeof(cbit)); 203578064Sume if (sizeof(cbit) + ntohs(cbit.words) * sizeof(v) > 203678064Sume clen) 203778064Sume return; 203878064Sume cp += sizeof(cbit); 203978064Sume clen = ntohs(cbit.words) * sizeof(v); 204078064Sume if (cur + clen * 8 + (u_long)ntohs(cbit.skip) * 32 > 204178064Sume MAXQTYPES) 204278064Sume return; 204378064Sume } 204478064Sume 204578064Sume for (off = 0; off < clen; off += sizeof(v)) { 204678064Sume memcpy(&v, cp + off, sizeof(v)); 204778064Sume v = (u_int32_t)ntohl(v); 204878064Sume b = pr_bitrange(v, (int)(cur + off * 8), b); 204978064Sume } 205078064Sume /* flush the remaining bits */ 205178064Sume b = pr_bitrange(0, (int)(cur + off * 8), b); 205278064Sume 205378064Sume cp += clen; 205478064Sume cur += clen * 8; 205578064Sume if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) != 0) 205678064Sume cur += ntohs(cbit.skip) * 32; 205778064Sume } 205878064Sume} 205978064Sume 206078064Sumevoid 2061216561Scharnierpr_nodeaddr(struct icmp6_nodeinfo *ni, int nilen) 2062216561Scharnier /* ni->qtype must be NODEADDR */ 206355163Sshin{ 206478064Sume u_char *cp = (u_char *)(ni + 1); 206562627Skris char ntop_buf[INET6_ADDRSTRLEN]; 206678064Sume int withttl = 0; 206755163Sshin 206855163Sshin nilen -= sizeof(struct icmp6_nodeinfo); 206955163Sshin 207055163Sshin if (options & F_VERBOSE) { 207178064Sume switch (ni->ni_code) { 207278064Sume case ICMP6_NI_REFUSED: 207378064Sume (void)printf("refused"); 207478064Sume break; 207578064Sume case ICMP6_NI_UNKNOWN: 207678064Sume (void)printf("unknown qtype"); 207778064Sume break; 207855163Sshin } 207978064Sume if (ni->ni_flags & NI_NODEADDR_FLAG_TRUNCATE) 208055163Sshin (void)printf(" truncated"); 208155163Sshin } 208255163Sshin putchar('\n'); 208355163Sshin if (nilen <= 0) 208455163Sshin printf(" no address\n"); 208578064Sume 208678064Sume /* 208778064Sume * In icmp-name-lookups 05 and later, TTL of each returned address 208878064Sume * is contained in the resposne. We try to detect the version 208978064Sume * by the length of the data, but note that the detection algorithm 209078064Sume * is incomplete. We assume the latest draft by default. 209178064Sume */ 209278064Sume if (nilen % (sizeof(u_int32_t) + sizeof(struct in6_addr)) == 0) 209378064Sume withttl = 1; 209478064Sume while (nilen > 0) { 209578064Sume u_int32_t ttl; 209678064Sume 209778064Sume if (withttl) { 209878064Sume /* XXX: alignment? */ 209978064Sume ttl = (u_int32_t)ntohl(*(u_int32_t *)cp); 210078064Sume cp += sizeof(u_int32_t); 210178064Sume nilen -= sizeof(u_int32_t); 210278064Sume } 210378064Sume 210478064Sume if (inet_ntop(AF_INET6, cp, ntop_buf, sizeof(ntop_buf)) == 210578064Sume NULL) 2106121472Sume strlcpy(ntop_buf, "?", sizeof(ntop_buf)); 210778064Sume printf(" %s", ntop_buf); 210878064Sume if (withttl) { 210978064Sume if (ttl == 0xffffffff) { 211078064Sume /* 211178064Sume * XXX: can this convention be applied to all 211278064Sume * type of TTL (i.e. non-ND TTL)? 211378064Sume */ 211478064Sume printf("(TTL=infty)"); 211578064Sume } 211678064Sume else 211778064Sume printf("(TTL=%u)", ttl); 211878064Sume } 211978064Sume putchar('\n'); 212078064Sume 212178064Sume nilen -= sizeof(struct in6_addr); 212278064Sume cp += sizeof(struct in6_addr); 212355163Sshin } 212455163Sshin} 212555163Sshin 212655163Sshinint 2127216561Scharnierget_hoplim(struct msghdr *mhdr) 212855163Sshin{ 212955163Sshin struct cmsghdr *cm; 213055163Sshin 213155163Sshin for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; 213255163Sshin cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { 213378064Sume if (cm->cmsg_len == 0) 213478064Sume return(-1); 213578064Sume 213655163Sshin if (cm->cmsg_level == IPPROTO_IPV6 && 213755163Sshin cm->cmsg_type == IPV6_HOPLIMIT && 213855163Sshin cm->cmsg_len == CMSG_LEN(sizeof(int))) 213955163Sshin return(*(int *)CMSG_DATA(cm)); 214055163Sshin } 214155163Sshin 214255163Sshin return(-1); 214355163Sshin} 214455163Sshin 214562627Skrisstruct in6_pktinfo * 2146216561Scharnierget_rcvpktinfo(struct msghdr *mhdr) 214762627Skris{ 214862627Skris struct cmsghdr *cm; 214962627Skris 215062627Skris for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; 215162627Skris cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { 215278064Sume if (cm->cmsg_len == 0) 215378064Sume return(NULL); 215478064Sume 215562627Skris if (cm->cmsg_level == IPPROTO_IPV6 && 215662627Skris cm->cmsg_type == IPV6_PKTINFO && 215762627Skris cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) 215862627Skris return((struct in6_pktinfo *)CMSG_DATA(cm)); 215962627Skris } 216062627Skris 216162627Skris return(NULL); 216262627Skris} 216362627Skris 216478064Sumeint 2165216561Scharnierget_pathmtu(struct msghdr *mhdr) 216678064Sume{ 216778064Sume#ifdef IPV6_RECVPATHMTU 216878064Sume struct cmsghdr *cm; 216978064Sume struct ip6_mtuinfo *mtuctl = NULL; 217078064Sume 217178064Sume for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; 217278064Sume cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { 217378064Sume if (cm->cmsg_len == 0) 217478064Sume return(0); 217578064Sume 217678064Sume if (cm->cmsg_level == IPPROTO_IPV6 && 217778064Sume cm->cmsg_type == IPV6_PATHMTU && 217878064Sume cm->cmsg_len == CMSG_LEN(sizeof(struct ip6_mtuinfo))) { 217978064Sume mtuctl = (struct ip6_mtuinfo *)CMSG_DATA(cm); 218078064Sume 218178064Sume /* 218278064Sume * If the notified destination is different from 218378064Sume * the one we are pinging, just ignore the info. 218478064Sume * We check the scope ID only when both notified value 218578064Sume * and our own value have non-0 values, because we may 218678064Sume * have used the default scope zone ID for sending, 218778064Sume * in which case the scope ID value is 0. 218878064Sume */ 218978064Sume if (!IN6_ARE_ADDR_EQUAL(&mtuctl->ip6m_addr.sin6_addr, 219078064Sume &dst.sin6_addr) || 219178064Sume (mtuctl->ip6m_addr.sin6_scope_id && 219278064Sume dst.sin6_scope_id && 219378064Sume mtuctl->ip6m_addr.sin6_scope_id != 219478064Sume dst.sin6_scope_id)) { 219578064Sume if ((options & F_VERBOSE) != 0) { 219678064Sume printf("path MTU for %s is notified. " 219778064Sume "(ignored)\n", 219878064Sume pr_addr((struct sockaddr *)&mtuctl->ip6m_addr, 219978064Sume sizeof(mtuctl->ip6m_addr))); 220078064Sume } 220178064Sume return(0); 220278064Sume } 220378064Sume 220478064Sume /* 220578064Sume * Ignore an invalid MTU. XXX: can we just believe 220678064Sume * the kernel check? 220778064Sume */ 220878064Sume if (mtuctl->ip6m_mtu < IPV6_MMTU) 220978064Sume return(0); 221078064Sume 221178064Sume /* notification for our destination. return the MTU. */ 221278064Sume return((int)mtuctl->ip6m_mtu); 221378064Sume } 221478064Sume } 221578064Sume#endif 221678064Sume return(0); 221778064Sume} 221878064Sume 221955163Sshin/* 222055163Sshin * tvsub -- 222155163Sshin * Subtract 2 timeval structs: out = out - in. Out is assumed to 222255163Sshin * be >= in. 222355163Sshin */ 222455163Sshinvoid 2225216561Scharniertvsub(struct timeval *out, struct timeval *in) 222655163Sshin{ 222755163Sshin if ((out->tv_usec -= in->tv_usec) < 0) { 222855163Sshin --out->tv_sec; 222955163Sshin out->tv_usec += 1000000; 223055163Sshin } 223155163Sshin out->tv_sec -= in->tv_sec; 223255163Sshin} 223355163Sshin 223455163Sshin/* 223555163Sshin * onint -- 223655163Sshin * SIGINT handler. 223755163Sshin */ 223862627Skris/* ARGSUSED */ 223955163Sshinvoid 2240216561Scharnieronint(int notused __unused) 224155163Sshin{ 224255163Sshin summary(); 224355163Sshin 2244209236Sbrucec if (res != NULL) 2245209236Sbrucec freeaddrinfo(res); 2246209236Sbrucec 2247209236Sbrucec if(packet != NULL) 2248209236Sbrucec free(packet); 2249209236Sbrucec 2250209236Sbrucec#ifndef HAVE_POLL_H 2251209236Sbrucec if(fdmaskp != NULL) 2252209236Sbrucec free(fdmaskp); 2253209236Sbrucec#endif 2254209236Sbrucec 2255121472Sume (void)signal(SIGINT, SIG_DFL); 2256121472Sume (void)kill(getpid(), SIGINT); 2257121472Sume 2258121472Sume /* NOTREACHED */ 2259121472Sume exit(1); 226055163Sshin} 226155163Sshin 226255163Sshin/* 226355163Sshin * summary -- 226455163Sshin * Print out statistics. 226555163Sshin */ 226655163Sshinvoid 2267216561Scharniersummary(void) 226855163Sshin{ 226955163Sshin 227055163Sshin (void)printf("\n--- %s ping6 statistics ---\n", hostname); 227155163Sshin (void)printf("%ld packets transmitted, ", ntransmitted); 227255163Sshin (void)printf("%ld packets received, ", nreceived); 227355163Sshin if (nrepeats) 227455163Sshin (void)printf("+%ld duplicates, ", nrepeats); 227555163Sshin if (ntransmitted) { 227655163Sshin if (nreceived > ntransmitted) 2277121472Sume (void)printf("-- somebody's duplicating packets!"); 227855163Sshin else 2279121472Sume (void)printf("%.1f%% packet loss", 2280121472Sume ((((double)ntransmitted - nreceived) * 100.0) / 228155163Sshin ntransmitted)); 228255163Sshin } 228355163Sshin (void)putchar('\n'); 228455163Sshin if (nreceived && timing) { 228555163Sshin /* Only display average to microseconds */ 228678064Sume double num = nreceived + nrepeats; 228778064Sume double avg = tsum / num; 228878064Sume double dev = sqrt(tsumsq / num - avg * avg); 228978064Sume (void)printf( 229078064Sume "round-trip min/avg/max/std-dev = %.3f/%.3f/%.3f/%.3f ms\n", 229178064Sume tmin, avg, tmax, dev); 229255163Sshin (void)fflush(stdout); 229355163Sshin } 229478064Sume (void)fflush(stdout); 229555163Sshin} 229655163Sshin 229778064Sume/*subject type*/ 2298121472Sumestatic const char *niqcode[] = { 229978064Sume "IPv6 address", 230078064Sume "DNS label", /*or empty*/ 230178064Sume "IPv4 address", 230255163Sshin}; 230355163Sshin 230478064Sume/*result code*/ 2305121472Sumestatic const char *nircode[] = { 230678064Sume "Success", "Refused", "Unknown", 230778064Sume}; 230878064Sume 230978064Sume 231055163Sshin/* 231155163Sshin * pr_icmph -- 231255163Sshin * Print a descriptive string about an ICMP header. 231355163Sshin */ 231455163Sshinvoid 2315216561Scharnierpr_icmph(struct icmp6_hdr *icp, u_char *end) 231655163Sshin{ 231762627Skris char ntop_buf[INET6_ADDRSTRLEN]; 231878064Sume struct nd_redirect *red; 231978064Sume struct icmp6_nodeinfo *ni; 232078064Sume char dnsname[MAXDNAME + 1]; 232178064Sume const u_char *cp; 232278064Sume size_t l; 232362627Skris 232478064Sume switch (icp->icmp6_type) { 232555163Sshin case ICMP6_DST_UNREACH: 232678064Sume switch (icp->icmp6_code) { 232755163Sshin case ICMP6_DST_UNREACH_NOROUTE: 232855163Sshin (void)printf("No Route to Destination\n"); 232955163Sshin break; 233055163Sshin case ICMP6_DST_UNREACH_ADMIN: 233155163Sshin (void)printf("Destination Administratively " 233278064Sume "Unreachable\n"); 233355163Sshin break; 233455163Sshin case ICMP6_DST_UNREACH_BEYONDSCOPE: 233555163Sshin (void)printf("Destination Unreachable Beyond Scope\n"); 233655163Sshin break; 233755163Sshin case ICMP6_DST_UNREACH_ADDR: 233855163Sshin (void)printf("Destination Host Unreachable\n"); 233955163Sshin break; 234055163Sshin case ICMP6_DST_UNREACH_NOPORT: 234155163Sshin (void)printf("Destination Port Unreachable\n"); 234255163Sshin break; 234355163Sshin default: 234455163Sshin (void)printf("Destination Unreachable, Bad Code: %d\n", 234555163Sshin icp->icmp6_code); 234655163Sshin break; 234755163Sshin } 234855163Sshin /* Print returned IP header information */ 234955163Sshin pr_retip((struct ip6_hdr *)(icp + 1), end); 235055163Sshin break; 235155163Sshin case ICMP6_PACKET_TOO_BIG: 235255163Sshin (void)printf("Packet too big mtu = %d\n", 235378064Sume (int)ntohl(icp->icmp6_mtu)); 235462627Skris pr_retip((struct ip6_hdr *)(icp + 1), end); 235555163Sshin break; 235655163Sshin case ICMP6_TIME_EXCEEDED: 235778064Sume switch (icp->icmp6_code) { 235855163Sshin case ICMP6_TIME_EXCEED_TRANSIT: 235955163Sshin (void)printf("Time to live exceeded\n"); 236055163Sshin break; 236155163Sshin case ICMP6_TIME_EXCEED_REASSEMBLY: 236255163Sshin (void)printf("Frag reassembly time exceeded\n"); 236355163Sshin break; 236455163Sshin default: 236555163Sshin (void)printf("Time exceeded, Bad Code: %d\n", 236655163Sshin icp->icmp6_code); 236755163Sshin break; 236855163Sshin } 236955163Sshin pr_retip((struct ip6_hdr *)(icp + 1), end); 237055163Sshin break; 237155163Sshin case ICMP6_PARAM_PROB: 237255163Sshin (void)printf("Parameter problem: "); 237378064Sume switch (icp->icmp6_code) { 237478064Sume case ICMP6_PARAMPROB_HEADER: 237578064Sume (void)printf("Erroneous Header "); 237678064Sume break; 237778064Sume case ICMP6_PARAMPROB_NEXTHEADER: 237878064Sume (void)printf("Unknown Nextheader "); 237978064Sume break; 238078064Sume case ICMP6_PARAMPROB_OPTION: 238178064Sume (void)printf("Unrecognized Option "); 238278064Sume break; 238378064Sume default: 238478064Sume (void)printf("Bad code(%d) ", icp->icmp6_code); 238578064Sume break; 238655163Sshin } 238755163Sshin (void)printf("pointer = 0x%02x\n", 238878064Sume (u_int32_t)ntohl(icp->icmp6_pptr)); 238955163Sshin pr_retip((struct ip6_hdr *)(icp + 1), end); 239055163Sshin break; 239155163Sshin case ICMP6_ECHO_REQUEST: 239262627Skris (void)printf("Echo Request"); 239355163Sshin /* XXX ID + Seq + Data */ 239455163Sshin break; 239555163Sshin case ICMP6_ECHO_REPLY: 239662627Skris (void)printf("Echo Reply"); 239755163Sshin /* XXX ID + Seq + Data */ 239855163Sshin break; 239955163Sshin case ICMP6_MEMBERSHIP_QUERY: 240062627Skris (void)printf("Listener Query"); 240155163Sshin break; 240255163Sshin case ICMP6_MEMBERSHIP_REPORT: 240362627Skris (void)printf("Listener Report"); 240455163Sshin break; 240555163Sshin case ICMP6_MEMBERSHIP_REDUCTION: 240662627Skris (void)printf("Listener Done"); 240755163Sshin break; 240855163Sshin case ND_ROUTER_SOLICIT: 240962627Skris (void)printf("Router Solicitation"); 241055163Sshin break; 241155163Sshin case ND_ROUTER_ADVERT: 241262627Skris (void)printf("Router Advertisement"); 241355163Sshin break; 241455163Sshin case ND_NEIGHBOR_SOLICIT: 241562627Skris (void)printf("Neighbor Solicitation"); 241655163Sshin break; 241755163Sshin case ND_NEIGHBOR_ADVERT: 241862627Skris (void)printf("Neighbor Advertisement"); 241955163Sshin break; 242055163Sshin case ND_REDIRECT: 242178064Sume red = (struct nd_redirect *)icp; 242255163Sshin (void)printf("Redirect\n"); 242378064Sume if (!inet_ntop(AF_INET6, &red->nd_rd_dst, ntop_buf, 242478064Sume sizeof(ntop_buf))) 2425121472Sume strlcpy(ntop_buf, "?", sizeof(ntop_buf)); 242678064Sume (void)printf("Destination: %s", ntop_buf); 242778064Sume if (!inet_ntop(AF_INET6, &red->nd_rd_target, ntop_buf, 242878064Sume sizeof(ntop_buf))) 2429121472Sume strlcpy(ntop_buf, "?", sizeof(ntop_buf)); 243078064Sume (void)printf(" New Target: %s", ntop_buf); 243155163Sshin break; 243255163Sshin case ICMP6_NI_QUERY: 243362627Skris (void)printf("Node Information Query"); 243455163Sshin /* XXX ID + Seq + Data */ 243578064Sume ni = (struct icmp6_nodeinfo *)icp; 243678064Sume l = end - (u_char *)(ni + 1); 243778064Sume printf(", "); 243878064Sume switch (ntohs(ni->ni_qtype)) { 243978064Sume case NI_QTYPE_NOOP: 244078064Sume (void)printf("NOOP"); 244178064Sume break; 244278064Sume case NI_QTYPE_SUPTYPES: 244378064Sume (void)printf("Supported qtypes"); 244478064Sume break; 244578064Sume case NI_QTYPE_FQDN: 244678064Sume (void)printf("DNS name"); 244778064Sume break; 244878064Sume case NI_QTYPE_NODEADDR: 244978064Sume (void)printf("nodeaddr"); 245078064Sume break; 245178064Sume case NI_QTYPE_IPV4ADDR: 245278064Sume (void)printf("IPv4 nodeaddr"); 245378064Sume break; 245478064Sume default: 245578064Sume (void)printf("unknown qtype"); 245678064Sume break; 245778064Sume } 245878064Sume if (options & F_VERBOSE) { 245978064Sume switch (ni->ni_code) { 246078064Sume case ICMP6_NI_SUBJ_IPV6: 246178064Sume if (l == sizeof(struct in6_addr) && 246278064Sume inet_ntop(AF_INET6, ni + 1, ntop_buf, 246378064Sume sizeof(ntop_buf)) != NULL) { 246478064Sume (void)printf(", subject=%s(%s)", 246578064Sume niqcode[ni->ni_code], ntop_buf); 246678064Sume } else { 246778064Sume#if 1 246878064Sume /* backward compat to -W */ 246978064Sume (void)printf(", oldfqdn"); 247078064Sume#else 247178064Sume (void)printf(", invalid"); 247278064Sume#endif 247378064Sume } 247478064Sume break; 247578064Sume case ICMP6_NI_SUBJ_FQDN: 247678064Sume if (end == (u_char *)(ni + 1)) { 247778064Sume (void)printf(", no subject"); 247878064Sume break; 247978064Sume } 248078064Sume printf(", subject=%s", niqcode[ni->ni_code]); 248178064Sume cp = (const u_char *)(ni + 1); 248278064Sume if (dnsdecode(&cp, end, NULL, dnsname, 248378064Sume sizeof(dnsname)) != NULL) 248478064Sume printf("(%s)", dnsname); 248578064Sume else 248678064Sume printf("(invalid)"); 248778064Sume break; 248878064Sume case ICMP6_NI_SUBJ_IPV4: 248978064Sume if (l == sizeof(struct in_addr) && 249078064Sume inet_ntop(AF_INET, ni + 1, ntop_buf, 249178064Sume sizeof(ntop_buf)) != NULL) { 249278064Sume (void)printf(", subject=%s(%s)", 249378064Sume niqcode[ni->ni_code], ntop_buf); 249478064Sume } else 249578064Sume (void)printf(", invalid"); 249678064Sume break; 249778064Sume default: 249878064Sume (void)printf(", invalid"); 249978064Sume break; 250078064Sume } 250178064Sume } 250255163Sshin break; 250355163Sshin case ICMP6_NI_REPLY: 250462627Skris (void)printf("Node Information Reply"); 250555163Sshin /* XXX ID + Seq + Data */ 250678064Sume ni = (struct icmp6_nodeinfo *)icp; 250778064Sume printf(", "); 250878064Sume switch (ntohs(ni->ni_qtype)) { 250978064Sume case NI_QTYPE_NOOP: 251078064Sume (void)printf("NOOP"); 251178064Sume break; 251278064Sume case NI_QTYPE_SUPTYPES: 251378064Sume (void)printf("Supported qtypes"); 251478064Sume break; 251578064Sume case NI_QTYPE_FQDN: 251678064Sume (void)printf("DNS name"); 251778064Sume break; 251878064Sume case NI_QTYPE_NODEADDR: 251978064Sume (void)printf("nodeaddr"); 252078064Sume break; 252178064Sume case NI_QTYPE_IPV4ADDR: 252278064Sume (void)printf("IPv4 nodeaddr"); 252378064Sume break; 252478064Sume default: 252578064Sume (void)printf("unknown qtype"); 252678064Sume break; 252778064Sume } 252878064Sume if (options & F_VERBOSE) { 252978064Sume if (ni->ni_code > sizeof(nircode) / sizeof(nircode[0])) 253078064Sume printf(", invalid"); 253178064Sume else 253278064Sume printf(", %s", nircode[ni->ni_code]); 253378064Sume } 253455163Sshin break; 253555163Sshin default: 253662627Skris (void)printf("Bad ICMP type: %d", icp->icmp6_type); 253755163Sshin } 253855163Sshin} 253955163Sshin 254055163Sshin/* 254155163Sshin * pr_iph -- 254255163Sshin * Print an IP6 header. 254355163Sshin */ 254455163Sshinvoid 2545216561Scharnierpr_iph(struct ip6_hdr *ip6) 254655163Sshin{ 254755163Sshin u_int32_t flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; 254855163Sshin u_int8_t tc; 254962627Skris char ntop_buf[INET6_ADDRSTRLEN]; 255055163Sshin 255155163Sshin tc = *(&ip6->ip6_vfc + 1); /* XXX */ 255255163Sshin tc = (tc >> 4) & 0x0f; 255355163Sshin tc |= (ip6->ip6_vfc << 4); 255455163Sshin 255555163Sshin printf("Vr TC Flow Plen Nxt Hlim\n"); 255655163Sshin printf(" %1x %02x %05x %04x %02x %02x\n", 255778064Sume (ip6->ip6_vfc & IPV6_VERSION_MASK) >> 4, tc, (u_int32_t)ntohl(flow), 255878064Sume ntohs(ip6->ip6_plen), ip6->ip6_nxt, ip6->ip6_hlim); 255978064Sume if (!inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf, sizeof(ntop_buf))) 2560121472Sume strlcpy(ntop_buf, "?", sizeof(ntop_buf)); 256178064Sume printf("%s->", ntop_buf); 256278064Sume if (!inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf, sizeof(ntop_buf))) 2563121472Sume strlcpy(ntop_buf, "?", sizeof(ntop_buf)); 256478064Sume printf("%s\n", ntop_buf); 256555163Sshin} 256655163Sshin 256755163Sshin/* 256855163Sshin * pr_addr -- 256955163Sshin * Return an ascii host address as a dotted quad and optionally with 257055163Sshin * a hostname. 257155163Sshin */ 257262627Skrisconst char * 2573216561Scharnierpr_addr(struct sockaddr *addr, int addrlen) 257455163Sshin{ 257578064Sume static char buf[NI_MAXHOST]; 2576121316Sume int flag = 0; 257755163Sshin 257862627Skris if ((options & F_HOSTNAME) == 0) 257955163Sshin flag |= NI_NUMERICHOST; 258055163Sshin 258178064Sume if (getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, flag) == 0) 258278064Sume return (buf); 258378064Sume else 258478064Sume return "?"; 258555163Sshin} 258655163Sshin 258755163Sshin/* 258855163Sshin * pr_retip -- 258955163Sshin * Dump some info on a returned (via ICMPv6) IPv6 packet. 259055163Sshin */ 259155163Sshinvoid 2592216561Scharnierpr_retip(struct ip6_hdr *ip6, u_char *end) 259355163Sshin{ 259455163Sshin u_char *cp = (u_char *)ip6, nh; 259555163Sshin int hlen; 259655163Sshin 259755163Sshin if (end - (u_char *)ip6 < sizeof(*ip6)) { 259855163Sshin printf("IP6"); 259955163Sshin goto trunc; 260055163Sshin } 260155163Sshin pr_iph(ip6); 260255163Sshin hlen = sizeof(*ip6); 260355163Sshin 260455163Sshin nh = ip6->ip6_nxt; 260555163Sshin cp += hlen; 260655163Sshin while (end - cp >= 8) { 260755163Sshin switch (nh) { 260878064Sume case IPPROTO_HOPOPTS: 260978064Sume printf("HBH "); 261078064Sume hlen = (((struct ip6_hbh *)cp)->ip6h_len+1) << 3; 261178064Sume nh = ((struct ip6_hbh *)cp)->ip6h_nxt; 261278064Sume break; 261378064Sume case IPPROTO_DSTOPTS: 261478064Sume printf("DSTOPT "); 261578064Sume hlen = (((struct ip6_dest *)cp)->ip6d_len+1) << 3; 261678064Sume nh = ((struct ip6_dest *)cp)->ip6d_nxt; 261778064Sume break; 261878064Sume case IPPROTO_FRAGMENT: 261978064Sume printf("FRAG "); 262078064Sume hlen = sizeof(struct ip6_frag); 262178064Sume nh = ((struct ip6_frag *)cp)->ip6f_nxt; 262278064Sume break; 262378064Sume case IPPROTO_ROUTING: 262478064Sume printf("RTHDR "); 262578064Sume hlen = (((struct ip6_rthdr *)cp)->ip6r_len+1) << 3; 262678064Sume nh = ((struct ip6_rthdr *)cp)->ip6r_nxt; 262778064Sume break; 262855163Sshin#ifdef IPSEC 262978064Sume case IPPROTO_AH: 263078064Sume printf("AH "); 263178064Sume hlen = (((struct ah *)cp)->ah_len+2) << 2; 263278064Sume nh = ((struct ah *)cp)->ah_nxt; 263378064Sume break; 263455163Sshin#endif 263578064Sume case IPPROTO_ICMPV6: 263678064Sume printf("ICMP6: type = %d, code = %d\n", 263778064Sume *cp, *(cp + 1)); 263878064Sume return; 263978064Sume case IPPROTO_ESP: 264078064Sume printf("ESP\n"); 264178064Sume return; 264278064Sume case IPPROTO_TCP: 264378064Sume printf("TCP: from port %u, to port %u (decimal)\n", 264478064Sume (*cp * 256 + *(cp + 1)), 264578064Sume (*(cp + 2) * 256 + *(cp + 3))); 264678064Sume return; 264778064Sume case IPPROTO_UDP: 264878064Sume printf("UDP: from port %u, to port %u (decimal)\n", 264978064Sume (*cp * 256 + *(cp + 1)), 265078064Sume (*(cp + 2) * 256 + *(cp + 3))); 265178064Sume return; 265278064Sume default: 265378064Sume printf("Unknown Header(%d)\n", nh); 265478064Sume return; 265555163Sshin } 265655163Sshin 265755163Sshin if ((cp += hlen) >= end) 265855163Sshin goto trunc; 265955163Sshin } 266055163Sshin if (end - cp < 8) 266155163Sshin goto trunc; 266255163Sshin 266355163Sshin putchar('\n'); 266455163Sshin return; 266555163Sshin 266655163Sshin trunc: 266755163Sshin printf("...\n"); 266855163Sshin return; 266955163Sshin} 267055163Sshin 267155163Sshinvoid 2672216561Scharnierfill(char *bp, char *patp) 267355163Sshin{ 267492806Sobrien int ii, jj, kk; 267555163Sshin int pat[16]; 267655163Sshin char *cp; 267755163Sshin 267855163Sshin for (cp = patp; *cp; cp++) 267955163Sshin if (!isxdigit(*cp)) 268055163Sshin errx(1, "patterns must be specified as hex digits"); 268155163Sshin ii = sscanf(patp, 268255163Sshin "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", 268355163Sshin &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6], 268455163Sshin &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12], 268555163Sshin &pat[13], &pat[14], &pat[15]); 268655163Sshin 268778064Sume/* xxx */ 268855163Sshin if (ii > 0) 268955163Sshin for (kk = 0; 2690121472Sume kk <= MAXDATALEN - (8 + sizeof(struct tv32) + ii); 269155163Sshin kk += ii) 269255163Sshin for (jj = 0; jj < ii; ++jj) 269355163Sshin bp[jj + kk] = pat[jj]; 269455163Sshin if (!(options & F_QUIET)) { 269555163Sshin (void)printf("PATTERN: 0x"); 269655163Sshin for (jj = 0; jj < ii; ++jj) 269755163Sshin (void)printf("%02x", bp[jj] & 0xFF); 269855163Sshin (void)printf("\n"); 269955163Sshin } 270055163Sshin} 270155163Sshin 270255163Sshin#ifdef IPSEC 270355163Sshin#ifdef IPSEC_POLICY_IPSEC 270455163Sshinint 2705216561Scharniersetpolicy(int so __unused, char *policy) 270655163Sshin{ 270755163Sshin char *buf; 270855163Sshin 270955163Sshin if (policy == NULL) 271055163Sshin return 0; /* ignore */ 271155163Sshin 271255163Sshin buf = ipsec_set_policy(policy, strlen(policy)); 271355163Sshin if (buf == NULL) 271464277Skris errx(1, "%s", ipsec_strerror()); 271578064Sume if (setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, buf, 271678064Sume ipsec_get_policylen(buf)) < 0) 2717121472Sume warnx("Unable to set IPsec policy"); 271855163Sshin free(buf); 271955163Sshin 272055163Sshin return 0; 272155163Sshin} 272255163Sshin#endif 272355163Sshin#endif 272455163Sshin 272562627Skrischar * 2726252021Shrsnigroup(char *name, int nig_oldmcprefix) 272762627Skris{ 272862627Skris char *p; 2729121472Sume char *q; 273062627Skris MD5_CTX ctxt; 273162627Skris u_int8_t digest[16]; 273278064Sume u_int8_t c; 273378064Sume size_t l; 273462627Skris char hbuf[NI_MAXHOST]; 273562627Skris struct in6_addr in6; 2736252021Shrs int valid; 273762627Skris 273878064Sume p = strchr(name, '.'); 273978064Sume if (!p) 274078064Sume p = name + strlen(name); 274178064Sume l = p - name; 274278064Sume if (l > 63 || l > sizeof(hbuf) - 1) 274362627Skris return NULL; /*label too long*/ 274478064Sume strncpy(hbuf, name, l); 274578064Sume hbuf[(int)l] = '\0'; 274662627Skris 274778064Sume for (q = name; *q; q++) { 2748121472Sume if (isupper(*(unsigned char *)q)) 2749121472Sume *q = tolower(*(unsigned char *)q); 275078064Sume } 275178064Sume 2752252021Shrs /* generate 16 bytes of pseudo-random value. */ 2753121472Sume memset(&ctxt, 0, sizeof(ctxt)); 275462627Skris MD5Init(&ctxt); 275578064Sume c = l & 0xff; 275678064Sume MD5Update(&ctxt, &c, sizeof(c)); 2757121472Sume MD5Update(&ctxt, (unsigned char *)name, l); 275862627Skris MD5Final(digest, &ctxt); 275962627Skris 2760252021Shrs if (nig_oldmcprefix) { 2761252021Shrs /* draft-ietf-ipngwg-icmp-name-lookup */ 2762252021Shrs valid = inet_pton(AF_INET6, "ff02::2:0000:0000", &in6); 2763252021Shrs } else { 2764252021Shrs /* RFC 4620 */ 2765252021Shrs valid = inet_pton(AF_INET6, "ff02::2:ff00:0000", &in6); 2766252021Shrs } 2767252021Shrs if (valid != 1) 276878064Sume return NULL; /*XXX*/ 2769252021Shrs 2770252021Shrs if (nig_oldmcprefix) { 2771252021Shrs /* draft-ietf-ipngwg-icmp-name-lookup */ 2772252021Shrs bcopy(digest, &in6.s6_addr[12], 4); 2773252021Shrs } else { 2774252021Shrs /* RFC 4620 */ 2775252021Shrs bcopy(digest, &in6.s6_addr[13], 3); 2776252021Shrs } 277762627Skris 277862627Skris if (inet_ntop(AF_INET6, &in6, hbuf, sizeof(hbuf)) == NULL) 277962627Skris return NULL; 278062627Skris 278162627Skris return strdup(hbuf); 278262627Skris} 278362627Skris 278455163Sshinvoid 2785216561Scharnierusage(void) 278655163Sshin{ 278755163Sshin (void)fprintf(stderr, 2788141611Sru#if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC) 2789141611Sru "A" 2790141611Sru#endif 2791141611Sru "usage: ping6 [-" 2792206889Smaxim "Dd" 2793141611Sru#if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC) 2794141611Sru "E" 2795141611Sru#endif 2796141611Sru "fH" 279778990Sume#ifdef IPV6_USE_MIN_MTU 279878990Sume "m" 279978990Sume#endif 2800182276Smatteo "nNoqrRtvwW] " 2801141611Sru "[-a addrtype] [-b bufsiz] [-c count] [-g gateway]\n" 2802141611Sru " [-h hoplimit] [-I interface] [-i wait] [-l preload]" 2803141611Sru#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 2804141611Sru " [-P policy]" 280555163Sshin#endif 2806141611Sru "\n" 2807141611Sru " [-p pattern] [-S sourceaddr] [-s packetsize] " 2808141611Sru "[hops ...] host\n"); 280955163Sshin exit(1); 281055163Sshin} 2811