GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/ping6/ping6.c Lines: 0 685 0.0 %
Date: 2016-12-06 Branches: 0 505 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: ping6.c,v 1.146 2016/03/03 18:30:48 florian Exp $	*/
2
/*	$KAME: ping6.c,v 1.163 2002/10/25 02:19:06 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. Neither the name of the University nor the names of its contributors
51
 *    may be used to endorse or promote products derived from this software
52
 *    without specific prior written permission.
53
 *
54
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64
 * SUCH DAMAGE.
65
 */
66
67
/*
68
 * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
69
 * measure round-trip-delays and packet loss across network paths.
70
 *
71
 * Author -
72
 *	Mike Muuss
73
 *	U. S. Army Ballistic Research Laboratory
74
 *	December, 1983
75
 *
76
 * Status -
77
 *	Public Domain.  Distribution Unlimited.
78
 * Bugs -
79
 *	More statistics could always be gathered.
80
 *	This program has to run SUID to ROOT to access the ICMP socket.
81
 */
82
83
#include <sys/types.h>
84
#include <sys/socket.h>
85
#include <sys/time.h>
86
#include <sys/uio.h>
87
88
#include <netinet/in.h>
89
#include <netinet/ip6.h>
90
#include <netinet/icmp6.h>
91
#include <netinet/ip_ah.h>
92
#include <arpa/inet.h>
93
#include <netdb.h>
94
95
#include <ctype.h>
96
#include <err.h>
97
#include <errno.h>
98
#include <limits.h>
99
#include <math.h>
100
#include <poll.h>
101
#include <signal.h>
102
#include <siphash.h>
103
#include <stdint.h>
104
#include <stdio.h>
105
#include <stdlib.h>
106
#include <string.h>
107
#include <time.h>
108
#include <unistd.h>
109
110
struct tv64 {
111
	u_int64_t	tv64_sec;
112
	u_int64_t	tv64_nsec;
113
};
114
115
struct payload {
116
	struct tv64	tv64;
117
	u_int8_t	mac[SIPHASH_DIGEST_LENGTH];
118
};
119
120
#define MAXPACKETLEN	131072
121
#define	IP6LEN		40
122
#define ICMP6ECHOLEN	8	/* icmp echo header len excluding time */
123
#define ICMP6ECHOTMLEN sizeof(struct payload)
124
#define	EXTRA		256	/* for AH and various other headers. weird. */
125
#define	DEFDATALEN	ICMP6ECHOTMLEN
126
#define MAXPAYLOAD	MAXPACKETLEN - IP6LEN - ICMP6ECHOLEN
127
#define	MAXWAIT_DEFAULT	10	/* secs to wait for response */
128
129
#define	A(bit)		rcvd_tbl[(bit)>>3]	/* identify byte in array */
130
#define	B(bit)		(1 << ((bit) & 0x07))	/* identify bit in byte */
131
#define	SET(bit)	(A(bit) |= B(bit))
132
#define	CLR(bit)	(A(bit) &= (~B(bit)))
133
#define	TST(bit)	(A(bit) & B(bit))
134
135
#define	F_FLOOD		0x0001
136
#define	F_INTERVAL	0x0002
137
#define	F_PINGFILLED	0x0008
138
#define	F_QUIET		0x0010
139
#define	F_SO_DEBUG	0x0040
140
#define	F_VERBOSE	0x0100
141
/*			0x4000 */
142
#define F_HOSTNAME	0x10000
143
#define F_AUD_RECV	0x200000
144
#define F_AUD_MISS	0x400000
145
u_int options;
146
147
/* multicast options */
148
int moptions;
149
#define	MULTICAST_NOLOOP	0x001
150
151
#define DUMMY_PORT	10101
152
153
/*
154
 * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
155
 * number of received sequence numbers we can keep track of.  Change 128
156
 * to 8192 for complete accuracy...
157
 */
