2 * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000
3 * The Regents of the University of California. All rights reserved.
5 * Busybox port by Vladimir Oleynik (C) 2005 <dzo@simtreas.ru>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that: (1) source code distributions
9 * retain the above copyright notice and this paragraph in its entirety, (2)
10 * distributions including binary code include the above copyright notice and
11 * this paragraph in its entirety in the documentation or other materials
12 * provided with the distribution, and (3) all advertising materials mentioning
13 * features or use of this software display the following acknowledgement:
14 * ``This product includes software developed by the University of California,
15 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16 * the University nor the names of its contributors may be used to endorse
17 * or promote products derived from this software without specific prior
19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24 //#define version "1.4a12"
28 * traceroute host - trace the route ip packets follow going to "host".
30 * Attempt to trace the route an ip packet would follow to some
31 * internet host. We find out intermediate hops by launching probe
32 * packets with a small ttl (time to live) then listening for an
33 * icmp "time exceeded" reply from a gateway. We start our probes
34 * with a ttl of one and increase by one until we get an icmp "port
35 * unreachable" (which means we got to "host") or hit a max (which
36 * defaults to 30 hops & can be changed with the -m flag). Three
37 * probes (change with -q flag) are sent at each ttl setting and a
38 * line is printed showing the ttl, address of the gateway and
39 * round trip time of each probe. If the probe answers come from
40 * different gateways, the address of each responding system will
41 * be printed. If there is no response within a 5 sec. timeout
42 * interval (changed with the -w flag), a "*" is printed for that
45 * Probe packets are UDP format. We don't want the destination
46 * host to process them so the destination port is set to an
47 * unlikely value (if some clod on the destination is using that
48 * value, it can be changed with the -p flag).
50 * A sample use might be:
52 * [yak 71]% traceroute nis.nsf.net.
53 * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
54 * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms
55 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
56 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
57 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms
58 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms
59 * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms
60 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms
61 * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms
62 * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms
63 * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms
64 * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms
66 * Note that lines 2 & 3 are the same. This is due to a buggy
67 * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
68 * packets with a zero ttl.
70 * A more interesting example is:
72 * [yak 72]% traceroute allspice.lcs.mit.edu.
73 * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
74 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
75 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms
76 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms
77 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms
78 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms
79 * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms
80 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms
81 * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms
82 * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms
83 * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms
84 * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms
86 * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms
91 * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms
93 * (I start to see why I'm having so much trouble with mail to
94 * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away
95 * either don't send ICMP "time exceeded" messages or send them
96 * with a ttl too small to reach us. 14 - 17 are running the
97 * MIT C Gateway code that doesn't send "time exceeded"s. God
98 * only knows what's going on with 12.
100 * The silent gateway 12 in the above may be the result of a bug in
101 * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3)
102 * sends an unreachable message using whatever ttl remains in the
103 * original datagram. Since, for gateways, the remaining ttl is
104 * zero, the icmp "time exceeded" is guaranteed to not make it back
105 * to us. The behavior of this bug is slightly more interesting
106 * when it appears on the destination system:
108 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
109 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms
110 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms
111 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms
112 * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms
113 * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms
120 * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms !
122 * Notice that there are 12 "gateways" (13 is the final
123 * destination) and exactly the last half of them are "missing".
124 * What's really happening is that rip (a Sun-3 running Sun OS3.5)
125 * is using the ttl from our arriving datagram as the ttl in its
126 * icmp reply. So, the reply will time out on the return path
127 * (with no notice sent to anyone since icmp's aren't sent for
128 * icmp's) until we probe with a ttl that's at least twice the path
129 * length. I.e., rip is really only 7 hops away. A reply that
130 * returns with a ttl of 1 is a clue this problem exists.
131 * Traceroute prints a "!" after the time if the ttl is <= 1.
132 * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
133 * non-standard (HPUX) software, expect to see this problem
134 * frequently and/or take care picking the target host of your
137 * Other possible annotations after the time are !H, !N, !P (got a host,
138 * network or protocol unreachable, respectively), !S or !F (source
139 * route failed or fragmentation needed -- neither of these should
140 * ever occur and the associated gateway is busted if you see one). If
141 * almost all the probes result in some kind of unreachable, traceroute
142 * will give up and exit.
146 * This program must be run by root or be setuid. (I suggest that
147 * you *don't* make it setuid -- casual use could result in a lot
148 * of unnecessary traffic on our poor, congested nets.)
150 * This program requires a kernel mod that does not appear in any
151 * system available from Berkeley: A raw ip socket using proto
152 * IPPROTO_RAW must interpret the data sent as an ip datagram (as
153 * opposed to data to be wrapped in a ip datagram). See the README
154 * file that came with the source to this program for a description
155 * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may
156 * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
157 * MODIFIED TO RUN THIS PROGRAM.
159 * The udp port usage may appear bizarre (well, ok, it is bizarre).
160 * The problem is that an icmp message only contains 8 bytes of
161 * data from the original datagram. 8 bytes is the size of a udp
162 * header so, if we want to associate replies with the original
163 * datagram, the necessary information must be encoded into the
164 * udp header (the ip id could be used but there's no way to
165 * interlock with the kernel's assignment of ip id's and, anyway,
166 * it would have taken a lot more kernel hacking to allow this
167 * code to set the ip id). So, to allow two or more users to
168 * use traceroute simultaneously, we use this task's pid as the
169 * source port (the high bit is set to move the port number out
170 * of the "likely" range). To keep track of which probe is being
171 * replied to (so times and/or hop counts don't get confused by a
172 * reply that was delayed in transit), we increment the destination
173 * port number before each probe.
175 * Don't use this as a coding example. I was trying to find a
176 * routing problem and this code sort-of popped out after 48 hours
177 * without sleep. I was amazed it ever compiled, much less ran.
179 * I stole the idea for this program from Steve Deering. Since
180 * the first release, I've learned that had I attended the right
181 * IETF working group meetings, I also could have stolen it from Guy
182 * Almes or Matt Mathis. I don't know (or care) who came up with
183 * the idea first. I envy the originators' perspicacity and I'm
184 * glad they didn't keep the idea a secret.
186 * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
187 * enhancements to the original distribution.
189 * I've hacked up a round-trip-route version of this that works by
190 * sending a loose-source-routed udp datagram through the destination
191 * back to yourself. Unfortunately, SO many gateways botch source
192 * routing, the thing is almost worthless. Maybe one day...
194 * -- Van Jacobson (van@ee.lbl.gov)
195 * Tue Dec 20 03:50:13 PST 1988
198 #undef CONFIG_FEATURE_TRACEROUTE_VERBOSE
199 //#define CONFIG_FEATURE_TRACEROUTE_VERBOSE
200 #undef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG /* not in documentation man */
201 #undef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
202 //#define CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
203 #undef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
204 //#define CONFIG_FEATURE_TRACEROUTE_USE_ICMP
218 #include <sys/param.h>
219 #include <sys/file.h>
220 #include <sys/ioctl.h>
221 #include <sys/socket.h>
222 #include <sys/time.h> /* concession to AIX */
223 #include <sys/select.h>
224 #include "inet_common.h"
227 #include <netinet/in.h>
228 #include <arpa/inet.h>
229 #include <netinet/udp.h>
230 #include <netinet/ip.h>
231 #include <netinet/ip_icmp.h>
237 * Definitions for internet protocol version 4.
238 * Per RFC 791, September 1981.
243 * Overlay for ip header used by other protocols (tcp, udp).
246 u_char ih_x1[9]; /* (unused) */
247 u_char ih_pr; /* protocol */
248 short ih_len; /* protocol length */
249 struct in_addr ih_src; /* source internet address */
250 struct in_addr ih_dst; /* destination internet address */
254 * UDP kernel structures and variables.
257 struct ipovly ui_i; /* overlaid ip structure */
258 struct udphdr ui_u; /* udp header */
260 #define ui_next ui_i.ih_next
261 #define ui_prev ui_i.ih_prev
262 #define ui_x1 ui_i.ih_x1
263 #define ui_pr ui_i.ih_pr
264 #define ui_len ui_i.ih_len
265 #define ui_src ui_i.ih_src
266 #define ui_dst ui_i.ih_dst
267 #define ui_sport ui_u.uh_sport
268 #define ui_dport ui_u.uh_dport
269 #define ui_ulen ui_u.uh_ulen
270 #define ui_sum ui_u.uh_sum
273 /* Host name and address list */
280 /* Data section of the probe packet */
282 u_char seq; /* sequence number of this packet */
283 u_char ttl; /* ttl packet left with */
284 struct timeval tv __attribute__((packed)); /* time packet left */
289 char device[sizeof(struct ifreq)];
293 static const char route[] = "/proc/net/route";
295 /* last inbound (icmp) packet */
296 static u_char packet[512] __attribute__((align (32)));
298 static struct ip *outip; /* last output (udp) packet */
299 static struct udphdr *outudp; /* last output (udp) packet */
300 static struct outdata *outdata; /* last output (udp) packet */
302 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
303 static struct icmp *outicmp; /* last output (icmp) packet */
306 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
307 /* Maximum number of gateways (include room for one noop) */
308 #define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))
309 /* loose source route gateway list (including room for final destination) */
310 static u_int32_t gwlist[NGATEWAYS + 1];
313 static int s; /* receive (icmp) socket file descriptor */
314 static int sndsock; /* send (udp/icmp) socket file descriptor */
316 static struct sockaddr_storage whereto; /* Who to try to reach */
317 static struct sockaddr_storage wherefrom; /* Who we are */
318 static int packlen; /* total length of packet */
319 static int minpacket; /* min ip packet size */
320 static int maxpacket = 32 * 1024; /* max ip packet size */
321 static int pmtu; /* Path MTU Discovery (RFC1191) */
323 static char *hostname;
324 static const char devnull[] = "/dev/null";
326 static u_short ident;
327 static u_short port = 32768 + 666; /* start udp dest port # for probe packets */
329 static int waittime = 5; /* time to wait for response (in seconds) */
330 static int nflag; /* print addresses numerically */
331 static int doipcksum = 1; /* calculate ip checksums by default */
333 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
334 static int optlen; /* length of ip options */
339 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
340 static int useicmp; /* use icmp echo instead of udp packets */
342 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
347 * Return the interface list
350 ifaddrlist(struct IFADDRLIST **ipaddrp)
353 #ifdef HAVE_SOCKADDR_SA_LEN
356 struct ifreq *ifrp, *ifend, *ifnext;
357 struct sockaddr_in *addr_sin;
358 struct IFADDRLIST *al;
360 struct ifreq ibuf[(32 * 1024) / sizeof(struct ifreq)], ifr;
361 struct IFADDRLIST *st_ifaddrlist;
363 fd = socket(AF_INET, SOCK_DGRAM, 0);
365 bb_perror_msg_and_die("socket");
367 ifc.ifc_len = sizeof(ibuf);
368 ifc.ifc_buf = (caddr_t)ibuf;
370 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
371 ifc.ifc_len < sizeof(struct ifreq)) {
373 bb_error_msg_and_die(
374 "SIOCGIFCONF: ifreq struct too small (%d bytes)",
377 bb_perror_msg_and_die("SIOCGIFCONF");
380 ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
382 nipaddr = 1 + (ifc.ifc_len / sizeof(struct ifreq));
383 st_ifaddrlist = xcalloc(nipaddr, sizeof(struct IFADDRLIST));
387 for (; ifrp < ifend; ifrp = ifnext) {
388 #ifdef HAVE_SOCKADDR_SA_LEN
389 n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
390 if (n < sizeof(*ifrp))
393 ifnext = (struct ifreq *)((char *)ifrp + n);
394 if (ifrp->ifr_addr.sa_family != AF_INET)
400 * Need a template to preserve address info that is
401 * used below to locate the next entry. (Otherwise,
402 * SIOCGIFFLAGS stomps over it because the requests
403 * are returned in a union.)
405 strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));
406 if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
409 bb_perror_msg_and_die("SIOCGIFFLAGS: %.*s",
410 (int)sizeof(ifr.ifr_name), ifr.ifr_name);
414 if ((ifr.ifr_flags & IFF_UP) == 0)
417 safe_strncpy(al->device, ifr.ifr_name, sizeof(ifr.ifr_name) + 1);
419 /* Ignore sun virtual interfaces */
420 if (strchr(al->device, ':') != NULL)
423 if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0)
424 bb_perror_msg_and_die("SIOCGIFADDR: %s", al->device);
426 addr_sin = (struct sockaddr_in *)&ifr.ifr_addr;
427 al->addr = addr_sin->sin_addr.s_addr;
432 bb_error_msg_and_die ("Can't find any network interfaces");
435 *ipaddrp = st_ifaddrlist;
441 setsin(struct sockaddr_in *addr_sin, u_int32_t addr)
443 memset(addr_sin, 0, sizeof(*addr_sin));
444 #ifdef HAVE_SOCKADDR_SA_LEN
445 addr_sin->sin_len = sizeof(*addr_sin);
447 addr_sin->sin_family = AF_INET;
448 addr_sin->sin_addr.s_addr = addr;
453 * Return the source address for the given destination address
456 findsaddr(const struct sockaddr_in *to, struct sockaddr_in *from)
461 u_int32_t dest, tmask;
462 struct IFADDRLIST *al;
463 char buf[256], tdevice[256], device[256];
465 f = bb_xfopen(route, "r");
467 /* Find the appropriate interface */
471 while (fgets(buf, sizeof(buf), f) != NULL) {
473 if (n == 1 && strncmp(buf, "Iface", 5) == 0)
475 if ((i = sscanf(buf, "%255s %x %*s %*s %*s %*s %*s %x",
476 tdevice, &dest, &tmask)) != 3)
477 bb_error_msg_and_die ("junk in buffer");
478 if ((to->sin_addr.s_addr & tmask) == dest &&
479 (tmask > mask || mask == 0)) {
481 strcpy(device, tdevice);
486 if (device[0] == '\0')
487 bb_error_msg_and_die ("Can't find interface");
489 /* Get the interface address list */
492 /* Find our appropriate source address */
493 for (i = n; i > 0; --i, ++al)
494 if (strcmp(device, al->device) == 0)
497 bb_error_msg_and_die("Can't find interface %s", device);
499 setsin(from, al->addr);
503 "Usage: %s [-dFIlnrvx] [-g gateway] [-i iface] [-f first_ttl]\n"
504 "\t[-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos]\n"
505 "\t[-w waittime] [-z pausemsecs] host [packetlen]"
509 /* String to value with optional min and max. Handles decimal and hex. */
511 str2val(const char *str, const char *what, int mi, int ma)
517 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
519 val = (int)strtol(cp, &ep, 16);
521 val = (int)strtol(str, &ep, 10);
523 bb_error_msg_and_die("\"%s\" bad value for %s \n", str, what);
525 if (val < mi && mi >= 0) {
527 bb_error_msg_and_die("%s must be >= %d\n", what, mi);
529 bb_error_msg_and_die("%s must be > %d\n", what, mi - 1);
531 if (val > ma && ma >= 0)
532 bb_error_msg_and_die("%s must be <= %d\n", what, ma);
538 * Subtract 2 timeval structs: out = out - in.
539 * Out is assumed to be >= in.
542 tvsub(struct timeval *out, struct timeval *in)
545 if ((out->tv_usec -= in->tv_usec) < 0) {
547 out->tv_usec += 1000000;
549 out->tv_sec -= in->tv_sec;
553 wait_for_reply(int sock, struct sockaddr_in *fromp, const struct timeval *tp)
556 struct timeval now, wait;
559 socklen_t fromlen = sizeof(*fromp);
564 wait.tv_sec = tp->tv_sec + waittime;
565 wait.tv_usec = tp->tv_usec;
566 (void)gettimeofday(&now, &tz);
569 if (select(sock + 1, &fds, NULL, NULL, &wait) > 0)
570 cc = recvfrom(sock, (char *)packet, sizeof(packet), 0,
571 (struct sockaddr *)fromp, &fromlen);
577 * Checksum routine for Internet Protocol family headers (C Version)
580 in_cksum(u_short *addr, int len)
588 * Our algorithm is simple, using a 32 bit accumulator (sum),
589 * we add sequential 16 bit words to it, and at the end, fold
590 * back all the carry bits from the top 16 bits into the lower
598 /* mop up an odd byte, if necessary */
603 * add back carry outs from top 16 bits to low 16 bits
605 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
606 sum += (sum >> 16); /* add carry */
607 answer = ~sum; /* truncate to 16 bits */
613 send_probe(int seq, int ttl, struct timeval *tp)
616 struct udpiphdr *ui, *oui;
620 outip->ip_id = htons(ident + seq);
623 * In most cases, the kernel will recalculate the ip checksum.
624 * But we must do it anyway so that the udp checksum comes out
629 in_cksum((u_short *)outip, sizeof(*outip) + optlen);
630 if (outip->ip_sum == 0)
631 outip->ip_sum = 0xffff;
637 memcpy(&outdata->tv, tp, sizeof(outdata->tv));
639 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
641 outicmp->icmp_seq = htons(seq);
644 outudp->dest = htons(port + seq);
646 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
648 /* Always calculate checksum for icmp packets */
649 outicmp->icmp_cksum = 0;
650 outicmp->icmp_cksum = in_cksum((u_short *)outicmp,
651 packlen - (sizeof(*outip) + optlen));
652 if (outicmp->icmp_cksum == 0)
653 outicmp->icmp_cksum = 0xffff;
657 /* Checksum (we must save and restore ip header) */
659 ui = (struct udpiphdr *)outip;
660 oui = (struct udpiphdr *)&tip;
661 /* Easier to zero and put back things that are ok */
662 memset((char *)ui, 0, sizeof(ui->ui_i));
663 ui->ui_src = oui->ui_src;
664 ui->ui_dst = oui->ui_dst;
665 ui->ui_pr = oui->ui_pr;
666 ui->ui_len = outudp->len;
668 outudp->check = in_cksum((u_short *)ui, packlen);
669 if (outudp->check == 0)
670 outudp->check = 0xffff;
674 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
675 /* XXX undocumented debugging hack */
680 sp = (u_short *)outip;
681 nshorts = (u_int)packlen / sizeof(u_short);
683 printf("[ %d bytes", packlen);
684 while (--nshorts >= 0) {
687 printf(" %04x", ntohs(*sp));
693 printf(" %02x", *(u_char *)sp);
699 #if !defined(IP_HDRINCL) && defined(IP_TTL)
700 if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
701 (char *)&ttl, sizeof(ttl)) < 0) {
702 bb_perror_msg_and_die("setsockopt ttl %d", ttl);
706 cc = sendto(sndsock, (char *)outip,
707 packlen, 0, (struct sockaddr *)&whereto, sizeof(whereto));
708 if (cc < 0 || cc != packlen) {
710 bb_perror_msg_and_die("sendto");
711 printf("%s: wrote %s %d chars, ret=%d\n",
712 bb_applet_name, hostname, packlen, cc);
713 (void)fflush(stdout);
718 deltaT(struct timeval *t1p, struct timeval *t2p)
722 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
723 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
727 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
729 * Convert an ICMP "type" field to a printable string.
731 static inline const char *
734 static const char * const ttab[] = {
735 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
736 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
737 "Echo", "Router Advert", "Router Solicit", "Time Exceeded",
738 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
739 "Info Reply", "Mask Request", "Mask Reply"
743 return "OUT-OF-RANGE";
750 packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
757 ip = (struct ip *) buf;
758 hlen = ip->ip_hl << 2;
759 if (cc < hlen + ICMP_MINLEN) {
760 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
762 printf("packet too short (%d bytes) from %s\n", cc,
763 inet_ntoa(from->sin_addr));
768 icp = (struct icmp *)(buf + hlen);
769 type = icp->icmp_type;
770 code = icp->icmp_code;
771 /* Path MTU Discovery (RFC1191) */
772 if (code != ICMP_UNREACH_NEEDFRAG)
775 pmtu = ntohs(icp->icmp_nextmtu);
777 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
778 type == ICMP_UNREACH || type == ICMP_ECHOREPLY) {
783 hlen = hip->ip_hl << 2;
784 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
789 if (type == ICMP_ECHOREPLY &&
790 icp->icmp_id == htons(ident) &&
791 icp->icmp_seq == htons(seq))
794 hicmp = (struct icmp *)((u_char *)hip + hlen);
795 /* XXX 8 is a magic number */
796 if (hlen + 8 <= cc &&
797 hip->ip_p == IPPROTO_ICMP &&
798 hicmp->icmp_id == htons(ident) &&
799 hicmp->icmp_seq == htons(seq))
800 return (type == ICMP_TIMXCEED ? -1 : code + 1);
804 up = (struct udphdr *)((u_char *)hip + hlen);
805 /* XXX 8 is a magic number */
806 if (hlen + 12 <= cc &&
807 hip->ip_p == IPPROTO_UDP &&
808 up->source == htons(ident) &&
809 up->dest == htons(port + seq))
810 return (type == ICMP_TIMXCEED ? -1 : code + 1);
813 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
816 u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
818 printf("\n%d bytes from %s to "
819 "%s: icmp type %d (%s) code %d\n",
820 cc, inet_ntoa(from->sin_addr),
821 inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
822 for (i = 4; i < cc ; i += sizeof(*lp))
823 printf("%2d: x%8.8x\n", i, *lp++);
831 * Construct an Internet address representation.
832 * If the nflag has been supplied, give
833 * numeric value, otherwise try for symbolic name.
836 inetname(struct sockaddr_in *from)
838 const char *n = NULL;
842 if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
843 if(INET_rresolve(name, sizeof(name), from, 0x4000, 0xffffffff) >= 0)
846 ina = inet_ntoa(from->sin_addr);
850 printf(" %s (%s)", (n ? n : ina), ina);
854 print(u_char *buf, int cc, struct sockaddr_in *from)
859 ip = (struct ip *) buf;
860 hlen = ip->ip_hl << 2;
864 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
866 printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
871 static struct hostinfo *
872 gethostinfo(const char *host)
880 hi = xcalloc(1, sizeof(*hi));
881 addr = inet_addr(host);
882 if ((int32_t)addr != -1) {
883 hi->name = bb_xstrdup(host);
885 hi->addrs = xcalloc(1, sizeof(hi->addrs[0]));
890 hp = xgethostbyname(host);
891 if (hp->h_addrtype != AF_INET || hp->h_length != 4)
892 bb_perror_msg_and_die("bad host %s", host);
893 hi->name = bb_xstrdup(hp->h_name);
894 for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
897 hi->addrs = xcalloc(n, sizeof(hi->addrs[0]));
898 for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
899 memcpy(ap, *p, sizeof(*ap));
904 freehostinfo(struct hostinfo *hi)
906 if (hi->name != NULL) {
910 free((char *)hi->addrs);
914 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
916 getaddr(u_int32_t *ap, const char *host)
920 hi = gethostinfo(host);
928 traceroute_main(int argc, char *argv[])
934 struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom;
935 struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
942 char *tos_str = NULL;
946 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
950 struct IFADDRLIST *al;
954 char *max_ttl_str = NULL;
955 char *port_str = NULL;
957 char *nprobes_str = NULL;
958 char *waittime_str = NULL;
959 u_int pausemsecs = 0;
960 char *pausemsecs_str = NULL;
962 char *first_ttl_str = NULL;
963 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
964 llist_t *sourse_route_list = NULL;
968 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
969 bb_opt_complementally = "x-x:g*";
971 bb_opt_complementally = "x-x";
974 op = bb_getopt_ulflags(argc, argv, "FIlnrdvxt:i:m:p:q:s:w:z:f:"
975 #define USAGE_OP_DONT_FRAGMNT (1<<0) /* F */
976 #define USAGE_OP_USE_ICMP (1<<1) /* I */
977 #define USAGE_OP_TTL_FLAG (1<<2) /* l */
978 #define USAGE_OP_ADDR_NUM (1<<3) /* n */
979 #define USAGE_OP_BYPASS_ROUTE (1<<4) /* r */
980 #define USAGE_OP_DEBUG (1<<5) /* d */
981 #define USAGE_OP_VERBOSE (1<<6) /* v */
982 #define USAGE_OP_IP_CHKSUM (1<<7) /* x */
984 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
987 , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str,
988 &source, &waittime_str, &pausemsecs_str, &first_ttl_str
989 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
994 if(op & USAGE_OP_DONT_FRAGMNT)
996 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
997 useicmp = op & USAGE_OP_USE_ICMP;
999 nflag = op & USAGE_OP_ADDR_NUM;
1000 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
1001 verbose = op & USAGE_OP_VERBOSE;
1003 if(op & USAGE_OP_IP_CHKSUM) {
1005 bb_error_msg("Warning: ip checksums disabled");
1008 tos = str2val(tos_str, "tos", 0, 255);
1010 max_ttl = str2val(max_ttl_str, "max ttl", 1, 255);
1012 port = (u_short)str2val(port_str, "port", 1, (1 << 16) - 1);
1014 nprobes = str2val(optarg, "nprobes", 1, -1);
1017 * set the ip source address of the outbound
1018 * probe (e.g., on a multi-homed host).
1021 bb_error_msg_and_die("-s %s: Permission denied", source);
1024 waittime = str2val(waittime_str, "wait time", 2, 24 * 60 * 60);
1026 pausemsecs = str2val(pausemsecs_str, "pause msecs", 0, 60 * 60 * 1000);
1028 first_ttl = str2val(first_ttl_str, "first ttl", 1, 255);
1030 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
1031 if(sourse_route_list) {
1034 for(l_sr = sourse_route_list; l_sr; ) {
1035 if (lsrr >= NGATEWAYS)
1036 bb_error_msg_and_die("No more than %d gateways", NGATEWAYS);
1037 getaddr(gwlist + lsrr, l_sr->data);
1040 free(sourse_route_list);
1041 sourse_route_list = l_sr;
1043 optlen = (lsrr + 1) * sizeof(gwlist[0]);
1047 if (first_ttl > max_ttl) {
1048 bb_error_msg_and_die(
1049 "first ttl (%d) may not be greater than max ttl (%d)",
1050 first_ttl, max_ttl);
1053 minpacket = sizeof(*outip) + sizeof(*outdata) + optlen;
1055 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
1057 minpacket += 8; /* XXX magic number */
1060 minpacket += sizeof(*outudp);
1061 packlen = minpacket; /* minimum sized packet */
1063 /* Process destination and optional packet size */
1064 switch (argc - optind) {
1067 packlen = str2val(argv[optind + 1],
1068 "packet length", minpacket, maxpacket);
1072 hostname = argv[optind];
1073 hi = gethostinfo(hostname);
1074 setsin(to, hi->addrs[0]);
1077 "Warning: %s has multiple addresses; using %s",
1078 hostname, inet_ntoa(to->sin_addr));
1079 hostname = hi->name;
1089 if ((pe = getprotobyname(cp)) == NULL)
1090 bb_perror_msg_and_die("unknown protocol %s", cp);
1092 /* Insure the socket fds won't be 0, 1 or 2 */
1093 do n = bb_xopen(devnull, O_RDONLY); while (n < 2);
1097 if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
1098 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
1100 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
1101 if (op & USAGE_OP_DEBUG)
1102 (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
1105 if (op & USAGE_OP_BYPASS_ROUTE)
1106 (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
1109 sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
1111 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
1113 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
1114 #if defined(IP_OPTIONS)
1116 u_char optlist[MAX_IPOPTLEN];
1119 if ((pe = getprotobyname(cp)) == NULL)
1120 bb_perror_msg_and_die("unknown protocol");
1123 gwlist[lsrr] = to->sin_addr.s_addr;
1126 /* force 4 byte alignment */
1127 optlist[0] = IPOPT_NOP;
1128 /* loose source route option */
1129 optlist[1] = IPOPT_LSRR;
1130 i = lsrr * sizeof(gwlist[0]);
1132 /* Pointer to LSRR addresses */
1133 optlist[3] = IPOPT_MINOFF;
1134 memcpy(optlist + 4, gwlist, i);
1136 if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS,
1137 (char *)optlist, i + sizeof(gwlist[0]))) < 0) {
1138 bb_perror_msg_and_die("IP_OPTIONS");
1141 #endif /* IP_OPTIONS */
1142 #endif /* CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE */
1145 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
1146 sizeof(packlen)) < 0) {
1147 bb_perror_msg_and_die("SO_SNDBUF");
1151 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
1152 sizeof(on)) < 0 && errno != ENOPROTOOPT) {
1153 bb_perror_msg_and_die("IP_HDRINCL");
1157 if (tos_str && setsockopt(sndsock, IPPROTO_IP, IP_TOS,
1158 (char *)&tos, sizeof(tos)) < 0) {
1159 bb_perror_msg_and_die("setsockopt tos %d", tos);
1163 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
1164 if (op & USAGE_OP_DEBUG)
1165 (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
1168 if (op & USAGE_OP_BYPASS_ROUTE)
1169 (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
1172 /* Revert to non-privileged user after opening sockets */
1176 outip = (struct ip *)xcalloc(1, (unsigned)packlen);
1178 outip->ip_v = IPVERSION;
1180 outip->ip_tos = tos;
1181 outip->ip_len = htons(packlen);
1182 outip->ip_off = htons(off);
1183 outp = (u_char *)(outip + 1);
1184 outip->ip_dst = to->sin_addr;
1186 outip->ip_hl = (outp - (u_char *)outip) >> 2;
1187 ident = (getpid() & 0xffff) | 0x8000;
1188 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
1190 outip->ip_p = IPPROTO_ICMP;
1192 outicmp = (struct icmp *)outp;
1193 outicmp->icmp_type = ICMP_ECHO;
1194 outicmp->icmp_id = htons(ident);
1196 outdata = (struct outdata *)(outp + 8); /* XXX magic number */
1200 outip->ip_p = IPPROTO_UDP;
1202 outudp = (struct udphdr *)outp;
1203 outudp->source = htons(ident);
1205 htons((u_short)(packlen - (sizeof(*outip) + optlen)));
1206 outdata = (struct outdata *)(outudp + 1);
1209 /* Get the interface address list */
1210 n = ifaddrlist(&al);
1212 /* Look for a specific device */
1213 if (device != NULL) {
1214 for (i = n; i > 0; --i, ++al)
1215 if (strcmp(device, al->device) == 0)
1218 bb_error_msg_and_die("Can't find interface %s", device);
1222 /* Determine our source address */
1223 if (source == NULL) {
1225 * If a device was specified, use the interface address.
1226 * Otherwise, try to determine our source address.
1229 setsin(from, al->addr);
1230 findsaddr(to, from);
1232 hi = gethostinfo(source);
1236 * If the device was specified make sure it
1237 * corresponds to the source address specified.
1238 * Otherwise, use the first address (and warn if
1239 * there are more than one).
1241 if (device != NULL) {
1242 for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
1243 if (*ap == al->addr)
1246 bb_error_msg_and_die(
1247 "%s is not on interface %s",
1252 setsin(from, hi->addrs[0]);
1255 "Warning: %s has multiple addresses; using %s",
1256 source, inet_ntoa(from->sin_addr));
1261 outip->ip_src = from->sin_addr;
1263 if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) {
1264 bb_perror_msg_and_die("bind");
1268 fprintf(stderr, "traceroute to %s (%s)", hostname, inet_ntoa(to->sin_addr));
1270 fprintf(stderr, " from %s", source);
1271 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
1272 (void)fflush(stderr);
1274 for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
1275 u_int32_t lastaddr = 0;
1276 int gotlastaddr = 0;
1278 int unreachable = 0;
1281 printf("%2d ", ttl);
1282 for (probe = 0; probe < nprobes; ++probe) {
1284 struct timeval t1, t2;
1288 if (sentfirst && pausemsecs > 0)
1289 usleep(pausemsecs * 1000);
1290 (void)gettimeofday(&t1, &tz);
1291 send_probe(++seq, ttl, &t1);
1293 while ((cc = wait_for_reply(s, from, &t1)) != 0) {
1294 (void)gettimeofday(&t2, &tz);
1295 i = packet_ok(packet, cc, from, seq);
1296 /* Skip short packet */
1300 from->sin_addr.s_addr != lastaddr) {
1301 print(packet, cc, from);
1302 lastaddr = from->sin_addr.s_addr;
1305 printf(" %.3f ms", deltaT(&t1, &t2));
1306 ip = (struct ip *)packet;
1307 if (op & USAGE_OP_TTL_FLAG)
1308 printf(" (%d)", ip->ip_ttl);
1310 if (ip->ip_ttl <= 1)
1315 /* time exceeded in transit */
1321 case ICMP_UNREACH_PORT:
1322 if (ip->ip_ttl <= 1)
1327 case ICMP_UNREACH_NET:
1332 case ICMP_UNREACH_HOST:
1337 case ICMP_UNREACH_PROTOCOL:
1342 case ICMP_UNREACH_NEEDFRAG:
1344 printf(" !F-%d", pmtu);
1347 case ICMP_UNREACH_SRCFAIL:
1352 case ICMP_UNREACH_FILTER_PROHIB:
1353 case ICMP_UNREACH_NET_PROHIB: /* misuse */
1358 case ICMP_UNREACH_HOST_PROHIB:
1363 case ICMP_UNREACH_HOST_PRECEDENCE:
1368 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1373 case ICMP_UNREACH_NET_UNKNOWN:
1374 case ICMP_UNREACH_HOST_UNKNOWN:
1379 case ICMP_UNREACH_ISOLATED:
1384 case ICMP_UNREACH_TOSNET:
1385 case ICMP_UNREACH_TOSHOST:
1392 printf(" !<%d>", code);
1399 (void)fflush(stdout);
1403 (unreachable > 0 && unreachable >= nprobes - 1))