GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/traceroute/worker.c Lines: 0 452 0.0 %
Date: 2017-11-13 Branches: 0 300 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: worker.c,v 1.5 2017/08/03 17:36:06 florian Exp $	*/
2
/*	$NetBSD: traceroute.c,v 1.10 1995/05/21 15:50:45 mycroft 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
/*-
34
 * Copyright (c) 1990, 1993
35
 *	The Regents of the University of California.  All rights reserved.
36
 *
37
 * This code is derived from software contributed to Berkeley by
38
 * Van Jacobson.
39
 *
40
 * Redistribution and use in source and binary forms, with or without
41
 * modification, are permitted provided that the following conditions
42
 * are met:
43
 * 1. Redistributions of source code must retain the above copyright
44
 *    notice, this list of conditions and the following disclaimer.
45
 * 2. Redistributions in binary form must reproduce the above copyright
46
 *    notice, this list of conditions and the following disclaimer in the
47
 *    documentation and/or other materials provided with the distribution.
48
 * 3. Neither the name of the University nor the names of its contributors
49
 *    may be used to endorse or promote products derived from this software
50
 *    without specific prior written permission.
51
 *
52
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62
 * SUCH DAMAGE.
63
 */
64
65
#include <arpa/inet.h>
66
#include <arpa/nameser.h>
67
#include <endian.h>
68
#include <err.h>
69
#include <limits.h>
70
#include <netdb.h>
71
#include <netinet/icmp6.h>
72
#include <netinet/in.h>
73
#include <netinet/ip.h>
74
#include <netinet/ip6.h>
75
#include <netinet/ip_icmp.h>
76
#include <netinet/udp.h>
77
#include <poll.h>
78
#include <stdio.h>
79
#include <string.h>
80
#include <sys/socket.h>
81
#include <sys/time.h>
82
#include <sys/types.h>
83
#include <sys/uio.h>
84
#include <time.h>
85
#include <unistd.h>
86
87
#include "traceroute.h"
88
89
static u_int8_t	icmp_type = ICMP_ECHO; /* default ICMP code/type */
90
91
void
92
print_exthdr(u_char *buf, int cc)
93
{
94
	struct icmp_ext_hdr exthdr;
95
	struct icmp_ext_obj_hdr objhdr;
96
	struct ip *ip;
97
	struct icmp *icp;
98
	int hlen, first;
99
	u_int32_t label;
100
	u_int16_t off, olen;
101
	u_int8_t type;
102
103
	ip = (struct ip *)buf;
104
	hlen = ip->ip_hl << 2;
105
	if (cc < hlen + ICMP_MINLEN)
106
		return;
107
	icp = (struct icmp *)(buf + hlen);
108
	cc -= hlen + ICMP_MINLEN;
109
	buf += hlen + ICMP_MINLEN;
110
111
	type = icp->icmp_type;
112
	if (type != ICMP_TIMXCEED && type != ICMP_UNREACH &&
113
	    type != ICMP_PARAMPROB)
114
		/* Wrong ICMP type for extension */
115
		return;
116
117
	off = icp->icmp_length * sizeof(u_int32_t);
118
	if (off == 0)
119
		/*
120
		 * rfc 4884 Section 5.5: traceroute MUST try to parse
121
		 * broken ext headers. Again IETF bent over to please
122
		 * idotic corporations.
123
		 */
124
		off = ICMP_EXT_OFFSET;
125
	else if (off < ICMP_EXT_OFFSET)
126
		/* rfc 4884 requires an offset of at least 128 bytes */
127
		return;
128
129
	/* make sure that at least one extension is present */
130
	if (cc < off + sizeof(exthdr) + sizeof(objhdr))
131
		/* Not enough space for ICMP extensions */
132
		return;
133
134
	cc -= off;
135
	buf += off;
136
	memcpy(&exthdr, buf, sizeof(exthdr));
137
138
	/* verify version */
139
	if ((exthdr.ieh_version & ICMP_EXT_HDR_VMASK) != ICMP_EXT_HDR_VERSION)
140
		return;
141
142
	/* verify checksum */
143
	if (exthdr.ieh_cksum && in_cksum((u_short *)buf, cc))
144
		return;
145
146
	buf += sizeof(exthdr);
147
	cc -= sizeof(exthdr);
148
149
	while (cc > sizeof(objhdr)) {
150
		memcpy(&objhdr, buf, sizeof(objhdr));
151
		olen = ntohs(objhdr.ieo_length);
152
153
		/* Sanity check the length field */
154
		if (olen < sizeof(objhdr) || olen > cc)
155
			return;
156
157
		cc -= olen;
158
159
		/* Move past the object header */
160
		buf += sizeof(objhdr);
161
		olen -= sizeof(objhdr);
162
163
		switch (objhdr.ieo_cnum) {
164
		case ICMP_EXT_MPLS:
165
			/* RFC 4950: ICMP Extensions for MPLS */
166
			switch (objhdr.ieo_ctype) {
167
			case 1:
168
				first = 0;
169
				while (olen >= sizeof(u_int32_t)) {
170
					memcpy(&label, buf, sizeof(u_int32_t));
171
					label = htonl(label);
172
					buf += sizeof(u_int32_t);
173
					olen -= sizeof(u_int32_t);
174
175
					if (first == 0) {
176
						printf(" [MPLS Label ");
177
						first++;
178
					} else
179
						printf(", ");
180
					printf("%d", MPLS_LABEL(label));
181
					if (MPLS_EXP(label))
182
						printf(" (Exp %x)",
183
						    MPLS_EXP(label));
184
				}
185
				if (olen > 0) {
186
					printf("|]");
187
					return;
188
				}
189
				if (first != 0)
190
					printf("]");
191
				break;
192
			default:
193
				buf += olen;
194
				break;
195
			}
196
			break;
197
		case ICMP_EXT_IFINFO:
198
		default:
199
			buf += olen;
200
			break;
201
		}
202
	}
203
}
204
205
void
206
check_tos(struct ip *ip, int *last_tos)
207
{
208
	struct icmp *icp;
209
	struct ip *inner_ip;
210
211
	icp = (struct icmp *) (((u_char *)ip)+(ip->ip_hl<<2));
212
	inner_ip = (struct ip *) (((u_char *)icp)+8);
213
214
	if (inner_ip->ip_tos != *last_tos)
215
		printf (" (TOS=%d!)", inner_ip->ip_tos);
216
217
	*last_tos = inner_ip->ip_tos;
218
}
219
220
int
221
wait_for_reply(int sock, struct msghdr *mhdr, int curwaittime)
222
{
223
	struct pollfd pfd[1];
224
	int cc = 0;
225
226
	pfd[0].fd = sock;
227
	pfd[0].events = POLLIN;
228
	pfd[0].revents = 0;
229
230
	if (poll(pfd, 1, curwaittime) > 0)
231
		cc = recvmsg(rcvsock, mhdr, 0);
232
233
	return (cc);
234
}
235
236
void
237
dump_packet(void)
238
{
239
	u_char *p;
240
	int i;
241
242
	fprintf(stderr, "packet data:");
243
	for (p = outpacket, i = 0; i < datalen; i++) {
244
		if ((i % 24) == 0)
245
			fprintf(stderr, "\n ");
246
		fprintf(stderr, " %02x", *p++);
247
	}
248
	fprintf(stderr, "\n");
249
}
250
251
void
252
build_probe4(struct tr_conf *conf, int seq, u_int8_t ttl, int iflag)
253
{
254
	struct ip *ip = (struct ip *)outpacket;
255
	u_char *p = (u_char *)(ip + 1);
256
	struct udphdr *up = (struct udphdr *)(p + conf->lsrrlen);
257
	struct icmp *icmpp = (struct icmp *)(p + conf->lsrrlen);
258
	struct packetdata *op;
259
	struct timeval tv;
260
261
	ip->ip_len = htons(datalen);
262
	ip->ip_ttl = ttl;
263
	ip->ip_id = htons(conf->ident+seq);
264
265
	switch (conf->proto) {
266
	case IPPROTO_ICMP:
267
		icmpp->icmp_type = icmp_type;
268
		icmpp->icmp_code = ICMP_CODE;
269
		icmpp->icmp_seq = htons(seq);
270
		icmpp->icmp_id = htons(conf->ident);
271
		op = (struct packetdata *)(icmpp + 1);
272
		break;
273
	case IPPROTO_UDP:
274
		up->uh_sport = htons(conf->ident);
275
		if (iflag)
276
			up->uh_dport = htons(conf->port+seq);
277
		else
278
			up->uh_dport = htons(conf->port);
279
		up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip) -
280
		    conf->lsrrlen));