158
#define	MAX_DUP_CHK	(8 * 8192)
159
int mx_dup_ck = MAX_DUP_CHK;
160
char rcvd_tbl[MAX_DUP_CHK / 8];
161
162
struct sockaddr_in6 dst;	/* who to ping6 */
163
164
int datalen = DEFDATALEN;
165
int s;				/* socket file descriptor */
166
u_char outpack[MAXPACKETLEN];
167
char BSPACE = '\b';		/* characters written for flood */
168
char DOT = '.';
169
char *hostname;
170
int ident;			/* process id to identify our packets */
171
int hoplimit = -1;		/* hoplimit */
172
173
/* counters */
174
int64_t npackets;		/* max packets to transmit */
175
int64_t nreceived;		/* # of packets we got back */
176
int64_t nrepeats;		/* number of duplicates */
177
int64_t ntransmitted;		/* sequence # for outbound packets = #sent */
178
int64_t nmissedmax = 1;		/* max value of ntransmitted - nreceived - 1 */
179
struct timeval interval = {1, 0}; /* interval between packets */
180
181
/* timing */
182
int timing;			/* flag to do timing */
183
unsigned int maxwait = MAXWAIT_DEFAULT;	/* max seconds to wait for response */
184
double tmin = 999999999.0;	/* minimum round trip time */
185
double tmax = 0.0;		/* maximum round trip time */
186
double tsum = 0.0;		/* sum of all times, for doing average */
187
double tsumsq = 0.0;		/* sum of all times squared, for std. dev. */
188
struct tv64 tv64_offset;	/* random offset for time values */
189
SIPHASH_KEY mac_key;
190
191
/* for ancillary data(advanced API) */
192
struct msghdr smsghdr;
193
struct iovec smsgiov;
194
195
volatile sig_atomic_t seenalrm;
196
volatile sig_atomic_t seenint;
197
volatile sig_atomic_t seeninfo;
198
199
int	 main(int, char *[]);
200
void	 fill(char *, char *);
201
int	 get_hoplim(struct msghdr *);
202
int	 get_pathmtu(struct msghdr *);
203
struct in6_pktinfo *get_rcvpktinfo(struct msghdr *);
204
void	 onsignal(int);
205
void	 retransmit(void);
206
void	 onint(int);
207
int	 pinger(void);
208
const char *pr_addr(struct sockaddr *, socklen_t);
209
void	 pr_icmph(struct icmp6_hdr *, u_char *);
210
void	 pr_iph(struct ip6_hdr *);
211
void	 pr_pack(u_char *, int, struct msghdr *);
212
void	 pr_exthdrs(struct msghdr *);
213
void	 pr_ip6opt(void *);
214
void	 pr_rthdr(void *);
215
void	 pr_retip(struct ip6_hdr *, u_char *);
216
void	 summary(int);
217
void	 usage(void);
218
219
int
220
main(int argc, char *argv[])
221
{
222
	struct addrinfo *res0;
223
	struct itimerval itimer;
224
	struct sockaddr_in6 from, from6;
225
	struct addrinfo hints;
226
	int64_t preload;
227
	int ch, i, maxsize, packlen, optval, error;
228
	socklen_t maxsizelen;
229
	u_char *datap, *packet;
230
	char *e, *target;
231
	char *source = NULL;
232
	const char *errstr;
233
	struct cmsghdr *scmsg = NULL;
234
	struct in6_pktinfo *pktinfo = NULL;
235
	double intval;
236
	int mflag = 0, loop = 1;
237
	uid_t uid;
238
	u_int rtableid = 0;
239
240
	if ((s = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
241
		err(1, "socket");
242
243
	/* revoke privs */
244
	uid = getuid();
245
	if (setresuid(uid, uid, uid) == -1)
246
		err(1, "setresuid");
247
248
	preload = 0;
249
	datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN];
250
	while ((ch = getopt(argc, argv,
251
	    "c:dEefHh:I:i:Ll:mNnp:qS:s:V:vw:")) != -1) {
252
		switch (ch) {
253
		case 'c':
254
			npackets = strtonum(optarg, 0, INT64_MAX, &errstr);
255
			if (errstr)
256
				errx(1,
257
				    "number of packets to transmit is %s: %s",
258
				    errstr, optarg);
259
			break;
260
		case 'd':
261
			options |= F_SO_DEBUG;
262
			break;
263
		case 'E':
264
			options |= F_AUD_MISS;
265
			break;
266
		case 'e':
267
			options |= F_AUD_RECV;
268
			break;
269
		case 'f':
270
			if (getuid())
271
				errx(1, "%s", strerror(EPERM));
272
			options |= F_FLOOD;
273
			setvbuf(stdout, NULL, _IONBF, 0);
274
			break;
275
		case 'H':
276
			options |= F_HOSTNAME;
277
			break;
278
		case 'h':		/* hoplimit */
279
			hoplimit = strtonum(optarg, 0, IPV6_MAXHLIM, &errstr);
280
			if (errstr)
281
				errx(1, "hoplimit is %s: %s", errstr, optarg);
282
			break;
283
		case 'I':
284
		case 'S':	/* deprecated */
285
			source = optarg;
286
			break;
287
		case 'i':		/* wait between sending packets */
288
			intval = strtod(optarg, &e);
289
			if (*optarg == '\0' || *e != '\0')
290
				errx(1, "illegal timing interval %s", optarg);
291
			if (intval < 1 && getuid()) {
292
				errx(1, "%s: only root may use interval < 1s",
293
				    strerror(EPERM));
294
			}
295
			interval.tv_sec = (time_t)intval;
296
			interval.tv_usec =
297
			    (long)((intval - interval.tv_sec) * 1000000);
298
			if (interval.tv_sec < 0)
299
				errx(1, "illegal timing interval %s", optarg);
300
			/* less than 1/Hz does not make sense */
301
			if (interval.tv_sec == 0 && interval.tv_usec < 10000) {
302
				warnx("too small interval, raised to 0.01");
303
				interval.tv_usec = 10000;
304
			}
305
			options |= F_INTERVAL;
306
			break;
307
		case 'L':
308
			moptions |= MULTICAST_NOLOOP;
309
			loop = 0;
310
			break;
311
		case 'l':
312
			if (getuid())
313
				errx(1, "%s", strerror(EPERM));
314
			preload = strtonum(optarg, 1, INT64_MAX, &errstr);
315
			if (errstr)
316
				errx(1, "preload value is %s: %s", errstr,
317
				    optarg);
318
			break;
319
		case 'm':
320
			mflag++;
321
			break;
322
		case 'n':
323
			options &= ~F_HOSTNAME;
324
			break;
325
		case 'p':		/* fill buffer with user pattern */
326
			options |= F_PINGFILLED;
327
			fill((char *)datap, optarg);
328
				break;
329
		case 'q':
330
			options |= F_QUIET;
331
			break;
332
		case 's':		/* size of packet to send */
333
			datalen = strtonum(optarg, 0, MAXPAYLOAD, &errstr);
334
			if (errstr)
335
				errx(1, "packet size is %s: %s", errstr,
336
				    optarg);
337
			break;
338
		case 'V':
339
			rtableid = strtonum(optarg, 0, RT_TABLEID_MAX, &errstr);
340
			if (errstr)
341
				errx(1, "rtable value is %s: %s", errstr,
342
				    optarg);
343
			if (setsockopt(s, SOL_SOCKET, SO_RTABLE, &rtableid,
344
			    sizeof(rtableid)) == -1)
345
				err(1, "setsockopt SO_RTABLE");
346
			break;
347
		case 'v':
348
			options |= F_VERBOSE;
349
			break;
350
		case 'w':
351
			maxwait = strtonum(optarg, 1, INT_MAX, &errstr);
352
			if (errstr)
353
				errx(1, "maxwait value is %s: %s",
354
				    errstr, optarg);
355
			break;
356
		default:
357
			usage();
358
			/*NOTREACHED*/
359
		}
360
	}
361
362
	argc -= optind;
363
	argv += optind;
364
365
	if (argc < 1) {
366
		usage();
367
		/*NOTREACHED*/
368
	}
369
370
	if (argc != 1)
371
		usage();
372
373
	target = argv[argc - 1];
374
375
	/* getaddrinfo */
376
	memset(&hints, 0, sizeof(struct addrinfo));
377
	hints.ai_flags = AI_CANONNAME;
378
	hints.ai_family = AF_INET6;
379
	hints.ai_socktype = SOCK_RAW;
380
	hints.ai_protocol = IPPROTO_ICMPV6;
381
382
	error = getaddrinfo(target, NULL, &hints, &res0);
383
	if (error)
384
		errx(1, "host %s: %s", target, gai_strerror(error));
385
	if (res0->ai_canonname) {
386
		if ((hostname = strdup(res0->ai_canonname)) == NULL)
387
			errx(1, "out of memory");
388
	} else
389
		hostname = target;
390
	if (res0->ai_next && (options & F_VERBOSE))
391
		warnx("host resolves to multiple addresses");
392
	if (res0->ai_family != AF_INET6 || res0->ai_addrlen != sizeof(dst))
393
		errx(1, "getaddrinfo failed");
394
	memcpy(&dst, res0->ai_addr, sizeof(dst));
395
396
	freeaddrinfo(res0);
397
398
	/* set the source address if specified. */
399
	if (source) {
400
		memset(&hints, 0, sizeof(struct addrinfo));
401
		hints.ai_flags = AI_NUMERICHOST; /* allow hostname? */
402
		hints.ai_family = AF_INET6;
403
		hints.ai_socktype = SOCK_RAW;
404
		hints.ai_protocol = IPPROTO_ICMPV6;
405
406
		error = getaddrinfo(source, NULL, &hints, &res0);
407
		if (error)
408
			errx(1, "invalid source address: %s",
409
			     gai_strerror(error));
410
411
		if (res0->ai_family != AF_INET6 || res0->ai_addrlen !=
412
		    sizeof(from6))
413
			errx(1, "invalid source address");
414
		memcpy(&from6, res0->ai_addr, sizeof(from6));
415
		freeaddrinfo(res0);
416
		if (bind(s, (struct sockaddr *)&from6, sizeof(from6)) != 0)
417
			err(1, "bind");
418
	}
419
420
	/*
421
	 * let the kernel pass extension headers of incoming packets,
422
	 * for privileged socket options
423
	 */
424
	if ((options & F_VERBOSE) != 0) {
425
		int opton = 1;
426
427
		if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &opton,
428
		    (socklen_t)sizeof(opton)))
429
			err(1, "setsockopt(IPV6_RECVHOPOPTS)");
430
		if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTOPTS, &opton,
431
		    (socklen_t)sizeof(opton)))
432
			err(1, "setsockopt(IPV6_RECVDSTOPTS)");
433
	}
434
435
	if ((options & F_FLOOD) && (options & F_INTERVAL))
436
		errx(1, "-f and -i incompatible options");
437
438
	if ((options & F_FLOOD) && (options & (F_AUD_RECV | F_AUD_MISS)))
