source: rtems-libbsd/freebsd-userspace/commands/sbin/ping6/ping6.c @ dafaba3

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since dafaba3 was dafaba3, checked in by Joel Sherrill <joel.sherrill@…>, on 09/05/12 at 18:15:58

ping6.c: Add include of port_before.h

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