source: rtems-libbsd/freebsd/sbin/ping6/ping6.c @ 338f300

55-freebsd-126-freebsd-12
Last change on this file since 338f300 was 338f300, checked in by Christian Mauderer <christian.mauderer@…>, on 04/25/18 at 14:28:00

buildset: Add minimal and everything config.

This adds two new buildset configurations: One that leaves out as much
features as possible and one that enables all features. For the default
configuration WiFi? support is now disabled.

To disable IPv6 for the minimal configuration, all -DINET6 are
eliminated in libbsd.py. They are now replaced by a #ifdef that checks
for RTEMS_BSD_MODULE_NETINET6 instead.

Close #3351.

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