439
		warnx("No audible output for flood pings");
440
441
	if ((moptions & MULTICAST_NOLOOP) &&
442
	    setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop,
443
	    sizeof(loop)) < 0)
444
		err(1, "setsockopt IP6_MULTICAST_LOOP");
445
446
	if (datalen >= sizeof(struct payload)) {
447
		/* we can time transfer */
448
		timing = 1;
449
	} else
450
		timing = 0;
451
	/* in F_VERBOSE case, we may get non-echoreply packets*/
452
	if (options & F_VERBOSE)
453
		packlen = 2048 + IP6LEN + ICMP6ECHOLEN + EXTRA; /* XXX 2048? */
454
	else
455
		packlen = datalen + IP6LEN + ICMP6ECHOLEN + EXTRA;
456
457
	if (!(packet = malloc(packlen)))
458
		err(1, "Unable to allocate packet");
459
460
	/*
461
	 * When trying to send large packets, you must increase the
462
	 * size of both the send and receive buffers...
463
	 */
464
	maxsizelen = sizeof maxsize;
465
	if (getsockopt(s, SOL_SOCKET, SO_SNDBUF, &maxsize, &maxsizelen) < 0)
466
		err(1, "getsockopt");
467
	if (maxsize < packlen &&
468
	    setsockopt(s, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(maxsize)) < 0)
469
		err(1, "setsockopt");
470
471
	if (getsockopt(s, SOL_SOCKET, SO_RCVBUF, &maxsize, &maxsizelen) < 0)
472
		err(1, "getsockopt");
473
	if (maxsize < packlen &&
474
	    setsockopt(s, SOL_SOCKET, SO_RCVBUF, &packlen, sizeof(maxsize)) < 0)
475
		err(1, "setsockopt");
476
477
	if (!(options & F_PINGFILLED))
478
		for (i = ICMP6ECHOLEN; i < packlen; ++i)
479
			*datap++ = i;
480
481
	ident = getpid() & 0xFFFF;
482
483
	optval = 1;
484
485
	if (options & F_SO_DEBUG)
486
		(void)setsockopt(s, SOL_SOCKET, SO_DEBUG, &optval,
487
		    (socklen_t)sizeof(optval));
488
	optval = IPV6_DEFHLIM;
489
	if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr))
490
		if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
491
		    &optval, (socklen_t)sizeof(optval)) == -1)
492
			err(1, "IPV6_MULTICAST_HOPS");
493
	if (mflag != 1) {
494
		optval = mflag > 1 ? 0 : 1;
495
496
		if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
497
		    &optval, (socklen_t)sizeof(optval)) == -1)
498
			err(1, "setsockopt(IPV6_USE_MIN_MTU)");
499
	} else {
500
		optval = 1;
501
		if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPATHMTU,
502
		    &optval, sizeof(optval)) == -1)
503
			err(1, "setsockopt(IPV6_RECVPATHMTU)");
504
	}
505
506
507
    {
508
	struct icmp6_filter filt;
509
	if (!(options & F_VERBOSE)) {
510
		ICMP6_FILTER_SETBLOCKALL(&filt);
511
		ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt);
512
	} else {
513
		ICMP6_FILTER_SETPASSALL(&filt);
514
	}
515
	if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
516
	    (socklen_t)sizeof(filt)) < 0)
517
		err(1, "setsockopt(ICMP6_FILTER)");
518
    }
519
520
	/* let the kernel pass extension headers of incoming packets */
521
	if ((options & F_VERBOSE) != 0) {
522
		int opton = 1;
523
524
		if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDR, &opton,
525
		    sizeof(opton)))
526
			err(1, "setsockopt(IPV6_RECVRTHDR)");
527
	}
528
529
	if (hoplimit != -1) {
530
		/* set IP6 packet options */
531
		if ((scmsg = malloc( CMSG_SPACE(sizeof(int)))) == NULL)
532
			errx(1, "can't allocate enough memory");
533
		smsghdr.msg_control = (caddr_t)scmsg;
534
		smsghdr.msg_controllen =  CMSG_SPACE(sizeof(int));
535
536
		scmsg->cmsg_len = CMSG_LEN(sizeof(int));
537
		scmsg->cmsg_level = IPPROTO_IPV6;
538
		scmsg->cmsg_type = IPV6_HOPLIMIT;
539
		*(int *)(CMSG_DATA(scmsg)) = hoplimit;
540
	}
541
542
	if (!source && options & F_VERBOSE) {
543
		/*
544
		 * get the source address. XXX since we revoked the root
545
		 * privilege, we cannot use a raw socket for this.
546
		 */
547
		int dummy;
548
		socklen_t len = sizeof(from6);
549
550
		if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
551
			err(1, "UDP socket");
552
553
		from6.sin6_family = AF_INET6;
554
		from6.sin6_addr = dst.sin6_addr;
555
		from6.sin6_port = ntohs(DUMMY_PORT);
556
		from6.sin6_scope_id = dst.sin6_scope_id;
557
558
		if (pktinfo &&
559
		    setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTINFO,
560
		    (void *)pktinfo, sizeof(*pktinfo)))
561
			err(1, "UDP setsockopt(IPV6_PKTINFO)");
562
563
		if (hoplimit != -1 &&
564
		    setsockopt(dummy, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
565
		    (void *)&hoplimit, sizeof(hoplimit)))
566
			err(1, "UDP setsockopt(IPV6_UNICAST_HOPS)");
567
568
		if (hoplimit != -1 &&
569
		    setsockopt(dummy, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
570
		    (void *)&hoplimit, sizeof(hoplimit)))
571
			err(1, "UDP setsockopt(IPV6_MULTICAST_HOPS)");
572
573
		if (rtableid > 0 &&
574
		    setsockopt(dummy, SOL_SOCKET, SO_RTABLE, &rtableid,
575
		    sizeof(rtableid)) < 0)
576
			err(1, "setsockopt(SO_RTABLE)");
577
578
		if (connect(dummy, (struct sockaddr *)&from6, len) < 0)
579
			err(1, "UDP connect");
580
581
		if (getsockname(dummy, (struct sockaddr *)&from6, &len) < 0)
582
			err(1, "getsockname");
583
584
		close(dummy);
585
	}
586
587
	optval = 1;
588
	if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &optval,
589
	    (socklen_t)sizeof(optval)) < 0)
590
		warn("setsockopt(IPV6_RECVPKTINFO)"); /* XXX err? */
591
	if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &optval,
592
	    (socklen_t)sizeof(optval)) < 0)
593
		warn("setsockopt(IPV6_RECVHOPLIMIT)"); /* XXX err? */
594
595
	if (options & F_HOSTNAME) {
596
		if (pledge("stdio inet dns rpath cpath wpath", NULL) == -1)
597
			err(1, "pledge");
598
	} else {
599
		if (pledge("stdio inet rpath cpath wpath", NULL) == -1)
600
			err(1, "pledge");
601
	}
602
603
	arc4random_buf(&tv64_offset, sizeof(tv64_offset));
604
	arc4random_buf(&mac_key, sizeof(mac_key));
605
606
	printf("PING6 %s (", hostname);
607
	if (options & F_VERBOSE)
608
		printf("%s --> ", pr_addr((struct sockaddr *)&from6,
609
		    sizeof(from6)));
610
	printf("%s): %d data bytes\n", pr_addr((struct sockaddr *)&dst,
611
	    sizeof(dst)), datalen);