281
		up->uh_sum = 0;
282
		op = (struct packetdata *)(up + 1);
283
		break;
284
	default:
285
		op = (struct packetdata *)(ip + 1);
286
		break;
287
	}
288
	op->seq = seq;
289
	op->ttl = ttl;
290
	gettime(&tv);
291
292
	/*
293
	 * We don't want hostiles snooping the net to get any useful
294
	 * information about us. Send the timestamp in network byte order,
295
	 * and perturb the timestamp enough that they won't know our
296
	 * real clock ticker. We don't want to perturb the time by too
297
	 * much: being off by a suspiciously large amount might indicate
298
	 * OpenBSD.
299
	 *
300
	 * The timestamps in the packet are currently unused. If future
301
	 * work wants to use them they will have to subtract out the
302
	 * perturbation first.
303
	 */
304
	gettime(&tv);
305
	op->sec = htonl(tv.tv_sec + sec_perturb);
306
	op->usec = htonl((tv.tv_usec + usec_perturb) % 1000000);
307
308
	if (conf->proto == IPPROTO_ICMP && icmp_type == ICMP_ECHO) {
309
		icmpp->icmp_cksum = 0;
310
		icmpp->icmp_cksum = in_cksum((u_short *)icmpp,
311
		    datalen - sizeof(struct ip) - conf->lsrrlen);
312
		if (icmpp->icmp_cksum == 0)
313
			icmpp->icmp_cksum = 0xffff;
314
	}
