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