On 2021-09-01 04:05 -06, "Theo de Raadt" <[email protected]> wrote:
> Stuart Henderson <[email protected]> wrote:
>
>> On 2021/09/01 11:25, Florian Obser wrote:
>> > So traceroute sends one probe, waits upto 5^W3 seconds for an answer to
>> > arrive, sends the next probe and so on.
>> >
>> > This makes it a bit faster (10x on a path with two intermediate systems
>> > not answering) by sending probes, waiting for the answer and doing
>> > reverse DNS lookups async.
>>
>> Basics are working here with icmp and udp. -A doesn't work reliably,
>> try it with an empty cache - I think it only prints if the route lookup
>> had a reply before the rdns lookup.
>
> interesting, this will need to be found and fixed.
I can't reproduce it here.
>
>> I don't know libevent, is it possible to reset the timer and skip the
>> 30ms delay if a response is received? Currently it's a little slower
>> for the case where all hops respond.
yes, one way is to shedule a timeout right now, done in the diff below.
>
> that is an interesting idea also, it can be even faster. claudio/florian
> and i have talked a lot about trying to send back-to-back packets to a
> single ttl target, because it may trigger control plane protection filters
> in those intermediate hops.
>
> but increasing the pace to other targets, is fine.
>
>> Hosts that don't respond result in a lot of *'s printed quickly, maybe
>> scrolling the useful output off the terminal. The overall output is the
>> same as the sequential version if you actually leave it to finish but
>> most users would have hit ^C by then. I don't know what could be done
>> to improve it (suppressing multiple * * * lines might help?) but user
>> experience with that isn't great as-is. Try mp3.com for an example.
>
> there are two proposals for this, which would diverge the output:
>
> 15 * * * [repeating to ttl 64]
>
> or
>
> 15 * * *
> [repeating to ttl 64]
>
we discussed a 3rd option in the hackroom:
15 192.168.2.23 42.0 ms 42.0 ms 42.0 ms
64 * * *
> how often do people run scripts against traceroute output, which will care
> about this change in format.
>
> I also considered a third option -- to meter the * * * printout lines
> rate to 3/second, but this kind of conflicts with the goal for speeding
> things up.
>
>
diff --git Makefile Makefile
index c9797ab7244..6b745132ff1 100644
--- Makefile
+++ Makefile
@@ -8,6 +8,8 @@ CFLAGS+= -Wall -I${.CURDIR}
CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes
CFLAGS+= -Wmissing-declarations
CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
+LDADD= -levent
+DPADD= ${LIBEVENT}
MAN= traceroute.8
diff --git traceroute.8 traceroute.8
index cc211c14083..4e8d0d5f52a 100644
--- traceroute.8
+++ traceroute.8
@@ -42,7 +42,7 @@
.Nd print the route packets take to network host
.Sh SYNOPSIS
.Nm traceroute\ \&
-.Op Fl AcDdIlnSvx
+.Op Fl ADdIlnSvx
.Op Fl f Ar first_ttl
.Op Fl g Ar gateway_addr
.Op Fl m Ar max_ttl
@@ -56,7 +56,7 @@
.Ar host
.Op Ar datalen
.Nm traceroute6
-.Op Fl AcDdIlnSv
+.Op Fl ADdIlnSv
.Op Fl f Ar first_hop
.Op Fl m Ar max_hop
.Op Fl p Ar port
@@ -91,11 +91,6 @@ The options are as follows:
Look up the AS number for each hop address.
Uses the DNS service described at
.Lk https://www.team-cymru.com/IP-ASN-mapping.html#dns
-.It Fl c
-Do not increment the destination port number in successive UDP packets.
-Rather, all UDP packets will have the same destination port, as set via the
-.Fl p
-flag (or 33434 if none is specified).
.It Fl D
Dump the packet data to standard error before transmitting it.
.It Fl d
diff --git traceroute.c traceroute.c
index 21ee76dba1c..d1a40d292ac 100644
--- traceroute.c
+++ traceroute.c
@@ -249,6 +249,7 @@
#include <err.h>
#include <errno.h>
+#include <event.h>
#include <limits.h>
#include <netdb.h>
#include <pwd.h>
@@ -271,33 +272,44 @@ int sndsock; /* send (udp) socket file
descriptor */
int rcvhlim;
struct in6_pktinfo *rcvpktinfo;
- int datalen; /* How much data */
+int datalen; /* How much data */
char *hostname;
u_int16_t srcport;
-void usage(int);
+void usage(void);
#define TRACEROUTE_USER "_traceroute"
+void sock_read(int, short, void *);
+void send_timer(int, short, void *);
+
+struct tr_conf *conf; /* configuration defaults */
+struct tr_result *tr_results;
+struct sockaddr_in from4, to4;
+struct sockaddr_in6 from6, to6;
+struct sockaddr *from, *to;
+struct msghdr rcvmhdr;
+struct event timer_ev;
+int v6flag;
+int *waiting_ttls;
+int last_tos = 0;
+
int
main(int argc, char *argv[])
{
int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL };
char hbuf[NI_MAXHOST];
- struct tr_conf *conf; /* configuration defaults */
- struct sockaddr_in from4, to4;
- struct sockaddr_in6 from6, to6;
- struct sockaddr *from, *to;
struct addrinfo hints, *res;
struct hostent *hp;
struct ip *ip = NULL;
struct iovec rcviov[2];
- struct msghdr rcvmhdr;
static u_char *rcvcmsgbuf;
struct passwd *pw;
+ struct event sock_ev;
+ struct timeval tv = {0, 0};
long l;
socklen_t len;
@@ -305,25 +317,18 @@ main(int argc, char *argv[])
int ch;
int on = 1;
- int seq = 0;
int error;
- int curwaittime;
int headerlen; /* How long packet's header is */
int i;
- int last_tos = 0;
int packetlen;
- int probe;
int rcvcmsglen;
int rcvsock4, rcvsock6;
int sndsock4, sndsock6;
u_int32_t tmprnd;
int v4sock_errno, v6sock_errno;
- int v6flag = 0;
- int xflag = 0; /* show ICMP extension header */
char *dest;
const char *errstr;
- u_int8_t ttl;
uid_t ouid, uid;
gid_t gid;
@@ -337,11 +342,11 @@ main(int argc, char *argv[])
if ((conf = calloc(1, sizeof(*conf))) == NULL)
err(1,NULL);
- conf->incflag = 1;
conf->first_ttl = 1;
conf->proto = IPPROTO_UDP;
conf->max_ttl = IPDEFTTL;
conf->nprobes = 3;
+ conf->expected_responses = 2; /* icmp + DNS */
/* start udp dest port # for probe packets */
conf->port = 32768+666;
@@ -421,14 +426,12 @@ main(int argc, char *argv[])
err(1, "sysctl");
conf->max_ttl = i;
- while ((ch = getopt(argc, argv, v6flag ? "AcDdf:Ilm:np:q:Ss:t:w:vV:" :
- "AcDdf:g:Ilm:nP:p:q:Ss:t:V:vw:x")) != -1)
+ while ((ch = getopt(argc, argv, v6flag ? "ADdf:Ilm:np:q:Ss:t:w:vV:" :
+ "ADdf:g:Ilm:nP:p:q:Ss:t:V:vw:x")) != -1)
switch (ch) {
case 'A':
conf->Aflag = 1;
- break;
- case 'c':
- conf->incflag = 0;
+ conf->expected_responses++;
break;
case 'd':
conf->dflag = 1;
@@ -476,6 +479,7 @@ main(int argc, char *argv[])
break;
case 'n':
conf->nflag = 1;
+ conf->expected_responses--;
break;
case 'p':
conf->port = strtonum(optarg, 1, 65535, &errstr);
@@ -500,7 +504,7 @@ main(int argc, char *argv[])
}
break;
case 'q':
- conf->nprobes = strtonum(optarg, 1, INT_MAX, &errstr);
+ conf->nprobes = strtonum(optarg, 1, 1024, &errstr);
if (errstr)
errx(1, "nprobes must be >0.");
break;
@@ -561,10 +565,10 @@ main(int argc, char *argv[])
conf->waittime *= 1000;
break;
case 'x':
- xflag = 1;
+ conf->xflag = 1;
break;
default:
- usage(v6flag);
+ usage();
}
if (ouid == 0 && (setgroups(1, &gid) ||
@@ -576,7 +580,16 @@ main(int argc, char *argv[])
argv += optind;
if (argc < 1 || argc > 2)
- usage(v6flag);
+ usage();
+
+ tr_results = calloc(sizeof(struct tr_result), conf->max_ttl *
+ conf->nprobes);
+ if (tr_results == NULL)
+ err(1, NULL);
+
+ waiting_ttls = calloc(sizeof(int), conf->max_ttl);
+ for (i = 0; i < conf->max_ttl; i++)
+ waiting_ttls[i] = conf->nprobes * conf->expected_responses;
setvbuf(stdout, NULL, _IOLBF, 0);
@@ -862,112 +875,26 @@ main(int argc, char *argv[])
if (conf->first_ttl > 1)
printf("Skipping %u intermediate hops\n", conf->first_ttl - 1);
- for (ttl = conf->first_ttl; ttl && ttl <= conf->max_ttl; ++ttl) {
- int got_there = 0, unreachable = 0, timeout = 0, loss;
- in_addr_t lastaddr = 0;
- struct in6_addr lastaddr6;
-
- printf("%2u ", ttl);
- memset(&lastaddr6, 0, sizeof(lastaddr6));
- for (probe = 0, loss = 0; probe < conf->nprobes; ++probe) {
- int cc;
- struct timeval t1, t2;
-
- gettime(&t1);
- send_probe(conf, ++seq, ttl, conf->incflag, to);
- curwaittime = conf->waittime;
- while ((cc = wait_for_reply(rcvsock, &rcvmhdr,
- curwaittime))) {
- gettime(&t2);
- i = packet_ok(conf, to->sa_family, &rcvmhdr,
- cc, seq, conf->incflag);
- /* Skip wrong packet */
- if (i == 0) {
- curwaittime = conf->waittime -
- ((t2.tv_sec - t1.tv_sec) * 1000 +
- (t2.tv_usec - t1.tv_usec) / 1000);
- if (curwaittime < 0)
- curwaittime = 0;
- continue;
- }
- if (to->sa_family == AF_INET) {
- ip = (struct ip *)packet;
- if (from4.sin_addr.s_addr != lastaddr) {
- print(conf, from,
- cc - (ip->ip_hl << 2),
- inet_ntop(AF_INET,
- &ip->ip_dst, hbuf,
- sizeof(hbuf)));
- lastaddr =
- from4.sin_addr.s_addr;
- }
- } else if (to->sa_family == AF_INET6) {
- if (!IN6_ARE_ADDR_EQUAL(
- &from6.sin6_addr, &lastaddr6)) {
- print(conf, from, cc,
- rcvpktinfo ?
- inet_ntop( AF_INET6,
- &rcvpktinfo->ipi6_addr,
- hbuf, sizeof(hbuf)) : "?");
- lastaddr6 = from6.sin6_addr;
- }
- } else
- errx(1, "unsupported AF: %d",
- to->sa_family);
-
- printf(" %g ms", deltaT(&t1, &t2));
- if (conf->ttl_flag)
- printf(" (%u)", v6flag ? rcvhlim :
- ip->ip_ttl);
- if (to->sa_family == AF_INET) {
- if (i == -2) {
- if (ip->ip_ttl <= 1)
- printf(" !");
- ++got_there;
- break;
- }
-
- if (conf->tflag)
- check_tos(ip, &last_tos);
- }
+ event_init();
- /* time exceeded in transit */
- if (i == -1)
- break;
- icmp_code(to->sa_family, i - 1, &got_there,
- &unreachable);
- break;
- }
- if (cc == 0) {
- printf(" *");
- timeout++;
- loss++;
- } else if (cc && probe == conf->nprobes - 1 &&
- (xflag || conf->verbose))
- print_exthdr(packet, cc);
- (void) fflush(stdout);
- }
- if (conf->sump)
- printf(" (%d%% loss)", (loss * 100) / conf->nprobes);
- putchar('\n');
- if (got_there ||
- (unreachable && (unreachable + timeout) >= conf->nprobes))
- break;
- }
- exit(0);
+ event_set(&sock_ev, rcvsock, EV_READ | EV_PERSIST, sock_read, NULL);
+ event_add(&sock_ev, NULL);
+ evtimer_set(&timer_ev, send_timer, &timer_ev);
+ evtimer_add(&timer_ev, &tv);
+ event_dispatch();
}
void
-usage(int v6flag)
+usage(void)
{
if (v6flag) {
fprintf(stderr, "usage: %s "
- "[-AcDdIlnSv] [-f first_hop] [-m max_hop] [-p port]\n"
+ "[-ADdIlnSv] [-f first_hop] [-m max_hop] [-p port]\n"
"\t[-q nqueries] [-s sourceaddr] [-t toskeyword] [-V
rtable] "
"[-w waittime]\n\thost [datalen]\n", __progname);
} else {
fprintf(stderr,
- "usage: %s [-AcDdIlnSvx] [-f first_ttl] [-g gateway_addr] "
+ "usage: %s [-ADdIlnSvx] [-f first_ttl] [-g gateway_addr] "
"[-m max_ttl]\n"
"\t[-P proto] [-p port] [-q nqueries] [-s sourceaddr]\n"
"\t[-t toskeyword] "
@@ -976,3 +903,104 @@ usage(int v6flag)
}
exit(1);
}
+
+void
+sock_read(int fd, short events, void *arg)
+{
+ struct ip *ip;
+ struct timeval t2, tv = {0, 0};
+ int pkg_ok, cc, recv_seq, recv_seq_row;
+ char hbuf[NI_MAXHOST];
+
+ cc = recvmsg(rcvsock, &rcvmhdr, 0);
+
+ if (cc == 0)
+ return;
+
+ evtimer_add(&timer_ev, &tv);
+
+ gettime(&t2);
+
+ pkg_ok = packet_ok(conf, to->sa_family, &rcvmhdr, cc, &recv_seq);
+
+ /* Skip wrong packet */
+ if (pkg_ok == 0)
+ goto out;
+
+ /* skip corrupt sequence number */
+ if (recv_seq < 0 || recv_seq >= conf->max_ttl * conf->nprobes)
+ goto out;
+
+ recv_seq_row = recv_seq / conf->nprobes;
+
+ /* skipping dup */
+ if (tr_results[recv_seq].dup++)
+ goto out;
+
+ switch (to->sa_family) {
+ case AF_INET:
+ ip = (struct ip *)packet;
+
+ print(conf, from, cc - (ip->ip_hl << 2), inet_ntop(AF_INET,
+ &ip->ip_dst, hbuf, sizeof(hbuf)), &tr_results[recv_seq]);
+ break;
+ case AF_INET6:
+ print(conf, from, cc, rcvpktinfo ? inet_ntop(AF_INET6,
+ &rcvpktinfo->ipi6_addr, hbuf, sizeof(hbuf)) : "?",
+ &tr_results[recv_seq]);
+ break;
+ default:
+ errx(1, "unsupported AF: %d", to->sa_family);
+ }
+
+ tr_results[recv_seq].t2 = t2;
+ tr_results[recv_seq].resp_ttl = v6flag ? rcvhlim : ip->ip_ttl;
+
+ waiting_ttls[recv_seq_row]--;
+
+ if (pkg_ok == -2) {
+ if ((v6flag && rcvhlim <= 1) ||
+ (!v6flag && ip->ip_ttl <=1))
+ snprintf(tr_results[recv_seq].icmp_code,
+ sizeof(tr_results[recv_seq].icmp_code), "%s", " !");
+ tr_results[recv_seq].got_there++;
+ } else {
+ if (to->sa_family == AF_INET && conf->tflag)
+ check_tos(ip, &last_tos, &tr_results[recv_seq]);
+ if (pkg_ok != -1) {
+ icmp_code(to->sa_family, pkg_ok - 1,
+ &tr_results[recv_seq].got_there,
+ &tr_results[recv_seq].unreachable,
+ &tr_results[recv_seq]);
+ }
+ }
+
+ if (cc && ((recv_seq + 1) % conf->nprobes) == 0 &&
+ (conf->xflag || conf->verbose))
+ print_exthdr(packet, cc, &tr_results[recv_seq]);
+ out:
+ catchup_result_rows(tr_results, conf);
+}
+
+void
+send_timer(int fd, short events, void *arg)
+{
+ static int seq;
+ struct timeval tv = {0, 30000}, t1;
+ struct event *ev = arg;
+ int ttl;
+
+ evtimer_add(ev, &tv);
+
+ ttl = conf->first_ttl + seq / conf->nprobes;
+ if (ttl <= conf->max_ttl) {
+ gettime(&t1);
+ tr_results[seq].seq = seq;
+ tr_results[seq].row = seq / conf->nprobes;
+ tr_results[seq].ttl = ttl;
+ tr_results[seq].t1 = t1;
+ send_probe(conf, seq, ttl, to);
+ seq++;
+ } else
+ catchup_result_rows(tr_results, conf);
+}
diff --git traceroute.h traceroute.h
index 1704068d29c..6e186cb29a2 100644
--- traceroute.h
+++ traceroute.h
@@ -67,6 +67,8 @@
#include <netinet/ip_var.h>
#include <netmpls/mpls.h>
+#define ICMP_CODE 0;
+
#define DUMMY_PORT 10010
#define MAX_LSRR ((MAX_IPOPTLEN - 4) / 4)
@@ -86,7 +88,6 @@ struct packetdata {
} __packed;
struct tr_conf {
- int incflag; /* Do not inc the dest. port num */
int first_ttl; /* Set the first TTL or hop limit */
u_char proto; /* IP payload protocol to use */
u_int8_t max_ttl; /* Set the maximum TTL / hop limit */
@@ -106,46 +107,55 @@ struct tr_conf {
int sump;
int tos;
int tflag; /* tos value was set */
+ int xflag; /* show ICMP extension header */
int verbose;
u_int rtableid; /* Set the routing table */
u_short ident;
+ int expected_responses;
+};
+
+struct tr_result {
+ int seq;
+ int row;
+ int dup;
+ int timeout;
+ uint8_t ttl;
+ uint8_t resp_ttl;
+ char hbuf[NI_MAXHOST];
+ char inetname[NI_MAXHOST];
+ char *asn;
+ char *exthdr;
+ char to[NI_MAXHOST];
+ int cc;
+ struct timeval t1;
+ struct timeval t2;
+ char icmp_code[sizeof("!<255>")];
+ char tos[sizeof(" (TOS=255!)")];
+ int got_there;
+ int unreachable;
+ int inetname_done;
+ int asn_done;
};
+extern int *waiting_ttls;
extern int32_t sec_perturb;
extern int32_t usec_perturb;
extern u_char packet[512];
extern u_char *outpacket; /* last inbound (icmp) packet */
-int wait_for_reply(int, struct msghdr *, int);
-void dump_packet(void);
-void build_probe4(struct tr_conf *, int, u_int8_t, int);
-void build_probe6(struct tr_conf *, int, u_int8_t, int,
- struct sockaddr *);
-void send_probe(struct tr_conf *, int, u_int8_t, int,
- struct sockaddr *);
-struct udphdr *get_udphdr(struct tr_conf *, struct ip6_hdr *, u_char *);
-int packet_ok(struct tr_conf *, int, struct msghdr *, int, int,
- int);
-int packet_ok4(struct tr_conf *, struct msghdr *, int, int, int);
-int packet_ok6(struct tr_conf *, struct msghdr *, int, int, int);
-void icmp_code(int, int, int *, int *);
-void icmp4_code(int, int *, int *);
-void icmp6_code(int, int *, int *);
-void dump_packet(void);
-void print_exthdr(u_char *, int);
-void check_tos(struct ip*, int *);
-void print(struct tr_conf *, struct sockaddr *, int, const char *);
-const char *inetname(struct sockaddr*);
-void print_asn(struct sockaddr_storage *);
-u_short in_cksum(u_short *, int);
-char *pr_type(u_int8_t);
+void send_probe(struct tr_conf *, int, u_int8_t, struct sockaddr *);
+int packet_ok(struct tr_conf *, int, struct msghdr *, int, int *);
+void icmp_code(int, int, int *, int *, struct tr_result *);
+void check_tos(struct ip*, int *, struct tr_result *);
int map_tos(char *, int *);
-double deltaT(struct timeval *, struct timeval *);
-
+void print(struct tr_conf *, struct sockaddr *, int, const char *,
+ struct tr_result *);
+void print_exthdr(u_char *, int, struct tr_result *);
void gettime(struct timeval *);
-extern int rcvsock; /* receive (icmp) socket file descriptor */
+void catchup_result_rows(struct tr_result *, struct tr_conf *);
+
extern int sndsock; /* send (udp) socket file descriptor */
extern int rcvhlim;
@@ -157,8 +167,6 @@ extern char *hostname;
extern u_int16_t srcport;
-#define ICMP_CODE 0;
-
extern int verbose;
extern int dump;
diff --git worker.c worker.c
index 7a6aef082c2..88dd5376b57 100644
--- worker.c
+++ worker.c
@@ -77,30 +77,50 @@
#include <arpa/inet.h>
#include <arpa/nameser.h>
+#include <asr.h>
#include <err.h>
+#include <event.h>
#include <limits.h>
#include <netdb.h>
-#include <poll.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "traceroute.h"
-static u_int8_t icmp_type = ICMP_ECHO; /* default ICMP code/type */
+void build_probe4(struct tr_conf *, int, u_int8_t);
+void build_probe6(struct tr_conf *, int, u_int8_t,
+ struct sockaddr *);
+int packet_ok4(struct tr_conf *, struct msghdr *, int, int *);
+int packet_ok6(struct tr_conf *, struct msghdr *, int, int *);
+void icmp4_code(int, int *, int *, struct tr_result *);
+void icmp6_code(int, int *, int *, struct tr_result *);
+struct udphdr *get_udphdr(struct tr_conf *, struct ip6_hdr *, u_char *);
+void dump_packet(void);
+void print_asn(struct sockaddr_storage *, struct tr_result *);
+u_short in_cksum(u_short *, int);
+char *pr_type(u_int8_t);
+double deltaT(struct timeval *, struct timeval *);
+void check_timeout(struct tr_result *, struct tr_conf *);
+void print_result_row(struct tr_result *, struct tr_conf *);
+void getnameinfo_async_done(struct asr_result *, void *);
+void getrrsetbyname_async_done(struct asr_result *, void *);
void
-print_exthdr(u_char *buf, int cc)
+print_exthdr(u_char *buf, int cc, struct tr_result *tr_res)
{
struct icmp_ext_hdr exthdr;
struct icmp_ext_obj_hdr objhdr;
struct ip *ip;
struct icmp *icp;
+ size_t exthdr_size, len;
int hlen, first;
u_int32_t label;
u_int16_t off, olen;
u_int8_t type;
+ char *exthdr_str;
ip = (struct ip *)buf;
hlen = ip->ip_hl << 2;
@@ -148,6 +168,13 @@ print_exthdr(u_char *buf, int cc)
buf += sizeof(exthdr);
cc -= sizeof(exthdr);
+ /* rough estimate of needed space */
+ exthdr_size = sizeof("[MPLS Label 1048576 (Exp 3)]") *
+ (cc / sizeof(u_int32_t));
+ if ((tr_res->exthdr = calloc(1, exthdr_size)) == NULL)
+ err(1, NULL);
+ exthdr_str = tr_res->exthdr;
+
while (cc > sizeof(objhdr)) {
memcpy(&objhdr, buf, sizeof(objhdr));
olen = ntohs(objhdr.ieo_length);
@@ -175,21 +202,62 @@ print_exthdr(u_char *buf, int cc)
olen -= sizeof(u_int32_t);
if (first == 0) {
- printf(" [MPLS Label ");
+ len = snprintf(exthdr_str,
+ exthdr_size, "%s",
+ " [MPLS Label ");
+ if (len != -1 && len <
+ exthdr_size) {
+ exthdr_str += len;
+ exthdr_size -= len;
+ }
first++;
- } else
- printf(", ");
- printf("%d", MPLS_LABEL(label));
- if (MPLS_EXP(label))
- printf(" (Exp %x)",
+ } else {
+ len = snprintf(exthdr_str,
+ exthdr_size, "%s",
+ ", ");
+ if (len != -1 && len <
+ exthdr_size) {
+ exthdr_str += len;
+ exthdr_size -= len;
+ }
+ }
+ len = snprintf(exthdr_str,
+ exthdr_size,
+ "%d", MPLS_LABEL(label));
+ if (len != -1 && len < exthdr_size) {
+ exthdr_str += len;
+ exthdr_size -= len;
+ }
+ if (MPLS_EXP(label)) {
+ len = snprintf(exthdr_str,
+ exthdr_size, " (Exp %x)",
MPLS_EXP(label));
+ if (len != -1 && len <
+ exthdr_size) {
+ exthdr_str += len;
+ exthdr_size -= len;
+ }
+ }
}
if (olen > 0) {
- printf("|]");
+ len = snprintf(exthdr_str,
+ exthdr_size, "%s", "|]");
+ if (len != -1 && len <
+ exthdr_size) {
+ exthdr_str += len;
+ exthdr_size -= len;
+ }
return;
}
- if (first != 0)
- printf("]");
+ if (first != 0) {
+ len = snprintf(exthdr_str,
+ exthdr_size, "%s", "]");
+ if (len != -1 && len <
+ exthdr_size) {
+ exthdr_str += len;
+ exthdr_size -= len;
+ }
+ }
break;
default:
buf += olen;
@@ -205,7 +273,7 @@ print_exthdr(u_char *buf, int cc)
}
void
-check_tos(struct ip *ip, int *last_tos)
+check_tos(struct ip *ip, int *last_tos, struct tr_result *tr_res)
{
struct icmp *icp;
struct ip *inner_ip;
@@ -214,27 +282,12 @@ check_tos(struct ip *ip, int *last_tos)
inner_ip = (struct ip *) (((u_char *)icp)+8);
if (inner_ip->ip_tos != *last_tos)
- printf (" (TOS=%d!)", inner_ip->ip_tos);
+ snprintf(tr_res->tos, sizeof(tr_res->tos),
+ " (TOS=%d!)", inner_ip->ip_tos);
*last_tos = inner_ip->ip_tos;
}
-int
-wait_for_reply(int sock, struct msghdr *mhdr, int curwaittime)
-{
- struct pollfd pfd[1];
- int cc = 0;
-
- pfd[0].fd = sock;
- pfd[0].events = POLLIN;
- pfd[0].revents = 0;
-
- if (poll(pfd, 1, curwaittime) > 0)
- cc = recvmsg(rcvsock, mhdr, 0);
-
- return (cc);
-}
-
void
dump_packet(void)
{
@@ -251,7 +304,7 @@ dump_packet(void)
}
void
-build_probe4(struct tr_conf *conf, int seq, u_int8_t ttl, int iflag)
+build_probe4(struct tr_conf *conf, int seq, u_int8_t ttl)
{
struct ip *ip = (struct ip *)outpacket;
u_char *p = (u_char *)(ip + 1);
@@ -266,7 +319,7 @@ build_probe4(struct tr_conf *conf, int seq, u_int8_t ttl,
int iflag)
switch (conf->proto) {
case IPPROTO_ICMP:
- icmpp->icmp_type = icmp_type;
+ icmpp->icmp_type = ICMP_ECHO;
icmpp->icmp_code = ICMP_CODE;
icmpp->icmp_seq = htons(seq);
icmpp->icmp_id = htons(conf->ident);
@@ -274,10 +327,7 @@ build_probe4(struct tr_conf *conf, int seq, u_int8_t ttl,
int iflag)
break;
case IPPROTO_UDP:
up->uh_sport = htons(conf->ident);
- if (iflag)
- up->uh_dport = htons(conf->port+seq);
- else
- up->uh_dport = htons(conf->port);
+ up->uh_dport = htons(conf->port+seq);
up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip) -
conf->lsrrlen));
up->uh_sum = 0;
@@ -307,7 +357,7 @@ build_probe4(struct tr_conf *conf, int seq, u_int8_t ttl,
int iflag)
op->sec = htonl(tv.tv_sec + sec_perturb);
op->usec = htonl((tv.tv_usec + usec_perturb) % 1000000);
- if (conf->proto == IPPROTO_ICMP && icmp_type == ICMP_ECHO) {
+ if (conf->proto == IPPROTO_ICMP) {
icmpp->icmp_cksum = 0;
icmpp->icmp_cksum = in_cksum((u_short *)icmpp,
datalen - sizeof(struct ip) - conf->lsrrlen);
@@ -317,7 +367,7 @@ build_probe4(struct tr_conf *conf, int seq, u_int8_t ttl,
int iflag)
}
void
-build_probe6(struct tr_conf *conf, int seq, u_int8_t hops, int iflag,
+build_probe6(struct tr_conf *conf, int seq, u_int8_t hops,
struct sockaddr *to)
{
struct timeval tv;
@@ -329,10 +379,9 @@ build_probe6(struct tr_conf *conf, int seq, u_int8_t hops,
int iflag,
(char *)&i, sizeof(i)) == -1)
warn("setsockopt IPV6_UNICAST_HOPS");
- if (iflag)
- ((struct sockaddr_in6*)to)->sin6_port = htons(conf->port + seq);
- else
- ((struct sockaddr_in6*)to)->sin6_port = htons(conf->port);
+
+ ((struct sockaddr_in6*)to)->sin6_port = htons(conf->port + seq);
+
gettime(&tv);
if (conf->proto == IPPROTO_ICMP) {
@@ -354,17 +403,16 @@ build_probe6(struct tr_conf *conf, int seq, u_int8_t
hops, int iflag,
}
void
-send_probe(struct tr_conf *conf, int seq, u_int8_t ttl, int iflag,
- struct sockaddr *to)
+send_probe(struct tr_conf *conf, int seq, u_int8_t ttl, struct sockaddr *to)
{
int i;
switch (to->sa_family) {
case AF_INET:
- build_probe4(conf, seq, ttl, iflag);
+ build_probe4(conf, seq, ttl);
break;
case AF_INET6:
- build_probe6(conf, seq, ttl, iflag, to);
+ build_probe6(conf, seq, ttl, to);
break;
default:
errx(1, "unsupported AF: %d", to->sa_family);
@@ -428,15 +476,14 @@ pr_type(u_int8_t t)
}
int
-packet_ok(struct tr_conf *conf, int af, struct msghdr *mhdr, int cc, int seq,
- int iflag)
+packet_ok(struct tr_conf *conf, int af, struct msghdr *mhdr, int cc, int *seq)
{
switch (af) {
case AF_INET:
- return packet_ok4(conf, mhdr, cc, seq, iflag);
+ return packet_ok4(conf, mhdr, cc, seq);
break;
case AF_INET6:
- return packet_ok6(conf, mhdr, cc, seq, iflag);
+ return packet_ok6(conf, mhdr, cc, seq);
break;
default:
errx(1, "unsupported AF: %d", af);
@@ -445,7 +492,7 @@ packet_ok(struct tr_conf *conf, int af, struct msghdr
*mhdr, int cc, int seq,
}
int
-packet_ok4(struct tr_conf *conf, struct msghdr *mhdr, int cc,int seq, int
iflag)
+packet_ok4(struct tr_conf *conf, struct msghdr *mhdr, int cc, int *seq)
{
struct sockaddr_in *from = (struct sockaddr_in *)mhdr->msg_name;
struct icmp *icp;
@@ -478,27 +525,26 @@ packet_ok4(struct tr_conf *conf, struct msghdr *mhdr, int
cc,int seq, int iflag)
switch (conf->proto) {
case IPPROTO_ICMP:
- if (icmp_type == ICMP_ECHO &&
- type == ICMP_ECHOREPLY &&
- icp->icmp_id == htons(conf->ident) &&
- icp->icmp_seq == htons(seq))
+ if (type == ICMP_ECHOREPLY &&
+ icp->icmp_id == htons(conf->ident)) {
+ *seq = ntohs(icp->icmp_seq);
return (-2); /* we got there */
-
+ }
icmpp = (struct icmp *)((u_char *)hip + hlen);
if (hlen + 8 <= cc && hip->ip_p == IPPROTO_ICMP &&
- icmpp->icmp_id == htons(conf->ident) &&
- icmpp->icmp_seq == htons(seq))
+ icmpp->icmp_id == htons(conf->ident)) {
+ *seq = ntohs(icmpp->icmp_seq);
return (type == ICMP_TIMXCEED? -1 : code + 1);
+ }
break;
case IPPROTO_UDP:
up = (struct udphdr *)((u_char *)hip + hlen);
if (hlen + 12 <= cc && hip->ip_p == conf->proto &&
- up->uh_sport == htons(conf->ident) &&
- ((iflag && up->uh_dport == htons(conf->port +
- seq)) ||
- (!iflag && up->uh_dport == htons(conf->port))))
+ up->uh_sport == htons(conf->ident)) {
+ *seq = ntohs(up->uh_dport) - conf->port;
return (type == ICMP_TIMXCEED? -1 : code + 1);
+ }
break;
default:
/* this is some odd, user specified proto,
@@ -523,8 +569,7 @@ packet_ok4(struct tr_conf *conf, struct msghdr *mhdr, int
cc,int seq, int iflag)
}
int
-packet_ok6(struct tr_conf *conf, struct msghdr *mhdr, int cc, int seq,
- int iflag)
+packet_ok6(struct tr_conf *conf, struct msghdr *mhdr, int cc, int *seq)
{
struct icmp6_hdr *icp;
struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
@@ -540,7 +585,8 @@ packet_ok6(struct tr_conf *conf, struct msghdr *mhdr, int
cc, int seq,
if (getnameinfo((struct sockaddr *)from, from->sin6_len,
hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
strlcpy(hbuf, "invalid", sizeof(hbuf));
- printf("data too short (%d bytes) from %s\n", cc, hbuf);
+ printf("packet too short (%d bytes) from %s\n", cc,
+ hbuf);
}
return(0);
}
@@ -582,18 +628,19 @@ packet_ok6(struct tr_conf *conf, struct msghdr *mhdr, int
cc, int seq,
return(0);
}
if (useicmp &&
- ((struct icmp6_hdr *)up)->icmp6_id == conf->ident &&
- ((struct icmp6_hdr *)up)->icmp6_seq == htons(seq))
+ ((struct icmp6_hdr *)up)->icmp6_id == conf->ident) {
+ *seq = ntohs(((struct icmp6_hdr *)up)->icmp6_seq);
return (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1);
- else if (!useicmp &&
- up->uh_sport == htons(srcport) &&
- ((iflag && up->uh_dport == htons(conf->port + seq)) ||
- (!iflag && up->uh_dport == htons(conf->port))))
+ } else if (!useicmp &&
+ up->uh_sport == htons(srcport)) {
+ *seq = ntohs(up->uh_dport) - conf->port;
return (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1);
+ }
} else if (useicmp && type == ICMP6_ECHO_REPLY) {
- if (icp->icmp6_id == conf->ident &&
- icp->icmp6_seq == htons(seq))
- return (ICMP6_DST_UNREACH_NOPORT + 1);
+ if (icp->icmp6_id == conf->ident) {
+ *seq = ntohs(icp->icmp6_seq);
+ return (-2);
+ }
}
if (conf->verbose) {
char sbuf[NI_MAXHOST], dbuf[INET6_ADDRSTRLEN];
@@ -626,22 +673,32 @@ packet_ok6(struct tr_conf *conf, struct msghdr *mhdr, int
cc, int seq,
}
void
-print(struct tr_conf *conf, struct sockaddr *from, int cc, const char *to)
+print(struct tr_conf *conf, struct sockaddr *from, int cc, const char *to,
+ struct tr_result *tr_res)
{
- char hbuf[NI_MAXHOST];
+ struct asr_query *aq;
+ char hbuf[NI_MAXHOST];
+
if (getnameinfo(from, from->sa_len,
- hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
- strlcpy(hbuf, "invalid", sizeof(hbuf));
- if (conf->nflag)
- printf(" %s", hbuf);
- else
- printf(" %s (%s)", inetname(from), hbuf);
+ tr_res->hbuf, sizeof(tr_res->hbuf), NULL, 0, NI_NUMERICHOST) != 0)
+ strlcpy(tr_res->hbuf, "invalid", sizeof(hbuf));
+
+ if (!conf->nflag) {
+ aq = getnameinfo_async(from, from->sa_len, tr_res->inetname,
+ sizeof(tr_res->inetname), NULL, 0, NI_NAMEREQD, NULL);
+ if (aq != NULL)
+ event_asr_run(aq, getnameinfo_async_done, tr_res);
+ else {
+ waiting_ttls[tr_res->row]--;
+ tr_res->inetname_done = 1; /* use hbuf */
+ }
+ }
if (conf->Aflag)
- print_asn((struct sockaddr_storage *)from);
+ print_asn((struct sockaddr_storage *)from, tr_res);
- if (conf->verbose)
- printf(" %d bytes to %s", cc, to);
+ strlcpy(tr_res->to, to, sizeof(tr_res->to));
+ tr_res->cc = cc;
}
/*
@@ -690,14 +747,15 @@ get_udphdr(struct tr_conf *conf, struct ip6_hdr *ip6,
u_char *lim)
}
void
-icmp_code(int af, int code, int *got_there, int *unreachable)
+icmp_code(int af, int code, int *got_there, int *unreachable,
+ struct tr_result *tr_res)
{
switch (af) {
case AF_INET:
- icmp4_code(code, got_there, unreachable);
+ icmp4_code(code, got_there, unreachable, tr_res);
break;
case AF_INET6:
- icmp6_code(code, got_there, unreachable);
+ icmp6_code(code, got_there, unreachable, tr_res);
break;
default:
errx(1, "unsupported AF: %d", af);
@@ -706,97 +764,116 @@ icmp_code(int af, int code, int *got_there, int
*unreachable)
}
void
-icmp4_code(int code, int *got_there, int *unreachable)
+icmp4_code(int code, int *got_there, int *unreachable, struct tr_result
*tr_res)
{
struct ip *ip = (struct ip *)packet;
switch (code) {
case ICMP_UNREACH_PORT:
if (ip->ip_ttl <= 1)
- printf(" !");
+ snprintf(tr_res->icmp_code, sizeof(tr_res->icmp_code),
+ "%s", " !");
++(*got_there);
break;
case ICMP_UNREACH_NET:
++(*unreachable);
- printf(" !N");
+ snprintf(tr_res->icmp_code, sizeof(tr_res->icmp_code), "%s",
+ " !N");
break;
case ICMP_UNREACH_HOST:
++(*unreachable);
- printf(" !H");
+ snprintf(tr_res->icmp_code, sizeof(tr_res->icmp_code), "%s",
+ " !H");
break;
case ICMP_UNREACH_PROTOCOL:
++(*got_there);
- printf(" !P");
+ snprintf(tr_res->icmp_code, sizeof(tr_res->icmp_code), "%s",
+ " !P");
break;
case ICMP_UNREACH_NEEDFRAG:
++(*unreachable);
- printf(" !F");
+ snprintf(tr_res->icmp_code, sizeof(tr_res->icmp_code), "%s",
+ " !F");
break;
case ICMP_UNREACH_SRCFAIL:
++(*unreachable);
- printf(" !S");
+ snprintf(tr_res->icmp_code, sizeof(tr_res->icmp_code), "%s",
+ " !S");
break;
case ICMP_UNREACH_FILTER_PROHIB:
++(*unreachable);
- printf(" !X");
+ snprintf(tr_res->icmp_code, sizeof(tr_res->icmp_code), "%s",
+ " !X");
break;
case ICMP_UNREACH_NET_PROHIB: /*misuse*/
++(*unreachable);
- printf(" !A");
+ snprintf(tr_res->icmp_code, sizeof(tr_res->icmp_code), "%s",
+ " !A");
break;
case ICMP_UNREACH_HOST_PROHIB:
++(*unreachable);
- printf(" !C");
+ snprintf(tr_res->icmp_code, sizeof(tr_res->icmp_code), "%s",
+ " !C");
break;
case ICMP_UNREACH_NET_UNKNOWN:
case ICMP_UNREACH_HOST_UNKNOWN:
++(*unreachable);
- printf(" !U");
+ snprintf(tr_res->icmp_code, sizeof(tr_res->icmp_code), "%s",
+ " !U");
break;
case ICMP_UNREACH_ISOLATED:
++(*unreachable);
- printf(" !I");
+ snprintf(tr_res->icmp_code, sizeof(tr_res->icmp_code), "%s",
+ " !I");
break;
case ICMP_UNREACH_TOSNET:
case ICMP_UNREACH_TOSHOST:
++(*unreachable);
- printf(" !T");
+ snprintf(tr_res->icmp_code, sizeof(tr_res->icmp_code), "%s",
+ " !T");
break;
default:
++(*unreachable);
- printf(" !<%d>", code);
+ snprintf(tr_res->icmp_code, sizeof(tr_res->icmp_code), " !<%d>",
+ code & 0xff);
break;
}
}
void
-icmp6_code(int code, int *got_there, int *unreachable)
+icmp6_code(int code, int *got_there, int *unreachable, struct tr_result
*tr_res)
{
switch (code) {
case ICMP6_DST_UNREACH_NOROUTE:
++(*unreachable);
- printf(" !N");
+ snprintf(tr_res->icmp_code, sizeof(tr_res->icmp_code), "%s",
+ " !N");
break;
case ICMP6_DST_UNREACH_ADMIN:
++(*unreachable);
- printf(" !P");
+ snprintf(tr_res->icmp_code, sizeof(tr_res->icmp_code), "%s",
+ " !P");
break;
case ICMP6_DST_UNREACH_BEYONDSCOPE:
++(*unreachable);
- printf(" !S");
+ snprintf(tr_res->icmp_code, sizeof(tr_res->icmp_code), "%s",
+ " !S");
break;
case ICMP6_DST_UNREACH_ADDR:
++(*unreachable);
- printf(" !A");
+ snprintf(tr_res->icmp_code, sizeof(tr_res->icmp_code), "%s",
+ " !A");
break;
case ICMP6_DST_UNREACH_NOPORT:
- if (rcvhlim >= 0 && rcvhlim <= 1)
- printf(" !");
+ if (rcvhlim <= 1)
+ snprintf(tr_res->icmp_code, sizeof(tr_res->icmp_code),
+ "%s", " !");
++(*got_there);
break;
default:
++(*unreachable);
- printf(" !<%d>", code);
+ snprintf(tr_res->icmp_code, sizeof(tr_res->icmp_code), " !<%d>",
+ code & 0xff);
break;
}
}
@@ -834,45 +911,12 @@ in_cksum(u_short *addr, int len)
return (answer);
}
-/*
- * Construct an Internet address representation.
- */
-const char *
-inetname(struct sockaddr *sa)
-{
- static char line[NI_MAXHOST], domain[HOST_NAME_MAX + 1];
- static int first = 1;
- char *cp;
-
- if (first) {
- first = 0;
- if (gethostname(domain, sizeof(domain)) == 0 &&
- (cp = strchr(domain, '.')) != NULL)
- memmove(domain, cp + 1, strlen(cp + 1) + 1);
- else
- domain[0] = 0;
- }
- if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0,
- NI_NAMEREQD) == 0) {
- if ((cp = strchr(line, '.')) != NULL && strcmp(cp + 1,
- domain) == 0)
- *cp = '\0';
- return (line);
- }
-
- if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0,
- NI_NUMERICHOST) != 0)
- return ("invalid");
- return (line);
-}
-
void
-print_asn(struct sockaddr_storage *ss)
+print_asn(struct sockaddr_storage *ss, struct tr_result *tr_res)
{
- struct rrsetinfo *answers = NULL;
- int counter;
- const u_char *uaddr;
- char qbuf[MAXDNAME];
+ struct asr_query *aq;
+ const u_char *uaddr;
+ char qbuf[MAXDNAME];
switch (ss->ss_family) {
case AF_INET:
@@ -911,21 +955,12 @@ print_asn(struct sockaddr_storage *ss)
return;
}
- if (getrrsetbyname(qbuf, C_IN, T_TXT, 0, &answers) != 0)
- return;
- for (counter = 0; counter < answers->rri_nrdatas; counter++) {
- char *p, *as = answers->rri_rdatas[counter].rdi_data;
- as++; /* skip first byte, it contains length */
- if ((p = strchr(as,'|'))) {
- printf(counter ? ", " : " [");
- p[-1] = 0;
- printf("AS%s", as);
- }
+ if ((aq = getrrsetbyname_async(qbuf, C_IN, T_TXT, 0, NULL)) != NULL)
+ event_asr_run(aq, getrrsetbyname_async_done, tr_res);
+ else {
+ waiting_ttls[tr_res->row]--;
+ tr_res->asn_done = 1;
}
- if (counter)
- printf("]");
-
- freerrset(answers);
}
int
@@ -986,3 +1021,201 @@ gettime(struct timeval *tv)
TIMESPEC_TO_TIMEVAL(tv, &ts);
}
+
+void
+check_timeout(struct tr_result *tr_row, struct tr_conf *conf)
+{
+ struct timeval t2;
+ int i;
+
+ gettime(&t2);
+
+ for (i = 0; i < conf->nprobes; i++) {
+ /* we didn't send the probe yet */
+ if (tr_row[i].ttl == 0)
+ return;
+ /* we got a result, it can no longer timeout */
+ if (tr_row[i].dup)
+ continue;
+
+ if (deltaT(&tr_row[i].t1, &t2) > conf->waittime) {
+ tr_row[i].timeout = 1;
+ tr_row[i].dup++; /* we "saw" the result */
+ waiting_ttls[tr_row[i].row] -=
+ conf->expected_responses;
+ }
+ }
+}
+
+void
+catchup_result_rows(struct tr_result *tr_results, struct tr_conf *conf)
+{
+ static int timeout_row = 0;
+ static int print_row = 0;
+ int i, j, all_timeout = 1;
+
+ for (; timeout_row < conf->max_ttl; timeout_row++) {
+ struct tr_result *tr_row = tr_results +
+ timeout_row * conf->nprobes;
+ check_timeout(tr_row, conf);
+ if (waiting_ttls[timeout_row] > 0)
+ break;
+ }
+
+ for (i = print_row; i < timeout_row; i++) {
+ struct tr_result *tr_row = tr_results + i * conf->nprobes;
+
+ if (waiting_ttls[i] > 0)
+ break;
+
+ for (j = 0; j < conf->nprobes; j++) {
+ if (!tr_row[j].timeout) {
+ all_timeout = 0;
+ break;
+ }
+ }
+ if (!all_timeout)
+ break;
+ }
+
+ if (all_timeout && i != conf->max_ttl)
+ return;
+
+ if (i == conf->max_ttl)
+ print_row = i - 1; /* jump ahead, skip long trail of * * * */
+
+ for (; print_row <= i; print_row++) {
+ struct tr_result *tr_row = tr_results +
+ print_row * conf->nprobes;
+ if (waiting_ttls[print_row] > 0)
+ break;
+ print_result_row(tr_row, conf);
+ }
+}
+
+void
+print_result_row(struct tr_result *tr_results, struct tr_conf *conf)
+{
+ int i, loss = 0, got_there = 0, unreachable = 0;
+ char *lastaddr = NULL;
+
+ printf("%2u ", tr_results[0].ttl);
+ for (i = 0; i < conf->nprobes; i++) {
+ got_there += tr_results[i].got_there;
+ unreachable += tr_results[i].unreachable;
+
+ if (tr_results[i].timeout) {
+ printf(" %s%s", "*", tr_results[i].icmp_code);
+ loss++;
+ continue;
+ }
+
+ if (lastaddr == NULL || strcmp(lastaddr, tr_results[i].hbuf)
+ != 0) {
+ if (*tr_results[i].hbuf != '\0') {
+ if (conf->nflag)
+ printf(" %s", tr_results[i].hbuf);
+ else
+ printf(" %s (%s)",
+ tr_results[i].inetname[0] == '\0' ?
+ tr_results[i].hbuf :
+ tr_results[i].inetname,
+ tr_results[i].hbuf);
+ if (conf->Aflag && tr_results[i].asn != NULL)
+ printf(" %s", tr_results[i].asn);
+ if (conf->verbose)
+ printf(" %d bytes to %s",
+ tr_results[i].cc,
+ tr_results[i].to);
+ }
+ }
+ lastaddr = tr_results[i].hbuf;
+ printf(" %g ms%s%s",
+ deltaT(&tr_results[i].t1,
+ &tr_results[i].t2),
+ tr_results[i].tos,
+ tr_results[i].icmp_code);
+ if (conf->ttl_flag)
+ printf(" (%u)", tr_results[i].resp_ttl);
+
+ if (tr_results[i].exthdr)
+ printf("%s", tr_results[i].exthdr);
+ }
+ if (conf->sump)
+ printf(" (%d%% loss)", (loss * 100) / conf->nprobes);
+ putchar('\n');
+ fflush(stdout);
+ if (got_there || unreachable || tr_results[0].ttl == conf->max_ttl)
+ exit(0);
+}
+
+void
+getnameinfo_async_done(struct asr_result *ar, void *arg)
+{
+ static char domain[HOST_NAME_MAX + 1];
+ static int first = 1;
+ struct tr_result *tr_res = arg;
+ char *cp;
+
+ if (first) {
+ first = 0;
+ if (gethostname(domain, sizeof(domain)) == 0 &&
+ (cp = strchr(domain, '.')) != NULL)
+ memmove(domain, cp + 1, strlen(cp + 1) + 1);
+ else
+ domain[0] = 0;
+ }
+
+ tr_res->inetname_done = 1;
+ waiting_ttls[tr_res->row]--;
+
+ if (ar->ar_gai_errno == 0) {
+ if ((cp = strchr(tr_res->inetname, '.')) != NULL &&
+ strcmp(cp + 1, domain) == 0)
+ *cp = '\0';
+ } else
+ tr_res->inetname[0]='\0';
+}
+
+void
+getrrsetbyname_async_done(struct asr_result *ar, void *arg)
+{
+ struct tr_result *tr_res = arg;
+ struct rrsetinfo *answers;
+ size_t asn_size = 0, len;
+ int counter;
+ char *asn;
+
+ tr_res->asn_done = 1;
+ waiting_ttls[tr_res->row]--;
+ if (ar->ar_rrset_errno != 0)
+ return;
+
+ answers = ar->ar_rrsetinfo;
+
+ if (answers->rri_nrdatas > 0) {
+ asn_size = answers->rri_nrdatas * sizeof("AS2147483647, ") + 3;
+ if ((tr_res->asn = calloc(1, asn_size)) == NULL)
+ err(1, NULL);
+ asn = tr_res->asn;
+ }
+
+ for (counter = 0; counter < answers->rri_nrdatas; counter++) {
+ char *p, *as = answers->rri_rdatas[counter].rdi_data;
+ as++; /* skip first byte, it contains length */
+ if ((p = strchr(as,'|'))) {
+ p[-1] = 0;
+ len = snprintf(asn, asn_size, "%sAS%s",
+ counter ? ", " : "[", as);
+ if (len != -1 && len < asn_size) {
+ asn += len;
+ asn_size -= len;
+ } else
+ asn_size = 0;
+ }
+ }
+ if (counter && asn_size > 0)
+ *asn=']';
+
+ freerrset(answers);
+}
--
I'm not entirely sure you are real.