315
}
316
317
void
318
build_probe6(struct tr_conf *conf, int seq, u_int8_t hops, int iflag,
319
    struct sockaddr *to)
320
{
321
	struct timeval tv;
322
	struct packetdata *op;
323
	int i;
324
325
	i = hops;
326
	if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
327
	    (char *)&i, sizeof(i)) < 0)
328
		warn("setsockopt IPV6_UNICAST_HOPS");
329
330
	if (iflag)
331
		((struct sockaddr_in6*)to)->sin6_port = htons(conf->port + seq);
332
	else
333
		((struct sockaddr_in6*)to)->sin6_port = htons(conf->port);
334
	gettime(&tv);
335
336
	if (conf->proto == IPPROTO_ICMP) {
337
		struct icmp6_hdr *icp = (struct icmp6_hdr *)outpacket;
338
339
		icp->icmp6_type = ICMP6_ECHO_REQUEST;
340
		icp->icmp6_code = 0;
341
		icp->icmp6_cksum = 0;
342
		icp->icmp6_id = conf->ident;
343
		icp->icmp6_seq = htons(seq);
344
		op = (struct packetdata *)(outpacket +
345
		    sizeof(struct icmp6_hdr));
346
	} else
347
		op = (struct packetdata *)outpacket;
348
	op->seq = seq;
349
	op->ttl = hops;
350
	op->sec = htonl(tv.tv_sec);
351
	op->usec = htonl(tv.tv_usec);
352
}
353
354
void
355
send_probe(struct tr_conf *conf, int seq, u_int8_t ttl, int iflag,
356
	struct sockaddr *to)
