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