612
613
	while (preload--)		/* Fire off them quickies. */
614
		(void)pinger();
615
616
	(void)signal(SIGINT, onsignal);
617
	(void)signal(SIGINFO, onsignal);
618
619
	if ((options & F_FLOOD) == 0) {
620
		(void)signal(SIGALRM, onsignal);
621
		itimer.it_interval = interval;
622
		itimer.it_value = interval;
623
		(void)setitimer(ITIMER_REAL, &itimer, NULL);
624
		if (ntransmitted == 0)
625
			retransmit();
626
	}
627
628
	seenalrm = seenint = 0;
629
	seeninfo = 0;
630
631
	for (;;) {
632
		struct msghdr	m;
633
		union {
634
			struct cmsghdr hdr;
635
			u_char buf[CMSG_SPACE(1024)];
636
		}		cmsgbuf;
637
		struct iovec	iov[1];
638
		struct pollfd	pfd;
639
		ssize_t		cc;
640
		int		timeout;
641
642
		/* signal handling */
643
		if (seenalrm) {
644
			retransmit();
645
			seenalrm = 0;
646
			if (ntransmitted - nreceived - 1 > nmissedmax) {
647
				nmissedmax = ntransmitted - nreceived - 1;
648
				if (!(options & F_FLOOD) &&
649
				    (options & F_AUD_MISS))
650
					(void)fputc('\a', stderr);
651
			}
652
			continue;
653
		}
654
		if (seenint) {
655
			onint(SIGINT);
656
			seenint = 0;
657
			continue;
658
		}
659
		if (seeninfo) {
660
			summary(0);
661
			seeninfo = 0;
662
			continue;
663
		}
664
665
		if (options & F_FLOOD) {
666
			(void)pinger();
667
			timeout = 10;
668
		} else
669
			timeout = INFTIM;
670
671
		pfd.fd = s;
672
		pfd.events = POLLIN;
673
674
		if (poll(&pfd, 1, timeout) <= 0)
675
			continue;
676
677
		m.msg_name = &from;
678
		m.msg_namelen = sizeof(from);
679
		memset(&iov, 0, sizeof(iov));
680
		iov[0].iov_base = (caddr_t)packet;
681
		iov[0].iov_len = packlen;
682
		m.msg_iov = iov;
683
		m.msg_iovlen = 1;
684
		m.msg_control = (caddr_t)&cmsgbuf.buf;
685
		m.msg_controllen = sizeof(cmsgbuf.buf);
686
687
		cc = recvmsg(s, &m, 0);
688
		if (cc < 0) {
689
			if (errno != EINTR) {
690
				warn("recvmsg");
691
				sleep(1);
692
			}
693
			continue;
694
		} else if (cc == 0) {
695
			int mtu;
696
697
			/*
698
			 * receive control messages only. Process the
699
			 * exceptions (currently the only possibility is
700
			 * a path MTU notification.)
701
			 */
702
			if ((mtu = get_pathmtu(&m)) > 0) {
703
				if ((options & F_VERBOSE) != 0) {
704
					printf("new path MTU (%d) is "
705
					    "notified\n", mtu);
706
				}
707
			}
708
			continue;
709
		} else {
710
			/*
711
			 * an ICMPv6 message (probably an echoreply) arrived.
712
			 */
713
			pr_pack(packet, cc, &m);
714
		}
715
		if (npackets && nreceived >= npackets)
716
			break;
717
	}
718
	summary(0);
719
	exit(nreceived == 0);
720
}
721
722
void
723
onsignal(int sig)
724
{
725
726
	switch (sig) {
727
	case SIGALRM:
728
		seenalrm++;
729
		break;
730
	case SIGINT:
731
		seenint++;
732
		break;
733
	case SIGINFO:
734
		seeninfo++;
735
		break;
736
	}
737
}
738
739
/*
740
 * retransmit --
741
 *	This routine transmits another ping6.
742
 */
743
void
744
retransmit(void)
745
{
746
	struct itimerval itimer;
747
748
	if (pinger() == 0)
749
		return;
750
751
	/*
752
	 * If we're not transmitting any more packets, change the timer
753
	 * to wait two round-trip times if we've received any packets or
754
	 * maxwait seconds if we haven't.
755
	 */
756
	if (nreceived) {
757
		itimer.it_value.tv_sec =  2 * tmax / 1000;
758
		if (itimer.it_value.tv_sec == 0)
759
			itimer.it_value.tv_sec = 1;
760
	} else
761
		itimer.it_value.tv_sec = maxwait;
762
	itimer.it_interval.tv_sec = 0;
763
	itimer.it_interval.tv_usec = 0;
764
	itimer.it_value.tv_usec = 0;
765
766
	(void)signal(SIGALRM, onint);
767
	(void)setitimer(ITIMER_REAL, &itimer, NULL);
768
}
769
770
/*
771
 * pinger --
772
 *	Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
773
 * will be added on by the kernel.  The ID field is our UNIX process ID,
774
 * and the sequence number is an ascending integer.  The first 8 bytes
775
 * of the data portion are used to hold a UNIX "timeval" struct in VAX
776
 * byte-order, to compute the round-trip time.
777
 */
778
779
int
780
pinger(void)
781
{
782
	struct icmp6_hdr *icp;
783
	int i, cc;
784
	int seq;
785
786
	if (npackets && ntransmitted >= npackets)
787
		return(-1);	/* no more transmission */
788
789
	icp = (struct icmp6_hdr *)outpack;
790
	memset(icp, 0, sizeof(*icp));
791
	icp->icmp6_cksum = 0;
792
	seq = ntransmitted++;
793
	CLR(seq % mx_dup_ck);
794
795
	icp->icmp6_type = ICMP6_ECHO_REQUEST;
796
	icp->icmp6_code = 0;
797
	icp->icmp6_id = htons(ident);
798
	icp->icmp6_seq = ntohs(seq);
799
	if (timing) {
800
		SIPHASH_CTX ctx;
801
		struct timespec ts;
802
		struct payload payload;
803
		struct tv64 *tv64 = &payload.tv64;
804
805
		if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
806
			err(1, "clock_gettime(CLOCK_MONOTONIC)");
807
		tv64->tv64_sec = htobe64((u_int64_t)ts.tv_sec +
808
		    tv64_offset.tv64_sec);
809
		tv64->tv64_nsec = htobe64((u_int64_t)ts.tv_nsec +
810
		    tv64_offset.tv64_nsec);
811
812
		SipHash24_Init(&ctx, &mac_key);
813
		SipHash24_Update(&ctx, tv64, sizeof(*tv64));
814
		SipHash24_Update(&ctx, &ident, sizeof(ident));
815
		SipHash24_Update(&ctx,
816
		    &icp->icmp6_seq, sizeof(icp->icmp6_seq));
817
		SipHash24_Final(&payload.mac, &ctx);
818
819
		memcpy(&outpack[ICMP6ECHOLEN],
820
		    &payload, sizeof(payload));
821
	}
822
	cc = ICMP6ECHOLEN + datalen;
823
824
	smsghdr.msg_name = &dst;
825
	smsghdr.msg_namelen = sizeof(dst);
826
	smsgiov.iov_base = (caddr_t)outpack;
827
	smsgiov.iov_len = cc;
828
	smsghdr.msg_iov = &smsgiov;
829
	smsghdr.msg_iovlen = 1;
830
831
	i = sendmsg(s, &smsghdr, 0);
832
833
	if (i < 0 || i != cc)  {
834
		if (i < 0)
835
			warn("sendmsg");
836
		(void)printf("ping6: wrote %s %d chars, ret=%d\n",
837
		    hostname, cc, i);
838
	}
839
	if (!(options & F_QUIET) && options & F_FLOOD)
840
		(void)write(STDOUT_FILENO, &DOT, 1);
841
842
	return(0);
843
}
844
845
#define MINIMUM(a,b) (((a)<(b))?(a):(b))
846
847
/*
848
 * pr_pack --
849
 *	Print out the packet, if it came from us.  This logic is necessary
850
 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
851
 * which arrive ('tis only fair).  This permits multiple copies of this
852
 * program to be run without having intermingled output (or statistics!).
853
 */
