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;
325 static u_short ident;
326 static u_short port = 32768 + 666; /* start udp dest port # for probe packets */
328 static int waittime = 5; /* time to wait for response (in seconds) */
329 static int nflag; /* print addresses numerically */
330 static int doipcksum = 1; /* calculate ip checksums by default */
332 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
333 static int optlen; /* length of ip options */
338 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
339 static int useicmp; /* use icmp echo instead of udp packets */
341 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
346 * Return the interface list
349 ifaddrlist(struct IFADDRLIST **ipaddrp)
352 #ifdef HAVE_SOCKADDR_SA_LEN
355 struct ifreq *ifrp, *ifend, *ifnext;
356 struct sockaddr_in *addr_sin;
357 struct IFADDRLIST *al;
359 struct ifreq ibuf[(32 * 1024) / sizeof(struct ifreq)], ifr;
360 struct IFADDRLIST *st_ifaddrlist;
362 fd = socket(AF_INET, SOCK_DGRAM, 0);
364 bb_perror_msg_and_die("socket");
366 ifc.ifc_len = sizeof(ibuf);
367 ifc.ifc_buf = (caddr_t)ibuf;
369 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
370 ifc.ifc_len < sizeof(struct ifreq)) {
372 bb_error_msg_and_die(
373 "SIOCGIFCONF: ifreq struct too small (%d bytes)",
376 bb_perror_msg_and_die("SIOCGIFCONF");
379 ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
381 nipaddr = 1 + (ifc.ifc_len / sizeof(struct ifreq));
382 st_ifaddrlist = xcalloc(nipaddr, sizeof(struct IFADDRLIST));
386 for (; ifrp < ifend; ifrp = ifnext) {
387 #ifdef HAVE_SOCKADDR_SA_LEN
388 n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
389 if (n < sizeof(*ifrp))
392 ifnext = (struct ifreq *)((char *)ifrp + n);
393 if (ifrp->ifr_addr.sa_family != AF_INET)
399 * Need a template to preserve address info that is
400 * used below to locate the next entry. (Otherwise,
401 * SIOCGIFFLAGS stomps over it because the requests
402 * are returned in a union.)
404 strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));
405 if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
408 bb_perror_msg_and_die("SIOCGIFFLAGS: %.*s",
409 (int)sizeof(ifr.ifr_name), ifr.ifr_name);
413 if ((ifr.ifr_flags & IFF_UP) == 0)
416 safe_strncpy(al->device, ifr.ifr_name, sizeof(ifr.ifr_name) + 1);
418 /* Ignore sun virtual interfaces */
419 if (strchr(al->device, ':') != NULL)
422 if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0)
423 bb_perror_msg_and_die("SIOCGIFADDR: %s", al->device);
425 addr_sin = (struct sockaddr_in *)&ifr.ifr_addr;
426 al->addr = addr_sin->sin_addr.s_addr;
431 bb_error_msg_and_die ("Can't find any network interfaces");
434 *ipaddrp = st_ifaddrlist;
440 setsin(struct sockaddr_in *addr_sin, u_int32_t addr)
442 memset(addr_sin, 0, sizeof(*addr_sin));
443 #ifdef HAVE_SOCKADDR_SA_LEN
444 addr_sin->sin_len = sizeof(*addr_sin);
446 addr_sin->sin_family = AF_INET;
447 addr_sin->sin_addr.s_addr = addr;
452 * Return the source address for the given destination address
455 findsaddr(const struct sockaddr_in *to, struct sockaddr_in *from)
460 u_int32_t dest, tmask;
461 struct IFADDRLIST *al;
462 char buf[256], tdevice[256], device[256];
464 f = bb_xfopen(route, "r");
466 /* Find the appropriate interface */
470 while (fgets(buf, sizeof(buf), f) != NULL) {
472 if (n == 1 && strncmp(buf, "Iface", 5) == 0)
474 if ((i = sscanf(buf, "%255s %x %*s %*s %*s %*s %*s %x",
475 tdevice, &dest, &tmask)) != 3)
476 bb_error_msg_and_die ("junk in buffer");
477 if ((to->sin_addr.s_addr & tmask) == dest &&
478 (tmask > mask || mask == 0)) {
480 strcpy(device, tdevice);
485 if (device[0] == '\0')
486 bb_error_msg_and_die ("Can't find interface");
488 /* Get the interface address list */
491 /* Find our appropriate source address */
492 for (i = n; i > 0; --i, ++al)
493 if (strcmp(device, al->device) == 0)
496 bb_error_msg_and_die("Can't find interface %s", device);
498 setsin(from, al->addr);
502 "Usage: %s [-dFIlnrvx] [-g gateway] [-i iface] [-f first_ttl]\n"
503 "\t[-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos]\n"
504 "\t[-w waittime] [-z pausemsecs] host [packetlen]"
508 /* String to value with optional min and max. Handles decimal and hex. */
510 str2val(const char *str, const char *what, int mi, int ma)
516 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
518 val = (int)strtol(cp, &ep, 16);
520 val = (int)strtol(str, &ep, 10);
522 bb_error_msg_and_die("\"%s\" bad value for %s \n", str, what);
524 if (val < mi && mi >= 0) {
526 bb_error_msg_and_die("%s must be >= %d\n", what, mi);
528 bb_error_msg_and_die("%s must be > %d\n", what, mi - 1);
530 if (val > ma && ma >= 0)
531 bb_error_msg_and_die("%s must be <= %d\n", what, ma);
537 * Subtract 2 timeval structs: out = out - in.
538 * Out is assumed to be >= in.
541 tvsub(struct timeval *out, struct timeval *in)
544 if ((out->tv_usec -= in->tv_usec) < 0) {
546 out->tv_usec += 1000000;
548 out->tv_sec -= in->tv_sec;
552 wait_for_reply(int sock, struct sockaddr_in *fromp, const struct timeval *tp)
555 struct timeval now, wait;
558 socklen_t fromlen = sizeof(*fromp);
563 wait.tv_sec = tp->tv_sec + waittime;
564 wait.tv_usec = tp->tv_usec;
565 (void)gettimeofday(&now, &tz);
568 if (select(sock + 1, &fds, NULL, NULL, &wait) > 0)
569 cc = recvfrom(sock, (char *)packet, sizeof(packet), 0,
570 (struct sockaddr *)fromp, &fromlen);
576 * Checksum routine for Internet Protocol family headers (C Version)
579 in_cksum(u_short *addr, int len)
587 * Our algorithm is simple, using a 32 bit accumulator (sum),
588 * we add sequential 16 bit words to it, and at the end, fold
589 * back all the carry bits from the top 16 bits into the lower
597 /* mop up an odd byte, if necessary */
602 * add back carry outs from top 16 bits to low 16 bits
604 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
605 sum += (sum >> 16); /* add carry */
606 answer = ~sum; /* truncate to 16 bits */
612 send_probe(int seq, int ttl, struct timeval *tp)
615 struct udpiphdr *ui, *oui;
619 outip->ip_id = htons(ident + seq);
622 * In most cases, the kernel will recalculate the ip checksum.
623 * But we must do it anyway so that the udp checksum comes out
628 in_cksum((u_short *)outip, sizeof(*outip) + optlen);
629 if (outip->ip_sum == 0)
630 outip->ip_sum = 0xffff;
636 memcpy(&outdata->tv, tp, sizeof(outdata->tv));
638 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
640 outicmp->icmp_seq = htons(seq);
643 outudp->dest = htons(port + seq);
645 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
647 /* Always calculate checksum for icmp packets */
648 outicmp->icmp_cksum = 0;
649 outicmp->icmp_cksum = in_cksum((u_short *)outicmp,
650 packlen - (sizeof(*outip) + optlen));
651 if (outicmp->icmp_cksum == 0)
652 outicmp->icmp_cksum = 0xffff;
656 /* Checksum (we must save and restore ip header) */
658 ui = (struct udpiphdr *)outip;
659 oui = (struct udpiphdr *)&tip;
660 /* Easier to zero and put back things that are ok */
661 memset((char *)ui, 0, sizeof(ui->ui_i));
662 ui->ui_src = oui->ui_src;
663 ui->ui_dst = oui->ui_dst;
664 ui->ui_pr = oui->ui_pr;
665 ui->ui_len = outudp->len;
667 outudp->check = in_cksum((u_short *)ui, packlen);
668 if (outudp->check == 0)
669 outudp->check = 0xffff;
673 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
674 /* XXX undocumented debugging hack */
679 sp = (u_short *)outip;
680 nshorts = (u_int)packlen / sizeof(u_short);
682 printf("[ %d bytes", packlen);
683 while (--nshorts >= 0) {
686 printf(" %04x", ntohs(*sp));
692 printf(" %02x", *(u_char *)sp);
698 #if !defined(IP_HDRINCL) && defined(IP_TTL)
699 if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
700 (char *)&ttl, sizeof(ttl)) < 0) {
701 bb_perror_msg_and_die("setsockopt ttl %d", ttl);
705 cc = sendto(sndsock, (char *)outip,
706 packlen, 0, (struct sockaddr *)&whereto, sizeof(whereto));
707 if (cc < 0 || cc != packlen) {
709 bb_perror_msg_and_die("sendto");
710 printf("%s: wrote %s %d chars, ret=%d\n",
711 bb_applet_name, hostname, packlen, cc);
712 (void)fflush(stdout);
717 deltaT(struct timeval *t1p, struct timeval *t2p)
721 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
722 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
726 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
728 * Convert an ICMP "type" field to a printable string.
730 static inline const char *
733 static const char * const ttab[] = {
734 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
735 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
736 "Echo", "Router Advert", "Router Solicit", "Time Exceeded",
737 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
738 "Info Reply", "Mask Request", "Mask Reply"
742 return "OUT-OF-RANGE";
749 packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
756 ip = (struct ip *) buf;
757 hlen = ip->ip_hl << 2;
758 if (cc < hlen + ICMP_MINLEN) {
759 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
761 printf("packet too short (%d bytes) from %s\n", cc,
762 inet_ntoa(from->sin_addr));
767 icp = (struct icmp *)(buf + hlen);
768 type = icp->icmp_type;
769 code = icp->icmp_code;
770 /* Path MTU Discovery (RFC1191) */
771 if (code != ICMP_UNREACH_NEEDFRAG)
774 pmtu = ntohs(icp->icmp_nextmtu);
776 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
777 type == ICMP_UNREACH || type == ICMP_ECHOREPLY) {
782 hlen = hip->ip_hl << 2;
783 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
788 if (type == ICMP_ECHOREPLY &&
789 icp->icmp_id == htons(ident) &&
790 icp->icmp_seq == htons(seq))
793 hicmp = (struct icmp *)((u_char *)hip + hlen);
794 /* XXX 8 is a magic number */
795 if (hlen + 8 <= cc &&
796 hip->ip_p == IPPROTO_ICMP &&
797 hicmp->icmp_id == htons(ident) &&
798 hicmp->icmp_seq == htons(seq))
799 return (type == ICMP_TIMXCEED ? -1 : code + 1);
803 up = (struct udphdr *)((u_char *)hip + hlen);
804 /* XXX 8 is a magic number */
805 if (hlen + 12 <= cc &&
806 hip->ip_p == IPPROTO_UDP &&
807 up->source == htons(ident) &&
808 up->dest == htons(port + seq))
809 return (type == ICMP_TIMXCEED ? -1 : code + 1);
812 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
815 u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
817 printf("\n%d bytes from %s to "
818 "%s: icmp type %d (%s) code %d\n",
819 cc, inet_ntoa(from->sin_addr),
820 inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
821 for (i = 4; i < cc ; i += sizeof(*lp))
822 printf("%2d: x%8.8x\n", i, *lp++);
830 * Construct an Internet address representation.
831 * If the nflag has been supplied, give
832 * numeric value, otherwise try for symbolic name.
835 inetname(struct sockaddr_in *from)
837 const char *n = NULL;
841 if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
842 if(INET_rresolve(name, sizeof(name), from, 0x4000, 0xffffffff) >= 0)
845 ina = inet_ntoa(from->sin_addr);
849 printf(" %s (%s)", (n ? n : ina), ina);
853 print(u_char *buf, int cc, struct sockaddr_in *from)
858 ip = (struct ip *) buf;
859 hlen = ip->ip_hl << 2;
863 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
865 printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
870 static struct hostinfo *
871 gethostinfo(const char *host)
879 hi = xcalloc(1, sizeof(*hi));
880 addr = inet_addr(host);
881 if ((int32_t)addr != -1) {
882 hi->name = bb_xstrdup(host);
884 hi->addrs = xcalloc(1, sizeof(hi->addrs[0]));
889 hp = xgethostbyname(host);
890 if (hp->h_addrtype != AF_INET || hp->h_length != 4)
891 bb_perror_msg_and_die("bad host %s", host);
892 hi->name = bb_xstrdup(hp->h_name);
893 for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
896 hi->addrs = xcalloc(n, sizeof(hi->addrs[0]));
897 for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
898 memcpy(ap, *p, sizeof(*ap));
903 freehostinfo(struct hostinfo *hi)
905 if (hi->name != NULL) {
909 free((char *)hi->addrs);
913 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
915 getaddr(u_int32_t *ap, const char *host)
919 hi = gethostinfo(host);
927 traceroute_main(int argc, char *argv[])
933 struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom;
934 struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
941 char *tos_str = NULL;
945 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
949 struct IFADDRLIST *al;
953 char *max_ttl_str = NULL;
954 char *port_str = NULL;
956 char *nprobes_str = NULL;
957 char *waittime_str = NULL;
958 u_int pausemsecs = 0;
959 char *pausemsecs_str = NULL;
961 char *first_ttl_str = NULL;
962 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
963 llist_t *sourse_route_list = NULL;
967 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
968 bb_opt_complementally = "x-x:g::";
970 bb_opt_complementally = "x-x";
973 op = bb_getopt_ulflags(argc, argv, "FIlnrdvxt:i:m:p:q:s:w:z:f:"
974 #define USAGE_OP_DONT_FRAGMNT (1<<0) /* F */
975 #define USAGE_OP_USE_ICMP (1<<1) /* I */
976 #define USAGE_OP_TTL_FLAG (1<<2) /* l */
977 #define USAGE_OP_ADDR_NUM (1<<3) /* n */
978 #define USAGE_OP_BYPASS_ROUTE (1<<4) /* r */
979 #define USAGE_OP_DEBUG (1<<5) /* d */
980 #define USAGE_OP_VERBOSE (1<<6) /* v */
981 #define USAGE_OP_IP_CHKSUM (1<<7) /* x */
983 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
986 , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str,
987 &source, &waittime_str, &pausemsecs_str, &first_ttl_str
988 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
993 if(op & USAGE_OP_DONT_FRAGMNT)
995 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
996 useicmp = op & USAGE_OP_USE_ICMP;
998 nflag = op & USAGE_OP_ADDR_NUM;
999 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
1000 verbose = op & USAGE_OP_VERBOSE;
1002 if(op & USAGE_OP_IP_CHKSUM) {
1004 bb_error_msg("Warning: ip checksums disabled");
1007 tos = str2val(tos_str, "tos", 0, 255);
1009 max_ttl = str2val(max_ttl_str, "max ttl", 1, 255);
1011 port = (u_short)str2val(port_str, "port", 1, (1 << 16) - 1);
1013 nprobes = str2val(optarg, "nprobes", 1, -1);
1016 * set the ip source address of the outbound
1017 * probe (e.g., on a multi-homed host).
1020 bb_error_msg_and_die("-s %s: Permission denied", source);
1023 waittime = str2val(waittime_str, "wait time", 2, 24 * 60 * 60);
1025 pausemsecs = str2val(pausemsecs_str, "pause msecs", 0, 60 * 60 * 1000);
1027 first_ttl = str2val(first_ttl_str, "first ttl", 1, 255);
1029 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
1030 if(sourse_route_list) {
1033 for(l_sr = sourse_route_list; l_sr; ) {
1034 if (lsrr >= NGATEWAYS)
1035 bb_error_msg_and_die("No more than %d gateways", NGATEWAYS);
1036 getaddr(gwlist + lsrr, l_sr->data);
1039 free(sourse_route_list);
1040 sourse_route_list = l_sr;
1042 optlen = (lsrr + 1) * sizeof(gwlist[0]);
1046 if (first_ttl > max_ttl) {
1047 bb_error_msg_and_die(
1048 "first ttl (%d) may not be greater than max ttl (%d)",
1049 first_ttl, max_ttl);
1052 minpacket = sizeof(*outip) + sizeof(*outdata) + optlen;
1054 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
1056 minpacket += 8; /* XXX magic number */
1059 minpacket += sizeof(*outudp);
1060 packlen = minpacket; /* minimum sized packet */
1062 /* Process destination and optional packet size */
1063 switch (argc - optind) {
1066 packlen = str2val(argv[optind + 1],
1067 "packet length", minpacket, maxpacket);
1071 hostname = argv[optind];
1072 hi = gethostinfo(hostname);
1073 setsin(to, hi->addrs[0]);
1076 "Warning: %s has multiple addresses; using %s",
1077 hostname, inet_ntoa(to->sin_addr));
1078 hostname = hi->name;
1088 if ((pe = getprotobyname(cp)) == NULL)
1089 bb_perror_msg_and_die("unknown protocol %s", cp);
1091 /* Insure the socket fds won't be 0, 1 or 2 */
1092 do n = bb_xopen(bb_dev_null, O_RDONLY); while (n < 2);
1096 if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
1097 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
1099 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
1100 if (op & USAGE_OP_DEBUG)
1101 (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
1104 if (op & USAGE_OP_BYPASS_ROUTE)
1105 (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
1108 sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
1110 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
1112 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
1113 #if defined(IP_OPTIONS)
1115 u_char optlist[MAX_IPOPTLEN];
1118 if ((pe = getprotobyname(cp)) == NULL)
1119 bb_perror_msg_and_die("unknown protocol");
1122 gwlist[lsrr] = to->sin_addr.s_addr;
1125 /* force 4 byte alignment */
1126 optlist[0] = IPOPT_NOP;
1127 /* loose source route option */
1128 optlist[1] = IPOPT_LSRR;
1129 i = lsrr * sizeof(gwlist[0]);
1131 /* Pointer to LSRR addresses */
1132 optlist[3] = IPOPT_MINOFF;
1133 memcpy(optlist + 4, gwlist, i);
1135 if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS,
1136 (char *)optlist, i + sizeof(gwlist[0]))) < 0) {
1137 bb_perror_msg_and_die("IP_OPTIONS");
1140 #endif /* IP_OPTIONS */
1141 #endif /* CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE */
1144 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
1145 sizeof(packlen)) < 0) {
1146 bb_perror_msg_and_die("SO_SNDBUF");
1150 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
1151 sizeof(on)) < 0 && errno != ENOPROTOOPT) {
1152 bb_perror_msg_and_die("IP_HDRINCL");
1156 if (tos_str && setsockopt(sndsock, IPPROTO_IP, IP_TOS,
1157 (char *)&tos, sizeof(tos)) < 0) {
1158 bb_perror_msg_and_die("setsockopt tos %d", tos);
1162 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
1163 if (op & USAGE_OP_DEBUG)
1164 (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
1167 if (op & USAGE_OP_BYPASS_ROUTE)
1168 (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
1171 /* Revert to non-privileged user after opening sockets */
1175 outip = (struct ip *)xcalloc(1, (unsigned)packlen);
1177 outip->ip_v = IPVERSION;
1179 outip->ip_tos = tos;
1180 outip->ip_len = htons(packlen);
1181 outip->ip_off = htons(off);
1182 outp = (u_char *)(outip + 1);
1183 outip->ip_dst = to->sin_addr;
1185 outip->ip_hl = (outp - (u_char *)outip) >> 2;
1186 ident = (getpid() & 0xffff) | 0x8000;
1187 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
1189 outip->ip_p = IPPROTO_ICMP;
1191 outicmp = (struct icmp *)outp;
1192 outicmp->icmp_type = ICMP_ECHO;
1193 outicmp->icmp_id = htons(ident);
1195 outdata = (struct outdata *)(outp + 8); /* XXX magic number */
1199 outip->ip_p = IPPROTO_UDP;
1201 outudp = (struct udphdr *)outp;
1202 outudp->source = htons(ident);
1204 htons((u_short)(packlen - (sizeof(*outip) + optlen)));
1205 outdata = (struct outdata *)(outudp + 1);
1208 /* Get the interface address list */
1209 n = ifaddrlist(&al);
1211 /* Look for a specific device */
1212 if (device != NULL) {
1213 for (i = n; i > 0; --i, ++al)
1214 if (strcmp(device, al->device) == 0)
1217 bb_error_msg_and_die("Can't find interface %s", device);
1221 /* Determine our source address */
1222 if (source == NULL) {
1224 * If a device was specified, use the interface address.
1225 * Otherwise, try to determine our source address.
1228 setsin(from, al->addr);
1229 findsaddr(to, from);
1231 hi = gethostinfo(source);
1235 * If the device was specified make sure it
1236 * corresponds to the source address specified.
1237 * Otherwise, use the first address (and warn if
1238 * there are more than one).
1240 if (device != NULL) {
1241 for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
1242 if (*ap == al->addr)
1245 bb_error_msg_and_die(
1246 "%s is not on interface %s",
1251 setsin(from, hi->addrs[0]);
1254 "Warning: %s has multiple addresses; using %s",
1255 source, inet_ntoa(from->sin_addr));
1260 outip->ip_src = from->sin_addr;
1262 if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) {
1263 bb_perror_msg_and_die("bind");
1267 fprintf(stderr, "traceroute to %s (%s)", hostname, inet_ntoa(to->sin_addr));
1269 fprintf(stderr, " from %s", source);
1270 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
1271 (void)fflush(stderr);
1273 for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
1274 u_int32_t lastaddr = 0;
1275 int gotlastaddr = 0;
1277 int unreachable = 0;
1280 printf("%2d ", ttl);
1281 for (probe = 0; probe < nprobes; ++probe) {
1283 struct timeval t1, t2;
1287 if (sentfirst && pausemsecs > 0)
1288 usleep(pausemsecs * 1000);
1289 (void)gettimeofday(&t1, &tz);
1290 send_probe(++seq, ttl, &t1);
1292 while ((cc = wait_for_reply(s, from, &t1)) != 0) {
1293 (void)gettimeofday(&t2, &tz);
1294 i = packet_ok(packet, cc, from, seq);
1295 /* Skip short packet */
1299 from->sin_addr.s_addr != lastaddr) {
1300 print(packet, cc, from);
1301 lastaddr = from->sin_addr.s_addr;
1304 printf(" %.3f ms", deltaT(&t1, &t2));
1305 ip = (struct ip *)packet;
1306 if (op & USAGE_OP_TTL_FLAG)
1307 printf(" (%d)", ip->ip_ttl);
1309 if (ip->ip_ttl <= 1)
1314 /* time exceeded in transit */
1320 case ICMP_UNREACH_PORT:
1321 if (ip->ip_ttl <= 1)
1326 case ICMP_UNREACH_NET:
1331 case ICMP_UNREACH_HOST:
1336 case ICMP_UNREACH_PROTOCOL:
1341 case ICMP_UNREACH_NEEDFRAG:
1343 printf(" !F-%d", pmtu);
1346 case ICMP_UNREACH_SRCFAIL:
1351 case ICMP_UNREACH_FILTER_PROHIB:
1352 case ICMP_UNREACH_NET_PROHIB: /* misuse */
1357 case ICMP_UNREACH_HOST_PROHIB:
1362 case ICMP_UNREACH_HOST_PRECEDENCE:
1367 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1372 case ICMP_UNREACH_NET_UNKNOWN:
1373 case ICMP_UNREACH_HOST_UNKNOWN:
1378 case ICMP_UNREACH_ISOLATED:
1383 case ICMP_UNREACH_TOSNET:
1384 case ICMP_UNREACH_TOSHOST:
1391 printf(" !<%d>", code);
1398 (void)fflush(stdout);
1402 (unreachable > 0 && unreachable >= nprobes - 1))