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

4.11
Last change on this file since fef6dd1 was fef6dd1, checked in by Christian Mauderer <Christian.Mauderer@…>, on 07/15/16 at 05:32:56

freebsd: Don't use new wrappers for old ports.

Some of the commands have been adapted manually. So the wrapper
currently don't necessarily work as expected. For example ifconfig calls
malloc outside of the program call.

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