854
void
855
pr_pack(u_char *buf, int cc, struct msghdr *mhdr)
856
{
857
#define safeputc(c)	printf((isprint((c)) ? "%c" : "\\%03o"), c)
858
	struct icmp6_hdr *icp;
859
	int i;
860
	int hoplim;
861
	struct sockaddr *from;
862
	socklen_t fromlen;
863
	u_char *cp = NULL, *dp, *end = buf + cc;
864
	struct in6_pktinfo *pktinfo = NULL;
865
	struct timespec ts, tp;
866
	struct payload payload;
867
	struct tv64 *tv64;
868
	double triptime = 0;
869
	int dupflag;
870
	u_int16_t seq;
871
872
	if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
873
		err(1, "clock_gettime(CLOCK_MONOTONIC)");
874
875
	if (!mhdr || !mhdr->msg_name ||
876
	    mhdr->msg_namelen != sizeof(struct sockaddr_in6) ||
877
	    ((struct sockaddr *)mhdr->msg_name)->sa_family != AF_INET6) {
878
		if (options & F_VERBOSE)
879
			warnx("invalid peername");
880
		return;
881
	}
882
	from = (struct sockaddr *)mhdr->msg_name;
883
	fromlen = mhdr->msg_namelen;
884
	if (cc < sizeof(struct icmp6_hdr)) {
885
		if (options & F_VERBOSE)
886
			warnx("packet too short (%d bytes) from %s", cc,
887
			    pr_addr(from, fromlen));
888
		return;
889
	}
890
	icp = (struct icmp6_hdr *)buf;
891
892
	if ((hoplim = get_hoplim(mhdr)) == -1) {
893
		warnx("failed to get receiving hop limit");
894
		return;
895
	}
896
	if ((pktinfo = get_rcvpktinfo(mhdr)) == NULL) {
897
		warnx("failed to get receiving packet information");
898
		return;
899
	}
900
901
	if (icp->icmp6_type == ICMP6_ECHO_REPLY) {
902
		if (ntohs(icp->icmp6_id) != ident)
903
			return;			/* 'Twas not our ECHO */
904
		seq = ntohs(icp->icmp6_seq);
905
		++nreceived;
906
		if (timing) {
907
			SIPHASH_CTX ctx;
908
			u_int8_t mac[SIPHASH_DIGEST_LENGTH];
909
910
			if (cc - sizeof(*cp) < sizeof(payload)) {
911
				(void)printf("signature missing!\n");
912
				return;
913
			}
914
915
			memcpy(&payload, icp + 1, sizeof(payload));
916
			tv64 = &payload.tv64;
917
918
			SipHash24_Init(&ctx, &mac_key);
919
			SipHash24_Update(&ctx, tv64, sizeof(*tv64));
920
			SipHash24_Update(&ctx, &ident, sizeof(ident));
921
			SipHash24_Update(&ctx,
922
			    &icp->icmp6_seq, sizeof(icp->icmp6_seq));
923
			SipHash24_Final(mac, &ctx);
924
925
			if (timingsafe_memcmp(mac, &payload.mac,
926
			    sizeof(mac)) != 0) {
927
				(void)printf("signature mismatch!\n");
928
				return;
929
			}
930
931
			tp.tv_sec = betoh64(tv64->tv64_sec) -
932
			    tv64_offset.tv64_sec;
933
			tp.tv_nsec = betoh64(tv64->tv64_nsec) -
934
			    tv64_offset.tv64_nsec;
935
			timespecsub(&ts, &tp, &ts);
936
			triptime = ((double)ts.tv_sec) * 1000.0 +
937
			    ((double)ts.tv_nsec) / 1000000.0;
938
			tsum += triptime;
939
			tsumsq += triptime * triptime;
940
			if (triptime < tmin)
941
				tmin = triptime;
942
			if (triptime > tmax)
943
				tmax = triptime;
944
		}
945
946
		if (TST(seq % mx_dup_ck)) {
947
			++nrepeats;
948
			--nreceived;
949
			dupflag = 1;
950
		} else {
951
			SET(seq % mx_dup_ck);
952
			dupflag = 0;
953
		}
954
955
		if (options & F_QUIET)
956
			return;
957
958
		if (options & F_FLOOD)
959
			(void)write(STDOUT_FILENO, &BSPACE, 1);
960
		else {
961
			(void)printf("%d bytes from %s, icmp_seq=%u", cc,
962
			    pr_addr(from, fromlen), seq);
963
			(void)printf(" hlim=%d", hoplim);
964
			if ((options & F_VERBOSE) != 0) {
965
				struct sockaddr_in6 dstsa;
966
967
				memset(&dstsa, 0, sizeof(dstsa));
968
				dstsa.sin6_family = AF_INET6;
969
				dstsa.sin6_len = sizeof(dstsa);
970
				dstsa.sin6_scope_id = pktinfo->ipi6_ifindex;
971
				dstsa.sin6_addr = pktinfo->ipi6_addr;
972
				(void)printf(" dst=%s",
973
				    pr_addr((struct sockaddr *)&dstsa,
974
				    sizeof(dstsa)));
975
			}
976
			if (timing)
977
				(void)printf(" time=%.3f ms", triptime);
978
			if (dupflag)
979
				(void)printf("(DUP!)");
980
			if (options & F_AUD_RECV)
981
				(void)fputc('\a', stderr);
982
			/* check the data */
983
			cp = buf + ICMP6ECHOLEN + ICMP6ECHOTMLEN;
984
			dp = outpack + ICMP6ECHOLEN + ICMP6ECHOTMLEN;
985
			if (cc != ICMP6ECHOLEN + datalen) {
986
				int delta = cc - (datalen + ICMP6ECHOLEN);
987
988
				(void)printf(" (%d bytes %s)",
989
				    abs(delta), delta > 0 ? "extra" : "short");
990
				end = buf + MINIMUM(cc, ICMP6ECHOLEN + datalen);
991
			}
992
			for (i = 8; cp < end; ++i, ++cp, ++dp) {
993
				if (*cp != *dp) {
994
					(void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", i, *dp, *cp);
995
					break;
996
				}
997
			}
998
		}
999
	} else {
1000
		/* We've got something other than an ECHOREPLY */
1001
		if (!(options & F_VERBOSE))
1002
			return;
1003
		(void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen));
1004
		pr_icmph(icp, end);
1005
	}
1006
1007
	if (!(options & F_FLOOD)) {
1008
		(void)putchar('\n');
1009
		if (options & F_VERBOSE)
1010
			pr_exthdrs(mhdr);
1011
		(void)fflush(stdout);
1012
	}
1013
#undef safeputc
1014
}
1015
1016
void
1017
pr_exthdrs(struct msghdr *mhdr)
1018
{
1019
	struct cmsghdr *cm;
1020
1021
	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
1022
	     cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
1023
		if (cm->cmsg_level != IPPROTO_IPV6)
1024
			continue;
1025
1026
		switch (cm->cmsg_type) {
1027
		case IPV6_HOPOPTS:
1028
			printf("  HbH Options: ");
1029
			pr_ip6opt(CMSG_DATA(cm));
1030
			break;
1031
		case IPV6_DSTOPTS:
1032
		case IPV6_RTHDRDSTOPTS:
1033
			printf("  Dst Options: ");
1034
			pr_ip6opt(CMSG_DATA(cm));
1035
			break;
1036
		case IPV6_RTHDR:
1037
			printf("  Routing: ");
1038
			pr_rthdr(CMSG_DATA(cm));
1039
			break;
1040
		}
1041
	}
