On 2021-09-01 04:05 -06, "Theo de Raadt" <dera...@openbsd.org> wrote:
> Stuart Henderson <s...@spacehopper.org> 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.

Reply via email to