source: rtems-libbsd/freebsd/sbin/ping6/ping6.c @ 4a16e28

4.115-freebsd-12freebsd-9.3
Last change on this file since 4a16e28 was 4a16e28, checked in by Sebastian Huber <sebastian.huber@…>, on Oct 31, 2013 at 9:13:17 AM

PING6(8): Fix isxdigit() usage

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