]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/ping6/ping6.c
This commit was generated by cvs2svn to compensate for changes in r154184,
[FreeBSD/FreeBSD.git] / sbin / ping6 / ping6.c
1 /*      $KAME: ping6.c,v 1.169 2003/07/25 06:01:47 itojun Exp $ */
2
3 /*
4  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the project nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 /*      BSDI    ping.c,v 2.3 1996/01/21 17:56:50 jch Exp        */
33
34 /*
35  * Copyright (c) 1989, 1993
36  *      The Regents of the University of California.  All rights reserved.
37  *
38  * This code is derived from software contributed to Berkeley by
39  * Mike Muuss.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. All advertising materials mentioning features or use of this software
50  *    must display the following acknowledgement:
51  *      This product includes software developed by the University of
52  *      California, Berkeley and its contributors.
53  * 4. Neither the name of the University nor the names of its contributors
54  *    may be used to endorse or promote products derived from this software
55  *    without specific prior written permission.
56  *
57  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67  * SUCH DAMAGE.
68  */
69
70 #ifndef lint
71 static const char copyright[] =
72 "@(#) Copyright (c) 1989, 1993\n\
73         The Regents of the University of California.  All rights reserved.\n";
74 #endif /* not lint */
75
76 #ifndef lint
77 #if 0
78 static char sccsid[] = "@(#)ping.c      8.1 (Berkeley) 6/5/93";
79 #endif
80 static const char rcsid[] =
81   "$FreeBSD$";
82 #endif /* not lint */
83
84 /*
85  * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
86  * measure round-trip-delays and packet loss across network paths.
87  *
88  * Author -
89  *      Mike Muuss
90  *      U. S. Army Ballistic Research Laboratory
91  *      December, 1983
92  *
93  * Status -
94  *      Public Domain.  Distribution Unlimited.
95  * Bugs -
96  *      More statistics could always be gathered.
97  *      This program has to run SUID to ROOT to access the ICMP socket.
98  */
99 /*
100  * NOTE:
101  * USE_SIN6_SCOPE_ID assumes that sin6_scope_id has the same semantics
102  * as IPV6_PKTINFO.  Some people object it (sin6_scope_id specifies *link*
103  * while IPV6_PKTINFO specifies *interface*.  Link is defined as collection of
104  * network attached to 1 or more interfaces)
105  */
106
107 #include <sys/param.h>
108 #include <sys/uio.h>
109 #include <sys/socket.h>
110 #include <sys/time.h>
111
112 #include <net/if.h>
113 #include <net/route.h>
114
115 #include <netinet/in.h>
116 #include <netinet/ip6.h>
117 #include <netinet/icmp6.h>
118 #include <arpa/inet.h>
119 #include <arpa/nameser.h>
120 #include <netdb.h>
121
122 #include <ctype.h>
123 #include <err.h>
124 #include <errno.h>
125 #include <fcntl.h>
126 #include <math.h>
127 #include <signal.h>
128 #include <stdio.h>
129 #include <stdlib.h>
130 #include <string.h>
131 #include <unistd.h>
132 #ifdef HAVE_POLL_H
133 #include <poll.h>
134 #endif
135
136 #ifdef IPSEC
137 #include <netinet6/ah.h>
138 #include <netinet6/ipsec.h>
139 #endif
140
141 #include <md5.h>
142
143 struct tv32 {
144         u_int32_t tv32_sec;
145         u_int32_t tv32_usec;
146 };
147
148 #define MAXPACKETLEN    131072
149 #define IP6LEN          40
150 #define ICMP6ECHOLEN    8       /* icmp echo header len excluding time */
151 #define ICMP6ECHOTMLEN sizeof(struct tv32)
152 #define ICMP6_NIQLEN    (ICMP6ECHOLEN + 8)
153 /* FQDN case, 64 bits of nonce + 32 bits ttl */
154 #define ICMP6_NIRLEN    (ICMP6ECHOLEN + 12)
155 #define EXTRA           256     /* for AH and various other headers. weird. */
156 #define DEFDATALEN      ICMP6ECHOTMLEN
157 #define MAXDATALEN      MAXPACKETLEN - IP6LEN - ICMP6ECHOLEN
158 #define NROUTES         9               /* number of record route slots */
159
160 #define A(bit)          rcvd_tbl[(bit)>>3]      /* identify byte in array */
161 #define B(bit)          (1 << ((bit) & 0x07))   /* identify bit in byte */
162 #define SET(bit)        (A(bit) |= B(bit))
163 #define CLR(bit)        (A(bit) &= (~B(bit)))
164 #define TST(bit)        (A(bit) & B(bit))
165
166 #define F_FLOOD         0x0001
167 #define F_INTERVAL      0x0002
168 #define F_PINGFILLED    0x0008
169 #define F_QUIET         0x0010
170 #define F_RROUTE        0x0020
171 #define F_SO_DEBUG      0x0040
172 #define F_VERBOSE       0x0100
173 #ifdef IPSEC
174 #ifdef IPSEC_POLICY_IPSEC
175 #define F_POLICY        0x0400
176 #else
177 #define F_AUTHHDR       0x0200
178 #define F_ENCRYPT       0x0400
179 #endif /*IPSEC_POLICY_IPSEC*/
180 #endif /*IPSEC*/
181 #define F_NODEADDR      0x0800
182 #define F_FQDN          0x1000
183 #define F_INTERFACE     0x2000
184 #define F_SRCADDR       0x4000
185 #define F_HOSTNAME      0x10000
186 #define F_FQDNOLD       0x20000
187 #define F_NIGROUP       0x40000
188 #define F_SUPTYPES      0x80000
189 #define F_NOMINMTU      0x100000
190 #define F_NOUSERDATA    (F_NODEADDR | F_FQDN | F_FQDNOLD | F_SUPTYPES)
191 u_int options;
192
193 #define IN6LEN          sizeof(struct in6_addr)
194 #define SA6LEN          sizeof(struct sockaddr_in6)
195 #define DUMMY_PORT      10101
196
197 #define SIN6(s) ((struct sockaddr_in6 *)(s))
198
199 /*
200  * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
201  * number of received sequence numbers we can keep track of.  Change 128
202  * to 8192 for complete accuracy...
203  */
204 #define MAX_DUP_CHK     (8 * 8192)
205 int mx_dup_ck = MAX_DUP_CHK;
206 char rcvd_tbl[MAX_DUP_CHK / 8];
207
208 struct addrinfo *res;
209 struct sockaddr_in6 dst;        /* who to ping6 */
210 struct sockaddr_in6 src;        /* src addr of this packet */
211 socklen_t srclen;
212 int datalen = DEFDATALEN;
213 int s;                          /* socket file descriptor */
214 u_char outpack[MAXPACKETLEN];
215 char BSPACE = '\b';             /* characters written for flood */
216 char DOT = '.';
217 char *hostname;
218 int ident;                      /* process id to identify our packets */
219 u_int8_t nonce[8];              /* nonce field for node information */
220 int hoplimit = -1;              /* hoplimit */
221 int pathmtu = 0;                /* path MTU for the destination.  0 = unspec. */
222
223 /* counters */
224 long npackets;                  /* max packets to transmit */
225 long nreceived;                 /* # of packets we got back */
226 long nrepeats;                  /* number of duplicates */
227 long ntransmitted;              /* sequence # for outbound packets = #sent */
228 struct timeval interval = {1, 0}; /* interval between packets */
229
230 /* timing */
231 int timing;                     /* flag to do timing */
232 double tmin = 999999999.0;      /* minimum round trip time */
233 double tmax = 0.0;              /* maximum round trip time */
234 double tsum = 0.0;              /* sum of all times, for doing average */
235 double tsumsq = 0.0;            /* sum of all times squared, for std. dev. */
236
237 /* for node addresses */
238 u_short naflags;
239
240 /* for ancillary data(advanced API) */
241 struct msghdr smsghdr;
242 struct iovec smsgiov;
243 char *scmsg = 0;
244
245 volatile sig_atomic_t seenalrm;
246 volatile sig_atomic_t seenint;
247 #ifdef SIGINFO
248 volatile sig_atomic_t seeninfo;
249 #endif
250
251 int      main(int, char *[]);
252 void     fill(char *, char *);
253 int      get_hoplim(struct msghdr *);
254 int      get_pathmtu(struct msghdr *);
255 struct in6_pktinfo *get_rcvpktinfo(struct msghdr *);
256 void     onsignal(int);
257 void     retransmit(void);
258 void     onint(int);
259 size_t   pingerlen(void);
260 int      pinger(void);
261 const char *pr_addr(struct sockaddr *, int);
262 void     pr_icmph(struct icmp6_hdr *, u_char *);
263 void     pr_iph(struct ip6_hdr *);
264 void     pr_suptypes(struct icmp6_nodeinfo *, size_t);
265 void     pr_nodeaddr(struct icmp6_nodeinfo *, int);
266 int      myechoreply(const struct icmp6_hdr *);
267 int      mynireply(const struct icmp6_nodeinfo *);
268 char *dnsdecode(const u_char **, const u_char *, const u_char *,
269         char *, size_t);
270 void     pr_pack(u_char *, int, struct msghdr *);
271 void     pr_exthdrs(struct msghdr *);
272 void     pr_ip6opt(void *);
273 void     pr_rthdr(void *);
274 int      pr_bitrange(u_int32_t, int, int);
275 void     pr_retip(struct ip6_hdr *, u_char *);
276 void     summary(void);
277 void     tvsub(struct timeval *, struct timeval *);
278 int      setpolicy(int, char *);
279 char    *nigroup(char *);
280 void     usage(void);
281
282 int
283 main(argc, argv)
284         int argc;
285         char *argv[];
286 {
287         struct itimerval itimer;
288         struct sockaddr_in6 from;
289 #ifndef HAVE_ARC4RANDOM
290         struct timeval seed;
291 #endif
292 #ifdef HAVE_POLL_H
293         int timeout;
294 #else
295         struct timeval timeout, *tv;
296 #endif
297         struct addrinfo hints;
298 #ifdef HAVE_POLL_H
299         struct pollfd fdmaskp[1];
300 #else
301         fd_set *fdmaskp;
302         int fdmasks;
303 #endif
304         int cc, i;
305         int ch, hold, packlen, preload, optval, ret_ga;
306         u_char *datap, *packet;
307         char *e, *target, *ifname = NULL, *gateway = NULL;
308         int ip6optlen = 0;
309         struct cmsghdr *scmsgp = NULL;
310 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
311         u_long lsockbufsize;
312         int sockbufsize = 0;
313 #endif
314         int usepktinfo = 0;
315         struct in6_pktinfo *pktinfo = NULL;
316 #ifdef USE_RFC2292BIS
317         struct ip6_rthdr *rthdr = NULL;
318 #endif
319 #ifdef IPSEC_POLICY_IPSEC
320         char *policy_in = NULL;
321         char *policy_out = NULL;
322 #endif
323         double intval;
324         size_t rthlen;
325 #ifdef IPV6_USE_MIN_MTU
326         int mflag = 0;
327 #endif
328
329         /* just to be sure */
330         memset(&smsghdr, 0, sizeof(smsghdr));
331         memset(&smsgiov, 0, sizeof(smsgiov));
332
333         preload = 0;
334         datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN];
335 #ifndef IPSEC
336 #define ADDOPTS
337 #else
338 #ifdef IPSEC_POLICY_IPSEC
339 #define ADDOPTS "P:"
340 #else
341 #define ADDOPTS "AE"
342 #endif /*IPSEC_POLICY_IPSEC*/
343 #endif
344         while ((ch = getopt(argc, argv,
345             "a:b:c:dfHg:h:I:i:l:mnNp:qS:s:tvwW" ADDOPTS)) != -1) {
346 #undef ADDOPTS
347                 switch (ch) {
348                 case 'a':
349                 {
350                         char *cp;
351
352                         options &= ~F_NOUSERDATA;
353                         options |= F_NODEADDR;
354                         for (cp = optarg; *cp != '\0'; cp++) {
355                                 switch (*cp) {
356                                 case 'a':
357                                         naflags |= NI_NODEADDR_FLAG_ALL;
358                                         break;
359                                 case 'c':
360                                 case 'C':
361                                         naflags |= NI_NODEADDR_FLAG_COMPAT;
362                                         break;
363                                 case 'l':
364                                 case 'L':
365                                         naflags |= NI_NODEADDR_FLAG_LINKLOCAL;
366                                         break;
367                                 case 's':
368                                 case 'S':
369                                         naflags |= NI_NODEADDR_FLAG_SITELOCAL;
370                                         break;
371                                 case 'g':
372                                 case 'G':
373                                         naflags |= NI_NODEADDR_FLAG_GLOBAL;
374                                         break;
375                                 case 'A': /* experimental. not in the spec */
376 #ifdef NI_NODEADDR_FLAG_ANYCAST
377                                         naflags |= NI_NODEADDR_FLAG_ANYCAST;
378                                         break;
379 #else
380                                         errx(1,
381 "-a A is not supported on the platform");
382                                         /*NOTREACHED*/
383 #endif
384                                 default:
385                                         usage();
386                                         /*NOTREACHED*/
387                                 }
388                         }
389                         break;
390                 }
391                 case 'b':
392 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
393                         errno = 0;
394                         e = NULL;
395                         lsockbufsize = strtoul(optarg, &e, 10);
396                         sockbufsize = lsockbufsize;
397                         if (errno || !*optarg || *e ||
398                             sockbufsize != lsockbufsize)
399                                 errx(1, "invalid socket buffer size");
400 #else
401                         errx(1,
402 "-b option ignored: SO_SNDBUF/SO_RCVBUF socket options not supported");
403 #endif
404                         break;
405                 case 'c':
406                         npackets = strtol(optarg, &e, 10);
407                         if (npackets <= 0 || *optarg == '\0' || *e != '\0')
408                                 errx(1,
409                                     "illegal number of packets -- %s", optarg);
410                         break;
411                 case 'd':
412                         options |= F_SO_DEBUG;
413                         break;
414                 case 'f':
415                         if (getuid()) {
416                                 errno = EPERM;
417                                 errx(1, "Must be superuser to flood ping");
418                         }
419                         options |= F_FLOOD;
420                         setbuf(stdout, (char *)NULL);
421                         break;
422                 case 'g':
423                         gateway = optarg;
424                         break;
425                 case 'H':
426                         options |= F_HOSTNAME;
427                         break;
428                 case 'h':               /* hoplimit */
429                         hoplimit = strtol(optarg, &e, 10);
430                         if (*optarg == '\0' || *e != '\0')
431                                 errx(1, "illegal hoplimit %s", optarg);
432                         if (255 < hoplimit || hoplimit < -1)
433                                 errx(1,
434                                     "illegal hoplimit -- %s", optarg);
435                         break;
436                 case 'I':
437                         ifname = optarg;
438                         options |= F_INTERFACE;
439 #ifndef USE_SIN6_SCOPE_ID
440                         usepktinfo++;
441 #endif
442                         break;
443                 case 'i':               /* wait between sending packets */
444                         intval = strtod(optarg, &e);
445                         if (*optarg == '\0' || *e != '\0')
446                                 errx(1, "illegal timing interval %s", optarg);
447                         if (intval < 1 && getuid()) {
448                                 errx(1, "%s: only root may use interval < 1s",
449                                     strerror(EPERM));
450                         }
451                         interval.tv_sec = (long)intval;
452                         interval.tv_usec =
453                             (long)((intval - interval.tv_sec) * 1000000);
454                         if (interval.tv_sec < 0)
455                                 errx(1, "illegal timing interval %s", optarg);
456                         /* less than 1/hz does not make sense */
457                         if (interval.tv_sec == 0 && interval.tv_usec < 10000) {
458                                 warnx("too small interval, raised to 0.01");
459                                 interval.tv_usec = 10000;
460                         }
461                         options |= F_INTERVAL;
462                         break;
463                 case 'l':
464                         if (getuid()) {
465                                 errno = EPERM;
466                                 errx(1, "Must be superuser to preload");
467                         }
468                         preload = strtol(optarg, &e, 10);
469                         if (preload < 0 || *optarg == '\0' || *e != '\0')
470                                 errx(1, "illegal preload value -- %s", optarg);
471                         break;
472                 case 'm':
473 #ifdef IPV6_USE_MIN_MTU
474                         mflag++;
475                         break;
476 #else
477                         errx(1, "-%c is not supported on this platform", ch);
478                         /*NOTREACHED*/
479 #endif
480                 case 'n':
481                         options &= ~F_HOSTNAME;
482                         break;
483                 case 'N':
484                         options |= F_NIGROUP;
485                         break;
486                 case 'p':               /* fill buffer with user pattern */
487                         options |= F_PINGFILLED;
488                         fill((char *)datap, optarg);
489                                 break;
490                 case 'q':
491                         options |= F_QUIET;
492                         break;
493                 case 'S':
494                         memset(&hints, 0, sizeof(struct addrinfo));
495                         hints.ai_flags = AI_NUMERICHOST; /* allow hostname? */
496                         hints.ai_family = AF_INET6;
497                         hints.ai_socktype = SOCK_RAW;
498                         hints.ai_protocol = IPPROTO_ICMPV6;
499
500                         ret_ga = getaddrinfo(optarg, NULL, &hints, &res);
501                         if (ret_ga) {
502                                 errx(1, "invalid source address: %s",
503                                      gai_strerror(ret_ga));
504                         }
505                         /*
506                          * res->ai_family must be AF_INET6 and res->ai_addrlen
507                          * must be sizeof(src).
508                          */
509                         memcpy(&src, res->ai_addr, res->ai_addrlen);
510                         srclen = res->ai_addrlen;
511                         freeaddrinfo(res);
512                         options |= F_SRCADDR;
513                         break;
514                 case 's':               /* size of packet to send */
515                         datalen = strtol(optarg, &e, 10);
516                         if (datalen <= 0 || *optarg == '\0' || *e != '\0')
517                                 errx(1, "illegal datalen value -- %s", optarg);
518                         if (datalen > MAXDATALEN) {
519                                 errx(1,
520                                     "datalen value too large, maximum is %d",
521                                     MAXDATALEN);
522                         }
523                         break;
524                 case 't':
525                         options &= ~F_NOUSERDATA;
526                         options |= F_SUPTYPES;
527                         break;
528                 case 'v':
529                         options |= F_VERBOSE;
530                         break;
531                 case 'w':
532                         options &= ~F_NOUSERDATA;
533                         options |= F_FQDN;
534                         break;
535                 case 'W':
536                         options &= ~F_NOUSERDATA;
537                         options |= F_FQDNOLD;
538                         break;
539 #ifdef IPSEC
540 #ifdef IPSEC_POLICY_IPSEC
541                 case 'P':
542                         options |= F_POLICY;
543                         if (!strncmp("in", optarg, 2)) {
544                                 if ((policy_in = strdup(optarg)) == NULL)
545                                         errx(1, "strdup");
546                         } else if (!strncmp("out", optarg, 3)) {
547                                 if ((policy_out = strdup(optarg)) == NULL)
548                                         errx(1, "strdup");
549                         } else
550                                 errx(1, "invalid security policy");
551                         break;
552 #else
553                 case 'A':
554                         options |= F_AUTHHDR;
555                         break;
556                 case 'E':
557                         options |= F_ENCRYPT;
558                         break;
559 #endif /*IPSEC_POLICY_IPSEC*/
560 #endif /*IPSEC*/
561                 default:
562                         usage();
563                         /*NOTREACHED*/
564                 }
565         }
566
567         argc -= optind;
568         argv += optind;
569
570         if (argc < 1) {
571                 usage();
572                 /*NOTREACHED*/
573         }
574
575         if (argc > 1) {
576 #ifdef IPV6_RECVRTHDR   /* 2292bis */
577                 rthlen = CMSG_SPACE(inet6_rth_space(IPV6_RTHDR_TYPE_0,
578                     argc - 1));
579 #else  /* RFC2292 */
580                 rthlen = inet6_rthdr_space(IPV6_RTHDR_TYPE_0, argc - 1);
581 #endif
582                 if (rthlen == 0) {
583                         errx(1, "too many intermediate hops");
584                         /*NOTREACHED*/
585                 }
586                 ip6optlen += rthlen;
587         }
588
589         if (options & F_NIGROUP) {
590                 target = nigroup(argv[argc - 1]);
591                 if (target == NULL) {
592                         usage();
593                         /*NOTREACHED*/
594                 }
595         } else
596                 target = argv[argc - 1];
597
598         /* getaddrinfo */
599         memset(&hints, 0, sizeof(struct addrinfo));
600         hints.ai_flags = AI_CANONNAME;
601         hints.ai_family = AF_INET6;
602         hints.ai_socktype = SOCK_RAW;
603         hints.ai_protocol = IPPROTO_ICMPV6;
604
605         ret_ga = getaddrinfo(target, NULL, &hints, &res);
606         if (ret_ga)
607                 errx(1, "%s", gai_strerror(ret_ga));
608         if (res->ai_canonname)
609                 hostname = res->ai_canonname;
610         else
611                 hostname = target;
612
613         if (!res->ai_addr)
614                 errx(1, "getaddrinfo failed");
615
616         (void)memcpy(&dst, res->ai_addr, res->ai_addrlen);
617
618         if ((s = socket(res->ai_family, res->ai_socktype,
619             res->ai_protocol)) < 0)
620                 err(1, "socket");
621
622         /* set the source address if specified. */
623         if ((options & F_SRCADDR) &&
624             bind(s, (struct sockaddr *)&src, srclen) != 0) {
625                 err(1, "bind");
626         }
627
628         /* set the gateway (next hop) if specified */
629         if (gateway) {
630                 struct addrinfo ghints, *gres;
631                 int error;
632
633                 memset(&ghints, 0, sizeof(ghints));
634                 ghints.ai_family = AF_INET6;
635                 ghints.ai_socktype = SOCK_RAW;
636                 ghints.ai_protocol = IPPROTO_ICMPV6;
637
638                 error = getaddrinfo(gateway, NULL, &hints, &gres);
639                 if (error) {
640                         errx(1, "getaddrinfo for the gateway %s: %s",
641                              gateway, gai_strerror(error));
642                 }
643                 if (gres->ai_next && (options & F_VERBOSE))
644                         warnx("gateway resolves to multiple addresses");
645
646                 if (setsockopt(s, IPPROTO_IPV6, IPV6_NEXTHOP,
647                                gres->ai_addr, gres->ai_addrlen)) {
648                         err(1, "setsockopt(IPV6_NEXTHOP)");
649                 }
650
651                 freeaddrinfo(gres);
652         }
653
654         /*
655          * let the kerel pass extension headers of incoming packets,
656          * for privileged socket options
657          */
658         if ((options & F_VERBOSE) != 0) {
659                 int opton = 1;
660
661 #ifdef IPV6_RECVHOPOPTS
662                 if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &opton,
663                     sizeof(opton)))
664                         err(1, "setsockopt(IPV6_RECVHOPOPTS)");
665 #else  /* old adv. API */
666                 if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPOPTS, &opton,
667                     sizeof(opton)))
668                         err(1, "setsockopt(IPV6_HOPOPTS)");
669 #endif
670 #ifdef IPV6_RECVDSTOPTS
671                 if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTOPTS, &opton,
672                     sizeof(opton)))
673                         err(1, "setsockopt(IPV6_RECVDSTOPTS)");
674 #else  /* old adv. API */
675                 if (setsockopt(s, IPPROTO_IPV6, IPV6_DSTOPTS, &opton,
676                     sizeof(opton)))
677                         err(1, "setsockopt(IPV6_DSTOPTS)");
678 #endif
679 #ifdef IPV6_RECVRTHDRDSTOPTS
680                 if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDRDSTOPTS, &opton,
681                     sizeof(opton)))
682                         err(1, "setsockopt(IPV6_RECVRTHDRDSTOPTS)");
683 #endif
684         }
685
686         /* revoke root privilege */
687         seteuid(getuid());
688         setuid(getuid());
689
690         if ((options & F_FLOOD) && (options & F_INTERVAL))
691                 errx(1, "-f and -i incompatible options");
692
693         if ((options & F_NOUSERDATA) == 0) {
694                 if (datalen >= sizeof(struct tv32)) {
695                         /* we can time transfer */
696                         timing = 1;
697                 } else
698                         timing = 0;
699                 /* in F_VERBOSE case, we may get non-echoreply packets*/
700                 if (options & F_VERBOSE)
701                         packlen = 2048 + IP6LEN + ICMP6ECHOLEN + EXTRA;
702                 else
703                         packlen = datalen + IP6LEN + ICMP6ECHOLEN + EXTRA;
704         } else {
705                 /* suppress timing for node information query */
706                 timing = 0;
707                 datalen = 2048;
708                 packlen = 2048 + IP6LEN + ICMP6ECHOLEN + EXTRA;
709         }
710
711         if (!(packet = (u_char *)malloc((u_int)packlen)))
712                 err(1, "Unable to allocate packet");
713         if (!(options & F_PINGFILLED))
714                 for (i = ICMP6ECHOLEN; i < packlen; ++i)
715                         *datap++ = i;
716
717         ident = getpid() & 0xFFFF;
718 #ifndef HAVE_ARC4RANDOM
719         gettimeofday(&seed, NULL);
720         srand((unsigned int)(seed.tv_sec ^ seed.tv_usec ^ (long)ident));
721         memset(nonce, 0, sizeof(nonce));
722         for (i = 0; i < sizeof(nonce); i += sizeof(int))
723                 *((int *)&nonce[i]) = rand();
724 #else
725         memset(nonce, 0, sizeof(nonce));
726         for (i = 0; i < sizeof(nonce); i += sizeof(u_int32_t))
727                 *((u_int32_t *)&nonce[i]) = arc4random();
728 #endif
729
730         hold = 1;
731
732         if (options & F_SO_DEBUG)
733                 (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
734                     sizeof(hold));
735         optval = IPV6_DEFHLIM;
736         if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr))
737                 if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
738                     &optval, sizeof(optval)) == -1)
739                         err(1, "IPV6_MULTICAST_HOPS");
740 #ifdef IPV6_USE_MIN_MTU
741         if (mflag != 1) {
742                 optval = mflag > 1 ? 0 : 1;
743
744                 if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
745                     &optval, sizeof(optval)) == -1)
746                         err(1, "setsockopt(IPV6_USE_MIN_MTU)");
747         }
748 #ifdef IPV6_RECVPATHMTU
749         else {
750                 optval = 1;
751                 if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPATHMTU,
752                     &optval, sizeof(optval)) == -1)
753                         err(1, "setsockopt(IPV6_RECVPATHMTU)");
754         }
755 #endif /* IPV6_RECVPATHMTU */
756 #endif /* IPV6_USE_MIN_MTU */
757
758 #ifdef IPSEC
759 #ifdef IPSEC_POLICY_IPSEC
760         if (options & F_POLICY) {
761                 if (setpolicy(s, policy_in) < 0)
762                         errx(1, "%s", ipsec_strerror());
763                 if (setpolicy(s, policy_out) < 0)
764                         errx(1, "%s", ipsec_strerror());
765         }
766 #else
767         if (options & F_AUTHHDR) {
768                 optval = IPSEC_LEVEL_REQUIRE;
769 #ifdef IPV6_AUTH_TRANS_LEVEL
770                 if (setsockopt(s, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL,
771                     &optval, sizeof(optval)) == -1)
772                         err(1, "setsockopt(IPV6_AUTH_TRANS_LEVEL)");
773 #else /* old def */
774                 if (setsockopt(s, IPPROTO_IPV6, IPV6_AUTH_LEVEL,
775                     &optval, sizeof(optval)) == -1)
776                         err(1, "setsockopt(IPV6_AUTH_LEVEL)");
777 #endif
778         }
779         if (options & F_ENCRYPT) {
780                 optval = IPSEC_LEVEL_REQUIRE;
781                 if (setsockopt(s, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL,
782                     &optval, sizeof(optval)) == -1)
783                         err(1, "setsockopt(IPV6_ESP_TRANS_LEVEL)");
784         }
785 #endif /*IPSEC_POLICY_IPSEC*/
786 #endif
787
788 #ifdef ICMP6_FILTER
789     {
790         struct icmp6_filter filt;
791         if (!(options & F_VERBOSE)) {
792                 ICMP6_FILTER_SETBLOCKALL(&filt);
793                 if ((options & F_FQDN) || (options & F_FQDNOLD) ||
794                     (options & F_NODEADDR) || (options & F_SUPTYPES))
795                         ICMP6_FILTER_SETPASS(ICMP6_NI_REPLY, &filt);
796                 else
797                         ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt);
798         } else {
799                 ICMP6_FILTER_SETPASSALL(&filt);
800         }
801         if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
802             sizeof(filt)) < 0)
803                 err(1, "setsockopt(ICMP6_FILTER)");
804     }
805 #endif /*ICMP6_FILTER*/
806
807         /* let the kerel pass extension headers of incoming packets */
808         if ((options & F_VERBOSE) != 0) {
809                 int opton = 1;
810
811 #ifdef IPV6_RECVRTHDR
812                 if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDR, &opton,
813                     sizeof(opton)))
814                         err(1, "setsockopt(IPV6_RECVRTHDR)");
815 #else  /* old adv. API */
816                 if (setsockopt(s, IPPROTO_IPV6, IPV6_RTHDR, &opton,
817                     sizeof(opton)))
818                         err(1, "setsockopt(IPV6_RTHDR)");
819 #endif
820         }
821
822 /*
823         optval = 1;
824         if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr))
825                 if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
826                     &optval, sizeof(optval)) == -1)
827                         err(1, "IPV6_MULTICAST_LOOP");
828 */
829
830         /* Specify the outgoing interface and/or the source address */
831         if (usepktinfo)
832                 ip6optlen += CMSG_SPACE(sizeof(struct in6_pktinfo));
833
834         if (hoplimit != -1)
835                 ip6optlen += CMSG_SPACE(sizeof(int));
836
837         /* set IP6 packet options */
838         if (ip6optlen) {
839                 if ((scmsg = (char *)malloc(ip6optlen)) == 0)
840                         errx(1, "can't allocate enough memory");
841                 smsghdr.msg_control = (caddr_t)scmsg;
842                 smsghdr.msg_controllen = ip6optlen;
843                 scmsgp = (struct cmsghdr *)scmsg;
844         }
845         if (usepktinfo) {
846                 pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp));
847                 memset(pktinfo, 0, sizeof(*pktinfo));
848                 scmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
849                 scmsgp->cmsg_level = IPPROTO_IPV6;
850                 scmsgp->cmsg_type = IPV6_PKTINFO;
851                 scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
852         }
853
854         /* set the outgoing interface */
855         if (ifname) {
856 #ifndef USE_SIN6_SCOPE_ID
857                 /* pktinfo must have already been allocated */
858                 if ((pktinfo->ipi6_ifindex = if_nametoindex(ifname)) == 0)
859                         errx(1, "%s: invalid interface name", ifname);
860 #else
861                 if ((dst.sin6_scope_id = if_nametoindex(ifname)) == 0)
862                         errx(1, "%s: invalid interface name", ifname);
863 #endif
864         }
865         if (hoplimit != -1) {
866                 scmsgp->cmsg_len = CMSG_LEN(sizeof(int));
867                 scmsgp->cmsg_level = IPPROTO_IPV6;
868                 scmsgp->cmsg_type = IPV6_HOPLIMIT;
869                 *(int *)(CMSG_DATA(scmsgp)) = hoplimit;
870
871                 scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
872         }
873
874         if (argc > 1) { /* some intermediate addrs are specified */
875                 int hops, error;
876 #ifdef USE_RFC2292BIS
877                 int rthdrlen;
878 #endif
879
880 #ifdef USE_RFC2292BIS
881                 rthdrlen = inet6_rth_space(IPV6_RTHDR_TYPE_0, argc - 1);
882                 scmsgp->cmsg_len = CMSG_LEN(rthdrlen);
883                 scmsgp->cmsg_level = IPPROTO_IPV6;
884                 scmsgp->cmsg_type = IPV6_RTHDR;
885                 rthdr = (struct ip6_rthdr *)CMSG_DATA(scmsgp);
886                 rthdr = inet6_rth_init((void *)rthdr, rthdrlen,
887                     IPV6_RTHDR_TYPE_0, argc - 1);
888                 if (rthdr == NULL)
889                         errx(1, "can't initialize rthdr");
890 #else  /* old advanced API */
891                 if ((scmsgp = (struct cmsghdr *)inet6_rthdr_init(scmsgp,
892                     IPV6_RTHDR_TYPE_0)) == 0)
893                         errx(1, "can't initialize rthdr");
894 #endif /* USE_RFC2292BIS */
895
896                 for (hops = 0; hops < argc - 1; hops++) {
897                         struct addrinfo *iaip;
898
899                         if ((error = getaddrinfo(argv[hops], NULL, &hints,
900                             &iaip)))
901                                 errx(1, "%s", gai_strerror(error));
902                         if (SIN6(iaip->ai_addr)->sin6_family != AF_INET6)
903                                 errx(1,
904                                     "bad addr family of an intermediate addr");
905
906 #ifdef USE_RFC2292BIS
907                         if (inet6_rth_add(rthdr,
908                             &(SIN6(iaip->ai_addr))->sin6_addr))
909                                 errx(1, "can't add an intermediate node");
910 #else  /* old advanced API */
911                         if (inet6_rthdr_add(scmsgp,
912                             &(SIN6(iaip->ai_addr))->sin6_addr,
913                             IPV6_RTHDR_LOOSE))
914                                 errx(1, "can't add an intermediate node");
915 #endif /* USE_RFC2292BIS */
916                         freeaddrinfo(iaip);
917                 }
918
919 #ifndef USE_RFC2292BIS
920                 if (inet6_rthdr_lasthop(scmsgp, IPV6_RTHDR_LOOSE))
921                         errx(1, "can't set the last flag");
922 #endif
923
924                 scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
925         }
926
927         if (!(options & F_SRCADDR)) {
928                 /*
929                  * get the source address. XXX since we revoked the root
930                  * privilege, we cannot use a raw socket for this.
931                  */
932                 int dummy;
933                 socklen_t len = sizeof(src);
934
935                 if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
936                         err(1, "UDP socket");
937
938                 src.sin6_family = AF_INET6;
939                 src.sin6_addr = dst.sin6_addr;
940                 src.sin6_port = ntohs(DUMMY_PORT);
941                 src.sin6_scope_id = dst.sin6_scope_id;
942
943 #ifdef USE_RFC2292BIS
944                 if (pktinfo &&
945                     setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTINFO,
946                     (void *)pktinfo, sizeof(*pktinfo)))
947                         err(1, "UDP setsockopt(IPV6_PKTINFO)");
948
949                 if (hoplimit != -1 &&
950                     setsockopt(dummy, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
951                     (void *)&hoplimit, sizeof(hoplimit)))
952                         err(1, "UDP setsockopt(IPV6_UNICAST_HOPS)");
953
954                 if (hoplimit != -1 &&
955                     setsockopt(dummy, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
956                     (void *)&hoplimit, sizeof(hoplimit)))
957                         err(1, "UDP setsockopt(IPV6_MULTICAST_HOPS)");
958
959                 if (rthdr &&
960                     setsockopt(dummy, IPPROTO_IPV6, IPV6_RTHDR,
961                     (void *)rthdr, (rthdr->ip6r_len + 1) << 3))
962                         err(1, "UDP setsockopt(IPV6_RTHDR)");
963 #else  /* old advanced API */
964                 if (smsghdr.msg_control &&
965                     setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTOPTIONS,
966                     (void *)smsghdr.msg_control, smsghdr.msg_controllen))
967                         err(1, "UDP setsockopt(IPV6_PKTOPTIONS)");
968 #endif
969
970                 if (connect(dummy, (struct sockaddr *)&src, len) < 0)
971                         err(1, "UDP connect");
972
973                 if (getsockname(dummy, (struct sockaddr *)&src, &len) < 0)
974                         err(1, "getsockname");
975
976                 close(dummy);
977         }
978
979 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
980         if (sockbufsize) {
981                 if (datalen > sockbufsize)
982                         warnx("you need -b to increase socket buffer size");
983                 if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sockbufsize,
984                     sizeof(sockbufsize)) < 0)
985                         err(1, "setsockopt(SO_SNDBUF)");
986                 if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &sockbufsize,
987                     sizeof(sockbufsize)) < 0)
988                         err(1, "setsockopt(SO_RCVBUF)");
989         }
990         else {
991                 if (datalen > 8 * 1024) /*XXX*/
992                         warnx("you need -b to increase socket buffer size");
993                 /*
994                  * When pinging the broadcast address, you can get a lot of
995                  * answers. Doing something so evil is useful if you are trying
996                  * to stress the ethernet, or just want to fill the arp cache
997                  * to get some stuff for /etc/ethers.
998                  */
999                 hold = 48 * 1024;
1000                 setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold,
1001                     sizeof(hold));
1002         }
1003 #endif
1004
1005         optval = 1;
1006 #ifndef USE_SIN6_SCOPE_ID
1007 #ifdef IPV6_RECVPKTINFO
1008         if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &optval,
1009             sizeof(optval)) < 0)
1010                 warn("setsockopt(IPV6_RECVPKTINFO)"); /* XXX err? */
1011 #else  /* old adv. API */
1012         if (setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &optval,
1013             sizeof(optval)) < 0)
1014                 warn("setsockopt(IPV6_PKTINFO)"); /* XXX err? */
1015 #endif
1016 #endif /* USE_SIN6_SCOPE_ID */
1017 #ifdef IPV6_RECVHOPLIMIT
1018         if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &optval,
1019             sizeof(optval)) < 0)
1020                 warn("setsockopt(IPV6_RECVHOPLIMIT)"); /* XXX err? */
1021 #else  /* old adv. API */
1022         if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPLIMIT, &optval,
1023             sizeof(optval)) < 0)
1024                 warn("setsockopt(IPV6_HOPLIMIT)"); /* XXX err? */
1025 #endif
1026
1027         printf("PING6(%lu=40+8+%lu bytes) ", (unsigned long)(40 + pingerlen()),
1028             (unsigned long)(pingerlen() - 8));
1029         printf("%s --> ", pr_addr((struct sockaddr *)&src, sizeof(src)));
1030         printf("%s\n", pr_addr((struct sockaddr *)&dst, sizeof(dst)));
1031
1032         while (preload--)               /* Fire off them quickies. */
1033                 (void)pinger();
1034
1035         (void)signal(SIGINT, onsignal);
1036 #ifdef SIGINFO
1037         (void)signal(SIGINFO, onsignal);
1038 #endif
1039
1040         if ((options & F_FLOOD) == 0) {
1041                 (void)signal(SIGALRM, onsignal);
1042                 itimer.it_interval = interval;
1043                 itimer.it_value = interval;
1044                 (void)setitimer(ITIMER_REAL, &itimer, NULL);
1045                 if (ntransmitted == 0)
1046                         retransmit();
1047         }
1048
1049 #ifndef HAVE_POLL_H
1050         fdmasks = howmany(s + 1, NFDBITS) * sizeof(fd_mask);
1051         if ((fdmaskp = malloc(fdmasks)) == NULL)
1052                 err(1, "malloc");
1053 #endif
1054
1055         seenalrm = seenint = 0;
1056 #ifdef SIGINFO
1057         seeninfo = 0;
1058 #endif
1059
1060         for (;;) {
1061                 struct msghdr m;
1062                 struct cmsghdr *cm;
1063                 u_char buf[1024];
1064                 struct iovec iov[2];
1065
1066                 /* signal handling */
1067                 if (seenalrm) {
1068                         retransmit();
1069                         seenalrm = 0;
1070                         continue;
1071                 }
1072                 if (seenint) {
1073                         onint(SIGINT);
1074                         seenint = 0;
1075                         continue;
1076                 }
1077 #ifdef SIGINFO
1078                 if (seeninfo) {
1079                         summary();
1080                         seeninfo = 0;
1081                         continue;
1082                 }
1083 #endif
1084
1085                 if (options & F_FLOOD) {
1086                         (void)pinger();
1087 #ifdef HAVE_POLL_H
1088                         timeout = 10;
1089 #else
1090                         timeout.tv_sec = 0;
1091                         timeout.tv_usec = 10000;
1092                         tv = &timeout;
1093 #endif
1094                 } else {
1095 #ifdef HAVE_POLL_H
1096                         timeout = INFTIM;
1097 #else
1098                         tv = NULL;
1099 #endif
1100                 }
1101 #ifdef HAVE_POLL_H
1102                 fdmaskp[0].fd = s;
1103                 fdmaskp[0].events = POLLIN;
1104                 cc = poll(fdmaskp, 1, timeout);
1105 #else
1106                 memset(fdmaskp, 0, fdmasks);
1107                 FD_SET(s, fdmaskp);
1108                 cc = select(s + 1, fdmaskp, NULL, NULL, tv);
1109 #endif
1110                 if (cc < 0) {
1111                         if (errno != EINTR) {
1112 #ifdef HAVE_POLL_H
1113                                 warn("poll");
1114 #else
1115                                 warn("select");
1116 #endif
1117                                 sleep(1);
1118                         }
1119                         continue;
1120                 } else if (cc == 0)
1121                         continue;
1122
1123                 m.msg_name = (caddr_t)&from;
1124                 m.msg_namelen = sizeof(from);
1125                 memset(&iov, 0, sizeof(iov));
1126                 iov[0].iov_base = (caddr_t)packet;
1127                 iov[0].iov_len = packlen;
1128                 m.msg_iov = iov;
1129                 m.msg_iovlen = 1;
1130                 cm = (struct cmsghdr *)buf;
1131                 m.msg_control = (caddr_t)buf;
1132                 m.msg_controllen = sizeof(buf);
1133
1134                 cc = recvmsg(s, &m, 0);
1135                 if (cc < 0) {
1136                         if (errno != EINTR) {
1137                                 warn("recvmsg");
1138                                 sleep(1);
1139                         }
1140                         continue;
1141                 } else if (cc == 0) {
1142                         int mtu;
1143
1144                         /*
1145                          * receive control messages only. Process the
1146                          * exceptions (currently the only possiblity is
1147                          * a path MTU notification.)
1148                          */
1149                         if ((mtu = get_pathmtu(&m)) > 0) {
1150                                 if ((options & F_VERBOSE) != 0) {
1151                                         printf("new path MTU (%d) is "
1152                                             "notified\n", mtu);
1153                                 }
1154                         }
1155                         continue;
1156                 } else {
1157                         /*
1158                          * an ICMPv6 message (probably an echoreply) arrived.
1159                          */
1160                         pr_pack(packet, cc, &m);
1161                 }
1162                 if (npackets && nreceived >= npackets)
1163                         break;
1164         }
1165         summary();
1166         exit(nreceived == 0);
1167 }
1168
1169 void
1170 onsignal(sig)
1171         int sig;
1172 {
1173
1174         switch (sig) {
1175         case SIGALRM:
1176                 seenalrm++;
1177                 break;
1178         case SIGINT:
1179                 seenint++;
1180                 break;
1181 #ifdef SIGINFO
1182         case SIGINFO:
1183                 seeninfo++;
1184                 break;
1185 #endif
1186         }
1187 }
1188
1189 /*
1190  * retransmit --
1191  *      This routine transmits another ping6.
1192  */
1193 void
1194 retransmit()
1195 {
1196         struct itimerval itimer;
1197
1198         if (pinger() == 0)
1199                 return;
1200
1201         /*
1202          * If we're not transmitting any more packets, change the timer
1203          * to wait two round-trip times if we've received any packets or
1204          * ten seconds if we haven't.
1205          */
1206 #define MAXWAIT         10
1207         if (nreceived) {
1208                 itimer.it_value.tv_sec =  2 * tmax / 1000;
1209                 if (itimer.it_value.tv_sec == 0)
1210                         itimer.it_value.tv_sec = 1;
1211         } else
1212                 itimer.it_value.tv_sec = MAXWAIT;
1213         itimer.it_interval.tv_sec = 0;
1214         itimer.it_interval.tv_usec = 0;
1215         itimer.it_value.tv_usec = 0;
1216
1217         (void)signal(SIGALRM, onint);
1218         (void)setitimer(ITIMER_REAL, &itimer, NULL);
1219 }
1220
1221 /*
1222  * pinger --
1223  *      Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
1224  * will be added on by the kernel.  The ID field is our UNIX process ID,
1225  * and the sequence number is an ascending integer.  The first 8 bytes
1226  * of the data portion are used to hold a UNIX "timeval" struct in VAX
1227  * byte-order, to compute the round-trip time.
1228  */
1229 size_t
1230 pingerlen()
1231 {
1232         size_t l;
1233
1234         if (options & F_FQDN)
1235                 l = ICMP6_NIQLEN + sizeof(dst.sin6_addr);
1236         else if (options & F_FQDNOLD)
1237                 l = ICMP6_NIQLEN;
1238         else if (options & F_NODEADDR)
1239                 l = ICMP6_NIQLEN + sizeof(dst.sin6_addr);
1240         else if (options & F_SUPTYPES)
1241                 l = ICMP6_NIQLEN;
1242         else
1243                 l = ICMP6ECHOLEN + datalen;
1244
1245         return l;
1246 }
1247
1248 int
1249 pinger()
1250 {
1251         struct icmp6_hdr *icp;
1252         struct iovec iov[2];
1253         int i, cc;
1254         struct icmp6_nodeinfo *nip;
1255         int seq;
1256
1257         if (npackets && ntransmitted >= npackets)
1258                 return(-1);     /* no more transmission */
1259
1260         icp = (struct icmp6_hdr *)outpack;
1261         nip = (struct icmp6_nodeinfo *)outpack;
1262         memset(icp, 0, sizeof(*icp));
1263         icp->icmp6_cksum = 0;
1264         seq = ntransmitted++;
1265         CLR(seq % mx_dup_ck);
1266
1267         if (options & F_FQDN) {
1268                 icp->icmp6_type = ICMP6_NI_QUERY;
1269                 icp->icmp6_code = ICMP6_NI_SUBJ_IPV6;
1270                 nip->ni_qtype = htons(NI_QTYPE_FQDN);
1271                 nip->ni_flags = htons(0);
1272
1273                 memcpy(nip->icmp6_ni_nonce, nonce,
1274                     sizeof(nip->icmp6_ni_nonce));
1275                 *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq);
1276
1277                 memcpy(&outpack[ICMP6_NIQLEN], &dst.sin6_addr,
1278                     sizeof(dst.sin6_addr));
1279                 cc = ICMP6_NIQLEN + sizeof(dst.sin6_addr);
1280                 datalen = 0;
1281         } else if (options & F_FQDNOLD) {
1282                 /* packet format in 03 draft - no Subject data on queries */
1283                 icp->icmp6_type = ICMP6_NI_QUERY;
1284                 icp->icmp6_code = 0;    /* code field is always 0 */
1285                 nip->ni_qtype = htons(NI_QTYPE_FQDN);
1286                 nip->ni_flags = htons(0);
1287
1288                 memcpy(nip->icmp6_ni_nonce, nonce,
1289                     sizeof(nip->icmp6_ni_nonce));
1290                 *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq);
1291
1292                 cc = ICMP6_NIQLEN;
1293                 datalen = 0;
1294         } else if (options & F_NODEADDR) {
1295                 icp->icmp6_type = ICMP6_NI_QUERY;
1296                 icp->icmp6_code = ICMP6_NI_SUBJ_IPV6;
1297                 nip->ni_qtype = htons(NI_QTYPE_NODEADDR);
1298                 nip->ni_flags = naflags;
1299
1300                 memcpy(nip->icmp6_ni_nonce, nonce,
1301                     sizeof(nip->icmp6_ni_nonce));
1302                 *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq);
1303
1304                 memcpy(&outpack[ICMP6_NIQLEN], &dst.sin6_addr,
1305                     sizeof(dst.sin6_addr));
1306                 cc = ICMP6_NIQLEN + sizeof(dst.sin6_addr);
1307                 datalen = 0;
1308         } else if (options & F_SUPTYPES) {
1309                 icp->icmp6_type = ICMP6_NI_QUERY;
1310                 icp->icmp6_code = ICMP6_NI_SUBJ_FQDN;   /*empty*/
1311                 nip->ni_qtype = htons(NI_QTYPE_SUPTYPES);
1312                 /* we support compressed bitmap */
1313                 nip->ni_flags = NI_SUPTYPE_FLAG_COMPRESS;
1314
1315                 memcpy(nip->icmp6_ni_nonce, nonce,
1316                     sizeof(nip->icmp6_ni_nonce));
1317                 *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq);
1318                 cc = ICMP6_NIQLEN;
1319                 datalen = 0;
1320         } else {
1321                 icp->icmp6_type = ICMP6_ECHO_REQUEST;
1322                 icp->icmp6_code = 0;
1323                 icp->icmp6_id = htons(ident);
1324                 icp->icmp6_seq = ntohs(seq);
1325                 if (timing) {
1326                         struct timeval tv;
1327                         struct tv32 *tv32;
1328                         (void)gettimeofday(&tv, NULL);
1329                         tv32 = (struct tv32 *)&outpack[ICMP6ECHOLEN];
1330                         tv32->tv32_sec = htonl(tv.tv_sec);
1331                         tv32->tv32_usec = htonl(tv.tv_usec);
1332                 }
1333                 cc = ICMP6ECHOLEN + datalen;
1334         }
1335
1336 #ifdef DIAGNOSTIC
1337         if (pingerlen() != cc)
1338                 errx(1, "internal error; length mismatch");
1339 #endif
1340
1341         smsghdr.msg_name = (caddr_t)&dst;
1342         smsghdr.msg_namelen = sizeof(dst);
1343         memset(&iov, 0, sizeof(iov));
1344         iov[0].iov_base = (caddr_t)outpack;
1345         iov[0].iov_len = cc;
1346         smsghdr.msg_iov = iov;
1347         smsghdr.msg_iovlen = 1;
1348
1349         i = sendmsg(s, &smsghdr, 0);
1350
1351         if (i < 0 || i != cc)  {
1352                 if (i < 0)
1353                         warn("sendmsg");
1354                 (void)printf("ping6: wrote %s %d chars, ret=%d\n",
1355                     hostname, cc, i);
1356         }
1357         if (!(options & F_QUIET) && options & F_FLOOD)
1358                 (void)write(STDOUT_FILENO, &DOT, 1);
1359
1360         return(0);
1361 }
1362
1363 int
1364 myechoreply(icp)
1365         const struct icmp6_hdr *icp;
1366 {
1367         if (ntohs(icp->icmp6_id) == ident)
1368                 return 1;
1369         else
1370                 return 0;
1371 }
1372
1373 int
1374 mynireply(nip)
1375         const struct icmp6_nodeinfo *nip;
1376 {
1377         if (memcmp(nip->icmp6_ni_nonce + sizeof(u_int16_t),
1378             nonce + sizeof(u_int16_t),
1379             sizeof(nonce) - sizeof(u_int16_t)) == 0)
1380                 return 1;
1381         else
1382                 return 0;
1383 }
1384
1385 char *
1386 dnsdecode(sp, ep, base, buf, bufsiz)
1387         const u_char **sp;
1388         const u_char *ep;
1389         const u_char *base;     /*base for compressed name*/
1390         char *buf;
1391         size_t bufsiz;
1392 {
1393         int i;
1394         const u_char *cp;
1395         char cresult[MAXDNAME + 1];
1396         const u_char *comp;
1397         int l;
1398
1399         cp = *sp;
1400         *buf = '\0';
1401
1402         if (cp >= ep)
1403                 return NULL;
1404         while (cp < ep) {
1405                 i = *cp;
1406                 if (i == 0 || cp != *sp) {
1407                         if (strlcat((char *)buf, ".", bufsiz) >= bufsiz)
1408                                 return NULL;    /*result overrun*/
1409                 }
1410                 if (i == 0)
1411                         break;
1412                 cp++;
1413
1414                 if ((i & 0xc0) == 0xc0 && cp - base > (i & 0x3f)) {
1415                         /* DNS compression */
1416                         if (!base)
1417                                 return NULL;
1418
1419                         comp = base + (i & 0x3f);
1420                         if (dnsdecode(&comp, cp, base, cresult,
1421                             sizeof(cresult)) == NULL)
1422                                 return NULL;
1423                         if (strlcat(buf, cresult, bufsiz) >= bufsiz)
1424                                 return NULL;    /*result overrun*/
1425                         break;
1426                 } else if ((i & 0x3f) == i) {
1427                         if (i > ep - cp)
1428                                 return NULL;    /*source overrun*/
1429                         while (i-- > 0 && cp < ep) {
1430                                 l = snprintf(cresult, sizeof(cresult),
1431                                     isprint(*cp) ? "%c" : "\\%03o", *cp & 0xff);
1432                                 if (l >= sizeof(cresult) || l < 0)
1433                                         return NULL;
1434                                 if (strlcat(buf, cresult, bufsiz) >= bufsiz)
1435                                         return NULL;    /*result overrun*/
1436                                 cp++;
1437                         }
1438                 } else
1439                         return NULL;    /*invalid label*/
1440         }
1441         if (i != 0)
1442                 return NULL;    /*not terminated*/
1443         cp++;
1444         *sp = cp;
1445         return buf;
1446 }
1447
1448 /*
1449  * pr_pack --
1450  *      Print out the packet, if it came from us.  This logic is necessary
1451  * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
1452  * which arrive ('tis only fair).  This permits multiple copies of this
1453  * program to be run without having intermingled output (or statistics!).
1454  */
1455 void
1456 pr_pack(buf, cc, mhdr)
1457         u_char *buf;
1458         int cc;
1459         struct msghdr *mhdr;
1460 {
1461 #define safeputc(c)     printf((isprint((c)) ? "%c" : "\\%03o"), c)
1462         struct icmp6_hdr *icp;
1463         struct icmp6_nodeinfo *ni;
1464         int i;
1465         int hoplim;
1466         struct sockaddr *from;
1467         int fromlen;
1468         u_char *cp = NULL, *dp, *end = buf + cc;
1469         struct in6_pktinfo *pktinfo = NULL;
1470         struct timeval tv, tp;
1471         struct tv32 *tpp;
1472         double triptime = 0;
1473         int dupflag;
1474         size_t off;
1475         int oldfqdn;
1476         u_int16_t seq;
1477         char dnsname[MAXDNAME + 1];
1478
1479         (void)gettimeofday(&tv, NULL);
1480
1481         if (!mhdr || !mhdr->msg_name ||
1482             mhdr->msg_namelen != sizeof(struct sockaddr_in6) ||
1483             ((struct sockaddr *)mhdr->msg_name)->sa_family != AF_INET6) {
1484                 if (options & F_VERBOSE)
1485                         warnx("invalid peername");
1486                 return;
1487         }
1488         from = (struct sockaddr *)mhdr->msg_name;
1489         fromlen = mhdr->msg_namelen;
1490         if (cc < sizeof(struct icmp6_hdr)) {
1491                 if (options & F_VERBOSE)
1492                         warnx("packet too short (%d bytes) from %s", cc,
1493                             pr_addr(from, fromlen));
1494                 return;
1495         }
1496         icp = (struct icmp6_hdr *)buf;
1497         ni = (struct icmp6_nodeinfo *)buf;
1498         off = 0;
1499
1500         if ((hoplim = get_hoplim(mhdr)) == -1) {
1501                 warnx("failed to get receiving hop limit");
1502                 return;
1503         }
1504         if ((pktinfo = get_rcvpktinfo(mhdr)) == NULL) {
1505                 warnx("failed to get receiving packet information");
1506                 return;
1507         }
1508
1509         if (icp->icmp6_type == ICMP6_ECHO_REPLY && myechoreply(icp)) {
1510                 seq = ntohs(icp->icmp6_seq);
1511                 ++nreceived;
1512                 if (timing) {
1513                         tpp = (struct tv32 *)(icp + 1);
1514                         tp.tv_sec = ntohl(tpp->tv32_sec);
1515                         tp.tv_usec = ntohl(tpp->tv32_usec);
1516                         tvsub(&tv, &tp);
1517                         triptime = ((double)tv.tv_sec) * 1000.0 +
1518                             ((double)tv.tv_usec) / 1000.0;
1519                         tsum += triptime;
1520                         tsumsq += triptime * triptime;
1521                         if (triptime < tmin)
1522                                 tmin = triptime;
1523                         if (triptime > tmax)
1524                                 tmax = triptime;
1525                 }
1526
1527                 if (TST(seq % mx_dup_ck)) {
1528                         ++nrepeats;
1529                         --nreceived;
1530                         dupflag = 1;
1531                 } else {
1532                         SET(seq % mx_dup_ck);
1533                         dupflag = 0;
1534                 }
1535
1536                 if (options & F_QUIET)
1537                         return;
1538
1539                 if (options & F_FLOOD)
1540                         (void)write(STDOUT_FILENO, &BSPACE, 1);
1541                 else {
1542                         (void)printf("%d bytes from %s, icmp_seq=%u", cc,
1543                             pr_addr(from, fromlen), seq);
1544                         (void)printf(" hlim=%d", hoplim);
1545                         if ((options & F_VERBOSE) != 0) {
1546                                 struct sockaddr_in6 dstsa;
1547
1548                                 memset(&dstsa, 0, sizeof(dstsa));
1549                                 dstsa.sin6_family = AF_INET6;
1550                                 dstsa.sin6_len = sizeof(dstsa);
1551                                 dstsa.sin6_scope_id = pktinfo->ipi6_ifindex;
1552                                 dstsa.sin6_addr = pktinfo->ipi6_addr;
1553                                 (void)printf(" dst=%s",
1554                                     pr_addr((struct sockaddr *)&dstsa,
1555                                     sizeof(dstsa)));
1556                         }
1557                         if (timing)
1558                                 (void)printf(" time=%.3f ms", triptime);
1559                         if (dupflag)
1560                                 (void)printf("(DUP!)");
1561                         /* check the data */
1562                         cp = buf + off + ICMP6ECHOLEN + ICMP6ECHOTMLEN;
1563                         dp = outpack + ICMP6ECHOLEN + ICMP6ECHOTMLEN;
1564                         for (i = 8; cp < end; ++i, ++cp, ++dp) {
1565                                 if (*cp != *dp) {
1566                                         (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", i, *dp, *cp);
1567                                         break;
1568                                 }
1569                         }
1570                 }
1571         } else if (icp->icmp6_type == ICMP6_NI_REPLY && mynireply(ni)) {
1572                 seq = ntohs(*(u_int16_t *)ni->icmp6_ni_nonce);
1573                 ++nreceived;
1574                 if (TST(seq % mx_dup_ck)) {
1575                         ++nrepeats;
1576                         --nreceived;
1577                         dupflag = 1;
1578                 } else {
1579                         SET(seq % mx_dup_ck);
1580                         dupflag = 0;
1581                 }
1582
1583                 if (options & F_QUIET)
1584                         return;
1585
1586                 (void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen));
1587
1588                 switch (ntohs(ni->ni_code)) {
1589                 case ICMP6_NI_SUCCESS:
1590                         break;
1591                 case ICMP6_NI_REFUSED:
1592                         printf("refused, type 0x%x", ntohs(ni->ni_type));
1593                         goto fqdnend;
1594                 case ICMP6_NI_UNKNOWN:
1595                         printf("unknown, type 0x%x", ntohs(ni->ni_type));
1596                         goto fqdnend;
1597                 default:
1598                         printf("unknown code 0x%x, type 0x%x",
1599                             ntohs(ni->ni_code), ntohs(ni->ni_type));
1600                         goto fqdnend;
1601                 }
1602
1603                 switch (ntohs(ni->ni_qtype)) {
1604                 case NI_QTYPE_NOOP:
1605                         printf("NodeInfo NOOP");
1606                         break;
1607                 case NI_QTYPE_SUPTYPES:
1608                         pr_suptypes(ni, end - (u_char *)ni);
1609                         break;
1610                 case NI_QTYPE_NODEADDR:
1611                         pr_nodeaddr(ni, end - (u_char *)ni);
1612                         break;
1613                 case NI_QTYPE_FQDN:
1614                 default:        /* XXX: for backward compatibility */
1615                         cp = (u_char *)ni + ICMP6_NIRLEN;
1616                         if (buf[off + ICMP6_NIRLEN] ==
1617                             cc - off - ICMP6_NIRLEN - 1)
1618                                 oldfqdn = 1;
1619                         else
1620                                 oldfqdn = 0;
1621                         if (oldfqdn) {
1622                                 cp++;   /* skip length */
1623                                 while (cp < end) {
1624                                         safeputc(*cp & 0xff);
1625                                         cp++;
1626                                 }
1627                         } else {
1628                                 i = 0;
1629                                 while (cp < end) {
1630                                         if (dnsdecode((const u_char **)&cp, end,
1631                                             (const u_char *)(ni + 1), dnsname,
1632                                             sizeof(dnsname)) == NULL) {
1633                                                 printf("???");
1634                                                 break;
1635                                         }
1636                                         /*
1637                                          * name-lookup special handling for
1638                                          * truncated name
1639                                          */
1640                                         if (cp + 1 <= end && !*cp &&
1641                                             strlen(dnsname) > 0) {
1642                                                 dnsname[strlen(dnsname) - 1] = '\0';
1643                                                 cp++;
1644                                         }
1645                                         printf("%s%s", i > 0 ? "," : "",
1646                                             dnsname);
1647                                 }
1648                         }
1649                         if (options & F_VERBOSE) {
1650                                 int32_t ttl;
1651                                 int comma = 0;
1652
1653                                 (void)printf(" (");     /*)*/
1654
1655                                 switch (ni->ni_code) {
1656                                 case ICMP6_NI_REFUSED:
1657                                         (void)printf("refused");
1658                                         comma++;
1659                                         break;
1660                                 case ICMP6_NI_UNKNOWN:
1661                                         (void)printf("unknown qtype");
1662                                         comma++;
1663                                         break;
1664                                 }
1665
1666                                 if ((end - (u_char *)ni) < ICMP6_NIRLEN) {
1667                                         /* case of refusion, unknown */
1668                                         /*(*/
1669                                         putchar(')');
1670                                         goto fqdnend;
1671                                 }
1672                                 ttl = (int32_t)ntohl(*(u_long *)&buf[off+ICMP6ECHOLEN+8]);
1673                                 if (comma)
1674                                         printf(",");
1675                                 if (!(ni->ni_flags & NI_FQDN_FLAG_VALIDTTL)) {
1676                                         (void)printf("TTL=%d:meaningless",
1677                                             (int)ttl);
1678                                 } else {
1679                                         if (ttl < 0) {
1680                                                 (void)printf("TTL=%d:invalid",
1681                                                    ttl);
1682                                         } else
1683                                                 (void)printf("TTL=%d", ttl);
1684                                 }
1685                                 comma++;
1686
1687                                 if (oldfqdn) {
1688                                         if (comma)
1689                                                 printf(",");
1690                                         printf("03 draft");
1691                                         comma++;
1692                                 } else {
1693                                         cp = (u_char *)ni + ICMP6_NIRLEN;
1694                                         if (cp == end) {
1695                                                 if (comma)
1696                                                         printf(",");
1697                                                 printf("no name");
1698                                                 comma++;
1699                                         }
1700                                 }
1701
1702                                 if (buf[off + ICMP6_NIRLEN] !=
1703                                     cc - off - ICMP6_NIRLEN - 1 && oldfqdn) {
1704                                         if (comma)
1705                                                 printf(",");
1706                                         (void)printf("invalid namelen:%d/%lu",
1707                                             buf[off + ICMP6_NIRLEN],
1708                                             (u_long)cc - off - ICMP6_NIRLEN - 1);
1709                                         comma++;
1710                                 }
1711                                 /*(*/
1712                                 putchar(')');
1713                         }
1714                 fqdnend:
1715                         ;
1716                 }
1717         } else {
1718                 /* We've got something other than an ECHOREPLY */
1719                 if (!(options & F_VERBOSE))
1720                         return;
1721                 (void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen));
1722                 pr_icmph(icp, end);
1723         }
1724
1725         if (!(options & F_FLOOD)) {
1726                 (void)putchar('\n');
1727                 if (options & F_VERBOSE)
1728                         pr_exthdrs(mhdr);
1729                 (void)fflush(stdout);
1730         }
1731 #undef safeputc
1732 }
1733
1734 void
1735 pr_exthdrs(mhdr)
1736         struct msghdr *mhdr;
1737 {
1738         struct cmsghdr *cm;
1739
1740         for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
1741              cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
1742                 if (cm->cmsg_level != IPPROTO_IPV6)
1743                         continue;
1744
1745                 switch (cm->cmsg_type) {
1746                 case IPV6_HOPOPTS:
1747                         printf("  HbH Options: ");
1748                         pr_ip6opt(CMSG_DATA(cm));
1749                         break;
1750                 case IPV6_DSTOPTS:
1751 #ifdef IPV6_RTHDRDSTOPTS
1752                 case IPV6_RTHDRDSTOPTS:
1753 #endif
1754                         printf("  Dst Options: ");
1755                         pr_ip6opt(CMSG_DATA(cm));
1756                         break;
1757                 case IPV6_RTHDR:
1758                         printf("  Routing: ");
1759                         pr_rthdr(CMSG_DATA(cm));
1760                         break;
1761                 }
1762         }
1763 }
1764
1765 #ifdef USE_RFC2292BIS
1766 void
1767 pr_ip6opt(void *extbuf)
1768 {
1769         struct ip6_hbh *ext;
1770         int currentlen;
1771         u_int8_t type;
1772         socklen_t extlen, len;
1773         void *databuf;
1774         size_t offset;
1775         u_int16_t value2;
1776         u_int32_t value4;
1777
1778         ext = (struct ip6_hbh *)extbuf;
1779         extlen = (ext->ip6h_len + 1) * 8;
1780         printf("nxt %u, len %u (%lu bytes)\n", ext->ip6h_nxt,
1781             (unsigned int)ext->ip6h_len, (unsigned long)extlen);
1782
1783         currentlen = 0;
1784         while (1) {
1785                 currentlen = inet6_opt_next(extbuf, extlen, currentlen,
1786                     &type, &len, &databuf);
1787                 if (currentlen == -1)
1788                         break;
1789                 switch (type) {
1790                 /*
1791                  * Note that inet6_opt_next automatically skips any padding
1792                  * optins.
1793                  */
1794                 case IP6OPT_JUMBO:
1795                         offset = 0;
1796                         offset = inet6_opt_get_val(databuf, offset,
1797                             &value4, sizeof(value4));
1798                         printf("    Jumbo Payload Opt: Length %u\n",
1799                             (u_int32_t)ntohl(value4));
1800                         break;
1801                 case IP6OPT_ROUTER_ALERT:
1802                         offset = 0;
1803                         offset = inet6_opt_get_val(databuf, offset,
1804                                                    &value2, sizeof(value2));
1805                         printf("    Router Alert Opt: Type %u\n",
1806                             ntohs(value2));
1807                         break;
1808                 default:
1809                         printf("    Received Opt %u len %lu\n",
1810                             type, (unsigned long)len);
1811                         break;
1812                 }
1813         }
1814         return;
1815 }
1816 #else  /* !USE_RFC2292BIS */
1817 /* ARGSUSED */
1818 void
1819 pr_ip6opt(void *extbuf)
1820 {
1821         putchar('\n');
1822         return;
1823 }
1824 #endif /* USE_RFC2292BIS */
1825
1826 #ifdef USE_RFC2292BIS
1827 void
1828 pr_rthdr(void *extbuf)
1829 {
1830         struct in6_addr *in6;
1831         char ntopbuf[INET6_ADDRSTRLEN];
1832         struct ip6_rthdr *rh = (struct ip6_rthdr *)extbuf;
1833         int i, segments;
1834
1835         /* print fixed part of the header */
1836         printf("nxt %u, len %u (%d bytes), type %u, ", rh->ip6r_nxt,
1837             rh->ip6r_len, (rh->ip6r_len + 1) << 3, rh->ip6r_type);
1838         if ((segments = inet6_rth_segments(extbuf)) >= 0)
1839                 printf("%d segments, ", segments);
1840         else
1841                 printf("segments unknown, ");
1842         printf("%d left\n", rh->ip6r_segleft);
1843
1844         for (i = 0; i < segments; i++) {
1845                 in6 = inet6_rth_getaddr(extbuf, i);
1846                 if (in6 == NULL)
1847                         printf("   [%d]<NULL>\n", i);
1848                 else {
1849                         if (!inet_ntop(AF_INET6, in6, ntopbuf,
1850                             sizeof(ntopbuf)))
1851                                 strlcpy(ntopbuf, "?", sizeof(ntopbuf));
1852                         printf("   [%d]%s\n", i, ntopbuf);
1853                 }
1854         }
1855
1856         return;
1857
1858 }
1859
1860 #else  /* !USE_RFC2292BIS */
1861 /* ARGSUSED */
1862 void
1863 pr_rthdr(void *extbuf)
1864 {
1865         putchar('\n');
1866         return;
1867 }
1868 #endif /* USE_RFC2292BIS */
1869
1870 int
1871 pr_bitrange(v, soff, ii)
1872         u_int32_t v;
1873         int soff;
1874         int ii;
1875 {
1876         int off;
1877         int i;
1878
1879         off = 0;
1880         while (off < 32) {
1881                 /* shift till we have 0x01 */
1882                 if ((v & 0x01) == 0) {
1883                         if (ii > 1)
1884                                 printf("-%u", soff + off - 1);
1885                         ii = 0;
1886                         switch (v & 0x0f) {
1887                         case 0x00:
1888                                 v >>= 4;
1889                                 off += 4;
1890                                 continue;
1891                         case 0x08:
1892                                 v >>= 3;
1893                                 off += 3;
1894                                 continue;
1895                         case 0x04: case 0x0c:
1896                                 v >>= 2;
1897                                 off += 2;
1898                                 continue;
1899                         default:
1900                                 v >>= 1;
1901                                 off += 1;
1902                                 continue;
1903                         }
1904                 }
1905
1906                 /* we have 0x01 with us */
1907                 for (i = 0; i < 32 - off; i++) {
1908                         if ((v & (0x01 << i)) == 0)
1909                                 break;
1910                 }
1911                 if (!ii)
1912                         printf(" %u", soff + off);
1913                 ii += i;
1914                 v >>= i; off += i;
1915         }
1916         return ii;
1917 }
1918
1919 void
1920 pr_suptypes(ni, nilen)
1921         struct icmp6_nodeinfo *ni; /* ni->qtype must be SUPTYPES */
1922         size_t nilen;
1923 {
1924         size_t clen;
1925         u_int32_t v;
1926         const u_char *cp, *end;
1927         u_int16_t cur;
1928         struct cbit {
1929                 u_int16_t words;        /*32bit count*/
1930                 u_int16_t skip;
1931         } cbit;
1932 #define MAXQTYPES       (1 << 16)
1933         size_t off;
1934         int b;
1935
1936         cp = (u_char *)(ni + 1);
1937         end = ((u_char *)ni) + nilen;
1938         cur = 0;
1939         b = 0;
1940
1941         printf("NodeInfo Supported Qtypes");
1942         if (options & F_VERBOSE) {
1943                 if (ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS)
1944                         printf(", compressed bitmap");
1945                 else
1946                         printf(", raw bitmap");
1947         }
1948
1949         while (cp < end) {
1950                 clen = (size_t)(end - cp);
1951                 if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) == 0) {
1952                         if (clen == 0 || clen > MAXQTYPES / 8 ||
1953                             clen % sizeof(v)) {
1954                                 printf("???");
1955                                 return;
1956                         }
1957                 } else {
1958                         if (clen < sizeof(cbit) || clen % sizeof(v))
1959                                 return;
1960                         memcpy(&cbit, cp, sizeof(cbit));
1961                         if (sizeof(cbit) + ntohs(cbit.words) * sizeof(v) >
1962                             clen)
1963                                 return;
1964                         cp += sizeof(cbit);
1965                         clen = ntohs(cbit.words) * sizeof(v);
1966                         if (cur + clen * 8 + (u_long)ntohs(cbit.skip) * 32 >
1967                             MAXQTYPES)
1968                                 return;
1969                 }
1970
1971                 for (off = 0; off < clen; off += sizeof(v)) {
1972                         memcpy(&v, cp + off, sizeof(v));
1973                         v = (u_int32_t)ntohl(v);
1974                         b = pr_bitrange(v, (int)(cur + off * 8), b);
1975                 }
1976                 /* flush the remaining bits */
1977                 b = pr_bitrange(0, (int)(cur + off * 8), b);
1978
1979                 cp += clen;
1980                 cur += clen * 8;
1981                 if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) != 0)
1982                         cur += ntohs(cbit.skip) * 32;
1983         }
1984 }
1985
1986 void
1987 pr_nodeaddr(ni, nilen)
1988         struct icmp6_nodeinfo *ni; /* ni->qtype must be NODEADDR */
1989         int nilen;
1990 {
1991         u_char *cp = (u_char *)(ni + 1);
1992         char ntop_buf[INET6_ADDRSTRLEN];
1993         int withttl = 0;
1994
1995         nilen -= sizeof(struct icmp6_nodeinfo);
1996
1997         if (options & F_VERBOSE) {
1998                 switch (ni->ni_code) {
1999                 case ICMP6_NI_REFUSED:
2000                         (void)printf("refused");
2001                         break;
2002                 case ICMP6_NI_UNKNOWN:
2003                         (void)printf("unknown qtype");
2004                         break;
2005                 }
2006                 if (ni->ni_flags & NI_NODEADDR_FLAG_TRUNCATE)
2007                         (void)printf(" truncated");
2008         }
2009         putchar('\n');
2010         if (nilen <= 0)
2011                 printf("  no address\n");
2012
2013         /*
2014          * In icmp-name-lookups 05 and later, TTL of each returned address
2015          * is contained in the resposne. We try to detect the version
2016          * by the length of the data, but note that the detection algorithm
2017          * is incomplete. We assume the latest draft by default.
2018          */
2019         if (nilen % (sizeof(u_int32_t) + sizeof(struct in6_addr)) == 0)
2020                 withttl = 1;
2021         while (nilen > 0) {
2022                 u_int32_t ttl;
2023
2024                 if (withttl) {
2025                         /* XXX: alignment? */
2026                         ttl = (u_int32_t)ntohl(*(u_int32_t *)cp);
2027                         cp += sizeof(u_int32_t);
2028                         nilen -= sizeof(u_int32_t);
2029                 }
2030
2031                 if (inet_ntop(AF_INET6, cp, ntop_buf, sizeof(ntop_buf)) ==
2032                     NULL)
2033                         strlcpy(ntop_buf, "?", sizeof(ntop_buf));
2034                 printf("  %s", ntop_buf);
2035                 if (withttl) {
2036                         if (ttl == 0xffffffff) {
2037                                 /*
2038                                  * XXX: can this convention be applied to all
2039                                  * type of TTL (i.e. non-ND TTL)?
2040                                  */
2041                                 printf("(TTL=infty)");
2042                         }
2043                         else
2044                                 printf("(TTL=%u)", ttl);
2045                 }
2046                 putchar('\n');
2047
2048                 nilen -= sizeof(struct in6_addr);
2049                 cp += sizeof(struct in6_addr);
2050         }
2051 }
2052
2053 int
2054 get_hoplim(mhdr)
2055         struct msghdr *mhdr;
2056 {
2057         struct cmsghdr *cm;
2058
2059         for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
2060              cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
2061                 if (cm->cmsg_len == 0)
2062                         return(-1);
2063
2064                 if (cm->cmsg_level == IPPROTO_IPV6 &&
2065                     cm->cmsg_type == IPV6_HOPLIMIT &&
2066                     cm->cmsg_len == CMSG_LEN(sizeof(int)))
2067                         return(*(int *)CMSG_DATA(cm));
2068         }
2069
2070         return(-1);
2071 }
2072
2073 struct in6_pktinfo *
2074 get_rcvpktinfo(mhdr)
2075         struct msghdr *mhdr;
2076 {
2077         struct cmsghdr *cm;
2078
2079         for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
2080              cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
2081                 if (cm->cmsg_len == 0)
2082                         return(NULL);
2083
2084                 if (cm->cmsg_level == IPPROTO_IPV6 &&
2085                     cm->cmsg_type == IPV6_PKTINFO &&
2086                     cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo)))
2087                         return((struct in6_pktinfo *)CMSG_DATA(cm));
2088         }
2089
2090         return(NULL);
2091 }
2092
2093 int
2094 get_pathmtu(mhdr)
2095         struct msghdr *mhdr;
2096 {
2097 #ifdef IPV6_RECVPATHMTU
2098         struct cmsghdr *cm;
2099         struct ip6_mtuinfo *mtuctl = NULL;
2100
2101         for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
2102              cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
2103                 if (cm->cmsg_len == 0)
2104                         return(0);
2105
2106                 if (cm->cmsg_level == IPPROTO_IPV6 &&
2107                     cm->cmsg_type == IPV6_PATHMTU &&
2108                     cm->cmsg_len == CMSG_LEN(sizeof(struct ip6_mtuinfo))) {
2109                         mtuctl = (struct ip6_mtuinfo *)CMSG_DATA(cm);
2110
2111                         /*
2112                          * If the notified destination is different from
2113                          * the one we are pinging, just ignore the info.
2114                          * We check the scope ID only when both notified value
2115                          * and our own value have non-0 values, because we may
2116                          * have used the default scope zone ID for sending,
2117                          * in which case the scope ID value is 0.
2118                          */
2119                         if (!IN6_ARE_ADDR_EQUAL(&mtuctl->ip6m_addr.sin6_addr,
2120                                                 &dst.sin6_addr) ||
2121                             (mtuctl->ip6m_addr.sin6_scope_id &&
2122                              dst.sin6_scope_id &&
2123                              mtuctl->ip6m_addr.sin6_scope_id !=
2124                              dst.sin6_scope_id)) {
2125                                 if ((options & F_VERBOSE) != 0) {
2126                                         printf("path MTU for %s is notified. "
2127                                                "(ignored)\n",
2128                                            pr_addr((struct sockaddr *)&mtuctl->ip6m_addr,
2129                                            sizeof(mtuctl->ip6m_addr)));
2130                                 }
2131                                 return(0);
2132                         }
2133
2134                         /*
2135                          * Ignore an invalid MTU. XXX: can we just believe
2136                          * the kernel check?
2137                          */
2138                         if (mtuctl->ip6m_mtu < IPV6_MMTU)
2139                                 return(0);
2140
2141                         /* notification for our destination. return the MTU. */
2142                         return((int)mtuctl->ip6m_mtu);
2143                 }
2144         }
2145 #endif
2146         return(0);
2147 }
2148
2149 /*
2150  * tvsub --
2151  *      Subtract 2 timeval structs:  out = out - in.  Out is assumed to
2152  * be >= in.
2153  */
2154 void
2155 tvsub(out, in)
2156         struct timeval *out, *in;
2157 {
2158         if ((out->tv_usec -= in->tv_usec) < 0) {
2159                 --out->tv_sec;
2160                 out->tv_usec += 1000000;
2161         }
2162         out->tv_sec -= in->tv_sec;
2163 }
2164
2165 /*
2166  * onint --
2167  *      SIGINT handler.
2168  */
2169 /* ARGSUSED */
2170 void
2171 onint(notused)
2172         int notused;
2173 {
2174         summary();
2175
2176         (void)signal(SIGINT, SIG_DFL);
2177         (void)kill(getpid(), SIGINT);
2178
2179         /* NOTREACHED */
2180         exit(1);
2181 }
2182
2183 /*
2184  * summary --
2185  *      Print out statistics.
2186  */
2187 void
2188 summary()
2189 {
2190
2191         (void)printf("\n--- %s ping6 statistics ---\n", hostname);
2192         (void)printf("%ld packets transmitted, ", ntransmitted);
2193         (void)printf("%ld packets received, ", nreceived);
2194         if (nrepeats)
2195                 (void)printf("+%ld duplicates, ", nrepeats);
2196         if (ntransmitted) {
2197                 if (nreceived > ntransmitted)
2198                         (void)printf("-- somebody's duplicating packets!");
2199                 else
2200                         (void)printf("%.1f%% packet loss",
2201                             ((((double)ntransmitted - nreceived) * 100.0) /
2202                             ntransmitted));
2203         }
2204         (void)putchar('\n');
2205         if (nreceived && timing) {
2206                 /* Only display average to microseconds */
2207                 double num = nreceived + nrepeats;
2208                 double avg = tsum / num;
2209                 double dev = sqrt(tsumsq / num - avg * avg);
2210                 (void)printf(
2211                     "round-trip min/avg/max/std-dev = %.3f/%.3f/%.3f/%.3f ms\n",
2212                     tmin, avg, tmax, dev);
2213                 (void)fflush(stdout);
2214         }
2215         (void)fflush(stdout);
2216 }
2217
2218 /*subject type*/
2219 static const char *niqcode[] = {
2220         "IPv6 address",
2221         "DNS label",    /*or empty*/
2222         "IPv4 address",
2223 };
2224
2225 /*result code*/
2226 static const char *nircode[] = {
2227         "Success", "Refused", "Unknown",
2228 };
2229
2230
2231 /*
2232  * pr_icmph --
2233  *      Print a descriptive string about an ICMP header.
2234  */
2235 void
2236 pr_icmph(icp, end)
2237         struct icmp6_hdr *icp;
2238         u_char *end;
2239 {
2240         char ntop_buf[INET6_ADDRSTRLEN];
2241         struct nd_redirect *red;
2242         struct icmp6_nodeinfo *ni;
2243         char dnsname[MAXDNAME + 1];
2244         const u_char *cp;
2245         size_t l;
2246
2247         switch (icp->icmp6_type) {
2248         case ICMP6_DST_UNREACH:
2249                 switch (icp->icmp6_code) {
2250                 case ICMP6_DST_UNREACH_NOROUTE:
2251                         (void)printf("No Route to Destination\n");
2252                         break;
2253                 case ICMP6_DST_UNREACH_ADMIN:
2254                         (void)printf("Destination Administratively "
2255                             "Unreachable\n");
2256                         break;
2257                 case ICMP6_DST_UNREACH_BEYONDSCOPE:
2258                         (void)printf("Destination Unreachable Beyond Scope\n");
2259                         break;
2260                 case ICMP6_DST_UNREACH_ADDR:
2261                         (void)printf("Destination Host Unreachable\n");
2262                         break;
2263                 case ICMP6_DST_UNREACH_NOPORT:
2264                         (void)printf("Destination Port Unreachable\n");
2265                         break;
2266                 default:
2267                         (void)printf("Destination Unreachable, Bad Code: %d\n",
2268                             icp->icmp6_code);
2269                         break;
2270                 }
2271                 /* Print returned IP header information */
2272                 pr_retip((struct ip6_hdr *)(icp + 1), end);
2273                 break;
2274         case ICMP6_PACKET_TOO_BIG:
2275                 (void)printf("Packet too big mtu = %d\n",
2276                     (int)ntohl(icp->icmp6_mtu));
2277                 pr_retip((struct ip6_hdr *)(icp + 1), end);
2278                 break;
2279         case ICMP6_TIME_EXCEEDED:
2280                 switch (icp->icmp6_code) {
2281                 case ICMP6_TIME_EXCEED_TRANSIT:
2282                         (void)printf("Time to live exceeded\n");
2283                         break;
2284                 case ICMP6_TIME_EXCEED_REASSEMBLY:
2285                         (void)printf("Frag reassembly time exceeded\n");
2286                         break;
2287                 default:
2288                         (void)printf("Time exceeded, Bad Code: %d\n",
2289                             icp->icmp6_code);
2290                         break;
2291                 }
2292                 pr_retip((struct ip6_hdr *)(icp + 1), end);
2293                 break;
2294         case ICMP6_PARAM_PROB:
2295                 (void)printf("Parameter problem: ");
2296                 switch (icp->icmp6_code) {
2297                 case ICMP6_PARAMPROB_HEADER:
2298                         (void)printf("Erroneous Header ");
2299                         break;
2300                 case ICMP6_PARAMPROB_NEXTHEADER:
2301                         (void)printf("Unknown Nextheader ");
2302                         break;
2303                 case ICMP6_PARAMPROB_OPTION:
2304                         (void)printf("Unrecognized Option ");
2305                         break;
2306                 default:
2307                         (void)printf("Bad code(%d) ", icp->icmp6_code);
2308                         break;
2309                 }
2310                 (void)printf("pointer = 0x%02x\n",
2311                     (u_int32_t)ntohl(icp->icmp6_pptr));
2312                 pr_retip((struct ip6_hdr *)(icp + 1), end);
2313                 break;
2314         case ICMP6_ECHO_REQUEST:
2315                 (void)printf("Echo Request");
2316                 /* XXX ID + Seq + Data */
2317                 break;
2318         case ICMP6_ECHO_REPLY:
2319                 (void)printf("Echo Reply");
2320                 /* XXX ID + Seq + Data */
2321                 break;
2322         case ICMP6_MEMBERSHIP_QUERY:
2323                 (void)printf("Listener Query");
2324                 break;
2325         case ICMP6_MEMBERSHIP_REPORT:
2326                 (void)printf("Listener Report");
2327                 break;
2328         case ICMP6_MEMBERSHIP_REDUCTION:
2329                 (void)printf("Listener Done");
2330                 break;
2331         case ND_ROUTER_SOLICIT:
2332                 (void)printf("Router Solicitation");
2333                 break;
2334         case ND_ROUTER_ADVERT:
2335                 (void)printf("Router Advertisement");
2336                 break;
2337         case ND_NEIGHBOR_SOLICIT:
2338                 (void)printf("Neighbor Solicitation");
2339                 break;
2340         case ND_NEIGHBOR_ADVERT:
2341                 (void)printf("Neighbor Advertisement");
2342                 break;
2343         case ND_REDIRECT:
2344                 red = (struct nd_redirect *)icp;
2345                 (void)printf("Redirect\n");
2346                 if (!inet_ntop(AF_INET6, &red->nd_rd_dst, ntop_buf,
2347                     sizeof(ntop_buf)))
2348                         strlcpy(ntop_buf, "?", sizeof(ntop_buf));
2349                 (void)printf("Destination: %s", ntop_buf);
2350                 if (!inet_ntop(AF_INET6, &red->nd_rd_target, ntop_buf,
2351                     sizeof(ntop_buf)))
2352                         strlcpy(ntop_buf, "?", sizeof(ntop_buf));
2353                 (void)printf(" New Target: %s", ntop_buf);
2354                 break;
2355         case ICMP6_NI_QUERY:
2356                 (void)printf("Node Information Query");
2357                 /* XXX ID + Seq + Data */
2358                 ni = (struct icmp6_nodeinfo *)icp;
2359                 l = end - (u_char *)(ni + 1);
2360                 printf(", ");
2361                 switch (ntohs(ni->ni_qtype)) {
2362                 case NI_QTYPE_NOOP:
2363                         (void)printf("NOOP");
2364                         break;
2365                 case NI_QTYPE_SUPTYPES:
2366                         (void)printf("Supported qtypes");
2367                         break;
2368                 case NI_QTYPE_FQDN:
2369                         (void)printf("DNS name");
2370                         break;
2371                 case NI_QTYPE_NODEADDR:
2372                         (void)printf("nodeaddr");
2373                         break;
2374                 case NI_QTYPE_IPV4ADDR:
2375                         (void)printf("IPv4 nodeaddr");
2376                         break;
2377                 default:
2378                         (void)printf("unknown qtype");
2379                         break;
2380                 }
2381                 if (options & F_VERBOSE) {
2382                         switch (ni->ni_code) {
2383                         case ICMP6_NI_SUBJ_IPV6:
2384                                 if (l == sizeof(struct in6_addr) &&
2385                                     inet_ntop(AF_INET6, ni + 1, ntop_buf,
2386                                     sizeof(ntop_buf)) != NULL) {
2387                                         (void)printf(", subject=%s(%s)",
2388                                             niqcode[ni->ni_code], ntop_buf);
2389                                 } else {
2390 #if 1
2391                                         /* backward compat to -W */
2392                                         (void)printf(", oldfqdn");
2393 #else
2394                                         (void)printf(", invalid");
2395 #endif
2396                                 }
2397                                 break;
2398                         case ICMP6_NI_SUBJ_FQDN:
2399                                 if (end == (u_char *)(ni + 1)) {
2400                                         (void)printf(", no subject");
2401                                         break;
2402                                 }
2403                                 printf(", subject=%s", niqcode[ni->ni_code]);
2404                                 cp = (const u_char *)(ni + 1);
2405                                 if (dnsdecode(&cp, end, NULL, dnsname,
2406                                     sizeof(dnsname)) != NULL)
2407                                         printf("(%s)", dnsname);
2408                                 else
2409                                         printf("(invalid)");
2410                                 break;
2411                         case ICMP6_NI_SUBJ_IPV4:
2412                                 if (l == sizeof(struct in_addr) &&
2413                                     inet_ntop(AF_INET, ni + 1, ntop_buf,
2414                                     sizeof(ntop_buf)) != NULL) {
2415                                         (void)printf(", subject=%s(%s)",
2416                                             niqcode[ni->ni_code], ntop_buf);
2417                                 } else
2418                                         (void)printf(", invalid");
2419                                 break;
2420                         default:
2421                                 (void)printf(", invalid");
2422                                 break;
2423                         }
2424                 }
2425                 break;
2426         case ICMP6_NI_REPLY:
2427                 (void)printf("Node Information Reply");
2428                 /* XXX ID + Seq + Data */
2429                 ni = (struct icmp6_nodeinfo *)icp;
2430                 printf(", ");
2431                 switch (ntohs(ni->ni_qtype)) {
2432                 case NI_QTYPE_NOOP:
2433                         (void)printf("NOOP");
2434                         break;
2435                 case NI_QTYPE_SUPTYPES:
2436                         (void)printf("Supported qtypes");
2437                         break;
2438                 case NI_QTYPE_FQDN:
2439                         (void)printf("DNS name");
2440                         break;
2441                 case NI_QTYPE_NODEADDR:
2442                         (void)printf("nodeaddr");
2443                         break;
2444                 case NI_QTYPE_IPV4ADDR:
2445                         (void)printf("IPv4 nodeaddr");
2446                         break;
2447                 default:
2448                         (void)printf("unknown qtype");
2449                         break;
2450                 }
2451                 if (options & F_VERBOSE) {
2452                         if (ni->ni_code > sizeof(nircode) / sizeof(nircode[0]))
2453                                 printf(", invalid");
2454                         else
2455                                 printf(", %s", nircode[ni->ni_code]);
2456                 }
2457                 break;
2458         default:
2459                 (void)printf("Bad ICMP type: %d", icp->icmp6_type);
2460         }
2461 }
2462
2463 /*
2464  * pr_iph --
2465  *      Print an IP6 header.
2466  */
2467 void
2468 pr_iph(ip6)
2469         struct ip6_hdr *ip6;
2470 {
2471         u_int32_t flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK;
2472         u_int8_t tc;
2473         char ntop_buf[INET6_ADDRSTRLEN];
2474
2475         tc = *(&ip6->ip6_vfc + 1); /* XXX */
2476         tc = (tc >> 4) & 0x0f;
2477         tc |= (ip6->ip6_vfc << 4);
2478
2479         printf("Vr TC  Flow Plen Nxt Hlim\n");
2480         printf(" %1x %02x %05x %04x  %02x   %02x\n",
2481             (ip6->ip6_vfc & IPV6_VERSION_MASK) >> 4, tc, (u_int32_t)ntohl(flow),
2482             ntohs(ip6->ip6_plen), ip6->ip6_nxt, ip6->ip6_hlim);
2483         if (!inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf, sizeof(ntop_buf)))
2484                 strlcpy(ntop_buf, "?", sizeof(ntop_buf));
2485         printf("%s->", ntop_buf);
2486         if (!inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf, sizeof(ntop_buf)))
2487                 strlcpy(ntop_buf, "?", sizeof(ntop_buf));
2488         printf("%s\n", ntop_buf);
2489 }
2490
2491 /*
2492  * pr_addr --
2493  *      Return an ascii host address as a dotted quad and optionally with
2494  * a hostname.
2495  */
2496 const char *
2497 pr_addr(addr, addrlen)
2498         struct sockaddr *addr;
2499         int addrlen;
2500 {
2501         static char buf[NI_MAXHOST];
2502         int flag = 0;
2503
2504         if ((options & F_HOSTNAME) == 0)
2505                 flag |= NI_NUMERICHOST;
2506
2507         if (getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, flag) == 0)
2508                 return (buf);
2509         else
2510                 return "?";
2511 }
2512
2513 /*
2514  * pr_retip --
2515  *      Dump some info on a returned (via ICMPv6) IPv6 packet.
2516  */
2517 void
2518 pr_retip(ip6, end)
2519         struct ip6_hdr *ip6;
2520         u_char *end;
2521 {
2522         u_char *cp = (u_char *)ip6, nh;
2523         int hlen;
2524
2525         if (end - (u_char *)ip6 < sizeof(*ip6)) {
2526                 printf("IP6");
2527                 goto trunc;
2528         }
2529         pr_iph(ip6);
2530         hlen = sizeof(*ip6);
2531
2532         nh = ip6->ip6_nxt;
2533         cp += hlen;
2534         while (end - cp >= 8) {
2535                 switch (nh) {
2536                 case IPPROTO_HOPOPTS:
2537                         printf("HBH ");
2538                         hlen = (((struct ip6_hbh *)cp)->ip6h_len+1) << 3;
2539                         nh = ((struct ip6_hbh *)cp)->ip6h_nxt;
2540                         break;
2541                 case IPPROTO_DSTOPTS:
2542                         printf("DSTOPT ");
2543                         hlen = (((struct ip6_dest *)cp)->ip6d_len+1) << 3;
2544                         nh = ((struct ip6_dest *)cp)->ip6d_nxt;
2545                         break;
2546                 case IPPROTO_FRAGMENT:
2547                         printf("FRAG ");
2548                         hlen = sizeof(struct ip6_frag);
2549                         nh = ((struct ip6_frag *)cp)->ip6f_nxt;
2550                         break;
2551                 case IPPROTO_ROUTING:
2552                         printf("RTHDR ");
2553                         hlen = (((struct ip6_rthdr *)cp)->ip6r_len+1) << 3;
2554                         nh = ((struct ip6_rthdr *)cp)->ip6r_nxt;
2555                         break;
2556 #ifdef IPSEC
2557                 case IPPROTO_AH:
2558                         printf("AH ");
2559                         hlen = (((struct ah *)cp)->ah_len+2) << 2;
2560                         nh = ((struct ah *)cp)->ah_nxt;
2561                         break;
2562 #endif
2563                 case IPPROTO_ICMPV6:
2564                         printf("ICMP6: type = %d, code = %d\n",
2565                             *cp, *(cp + 1));
2566                         return;
2567                 case IPPROTO_ESP:
2568                         printf("ESP\n");
2569                         return;
2570                 case IPPROTO_TCP:
2571                         printf("TCP: from port %u, to port %u (decimal)\n",
2572                             (*cp * 256 + *(cp + 1)),
2573                             (*(cp + 2) * 256 + *(cp + 3)));
2574                         return;
2575                 case IPPROTO_UDP:
2576                         printf("UDP: from port %u, to port %u (decimal)\n",
2577                             (*cp * 256 + *(cp + 1)),
2578                             (*(cp + 2) * 256 + *(cp + 3)));
2579                         return;
2580                 default:
2581                         printf("Unknown Header(%d)\n", nh);
2582                         return;
2583                 }
2584
2585                 if ((cp += hlen) >= end)
2586                         goto trunc;
2587         }
2588         if (end - cp < 8)
2589                 goto trunc;
2590
2591         putchar('\n');
2592         return;
2593
2594   trunc:
2595         printf("...\n");
2596         return;
2597 }
2598
2599 void
2600 fill(bp, patp)
2601         char *bp, *patp;
2602 {
2603         int ii, jj, kk;
2604         int pat[16];
2605         char *cp;
2606
2607         for (cp = patp; *cp; cp++)
2608                 if (!isxdigit(*cp))
2609                         errx(1, "patterns must be specified as hex digits");
2610         ii = sscanf(patp,
2611             "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
2612             &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
2613             &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
2614             &pat[13], &pat[14], &pat[15]);
2615
2616 /* xxx */
2617         if (ii > 0)
2618                 for (kk = 0;
2619                     kk <= MAXDATALEN - (8 + sizeof(struct tv32) + ii);
2620                     kk += ii)
2621                         for (jj = 0; jj < ii; ++jj)
2622                                 bp[jj + kk] = pat[jj];
2623         if (!(options & F_QUIET)) {
2624                 (void)printf("PATTERN: 0x");
2625                 for (jj = 0; jj < ii; ++jj)
2626                         (void)printf("%02x", bp[jj] & 0xFF);
2627                 (void)printf("\n");
2628         }
2629 }
2630
2631 #ifdef IPSEC
2632 #ifdef IPSEC_POLICY_IPSEC
2633 int
2634 setpolicy(so, policy)
2635         int so;
2636         char *policy;
2637 {
2638         char *buf;
2639
2640         if (policy == NULL)
2641                 return 0;       /* ignore */
2642
2643         buf = ipsec_set_policy(policy, strlen(policy));
2644         if (buf == NULL)
2645                 errx(1, "%s", ipsec_strerror());
2646         if (setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, buf,
2647             ipsec_get_policylen(buf)) < 0)
2648                 warnx("Unable to set IPsec policy");
2649         free(buf);
2650
2651         return 0;
2652 }
2653 #endif
2654 #endif
2655
2656 char *
2657 nigroup(name)
2658         char *name;
2659 {
2660         char *p;
2661         char *q;
2662         MD5_CTX ctxt;
2663         u_int8_t digest[16];
2664         u_int8_t c;
2665         size_t l;
2666         char hbuf[NI_MAXHOST];
2667         struct in6_addr in6;
2668
2669         p = strchr(name, '.');
2670         if (!p)
2671                 p = name + strlen(name);
2672         l = p - name;
2673         if (l > 63 || l > sizeof(hbuf) - 1)
2674                 return NULL;    /*label too long*/
2675         strncpy(hbuf, name, l);
2676         hbuf[(int)l] = '\0';
2677
2678         for (q = name; *q; q++) {
2679                 if (isupper(*(unsigned char *)q))
2680                         *q = tolower(*(unsigned char *)q);
2681         }
2682
2683         /* generate 8 bytes of pseudo-random value. */
2684         memset(&ctxt, 0, sizeof(ctxt));
2685         MD5Init(&ctxt);
2686         c = l & 0xff;
2687         MD5Update(&ctxt, &c, sizeof(c));
2688         MD5Update(&ctxt, (unsigned char *)name, l);
2689         MD5Final(digest, &ctxt);
2690
2691         if (inet_pton(AF_INET6, "ff02::2:0000:0000", &in6) != 1)
2692                 return NULL;    /*XXX*/
2693         bcopy(digest, &in6.s6_addr[12], 4);
2694
2695         if (inet_ntop(AF_INET6, &in6, hbuf, sizeof(hbuf)) == NULL)
2696                 return NULL;
2697
2698         return strdup(hbuf);
2699 }
2700
2701 void
2702 usage()
2703 {
2704         (void)fprintf(stderr,
2705 #if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC)
2706             "A"
2707 #endif
2708             "usage: ping6 [-"
2709             "d"
2710 #if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC)
2711             "E"
2712 #endif
2713             "fH"
2714 #ifdef IPV6_USE_MIN_MTU
2715             "m"
2716 #endif
2717             "nNqtvwW] "
2718             "[-a addrtype] [-b bufsiz] [-c count] [-g gateway]\n"
2719             "             [-h hoplimit] [-I interface] [-i wait] [-l preload]"
2720 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
2721             " [-P policy]"
2722 #endif
2723             "\n"
2724             "             [-p pattern] [-S sourceaddr] [-s packetsize] "
2725             "[hops ...] host\n");
2726         exit(1);
2727 }