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 unsigned char ih_x1[9]; /* (unused) */
247 unsigned 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 unsigned char seq; /* sequence number of this packet */
283 unsigned 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 unsigned char packet[512] ATTRIBUTE_ALIGNED(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 */
599 sum += *(unsigned char *)w;
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", *(unsigned 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 *
731 pr_type(unsigned char t)
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(unsigned char *buf, int cc, struct sockaddr_in *from, int seq)
752 unsigned char type, code;
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 *)((unsigned 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 *)((unsigned 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(unsigned 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)
907 free((char *)hi->addrs);
911 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
913 getaddr(u_int32_t *ap, const char *host)
917 hi = gethostinfo(host);
925 traceroute_main(int argc, char *argv[])
931 struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom;
932 struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
939 char *tos_str = NULL;
943 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
947 struct IFADDRLIST *al;
951 char *max_ttl_str = NULL;
952 char *port_str = NULL;
954 char *nprobes_str = NULL;
955 char *waittime_str = NULL;
956 u_int pausemsecs = 0;
957 char *pausemsecs_str = NULL;
959 char *first_ttl_str = NULL;
960 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
961 llist_t *sourse_route_list = NULL;
965 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
966 bb_opt_complementally = "x-x:g::";
968 bb_opt_complementally = "x-x";
971 op = bb_getopt_ulflags(argc, argv, "FIlnrdvxt:i:m:p:q:s:w:z:f:"
972 #define USAGE_OP_DONT_FRAGMNT (1<<0) /* F */
973 #define USAGE_OP_USE_ICMP (1<<1) /* I */
974 #define USAGE_OP_TTL_FLAG (1<<2) /* l */
975 #define USAGE_OP_ADDR_NUM (1<<3) /* n */
976 #define USAGE_OP_BYPASS_ROUTE (1<<4) /* r */
977 #define USAGE_OP_DEBUG (1<<5) /* d */
978 #define USAGE_OP_VERBOSE (1<<6) /* v */
979 #define USAGE_OP_IP_CHKSUM (1<<7) /* x */
981 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
984 , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str,
985 &source, &waittime_str, &pausemsecs_str, &first_ttl_str
986 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
991 if(op & USAGE_OP_DONT_FRAGMNT)
993 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
994 useicmp = op & USAGE_OP_USE_ICMP;
996 nflag = op & USAGE_OP_ADDR_NUM;
997 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
998 verbose = op & USAGE_OP_VERBOSE;
1000 if(op & USAGE_OP_IP_CHKSUM) {
1002 bb_error_msg("Warning: ip checksums disabled");
1005 tos = str2val(tos_str, "tos", 0, 255);
1007 max_ttl = str2val(max_ttl_str, "max ttl", 1, 255);
1009 port = (u_short)str2val(port_str, "port", 1, (1 << 16) - 1);
1011 nprobes = str2val(optarg, "nprobes", 1, -1);
1014 * set the ip source address of the outbound
1015 * probe (e.g., on a multi-homed host).
1018 bb_error_msg_and_die("-s %s: Permission denied", source);
1021 waittime = str2val(waittime_str, "wait time", 2, 24 * 60 * 60);
1023 pausemsecs = str2val(pausemsecs_str, "pause msecs", 0, 60 * 60 * 1000);
1025 first_ttl = str2val(first_ttl_str, "first ttl", 1, 255);
1027 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
1028 if(sourse_route_list) {
1031 for(l_sr = sourse_route_list; l_sr; ) {
1032 if (lsrr >= NGATEWAYS)
1033 bb_error_msg_and_die("No more than %d gateways", NGATEWAYS);
1034 getaddr(gwlist + lsrr, l_sr->data);
1037 free(sourse_route_list);
1038 sourse_route_list = l_sr;
1040 optlen = (lsrr + 1) * sizeof(gwlist[0]);
1044 if (first_ttl > max_ttl) {
1045 bb_error_msg_and_die(
1046 "first ttl (%d) may not be greater than max ttl (%d)",
1047 first_ttl, max_ttl);
1050 minpacket = sizeof(*outip) + sizeof(*outdata) + optlen;
1052 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
1054 minpacket += 8; /* XXX magic number */
1057 minpacket += sizeof(*outudp);
1058 packlen = minpacket; /* minimum sized packet */
1060 /* Process destination and optional packet size */
1061 switch (argc - optind) {
1064 packlen = str2val(argv[optind + 1],
1065 "packet length", minpacket, maxpacket);
1069 hostname = argv[optind];
1070 hi = gethostinfo(hostname);
1071 setsin(to, hi->addrs[0]);
1074 "Warning: %s has multiple addresses; using %s",
1075 hostname, inet_ntoa(to->sin_addr));
1076 hostname = hi->name;
1086 if ((pe = getprotobyname(cp)) == NULL)
1087 bb_perror_msg_and_die("unknown protocol %s", cp);
1089 /* Insure the socket fds won't be 0, 1 or 2 */
1090 do n = bb_xopen(bb_dev_null, O_RDONLY); while (n < 2);
1094 if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
1095 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
1097 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
1098 if (op & USAGE_OP_DEBUG)
1099 (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
1102 if (op & USAGE_OP_BYPASS_ROUTE)
1103 (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
1106 sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
1108 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
1110 #ifdef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
1111 #if defined(IP_OPTIONS)
1113 unsigned char optlist[MAX_IPOPTLEN];
1116 if ((pe = getprotobyname(cp)) == NULL)
1117 bb_perror_msg_and_die("unknown protocol");
1120 gwlist[lsrr] = to->sin_addr.s_addr;
1123 /* force 4 byte alignment */
1124 optlist[0] = IPOPT_NOP;
1125 /* loose source route option */
1126 optlist[1] = IPOPT_LSRR;
1127 i = lsrr * sizeof(gwlist[0]);
1129 /* Pointer to LSRR addresses */
1130 optlist[3] = IPOPT_MINOFF;
1131 memcpy(optlist + 4, gwlist, i);
1133 if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS,
1134 (char *)optlist, i + sizeof(gwlist[0]))) < 0) {
1135 bb_perror_msg_and_die("IP_OPTIONS");
1138 #endif /* IP_OPTIONS */
1139 #endif /* CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE */
1142 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
1143 sizeof(packlen)) < 0) {
1144 bb_perror_msg_and_die("SO_SNDBUF");
1148 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
1149 sizeof(on)) < 0 && errno != ENOPROTOOPT) {
1150 bb_perror_msg_and_die("IP_HDRINCL");
1154 if (tos_str && setsockopt(sndsock, IPPROTO_IP, IP_TOS,
1155 (char *)&tos, sizeof(tos)) < 0) {
1156 bb_perror_msg_and_die("setsockopt tos %d", tos);
1160 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
1161 if (op & USAGE_OP_DEBUG)
1162 (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
1165 if (op & USAGE_OP_BYPASS_ROUTE)
1166 (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
1169 /* Revert to non-privileged user after opening sockets */
1173 outip = (struct ip *)xcalloc(1, (unsigned)packlen);
1175 outip->ip_v = IPVERSION;
1177 outip->ip_tos = tos;
1178 outip->ip_len = htons(packlen);
1179 outip->ip_off = htons(off);
1180 outp = (unsigned char *)(outip + 1);
1181 outip->ip_dst = to->sin_addr;
1183 outip->ip_hl = (outp - (unsigned char *)outip) >> 2;
1184 ident = (getpid() & 0xffff) | 0x8000;
1185 #ifdef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
1187 outip->ip_p = IPPROTO_ICMP;
1189 outicmp = (struct icmp *)outp;
1190 outicmp->icmp_type = ICMP_ECHO;
1191 outicmp->icmp_id = htons(ident);
1193 outdata = (struct outdata *)(outp + 8); /* XXX magic number */
1197 outip->ip_p = IPPROTO_UDP;
1199 outudp = (struct udphdr *)outp;
1200 outudp->source = htons(ident);
1202 htons((u_short)(packlen - (sizeof(*outip) + optlen)));
1203 outdata = (struct outdata *)(outudp + 1);
1206 /* Get the interface address list */
1207 n = ifaddrlist(&al);
1209 /* Look for a specific device */
1210 if (device != NULL) {
1211 for (i = n; i > 0; --i, ++al)
1212 if (strcmp(device, al->device) == 0)
1215 bb_error_msg_and_die("Can't find interface %s", device);
1219 /* Determine our source address */
1220 if (source == NULL) {
1222 * If a device was specified, use the interface address.
1223 * Otherwise, try to determine our source address.
1226 setsin(from, al->addr);
1227 findsaddr(to, from);
1229 hi = gethostinfo(source);
1233 * If the device was specified make sure it
1234 * corresponds to the source address specified.
1235 * Otherwise, use the first address (and warn if
1236 * there are more than one).
1238 if (device != NULL) {
1239 for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
1240 if (*ap == al->addr)
1243 bb_error_msg_and_die(
1244 "%s is not on interface %s",
1249 setsin(from, hi->addrs[0]);
1252 "Warning: %s has multiple addresses; using %s",
1253 source, inet_ntoa(from->sin_addr));
1258 outip->ip_src = from->sin_addr;
1260 if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) {
1261 bb_perror_msg_and_die("bind");
1265 fprintf(stderr, "traceroute to %s (%s)", hostname, inet_ntoa(to->sin_addr));
1267 fprintf(stderr, " from %s", source);
1268 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
1269 (void)fflush(stderr);
1271 for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
1272 u_int32_t lastaddr = 0;
1273 int gotlastaddr = 0;
1275 int unreachable = 0;
1278 printf("%2d ", ttl);
1279 for (probe = 0; probe < nprobes; ++probe) {
1281 struct timeval t1, t2;
1285 if (sentfirst && pausemsecs > 0)
1286 usleep(pausemsecs * 1000);
1287 (void)gettimeofday(&t1, &tz);
1288 send_probe(++seq, ttl, &t1);
1290 while ((cc = wait_for_reply(s, from, &t1)) != 0) {
1291 (void)gettimeofday(&t2, &tz);
1292 i = packet_ok(packet, cc, from, seq);
1293 /* Skip short packet */
1297 from->sin_addr.s_addr != lastaddr) {
1298 print(packet, cc, from);
1299 lastaddr = from->sin_addr.s_addr;
1302 printf(" %.3f ms", deltaT(&t1, &t2));
1303 ip = (struct ip *)packet;
1304 if (op & USAGE_OP_TTL_FLAG)
1305 printf(" (%d)", ip->ip_ttl);
1307 if (ip->ip_ttl <= 1)
1312 /* time exceeded in transit */
1318 case ICMP_UNREACH_PORT:
1319 if (ip->ip_ttl <= 1)
1324 case ICMP_UNREACH_NET:
1329 case ICMP_UNREACH_HOST:
1334 case ICMP_UNREACH_PROTOCOL:
1339 case ICMP_UNREACH_NEEDFRAG:
1341 printf(" !F-%d", pmtu);
1344 case ICMP_UNREACH_SRCFAIL:
1349 case ICMP_UNREACH_FILTER_PROHIB:
1350 case ICMP_UNREACH_NET_PROHIB: /* misuse */
1355 case ICMP_UNREACH_HOST_PROHIB:
1360 case ICMP_UNREACH_HOST_PRECEDENCE:
1365 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1370 case ICMP_UNREACH_NET_UNKNOWN:
1371 case ICMP_UNREACH_HOST_UNKNOWN:
1376 case ICMP_UNREACH_ISOLATED:
1381 case ICMP_UNREACH_TOSNET:
1382 case ICMP_UNREACH_TOSHOST:
1389 printf(" !<%d>", code);
1396 (void)fflush(stdout);
1400 (unreachable > 0 && unreachable >= nprobes - 1))