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