357
{
358
	int i;
359
360
	switch (to->sa_family) {
361
	case AF_INET:
362
		build_probe4(conf, seq, ttl, iflag);
363
		break;
364
	case AF_INET6:
365
		build_probe6(conf, seq, ttl, iflag, to);
366
		break;
367
	default:
368
		errx(1, "unsupported AF: %d", to->sa_family);
369
		break;
370
	}
371
372
	if (conf->dump)
373
		dump_packet();
374
375
	i = sendto(sndsock, outpacket, datalen, 0, to, to->sa_len);
376
	if (i < 0 || i != datalen)  {
377
		if (i < 0)
378
			warn("sendto");
379
		printf("%s: wrote %s %d chars, ret=%d\n", __progname, hostname,
380
		    datalen, i);
381
		(void) fflush(stdout);
382
	}
383
}
384
385
double
386
deltaT(struct timeval *t1p, struct timeval *t2p)
387
{
388
	double dt;
389
390
	dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
391
	    (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
392
	return (dt);
393
}
394
395
static char *ttab[] = {
396
	"Echo Reply",
397
	"ICMP 1",
398
	"ICMP 2",
399
	"Dest Unreachable",
400
	"Source Quench",
401
	"Redirect",
402
	"ICMP 6",
403
	"ICMP 7",
404
	"Echo",
405
	"Router Advert",
406
	"Router Solicit",
407
	"Time Exceeded",
408
	"Param Problem",
409
	"Timestamp",
410
	"Timestamp Reply",
411
	"Info Request",
412
	"Info Reply",
413
	"Mask Request",
414
	"Mask Reply"
415
};
416
417
/*
418
 * Convert an ICMP "type" field to a printable string.
419
 */
420
char *
421
pr_type(u_int8_t t)
422
{
423
	if (t > 18)
424
		return ("OUT-OF-RANGE");
425
	return (ttab[t]);
426
}
427
428
int
429
packet_ok(struct tr_conf *conf, int af, struct msghdr *mhdr, int cc, int seq,
430
    int iflag)
431
{
432
	switch (af) {
433
	case AF_INET:
434
		return packet_ok4(conf, mhdr, cc, seq, iflag);
435
		break;
436
	case AF_INET6:
437
		return packet_ok6(conf, mhdr, cc, seq, iflag);
438
		break;
439
	default:
440
		errx(1, "unsupported AF: %d", af);
441
		break;
442
	}
443
}
444
445
int
446
packet_ok4(struct tr_conf *conf, struct msghdr *mhdr, int cc,int seq, int iflag)
447
{
448
	struct sockaddr_in *from = (struct sockaddr_in *)mhdr->msg_name;
449
	struct icmp *icp;
450
	u_char code;
451
	char *buf = (char *)mhdr->msg_iov[0].iov_base;
452
	u_int8_t type;
453
	int hlen;
454
	struct ip *ip;
455
456
	ip = (struct ip *) buf;
457
	hlen = ip->ip_hl << 2;
458
	if (cc < hlen + ICMP_MINLEN) {
459
		if (conf->verbose)
460
			printf("packet too short (%d bytes) from %s\n", cc,
461
			    inet_ntoa(from->sin_addr));
462
		return (0);
463
	}
464
	cc -= hlen;
465
	icp = (struct icmp *)(buf + hlen);
466
	type = icp->icmp_type;
467
	code = icp->icmp_code;
468
	if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
469
	    type == ICMP_UNREACH || type == ICMP_ECHOREPLY) {
470
		struct ip *hip;
471
		struct udphdr *up;
472
		struct icmp *icmpp;
473
474
		hip = &icp->icmp_ip;
475
		hlen = hip->ip_hl << 2;
476
477
		switch (conf->proto) {
478
		case IPPROTO_ICMP:
479
			if (icmp_type == ICMP_ECHO &&
480
			    type == ICMP_ECHOREPLY &&
481
			    icp->icmp_id == htons(conf->ident) &&
482
			    icp->icmp_seq == htons(seq))
483
				return (-2); /* we got there */
484
485
			icmpp = (struct icmp *)((u_char *)hip + hlen);
486
			if (hlen + 8 <= cc && hip->ip_p == IPPROTO_ICMP &&
487
			    icmpp->icmp_id == htons(conf->ident) &&
488
			    icmpp->icmp_seq == htons(seq))
489
				return (type == ICMP_TIMXCEED? -1 : code + 1);
490
			break;
491
492
		case IPPROTO_UDP:
493
			up = (struct udphdr *)((u_char *)hip + hlen);
494
			if (hlen + 12 <= cc && hip->ip_p == conf->proto &&
495
			    up->uh_sport == htons(conf->ident) &&
496
			    ((iflag && up->uh_dport == htons(conf->port +
497
			    seq)) ||
498
			    (!iflag && up->uh_dport == htons(conf->port))))
499
				return (type == ICMP_TIMXCEED? -1 : code + 1);
500
			break;
501
		default:
502
			/* this is some odd, user specified proto,
503
			 * how do we check it?
504
			 */
505
			if (hip->ip_p == conf->proto)
506
				return (type == ICMP_TIMXCEED? -1 : code + 1);
507
		}
508
	}
509
	if (conf->verbose) {
510
		int i;
511
		in_addr_t *lp = (in_addr_t *)&icp->icmp_ip;
512
513
		printf("\n%d bytes from %s", cc, inet_ntoa(from->sin_addr));
514
		printf(" to %s", inet_ntoa(ip->ip_dst));
515
		printf(": icmp type %u (%s) code %d\n", type, pr_type(type),
516
		    icp->icmp_code);
517
		for (i = 4; i < cc ; i += sizeof(in_addr_t))
518
			printf("%2d: x%8.8lx\n", i, (unsigned long)*lp++);
519
	}
520
	return (0);
521
}
522
523
int
524
packet_ok6(struct tr_conf *conf, struct msghdr *mhdr, int cc, int seq,
525
    int iflag)
