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> 128285820Shrs#include <sysexits.h> 12955163Sshin#include <unistd.h> 13055163Sshin 13155163Sshin#ifdef IPSEC 132171135Sgnn#include <netipsec/ah.h> 133171135Sgnn#include <netipsec/ipsec.h> 13455163Sshin#endif 13555163Sshin 13662627Skris#include <md5.h> 13762627Skris 138121472Sumestruct tv32 { 139121472Sume u_int32_t tv32_sec; 140121472Sume u_int32_t tv32_usec; 141121472Sume}; 142121472Sume 14362627Skris#define MAXPACKETLEN 131072 14455163Sshin#define IP6LEN 40 145121472Sume#define ICMP6ECHOLEN 8 /* icmp echo header len excluding time */ 146121472Sume#define ICMP6ECHOTMLEN sizeof(struct tv32) 14762627Skris#define ICMP6_NIQLEN (ICMP6ECHOLEN + 8) 148168866Smtm# define CONTROLLEN 10240 /* ancillary data buffer size RFC3542 20.1 */ 14978064Sume/* FQDN case, 64 bits of nonce + 32 bits ttl */ 15078064Sume#define ICMP6_NIRLEN (ICMP6ECHOLEN + 12) 15155163Sshin#define EXTRA 256 /* for AH and various other headers. weird. */ 15255163Sshin#define DEFDATALEN ICMP6ECHOTMLEN 15362627Skris#define MAXDATALEN MAXPACKETLEN - IP6LEN - ICMP6ECHOLEN 15455163Sshin#define NROUTES 9 /* number of record route slots */ 155285820Shrs#define MAXWAIT 10000 /* max ms to wait for response */ 156285820Shrs#define MAXALARM (60 * 60) /* max seconds for alarm timeout */ 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) 193285820Shrs#define F_WAITTIME 0x2000000 19455163Sshinu_int options; 19555163Sshin 19662627Skris#define IN6LEN sizeof(struct in6_addr) 19762627Skris#define SA6LEN sizeof(struct sockaddr_in6) 19878064Sume#define DUMMY_PORT 10101 19955163Sshin 20078064Sume#define SIN6(s) ((struct sockaddr_in6 *)(s)) 20155163Sshin 20255163Sshin/* 20355163Sshin * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum 20455163Sshin * number of received sequence numbers we can keep track of. Change 128 20555163Sshin * to 8192 for complete accuracy... 20655163Sshin */ 20755163Sshin#define MAX_DUP_CHK (8 * 8192) 20855163Sshinint mx_dup_ck = MAX_DUP_CHK; 20955163Sshinchar rcvd_tbl[MAX_DUP_CHK / 8]; 21055163Sshin 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; 22655163Sshin 22755163Sshin/* counters */ 228182276Smatteolong nmissedmax; /* max value of ntransmitted - nreceived - 1 */ 22955163Sshinlong npackets; /* max packets to transmit */ 23055163Sshinlong nreceived; /* # of packets we got back */ 23155163Sshinlong nrepeats; /* number of duplicates */ 23255163Sshinlong ntransmitted; /* sequence # for outbound packets = #sent */ 233285820Shrsint interval = 1000; /* interval between packets in ms */ 234285820Shrsint waittime = MAXWAIT; /* timeout for each packet */ 235285820Shrslong nrcvtimeout = 0; /* # of packets we got back after waittime */ 23655163Sshin 23755163Sshin/* timing */ 23855163Sshinint timing; /* flag to do timing */ 23955163Sshindouble tmin = 999999999.0; /* minimum round trip time */ 24055163Sshindouble tmax = 0.0; /* maximum round trip time */ 24155163Sshindouble tsum = 0.0; /* sum of all times, for doing average */ 24278064Sumedouble tsumsq = 0.0; /* sum of all times squared, for std. dev. */ 24355163Sshin 24455163Sshin/* for node addresses */ 24555163Sshinu_short naflags; 24655163Sshin 24755163Sshin/* for ancillary data(advanced API) */ 24855163Sshinstruct msghdr smsghdr; 24955163Sshinstruct iovec smsgiov; 25055163Sshinchar *scmsg = 0; 25155163Sshin 25278064Sumevolatile sig_atomic_t seenint; 25378064Sume#ifdef SIGINFO 25478064Sumevolatile sig_atomic_t seeninfo; 25578064Sume#endif 25678064Sume 257121472Sumeint main(int, char *[]); 25892883Simpvoid fill(char *, char *); 25992883Simpint get_hoplim(struct msghdr *); 26092883Simpint get_pathmtu(struct msghdr *); 26192883Simpstruct in6_pktinfo *get_rcvpktinfo(struct msghdr *); 26292883Simpvoid onsignal(int); 26392883Simpvoid onint(int); 26492883Simpsize_t pingerlen(void); 26592883Simpint pinger(void); 26692883Simpconst char *pr_addr(struct sockaddr *, int); 26792883Simpvoid pr_icmph(struct icmp6_hdr *, u_char *); 26892883Simpvoid pr_iph(struct ip6_hdr *); 26992883Simpvoid pr_suptypes(struct icmp6_nodeinfo *, size_t); 27092883Simpvoid pr_nodeaddr(struct icmp6_nodeinfo *, int); 27192883Simpint myechoreply(const struct icmp6_hdr *); 27292883Simpint mynireply(const struct icmp6_nodeinfo *); 27392883Simpchar *dnsdecode(const u_char **, const u_char *, const u_char *, 274121472Sume char *, size_t); 27592883Simpvoid pr_pack(u_char *, int, struct msghdr *); 27692883Simpvoid pr_exthdrs(struct msghdr *); 277168866Smtmvoid pr_ip6opt(void *, size_t); 278168866Smtmvoid pr_rthdr(void *, size_t); 27992883Simpint pr_bitrange(u_int32_t, int, int); 28092883Simpvoid pr_retip(struct ip6_hdr *, u_char *); 28192883Simpvoid summary(void); 28292883Simpvoid tvsub(struct timeval *, struct timeval *); 28392883Simpint setpolicy(int, char *); 284250251Shrschar *nigroup(char *, int); 28592883Simpvoid usage(void); 28655163Sshin 28755163Sshinint 288216561Scharniermain(int argc, char *argv[]) 28955163Sshin{ 290285820Shrs struct timeval last, intvl; 291285820Shrs struct sockaddr_in6 from, *sin6; 292285820Shrs struct addrinfo hints, *res; 293285820Shrs struct sigaction si_sa; 29492806Sobrien int cc, i; 295285820Shrs int almost_done, ch, hold, packlen, preload, optval, error; 296250251Shrs int nig_oldmcprefix = -1; 297209236Sbrucec u_char *datap; 298121472Sume char *e, *target, *ifname = NULL, *gateway = NULL; 29955163Sshin int ip6optlen = 0; 30055163Sshin struct cmsghdr *scmsgp = NULL; 301209236Sbrucec /* For control (ancillary) data received from recvmsg() */ 302209236Sbrucec struct cmsghdr cm[CONTROLLEN]; 303121472Sume#if defined(SO_SNDBUF) && defined(SO_RCVBUF) 304121472Sume u_long lsockbufsize; 30555163Sshin int sockbufsize = 0; 306121472Sume#endif 30762627Skris int usepktinfo = 0; 30862627Skris struct in6_pktinfo *pktinfo = NULL; 30962627Skris#ifdef USE_RFC2292BIS 31062627Skris struct ip6_rthdr *rthdr = NULL; 31162627Skris#endif 31255163Sshin#ifdef IPSEC_POLICY_IPSEC 31355163Sshin char *policy_in = NULL; 31455163Sshin char *policy_out = NULL; 31555163Sshin#endif 316285820Shrs double t; 317285820Shrs u_long alarmtimeout; 31878064Sume size_t rthlen; 319121472Sume#ifdef IPV6_USE_MIN_MTU 320121472Sume int mflag = 0; 321121472Sume#endif 32255163Sshin 32355163Sshin /* just to be sure */ 324107652Ssuz memset(&smsghdr, 0, sizeof(smsghdr)); 325107652Ssuz memset(&smsgiov, 0, sizeof(smsgiov)); 32655163Sshin 327285820Shrs alarmtimeout = preload = 0; 32855163Sshin datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN]; 32955163Sshin#ifndef IPSEC 33078064Sume#define ADDOPTS 33155163Sshin#else 33255163Sshin#ifdef IPSEC_POLICY_IPSEC 33378064Sume#define ADDOPTS "P:" 33455163Sshin#else 33578064Sume#define ADDOPTS "AE" 33655163Sshin#endif /*IPSEC_POLICY_IPSEC*/ 33755163Sshin#endif 33878064Sume while ((ch = getopt(argc, argv, 339285820Shrs "a:b:c:DdfHg:h:I:i:l:mnNop:qrRS:s:tvwWx:X:" ADDOPTS)) != -1) { 34078064Sume#undef ADDOPTS 34178064Sume switch (ch) { 34278064Sume case 'a': 34378064Sume { 34478064Sume char *cp; 34555163Sshin 34678064Sume options &= ~F_NOUSERDATA; 34778064Sume options |= F_NODEADDR; 34878064Sume for (cp = optarg; *cp != '\0'; cp++) { 34978064Sume switch (*cp) { 35078064Sume case 'a': 35178064Sume naflags |= NI_NODEADDR_FLAG_ALL; 35278064Sume break; 35378064Sume case 'c': 35478064Sume case 'C': 35578064Sume naflags |= NI_NODEADDR_FLAG_COMPAT; 35678064Sume break; 35778064Sume case 'l': 35878064Sume case 'L': 35978064Sume naflags |= NI_NODEADDR_FLAG_LINKLOCAL; 36078064Sume break; 36178064Sume case 's': 36278064Sume case 'S': 36378064Sume naflags |= NI_NODEADDR_FLAG_SITELOCAL; 36478064Sume break; 36578064Sume case 'g': 36678064Sume case 'G': 36778064Sume naflags |= NI_NODEADDR_FLAG_GLOBAL; 36878064Sume break; 36978064Sume case 'A': /* experimental. not in the spec */ 37078064Sume#ifdef NI_NODEADDR_FLAG_ANYCAST 37178064Sume naflags |= NI_NODEADDR_FLAG_ANYCAST; 37278064Sume break; 37378064Sume#else 37478064Sume errx(1, 37578064Sume"-a A is not supported on the platform"); 37678064Sume /*NOTREACHED*/ 37778064Sume#endif 37878064Sume default: 37978064Sume usage(); 38078064Sume /*NOTREACHED*/ 38178064Sume } 38278064Sume } 38378064Sume break; 38478064Sume } 38578064Sume case 'b': 38655163Sshin#if defined(SO_SNDBUF) && defined(SO_RCVBUF) 387121472Sume errno = 0; 388121472Sume e = NULL; 389121472Sume lsockbufsize = strtoul(optarg, &e, 10); 390121472Sume sockbufsize = lsockbufsize; 391121472Sume if (errno || !*optarg || *e || 392121472Sume sockbufsize != lsockbufsize) 393121472Sume errx(1, "invalid socket buffer size"); 39455163Sshin#else 39587668Scharnier errx(1, 39655163Sshin"-b option ignored: SO_SNDBUF/SO_RCVBUF socket options not supported"); 39755163Sshin#endif 39855163Sshin break; 39955163Sshin case 'c': 40055163Sshin npackets = strtol(optarg, &e, 10); 40155163Sshin if (npackets <= 0 || *optarg == '\0' || *e != '\0') 40255163Sshin errx(1, 40355163Sshin "illegal number of packets -- %s", optarg); 40455163Sshin break; 405206889Smaxim case 'D': 406206889Smaxim options |= F_DONTFRAG; 407206889Smaxim break; 40855163Sshin case 'd': 40955163Sshin options |= F_SO_DEBUG; 41055163Sshin break; 41155163Sshin case 'f': 412121472Sume if (getuid()) { 413121472Sume errno = EPERM; 414121472Sume errx(1, "Must be superuser to flood ping"); 415121472Sume } 41655163Sshin options |= F_FLOOD; 41755163Sshin setbuf(stdout, (char *)NULL); 41855163Sshin break; 419121472Sume case 'g': 420121472Sume gateway = optarg; 421121472Sume break; 42262627Skris case 'H': 42362627Skris options |= F_HOSTNAME; 42462627Skris break; 42555163Sshin case 'h': /* hoplimit */ 42655163Sshin hoplimit = strtol(optarg, &e, 10); 427121472Sume if (*optarg == '\0' || *e != '\0') 428121472Sume errx(1, "illegal hoplimit %s", optarg); 42955163Sshin if (255 < hoplimit || hoplimit < -1) 43055163Sshin errx(1, 43155163Sshin "illegal hoplimit -- %s", optarg); 43255163Sshin break; 43355163Sshin case 'I': 43455163Sshin ifname = optarg; 43555163Sshin options |= F_INTERFACE; 43662627Skris#ifndef USE_SIN6_SCOPE_ID 43762627Skris usepktinfo++; 43862627Skris#endif 43955163Sshin break; 44055163Sshin case 'i': /* wait between sending packets */ 441285820Shrs t = strtod(optarg, &e); 44278064Sume if (*optarg == '\0' || *e != '\0') 44378064Sume errx(1, "illegal timing interval %s", optarg); 444285820Shrs if (t < 1 && getuid()) { 44578064Sume errx(1, "%s: only root may use interval < 1s", 44678064Sume strerror(EPERM)); 44778064Sume } 448285820Shrs intvl.tv_sec = (long)t; 449285820Shrs intvl.tv_usec = 450285820Shrs (long)((t - intvl.tv_sec) * 1000000); 451285820Shrs if (intvl.tv_sec < 0) 45278064Sume errx(1, "illegal timing interval %s", optarg); 45378064Sume /* less than 1/hz does not make sense */ 454285820Shrs if (intvl.tv_sec == 0 && intvl.tv_usec < 1) { 455176549Ssilby warnx("too small interval, raised to .000001"); 456285820Shrs intvl.tv_usec = 1; 45778064Sume } 45855163Sshin options |= F_INTERVAL; 45955163Sshin break; 46055163Sshin case 'l': 461121472Sume if (getuid()) { 462121472Sume errno = EPERM; 463121472Sume errx(1, "Must be superuser to preload"); 464121472Sume } 46555163Sshin preload = strtol(optarg, &e, 10); 46655163Sshin if (preload < 0 || *optarg == '\0' || *e != '\0') 46755163Sshin errx(1, "illegal preload value -- %s", optarg); 46855163Sshin break; 46978064Sume case 'm': 47078064Sume#ifdef IPV6_USE_MIN_MTU 471121472Sume mflag++; 47278064Sume break; 47378064Sume#else 47478064Sume errx(1, "-%c is not supported on this platform", ch); 47578064Sume /*NOTREACHED*/ 47678064Sume#endif 47755163Sshin case 'n': 47878064Sume options &= ~F_HOSTNAME; 47955163Sshin break; 48062627Skris case 'N': 48162627Skris options |= F_NIGROUP; 482250251Shrs nig_oldmcprefix++; 48362627Skris break; 484173765Sdd case 'o': 485173765Sdd options |= F_ONCE; 486173765Sdd break; 48755163Sshin case 'p': /* fill buffer with user pattern */ 48855163Sshin options |= F_PINGFILLED; 48955163Sshin fill((char *)datap, optarg); 49055163Sshin break; 49155163Sshin case 'q': 49255163Sshin options |= F_QUIET; 49355163Sshin break; 494182276Smatteo case 'r': 495182276Smatteo options |= F_AUDIBLE; 496182276Smatteo break; 497182276Smatteo case 'R': 498182276Smatteo options |= F_MISSED; 499182276Smatteo break; 50062627Skris case 'S': 501121472Sume memset(&hints, 0, sizeof(struct addrinfo)); 502121472Sume hints.ai_flags = AI_NUMERICHOST; /* allow hostname? */ 503121472Sume hints.ai_family = AF_INET6; 504121472Sume hints.ai_socktype = SOCK_RAW; 505121472Sume hints.ai_protocol = IPPROTO_ICMPV6; 506121472Sume 507285820Shrs error = getaddrinfo(optarg, NULL, &hints, &res); 508285820Shrs if (error) { 509121472Sume errx(1, "invalid source address: %s", 510285820Shrs gai_strerror(error)); 511121472Sume } 512121472Sume /* 513121472Sume * res->ai_family must be AF_INET6 and res->ai_addrlen 514121472Sume * must be sizeof(src). 515121472Sume */ 516121472Sume memcpy(&src, res->ai_addr, res->ai_addrlen); 517121472Sume srclen = res->ai_addrlen; 518121472Sume freeaddrinfo(res); 519209236Sbrucec res = NULL; 52062627Skris options |= F_SRCADDR; 52162627Skris break; 52255163Sshin case 's': /* size of packet to send */ 52355163Sshin datalen = strtol(optarg, &e, 10); 52455163Sshin if (datalen <= 0 || *optarg == '\0' || *e != '\0') 52555163Sshin errx(1, "illegal datalen value -- %s", optarg); 52678064Sume if (datalen > MAXDATALEN) { 52755163Sshin errx(1, 52855163Sshin "datalen value too large, maximum is %d", 52955163Sshin MAXDATALEN); 53078064Sume } 53155163Sshin break; 53278064Sume case 't': 53378064Sume options &= ~F_NOUSERDATA; 53478064Sume options |= F_SUPTYPES; 53578064Sume break; 53655163Sshin case 'v': 53755163Sshin options |= F_VERBOSE; 53855163Sshin break; 53955163Sshin case 'w': 54078064Sume options &= ~F_NOUSERDATA; 54155163Sshin options |= F_FQDN; 54255163Sshin break; 54362627Skris case 'W': 54478064Sume options &= ~F_NOUSERDATA; 54562627Skris options |= F_FQDNOLD; 54662627Skris break; 547285820Shrs case 'x': 548285820Shrs t = strtod(optarg, &e); 549285820Shrs if (*e || e == optarg || t > (double)INT_MAX) 550285820Shrs err(EX_USAGE, "invalid timing interval: `%s'", 551285820Shrs optarg); 552285820Shrs options |= F_WAITTIME; 553285820Shrs waittime = (int)t; 554285820Shrs break; 555285820Shrs case 'X': 556285820Shrs alarmtimeout = strtoul(optarg, &e, 0); 557285820Shrs if ((alarmtimeout < 1) || (alarmtimeout == ULONG_MAX)) 558285820Shrs errx(EX_USAGE, "invalid timeout: `%s'", 559285820Shrs optarg); 560285820Shrs if (alarmtimeout > MAXALARM) 561285820Shrs errx(EX_USAGE, "invalid timeout: `%s' > %d", 562285820Shrs optarg, MAXALARM); 563285820Shrs alarm((int)alarmtimeout); 564285820Shrs break; 56555163Sshin#ifdef IPSEC 56655163Sshin#ifdef IPSEC_POLICY_IPSEC 56755163Sshin case 'P': 56855163Sshin options |= F_POLICY; 56969571Sume if (!strncmp("in", optarg, 2)) { 57069571Sume if ((policy_in = strdup(optarg)) == NULL) 57169571Sume errx(1, "strdup"); 57269571Sume } else if (!strncmp("out", optarg, 3)) { 57369571Sume if ((policy_out = strdup(optarg)) == NULL) 57469571Sume errx(1, "strdup"); 57569571Sume } else 57655163Sshin errx(1, "invalid security policy"); 57755163Sshin break; 57855163Sshin#else 57955163Sshin case 'A': 58055163Sshin options |= F_AUTHHDR; 58155163Sshin break; 58255163Sshin case 'E': 58355163Sshin options |= F_ENCRYPT; 58455163Sshin break; 58555163Sshin#endif /*IPSEC_POLICY_IPSEC*/ 58655163Sshin#endif /*IPSEC*/ 58755163Sshin default: 58855163Sshin usage(); 58962627Skris /*NOTREACHED*/ 59055163Sshin } 59162627Skris } 592121472Sume 59355163Sshin argc -= optind; 59455163Sshin argv += optind; 59555163Sshin 59662627Skris if (argc < 1) { 59755163Sshin usage(); 59862627Skris /*NOTREACHED*/ 59962627Skris } 60055163Sshin 60162627Skris if (argc > 1) { 60278064Sume#ifdef IPV6_RECVRTHDR /* 2292bis */ 60378064Sume rthlen = CMSG_SPACE(inet6_rth_space(IPV6_RTHDR_TYPE_0, 60478064Sume argc - 1)); 60578064Sume#else /* RFC2292 */ 60678064Sume rthlen = inet6_rthdr_space(IPV6_RTHDR_TYPE_0, argc - 1); 60762627Skris#endif 60878064Sume if (rthlen == 0) { 60978064Sume errx(1, "too many intermediate hops"); 61078064Sume /*NOTREACHED*/ 61178064Sume } 61278064Sume ip6optlen += rthlen; 61362627Skris } 61455163Sshin 61562627Skris if (options & F_NIGROUP) { 616250251Shrs target = nigroup(argv[argc - 1], nig_oldmcprefix); 61762627Skris if (target == NULL) { 61862627Skris usage(); 61962627Skris /*NOTREACHED*/ 62062627Skris } 62162627Skris } else 62262627Skris target = argv[argc - 1]; 62355163Sshin 62455163Sshin /* getaddrinfo */ 625121472Sume memset(&hints, 0, sizeof(struct addrinfo)); 62678064Sume hints.ai_flags = AI_CANONNAME; 62755163Sshin hints.ai_family = AF_INET6; 62855163Sshin hints.ai_socktype = SOCK_RAW; 62955163Sshin hints.ai_protocol = IPPROTO_ICMPV6; 63055163Sshin 631285820Shrs error = getaddrinfo(target, NULL, &hints, &res); 632285820Shrs if (error) 633285820Shrs errx(1, "%s", gai_strerror(error)); 63455163Sshin if (res->ai_canonname) 63555163Sshin hostname = res->ai_canonname; 63655163Sshin else 63755163Sshin hostname = target; 63878064Sume 63955163Sshin if (!res->ai_addr) 64055163Sshin errx(1, "getaddrinfo failed"); 64155163Sshin 64255163Sshin (void)memcpy(&dst, res->ai_addr, res->ai_addrlen); 64355163Sshin 64478064Sume if ((s = socket(res->ai_family, res->ai_socktype, 64578064Sume res->ai_protocol)) < 0) 64678064Sume err(1, "socket"); 64778064Sume 648121472Sume /* set the source address if specified. */ 649121472Sume if ((options & F_SRCADDR) && 650121472Sume bind(s, (struct sockaddr *)&src, srclen) != 0) { 651121472Sume err(1, "bind"); 652121472Sume } 653121472Sume 654121472Sume /* set the gateway (next hop) if specified */ 655121472Sume if (gateway) { 656285820Shrs memset(&hints, 0, sizeof(hints)); 657285820Shrs hints.ai_family = AF_INET6; 658285820Shrs hints.ai_socktype = SOCK_RAW; 659285820Shrs hints.ai_protocol = IPPROTO_ICMPV6; 660121472Sume 661285820Shrs error = getaddrinfo(gateway, NULL, &hints, &res); 662121472Sume if (error) { 663121472Sume errx(1, "getaddrinfo for the gateway %s: %s", 664121472Sume gateway, gai_strerror(error)); 665121472Sume } 666285820Shrs if (res->ai_next && (options & F_VERBOSE)) 667121472Sume warnx("gateway resolves to multiple addresses"); 668121472Sume 669121472Sume if (setsockopt(s, IPPROTO_IPV6, IPV6_NEXTHOP, 670285820Shrs res->ai_addr, res->ai_addrlen)) { 671121472Sume err(1, "setsockopt(IPV6_NEXTHOP)"); 672121472Sume } 673121472Sume 674285820Shrs freeaddrinfo(res); 675121472Sume } 676121472Sume 67778064Sume /* 67878064Sume * let the kerel pass extension headers of incoming packets, 67978064Sume * for privileged socket options 68078064Sume */ 68178064Sume if ((options & F_VERBOSE) != 0) { 68278064Sume int opton = 1; 68378064Sume 68478064Sume#ifdef IPV6_RECVHOPOPTS 68578064Sume if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &opton, 68678064Sume sizeof(opton))) 68778064Sume err(1, "setsockopt(IPV6_RECVHOPOPTS)"); 68878064Sume#else /* old adv. API */ 68978064Sume if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPOPTS, &opton, 69078064Sume sizeof(opton))) 69178064Sume err(1, "setsockopt(IPV6_HOPOPTS)"); 69278064Sume#endif 69378064Sume#ifdef IPV6_RECVDSTOPTS 69478064Sume if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTOPTS, &opton, 69578064Sume sizeof(opton))) 69678064Sume err(1, "setsockopt(IPV6_RECVDSTOPTS)"); 69778064Sume#else /* old adv. API */ 69878064Sume if (setsockopt(s, IPPROTO_IPV6, IPV6_DSTOPTS, &opton, 69978064Sume sizeof(opton))) 70078064Sume err(1, "setsockopt(IPV6_DSTOPTS)"); 70178064Sume#endif 70278064Sume#ifdef IPV6_RECVRTHDRDSTOPTS 70378064Sume if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDRDSTOPTS, &opton, 70478064Sume sizeof(opton))) 70578064Sume err(1, "setsockopt(IPV6_RECVRTHDRDSTOPTS)"); 70678064Sume#endif 70778064Sume } 70878064Sume 70978064Sume /* revoke root privilege */ 710241852Seadler if (seteuid(getuid()) != 0) 711241852Seadler err(1, "seteuid() failed"); 712241852Seadler if (setuid(getuid()) != 0) 713241852Seadler err(1, "setuid() failed"); 71478064Sume 715121472Sume if ((options & F_FLOOD) && (options & F_INTERVAL)) 71655163Sshin errx(1, "-f and -i incompatible options"); 71755163Sshin 71878064Sume if ((options & F_NOUSERDATA) == 0) { 719121472Sume if (datalen >= sizeof(struct tv32)) { 72078064Sume /* we can time transfer */ 72178064Sume timing = 1; 72278064Sume } else 72378064Sume timing = 0; 72478064Sume /* in F_VERBOSE case, we may get non-echoreply packets*/ 72578064Sume if (options & F_VERBOSE) 72678064Sume packlen = 2048 + IP6LEN + ICMP6ECHOLEN + EXTRA; 72778064Sume else 72878064Sume packlen = datalen + IP6LEN + ICMP6ECHOLEN + EXTRA; 72978064Sume } else { 73078064Sume /* suppress timing for node information query */ 73178064Sume timing = 0; 73278064Sume datalen = 2048; 73378064Sume packlen = 2048 + IP6LEN + ICMP6ECHOLEN + EXTRA; 73478064Sume } 73578064Sume 73655163Sshin if (!(packet = (u_char *)malloc((u_int)packlen))) 737121472Sume err(1, "Unable to allocate packet"); 73855163Sshin if (!(options & F_PINGFILLED)) 73978064Sume for (i = ICMP6ECHOLEN; i < packlen; ++i) 74055163Sshin *datap++ = i; 74155163Sshin 74255163Sshin ident = getpid() & 0xFFFF; 743287328Sdelphij arc4random_buf(nonce, sizeof(nonce)); 744206889Smaxim optval = 1; 745206889Smaxim if (options & F_DONTFRAG) 746206889Smaxim if (setsockopt(s, IPPROTO_IPV6, IPV6_DONTFRAG, 747206889Smaxim &optval, sizeof(optval)) == -1) 748206889Smaxim err(1, "IPV6_DONTFRAG"); 74955163Sshin hold = 1; 75055163Sshin 75155163Sshin if (options & F_SO_DEBUG) 75255163Sshin (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold, 75355163Sshin sizeof(hold)); 75455163Sshin optval = IPV6_DEFHLIM; 75555163Sshin if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) 75655163Sshin if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 75778064Sume &optval, sizeof(optval)) == -1) 75855163Sshin err(1, "IPV6_MULTICAST_HOPS"); 75978064Sume#ifdef IPV6_USE_MIN_MTU 760121472Sume if (mflag != 1) { 761121472Sume optval = mflag > 1 ? 0 : 1; 762121472Sume 76378064Sume if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU, 76478064Sume &optval, sizeof(optval)) == -1) 76578064Sume err(1, "setsockopt(IPV6_USE_MIN_MTU)"); 76678064Sume } 76778064Sume#ifdef IPV6_RECVPATHMTU 76878064Sume else { 76978064Sume optval = 1; 77078064Sume if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPATHMTU, 77178064Sume &optval, sizeof(optval)) == -1) 77278064Sume err(1, "setsockopt(IPV6_RECVPATHMTU)"); 77378064Sume } 77478064Sume#endif /* IPV6_RECVPATHMTU */ 77578064Sume#endif /* IPV6_USE_MIN_MTU */ 77655163Sshin 77755163Sshin#ifdef IPSEC 77855163Sshin#ifdef IPSEC_POLICY_IPSEC 77955163Sshin if (options & F_POLICY) { 78055163Sshin if (setpolicy(s, policy_in) < 0) 78164277Skris errx(1, "%s", ipsec_strerror()); 78255163Sshin if (setpolicy(s, policy_out) < 0) 78364277Skris errx(1, "%s", ipsec_strerror()); 78455163Sshin } 78555163Sshin#else 78655163Sshin if (options & F_AUTHHDR) { 78755163Sshin optval = IPSEC_LEVEL_REQUIRE; 78855163Sshin#ifdef IPV6_AUTH_TRANS_LEVEL 78955163Sshin if (setsockopt(s, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, 79078064Sume &optval, sizeof(optval)) == -1) 79155163Sshin err(1, "setsockopt(IPV6_AUTH_TRANS_LEVEL)"); 79255163Sshin#else /* old def */ 79355163Sshin if (setsockopt(s, IPPROTO_IPV6, IPV6_AUTH_LEVEL, 79478064Sume &optval, sizeof(optval)) == -1) 79555163Sshin err(1, "setsockopt(IPV6_AUTH_LEVEL)"); 79655163Sshin#endif 79755163Sshin } 79855163Sshin if (options & F_ENCRYPT) { 79955163Sshin optval = IPSEC_LEVEL_REQUIRE; 80055163Sshin if (setsockopt(s, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, 80178064Sume &optval, sizeof(optval)) == -1) 80255163Sshin err(1, "setsockopt(IPV6_ESP_TRANS_LEVEL)"); 80355163Sshin } 80455163Sshin#endif /*IPSEC_POLICY_IPSEC*/ 80555163Sshin#endif 80655163Sshin 80755163Sshin#ifdef ICMP6_FILTER 80855163Sshin { 80955163Sshin struct icmp6_filter filt; 81055163Sshin if (!(options & F_VERBOSE)) { 81155163Sshin ICMP6_FILTER_SETBLOCKALL(&filt); 81262627Skris if ((options & F_FQDN) || (options & F_FQDNOLD) || 81378064Sume (options & F_NODEADDR) || (options & F_SUPTYPES)) 81455163Sshin ICMP6_FILTER_SETPASS(ICMP6_NI_REPLY, &filt); 81555163Sshin else 81655163Sshin ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt); 81755163Sshin } else { 81855163Sshin ICMP6_FILTER_SETPASSALL(&filt); 81955163Sshin } 82055163Sshin if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, 82178064Sume sizeof(filt)) < 0) 82255163Sshin err(1, "setsockopt(ICMP6_FILTER)"); 82355163Sshin } 82455163Sshin#endif /*ICMP6_FILTER*/ 82555163Sshin 82662627Skris /* let the kerel pass extension headers of incoming packets */ 82762627Skris if ((options & F_VERBOSE) != 0) { 82862627Skris int opton = 1; 82962627Skris 83062627Skris#ifdef IPV6_RECVRTHDR 83162627Skris if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDR, &opton, 83278064Sume sizeof(opton))) 83362627Skris err(1, "setsockopt(IPV6_RECVRTHDR)"); 83462627Skris#else /* old adv. API */ 83562627Skris if (setsockopt(s, IPPROTO_IPV6, IPV6_RTHDR, &opton, 83678064Sume sizeof(opton))) 83762627Skris err(1, "setsockopt(IPV6_RTHDR)"); 83862627Skris#endif 83962627Skris } 84062627Skris 84155163Sshin/* 84255163Sshin optval = 1; 84355163Sshin if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) 84455163Sshin if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 84578064Sume &optval, sizeof(optval)) == -1) 84655163Sshin err(1, "IPV6_MULTICAST_LOOP"); 84755163Sshin*/ 84855163Sshin 84962627Skris /* Specify the outgoing interface and/or the source address */ 85062627Skris if (usepktinfo) 85155163Sshin ip6optlen += CMSG_SPACE(sizeof(struct in6_pktinfo)); 85255163Sshin 85355163Sshin if (hoplimit != -1) 85455163Sshin ip6optlen += CMSG_SPACE(sizeof(int)); 85555163Sshin 85655163Sshin /* set IP6 packet options */ 85755163Sshin if (ip6optlen) { 85855163Sshin if ((scmsg = (char *)malloc(ip6optlen)) == 0) 85955163Sshin errx(1, "can't allocate enough memory"); 86055163Sshin smsghdr.msg_control = (caddr_t)scmsg; 86155163Sshin smsghdr.msg_controllen = ip6optlen; 86255163Sshin scmsgp = (struct cmsghdr *)scmsg; 86355163Sshin } 86462627Skris if (usepktinfo) { 86562627Skris pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp)); 86662627Skris memset(pktinfo, 0, sizeof(*pktinfo)); 86755163Sshin scmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 86855163Sshin scmsgp->cmsg_level = IPPROTO_IPV6; 86955163Sshin scmsgp->cmsg_type = IPV6_PKTINFO; 87062627Skris scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp); 87162627Skris } 87255163Sshin 87362627Skris /* set the outgoing interface */ 87462627Skris if (ifname) { 87562627Skris#ifndef USE_SIN6_SCOPE_ID 87662627Skris /* pktinfo must have already been allocated */ 87762627Skris if ((pktinfo->ipi6_ifindex = if_nametoindex(ifname)) == 0) 87878064Sume errx(1, "%s: invalid interface name", ifname); 87955163Sshin#else 88055163Sshin if ((dst.sin6_scope_id = if_nametoindex(ifname)) == 0) 88155163Sshin errx(1, "%s: invalid interface name", ifname); 88255163Sshin#endif 88355163Sshin } 88455163Sshin if (hoplimit != -1) { 88555163Sshin scmsgp->cmsg_len = CMSG_LEN(sizeof(int)); 88655163Sshin scmsgp->cmsg_level = IPPROTO_IPV6; 88755163Sshin scmsgp->cmsg_type = IPV6_HOPLIMIT; 88855163Sshin *(int *)(CMSG_DATA(scmsgp)) = hoplimit; 88955163Sshin 89055163Sshin scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp); 89155163Sshin } 89262627Skris 89355163Sshin if (argc > 1) { /* some intermediate addrs are specified */ 894285820Shrs int hops; 89562627Skris#ifdef USE_RFC2292BIS 89662627Skris int rthdrlen; 89762627Skris#endif 89855163Sshin 89962627Skris#ifdef USE_RFC2292BIS 90062627Skris rthdrlen = inet6_rth_space(IPV6_RTHDR_TYPE_0, argc - 1); 90162627Skris scmsgp->cmsg_len = CMSG_LEN(rthdrlen); 90262627Skris scmsgp->cmsg_level = IPPROTO_IPV6; 90362627Skris scmsgp->cmsg_type = IPV6_RTHDR; 90462627Skris rthdr = (struct ip6_rthdr *)CMSG_DATA(scmsgp); 90562627Skris rthdr = inet6_rth_init((void *)rthdr, rthdrlen, 90678064Sume IPV6_RTHDR_TYPE_0, argc - 1); 90762627Skris if (rthdr == NULL) 90862627Skris errx(1, "can't initialize rthdr"); 90962627Skris#else /* old advanced API */ 91055163Sshin if ((scmsgp = (struct cmsghdr *)inet6_rthdr_init(scmsgp, 91178064Sume IPV6_RTHDR_TYPE_0)) == 0) 91255163Sshin errx(1, "can't initialize rthdr"); 91362627Skris#endif /* USE_RFC2292BIS */ 91455163Sshin 91555163Sshin for (hops = 0; hops < argc - 1; hops++) { 916285820Shrs memset(&hints, 0, sizeof(hints)); 917285820Shrs hints.ai_family = AF_INET6; 91855163Sshin 91978064Sume if ((error = getaddrinfo(argv[hops], NULL, &hints, 920285820Shrs &res))) 92164277Skris errx(1, "%s", gai_strerror(error)); 922285820Shrs if (res->ai_addr->sa_family != AF_INET6) 92355163Sshin errx(1, 92478064Sume "bad addr family of an intermediate addr"); 925285820Shrs sin6 = (struct sockaddr_in6 *)(void *)res->ai_addr; 92662627Skris#ifdef USE_RFC2292BIS 927285820Shrs if (inet6_rth_add(rthdr, &sin6->sin6_addr)) 92862627Skris errx(1, "can't add an intermediate node"); 92962627Skris#else /* old advanced API */ 930285820Shrs if (inet6_rthdr_add(scmsg, &sin6->sin6_addr, 93178064Sume IPV6_RTHDR_LOOSE)) 93255163Sshin errx(1, "can't add an intermediate node"); 93362627Skris#endif /* USE_RFC2292BIS */ 934285820Shrs freeaddrinfo(res); 93555163Sshin } 93655163Sshin 93762627Skris#ifndef USE_RFC2292BIS 93855163Sshin if (inet6_rthdr_lasthop(scmsgp, IPV6_RTHDR_LOOSE)) 93955163Sshin errx(1, "can't set the last flag"); 94062627Skris#endif 94155163Sshin 94255163Sshin scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp); 94355163Sshin } 94455163Sshin 945121472Sume if (!(options & F_SRCADDR)) { 94655163Sshin /* 947121472Sume * get the source address. XXX since we revoked the root 948121472Sume * privilege, we cannot use a raw socket for this. 94955163Sshin */ 950121472Sume int dummy; 951121472Sume socklen_t len = sizeof(src); 95278064Sume 95355163Sshin if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 95455163Sshin err(1, "UDP socket"); 95555163Sshin 95655163Sshin src.sin6_family = AF_INET6; 95755163Sshin src.sin6_addr = dst.sin6_addr; 95855163Sshin src.sin6_port = ntohs(DUMMY_PORT); 95955163Sshin src.sin6_scope_id = dst.sin6_scope_id; 96055163Sshin 96162627Skris#ifdef USE_RFC2292BIS 96262627Skris if (pktinfo && 96362627Skris setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTINFO, 96478064Sume (void *)pktinfo, sizeof(*pktinfo))) 96562627Skris err(1, "UDP setsockopt(IPV6_PKTINFO)"); 96662627Skris 96762627Skris if (hoplimit != -1 && 968121472Sume setsockopt(dummy, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 96978064Sume (void *)&hoplimit, sizeof(hoplimit))) 970121472Sume err(1, "UDP setsockopt(IPV6_UNICAST_HOPS)"); 97162627Skris 972121472Sume if (hoplimit != -1 && 973121472Sume setsockopt(dummy, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 974121472Sume (void *)&hoplimit, sizeof(hoplimit))) 975121472Sume err(1, "UDP setsockopt(IPV6_MULTICAST_HOPS)"); 976121472Sume 97762627Skris if (rthdr && 97862627Skris setsockopt(dummy, IPPROTO_IPV6, IPV6_RTHDR, 97978064Sume (void *)rthdr, (rthdr->ip6r_len + 1) << 3)) 98062627Skris err(1, "UDP setsockopt(IPV6_RTHDR)"); 98162627Skris#else /* old advanced API */ 98262627Skris if (smsghdr.msg_control && 98362627Skris setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTOPTIONS, 98478064Sume (void *)smsghdr.msg_control, smsghdr.msg_controllen)) 98562627Skris err(1, "UDP setsockopt(IPV6_PKTOPTIONS)"); 98655163Sshin#endif 98778064Sume 98855163Sshin if (connect(dummy, (struct sockaddr *)&src, len) < 0) 98955163Sshin err(1, "UDP connect"); 99078064Sume 99155163Sshin if (getsockname(dummy, (struct sockaddr *)&src, &len) < 0) 99255163Sshin err(1, "getsockname"); 99355163Sshin 99455163Sshin close(dummy); 99555163Sshin } 99655163Sshin 99755163Sshin#if defined(SO_SNDBUF) && defined(SO_RCVBUF) 99855163Sshin if (sockbufsize) { 99955163Sshin if (datalen > sockbufsize) 100062627Skris warnx("you need -b to increase socket buffer size"); 100155163Sshin if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sockbufsize, 100278064Sume sizeof(sockbufsize)) < 0) 100355163Sshin err(1, "setsockopt(SO_SNDBUF)"); 100455163Sshin if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &sockbufsize, 100578064Sume sizeof(sockbufsize)) < 0) 100655163Sshin err(1, "setsockopt(SO_RCVBUF)"); 100755163Sshin } 100855163Sshin else { 100955163Sshin if (datalen > 8 * 1024) /*XXX*/ 101055163Sshin warnx("you need -b to increase socket buffer size"); 101155163Sshin /* 101255163Sshin * When pinging the broadcast address, you can get a lot of 101355163Sshin * answers. Doing something so evil is useful if you are trying 101455163Sshin * to stress the ethernet, or just want to fill the arp cache 101555163Sshin * to get some stuff for /etc/ethers. 101655163Sshin */ 101755163Sshin hold = 48 * 1024; 101878064Sume setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold, 101978064Sume sizeof(hold)); 102055163Sshin } 102155163Sshin#endif 102255163Sshin 102355163Sshin optval = 1; 102455163Sshin#ifndef USE_SIN6_SCOPE_ID 102562627Skris#ifdef IPV6_RECVPKTINFO 102662627Skris if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &optval, 102778064Sume sizeof(optval)) < 0) 102862627Skris warn("setsockopt(IPV6_RECVPKTINFO)"); /* XXX err? */ 102962627Skris#else /* old adv. API */ 103062627Skris if (setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &optval, 103178064Sume sizeof(optval)) < 0) 103262627Skris warn("setsockopt(IPV6_PKTINFO)"); /* XXX err? */ 103355163Sshin#endif 103462627Skris#endif /* USE_SIN6_SCOPE_ID */ 103562627Skris#ifdef IPV6_RECVHOPLIMIT 103662627Skris if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &optval, 103778064Sume sizeof(optval)) < 0) 103862627Skris warn("setsockopt(IPV6_RECVHOPLIMIT)"); /* XXX err? */ 103962627Skris#else /* old adv. API */ 104062627Skris if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPLIMIT, &optval, 104178064Sume sizeof(optval)) < 0) 104262627Skris warn("setsockopt(IPV6_HOPLIMIT)"); /* XXX err? */ 104362627Skris#endif 104455163Sshin 104578064Sume printf("PING6(%lu=40+8+%lu bytes) ", (unsigned long)(40 + pingerlen()), 104678064Sume (unsigned long)(pingerlen() - 8)); 104778064Sume printf("%s --> ", pr_addr((struct sockaddr *)&src, sizeof(src))); 104878064Sume printf("%s\n", pr_addr((struct sockaddr *)&dst, sizeof(dst))); 104955163Sshin 1050285820Shrs if (preload == 0) 1051285820Shrs pinger(); 1052285820Shrs else { 1053285820Shrs if (npackets != 0 && preload > npackets) 1054285820Shrs preload = npackets; 1055285820Shrs while (preload--) 1056285820Shrs pinger(); 105755163Sshin } 1058285820Shrs gettimeofday(&last, NULL); 105955163Sshin 1060285820Shrs sigemptyset(&si_sa.sa_mask); 1061285820Shrs si_sa.sa_flags = 0; 1062285820Shrs si_sa.sa_handler = onsignal; 1063285820Shrs if (sigaction(SIGINT, &si_sa, 0) == -1) 1064285820Shrs err(EX_OSERR, "sigaction SIGINT"); 1065285820Shrs seenint = 0; 106678064Sume#ifdef SIGINFO 1067285820Shrs if (sigaction(SIGINFO, &si_sa, 0) == -1) 1068285820Shrs err(EX_OSERR, "sigaction SIGINFO"); 106978064Sume seeninfo = 0; 107078064Sume#endif 1071285820Shrs if (alarmtimeout > 0) { 1072285820Shrs if (sigaction(SIGALRM, &si_sa, 0) == -1) 1073285820Shrs err(EX_OSERR, "sigaction SIGALRM"); 1074285820Shrs } 1075285820Shrs if (options & F_FLOOD) { 1076285820Shrs intvl.tv_sec = 0; 1077285820Shrs intvl.tv_usec = 10000; 1078285820Shrs } else if ((options & F_INTERVAL) == 0) { 1079285820Shrs intvl.tv_sec = interval / 1000; 1080285820Shrs intvl.tv_usec = interval % 1000 * 1000; 1081285820Shrs } 108278064Sume 1083285820Shrs almost_done = 0; 1084285820Shrs while (seenint == 0) { 1085285820Shrs struct timeval now, timeout; 108655163Sshin struct msghdr m; 108755163Sshin struct iovec iov[2]; 1088285820Shrs fd_set rfds; 1089285820Shrs int n; 109055163Sshin 109178064Sume /* signal handling */ 1092285820Shrs if (seenint) 109378064Sume onint(SIGINT); 109478064Sume#ifdef SIGINFO 109578064Sume if (seeninfo) { 109678064Sume summary(); 109778064Sume seeninfo = 0; 109878064Sume continue; 109978064Sume } 110078064Sume#endif 1101285820Shrs FD_ZERO(&rfds); 1102285820Shrs FD_SET(s, &rfds); 1103285820Shrs gettimeofday(&now, NULL); 1104285820Shrs timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec; 1105285820Shrs timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec; 1106285820Shrs while (timeout.tv_usec < 0) { 1107285820Shrs timeout.tv_usec += 1000000; 1108285820Shrs timeout.tv_sec--; 1109121472Sume } 1110285820Shrs while (timeout.tv_usec > 1000000) { 1111285820Shrs timeout.tv_usec -= 1000000; 1112285820Shrs timeout.tv_sec++; 1113285820Shrs } 1114285820Shrs if (timeout.tv_sec < 0) 1115285820Shrs timeout.tv_sec = timeout.tv_usec = 0; 111678064Sume 1117285820Shrs n = select(s + 1, &rfds, NULL, NULL, &timeout); 1118285820Shrs if (n < 0) 1119285820Shrs continue; /* EINTR */ 1120285820Shrs if (n == 1) { 1121285820Shrs m.msg_name = (caddr_t)&from; 1122285820Shrs m.msg_namelen = sizeof(from); 1123285820Shrs memset(&iov, 0, sizeof(iov)); 1124285820Shrs iov[0].iov_base = (caddr_t)packet; 1125285820Shrs iov[0].iov_len = packlen; 1126285820Shrs m.msg_iov = iov; 1127285820Shrs m.msg_iovlen = 1; 1128285820Shrs memset(cm, 0, CONTROLLEN); 1129285820Shrs m.msg_control = (void *)cm; 1130285820Shrs m.msg_controllen = CONTROLLEN; 113155163Sshin 1132285820Shrs cc = recvmsg(s, &m, 0); 1133285820Shrs if (cc < 0) { 1134285820Shrs if (errno != EINTR) { 1135285820Shrs warn("recvmsg"); 1136285820Shrs sleep(1); 1137285820Shrs } 1138285820Shrs continue; 1139285820Shrs } else if (cc == 0) { 1140285820Shrs int mtu; 1141285820Shrs 1142285820Shrs /* 1143285820Shrs * receive control messages only. Process the 1144285820Shrs * exceptions (currently the only possibility is 1145285820Shrs * a path MTU notification.) 1146285820Shrs */ 1147285820Shrs if ((mtu = get_pathmtu(&m)) > 0) { 1148285820Shrs if ((options & F_VERBOSE) != 0) { 1149285820Shrs printf("new path MTU (%d) is " 1150285820Shrs "notified\n", mtu); 1151285820Shrs } 1152285820Shrs } 1153285820Shrs continue; 1154285820Shrs } else { 1155285820Shrs /* 1156285820Shrs * an ICMPv6 message (probably an echoreply) 1157285820Shrs * arrived. 1158285820Shrs */ 1159285820Shrs pr_pack(packet, cc, &m); 116078064Sume } 1161285820Shrs if (((options & F_ONCE) != 0 && nreceived > 0) || 1162285820Shrs (npackets > 0 && nreceived >= npackets)) 1163285820Shrs break; 1164285820Shrs } 1165285820Shrs if (n == 0 || (options & F_FLOOD)) { 1166285820Shrs if (npackets == 0 || ntransmitted < npackets) 1167285820Shrs pinger(); 1168285820Shrs else { 1169285820Shrs if (almost_done) 1170285820Shrs break; 1171285820Shrs almost_done = 1; 117278064Sume /* 1173285820Shrs * If we're not transmitting any more packets, 1174285820Shrs * change the timer to wait two round-trip times 1175285820Shrs * if we've received any packets or (waittime) 1176285820Shrs * milliseconds if we haven't. 117778064Sume */ 1178285820Shrs intvl.tv_usec = 0; 1179285820Shrs if (nreceived) { 1180285820Shrs intvl.tv_sec = 2 * tmax / 1000; 1181285820Shrs if (intvl.tv_sec == 0) 1182285820Shrs intvl.tv_sec = 1; 1183285820Shrs } else { 1184285820Shrs intvl.tv_sec = waittime / 1000; 1185285820Shrs intvl.tv_usec = waittime % 1000 * 1000; 118678064Sume } 118778064Sume } 1188285820Shrs gettimeofday(&last, NULL); 1189285820Shrs if (ntransmitted - nreceived - 1 > nmissedmax) { 1190285820Shrs nmissedmax = ntransmitted - nreceived - 1; 1191285820Shrs if (options & F_MISSED) 1192285820Shrs (void)write(STDOUT_FILENO, &BBELL, 1); 1193285820Shrs } 119455163Sshin } 119555163Sshin } 1196285820Shrs sigemptyset(&si_sa.sa_mask); 1197285820Shrs si_sa.sa_flags = 0; 1198285820Shrs si_sa.sa_handler = SIG_IGN; 1199285820Shrs sigaction(SIGINT, &si_sa, 0); 1200285820Shrs sigaction(SIGALRM, &si_sa, 0); 120155163Sshin summary(); 1202209236Sbrucec 1203209236Sbrucec if (res != NULL) 1204209236Sbrucec freeaddrinfo(res); 1205209236Sbrucec 1206209236Sbrucec if(packet != NULL) 1207209236Sbrucec free(packet); 1208209236Sbrucec 1209179356Sbz exit(nreceived == 0 ? 2 : 0); 121055163Sshin} 121155163Sshin 121278064Sumevoid 1213216561Scharnieronsignal(int sig) 121478064Sume{ 1215121472Sume 121678064Sume switch (sig) { 1217285820Shrs case SIGINT: 121878064Sume case SIGALRM: 121978064Sume seenint++; 122078064Sume break; 122178064Sume#ifdef SIGINFO 122278064Sume case SIGINFO: 122378064Sume seeninfo++; 122478064Sume break; 122578064Sume#endif 122678064Sume } 122778064Sume} 122878064Sume 122955163Sshin/* 123055163Sshin * pinger -- 123155163Sshin * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet 123255163Sshin * will be added on by the kernel. The ID field is our UNIX process ID, 123355163Sshin * and the sequence number is an ascending integer. The first 8 bytes 123455163Sshin * of the data portion are used to hold a UNIX "timeval" struct in VAX 123555163Sshin * byte-order, to compute the round-trip time. 123655163Sshin */ 123778064Sumesize_t 1238216561Scharnierpingerlen(void) 123978064Sume{ 124078064Sume size_t l; 124178064Sume 124278064Sume if (options & F_FQDN) 124378064Sume l = ICMP6_NIQLEN + sizeof(dst.sin6_addr); 124478064Sume else if (options & F_FQDNOLD) 124578064Sume l = ICMP6_NIQLEN; 124678064Sume else if (options & F_NODEADDR) 124778064Sume l = ICMP6_NIQLEN + sizeof(dst.sin6_addr); 124878064Sume else if (options & F_SUPTYPES) 124978064Sume l = ICMP6_NIQLEN; 125078064Sume else 125178064Sume l = ICMP6ECHOLEN + datalen; 125278064Sume 125378064Sume return l; 125478064Sume} 125578064Sume 125678984Sumeint 1257216561Scharnierpinger(void) 125855163Sshin{ 125955163Sshin struct icmp6_hdr *icp; 126055163Sshin struct iovec iov[2]; 126155163Sshin int i, cc; 126278064Sume struct icmp6_nodeinfo *nip; 126378064Sume int seq; 126455163Sshin 126578984Sume if (npackets && ntransmitted >= npackets) 126678984Sume return(-1); /* no more transmission */ 126778984Sume 126855163Sshin icp = (struct icmp6_hdr *)outpack; 126978064Sume nip = (struct icmp6_nodeinfo *)outpack; 127062627Skris memset(icp, 0, sizeof(*icp)); 127155163Sshin icp->icmp6_cksum = 0; 127278064Sume seq = ntransmitted++; 127378064Sume CLR(seq % mx_dup_ck); 127455163Sshin 127555163Sshin if (options & F_FQDN) { 127655163Sshin icp->icmp6_type = ICMP6_NI_QUERY; 127762627Skris icp->icmp6_code = ICMP6_NI_SUBJ_IPV6; 127878064Sume nip->ni_qtype = htons(NI_QTYPE_FQDN); 127978064Sume nip->ni_flags = htons(0); 128078064Sume 128178064Sume memcpy(nip->icmp6_ni_nonce, nonce, 128278064Sume sizeof(nip->icmp6_ni_nonce)); 128378064Sume *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); 128478064Sume 128562627Skris memcpy(&outpack[ICMP6_NIQLEN], &dst.sin6_addr, 128662627Skris sizeof(dst.sin6_addr)); 128762627Skris cc = ICMP6_NIQLEN + sizeof(dst.sin6_addr); 128862627Skris datalen = 0; 128962627Skris } else if (options & F_FQDNOLD) { 129062627Skris /* packet format in 03 draft - no Subject data on queries */ 129162627Skris icp->icmp6_type = ICMP6_NI_QUERY; 129278064Sume icp->icmp6_code = 0; /* code field is always 0 */ 129378064Sume nip->ni_qtype = htons(NI_QTYPE_FQDN); 129478064Sume nip->ni_flags = htons(0); 129578064Sume 129678064Sume memcpy(nip->icmp6_ni_nonce, nonce, 129778064Sume sizeof(nip->icmp6_ni_nonce)); 129878064Sume *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); 129978064Sume 130055163Sshin cc = ICMP6_NIQLEN; 130155163Sshin datalen = 0; 130255163Sshin } else if (options & F_NODEADDR) { 130355163Sshin icp->icmp6_type = ICMP6_NI_QUERY; 130462627Skris icp->icmp6_code = ICMP6_NI_SUBJ_IPV6; 130578064Sume nip->ni_qtype = htons(NI_QTYPE_NODEADDR); 130678064Sume nip->ni_flags = naflags; 130778064Sume 130878064Sume memcpy(nip->icmp6_ni_nonce, nonce, 130978064Sume sizeof(nip->icmp6_ni_nonce)); 131078064Sume *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); 131178064Sume 131262627Skris memcpy(&outpack[ICMP6_NIQLEN], &dst.sin6_addr, 131362627Skris sizeof(dst.sin6_addr)); 131462627Skris cc = ICMP6_NIQLEN + sizeof(dst.sin6_addr); 131555163Sshin datalen = 0; 131678064Sume } else if (options & F_SUPTYPES) { 131778064Sume icp->icmp6_type = ICMP6_NI_QUERY; 131878064Sume icp->icmp6_code = ICMP6_NI_SUBJ_FQDN; /*empty*/ 131978064Sume nip->ni_qtype = htons(NI_QTYPE_SUPTYPES); 132078064Sume /* we support compressed bitmap */ 132178064Sume nip->ni_flags = NI_SUPTYPE_FLAG_COMPRESS; 132278064Sume 132378064Sume memcpy(nip->icmp6_ni_nonce, nonce, 132478064Sume sizeof(nip->icmp6_ni_nonce)); 132578064Sume *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); 132678064Sume cc = ICMP6_NIQLEN; 132778064Sume datalen = 0; 132878064Sume } else { 132955163Sshin icp->icmp6_type = ICMP6_ECHO_REQUEST; 133078064Sume icp->icmp6_code = 0; 133178064Sume icp->icmp6_id = htons(ident); 133278064Sume icp->icmp6_seq = ntohs(seq); 1333121472Sume if (timing) { 1334121472Sume struct timeval tv; 1335121472Sume struct tv32 *tv32; 1336121472Sume (void)gettimeofday(&tv, NULL); 1337121472Sume tv32 = (struct tv32 *)&outpack[ICMP6ECHOLEN]; 1338121472Sume tv32->tv32_sec = htonl(tv.tv_sec); 1339121472Sume tv32->tv32_usec = htonl(tv.tv_usec); 1340121472Sume } 134155163Sshin cc = ICMP6ECHOLEN + datalen; 134255163Sshin } 134355163Sshin 134478064Sume#ifdef DIAGNOSTIC 134578064Sume if (pingerlen() != cc) 134678064Sume errx(1, "internal error; length mismatch"); 134778064Sume#endif 134878064Sume 134955163Sshin smsghdr.msg_name = (caddr_t)&dst; 135055163Sshin smsghdr.msg_namelen = sizeof(dst); 135155163Sshin memset(&iov, 0, sizeof(iov)); 135255163Sshin iov[0].iov_base = (caddr_t)outpack; 135355163Sshin iov[0].iov_len = cc; 135455163Sshin smsghdr.msg_iov = iov; 135555163Sshin smsghdr.msg_iovlen = 1; 135655163Sshin 135755163Sshin i = sendmsg(s, &smsghdr, 0); 135855163Sshin 135955163Sshin if (i < 0 || i != cc) { 136055163Sshin if (i < 0) 136155163Sshin warn("sendmsg"); 136255163Sshin (void)printf("ping6: wrote %s %d chars, ret=%d\n", 136355163Sshin hostname, cc, i); 136455163Sshin } 136555163Sshin if (!(options & F_QUIET) && options & F_FLOOD) 136655163Sshin (void)write(STDOUT_FILENO, &DOT, 1); 136778984Sume 136878984Sume return(0); 136955163Sshin} 137055163Sshin 137178064Sumeint 1372216561Scharniermyechoreply(const struct icmp6_hdr *icp) 137378064Sume{ 137478064Sume if (ntohs(icp->icmp6_id) == ident) 137578064Sume return 1; 137678064Sume else 137778064Sume return 0; 137878064Sume} 137978064Sume 138078064Sumeint 1381216561Scharniermynireply(const struct icmp6_nodeinfo *nip) 138278064Sume{ 138378064Sume if (memcmp(nip->icmp6_ni_nonce + sizeof(u_int16_t), 138478064Sume nonce + sizeof(u_int16_t), 138578064Sume sizeof(nonce) - sizeof(u_int16_t)) == 0) 138678064Sume return 1; 138778064Sume else 138878064Sume return 0; 138978064Sume} 139078064Sume 139178064Sumechar * 1392216561Scharnierdnsdecode(const u_char **sp, const u_char *ep, const u_char *base, char *buf, 1393216561Scharnier size_t bufsiz) 1394216561Scharnier /*base for compressed name*/ 139578064Sume{ 139678064Sume int i; 139778064Sume const u_char *cp; 139878064Sume char cresult[MAXDNAME + 1]; 139978064Sume const u_char *comp; 140078064Sume int l; 140178064Sume 140278064Sume cp = *sp; 140378064Sume *buf = '\0'; 140478064Sume 140578064Sume if (cp >= ep) 140678064Sume return NULL; 140778064Sume while (cp < ep) { 140878064Sume i = *cp; 140978064Sume if (i == 0 || cp != *sp) { 1410121472Sume if (strlcat((char *)buf, ".", bufsiz) >= bufsiz) 141178064Sume return NULL; /*result overrun*/ 141278064Sume } 141378064Sume if (i == 0) 141478064Sume break; 141578064Sume cp++; 141678064Sume 141778064Sume if ((i & 0xc0) == 0xc0 && cp - base > (i & 0x3f)) { 141878064Sume /* DNS compression */ 141978064Sume if (!base) 142078064Sume return NULL; 142178064Sume 142278064Sume comp = base + (i & 0x3f); 142378064Sume if (dnsdecode(&comp, cp, base, cresult, 142478064Sume sizeof(cresult)) == NULL) 142578064Sume return NULL; 142678064Sume if (strlcat(buf, cresult, bufsiz) >= bufsiz) 142778064Sume return NULL; /*result overrun*/ 142878064Sume break; 142978064Sume } else if ((i & 0x3f) == i) { 143078064Sume if (i > ep - cp) 143178064Sume return NULL; /*source overrun*/ 143278064Sume while (i-- > 0 && cp < ep) { 143378064Sume l = snprintf(cresult, sizeof(cresult), 143478064Sume isprint(*cp) ? "%c" : "\\%03o", *cp & 0xff); 1435121472Sume if (l >= sizeof(cresult) || l < 0) 143678064Sume return NULL; 143778064Sume if (strlcat(buf, cresult, bufsiz) >= bufsiz) 143878064Sume return NULL; /*result overrun*/ 143978064Sume cp++; 144078064Sume } 144178064Sume } else 144278064Sume return NULL; /*invalid label*/ 144378064Sume } 144478064Sume if (i != 0) 144578064Sume return NULL; /*not terminated*/ 144678064Sume cp++; 144778064Sume *sp = cp; 144878064Sume return buf; 144978064Sume} 145078064Sume 145155163Sshin/* 145255163Sshin * pr_pack -- 145355163Sshin * Print out the packet, if it came from us. This logic is necessary 145455163Sshin * because ALL readers of the ICMP socket get a copy of ALL ICMP packets 145555163Sshin * which arrive ('tis only fair). This permits multiple copies of this 145655163Sshin * program to be run without having intermingled output (or statistics!). 145755163Sshin */ 145855163Sshinvoid 1459216561Scharnierpr_pack(u_char *buf, int cc, struct msghdr *mhdr) 146055163Sshin{ 146162627Skris#define safeputc(c) printf((isprint((c)) ? "%c" : "\\%03o"), c) 146255163Sshin struct icmp6_hdr *icp; 146378064Sume struct icmp6_nodeinfo *ni; 146455163Sshin int i; 146555163Sshin int hoplim; 146678064Sume struct sockaddr *from; 146778064Sume int fromlen; 146855163Sshin u_char *cp = NULL, *dp, *end = buf + cc; 146962627Skris struct in6_pktinfo *pktinfo = NULL; 1470121472Sume struct timeval tv, tp; 1471121472Sume struct tv32 *tpp; 147255163Sshin double triptime = 0; 147355163Sshin int dupflag; 147455163Sshin size_t off; 147562627Skris int oldfqdn; 147678064Sume u_int16_t seq; 147778064Sume char dnsname[MAXDNAME + 1]; 147855163Sshin 147955163Sshin (void)gettimeofday(&tv, NULL); 148055163Sshin 148178064Sume if (!mhdr || !mhdr->msg_name || 148278064Sume mhdr->msg_namelen != sizeof(struct sockaddr_in6) || 148378064Sume ((struct sockaddr *)mhdr->msg_name)->sa_family != AF_INET6) { 148478064Sume if (options & F_VERBOSE) 1485121472Sume warnx("invalid peername"); 148678064Sume return; 148778064Sume } 148878064Sume from = (struct sockaddr *)mhdr->msg_name; 148978064Sume fromlen = mhdr->msg_namelen; 149055163Sshin if (cc < sizeof(struct icmp6_hdr)) { 149155163Sshin if (options & F_VERBOSE) 149287668Scharnier warnx("packet too short (%d bytes) from %s", cc, 149378064Sume pr_addr(from, fromlen)); 149455163Sshin return; 149555163Sshin } 1496168866Smtm if (((mhdr->msg_flags & MSG_CTRUNC) != 0) && 1497168866Smtm (options & F_VERBOSE) != 0) 1498168866Smtm warnx("some control data discarded, insufficient buffer size"); 149955163Sshin icp = (struct icmp6_hdr *)buf; 150078064Sume ni = (struct icmp6_nodeinfo *)buf; 150155163Sshin off = 0; 150255163Sshin 150355163Sshin if ((hoplim = get_hoplim(mhdr)) == -1) { 150455163Sshin warnx("failed to get receiving hop limit"); 150555163Sshin return; 150655163Sshin } 150762627Skris if ((pktinfo = get_rcvpktinfo(mhdr)) == NULL) { 150887668Scharnier warnx("failed to get receiving packet information"); 150962627Skris return; 151062627Skris } 151155163Sshin 151278064Sume if (icp->icmp6_type == ICMP6_ECHO_REPLY && myechoreply(icp)) { 151378064Sume seq = ntohs(icp->icmp6_seq); 151455163Sshin ++nreceived; 151555163Sshin if (timing) { 1516121472Sume tpp = (struct tv32 *)(icp + 1); 1517121472Sume tp.tv_sec = ntohl(tpp->tv32_sec); 1518121472Sume tp.tv_usec = ntohl(tpp->tv32_usec); 1519121472Sume tvsub(&tv, &tp); 152055163Sshin triptime = ((double)tv.tv_sec) * 1000.0 + 152155163Sshin ((double)tv.tv_usec) / 1000.0; 152255163Sshin tsum += triptime; 152378064Sume tsumsq += triptime * triptime; 152455163Sshin if (triptime < tmin) 152555163Sshin tmin = triptime; 152655163Sshin if (triptime > tmax) 152755163Sshin tmax = triptime; 152855163Sshin } 152955163Sshin 153078064Sume if (TST(seq % mx_dup_ck)) { 153155163Sshin ++nrepeats; 153255163Sshin --nreceived; 153355163Sshin dupflag = 1; 153455163Sshin } else { 153578064Sume SET(seq % mx_dup_ck); 153655163Sshin dupflag = 0; 153755163Sshin } 153855163Sshin 153955163Sshin if (options & F_QUIET) 154055163Sshin return; 154155163Sshin 1542285820Shrs if (options & F_WAITTIME && triptime > waittime) { 1543285820Shrs ++nrcvtimeout; 1544285820Shrs return; 1545285820Shrs } 1546285820Shrs 154755163Sshin if (options & F_FLOOD) 154855163Sshin (void)write(STDOUT_FILENO, &BSPACE, 1); 154955163Sshin else { 1550182195Smatteo if (options & F_AUDIBLE) 1551182195Smatteo (void)write(STDOUT_FILENO, &BBELL, 1); 155255163Sshin (void)printf("%d bytes from %s, icmp_seq=%u", cc, 155378064Sume pr_addr(from, fromlen), seq); 155455163Sshin (void)printf(" hlim=%d", hoplim); 155562627Skris if ((options & F_VERBOSE) != 0) { 155662627Skris struct sockaddr_in6 dstsa; 155762627Skris 155862627Skris memset(&dstsa, 0, sizeof(dstsa)); 155962627Skris dstsa.sin6_family = AF_INET6; 156062627Skris dstsa.sin6_len = sizeof(dstsa); 156162627Skris dstsa.sin6_scope_id = pktinfo->ipi6_ifindex; 156262627Skris dstsa.sin6_addr = pktinfo->ipi6_addr; 156378064Sume (void)printf(" dst=%s", 156478064Sume pr_addr((struct sockaddr *)&dstsa, 156578064Sume sizeof(dstsa))); 156662627Skris } 156755163Sshin if (timing) 1568117824Smaxim (void)printf(" time=%.3f ms", triptime); 156955163Sshin if (dupflag) 157055163Sshin (void)printf("(DUP!)"); 157155163Sshin /* check the data */ 157255163Sshin cp = buf + off + ICMP6ECHOLEN + ICMP6ECHOTMLEN; 157355163Sshin dp = outpack + ICMP6ECHOLEN + ICMP6ECHOTMLEN; 157455163Sshin for (i = 8; cp < end; ++i, ++cp, ++dp) { 157555163Sshin if (*cp != *dp) { 157655163Sshin (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", i, *dp, *cp); 157755163Sshin break; 157855163Sshin } 157955163Sshin } 158055163Sshin } 158178064Sume } else if (icp->icmp6_type == ICMP6_NI_REPLY && mynireply(ni)) { 158278064Sume seq = ntohs(*(u_int16_t *)ni->icmp6_ni_nonce); 158378064Sume ++nreceived; 158478064Sume if (TST(seq % mx_dup_ck)) { 158578064Sume ++nrepeats; 158678064Sume --nreceived; 158778064Sume dupflag = 1; 158878064Sume } else { 158978064Sume SET(seq % mx_dup_ck); 159078064Sume dupflag = 0; 159178064Sume } 159255163Sshin 159378064Sume if (options & F_QUIET) 159478064Sume return; 159555163Sshin 159678064Sume (void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen)); 159778064Sume 159878064Sume switch (ntohs(ni->ni_code)) { 159978064Sume case ICMP6_NI_SUCCESS: 160078064Sume break; 160178064Sume case ICMP6_NI_REFUSED: 160278064Sume printf("refused, type 0x%x", ntohs(ni->ni_type)); 160378064Sume goto fqdnend; 160478064Sume case ICMP6_NI_UNKNOWN: 160578064Sume printf("unknown, type 0x%x", ntohs(ni->ni_type)); 160678064Sume goto fqdnend; 160778064Sume default: 160878064Sume printf("unknown code 0x%x, type 0x%x", 160978064Sume ntohs(ni->ni_code), ntohs(ni->ni_type)); 161078064Sume goto fqdnend; 161178064Sume } 161278064Sume 161378064Sume switch (ntohs(ni->ni_qtype)) { 161478064Sume case NI_QTYPE_NOOP: 161578064Sume printf("NodeInfo NOOP"); 161678064Sume break; 161778064Sume case NI_QTYPE_SUPTYPES: 161878064Sume pr_suptypes(ni, end - (u_char *)ni); 161978064Sume break; 162078064Sume case NI_QTYPE_NODEADDR: 162178064Sume pr_nodeaddr(ni, end - (u_char *)ni); 162278064Sume break; 162378064Sume case NI_QTYPE_FQDN: 162478064Sume default: /* XXX: for backward compatibility */ 162562627Skris cp = (u_char *)ni + ICMP6_NIRLEN; 162662627Skris if (buf[off + ICMP6_NIRLEN] == 162762627Skris cc - off - ICMP6_NIRLEN - 1) 162862627Skris oldfqdn = 1; 162962627Skris else 163062627Skris oldfqdn = 0; 163162627Skris if (oldfqdn) { 163278064Sume cp++; /* skip length */ 163362627Skris while (cp < end) { 163462627Skris safeputc(*cp & 0xff); 163562627Skris cp++; 163662627Skris } 163762627Skris } else { 163878064Sume i = 0; 163962627Skris while (cp < end) { 164078064Sume if (dnsdecode((const u_char **)&cp, end, 164178064Sume (const u_char *)(ni + 1), dnsname, 164278064Sume sizeof(dnsname)) == NULL) { 164378064Sume printf("???"); 164462627Skris break; 164562627Skris } 164678064Sume /* 164778064Sume * name-lookup special handling for 164878064Sume * truncated name 164978064Sume */ 165078064Sume if (cp + 1 <= end && !*cp && 165178064Sume strlen(dnsname) > 0) { 165278064Sume dnsname[strlen(dnsname) - 1] = '\0'; 165378064Sume cp++; 165478064Sume } 165578064Sume printf("%s%s", i > 0 ? "," : "", 165678064Sume dnsname); 165762627Skris } 165862627Skris } 165962627Skris if (options & F_VERBOSE) { 166062627Skris int32_t ttl; 166162627Skris int comma = 0; 166255163Sshin 166362627Skris (void)printf(" ("); /*)*/ 166455163Sshin 166578064Sume switch (ni->ni_code) { 166662627Skris case ICMP6_NI_REFUSED: 166762627Skris (void)printf("refused"); 166862627Skris comma++; 166962627Skris break; 167062627Skris case ICMP6_NI_UNKNOWN: 167187668Scharnier (void)printf("unknown qtype"); 167262627Skris comma++; 167362627Skris break; 167462627Skris } 167555163Sshin 167662627Skris if ((end - (u_char *)ni) < ICMP6_NIRLEN) { 167778064Sume /* case of refusion, unknown */ 167878064Sume /*(*/ 167978064Sume putchar(')'); 168062627Skris goto fqdnend; 168162627Skris } 168262627Skris ttl = (int32_t)ntohl(*(u_long *)&buf[off+ICMP6ECHOLEN+8]); 168362627Skris if (comma) 168462627Skris printf(","); 168578064Sume if (!(ni->ni_flags & NI_FQDN_FLAG_VALIDTTL)) { 168662627Skris (void)printf("TTL=%d:meaningless", 168778064Sume (int)ttl); 168878064Sume } else { 168962627Skris if (ttl < 0) { 169062627Skris (void)printf("TTL=%d:invalid", 169178064Sume ttl); 169262627Skris } else 169362627Skris (void)printf("TTL=%d", ttl); 169462627Skris } 169562627Skris comma++; 169655163Sshin 169762627Skris if (oldfqdn) { 169862627Skris if (comma) 169962627Skris printf(","); 170062627Skris printf("03 draft"); 170162627Skris comma++; 170262627Skris } else { 170362627Skris cp = (u_char *)ni + ICMP6_NIRLEN; 170462627Skris if (cp == end) { 170562627Skris if (comma) 170662627Skris printf(","); 170762627Skris printf("no name"); 170862627Skris comma++; 170962627Skris } 171062627Skris } 171162627Skris 171262627Skris if (buf[off + ICMP6_NIRLEN] != 171362627Skris cc - off - ICMP6_NIRLEN - 1 && oldfqdn) { 171462627Skris if (comma) 171562627Skris printf(","); 171662627Skris (void)printf("invalid namelen:%d/%lu", 171778064Sume buf[off + ICMP6_NIRLEN], 171878064Sume (u_long)cc - off - ICMP6_NIRLEN - 1); 171962627Skris comma++; 172062627Skris } 172162627Skris /*(*/ 172262627Skris putchar(')'); 172362627Skris } 172478064Sume fqdnend: 172562627Skris ; 172655163Sshin } 172755163Sshin } else { 172855163Sshin /* We've got something other than an ECHOREPLY */ 172955163Sshin if (!(options & F_VERBOSE)) 173055163Sshin return; 173178064Sume (void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen)); 173255163Sshin pr_icmph(icp, end); 173355163Sshin } 173455163Sshin 173555163Sshin if (!(options & F_FLOOD)) { 173655163Sshin (void)putchar('\n'); 173762627Skris if (options & F_VERBOSE) 173862627Skris pr_exthdrs(mhdr); 173955163Sshin (void)fflush(stdout); 174055163Sshin } 174162627Skris#undef safeputc 174255163Sshin} 174355163Sshin 174455163Sshinvoid 1745216561Scharnierpr_exthdrs(struct msghdr *mhdr) 174662627Skris{ 1747168866Smtm ssize_t bufsize; 1748168866Smtm void *bufp; 174962627Skris struct cmsghdr *cm; 175062627Skris 1751168866Smtm bufsize = 0; 1752168866Smtm bufp = mhdr->msg_control; 175362627Skris for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; 175462627Skris cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { 175562627Skris if (cm->cmsg_level != IPPROTO_IPV6) 175662627Skris continue; 175762627Skris 1758168866Smtm bufsize = CONTROLLEN - ((caddr_t)CMSG_DATA(cm) - (caddr_t)bufp); 1759168866Smtm if (bufsize <= 0) 1760168866Smtm continue; 176178064Sume switch (cm->cmsg_type) { 176262627Skris case IPV6_HOPOPTS: 176362627Skris printf(" HbH Options: "); 1764168866Smtm pr_ip6opt(CMSG_DATA(cm), (size_t)bufsize); 176562627Skris break; 176662627Skris case IPV6_DSTOPTS: 176762627Skris#ifdef IPV6_RTHDRDSTOPTS 176862627Skris case IPV6_RTHDRDSTOPTS: 176962627Skris#endif 177062627Skris printf(" Dst Options: "); 1771168866Smtm pr_ip6opt(CMSG_DATA(cm), (size_t)bufsize); 177262627Skris break; 177362627Skris case IPV6_RTHDR: 177462627Skris printf(" Routing: "); 1775168866Smtm pr_rthdr(CMSG_DATA(cm), (size_t)bufsize); 177662627Skris break; 177762627Skris } 177862627Skris } 177962627Skris} 178062627Skris 178162627Skris#ifdef USE_RFC2292BIS 178262627Skrisvoid 1783168866Smtmpr_ip6opt(void *extbuf, size_t bufsize) 178462627Skris{ 178562627Skris struct ip6_hbh *ext; 178662627Skris int currentlen; 178762627Skris u_int8_t type; 1788229912Seadler socklen_t extlen, len; 178962627Skris void *databuf; 179062627Skris size_t offset; 179162627Skris u_int16_t value2; 179262627Skris u_int32_t value4; 179362627Skris 179462627Skris ext = (struct ip6_hbh *)extbuf; 179562627Skris extlen = (ext->ip6h_len + 1) * 8; 179678064Sume printf("nxt %u, len %u (%lu bytes)\n", ext->ip6h_nxt, 179778064Sume (unsigned int)ext->ip6h_len, (unsigned long)extlen); 179862627Skris 1799168866Smtm /* 1800168866Smtm * Bounds checking on the ancillary data buffer: 1801168866Smtm * subtract the size of a cmsg structure from the buffer size. 1802168866Smtm */ 1803168866Smtm if (bufsize < (extlen + CMSG_SPACE(0))) { 1804168866Smtm extlen = bufsize - CMSG_SPACE(0); 1805168866Smtm warnx("options truncated, showing only %u (total=%u)", 1806168866Smtm (unsigned int)(extlen / 8 - 1), 1807168866Smtm (unsigned int)(ext->ip6h_len)); 1808168866Smtm } 1809168866Smtm 181062627Skris currentlen = 0; 181162627Skris while (1) { 181262627Skris currentlen = inet6_opt_next(extbuf, extlen, currentlen, 181378064Sume &type, &len, &databuf); 181462627Skris if (currentlen == -1) 181562627Skris break; 181662627Skris switch (type) { 181762627Skris /* 181862627Skris * Note that inet6_opt_next automatically skips any padding 181962627Skris * optins. 182062627Skris */ 182162627Skris case IP6OPT_JUMBO: 182262627Skris offset = 0; 182362627Skris offset = inet6_opt_get_val(databuf, offset, 182478064Sume &value4, sizeof(value4)); 182562627Skris printf(" Jumbo Payload Opt: Length %u\n", 182678064Sume (u_int32_t)ntohl(value4)); 182762627Skris break; 182862627Skris case IP6OPT_ROUTER_ALERT: 182962627Skris offset = 0; 183062627Skris offset = inet6_opt_get_val(databuf, offset, 183162627Skris &value2, sizeof(value2)); 183262627Skris printf(" Router Alert Opt: Type %u\n", 183378064Sume ntohs(value2)); 183462627Skris break; 183562627Skris default: 183678064Sume printf(" Received Opt %u len %lu\n", 183778064Sume type, (unsigned long)len); 183862627Skris break; 183962627Skris } 184062627Skris } 184162627Skris return; 184262627Skris} 184362627Skris#else /* !USE_RFC2292BIS */ 184462627Skris/* ARGSUSED */ 184562627Skrisvoid 1846168866Smtmpr_ip6opt(void *extbuf, size_t bufsize __unused) 184762627Skris{ 184862627Skris putchar('\n'); 184962627Skris return; 185062627Skris} 185162627Skris#endif /* USE_RFC2292BIS */ 185262627Skris 185362627Skris#ifdef USE_RFC2292BIS 185462627Skrisvoid 1855168866Smtmpr_rthdr(void *extbuf, size_t bufsize) 185662627Skris{ 185762627Skris struct in6_addr *in6; 185862627Skris char ntopbuf[INET6_ADDRSTRLEN]; 185962627Skris struct ip6_rthdr *rh = (struct ip6_rthdr *)extbuf; 1860168866Smtm int i, segments, origsegs, rthsize, size0, size1; 186162627Skris 186262627Skris /* print fixed part of the header */ 186362627Skris printf("nxt %u, len %u (%d bytes), type %u, ", rh->ip6r_nxt, 186478064Sume rh->ip6r_len, (rh->ip6r_len + 1) << 3, rh->ip6r_type); 1865168866Smtm if ((segments = inet6_rth_segments(extbuf)) >= 0) { 186662627Skris printf("%d segments, ", segments); 1867168866Smtm printf("%d left\n", rh->ip6r_segleft); 1868168866Smtm } else { 186962627Skris printf("segments unknown, "); 1870168866Smtm printf("%d left\n", rh->ip6r_segleft); 1871168866Smtm return; 1872168866Smtm } 187362627Skris 1874168866Smtm /* 1875168866Smtm * Bounds checking on the ancillary data buffer. When calculating 1876168866Smtm * the number of items to show keep in mind: 1877168866Smtm * - The size of the cmsg structure 1878168866Smtm * - The size of one segment (the size of a Type 0 routing header) 1879168866Smtm * - When dividing add a fudge factor of one in case the 1880168866Smtm * dividend is not evenly divisible by the divisor 1881168866Smtm */ 1882168866Smtm rthsize = (rh->ip6r_len + 1) * 8; 1883168866Smtm if (bufsize < (rthsize + CMSG_SPACE(0))) { 1884168866Smtm origsegs = segments; 1885168866Smtm size0 = inet6_rth_space(IPV6_RTHDR_TYPE_0, 0); 1886168866Smtm size1 = inet6_rth_space(IPV6_RTHDR_TYPE_0, 1); 1887168866Smtm segments -= (rthsize - (bufsize - CMSG_SPACE(0))) / 1888168866Smtm (size1 - size0) + 1; 1889168866Smtm warnx("segments truncated, showing only %d (total=%d)", 1890168866Smtm segments, origsegs); 1891168866Smtm } 1892168866Smtm 189362627Skris for (i = 0; i < segments; i++) { 189462627Skris in6 = inet6_rth_getaddr(extbuf, i); 189562627Skris if (in6 == NULL) 189662627Skris printf(" [%d]<NULL>\n", i); 189778064Sume else { 189878064Sume if (!inet_ntop(AF_INET6, in6, ntopbuf, 189978064Sume sizeof(ntopbuf))) 1900121472Sume strlcpy(ntopbuf, "?", sizeof(ntopbuf)); 190178064Sume printf(" [%d]%s\n", i, ntopbuf); 190278064Sume } 190362627Skris } 190462627Skris 190562627Skris return; 190678064Sume 190762627Skris} 190878064Sume 190962627Skris#else /* !USE_RFC2292BIS */ 191062627Skris/* ARGSUSED */ 191162627Skrisvoid 1912168866Smtmpr_rthdr(void *extbuf, size_t bufsize __unused) 191362627Skris{ 191462627Skris putchar('\n'); 191562627Skris return; 191662627Skris} 191762627Skris#endif /* USE_RFC2292BIS */ 191862627Skris 191978064Sumeint 1920216561Scharnierpr_bitrange(u_int32_t v, int soff, int ii) 192178064Sume{ 192278064Sume int off; 192378064Sume int i; 192462627Skris 192578064Sume off = 0; 192678064Sume while (off < 32) { 192778064Sume /* shift till we have 0x01 */ 192878064Sume if ((v & 0x01) == 0) { 192978064Sume if (ii > 1) 1930121472Sume printf("-%u", soff + off - 1); 193178064Sume ii = 0; 193278064Sume switch (v & 0x0f) { 193378064Sume case 0x00: 193478064Sume v >>= 4; 193578064Sume off += 4; 193678064Sume continue; 193778064Sume case 0x08: 193878064Sume v >>= 3; 193978064Sume off += 3; 194078064Sume continue; 194178064Sume case 0x04: case 0x0c: 194278064Sume v >>= 2; 194378064Sume off += 2; 194478064Sume continue; 194578064Sume default: 194678064Sume v >>= 1; 194778064Sume off += 1; 194878064Sume continue; 194978064Sume } 195078064Sume } 195178064Sume 195278064Sume /* we have 0x01 with us */ 195378064Sume for (i = 0; i < 32 - off; i++) { 195478064Sume if ((v & (0x01 << i)) == 0) 195578064Sume break; 195678064Sume } 195778064Sume if (!ii) 1958121472Sume printf(" %u", soff + off); 195978064Sume ii += i; 196078064Sume v >>= i; off += i; 196178064Sume } 196278064Sume return ii; 196378064Sume} 196478064Sume 196562627Skrisvoid 1966216561Scharnierpr_suptypes(struct icmp6_nodeinfo *ni, size_t nilen) 1967216561Scharnier /* ni->qtype must be SUPTYPES */ 196878064Sume{ 196978064Sume size_t clen; 197078064Sume u_int32_t v; 197178064Sume const u_char *cp, *end; 197278064Sume u_int16_t cur; 197378064Sume struct cbit { 197478064Sume u_int16_t words; /*32bit count*/ 197578064Sume u_int16_t skip; 197678064Sume } cbit; 197778064Sume#define MAXQTYPES (1 << 16) 197878064Sume size_t off; 197978064Sume int b; 198078064Sume 198178064Sume cp = (u_char *)(ni + 1); 198278064Sume end = ((u_char *)ni) + nilen; 198378064Sume cur = 0; 198478064Sume b = 0; 198578064Sume 198678064Sume printf("NodeInfo Supported Qtypes"); 198778064Sume if (options & F_VERBOSE) { 198878064Sume if (ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) 198978064Sume printf(", compressed bitmap"); 199078064Sume else 199178064Sume printf(", raw bitmap"); 199278064Sume } 199378064Sume 199478064Sume while (cp < end) { 199578064Sume clen = (size_t)(end - cp); 199678064Sume if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) == 0) { 199778064Sume if (clen == 0 || clen > MAXQTYPES / 8 || 199878064Sume clen % sizeof(v)) { 199978064Sume printf("???"); 200078064Sume return; 200178064Sume } 200278064Sume } else { 200378064Sume if (clen < sizeof(cbit) || clen % sizeof(v)) 200478064Sume return; 200578064Sume memcpy(&cbit, cp, sizeof(cbit)); 200678064Sume if (sizeof(cbit) + ntohs(cbit.words) * sizeof(v) > 200778064Sume clen) 200878064Sume return; 200978064Sume cp += sizeof(cbit); 201078064Sume clen = ntohs(cbit.words) * sizeof(v); 201178064Sume if (cur + clen * 8 + (u_long)ntohs(cbit.skip) * 32 > 201278064Sume MAXQTYPES) 201378064Sume return; 201478064Sume } 201578064Sume 201678064Sume for (off = 0; off < clen; off += sizeof(v)) { 201778064Sume memcpy(&v, cp + off, sizeof(v)); 201878064Sume v = (u_int32_t)ntohl(v); 201978064Sume b = pr_bitrange(v, (int)(cur + off * 8), b); 202078064Sume } 202178064Sume /* flush the remaining bits */ 202278064Sume b = pr_bitrange(0, (int)(cur + off * 8), b); 202378064Sume 202478064Sume cp += clen; 202578064Sume cur += clen * 8; 202678064Sume if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) != 0) 202778064Sume cur += ntohs(cbit.skip) * 32; 202878064Sume } 202978064Sume} 203078064Sume 203178064Sumevoid 2032216561Scharnierpr_nodeaddr(struct icmp6_nodeinfo *ni, int nilen) 2033216561Scharnier /* ni->qtype must be NODEADDR */ 203455163Sshin{ 203578064Sume u_char *cp = (u_char *)(ni + 1); 203662627Skris char ntop_buf[INET6_ADDRSTRLEN]; 203778064Sume int withttl = 0; 203855163Sshin 203955163Sshin nilen -= sizeof(struct icmp6_nodeinfo); 204055163Sshin 204155163Sshin if (options & F_VERBOSE) { 204278064Sume switch (ni->ni_code) { 204378064Sume case ICMP6_NI_REFUSED: 204478064Sume (void)printf("refused"); 204578064Sume break; 204678064Sume case ICMP6_NI_UNKNOWN: 204778064Sume (void)printf("unknown qtype"); 204878064Sume break; 204955163Sshin } 205078064Sume if (ni->ni_flags & NI_NODEADDR_FLAG_TRUNCATE) 205155163Sshin (void)printf(" truncated"); 205255163Sshin } 205355163Sshin putchar('\n'); 205455163Sshin if (nilen <= 0) 205555163Sshin printf(" no address\n"); 205678064Sume 205778064Sume /* 205878064Sume * In icmp-name-lookups 05 and later, TTL of each returned address 205978064Sume * is contained in the resposne. We try to detect the version 206078064Sume * by the length of the data, but note that the detection algorithm 206178064Sume * is incomplete. We assume the latest draft by default. 206278064Sume */ 206378064Sume if (nilen % (sizeof(u_int32_t) + sizeof(struct in6_addr)) == 0) 206478064Sume withttl = 1; 206578064Sume while (nilen > 0) { 206678064Sume u_int32_t ttl; 206778064Sume 206878064Sume if (withttl) { 206978064Sume /* XXX: alignment? */ 207078064Sume ttl = (u_int32_t)ntohl(*(u_int32_t *)cp); 207178064Sume cp += sizeof(u_int32_t); 207278064Sume nilen -= sizeof(u_int32_t); 207378064Sume } 207478064Sume 207578064Sume if (inet_ntop(AF_INET6, cp, ntop_buf, sizeof(ntop_buf)) == 207678064Sume NULL) 2077121472Sume strlcpy(ntop_buf, "?", sizeof(ntop_buf)); 207878064Sume printf(" %s", ntop_buf); 207978064Sume if (withttl) { 208078064Sume if (ttl == 0xffffffff) { 208178064Sume /* 208278064Sume * XXX: can this convention be applied to all 208378064Sume * type of TTL (i.e. non-ND TTL)? 208478064Sume */ 208578064Sume printf("(TTL=infty)"); 208678064Sume } 208778064Sume else 208878064Sume printf("(TTL=%u)", ttl); 208978064Sume } 209078064Sume putchar('\n'); 209178064Sume 209278064Sume nilen -= sizeof(struct in6_addr); 209378064Sume cp += sizeof(struct in6_addr); 209455163Sshin } 209555163Sshin} 209655163Sshin 209755163Sshinint 2098216561Scharnierget_hoplim(struct msghdr *mhdr) 209955163Sshin{ 210055163Sshin struct cmsghdr *cm; 210155163Sshin 210255163Sshin for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; 210355163Sshin cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { 210478064Sume if (cm->cmsg_len == 0) 210578064Sume return(-1); 210678064Sume 210755163Sshin if (cm->cmsg_level == IPPROTO_IPV6 && 210855163Sshin cm->cmsg_type == IPV6_HOPLIMIT && 210955163Sshin cm->cmsg_len == CMSG_LEN(sizeof(int))) 211055163Sshin return(*(int *)CMSG_DATA(cm)); 211155163Sshin } 211255163Sshin 211355163Sshin return(-1); 211455163Sshin} 211555163Sshin 211662627Skrisstruct in6_pktinfo * 2117216561Scharnierget_rcvpktinfo(struct msghdr *mhdr) 211862627Skris{ 211962627Skris struct cmsghdr *cm; 212062627Skris 212162627Skris for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; 212262627Skris cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { 212378064Sume if (cm->cmsg_len == 0) 212478064Sume return(NULL); 212578064Sume 212662627Skris if (cm->cmsg_level == IPPROTO_IPV6 && 212762627Skris cm->cmsg_type == IPV6_PKTINFO && 212862627Skris cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) 212962627Skris return((struct in6_pktinfo *)CMSG_DATA(cm)); 213062627Skris } 213162627Skris 213262627Skris return(NULL); 213362627Skris} 213462627Skris 213578064Sumeint 2136216561Scharnierget_pathmtu(struct msghdr *mhdr) 213778064Sume{ 213878064Sume#ifdef IPV6_RECVPATHMTU 213978064Sume struct cmsghdr *cm; 214078064Sume struct ip6_mtuinfo *mtuctl = NULL; 214178064Sume 214278064Sume for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; 214378064Sume cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { 214478064Sume if (cm->cmsg_len == 0) 214578064Sume return(0); 214678064Sume 214778064Sume if (cm->cmsg_level == IPPROTO_IPV6 && 214878064Sume cm->cmsg_type == IPV6_PATHMTU && 214978064Sume cm->cmsg_len == CMSG_LEN(sizeof(struct ip6_mtuinfo))) { 215078064Sume mtuctl = (struct ip6_mtuinfo *)CMSG_DATA(cm); 215178064Sume 215278064Sume /* 215378064Sume * If the notified destination is different from 215478064Sume * the one we are pinging, just ignore the info. 215578064Sume * We check the scope ID only when both notified value 215678064Sume * and our own value have non-0 values, because we may 215778064Sume * have used the default scope zone ID for sending, 215878064Sume * in which case the scope ID value is 0. 215978064Sume */ 216078064Sume if (!IN6_ARE_ADDR_EQUAL(&mtuctl->ip6m_addr.sin6_addr, 216178064Sume &dst.sin6_addr) || 216278064Sume (mtuctl->ip6m_addr.sin6_scope_id && 216378064Sume dst.sin6_scope_id && 216478064Sume mtuctl->ip6m_addr.sin6_scope_id != 216578064Sume dst.sin6_scope_id)) { 216678064Sume if ((options & F_VERBOSE) != 0) { 216778064Sume printf("path MTU for %s is notified. " 216878064Sume "(ignored)\n", 216978064Sume pr_addr((struct sockaddr *)&mtuctl->ip6m_addr, 217078064Sume sizeof(mtuctl->ip6m_addr))); 217178064Sume } 217278064Sume return(0); 217378064Sume } 217478064Sume 217578064Sume /* 217678064Sume * Ignore an invalid MTU. XXX: can we just believe 217778064Sume * the kernel check? 217878064Sume */ 217978064Sume if (mtuctl->ip6m_mtu < IPV6_MMTU) 218078064Sume return(0); 218178064Sume 218278064Sume /* notification for our destination. return the MTU. */ 218378064Sume return((int)mtuctl->ip6m_mtu); 218478064Sume } 218578064Sume } 218678064Sume#endif 218778064Sume return(0); 218878064Sume} 218978064Sume 219055163Sshin/* 219155163Sshin * tvsub -- 219255163Sshin * Subtract 2 timeval structs: out = out - in. Out is assumed to 219355163Sshin * be >= in. 219455163Sshin */ 219555163Sshinvoid 2196216561Scharniertvsub(struct timeval *out, struct timeval *in) 219755163Sshin{ 219855163Sshin if ((out->tv_usec -= in->tv_usec) < 0) { 219955163Sshin --out->tv_sec; 220055163Sshin out->tv_usec += 1000000; 220155163Sshin } 220255163Sshin out->tv_sec -= in->tv_sec; 220355163Sshin} 220455163Sshin 220555163Sshin/* 220655163Sshin * onint -- 220755163Sshin * SIGINT handler. 220855163Sshin */ 220962627Skris/* ARGSUSED */ 221055163Sshinvoid 2211216561Scharnieronint(int notused __unused) 221255163Sshin{ 2213285820Shrs /* 2214285820Shrs * When doing reverse DNS lookups, the seenint flag might not 2215285820Shrs * be noticed for a while. Just exit if we get a second SIGINT. 2216285820Shrs */ 2217285820Shrs if ((options & F_HOSTNAME) && seenint != 0) 2218285820Shrs _exit(nreceived ? 0 : 2); 221955163Sshin} 222055163Sshin 222155163Sshin/* 222255163Sshin * summary -- 222355163Sshin * Print out statistics. 222455163Sshin */ 222555163Sshinvoid 2226216561Scharniersummary(void) 222755163Sshin{ 222855163Sshin 222955163Sshin (void)printf("\n--- %s ping6 statistics ---\n", hostname); 223055163Sshin (void)printf("%ld packets transmitted, ", ntransmitted); 223155163Sshin (void)printf("%ld packets received, ", nreceived); 223255163Sshin if (nrepeats) 223355163Sshin (void)printf("+%ld duplicates, ", nrepeats); 223455163Sshin if (ntransmitted) { 223555163Sshin if (nreceived > ntransmitted) 2236121472Sume (void)printf("-- somebody's duplicating packets!"); 223755163Sshin else 2238121472Sume (void)printf("%.1f%% packet loss", 2239121472Sume ((((double)ntransmitted - nreceived) * 100.0) / 224055163Sshin ntransmitted)); 224155163Sshin } 2242285820Shrs if (nrcvtimeout) 2243285820Shrs printf(", %ld packets out of wait time", nrcvtimeout); 224455163Sshin (void)putchar('\n'); 224555163Sshin if (nreceived && timing) { 224655163Sshin /* Only display average to microseconds */ 224778064Sume double num = nreceived + nrepeats; 224878064Sume double avg = tsum / num; 224978064Sume double dev = sqrt(tsumsq / num - avg * avg); 225078064Sume (void)printf( 225178064Sume "round-trip min/avg/max/std-dev = %.3f/%.3f/%.3f/%.3f ms\n", 225278064Sume tmin, avg, tmax, dev); 225355163Sshin (void)fflush(stdout); 225455163Sshin } 225578064Sume (void)fflush(stdout); 225655163Sshin} 225755163Sshin 225878064Sume/*subject type*/ 2259121472Sumestatic const char *niqcode[] = { 226078064Sume "IPv6 address", 226178064Sume "DNS label", /*or empty*/ 226278064Sume "IPv4 address", 226355163Sshin}; 226455163Sshin 226578064Sume/*result code*/ 2266121472Sumestatic const char *nircode[] = { 226778064Sume "Success", "Refused", "Unknown", 226878064Sume}; 226978064Sume 227078064Sume 227155163Sshin/* 227255163Sshin * pr_icmph -- 227355163Sshin * Print a descriptive string about an ICMP header. 227455163Sshin */ 227555163Sshinvoid 2276216561Scharnierpr_icmph(struct icmp6_hdr *icp, u_char *end) 227755163Sshin{ 227862627Skris char ntop_buf[INET6_ADDRSTRLEN]; 227978064Sume struct nd_redirect *red; 228078064Sume struct icmp6_nodeinfo *ni; 228178064Sume char dnsname[MAXDNAME + 1]; 228278064Sume const u_char *cp; 228378064Sume size_t l; 228462627Skris 228578064Sume switch (icp->icmp6_type) { 228655163Sshin case ICMP6_DST_UNREACH: 228778064Sume switch (icp->icmp6_code) { 228855163Sshin case ICMP6_DST_UNREACH_NOROUTE: 228955163Sshin (void)printf("No Route to Destination\n"); 229055163Sshin break; 229155163Sshin case ICMP6_DST_UNREACH_ADMIN: 229255163Sshin (void)printf("Destination Administratively " 229378064Sume "Unreachable\n"); 229455163Sshin break; 229555163Sshin case ICMP6_DST_UNREACH_BEYONDSCOPE: 229655163Sshin (void)printf("Destination Unreachable Beyond Scope\n"); 229755163Sshin break; 229855163Sshin case ICMP6_DST_UNREACH_ADDR: 229955163Sshin (void)printf("Destination Host Unreachable\n"); 230055163Sshin break; 230155163Sshin case ICMP6_DST_UNREACH_NOPORT: 230255163Sshin (void)printf("Destination Port Unreachable\n"); 230355163Sshin break; 230455163Sshin default: 230555163Sshin (void)printf("Destination Unreachable, Bad Code: %d\n", 230655163Sshin icp->icmp6_code); 230755163Sshin break; 230855163Sshin } 230955163Sshin /* Print returned IP header information */ 231055163Sshin pr_retip((struct ip6_hdr *)(icp + 1), end); 231155163Sshin break; 231255163Sshin case ICMP6_PACKET_TOO_BIG: 231355163Sshin (void)printf("Packet too big mtu = %d\n", 231478064Sume (int)ntohl(icp->icmp6_mtu)); 231562627Skris pr_retip((struct ip6_hdr *)(icp + 1), end); 231655163Sshin break; 231755163Sshin case ICMP6_TIME_EXCEEDED: 231878064Sume switch (icp->icmp6_code) { 231955163Sshin case ICMP6_TIME_EXCEED_TRANSIT: 232055163Sshin (void)printf("Time to live exceeded\n"); 232155163Sshin break; 232255163Sshin case ICMP6_TIME_EXCEED_REASSEMBLY: 232355163Sshin (void)printf("Frag reassembly time exceeded\n"); 232455163Sshin break; 232555163Sshin default: 232655163Sshin (void)printf("Time exceeded, Bad Code: %d\n", 232755163Sshin icp->icmp6_code); 232855163Sshin break; 232955163Sshin } 233055163Sshin pr_retip((struct ip6_hdr *)(icp + 1), end); 233155163Sshin break; 233255163Sshin case ICMP6_PARAM_PROB: 233355163Sshin (void)printf("Parameter problem: "); 233478064Sume switch (icp->icmp6_code) { 233578064Sume case ICMP6_PARAMPROB_HEADER: 233678064Sume (void)printf("Erroneous Header "); 233778064Sume break; 233878064Sume case ICMP6_PARAMPROB_NEXTHEADER: 233978064Sume (void)printf("Unknown Nextheader "); 234078064Sume break; 234178064Sume case ICMP6_PARAMPROB_OPTION: 234278064Sume (void)printf("Unrecognized Option "); 234378064Sume break; 234478064Sume default: 234578064Sume (void)printf("Bad code(%d) ", icp->icmp6_code); 234678064Sume break; 234755163Sshin } 234855163Sshin (void)printf("pointer = 0x%02x\n", 234978064Sume (u_int32_t)ntohl(icp->icmp6_pptr)); 235055163Sshin pr_retip((struct ip6_hdr *)(icp + 1), end); 235155163Sshin break; 235255163Sshin case ICMP6_ECHO_REQUEST: 235362627Skris (void)printf("Echo Request"); 235455163Sshin /* XXX ID + Seq + Data */ 235555163Sshin break; 235655163Sshin case ICMP6_ECHO_REPLY: 235762627Skris (void)printf("Echo Reply"); 235855163Sshin /* XXX ID + Seq + Data */ 235955163Sshin break; 236055163Sshin case ICMP6_MEMBERSHIP_QUERY: 236162627Skris (void)printf("Listener Query"); 236255163Sshin break; 236355163Sshin case ICMP6_MEMBERSHIP_REPORT: 236462627Skris (void)printf("Listener Report"); 236555163Sshin break; 236655163Sshin case ICMP6_MEMBERSHIP_REDUCTION: 236762627Skris (void)printf("Listener Done"); 236855163Sshin break; 236955163Sshin case ND_ROUTER_SOLICIT: 237062627Skris (void)printf("Router Solicitation"); 237155163Sshin break; 237255163Sshin case ND_ROUTER_ADVERT: 237362627Skris (void)printf("Router Advertisement"); 237455163Sshin break; 237555163Sshin case ND_NEIGHBOR_SOLICIT: 237662627Skris (void)printf("Neighbor Solicitation"); 237755163Sshin break; 237855163Sshin case ND_NEIGHBOR_ADVERT: 237962627Skris (void)printf("Neighbor Advertisement"); 238055163Sshin break; 238155163Sshin case ND_REDIRECT: 238278064Sume red = (struct nd_redirect *)icp; 238355163Sshin (void)printf("Redirect\n"); 238478064Sume if (!inet_ntop(AF_INET6, &red->nd_rd_dst, ntop_buf, 238578064Sume sizeof(ntop_buf))) 2386121472Sume strlcpy(ntop_buf, "?", sizeof(ntop_buf)); 238778064Sume (void)printf("Destination: %s", ntop_buf); 238878064Sume if (!inet_ntop(AF_INET6, &red->nd_rd_target, ntop_buf, 238978064Sume sizeof(ntop_buf))) 2390121472Sume strlcpy(ntop_buf, "?", sizeof(ntop_buf)); 239178064Sume (void)printf(" New Target: %s", ntop_buf); 239255163Sshin break; 239355163Sshin case ICMP6_NI_QUERY: 239462627Skris (void)printf("Node Information Query"); 239555163Sshin /* XXX ID + Seq + Data */ 239678064Sume ni = (struct icmp6_nodeinfo *)icp; 239778064Sume l = end - (u_char *)(ni + 1); 239878064Sume printf(", "); 239978064Sume switch (ntohs(ni->ni_qtype)) { 240078064Sume case NI_QTYPE_NOOP: 240178064Sume (void)printf("NOOP"); 240278064Sume break; 240378064Sume case NI_QTYPE_SUPTYPES: 240478064Sume (void)printf("Supported qtypes"); 240578064Sume break; 240678064Sume case NI_QTYPE_FQDN: 240778064Sume (void)printf("DNS name"); 240878064Sume break; 240978064Sume case NI_QTYPE_NODEADDR: 241078064Sume (void)printf("nodeaddr"); 241178064Sume break; 241278064Sume case NI_QTYPE_IPV4ADDR: 241378064Sume (void)printf("IPv4 nodeaddr"); 241478064Sume break; 241578064Sume default: 241678064Sume (void)printf("unknown qtype"); 241778064Sume break; 241878064Sume } 241978064Sume if (options & F_VERBOSE) { 242078064Sume switch (ni->ni_code) { 242178064Sume case ICMP6_NI_SUBJ_IPV6: 242278064Sume if (l == sizeof(struct in6_addr) && 242378064Sume inet_ntop(AF_INET6, ni + 1, ntop_buf, 242478064Sume sizeof(ntop_buf)) != NULL) { 242578064Sume (void)printf(", subject=%s(%s)", 242678064Sume niqcode[ni->ni_code], ntop_buf); 242778064Sume } else { 242878064Sume#if 1 242978064Sume /* backward compat to -W */ 243078064Sume (void)printf(", oldfqdn"); 243178064Sume#else 243278064Sume (void)printf(", invalid"); 243378064Sume#endif 243478064Sume } 243578064Sume break; 243678064Sume case ICMP6_NI_SUBJ_FQDN: 243778064Sume if (end == (u_char *)(ni + 1)) { 243878064Sume (void)printf(", no subject"); 243978064Sume break; 244078064Sume } 244178064Sume printf(", subject=%s", niqcode[ni->ni_code]); 244278064Sume cp = (const u_char *)(ni + 1); 244378064Sume if (dnsdecode(&cp, end, NULL, dnsname, 244478064Sume sizeof(dnsname)) != NULL) 244578064Sume printf("(%s)", dnsname); 244678064Sume else 244778064Sume printf("(invalid)"); 244878064Sume break; 244978064Sume case ICMP6_NI_SUBJ_IPV4: 245078064Sume if (l == sizeof(struct in_addr) && 245178064Sume inet_ntop(AF_INET, ni + 1, ntop_buf, 245278064Sume sizeof(ntop_buf)) != NULL) { 245378064Sume (void)printf(", subject=%s(%s)", 245478064Sume niqcode[ni->ni_code], ntop_buf); 245578064Sume } else 245678064Sume (void)printf(", invalid"); 245778064Sume break; 245878064Sume default: 245978064Sume (void)printf(", invalid"); 246078064Sume break; 246178064Sume } 246278064Sume } 246355163Sshin break; 246455163Sshin case ICMP6_NI_REPLY: 246562627Skris (void)printf("Node Information Reply"); 246655163Sshin /* XXX ID + Seq + Data */ 246778064Sume ni = (struct icmp6_nodeinfo *)icp; 246878064Sume printf(", "); 246978064Sume switch (ntohs(ni->ni_qtype)) { 247078064Sume case NI_QTYPE_NOOP: 247178064Sume (void)printf("NOOP"); 247278064Sume break; 247378064Sume case NI_QTYPE_SUPTYPES: 247478064Sume (void)printf("Supported qtypes"); 247578064Sume break; 247678064Sume case NI_QTYPE_FQDN: 247778064Sume (void)printf("DNS name"); 247878064Sume break; 247978064Sume case NI_QTYPE_NODEADDR: 248078064Sume (void)printf("nodeaddr"); 248178064Sume break; 248278064Sume case NI_QTYPE_IPV4ADDR: 248378064Sume (void)printf("IPv4 nodeaddr"); 248478064Sume break; 248578064Sume default: 248678064Sume (void)printf("unknown qtype"); 248778064Sume break; 248878064Sume } 248978064Sume if (options & F_VERBOSE) { 249078064Sume if (ni->ni_code > sizeof(nircode) / sizeof(nircode[0])) 249178064Sume printf(", invalid"); 249278064Sume else 249378064Sume printf(", %s", nircode[ni->ni_code]); 249478064Sume } 249555163Sshin break; 249655163Sshin default: 249762627Skris (void)printf("Bad ICMP type: %d", icp->icmp6_type); 249855163Sshin } 249955163Sshin} 250055163Sshin 250155163Sshin/* 250255163Sshin * pr_iph -- 250355163Sshin * Print an IP6 header. 250455163Sshin */ 250555163Sshinvoid 2506216561Scharnierpr_iph(struct ip6_hdr *ip6) 250755163Sshin{ 250855163Sshin u_int32_t flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; 250955163Sshin u_int8_t tc; 251062627Skris char ntop_buf[INET6_ADDRSTRLEN]; 251155163Sshin 251255163Sshin tc = *(&ip6->ip6_vfc + 1); /* XXX */ 251355163Sshin tc = (tc >> 4) & 0x0f; 251455163Sshin tc |= (ip6->ip6_vfc << 4); 251555163Sshin 251655163Sshin printf("Vr TC Flow Plen Nxt Hlim\n"); 251755163Sshin printf(" %1x %02x %05x %04x %02x %02x\n", 251878064Sume (ip6->ip6_vfc & IPV6_VERSION_MASK) >> 4, tc, (u_int32_t)ntohl(flow), 251978064Sume ntohs(ip6->ip6_plen), ip6->ip6_nxt, ip6->ip6_hlim); 252078064Sume if (!inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf, sizeof(ntop_buf))) 2521121472Sume strlcpy(ntop_buf, "?", sizeof(ntop_buf)); 252278064Sume printf("%s->", ntop_buf); 252378064Sume if (!inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf, sizeof(ntop_buf))) 2524121472Sume strlcpy(ntop_buf, "?", sizeof(ntop_buf)); 252578064Sume printf("%s\n", ntop_buf); 252655163Sshin} 252755163Sshin 252855163Sshin/* 252955163Sshin * pr_addr -- 253055163Sshin * Return an ascii host address as a dotted quad and optionally with 253155163Sshin * a hostname. 253255163Sshin */ 253362627Skrisconst char * 2534216561Scharnierpr_addr(struct sockaddr *addr, int addrlen) 253555163Sshin{ 253678064Sume static char buf[NI_MAXHOST]; 2537121316Sume int flag = 0; 253855163Sshin 253962627Skris if ((options & F_HOSTNAME) == 0) 254055163Sshin flag |= NI_NUMERICHOST; 254155163Sshin 254278064Sume if (getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, flag) == 0) 254378064Sume return (buf); 254478064Sume else 254578064Sume return "?"; 254655163Sshin} 254755163Sshin 254855163Sshin/* 254955163Sshin * pr_retip -- 255055163Sshin * Dump some info on a returned (via ICMPv6) IPv6 packet. 255155163Sshin */ 255255163Sshinvoid 2553216561Scharnierpr_retip(struct ip6_hdr *ip6, u_char *end) 255455163Sshin{ 255555163Sshin u_char *cp = (u_char *)ip6, nh; 255655163Sshin int hlen; 255755163Sshin 255855163Sshin if (end - (u_char *)ip6 < sizeof(*ip6)) { 255955163Sshin printf("IP6"); 256055163Sshin goto trunc; 256155163Sshin } 256255163Sshin pr_iph(ip6); 256355163Sshin hlen = sizeof(*ip6); 256455163Sshin 256555163Sshin nh = ip6->ip6_nxt; 256655163Sshin cp += hlen; 256755163Sshin while (end - cp >= 8) { 256855163Sshin switch (nh) { 256978064Sume case IPPROTO_HOPOPTS: 257078064Sume printf("HBH "); 257178064Sume hlen = (((struct ip6_hbh *)cp)->ip6h_len+1) << 3; 257278064Sume nh = ((struct ip6_hbh *)cp)->ip6h_nxt; 257378064Sume break; 257478064Sume case IPPROTO_DSTOPTS: 257578064Sume printf("DSTOPT "); 257678064Sume hlen = (((struct ip6_dest *)cp)->ip6d_len+1) << 3; 257778064Sume nh = ((struct ip6_dest *)cp)->ip6d_nxt; 257878064Sume break; 257978064Sume case IPPROTO_FRAGMENT: 258078064Sume printf("FRAG "); 258178064Sume hlen = sizeof(struct ip6_frag); 258278064Sume nh = ((struct ip6_frag *)cp)->ip6f_nxt; 258378064Sume break; 258478064Sume case IPPROTO_ROUTING: 258578064Sume printf("RTHDR "); 258678064Sume hlen = (((struct ip6_rthdr *)cp)->ip6r_len+1) << 3; 258778064Sume nh = ((struct ip6_rthdr *)cp)->ip6r_nxt; 258878064Sume break; 258955163Sshin#ifdef IPSEC 259078064Sume case IPPROTO_AH: 259178064Sume printf("AH "); 259278064Sume hlen = (((struct ah *)cp)->ah_len+2) << 2; 259378064Sume nh = ((struct ah *)cp)->ah_nxt; 259478064Sume break; 259555163Sshin#endif 259678064Sume case IPPROTO_ICMPV6: 259778064Sume printf("ICMP6: type = %d, code = %d\n", 259878064Sume *cp, *(cp + 1)); 259978064Sume return; 260078064Sume case IPPROTO_ESP: 260178064Sume printf("ESP\n"); 260278064Sume return; 260378064Sume case IPPROTO_TCP: 260478064Sume printf("TCP: from port %u, to port %u (decimal)\n", 260578064Sume (*cp * 256 + *(cp + 1)), 260678064Sume (*(cp + 2) * 256 + *(cp + 3))); 260778064Sume return; 260878064Sume case IPPROTO_UDP: 260978064Sume printf("UDP: from port %u, to port %u (decimal)\n", 261078064Sume (*cp * 256 + *(cp + 1)), 261178064Sume (*(cp + 2) * 256 + *(cp + 3))); 261278064Sume return; 261378064Sume default: 261478064Sume printf("Unknown Header(%d)\n", nh); 261578064Sume return; 261655163Sshin } 261755163Sshin 261855163Sshin if ((cp += hlen) >= end) 261955163Sshin goto trunc; 262055163Sshin } 262155163Sshin if (end - cp < 8) 262255163Sshin goto trunc; 262355163Sshin 262455163Sshin putchar('\n'); 262555163Sshin return; 262655163Sshin 262755163Sshin trunc: 262855163Sshin printf("...\n"); 262955163Sshin return; 263055163Sshin} 263155163Sshin 263255163Sshinvoid 2633216561Scharnierfill(char *bp, char *patp) 263455163Sshin{ 263592806Sobrien int ii, jj, kk; 263655163Sshin int pat[16]; 263755163Sshin char *cp; 263855163Sshin 263955163Sshin for (cp = patp; *cp; cp++) 264055163Sshin if (!isxdigit(*cp)) 264155163Sshin errx(1, "patterns must be specified as hex digits"); 264255163Sshin ii = sscanf(patp, 264355163Sshin "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", 264455163Sshin &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6], 264555163Sshin &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12], 264655163Sshin &pat[13], &pat[14], &pat[15]); 264755163Sshin 264878064Sume/* xxx */ 264955163Sshin if (ii > 0) 265055163Sshin for (kk = 0; 2651121472Sume kk <= MAXDATALEN - (8 + sizeof(struct tv32) + ii); 265255163Sshin kk += ii) 265355163Sshin for (jj = 0; jj < ii; ++jj) 265455163Sshin bp[jj + kk] = pat[jj]; 265555163Sshin if (!(options & F_QUIET)) { 265655163Sshin (void)printf("PATTERN: 0x"); 265755163Sshin for (jj = 0; jj < ii; ++jj) 265855163Sshin (void)printf("%02x", bp[jj] & 0xFF); 265955163Sshin (void)printf("\n"); 266055163Sshin } 266155163Sshin} 266255163Sshin 266355163Sshin#ifdef IPSEC 266455163Sshin#ifdef IPSEC_POLICY_IPSEC 266555163Sshinint 2666216561Scharniersetpolicy(int so __unused, char *policy) 266755163Sshin{ 266855163Sshin char *buf; 266955163Sshin 267055163Sshin if (policy == NULL) 267155163Sshin return 0; /* ignore */ 267255163Sshin 267355163Sshin buf = ipsec_set_policy(policy, strlen(policy)); 267455163Sshin if (buf == NULL) 267564277Skris errx(1, "%s", ipsec_strerror()); 267678064Sume if (setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, buf, 267778064Sume ipsec_get_policylen(buf)) < 0) 2678121472Sume warnx("Unable to set IPsec policy"); 267955163Sshin free(buf); 268055163Sshin 268155163Sshin return 0; 268255163Sshin} 268355163Sshin#endif 268455163Sshin#endif 268555163Sshin 268662627Skrischar * 2687250251Shrsnigroup(char *name, int nig_oldmcprefix) 268862627Skris{ 268962627Skris char *p; 2690121472Sume char *q; 269162627Skris MD5_CTX ctxt; 269262627Skris u_int8_t digest[16]; 269378064Sume u_int8_t c; 269478064Sume size_t l; 269562627Skris char hbuf[NI_MAXHOST]; 269662627Skris struct in6_addr in6; 2697250251Shrs int valid; 269862627Skris 269978064Sume p = strchr(name, '.'); 270078064Sume if (!p) 270178064Sume p = name + strlen(name); 270278064Sume l = p - name; 270378064Sume if (l > 63 || l > sizeof(hbuf) - 1) 270462627Skris return NULL; /*label too long*/ 270578064Sume strncpy(hbuf, name, l); 270678064Sume hbuf[(int)l] = '\0'; 270762627Skris 270878064Sume for (q = name; *q; q++) { 2709121472Sume if (isupper(*(unsigned char *)q)) 2710121472Sume *q = tolower(*(unsigned char *)q); 271178064Sume } 271278064Sume 2713250251Shrs /* generate 16 bytes of pseudo-random value. */ 2714121472Sume memset(&ctxt, 0, sizeof(ctxt)); 271562627Skris MD5Init(&ctxt); 271678064Sume c = l & 0xff; 271778064Sume MD5Update(&ctxt, &c, sizeof(c)); 2718121472Sume MD5Update(&ctxt, (unsigned char *)name, l); 271962627Skris MD5Final(digest, &ctxt); 272062627Skris 2721250251Shrs if (nig_oldmcprefix) { 2722250251Shrs /* draft-ietf-ipngwg-icmp-name-lookup */ 2723250251Shrs valid = inet_pton(AF_INET6, "ff02::2:0000:0000", &in6); 2724250251Shrs } else { 2725250251Shrs /* RFC 4620 */ 2726250251Shrs valid = inet_pton(AF_INET6, "ff02::2:ff00:0000", &in6); 2727250251Shrs } 2728250251Shrs if (valid != 1) 272978064Sume return NULL; /*XXX*/ 2730250251Shrs 2731250251Shrs if (nig_oldmcprefix) { 2732250251Shrs /* draft-ietf-ipngwg-icmp-name-lookup */ 2733250251Shrs bcopy(digest, &in6.s6_addr[12], 4); 2734250251Shrs } else { 2735250251Shrs /* RFC 4620 */ 2736250251Shrs bcopy(digest, &in6.s6_addr[13], 3); 2737250251Shrs } 273862627Skris 273962627Skris if (inet_ntop(AF_INET6, &in6, hbuf, sizeof(hbuf)) == NULL) 274062627Skris return NULL; 274162627Skris 274262627Skris return strdup(hbuf); 274362627Skris} 274462627Skris 274555163Sshinvoid 2746216561Scharnierusage(void) 274755163Sshin{ 274855163Sshin (void)fprintf(stderr, 2749141611Sru#if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC) 2750141611Sru "A" 2751141611Sru#endif 2752141611Sru "usage: ping6 [-" 2753206889Smaxim "Dd" 2754141611Sru#if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC) 2755141611Sru "E" 2756141611Sru#endif 2757141611Sru "fH" 275878990Sume#ifdef IPV6_USE_MIN_MTU 275978990Sume "m" 276078990Sume#endif 2761182276Smatteo "nNoqrRtvwW] " 2762141611Sru "[-a addrtype] [-b bufsiz] [-c count] [-g gateway]\n" 2763141611Sru " [-h hoplimit] [-I interface] [-i wait] [-l preload]" 2764141611Sru#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 2765141611Sru " [-P policy]" 276655163Sshin#endif 2767141611Sru "\n" 2768141611Sru " [-p pattern] [-S sourceaddr] [-s packetsize] " 2769285820Shrs "[-x waittime]\n" 2770285820Shrs " [-X timeout] [hops ...] host\n"); 277155163Sshin exit(1); 277255163Sshin} 2773