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