1042
}
1043
1044
void
1045
pr_ip6opt(void *extbuf)
1046
{
1047
	struct ip6_hbh *ext;
1048
	int currentlen;
1049
	u_int8_t type;
1050
	size_t extlen;
1051
	socklen_t len;
1052
	void *databuf;
1053
	u_int16_t value2;
1054
	u_int32_t value4;
1055
1056
	ext = (struct ip6_hbh *)extbuf;
1057
	extlen = (ext->ip6h_len + 1) * 8;
1058
	printf("nxt %u, len %u (%lu bytes)\n", ext->ip6h_nxt,
1059
	    (unsigned int)ext->ip6h_len, (unsigned long)extlen);
1060
1061
	currentlen = 0;
1062
	while (1) {
1063
		currentlen = inet6_opt_next(extbuf, extlen, currentlen,
1064
		    &type, &len, &databuf);
1065
		if (currentlen == -1)
1066
			break;
1067
		switch (type) {
1068
		/*
1069
		 * Note that inet6_opt_next automatically skips any padding
1070
		 * options.
1071
		 */
1072
		case IP6OPT_JUMBO:
1073
			inet6_opt_get_val(databuf, 0, &value4, sizeof(value4));
1074
			printf("    Jumbo Payload Opt: Length %u\n",
1075
			    (u_int32_t)ntohl(value4));
1076
			break;
1077
		case IP6OPT_ROUTER_ALERT:
1078
			inet6_opt_get_val(databuf, 0, &value2, sizeof(value2));
1079
			printf("    Router Alert Opt: Type %u\n",
1080
			    ntohs(value2));
1081
			break;
1082
		default:
1083
			printf("    Received Opt %u len %lu\n",
1084
			    type, (unsigned long)len);
1085
			break;
1086
		}
1087
	}
1088
	return;
1089
}
1090
1091
void
1092
pr_rthdr(void *extbuf)
1093
{
1094
	struct in6_addr *in6;
1095
	char ntopbuf[INET6_ADDRSTRLEN];
1096
	struct ip6_rthdr *rh = (struct ip6_rthdr *)extbuf;
1097
	int i, segments;
1098
1099
	/* print fixed part of the header */
1100
	printf("nxt %u, len %u (%d bytes), type %u, ", rh->ip6r_nxt,
1101
	    rh->ip6r_len, (rh->ip6r_len + 1) << 3, rh->ip6r_type);
1102
	if ((segments = inet6_rth_segments(extbuf)) >= 0)
1103
		printf("%d segments, ", segments);
1104
	else
1105
		printf("segments unknown, ");
1106
	printf("%d left\n", rh->ip6r_segleft);
1107
1108
	for (i = 0; i < segments; i++) {
1109
		in6 = inet6_rth_getaddr(extbuf, i);
1110
		if (in6 == NULL)
1111
			printf("   [%d]<NULL>\n", i);
1112
		else {
1113
			if (!inet_ntop(AF_INET6, in6, ntopbuf,
1114
			    sizeof(ntopbuf)))
1115
				strncpy(ntopbuf, "?", sizeof(ntopbuf));
1116
			printf("   [%d]%s\n", i, ntopbuf);
1117
		}
1118
	}
1119
1120
	return;
1121
1122
}
1123
1124
int
1125
get_hoplim(struct msghdr *mhdr)
1126
{
1127
	struct cmsghdr *cm;
1128
1129
	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
1130
	     cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
1131
		if (cm->cmsg_len == 0)
1132
			return(-1);
1133
1134
		if (cm->cmsg_level == IPPROTO_IPV6 &&
1135
		    cm->cmsg_type == IPV6_HOPLIMIT &&
1136
		    cm->cmsg_len == CMSG_LEN(sizeof(int)))
1137
			return(*(int *)CMSG_DATA(cm));
1138
	}
1139
1140
	return(-1);
1141
}
1142
1143
struct in6_pktinfo *
1144
get_rcvpktinfo(struct msghdr *mhdr)
1145
{
1146
	struct cmsghdr *cm;
1147
1148
	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
1149
	     cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
1150
		if (cm->cmsg_len == 0)
1151
			return(NULL);
1152
1153
		if (cm->cmsg_level == IPPROTO_IPV6 &&
1154
		    cm->cmsg_type == IPV6_PKTINFO &&
1155
		    cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo)))
1156
			return((struct in6_pktinfo *)CMSG_DATA(cm));
1157
	}
1158
1159
	return(NULL);
1160
}
1161
1162
int
1163
get_pathmtu(struct msghdr *mhdr)
1164
{
1165
	struct cmsghdr *cm;
1166
	struct ip6_mtuinfo *mtuctl = NULL;
1167
1168
	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
1169
	     cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
1170
		if (cm->cmsg_len == 0)
1171
			return(0);
1172
1173
		if (cm->cmsg_level == IPPROTO_IPV6 &&
1174
		    cm->cmsg_type == IPV6_PATHMTU &&
1175
		    cm->cmsg_len == CMSG_LEN(sizeof(struct ip6_mtuinfo))) {
1176
			mtuctl = (struct ip6_mtuinfo *)CMSG_DATA(cm);
1177
1178
			/*
1179
			 * If the notified destination is different from
1180
			 * the one we are pinging, just ignore the info.
1181
			 * We check the scope ID only when both notified value
1182
			 * and our own value have non-0 values, because we may
1183
			 * have used the default scope zone ID for sending,
1184
			 * in which case the scope ID value is 0.
1185
			 */
1186
			if (!IN6_ARE_ADDR_EQUAL(&mtuctl->ip6m_addr.sin6_addr,
1187
						&dst.sin6_addr) ||
1188
			    (mtuctl->ip6m_addr.sin6_scope_id &&
1189
			     dst.sin6_scope_id &&
1190
			     mtuctl->ip6m_addr.sin6_scope_id !=
1191
			     dst.sin6_scope_id)) {
1192
				if ((options & F_VERBOSE) != 0) {
1193
					printf("path MTU for %s is notified. "
1194
					       "(ignored)\n",
1195
					   pr_addr((struct sockaddr *)&mtuctl->ip6m_addr,
1196
					   sizeof(mtuctl->ip6m_addr)));
1197
				}
1198
				return(0);
1199
			}
1200
1201
			/*
1202
			 * Ignore an invalid MTU. XXX: can we just believe
1203
			 * the kernel check?
1204
			 */
1205
			if (mtuctl->ip6m_mtu < IPV6_MMTU)
1206
				return(0);
1207
1208
			/* notification for our destination. return the MTU. */
1209
			return((int)mtuctl->ip6m_mtu);
1210
		}
1211
	}
1212
	return(0);
