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