source: rtems-libbsd/freebsd/sbin/ping6/ping6.c @ 998ab36

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 998ab36 was 998ab36, checked in by Sebastian Huber <sebastian.huber@…>, on 10/31/13 at 09:09:41

PING6(8): Add const qualifier

  • Property mode set to 100644
File size: 69.0 KB
RevLine 
[1f877f9]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
[c333bab]107#ifdef __rtems__
108#define __need_getopt_newlib
109#include <getopt.h>
110
111#define USE_RFC2292BIS
112#endif /* __rtems__ */
[e599318]113#include <rtems/bsd/sys/param.h>
[1f877f9]114#include <sys/uio.h>
115#include <sys/socket.h>
[e599318]116#include <rtems/bsd/sys/time.h>
[1f877f9]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)
[2f72888]202static u_int options;
[1f877f9]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)
[998ab36]216static const int mx_dup_ck = MAX_DUP_CHK;
[2f72888]217static char rcvd_tbl[MAX_DUP_CHK / 8];
[1f877f9]218
[2f72888]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];
[998ab36]226static const char BSPACE = '\b';        /* characters written for flood */
227static const char BBELL = '\a';         /* characters written for AUDIBLE */
228static const char DOT = '.';
[2f72888]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. */
[1f877f9]234
235/* counters */
[2f72888]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 */
[1f877f9]242
243/* timing */
[2f72888]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. */
[1f877f9]249
250/* for node addresses */
[2f72888]251static u_short naflags;
[1f877f9]252
253/* for ancillary data(advanced API) */
[2f72888]254static struct msghdr smsghdr;
255static struct iovec smsgiov;
256static char *scmsg = 0;
[1f877f9]257
[2f72888]258static volatile sig_atomic_t seenalrm;
259static volatile sig_atomic_t seenint;
[1f877f9]260#ifdef SIGINFO
[2f72888]261static volatile sig_atomic_t seeninfo;
[1f877f9]262#endif
263
[aa5c35a]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
[234dfb8]295#endif
[aa5c35a]296static char     *nigroup(char *);
297static void      usage(void);
298
[1f877f9]299
300int
[234dfb8]301#ifdef __rtems__
302main_ping6(argc, argv)
303#else
[1f877f9]304main(argc, argv)
[234dfb8]305#endif
[1f877f9]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
[234dfb8]351#ifdef __rtems__
[c333bab]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__ */
[1f877f9]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, origextlen;
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                origextlen = extlen;
1861                extlen = bufsize - CMSG_SPACE(0);
1862                warnx("options truncated, showing only %u (total=%u)",
1863                    (unsigned int)(extlen / 8 - 1),
1864                    (unsigned int)(ext->ip6h_len));
1865        }
1866
1867        currentlen = 0;
1868        while (1) {
1869                currentlen = inet6_opt_next(extbuf, extlen, currentlen,
1870                    &type, &len, &databuf);
1871                if (currentlen == -1)
1872                        break;
1873                switch (type) {
1874                /*
1875                 * Note that inet6_opt_next automatically skips any padding
1876                 * optins.
1877                 */
1878                case IP6OPT_JUMBO:
1879                        offset = 0;
1880                        offset = inet6_opt_get_val(databuf, offset,
1881                            &value4, sizeof(value4));
1882                        printf("    Jumbo Payload Opt: Length %u\n",
1883                            (u_int32_t)ntohl(value4));
1884                        break;
1885                case IP6OPT_ROUTER_ALERT:
1886                        offset = 0;
1887                        offset = inet6_opt_get_val(databuf, offset,
1888                                                   &value2, sizeof(value2));
1889                        printf("    Router Alert Opt: Type %u\n",
1890                            ntohs(value2));
1891                        break;
1892                default:
1893                        printf("    Received Opt %u len %lu\n",
1894                            type, (unsigned long)len);
1895                        break;
1896                }
1897        }
1898        return;
1899}
1900#else  /* !USE_RFC2292BIS */
1901/* ARGSUSED */
1902void
1903pr_ip6opt(void *extbuf, size_t bufsize __unused)
1904{
1905        putchar('\n');
1906        return;
1907}
1908#endif /* USE_RFC2292BIS */
1909
1910#ifdef USE_RFC2292BIS
1911void
1912pr_rthdr(void *extbuf, size_t bufsize)
1913{
1914        struct in6_addr *in6;
1915        char ntopbuf[INET6_ADDRSTRLEN];
1916        struct ip6_rthdr *rh = (struct ip6_rthdr *)extbuf;
1917        int i, segments, origsegs, rthsize, size0, size1;
1918
1919        /* print fixed part of the header */
1920        printf("nxt %u, len %u (%d bytes), type %u, ", rh->ip6r_nxt,
1921            rh->ip6r_len, (rh->ip6r_len + 1) << 3, rh->ip6r_type);
1922        if ((segments = inet6_rth_segments(extbuf)) >= 0) {
1923                printf("%d segments, ", segments);
1924                printf("%d left\n", rh->ip6r_segleft);
1925        } else {
1926                printf("segments unknown, ");
1927                printf("%d left\n", rh->ip6r_segleft);
1928                return;
1929        }
1930
1931        /*
1932         * Bounds checking on the ancillary data buffer. When calculating
1933         * the number of items to show keep in mind:
1934         *      - The size of the cmsg structure
1935         *      - The size of one segment (the size of a Type 0 routing header)
1936         *      - When dividing add a fudge factor of one in case the
1937         *        dividend is not evenly divisible by the divisor
1938         */
1939        rthsize = (rh->ip6r_len + 1) * 8;
1940        if (bufsize < (rthsize + CMSG_SPACE(0))) {
1941                origsegs = segments;
1942                size0 = inet6_rth_space(IPV6_RTHDR_TYPE_0, 0);
1943                size1 = inet6_rth_space(IPV6_RTHDR_TYPE_0, 1);
1944                segments -= (rthsize - (bufsize - CMSG_SPACE(0))) /
1945                    (size1 - size0) + 1;
1946                warnx("segments truncated, showing only %d (total=%d)",
1947                    segments, origsegs);
1948        }
1949
1950        for (i = 0; i < segments; i++) {
1951                in6 = inet6_rth_getaddr(extbuf, i);
1952                if (in6 == NULL)
1953                        printf("   [%d]<NULL>\n", i);
1954                else {
1955                        if (!inet_ntop(AF_INET6, in6, ntopbuf,
1956                            sizeof(ntopbuf)))
1957                                strlcpy(ntopbuf, "?", sizeof(ntopbuf));
1958                        printf("   [%d]%s\n", i, ntopbuf);
1959                }
1960        }
1961
1962        return;
1963
1964}
1965
1966#else  /* !USE_RFC2292BIS */
1967/* ARGSUSED */
1968void
1969pr_rthdr(void *extbuf, size_t bufsize __unused)
1970{
1971        putchar('\n');
1972        return;
1973}
1974#endif /* USE_RFC2292BIS */
1975
1976int
1977pr_bitrange(v, soff, ii)
1978        u_int32_t v;
1979        int soff;
1980        int ii;
1981{
1982        int off;
1983        int i;
1984
1985        off = 0;
1986        while (off < 32) {
1987                /* shift till we have 0x01 */
1988                if ((v & 0x01) == 0) {
1989                        if (ii > 1)
1990                                printf("-%u", soff + off - 1);
1991                        ii = 0;
1992                        switch (v & 0x0f) {
1993                        case 0x00:
1994                                v >>= 4;
1995                                off += 4;
1996                                continue;
1997                        case 0x08:
1998                                v >>= 3;
1999                                off += 3;
2000                                continue;
2001                        case 0x04: case 0x0c:
2002                                v >>= 2;
2003                                off += 2;
2004                                continue;
2005                        default:
2006                                v >>= 1;
2007                                off += 1;
2008                                continue;
2009                        }
2010                }
2011
2012                /* we have 0x01 with us */
2013                for (i = 0; i < 32 - off; i++) {
2014                        if ((v & (0x01 << i)) == 0)
2015                                break;
2016                }
2017                if (!ii)
2018                        printf(" %u", soff + off);
2019                ii += i;
2020                v >>= i; off += i;
2021        }
2022        return ii;
2023}
2024
2025void
2026pr_suptypes(ni, nilen)
2027        struct icmp6_nodeinfo *ni; /* ni->qtype must be SUPTYPES */
2028        size_t nilen;
2029{
2030        size_t clen;
2031        u_int32_t v;
2032        const u_char *cp, *end;
2033        u_int16_t cur;
2034        struct cbit {
2035                u_int16_t words;        /*32bit count*/
2036                u_int16_t skip;
2037        } cbit;
2038#define MAXQTYPES       (1 << 16)
2039        size_t off;
2040        int b;
2041
2042        cp = (u_char *)(ni + 1);
2043        end = ((u_char *)ni) + nilen;
2044        cur = 0;
2045        b = 0;
2046
2047        printf("NodeInfo Supported Qtypes");
2048        if (options & F_VERBOSE) {
2049                if (ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS)
2050                        printf(", compressed bitmap");
2051                else
2052                        printf(", raw bitmap");
2053        }
2054
2055        while (cp < end) {
2056                clen = (size_t)(end - cp);
2057                if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) == 0) {
2058                        if (clen == 0 || clen > MAXQTYPES / 8 ||
2059                            clen % sizeof(v)) {
2060                                printf("???");
2061                                return;
2062                        }
2063                } else {
2064                        if (clen < sizeof(cbit) || clen % sizeof(v))
2065                                return;
2066                        memcpy(&cbit, cp, sizeof(cbit));
2067                        if (sizeof(cbit) + ntohs(cbit.words) * sizeof(v) >
2068                            clen)
2069                                return;
2070                        cp += sizeof(cbit);
2071                        clen = ntohs(cbit.words) * sizeof(v);
2072                        if (cur + clen * 8 + (u_long)ntohs(cbit.skip) * 32 >
2073                            MAXQTYPES)
2074                                return;
2075                }
2076
2077                for (off = 0; off < clen; off += sizeof(v)) {
2078                        memcpy(&v, cp + off, sizeof(v));
2079                        v = (u_int32_t)ntohl(v);
2080                        b = pr_bitrange(v, (int)(cur + off * 8), b);
2081                }
2082                /* flush the remaining bits */
2083                b = pr_bitrange(0, (int)(cur + off * 8), b);
2084
2085                cp += clen;
2086                cur += clen * 8;
2087                if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) != 0)
2088                        cur += ntohs(cbit.skip) * 32;
2089        }
2090}
2091
2092void
2093pr_nodeaddr(ni, nilen)
2094        struct icmp6_nodeinfo *ni; /* ni->qtype must be NODEADDR */
2095        int nilen;
2096{
2097        u_char *cp = (u_char *)(ni + 1);
2098        char ntop_buf[INET6_ADDRSTRLEN];
2099        int withttl = 0;
2100
2101        nilen -= sizeof(struct icmp6_nodeinfo);
2102
2103        if (options & F_VERBOSE) {
2104                switch (ni->ni_code) {
2105                case ICMP6_NI_REFUSED:
2106                        (void)printf("refused");
2107                        break;
2108                case ICMP6_NI_UNKNOWN:
2109                        (void)printf("unknown qtype");
2110                        break;
2111                }
2112                if (ni->ni_flags & NI_NODEADDR_FLAG_TRUNCATE)
2113                        (void)printf(" truncated");
2114        }
2115        putchar('\n');
2116        if (nilen <= 0)
2117                printf("  no address\n");
2118
2119        /*
2120         * In icmp-name-lookups 05 and later, TTL of each returned address
2121         * is contained in the resposne. We try to detect the version
2122         * by the length of the data, but note that the detection algorithm
2123         * is incomplete. We assume the latest draft by default.
2124         */
2125        if (nilen % (sizeof(u_int32_t) + sizeof(struct in6_addr)) == 0)
2126                withttl = 1;
2127        while (nilen > 0) {
2128                u_int32_t ttl;
2129
2130                if (withttl) {
2131                        /* XXX: alignment? */
2132                        ttl = (u_int32_t)ntohl(*(u_int32_t *)cp);
2133                        cp += sizeof(u_int32_t);
2134                        nilen -= sizeof(u_int32_t);
2135                }
2136
2137                if (inet_ntop(AF_INET6, cp, ntop_buf, sizeof(ntop_buf)) ==
2138                    NULL)
2139                        strlcpy(ntop_buf, "?", sizeof(ntop_buf));
2140                printf("  %s", ntop_buf);
2141                if (withttl) {
2142                        if (ttl == 0xffffffff) {
2143                                /*
2144                                 * XXX: can this convention be applied to all
2145                                 * type of TTL (i.e. non-ND TTL)?
2146                                 */
2147                                printf("(TTL=infty)");
2148                        }
2149                        else
2150                                printf("(TTL=%u)", ttl);
2151                }
2152                putchar('\n');
2153
2154                nilen -= sizeof(struct in6_addr);
2155                cp += sizeof(struct in6_addr);
2156        }
2157}
2158
2159int
2160get_hoplim(mhdr)
2161        struct msghdr *mhdr;
2162{
2163        struct cmsghdr *cm;
2164
2165        for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
2166             cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
2167                if (cm->cmsg_len == 0)
2168                        return(-1);
2169
2170                if (cm->cmsg_level == IPPROTO_IPV6 &&
2171                    cm->cmsg_type == IPV6_HOPLIMIT &&
2172                    cm->cmsg_len == CMSG_LEN(sizeof(int)))
2173                        return(*(int *)CMSG_DATA(cm));
2174        }
2175
2176        return(-1);
2177}
2178
2179struct in6_pktinfo *
2180get_rcvpktinfo(mhdr)
2181        struct msghdr *mhdr;
2182{
2183        struct cmsghdr *cm;
2184
2185        for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
2186             cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
2187                if (cm->cmsg_len == 0)
2188                        return(NULL);
2189
2190                if (cm->cmsg_level == IPPROTO_IPV6 &&
2191                    cm->cmsg_type == IPV6_PKTINFO &&
2192                    cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo)))
2193                        return((struct in6_pktinfo *)CMSG_DATA(cm));
2194        }
2195
2196        return(NULL);
2197}
2198
2199int
2200get_pathmtu(mhdr)
2201        struct msghdr *mhdr;
2202{
2203#ifdef IPV6_RECVPATHMTU
2204        struct cmsghdr *cm;
2205        struct ip6_mtuinfo *mtuctl = NULL;
2206
2207        for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
2208             cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
2209                if (cm->cmsg_len == 0)
2210                        return(0);
2211
2212                if (cm->cmsg_level == IPPROTO_IPV6 &&
2213                    cm->cmsg_type == IPV6_PATHMTU &&
2214                    cm->cmsg_len == CMSG_LEN(sizeof(struct ip6_mtuinfo))) {
2215                        mtuctl = (struct ip6_mtuinfo *)CMSG_DATA(cm);
2216
2217                        /*
2218                         * If the notified destination is different from
2219                         * the one we are pinging, just ignore the info.
2220                         * We check the scope ID only when both notified value
2221                         * and our own value have non-0 values, because we may
2222                         * have used the default scope zone ID for sending,
2223                         * in which case the scope ID value is 0.
2224                         */
2225                        if (!IN6_ARE_ADDR_EQUAL(&mtuctl->ip6m_addr.sin6_addr,
2226                                                &dst.sin6_addr) ||
2227                            (mtuctl->ip6m_addr.sin6_scope_id &&
2228                             dst.sin6_scope_id &&
2229                             mtuctl->ip6m_addr.sin6_scope_id !=
2230                             dst.sin6_scope_id)) {
2231                                if ((options & F_VERBOSE) != 0) {
2232                                        printf("path MTU for %s is notified. "
2233                                               "(ignored)\n",
2234                                           pr_addr((struct sockaddr *)&mtuctl->ip6m_addr,
2235                                           sizeof(mtuctl->ip6m_addr)));
2236                                }
2237                                return(0);
2238                        }
2239
2240                        /*
2241                         * Ignore an invalid MTU. XXX: can we just believe
2242                         * the kernel check?
2243                         */
2244                        if (mtuctl->ip6m_mtu < IPV6_MMTU)
2245                                return(0);
2246
2247                        /* notification for our destination. return the MTU. */
2248                        return((int)mtuctl->ip6m_mtu);
2249                }
2250        }
2251#endif
2252        return(0);
2253}
2254
2255/*
2256 * tvsub --
2257 *      Subtract 2 timeval structs:  out = out - in.  Out is assumed to
2258 * be >= in.
2259 */
2260void
2261tvsub(out, in)
2262        struct timeval *out, *in;
2263{
2264        if ((out->tv_usec -= in->tv_usec) < 0) {
2265                --out->tv_sec;
2266                out->tv_usec += 1000000;
2267        }
2268        out->tv_sec -= in->tv_sec;
2269}
2270
2271/*
2272 * onint --
2273 *      SIGINT handler.
2274 */
2275/* ARGSUSED */
2276void
2277onint(notused)
2278        int notused;
2279{
2280        summary();
2281
2282        (void)signal(SIGINT, SIG_DFL);
2283        (void)kill(getpid(), SIGINT);
2284
2285        /* NOTREACHED */
2286        exit(1);
2287}
2288
2289/*
2290 * summary --
2291 *      Print out statistics.
2292 */
2293void
2294summary()
2295{
2296
2297        (void)printf("\n--- %s ping6 statistics ---\n", hostname);
2298        (void)printf("%ld packets transmitted, ", ntransmitted);
2299        (void)printf("%ld packets received, ", nreceived);
2300        if (nrepeats)
2301                (void)printf("+%ld duplicates, ", nrepeats);
2302        if (ntransmitted) {
2303                if (nreceived > ntransmitted)
2304                        (void)printf("-- somebody's duplicating packets!");
2305                else
2306                        (void)printf("%.1f%% packet loss",
2307                            ((((double)ntransmitted - nreceived) * 100.0) /
2308                            ntransmitted));
2309        }
2310        (void)putchar('\n');
2311        if (nreceived && timing) {
2312                /* Only display average to microseconds */
2313                double num = nreceived + nrepeats;
2314                double avg = tsum / num;
2315                double dev = sqrt(tsumsq / num - avg * avg);
2316                (void)printf(
2317                    "round-trip min/avg/max/std-dev = %.3f/%.3f/%.3f/%.3f ms\n",
2318                    tmin, avg, tmax, dev);
2319                (void)fflush(stdout);
2320        }
2321        (void)fflush(stdout);
2322}
2323
2324/*subject type*/
2325static const char *niqcode[] = {
2326        "IPv6 address",
2327        "DNS label",    /*or empty*/
2328        "IPv4 address",
2329};
2330
2331/*result code*/
2332static const char *nircode[] = {
2333        "Success", "Refused", "Unknown",
2334};
2335
2336
2337/*
2338 * pr_icmph --
2339 *      Print a descriptive string about an ICMP header.
2340 */
2341void
2342pr_icmph(icp, end)
2343        struct icmp6_hdr *icp;
2344        u_char *end;
2345{
2346        char ntop_buf[INET6_ADDRSTRLEN];
2347        struct nd_redirect *red;
2348        struct icmp6_nodeinfo *ni;
2349        char dnsname[MAXDNAME + 1];
2350        const u_char *cp;
2351        size_t l;
2352
2353        switch (icp->icmp6_type) {
2354        case ICMP6_DST_UNREACH:
2355                switch (icp->icmp6_code) {
2356                case ICMP6_DST_UNREACH_NOROUTE:
2357                        (void)printf("No Route to Destination\n");
2358                        break;
2359                case ICMP6_DST_UNREACH_ADMIN:
2360                        (void)printf("Destination Administratively "
2361                            "Unreachable\n");
2362                        break;
2363                case ICMP6_DST_UNREACH_BEYONDSCOPE:
2364                        (void)printf("Destination Unreachable Beyond Scope\n");
2365                        break;
2366                case ICMP6_DST_UNREACH_ADDR:
2367                        (void)printf("Destination Host Unreachable\n");
2368                        break;
2369                case ICMP6_DST_UNREACH_NOPORT:
2370                        (void)printf("Destination Port Unreachable\n");
2371                        break;
2372                default:
2373                        (void)printf("Destination Unreachable, Bad Code: %d\n",
2374                            icp->icmp6_code);
2375                        break;
2376                }
2377                /* Print returned IP header information */
2378                pr_retip((struct ip6_hdr *)(icp + 1), end);
2379                break;
2380        case ICMP6_PACKET_TOO_BIG:
2381                (void)printf("Packet too big mtu = %d\n",
2382                    (int)ntohl(icp->icmp6_mtu));
2383                pr_retip((struct ip6_hdr *)(icp + 1), end);
2384                break;
2385        case ICMP6_TIME_EXCEEDED:
2386                switch (icp->icmp6_code) {
2387                case ICMP6_TIME_EXCEED_TRANSIT:
2388                        (void)printf("Time to live exceeded\n");
2389                        break;
2390                case ICMP6_TIME_EXCEED_REASSEMBLY:
2391                        (void)printf("Frag reassembly time exceeded\n");
2392                        break;
2393                default:
2394                        (void)printf("Time exceeded, Bad Code: %d\n",
2395                            icp->icmp6_code);
2396                        break;
2397                }
2398                pr_retip((struct ip6_hdr *)(icp + 1), end);
2399                break;
2400        case ICMP6_PARAM_PROB:
2401                (void)printf("Parameter problem: ");
2402                switch (icp->icmp6_code) {
2403                case ICMP6_PARAMPROB_HEADER:
2404                        (void)printf("Erroneous Header ");
2405                        break;
2406                case ICMP6_PARAMPROB_NEXTHEADER:
2407                        (void)printf("Unknown Nextheader ");
2408                        break;
2409                case ICMP6_PARAMPROB_OPTION:
2410                        (void)printf("Unrecognized Option ");
2411                        break;
2412                default:
2413                        (void)printf("Bad code(%d) ", icp->icmp6_code);
2414                        break;
2415                }
2416                (void)printf("pointer = 0x%02x\n",
2417                    (u_int32_t)ntohl(icp->icmp6_pptr));
2418                pr_retip((struct ip6_hdr *)(icp + 1), end);
2419                break;
2420        case ICMP6_ECHO_REQUEST:
2421                (void)printf("Echo Request");
2422                /* XXX ID + Seq + Data */
2423                break;
2424        case ICMP6_ECHO_REPLY:
2425                (void)printf("Echo Reply");
2426                /* XXX ID + Seq + Data */
2427                break;
2428        case ICMP6_MEMBERSHIP_QUERY:
2429                (void)printf("Listener Query");
2430                break;
2431        case ICMP6_MEMBERSHIP_REPORT:
2432                (void)printf("Listener Report");
2433                break;
2434        case ICMP6_MEMBERSHIP_REDUCTION:
2435                (void)printf("Listener Done");
2436                break;
2437        case ND_ROUTER_SOLICIT:
2438                (void)printf("Router Solicitation");
2439                break;
2440        case ND_ROUTER_ADVERT:
2441                (void)printf("Router Advertisement");
2442                break;
2443        case ND_NEIGHBOR_SOLICIT:
2444                (void)printf("Neighbor Solicitation");
2445                break;
2446        case ND_NEIGHBOR_ADVERT:
2447                (void)printf("Neighbor Advertisement");
2448                break;
2449        case ND_REDIRECT:
2450                red = (struct nd_redirect *)icp;
2451                (void)printf("Redirect\n");
2452                if (!inet_ntop(AF_INET6, &red->nd_rd_dst, ntop_buf,
2453                    sizeof(ntop_buf)))
2454                        strlcpy(ntop_buf, "?", sizeof(ntop_buf));
2455                (void)printf("Destination: %s", ntop_buf);
2456                if (!inet_ntop(AF_INET6, &red->nd_rd_target, ntop_buf,
2457                    sizeof(ntop_buf)))
2458                        strlcpy(ntop_buf, "?", sizeof(ntop_buf));
2459                (void)printf(" New Target: %s", ntop_buf);
2460                break;
2461        case ICMP6_NI_QUERY:
2462                (void)printf("Node Information Query");
2463                /* XXX ID + Seq + Data */
2464                ni = (struct icmp6_nodeinfo *)icp;
2465                l = end - (u_char *)(ni + 1);
2466                printf(", ");
2467                switch (ntohs(ni->ni_qtype)) {
2468                case NI_QTYPE_NOOP:
2469                        (void)printf("NOOP");
2470                        break;
2471                case NI_QTYPE_SUPTYPES:
2472                        (void)printf("Supported qtypes");
2473                        break;
2474                case NI_QTYPE_FQDN:
2475                        (void)printf("DNS name");
2476                        break;
2477                case NI_QTYPE_NODEADDR:
2478                        (void)printf("nodeaddr");
2479                        break;
2480                case NI_QTYPE_IPV4ADDR:
2481                        (void)printf("IPv4 nodeaddr");
2482                        break;
2483                default:
2484                        (void)printf("unknown qtype");
2485                        break;
2486                }
2487                if (options & F_VERBOSE) {
2488                        switch (ni->ni_code) {
2489                        case ICMP6_NI_SUBJ_IPV6:
2490                                if (l == sizeof(struct in6_addr) &&
2491                                    inet_ntop(AF_INET6, ni + 1, ntop_buf,
2492                                    sizeof(ntop_buf)) != NULL) {
2493                                        (void)printf(", subject=%s(%s)",
2494                                            niqcode[ni->ni_code], ntop_buf);
2495                                } else {
2496#if 1
2497                                        /* backward compat to -W */
2498                                        (void)printf(", oldfqdn");
2499#else
2500                                        (void)printf(", invalid");
2501#endif
2502                                }
2503                                break;
2504                        case ICMP6_NI_SUBJ_FQDN:
2505                                if (end == (u_char *)(ni + 1)) {
2506                                        (void)printf(", no subject");
2507                                        break;
2508                                }
2509                                printf(", subject=%s", niqcode[ni->ni_code]);
2510                                cp = (const u_char *)(ni + 1);
2511                                if (dnsdecode(&cp, end, NULL, dnsname,
2512                                    sizeof(dnsname)) != NULL)
2513                                        printf("(%s)", dnsname);
2514                                else
2515                                        printf("(invalid)");
2516                                break;
2517                        case ICMP6_NI_SUBJ_IPV4:
2518                                if (l == sizeof(struct in_addr) &&
2519                                    inet_ntop(AF_INET, ni + 1, ntop_buf,
2520                                    sizeof(ntop_buf)) != NULL) {
2521                                        (void)printf(", subject=%s(%s)",
2522                                            niqcode[ni->ni_code], ntop_buf);
2523                                } else
2524                                        (void)printf(", invalid");
2525                                break;
2526                        default:
2527                                (void)printf(", invalid");
2528                                break;
2529                        }
2530                }
2531                break;
2532        case ICMP6_NI_REPLY:
2533                (void)printf("Node Information Reply");
2534                /* XXX ID + Seq + Data */
2535                ni = (struct icmp6_nodeinfo *)icp;
2536                printf(", ");
2537                switch (ntohs(ni->ni_qtype)) {
2538                case NI_QTYPE_NOOP:
2539                        (void)printf("NOOP");
2540                        break;
2541                case NI_QTYPE_SUPTYPES:
2542                        (void)printf("Supported qtypes");
2543                        break;
2544                case NI_QTYPE_FQDN:
2545                        (void)printf("DNS name");
2546                        break;
2547                case NI_QTYPE_NODEADDR:
2548                        (void)printf("nodeaddr");
2549                        break;
2550                case NI_QTYPE_IPV4ADDR:
2551                        (void)printf("IPv4 nodeaddr");
2552                        break;
2553                default:
2554                        (void)printf("unknown qtype");
2555                        break;
2556                }
2557                if (options & F_VERBOSE) {
2558                        if (ni->ni_code > sizeof(nircode) / sizeof(nircode[0]))
2559                                printf(", invalid");
2560                        else
2561                                printf(", %s", nircode[ni->ni_code]);
2562                }
2563                break;
2564        default:
2565                (void)printf("Bad ICMP type: %d", icp->icmp6_type);
2566        }
2567}
2568
2569/*
2570 * pr_iph --
2571 *      Print an IP6 header.
2572 */
2573void
2574pr_iph(ip6)
2575        struct ip6_hdr *ip6;
2576{
2577        u_int32_t flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK;
2578        u_int8_t tc;
2579        char ntop_buf[INET6_ADDRSTRLEN];
2580
2581        tc = *(&ip6->ip6_vfc + 1); /* XXX */
2582        tc = (tc >> 4) & 0x0f;
2583        tc |= (ip6->ip6_vfc << 4);
2584
2585        printf("Vr TC  Flow Plen Nxt Hlim\n");
2586        printf(" %1x %02x %05x %04x  %02x   %02x\n",
2587            (ip6->ip6_vfc & IPV6_VERSION_MASK) >> 4, tc, (u_int32_t)ntohl(flow),
2588            ntohs(ip6->ip6_plen), ip6->ip6_nxt, ip6->ip6_hlim);
2589        if (!inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf, sizeof(ntop_buf)))
2590                strlcpy(ntop_buf, "?", sizeof(ntop_buf));
2591        printf("%s->", ntop_buf);
2592        if (!inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf, sizeof(ntop_buf)))
2593                strlcpy(ntop_buf, "?", sizeof(ntop_buf));
2594        printf("%s\n", ntop_buf);
2595}
2596
2597/*
2598 * pr_addr --
2599 *      Return an ascii host address as a dotted quad and optionally with
2600 * a hostname.
2601 */
2602const char *
2603pr_addr(addr, addrlen)
2604        struct sockaddr *addr;
2605        int addrlen;
2606{
2607        static char buf[NI_MAXHOST];
2608        int flag = 0;
2609
2610        if ((options & F_HOSTNAME) == 0)
2611                flag |= NI_NUMERICHOST;
2612
2613        if (getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, flag) == 0)
2614                return (buf);
2615        else
2616                return "?";
2617}
2618
2619/*
2620 * pr_retip --
2621 *      Dump some info on a returned (via ICMPv6) IPv6 packet.
2622 */
2623void
2624pr_retip(ip6, end)
2625        struct ip6_hdr *ip6;
2626        u_char *end;
2627{
2628        u_char *cp = (u_char *)ip6, nh;
2629        int hlen;
2630
2631        if (end - (u_char *)ip6 < sizeof(*ip6)) {
2632                printf("IP6");
2633                goto trunc;
2634        }
2635        pr_iph(ip6);
2636        hlen = sizeof(*ip6);
2637
2638        nh = ip6->ip6_nxt;
2639        cp += hlen;
2640        while (end - cp >= 8) {
2641                switch (nh) {
2642                case IPPROTO_HOPOPTS:
2643                        printf("HBH ");
2644                        hlen = (((struct ip6_hbh *)cp)->ip6h_len+1) << 3;
2645                        nh = ((struct ip6_hbh *)cp)->ip6h_nxt;
2646                        break;
2647                case IPPROTO_DSTOPTS:
2648                        printf("DSTOPT ");
2649                        hlen = (((struct ip6_dest *)cp)->ip6d_len+1) << 3;
2650                        nh = ((struct ip6_dest *)cp)->ip6d_nxt;
2651                        break;
2652                case IPPROTO_FRAGMENT:
2653                        printf("FRAG ");
2654                        hlen = sizeof(struct ip6_frag);
2655                        nh = ((struct ip6_frag *)cp)->ip6f_nxt;
2656                        break;
2657                case IPPROTO_ROUTING:
2658                        printf("RTHDR ");
2659                        hlen = (((struct ip6_rthdr *)cp)->ip6r_len+1) << 3;
2660                        nh = ((struct ip6_rthdr *)cp)->ip6r_nxt;
2661                        break;
2662#ifdef IPSEC
2663                case IPPROTO_AH:
2664                        printf("AH ");
2665                        hlen = (((struct ah *)cp)->ah_len+2) << 2;
2666                        nh = ((struct ah *)cp)->ah_nxt;
2667                        break;
2668#endif
2669                case IPPROTO_ICMPV6:
2670                        printf("ICMP6: type = %d, code = %d\n",
2671                            *cp, *(cp + 1));
2672                        return;
2673                case IPPROTO_ESP:
2674                        printf("ESP\n");
2675                        return;
2676                case IPPROTO_TCP:
2677                        printf("TCP: from port %u, to port %u (decimal)\n",
2678                            (*cp * 256 + *(cp + 1)),
2679                            (*(cp + 2) * 256 + *(cp + 3)));
2680                        return;
2681                case IPPROTO_UDP:
2682                        printf("UDP: from port %u, to port %u (decimal)\n",
2683                            (*cp * 256 + *(cp + 1)),
2684                            (*(cp + 2) * 256 + *(cp + 3)));
2685                        return;
2686                default:
2687                        printf("Unknown Header(%d)\n", nh);
2688                        return;
2689                }
2690
2691                if ((cp += hlen) >= end)
2692                        goto trunc;
2693        }
2694        if (end - cp < 8)
2695                goto trunc;
2696
2697        putchar('\n');
2698        return;
2699
2700  trunc:
2701        printf("...\n");
2702        return;
2703}
2704
2705void
2706fill(bp, patp)
2707        char *bp, *patp;
2708{
2709        int ii, jj, kk;
2710        int pat[16];
2711        char *cp;
2712
2713        for (cp = patp; *cp; cp++)
2714                if (!isxdigit(*cp))
2715                        errx(1, "patterns must be specified as hex digits");
2716        ii = sscanf(patp,
2717            "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
2718            &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
2719            &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
2720            &pat[13], &pat[14], &pat[15]);
2721
2722/* xxx */
2723        if (ii > 0)
2724                for (kk = 0;
2725                    kk <= MAXDATALEN - (8 + sizeof(struct tv32) + ii);
2726                    kk += ii)
2727                        for (jj = 0; jj < ii; ++jj)
2728                                bp[jj + kk] = pat[jj];
2729        if (!(options & F_QUIET)) {
2730                (void)printf("PATTERN: 0x");
2731                for (jj = 0; jj < ii; ++jj)
2732                        (void)printf("%02x", bp[jj] & 0xFF);
2733                (void)printf("\n");
2734        }
2735}
2736
2737#ifdef IPSEC
2738#ifdef IPSEC_POLICY_IPSEC
2739int
2740setpolicy(so, policy)
2741        int so;
2742        char *policy;
2743{
2744        char *buf;
2745
2746        if (policy == NULL)
2747                return 0;       /* ignore */
2748
2749        buf = ipsec_set_policy(policy, strlen(policy));
2750        if (buf == NULL)
2751                errx(1, "%s", ipsec_strerror());
2752        if (setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, buf,
2753            ipsec_get_policylen(buf)) < 0)
2754                warnx("Unable to set IPsec policy");
2755        free(buf);
2756
2757        return 0;
2758}
2759#endif
2760#endif
2761
2762char *
2763nigroup(name)
2764        char *name;
2765{
2766        char *p;
2767        char *q;
2768        MD5_CTX ctxt;
2769        u_int8_t digest[16];
2770        u_int8_t c;
2771        size_t l;
2772        char hbuf[NI_MAXHOST];
2773        struct in6_addr in6;
2774
2775        p = strchr(name, '.');
2776        if (!p)
2777                p = name + strlen(name);
2778        l = p - name;
2779        if (l > 63 || l > sizeof(hbuf) - 1)
2780                return NULL;    /*label too long*/
2781        strncpy(hbuf, name, l);
2782        hbuf[(int)l] = '\0';
2783
2784        for (q = name; *q; q++) {
2785                if (isupper(*(unsigned char *)q))
2786                        *q = tolower(*(unsigned char *)q);
2787        }
2788
2789        /* generate 8 bytes of pseudo-random value. */
2790        memset(&ctxt, 0, sizeof(ctxt));
2791        MD5Init(&ctxt);
2792        c = l & 0xff;
2793        MD5Update(&ctxt, &c, sizeof(c));
2794        MD5Update(&ctxt, (unsigned char *)name, l);
2795        MD5Final(digest, &ctxt);
2796
2797        if (inet_pton(AF_INET6, "ff02::2:0000:0000", &in6) != 1)
2798                return NULL;    /*XXX*/
2799        bcopy(digest, &in6.s6_addr[12], 4);
2800
2801        if (inet_ntop(AF_INET6, &in6, hbuf, sizeof(hbuf)) == NULL)
2802                return NULL;
2803
2804        return strdup(hbuf);
2805}
2806
2807void
2808usage()
2809{
2810        (void)fprintf(stderr,
2811#if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC)
2812            "A"
2813#endif
2814            "usage: ping6 [-"
2815            "Dd"
2816#if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC)
2817            "E"
2818#endif
2819            "fH"
2820#ifdef IPV6_USE_MIN_MTU
2821            "m"
2822#endif
2823            "nNoqrRtvwW] "
2824            "[-a addrtype] [-b bufsiz] [-c count] [-g gateway]\n"
2825            "             [-h hoplimit] [-I interface] [-i wait] [-l preload]"
2826#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
2827            " [-P policy]"
2828#endif
2829            "\n"
2830            "             [-p pattern] [-S sourceaddr] [-s packetsize] "
2831            "[hops ...] host\n");
2832        exit(1);
2833}
Note: See TracBrowser for help on using the repository browser.