526
{
527
	struct icmp6_hdr *icp;
528
	struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
529
	u_char type, code;
530
	char *buf = (char *)mhdr->msg_iov[0].iov_base;
531
	struct cmsghdr *cm;
532
	int *hlimp;
533
	char hbuf[NI_MAXHOST];
534
	int useicmp = (conf->proto == IPPROTO_ICMP);
535
536
	if (cc < sizeof(struct icmp6_hdr)) {
537
		if (conf->verbose) {
538
			if (getnameinfo((struct sockaddr *)from, from->sin6_len,
539
			    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
540
				strlcpy(hbuf, "invalid", sizeof(hbuf));
541
			printf("data too short (%d bytes) from %s\n", cc, hbuf);
542
		}
543
		return(0);
544
	}
545
	icp = (struct icmp6_hdr *)buf;
546
	/* get optional information via advanced API */
547
	rcvpktinfo = NULL;
548
	hlimp = NULL;
549
	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
550
	    cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
551
		if (cm->cmsg_level == IPPROTO_IPV6 &&
552
		    cm->cmsg_type == IPV6_PKTINFO &&
553
		    cm->cmsg_len ==
554
		    CMSG_LEN(sizeof(struct in6_pktinfo)))
555
			rcvpktinfo = (struct in6_pktinfo *)(CMSG_DATA(cm));
556
557
		if (cm->cmsg_level == IPPROTO_IPV6 &&
558
		    cm->cmsg_type == IPV6_HOPLIMIT &&
559
		    cm->cmsg_len == CMSG_LEN(sizeof(int)))
560
			hlimp = (int *)CMSG_DATA(cm);
561
	}
562
	if (rcvpktinfo == NULL || hlimp == NULL) {
563
		warnx("failed to get received hop limit or packet info");
564
		rcvhlim = 0;	/*XXX*/
565
	} else
566
		rcvhlim = *hlimp;
567
568
	type = icp->icmp6_type;
569
	code = icp->icmp6_code;
570
	if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT)
571
	    || type == ICMP6_DST_UNREACH) {
572
		struct ip6_hdr *hip;
573
		struct udphdr *up;
574
575
		hip = (struct ip6_hdr *)(icp + 1);
576
		if ((up = get_udphdr(conf, hip, (u_char *)(buf + cc))) ==
577
		    NULL) {
578
			if (conf->verbose)
579
				warnx("failed to get upper layer header");
580
			return(0);
581
		}
582
		if (useicmp &&
583
		    ((struct icmp6_hdr *)up)->icmp6_id == conf->ident &&
584
		    ((struct icmp6_hdr *)up)->icmp6_seq == htons(seq))
585
			return (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1);
586
		else if (!useicmp &&
587
		    up->uh_sport == htons(srcport) &&
588
		    ((iflag && up->uh_dport == htons(conf->port + seq)) ||
589
		    (!iflag && up->uh_dport == htons(conf->port))))
590
			return (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1);
591
	} else if (useicmp && type == ICMP6_ECHO_REPLY) {
592
		if (icp->icmp6_id == conf->ident &&
593
		    icp->icmp6_seq == htons(seq))
594
			return (ICMP6_DST_UNREACH_NOPORT + 1);
595
	}
596
	if (conf->verbose) {
597
		char sbuf[NI_MAXHOST], dbuf[INET6_ADDRSTRLEN];
598
		u_int8_t *p;
599
		int i;
600
601
		if (getnameinfo((struct sockaddr *)from, from->sin6_len,
602
		    sbuf, sizeof(sbuf), NULL, 0, NI_NUMERICHOST) != 0)
603
			strlcpy(sbuf, "invalid", sizeof(sbuf));
604
		printf("\n%d bytes from %s to %s", cc, sbuf,
605
		    rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
606
		    dbuf, sizeof(dbuf)) : "?");
607
		printf(": icmp type %d (%s) code %d\n", type, pr_type(type),
608
		    icp->icmp6_code);
609
		p = (u_int8_t *)(icp + 1);
610
#define WIDTH	16
611
		for (i = 0; i < cc; i++) {
612
			if (i % WIDTH == 0)
613
				printf("%04x:", i);
614
			if (i % 4 == 0)
615
				printf(" ");
616
			printf("%02x", p[i]);
617
			if (i % WIDTH == WIDTH - 1)
618
				printf("\n");
619
		}
620
		if (cc % WIDTH != 0)
621
			printf("\n");
622
	}
623
	return(0);