1213
}
1214
1215
/*
1216
 * onint --
1217
 *	SIGINT handler.
1218
 */
1219
void
1220
onint(int signo)
1221
{
1222
	summary(signo);
1223
1224
	if (signo)
1225
		_exit(nreceived ? 0 : 1);
1226
	else
1227
		exit(nreceived ? 0 : 1);
1228
}
1229
1230
/*
1231
 * summary --
1232
 *	Print out statistics.
1233
 */
1234
void
1235
summary(int signo)
1236
{
1237
	char buf[8192], buft[8192];
1238
1239
	buf[0] = '\0';
1240
1241
	snprintf(buft, sizeof(buft), "--- %s ping6 statistics ---\n",
1242
	    hostname);
1243
	strlcat(buf, buft, sizeof(buf));
1244
	snprintf(buft, sizeof(buft), "%lld packets transmitted, ",
1245
	    ntransmitted);
1246
	strlcat(buf, buft, sizeof(buf));
1247
	snprintf(buft, sizeof(buft), "%lld packets received, ",
1248
	    nreceived);
1249
	strlcat(buf, buft, sizeof(buf));
1250
	if (nrepeats) {
1251
		snprintf(buft, sizeof(buft), "+%lld duplicates, ",
1252
		    nrepeats);
1253
		strlcat(buf, buft, sizeof(buf));
1254
	}
1255
	if (ntransmitted) {
1256
		if (nreceived > ntransmitted)
1257
			snprintf(buft, sizeof(buft),
1258
			    "-- somebody's duplicating packets!");
1259
		else
1260
			snprintf(buft, sizeof(buft), "%.1lf%% packet loss",
1261
			    ((((double)ntransmitted - nreceived) * 100) /
1262
			    ntransmitted));
1263
		strlcat(buf, buft, sizeof(buf));
1264
	}
1265
	strlcat(buf, "\n", sizeof(buf));
1266
	if (nreceived && timing) {
1267
		/* Only display average to microseconds */
1268
		double num = nreceived + nrepeats;
1269
		double avg = tsum / num;
1270
		double dev = sqrt(fmax(0, tsumsq / num - avg * avg));
1271
		snprintf(buft, sizeof(buft),
1272
		    "round-trip min/avg/max/std-dev = %.3f/%.3f/%.3f/%.3f ms\n",
1273
		    tmin, avg, tmax, dev);
1274
		strlcat(buf, buft, sizeof(buf));
1275
	}
1276
	write(STDOUT_FILENO, buf, strlen(buf));
1277
	if (signo == 0)
1278
		(void)fflush(stdout);
1279
}
1280
1281
/*
1282
 * pr_icmph --
1283
 *	Print a descriptive string about an ICMP header.
1284
 */
1285
void
1286
pr_icmph(struct icmp6_hdr *icp, u_char *end)
1287
{
1288
	char ntop_buf[INET6_ADDRSTRLEN];
1289
	struct nd_redirect *red;
1290
1291
	switch (icp->icmp6_type) {
1292
	case ICMP6_DST_UNREACH:
1293
		switch (icp->icmp6_code) {
1294
		case ICMP6_DST_UNREACH_NOROUTE:
1295
			(void)printf("No Route to Destination\n");
1296
			break;
1297
		case ICMP6_DST_UNREACH_ADMIN:
1298
			(void)printf("Destination Administratively "
1299
			    "Unreachable\n");
1300
			break;
1301
		case ICMP6_DST_UNREACH_BEYONDSCOPE:
1302
			(void)printf("Destination Unreachable Beyond Scope\n");
1303
			break;
1304
		case ICMP6_DST_UNREACH_ADDR:
1305
			(void)printf("Destination Host Unreachable\n");
1306
			break;
1307
		case ICMP6_DST_UNREACH_NOPORT:
1308
			(void)printf("Destination Port Unreachable\n");
1309
			break;
1310
		default:
1311
			(void)printf("Destination Unreachable, Bad Code: %d\n",
1312
			    icp->icmp6_code);
1313
			break;
1314
		}
1315
		/* Print returned IP header information */
1316
		pr_retip((struct ip6_hdr *)(icp + 1), end);
1317
		break;
1318
	case ICMP6_PACKET_TOO_BIG:
1319
		(void)printf("Packet too big mtu = %d\n",
1320
		    (int)ntohl(icp->icmp6_mtu));
1321
		pr_retip((struct ip6_hdr *)(icp + 1), end);
1322
		break;
1323
	case ICMP6_TIME_EXCEEDED:
1324
		switch (icp->icmp6_code) {
1325
		case ICMP6_TIME_EXCEED_TRANSIT:
1326
			(void)printf("Time to live exceeded\n");
1327
			break;
1328
		case ICMP6_TIME_EXCEED_REASSEMBLY:
1329
			(void)printf("Frag reassembly time exceeded\n");
1330
			break;
1331
		default:
1332
			(void)printf("Time exceeded, Bad Code: %d\n",
1333
			    icp->icmp6_code);
1334
			break;
1335
		}
1336
		pr_retip((struct ip6_hdr *)(icp + 1), end);
1337
		break;
1338
	case ICMP6_PARAM_PROB:
1339
		(void)printf("Parameter problem: ");
1340
		switch (icp->icmp6_code) {
1341
		case ICMP6_PARAMPROB_HEADER:
1342
			(void)printf("Erroneous Header ");
1343
			break;
1344
		case ICMP6_PARAMPROB_NEXTHEADER:
1345
			(void)printf("Unknown Nextheader ");
1346
			break;
1347
		case ICMP6_PARAMPROB_OPTION:
1348
			(void)printf("Unrecognized Option ");
1349
			break;
1350
		default:
1351
			(void)printf("Bad code(%d) ", icp->icmp6_code);
1352
			break;
1353
		}
1354
		(void)printf("pointer = 0x%02x\n",
1355
		    (u_int32_t)ntohl(icp->icmp6_pptr));
1356
		pr_retip((struct ip6_hdr *)(icp + 1), end);
1357
		break;
1358
	case ICMP6_ECHO_REQUEST:
1359
		(void)printf("Echo Request");
1360
		/* XXX ID + Seq + Data */
1361
		break;
1362
	case ICMP6_ECHO_REPLY:
1363
		(void)printf("Echo Reply");
1364
		/* XXX ID + Seq + Data */
1365
		break;
1366
	case ICMP6_MEMBERSHIP_QUERY:
1367
		(void)printf("Listener Query");
1368
		break;
1369
	case ICMP6_MEMBERSHIP_REPORT:
1370
		(void)printf("Listener Report");
1371
		break;
1372
	case ICMP6_MEMBERSHIP_REDUCTION:
1373
		(void)printf("Listener Done");
1374
		break;
1375
	case ND_ROUTER_SOLICIT:
1376
		(void)printf("Router Solicitation");
1377
		break;
1378
	case ND_ROUTER_ADVERT:
1379
		(void)printf("Router Advertisement");
1380
		break;
1381
	case ND_NEIGHBOR_SOLICIT:
1382
		(void)printf("Neighbor Solicitation");
1383
		break;
1384
	case ND_NEIGHBOR_ADVERT:
1385
		(void)printf("Neighbor Advertisement");
1386
		break;
1387
	case ND_REDIRECT:
1388
		red = (struct nd_redirect *)icp;
1389
		(void)printf("Redirect\n");
1390
		if (!inet_ntop(AF_INET6, &red->nd_rd_dst, ntop_buf,
1391
		    sizeof(ntop_buf)))
1392
			strncpy(ntop_buf, "?", sizeof(ntop_buf));
1393
		(void)printf("Destination: %s", ntop_buf);
1394
		if (!inet_ntop(AF_INET6, &red->nd_rd_target, ntop_buf,
1395
		    sizeof(ntop_buf)))
1396
			strncpy(ntop_buf, "?", sizeof(ntop_buf));
1397
		(void)printf(" New Target: %s", ntop_buf);
1398
		break;
1399
	default:
1400
		(void)printf("Bad ICMP type: %d", icp->icmp6_type);
1401
	}
1402
}
1403
1404
/*
1405
 * pr_iph --
1406
 *	Print an IP6 header.
1407
 */