624
}
625
626
void
627
print(struct tr_conf *conf, struct sockaddr *from, int cc, const char *to)
628
{
629
	char hbuf[NI_MAXHOST];
630
	if (getnameinfo(from, from->sa_len,
631
	    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
632
		strlcpy(hbuf, "invalid", sizeof(hbuf));
633
	if (conf->nflag)
634
		printf(" %s", hbuf);
635
	else
636
		printf(" %s (%s)", inetname(from), hbuf);
637
638
	if (conf->Aflag)
639
		print_asn((struct sockaddr_storage *)from);
640
641
	if (conf->verbose)
642
		printf(" %d bytes to %s", cc, to);
643
}
644
645
/*
646
 * Increment pointer until find the UDP or ICMP header.
647
 */
648
struct udphdr *
649
get_udphdr(struct tr_conf *conf, struct ip6_hdr *ip6, u_char *lim)
650
{
651
	u_char *cp = (u_char *)ip6, nh;
652
	int hlen;
653
	int useicmp = (conf->proto == IPPROTO_ICMP);
654
655
	if (cp + sizeof(*ip6) >= lim)
656
		return(NULL);
657
658
	nh = ip6->ip6_nxt;
659
	cp += sizeof(struct ip6_hdr);
660
661
	while (lim - cp >= 8) {
662
		switch (nh) {
663
		case IPPROTO_ESP:
664
		case IPPROTO_TCP:
665
			return(NULL);
666
		case IPPROTO_ICMPV6:
667
			return(useicmp ? (struct udphdr *)cp : NULL);
668
		case IPPROTO_UDP:
669
			return(useicmp ? NULL : (struct udphdr *)cp);
670
		case IPPROTO_FRAGMENT:
671
			hlen = sizeof(struct ip6_frag);
672
			nh = ((struct ip6_frag *)cp)->ip6f_nxt;
673
			break;
674
		case IPPROTO_AH:
675
			hlen = (((struct ip6_ext *)cp)->ip6e_len + 2) << 2;
676
			nh = ((struct ip6_ext *)cp)->ip6e_nxt;
677
			break;
678
		default:
679
			hlen = (((struct ip6_ext *)cp)->ip6e_len + 1) << 3;
680
			nh = ((struct ip6_ext *)cp)->ip6e_nxt;
681
			break;
682
		}
683
684
		cp += hlen;
685
	}
686
687
	return(NULL);
688
}
689
690
void
691
icmp_code(int af, int code, int *got_there, int *unreachable)
692
{
693
	switch (af) {
694
	case AF_INET:
695
		icmp4_code(code, got_there, unreachable);
696
		break;
697
	case AF_INET6:
698
		icmp6_code(code, got_there, unreachable);
699
		break;
700
	default:
701
		errx(1, "unsupported AF: %d", af);
702
		break;
703
	}
704
}
705
706
void
707
icmp4_code(int code, int *got_there, int *unreachable)
708
{
709
	struct ip *ip = (struct ip *)packet;
710
711
	switch (code) {
712
	case ICMP_UNREACH_PORT:
713
		if (ip->ip_ttl <= 1)
714
			printf(" !");
715
		++(*got_there);
716
		break;
717
	case ICMP_UNREACH_NET:
718
		++(*unreachable);
719
		printf(" !N");
720
		break;
721
	case ICMP_UNREACH_HOST:
722
		++(*unreachable);
723
		printf(" !H");
724
		break;
725
	case ICMP_UNREACH_PROTOCOL:
726
		++(*got_there);
727
		printf(" !P");
728
		break;
729
	case ICMP_UNREACH_NEEDFRAG:
730
		++(*unreachable);
731
		printf(" !F");
732
		break;
733
	case ICMP_UNREACH_SRCFAIL:
734
		++(*unreachable);
735
		printf(" !S");
736
		break;
737
	case ICMP_UNREACH_FILTER_PROHIB:
738
		++(*unreachable);
739
		printf(" !X");
740
		break;
741
	case ICMP_UNREACH_NET_PROHIB: /*misuse*/
742
		++(*unreachable);
743
		printf(" !A");
744
		break;
745
	case ICMP_UNREACH_HOST_PROHIB:
746
		++(*unreachable);
747
		printf(" !C");
748
		break;
749
	case ICMP_UNREACH_NET_UNKNOWN:
750
	case ICMP_UNREACH_HOST_UNKNOWN:
751
		++(*unreachable);
752
		printf(" !U");
753
		break;
754
	case ICMP_UNREACH_ISOLATED:
755
		++(*unreachable);
756
		printf(" !I");
757
		break;
758
	case ICMP_UNREACH_TOSNET:
759
	case ICMP_UNREACH_TOSHOST:
760
		++(*unreachable);
761
		printf(" !T");
762
		break;
763
	default:
764
		++(*unreachable);
765
		printf(" !<%d>", code);
766
		break;
767
	}
768
}
769
770
void
771
icmp6_code(int code, int *got_there, int *unreachable)
772
{
773
	switch (code) {
774
	case ICMP6_DST_UNREACH_NOROUTE:
775
		++(*unreachable);
776
		printf(" !N");
777
		break;
778
	case ICMP6_DST_UNREACH_ADMIN:
779
		++(*unreachable);
780
		printf(" !P");
781
		break;
782
	case ICMP6_DST_UNREACH_BEYONDSCOPE:
783
		++(*unreachable);
784
		printf(" !S");
785
		break;
786
	case ICMP6_DST_UNREACH_ADDR:
787
		++(*unreachable);
788
		printf(" !A");
789
		break;
790
	case ICMP6_DST_UNREACH_NOPORT:
791
		if (rcvhlim >= 0 && rcvhlim <= 1)
792
			printf(" !");
793
		++(*got_there);
794
		break;
795
	default:
796
		++(*unreachable);
797
		printf(" !<%d>", code);
798
		break;
799
	}
800
}
801
802
/*
803
 * Checksum routine for Internet Protocol family headers (C Version)
804
 */
805
u_short
806
in_cksum(u_short *addr, int len)
807
{
808
	u_short *w = addr, answer;
809
	int nleft = len, sum = 0;
810
811
	/*
812
	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
813
	 *  we add sequential 16 bit words to it, and at the end, fold
814
	 *  back all the carry bits from the top 16 bits into the lower
815
	 *  16 bits.
816
	 */
817
	while (nleft > 1)  {
818
		sum += *w++;
819
		nleft -= 2;
820
	}
821
822
	/* mop up an odd byte, if necessary */
823
	if (nleft == 1)
824
		sum += *(u_char *)w;
825
826
	/*
827
	 * add back carry outs from top 16 bits to low 16 bits
828
	 */
829
	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
830
	sum += (sum >> 16);			/* add carry */
831
	answer = ~sum;				/* truncate to 16 bits */
832
	return (answer);
833
}
834
835
/*
836
 * Construct an Internet address representation.
837
 */
838
const char *
839
inetname(struct sockaddr *sa)
840
{
841
	static char line[NI_MAXHOST], domain[HOST_NAME_MAX + 1];
842
	static int first = 1;
843
	char *cp;
844
845
	if (first) {
846
		first = 0;
847
		if (gethostname(domain, sizeof(domain)) == 0 &&
848
		    (cp = strchr(domain, '.')) != NULL)
849
			memmove(domain, cp + 1, strlen(cp + 1) + 1);
850
		else
851
			domain[0] = 0;
852
	}
853
	if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0,
854
	    NI_NAMEREQD) == 0) {
855
		if ((cp = strchr(line, '.')) != NULL && strcmp(cp + 1,
856
		    domain) == 0)
857
			*cp = '\0';
858
		return (line);
859
	}
860
861
	if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0,
862
	    NI_NUMERICHOST) != 0)
863
		return ("invalid");
864
	return (line);
865
}
866
867
void
868
print_asn(struct sockaddr_storage *ss)
869
{
870
	struct rrsetinfo *answers = NULL;
871
	int counter;
872
	const u_char *uaddr;
873
	char qbuf[MAXDNAME];
874
875
	switch (ss->ss_family) {
876
	case AF_INET:
877
		uaddr = (const u_char *)&((struct sockaddr_in *) ss)->sin_addr;
878
		if (snprintf(qbuf, sizeof qbuf, "%u.%u.%u.%u."
879
		    "origin.asn.cymru.com",
880
		    (uaddr[3] & 0xff), (uaddr[2] & 0xff),
881
		    (uaddr[1] & 0xff), (uaddr[0] & 0xff)) >= sizeof (qbuf))
882
			return;
883
		break;
884
	case AF_INET6:
885
		uaddr = (const u_char *)&((struct sockaddr_in6 *) ss)->sin6_addr;
886
		if (snprintf(qbuf, sizeof qbuf,
887
		    "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
888
		    "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
889
		    "origin6.asn.cymru.com",
890
		    (uaddr[15] & 0x0f), ((uaddr[15] >>4)& 0x0f),
891
		    (uaddr[14] & 0x0f), ((uaddr[14] >>4)& 0x0f),
892
		    (uaddr[13] & 0x0f), ((uaddr[13] >>4)& 0x0f),
893
		    (uaddr[12] & 0x0f), ((uaddr[12] >>4)& 0x0f),
894
		    (uaddr[11] & 0x0f), ((uaddr[11] >>4)& 0x0f),
895
		    (uaddr[10] & 0x0f), ((uaddr[10] >>4)& 0x0f),
896
		    (uaddr[9] & 0x0f), ((uaddr[9] >>4)& 0x0f),
897
		    (uaddr[8] & 0x0f), ((uaddr[8] >>4)& 0x0f),
898
		    (uaddr[7] & 0x0f), ((uaddr[7] >>4)& 0x0f),
899
		    (uaddr[6] & 0x0f), ((uaddr[6] >>4)& 0x0f),
900
		    (uaddr[5] & 0x0f), ((uaddr[5] >>4)& 0x0f),
901
		    (uaddr[4] & 0x0f), ((uaddr[4] >>4)& 0x0f),
902
		    (uaddr[3] & 0x0f), ((uaddr[3] >>4)& 0x0f),
903
		    (uaddr[2] & 0x0f), ((uaddr[2] >>4)& 0x0f),
904
		    (uaddr[1] & 0x0f), ((uaddr[1] >>4)& 0x0f),
905
		    (uaddr[0] & 0x0f), ((uaddr[0] >>4)& 0x0f)) >= sizeof (qbuf))
906
			return;
907
		break;
908
	default:
909
		return;
910
	}
911
912
	if (getrrsetbyname(qbuf, C_IN, T_TXT, 0, &answers) != 0)
913
		return;
914
	for (counter = 0; counter < answers->rri_nrdatas; counter++) {
915
		char *p, *as = answers->rri_rdatas[counter].rdi_data;
916
		as++; /* skip first byte, it contains length */
917
		if ((p = strchr(as,'|'))) {
918
			printf(counter ? ", " : " [");
919
			p[-1] = 0;
920
			printf("AS%s", as);
921
		}
922
	}
923
	if (counter)
924
		printf("]");
925
926
	freerrset(answers);
927
}
928
929
int
930
map_tos(char *s, int *val)
931
{
932
	/* DiffServ Codepoints and other TOS mappings */
933
	const struct toskeywords {
934
		const char	*keyword;
935
		int		 val;
936
	} *t, toskeywords[] = {
937
		{ "af11",		IPTOS_DSCP_AF11 },
938
		{ "af12",		IPTOS_DSCP_AF12 },
939
		{ "af13",		IPTOS_DSCP_AF13 },
940
		{ "af21",		IPTOS_DSCP_AF21 },
941
		{ "af22",		IPTOS_DSCP_AF22 },
942
		{ "af23",		IPTOS_DSCP_AF23 },
943
		{ "af31",		IPTOS_DSCP_AF31 },
944
		{ "af32",		IPTOS_DSCP_AF32 },
945
		{ "af33",		IPTOS_DSCP_AF33 },
946
		{ "af41",		IPTOS_DSCP_AF41 },
947
		{ "af42",		IPTOS_DSCP_AF42 },
948
		{ "af43",		IPTOS_DSCP_AF43 },
949
		{ "critical",		IPTOS_PREC_CRITIC_ECP },
950
		{ "cs0",		IPTOS_DSCP_CS0 },
951
		{ "cs1",		IPTOS_DSCP_CS1 },
952
		{ "cs2",		IPTOS_DSCP_CS2 },
953
		{ "cs3",		IPTOS_DSCP_CS3 },
954
		{ "cs4",		IPTOS_DSCP_CS4 },
955
		{ "cs5",		IPTOS_DSCP_CS5 },
956
		{ "cs6",		IPTOS_DSCP_CS6 },
957
		{ "cs7",		IPTOS_DSCP_CS7 },
958
		{ "ef",			IPTOS_DSCP_EF },
959
		{ "inetcontrol",	IPTOS_PREC_INTERNETCONTROL },
960
		{ "lowdelay",		IPTOS_LOWDELAY },
961
		{ "netcontrol",		IPTOS_PREC_NETCONTROL },
962
		{ "reliability",	IPTOS_RELIABILITY },
963
		{ "throughput",		IPTOS_THROUGHPUT },
964
		{ NULL,			-1 },
965
	};
966
967
	for (t = toskeywords; t->keyword != NULL; t++) {
968
		if (strcmp(s, t->keyword) == 0) {
969
			*val = t->val;
970
			return (1);
971
		}
972
	}
973
974
	return (0);
975
}
976
977
void
978
gettime(struct timeval *tv)
979
{
980
	struct timespec ts;
981
982
	if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
983
		err(1, "clock_gettime(CLOCK_MONOTONIC)");
984
985
	TIMESPEC_TO_TIMEVAL(tv, &ts);
986
}