1408
void
1409
pr_iph(struct ip6_hdr *ip6)
1410
{
1411
	u_int32_t flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK;
1412
	u_int8_t tc;
1413
	char ntop_buf[INET6_ADDRSTRLEN];
1414
1415
	tc = *(&ip6->ip6_vfc + 1); /* XXX */
1416
	tc = (tc >> 4) & 0x0f;
1417
	tc |= (ip6->ip6_vfc << 4);
1418
1419
	printf("Vr TC  Flow Plen Nxt Hlim\n");
1420
	printf(" %1x %02x %05x %04x  %02x   %02x\n",
1421
	    (ip6->ip6_vfc & IPV6_VERSION_MASK) >> 4, tc, (u_int32_t)ntohl(flow),
1422
	    ntohs(ip6->ip6_plen), ip6->ip6_nxt, ip6->ip6_hlim);
1423
	if (!inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf, sizeof(ntop_buf)))
1424
		strncpy(ntop_buf, "?", sizeof(ntop_buf));
1425
	printf("%s->", ntop_buf);
1426
	if (!inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf, sizeof(ntop_buf)))
1427
		strncpy(ntop_buf, "?", sizeof(ntop_buf));
1428
	printf("%s\n", ntop_buf);
1429
}
1430
1431
/*
1432
 * pr_addr --
1433
 *	Return an ascii host address as a dotted quad and optionally with
1434
 * a hostname.
1435
 */
1436
const char *
1437
pr_addr(struct sockaddr *addr, socklen_t addrlen)
1438
{
1439
	static char buf[NI_MAXHOST];
1440
	int flag = 0;
1441
1442
	if ((options & F_HOSTNAME) == 0)
1443
		flag |= NI_NUMERICHOST;
1444
1445
	if (getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, flag) == 0)
1446
		return (buf);
1447
	else
1448
		return "?";
1449
}
1450
1451
/*
1452
 * pr_retip --
1453
 *	Dump some info on a returned (via ICMPv6) IPv6 packet.
1454
 */
1455
void
1456
pr_retip(struct ip6_hdr *ip6, u_char *end)
1457
{
1458
	u_char *cp = (u_char *)ip6, nh;
1459
	int hlen;
1460
1461
	if (end - (u_char *)ip6 < sizeof(*ip6)) {
1462
		printf("IP6");
1463
		goto trunc;
1464
	}
1465
	pr_iph(ip6);
1466
	hlen = sizeof(*ip6);
1467
1468
	nh = ip6->ip6_nxt;
1469
	cp += hlen;
1470
	while (end - cp >= 8) {
1471
		switch (nh) {
1472
		case IPPROTO_HOPOPTS:
1473
			printf("HBH ");
1474
			hlen = (((struct ip6_hbh *)cp)->ip6h_len+1) << 3;
1475
			nh = ((struct ip6_hbh *)cp)->ip6h_nxt;
1476
			break;
1477
		case IPPROTO_DSTOPTS:
1478
			printf("DSTOPT ");
1479
			hlen = (((struct ip6_dest *)cp)->ip6d_len+1) << 3;
1480
			nh = ((struct ip6_dest *)cp)->ip6d_nxt;
1481
			break;
1482
		case IPPROTO_FRAGMENT:
1483
			printf("FRAG ");
1484
			hlen = sizeof(struct ip6_frag);
1485
			nh = ((struct ip6_frag *)cp)->ip6f_nxt;
1486
			break;
1487
		case IPPROTO_ROUTING:
1488
			printf("RTHDR ");
1489
			hlen = (((struct ip6_rthdr *)cp)->ip6r_len+1) << 3;
1490
			nh = ((struct ip6_rthdr *)cp)->ip6r_nxt;
1491
			break;
1492
		case IPPROTO_AH:
1493
			printf("AH ");
1494
			hlen = (((struct ah *)cp)->ah_hl+2) << 2;
1495
			nh = ((struct ah *)cp)->ah_nh;
1496
			break;
1497
		case IPPROTO_ICMPV6:
1498
			printf("ICMP6: type = %d, code = %d\n",
1499
			    *cp, *(cp + 1));
1500
			return;
1501
		case IPPROTO_ESP:
1502
			printf("ESP\n");
1503
			return;
1504
		case IPPROTO_TCP:
1505
			printf("TCP: from port %u, to port %u (decimal)\n",
1506
			    (*cp * 256 + *(cp + 1)),
1507
			    (*(cp + 2) * 256 + *(cp + 3)));
1508
			return;
1509
		case IPPROTO_UDP:
1510
			printf("UDP: from port %u, to port %u (decimal)\n",
1511
			    (*cp * 256 + *(cp + 1)),
1512
			    (*(cp + 2) * 256 + *(cp + 3)));
1513
			return;
1514
		default:
1515
			printf("Unknown Header(%d)\n", nh);
1516
			return;
1517
		}
1518
1519
		if ((cp += hlen) >= end)
1520
			goto trunc;
1521
	}
1522
	if (end - cp < 8)
1523
		goto trunc;
1524
1525
	putchar('\n');
1526
	return;
1527
1528
  trunc:
1529
	printf("...\n");
1530
	return;
1531
}
1532
1533
void
1534
fill(char *bp, char *patp)
1535
{
1536
	int ii, jj, kk;
1537
	int pat[16];
1538
	char *cp;
1539
1540
	for (cp = patp; *cp; cp++)
1541
		if (!isxdigit((unsigned char)*cp))
1542
			errx(1, "patterns must be specified as hex digits");
1543
	ii = sscanf(patp,
1544
	    "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
1545
	    &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
1546
	    &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
1547
	    &pat[13], &pat[14], &pat[15]);
1548
1549
/* xxx */
1550
	if (ii > 0)
1551
		for (kk = 0;
1552
		    kk <= MAXPAYLOAD - (8 + sizeof(struct payload) + ii);
1553
		    kk += ii)
1554
			for (jj = 0; jj < ii; ++jj)
1555
				bp[jj + kk] = pat[jj];
1556
	if (!(options & F_QUIET)) {
1557
		(void)printf("PATTERN: 0x");
1558
		for (jj = 0; jj < ii; ++jj)
1559
			(void)printf("%02x", bp[jj] & 0xFF);
1560
		(void)printf("\n");
1561
	}
1562
}
1563
1564
void
1565
usage(void)
1566
{
1567
	(void)fprintf(stderr,
1568
	    "usage: ping6 [-dEefHLmnqv] [-c count] [-h hoplimit] "
1569
	    "[-I sourceaddr]\n\t[-i wait] [-l preload] [-p pattern] "
1570
	    "[-s packetsize] [-V rtable]\n\t[-w maxwait] host\n");
1571
	exit(1);
1572
}