1 /* vi: set sw=4 ts=4: */
3 * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000
4 * The Regents of the University of California. All rights reserved.
6 * Busybox port by Vladimir Oleynik (C) 2005 <dzo@simtreas.ru>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that: (1) source code distributions
10 * retain the above copyright notice and this paragraph in its entirety, (2)
11 * distributions including binary code include the above copyright notice and
12 * this paragraph in its entirety in the documentation or other materials
13 * provided with the distribution, and (3) all advertising materials mentioning
14 * features or use of this software display the following acknowledgement:
15 * ``This product includes software developed by the University of California,
16 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
17 * the University nor the names of its contributors may be used to endorse
18 * or promote products derived from this software without specific prior
20 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
21 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
22 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
25 //#define version "1.4a12"
29 * traceroute host - trace the route ip packets follow going to "host".
31 * Attempt to trace the route an ip packet would follow to some
32 * internet host. We find out intermediate hops by launching probe
33 * packets with a small ttl (time to live) then listening for an
34 * icmp "time exceeded" reply from a gateway. We start our probes
35 * with a ttl of one and increase by one until we get an icmp "port
36 * unreachable" (which means we got to "host") or hit a max (which
37 * defaults to 30 hops & can be changed with the -m flag). Three
38 * probes (change with -q flag) are sent at each ttl setting and a
39 * line is printed showing the ttl, address of the gateway and
40 * round trip time of each probe. If the probe answers come from
41 * different gateways, the address of each responding system will
42 * be printed. If there is no response within a 5 sec. timeout
43 * interval (changed with the -w flag), a "*" is printed for that
46 * Probe packets are UDP format. We don't want the destination
47 * host to process them so the destination port is set to an
48 * unlikely value (if some clod on the destination is using that
49 * value, it can be changed with the -p flag).
51 * A sample use might be:
53 * [yak 71]% traceroute nis.nsf.net.
54 * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
55 * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms
56 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
57 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
58 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms
59 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms
60 * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms
61 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms
62 * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms
63 * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms
64 * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms
65 * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms
67 * Note that lines 2 & 3 are the same. This is due to a buggy
68 * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
69 * packets with a zero ttl.
71 * A more interesting example is:
73 * [yak 72]% traceroute allspice.lcs.mit.edu.
74 * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
75 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
76 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms
77 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms
78 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms
79 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms
80 * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms
81 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms
82 * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms
83 * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms
84 * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms
85 * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms
87 * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms
92 * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms
94 * (I start to see why I'm having so much trouble with mail to
95 * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away
96 * either don't send ICMP "time exceeded" messages or send them
97 * with a ttl too small to reach us. 14 - 17 are running the
98 * MIT C Gateway code that doesn't send "time exceeded"s. God
99 * only knows what's going on with 12.
101 * The silent gateway 12 in the above may be the result of a bug in
102 * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3)
103 * sends an unreachable message using whatever ttl remains in the
104 * original datagram. Since, for gateways, the remaining ttl is
105 * zero, the icmp "time exceeded" is guaranteed to not make it back
106 * to us. The behavior of this bug is slightly more interesting
107 * when it appears on the destination system:
109 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
110 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms
111 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms
112 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms
113 * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms
114 * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms
121 * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms !
123 * Notice that there are 12 "gateways" (13 is the final
124 * destination) and exactly the last half of them are "missing".
125 * What's really happening is that rip (a Sun-3 running Sun OS3.5)
126 * is using the ttl from our arriving datagram as the ttl in its
127 * icmp reply. So, the reply will time out on the return path
128 * (with no notice sent to anyone since icmp's aren't sent for
129 * icmp's) until we probe with a ttl that's at least twice the path
130 * length. I.e., rip is really only 7 hops away. A reply that
131 * returns with a ttl of 1 is a clue this problem exists.
132 * Traceroute prints a "!" after the time if the ttl is <= 1.
133 * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
134 * non-standard (HPUX) software, expect to see this problem
135 * frequently and/or take care picking the target host of your
138 * Other possible annotations after the time are !H, !N, !P (got a host,
139 * network or protocol unreachable, respectively), !S or !F (source
140 * route failed or fragmentation needed -- neither of these should
141 * ever occur and the associated gateway is busted if you see one). If
142 * almost all the probes result in some kind of unreachable, traceroute
143 * will give up and exit.
147 * This program must be run by root or be setuid. (I suggest that
148 * you *don't* make it setuid -- casual use could result in a lot
149 * of unnecessary traffic on our poor, congested nets.)
151 * This program requires a kernel mod that does not appear in any
152 * system available from Berkeley: A raw ip socket using proto
153 * IPPROTO_RAW must interpret the data sent as an ip datagram (as
154 * opposed to data to be wrapped in a ip datagram). See the README
155 * file that came with the source to this program for a description
156 * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may
157 * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
158 * MODIFIED TO RUN THIS PROGRAM.
160 * The udp port usage may appear bizarre (well, ok, it is bizarre).
161 * The problem is that an icmp message only contains 8 bytes of
162 * data from the original datagram. 8 bytes is the size of a udp
163 * header so, if we want to associate replies with the original
164 * datagram, the necessary information must be encoded into the
165 * udp header (the ip id could be used but there's no way to
166 * interlock with the kernel's assignment of ip id's and, anyway,
167 * it would have taken a lot more kernel hacking to allow this
168 * code to set the ip id). So, to allow two or more users to
169 * use traceroute simultaneously, we use this task's pid as the
170 * source port (the high bit is set to move the port number out
171 * of the "likely" range). To keep track of which probe is being
172 * replied to (so times and/or hop counts don't get confused by a
173 * reply that was delayed in transit), we increment the destination
174 * port number before each probe.
176 * Don't use this as a coding example. I was trying to find a
177 * routing problem and this code sort-of popped out after 48 hours
178 * without sleep. I was amazed it ever compiled, much less ran.
180 * I stole the idea for this program from Steve Deering. Since
181 * the first release, I've learned that had I attended the right
182 * IETF working group meetings, I also could have stolen it from Guy
183 * Almes or Matt Mathis. I don't know (or care) who came up with
184 * the idea first. I envy the originators' perspicacity and I'm
185 * glad they didn't keep the idea a secret.
187 * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
188 * enhancements to the original distribution.
190 * I've hacked up a round-trip-route version of this that works by
191 * sending a loose-source-routed udp datagram through the destination
192 * back to yourself. Unfortunately, SO many gateways botch source
193 * routing, the thing is almost worthless. Maybe one day...
195 * -- Van Jacobson (van@ee.lbl.gov)
196 * Tue Dec 20 03:50:13 PST 1988
199 #define TRACEROUTE_SO_DEBUG 0
201 /* TODO: undefs were uncommented - ??! we have config system for that! */
202 /* probably ok to remove altogether */
203 //#undef CONFIG_FEATURE_TRACEROUTE_VERBOSE
204 //#define CONFIG_FEATURE_TRACEROUTE_VERBOSE
205 //#undef CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
206 //#define CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE
207 //#undef CONFIG_FEATURE_TRACEROUTE_USE_ICMP
208 //#define CONFIG_FEATURE_TRACEROUTE_USE_ICMP
210 #include "inet_common.h"
213 #include <arpa/inet.h>
214 #include <netinet/in.h>
215 #include <netinet/udp.h>
216 #include <netinet/ip.h>
217 #include <netinet/ip_icmp.h>
223 * Definitions for internet protocol version 4.
224 * Per RFC 791, September 1981.
230 #define IPPROTO_ICMP 1
237 * Overlay for ip header used by other protocols (tcp, udp).
240 unsigned char ih_x1[9]; /* (unused) */
241 unsigned char ih_pr; /* protocol */
242 short ih_len; /* protocol length */
243 struct in_addr ih_src; /* source internet address */
244 struct in_addr ih_dst; /* destination internet address */
248 * UDP kernel structures and variables.
251 struct ipovly ui_i; /* overlaid ip structure */
252 struct udphdr ui_u; /* udp header */
254 #define ui_next ui_i.ih_next
255 #define ui_prev ui_i.ih_prev
256 #define ui_x1 ui_i.ih_x1
257 #define ui_pr ui_i.ih_pr
258 #define ui_len ui_i.ih_len
259 #define ui_src ui_i.ih_src
260 #define ui_dst ui_i.ih_dst
261 #define ui_sport ui_u.uh_sport
262 #define ui_dport ui_u.uh_dport
263 #define ui_ulen ui_u.uh_ulen
264 #define ui_sum ui_u.uh_sum
267 /* Host name and address list */
274 /* Data section of the probe packet */
276 unsigned char seq; /* sequence number of this packet */
277 unsigned char ttl; /* ttl packet left with */
278 struct timeval tv ATTRIBUTE_PACKED; /* time packet left */
283 char device[sizeof(struct ifreq)];
287 static const char route[] = "/proc/net/route";
289 /* last inbound (icmp) packet */
290 static unsigned char packet[512] ATTRIBUTE_ALIGNED(32);
292 static struct ip *outip; /* last output (udp) packet */
293 static struct udphdr *outudp; /* last output (udp) packet */
294 static struct outdata *outdata; /* last output (udp) packet */
296 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
297 static struct icmp *outicmp; /* last output (icmp) packet */
300 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
301 /* Maximum number of gateways (include room for one noop) */
302 #define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))
303 /* loose source route gateway list (including room for final destination) */
304 static u_int32_t gwlist[NGATEWAYS + 1];
307 static int s; /* receive (icmp) socket file descriptor */
308 static int sndsock; /* send (udp/icmp) socket file descriptor */
310 static struct sockaddr_storage whereto; /* Who to try to reach */
311 static struct sockaddr_storage wherefrom; /* Who we are */
312 static int packlen; /* total length of packet */
313 static int minpacket; /* min ip packet size */
314 static int maxpacket = 32 * 1024; /* max ip packet size */
315 static int pmtu; /* Path MTU Discovery (RFC1191) */
317 static char *hostname;
319 static u_short ident;
320 static u_short port = 32768 + 666; /* start udp dest port # for probe packets */
322 static int waittime = 5; /* time to wait for response (in seconds) */
323 static int nflag; /* print addresses numerically */
324 static int doipcksum = 1; /* calculate ip checksums by default */
326 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
327 static int optlen; /* length of ip options */
332 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
333 static int useicmp; /* use icmp echo instead of udp packets */
335 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE
340 * Return the interface list
343 ifaddrlist(struct IFADDRLIST **ipaddrp)
346 #ifdef HAVE_SOCKADDR_SA_LEN
349 struct ifreq *ifrp, *ifend, *ifnext;
350 struct sockaddr_in *addr_sin;
351 struct IFADDRLIST *al;
353 struct ifreq ibuf[(32 * 1024) / sizeof(struct ifreq)], ifr;
354 struct IFADDRLIST *st_ifaddrlist;
356 fd = xsocket(AF_INET, SOCK_DGRAM, 0);
358 ifc.ifc_len = sizeof(ibuf);
359 ifc.ifc_buf = (caddr_t)ibuf;
361 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
362 ifc.ifc_len < sizeof(struct ifreq)) {
364 bb_error_msg_and_die(
365 "SIOCGIFCONF: ifreq struct too small (%d bytes)",
368 bb_perror_msg_and_die("SIOCGIFCONF");
371 ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
373 nipaddr = 1 + (ifc.ifc_len / sizeof(struct ifreq));
374 st_ifaddrlist = xzalloc(nipaddr * sizeof(struct IFADDRLIST));
378 for (; ifrp < ifend; ifrp = ifnext) {
379 #ifdef HAVE_SOCKADDR_SA_LEN
380 n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
381 if (n < sizeof(*ifrp))
384 ifnext = (struct ifreq *)((char *)ifrp + n);
385 if (ifrp->ifr_addr.sa_family != AF_INET)
391 * Need a template to preserve address info that is
392 * used below to locate the next entry. (Otherwise,
393 * SIOCGIFFLAGS stomps over it because the requests
394 * are returned in a union.)
396 strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));
397 if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
400 bb_perror_msg_and_die("SIOCGIFFLAGS: %.*s",
401 (int)sizeof(ifr.ifr_name), ifr.ifr_name);
405 if ((ifr.ifr_flags & IFF_UP) == 0)
408 safe_strncpy(al->device, ifr.ifr_name, sizeof(ifr.ifr_name) + 1);
410 /* Ignore sun virtual interfaces */
411 if (strchr(al->device, ':') != NULL)
414 if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0)
415 bb_perror_msg_and_die("SIOCGIFADDR: %s", al->device);
417 addr_sin = (struct sockaddr_in *)&ifr.ifr_addr;
418 al->addr = addr_sin->sin_addr.s_addr;
423 bb_error_msg_and_die ("can't find any network interfaces");
426 *ipaddrp = st_ifaddrlist;
432 setsin(struct sockaddr_in *addr_sin, u_int32_t addr)
434 memset(addr_sin, 0, sizeof(*addr_sin));
435 #ifdef HAVE_SOCKADDR_SA_LEN
436 addr_sin->sin_len = sizeof(*addr_sin);
438 addr_sin->sin_family = AF_INET;
439 addr_sin->sin_addr.s_addr = addr;
444 * Return the source address for the given destination address
447 findsaddr(const struct sockaddr_in *to, struct sockaddr_in *from)
452 u_int32_t dest, tmask;
453 struct IFADDRLIST *al;
454 char buf[256], tdevice[256], device[256];
456 f = xfopen(route, "r");
458 /* Find the appropriate interface */
462 while (fgets(buf, sizeof(buf), f) != NULL) {
464 if (n == 1 && strncmp(buf, "Iface", 5) == 0)
466 if ((i = sscanf(buf, "%255s %x %*s %*s %*s %*s %*s %x",
467 tdevice, &dest, &tmask)) != 3)
468 bb_error_msg_and_die ("junk in buffer");
469 if ((to->sin_addr.s_addr & tmask) == dest &&
470 (tmask > mask || mask == 0)) {
472 strcpy(device, tdevice);
477 if (device[0] == '\0')
478 bb_error_msg_and_die ("can't find interface");
480 /* Get the interface address list */
483 /* Find our appropriate source address */
484 for (i = n; i > 0; --i, ++al)
485 if (strcmp(device, al->device) == 0)
488 bb_error_msg_and_die("can't find interface %s", device);
490 setsin(from, al->addr);
494 "Usage: %s [-dFIlnrvx] [-g gateway] [-i iface] [-f first_ttl]\n"
495 "\t[-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos]\n"
496 "\t[-w waittime] [-z pausemsecs] host [packetlen]"
501 * Subtract 2 timeval structs: out = out - in.
502 * Out is assumed to be >= in.
505 tvsub(struct timeval *out, struct timeval *in)
508 if ((out->tv_usec -= in->tv_usec) < 0) {
510 out->tv_usec += 1000000;
512 out->tv_sec -= in->tv_sec;
516 wait_for_reply(int sock, struct sockaddr_in *fromp, const struct timeval *tp)
519 struct timeval now, tvwait;
522 socklen_t fromlen = sizeof(*fromp);
527 tvwait.tv_sec = tp->tv_sec + waittime;
528 tvwait.tv_usec = tp->tv_usec;
529 (void)gettimeofday(&now, &tz);
530 tvsub(&tvwait, &now);
532 if (select(sock + 1, &fds, NULL, NULL, &tvwait) > 0)
533 cc = recvfrom(sock, (char *)packet, sizeof(packet), 0,
534 (struct sockaddr *)fromp, &fromlen);
540 * Checksum routine for Internet Protocol family headers (C Version)
543 in_cksum(u_short *addr, int len)
551 * Our algorithm is simple, using a 32 bit accumulator (sum),
552 * we add sequential 16 bit words to it, and at the end, fold
553 * back all the carry bits from the top 16 bits into the lower
561 /* mop up an odd byte, if necessary */
563 sum += *(unsigned char *)w;
566 * add back carry outs from top 16 bits to low 16 bits
568 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
569 sum += (sum >> 16); /* add carry */
570 answer = ~sum; /* truncate to 16 bits */
576 send_probe(int seq, int ttl, struct timeval *tp)
579 struct udpiphdr *ui, *oui;
583 outip->ip_id = htons(ident + seq);
586 * In most cases, the kernel will recalculate the ip checksum.
587 * But we must do it anyway so that the udp checksum comes out
592 in_cksum((u_short *)outip, sizeof(*outip) + optlen);
593 if (outip->ip_sum == 0)
594 outip->ip_sum = 0xffff;
600 memcpy(&outdata->tv, tp, sizeof(outdata->tv));
602 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
604 outicmp->icmp_seq = htons(seq);
607 outudp->dest = htons(port + seq);
609 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
611 /* Always calculate checksum for icmp packets */
612 outicmp->icmp_cksum = 0;
613 outicmp->icmp_cksum = in_cksum((u_short *)outicmp,
614 packlen - (sizeof(*outip) + optlen));
615 if (outicmp->icmp_cksum == 0)
616 outicmp->icmp_cksum = 0xffff;
620 /* Checksum (we must save and restore ip header) */
622 ui = (struct udpiphdr *)outip;
623 oui = (struct udpiphdr *)&tip;
624 /* Easier to zero and put back things that are ok */
625 memset((char *)ui, 0, sizeof(ui->ui_i));
626 ui->ui_src = oui->ui_src;
627 ui->ui_dst = oui->ui_dst;
628 ui->ui_pr = oui->ui_pr;
629 ui->ui_len = outudp->len;
631 outudp->check = in_cksum((u_short *)ui, packlen);
632 if (outudp->check == 0)
633 outudp->check = 0xffff;
637 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE
638 /* XXX undocumented debugging hack */
643 sp = (u_short *)outip;
644 nshorts = (u_int)packlen / sizeof(u_short);
646 printf("[ %d bytes", packlen);
647 while (--nshorts >= 0) {
650 printf(" %04x", ntohs(*sp));
656 printf(" %02x", *(unsigned char *)sp);
662 #if !defined(IP_HDRINCL) && defined(IP_TTL)
663 if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
664 (char *)&ttl, sizeof(ttl)) < 0) {
665 bb_perror_msg_and_die("setsockopt ttl %d", ttl);
669 cc = sendto(sndsock, (char *)outip,
670 packlen, 0, (struct sockaddr *)&whereto, sizeof(whereto));
671 if (cc < 0 || cc != packlen) {
673 bb_perror_msg_and_die("sendto");
674 printf("%s: wrote %s %d chars, ret=%d\n",
675 applet_name, hostname, packlen, cc);
676 (void)fflush(stdout);
681 deltaT(struct timeval *t1p, struct timeval *t2p)
685 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
686 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
690 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE
692 * Convert an ICMP "type" field to a printable string.
694 static inline const char *
695 pr_type(unsigned char t)
697 static const char * const ttab[] = {
698 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
699 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
700 "Echo", "Router Advert", "Router Solicit", "Time Exceeded",
701 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
702 "Info Reply", "Mask Request", "Mask Reply"
706 return "OUT-OF-RANGE";
713 packet_ok(unsigned char *buf, int cc, struct sockaddr_in *from, int seq)
716 unsigned char type, code;
720 ip = (struct ip *) buf;
721 hlen = ip->ip_hl << 2;
722 if (cc < hlen + ICMP_MINLEN) {
723 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE
725 printf("packet too short (%d bytes) from %s\n", cc,
726 inet_ntoa(from->sin_addr));
731 icp = (struct icmp *)(buf + hlen);
732 type = icp->icmp_type;
733 code = icp->icmp_code;
734 /* Path MTU Discovery (RFC1191) */
735 if (code != ICMP_UNREACH_NEEDFRAG)
738 pmtu = ntohs(icp->icmp_nextmtu);
740 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
741 type == ICMP_UNREACH || type == ICMP_ECHOREPLY) {
746 hlen = hip->ip_hl << 2;
747 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
752 if (type == ICMP_ECHOREPLY &&
753 icp->icmp_id == htons(ident) &&
754 icp->icmp_seq == htons(seq))
757 hicmp = (struct icmp *)((unsigned char *)hip + hlen);
758 /* XXX 8 is a magic number */
759 if (hlen + 8 <= cc &&
760 hip->ip_p == IPPROTO_ICMP &&
761 hicmp->icmp_id == htons(ident) &&
762 hicmp->icmp_seq == htons(seq))
763 return (type == ICMP_TIMXCEED ? -1 : code + 1);
767 up = (struct udphdr *)((unsigned char *)hip + hlen);
768 /* XXX 8 is a magic number */
769 if (hlen + 12 <= cc &&
770 hip->ip_p == IPPROTO_UDP &&
771 up->source == htons(ident) &&
772 up->dest == htons(port + seq))
773 return (type == ICMP_TIMXCEED ? -1 : code + 1);
776 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE
779 u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
781 printf("\n%d bytes from %s to "
782 "%s: icmp type %d (%s) code %d\n",
783 cc, inet_ntoa(from->sin_addr),
784 inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
785 for (i = 4; i < cc ; i += sizeof(*lp))
786 printf("%2d: x%8.8x\n", i, *lp++);
794 * Construct an Internet address representation.
795 * If the nflag has been supplied, give
796 * numeric value, otherwise try for symbolic name.
799 inetname(struct sockaddr_in *from)
801 const char *n = NULL;
805 if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
806 if (INET_rresolve(name, sizeof(name), from, 0x4000, 0xffffffff) >= 0)
809 ina = inet_ntoa(from->sin_addr);
813 printf(" %s (%s)", (n ? n : ina), ina);
817 print(unsigned char *buf, int cc, struct sockaddr_in *from)
822 ip = (struct ip *) buf;
823 hlen = ip->ip_hl << 2;
827 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE
829 printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
834 static struct hostinfo *
835 gethostinfo(const char *host)
843 hi = xzalloc(sizeof(*hi));
844 addr = inet_addr(host);
845 if ((int32_t)addr != -1) {
846 hi->name = xstrdup(host);
848 hi->addrs = xzalloc(sizeof(hi->addrs[0]));
853 hp = xgethostbyname(host);
854 if (hp->h_addrtype != AF_INET || hp->h_length != 4)
855 bb_perror_msg_and_die("bad host %s", host);
856 hi->name = xstrdup(hp->h_name);
857 for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
860 hi->addrs = xzalloc(n * sizeof(hi->addrs[0]));
861 for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
862 memcpy(ap, *p, sizeof(*ap));
867 freehostinfo(struct hostinfo *hi)
871 free((char *)hi->addrs);
875 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
877 getaddr(u_int32_t *ap, const char *host)
881 hi = gethostinfo(host);
889 traceroute_main(int argc, char *argv[])
894 struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom;
895 struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
901 char *tos_str = NULL;
905 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
909 struct IFADDRLIST *al;
912 char *max_ttl_str = NULL;
913 char *port_str = NULL;
915 char *nprobes_str = NULL;
916 char *waittime_str = NULL;
917 u_int pausemsecs = 0;
918 char *pausemsecs_str = NULL;
920 char *first_ttl_str = NULL;
921 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
922 llist_t *sourse_route_list = NULL;
926 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
927 opt_complementary = "x-x:g::";
929 opt_complementary = "x-x";
932 op = getopt32(argc, argv, "FIlnrdvxt:i:m:p:q:s:w:z:f:"
933 #define USAGE_OP_DONT_FRAGMNT (1<<0) /* F */
934 #define USAGE_OP_USE_ICMP (1<<1) /* I */
935 #define USAGE_OP_TTL_FLAG (1<<2) /* l */
936 #define USAGE_OP_ADDR_NUM (1<<3) /* n */
937 #define USAGE_OP_BYPASS_ROUTE (1<<4) /* r */
938 #define USAGE_OP_DEBUG (1<<5) /* d */
939 #define USAGE_OP_VERBOSE (1<<6) /* v */
940 #define USAGE_OP_IP_CHKSUM (1<<7) /* x */
942 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
945 , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str,
946 &source, &waittime_str, &pausemsecs_str, &first_ttl_str
947 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
952 if (op & USAGE_OP_DONT_FRAGMNT)
954 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
955 useicmp = op & USAGE_OP_USE_ICMP;
957 nflag = op & USAGE_OP_ADDR_NUM;
958 #if ENABLE_FEATURE_TRACEROUTE_VERBOSE
959 verbose = op & USAGE_OP_VERBOSE;
961 if (op & USAGE_OP_IP_CHKSUM) {
963 bb_error_msg("warning: ip checksums disabled");
966 tos = xatoul_range(tos_str, 0, 255);
968 max_ttl = xatoul_range(max_ttl_str, 1, 255);
970 port = xatou16(port_str);
972 nprobes = xatoul_range(nprobes_str, 1, INT_MAX);
975 * set the ip source address of the outbound
976 * probe (e.g., on a multi-homed host).
978 if (getuid()) bb_error_msg_and_die("-s %s: permission denied", source);
981 waittime = xatoul_range(waittime_str, 2, 24 * 60 * 60);
983 pausemsecs = xatoul_range(pausemsecs_str, 0, 60 * 60 * 1000);
985 first_ttl = xatoul_range(first_ttl_str, 1, 255);
987 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
988 if (sourse_route_list) {
991 for(l_sr = sourse_route_list; l_sr; ) {
992 if (lsrr >= NGATEWAYS)
993 bb_error_msg_and_die("no more than %d gateways", NGATEWAYS);
994 getaddr(gwlist + lsrr, l_sr->data);
997 free(sourse_route_list);
998 sourse_route_list = l_sr;
1000 optlen = (lsrr + 1) * sizeof(gwlist[0]);
1004 if (first_ttl > max_ttl) {
1005 bb_error_msg_and_die(
1006 "first ttl (%d) may not be greater than max ttl (%d)",
1007 first_ttl, max_ttl);
1010 minpacket = sizeof(*outip) + sizeof(*outdata) + optlen;
1012 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
1014 minpacket += 8; /* XXX magic number */
1017 minpacket += sizeof(*outudp);
1018 packlen = minpacket; /* minimum sized packet */
1020 /* Process destination and optional packet size */
1021 switch (argc - optind) {
1024 packlen = xatoul_range(argv[optind + 1], minpacket, maxpacket);
1028 hostname = argv[optind];
1029 hi = gethostinfo(hostname);
1030 setsin(to, hi->addrs[0]);
1032 bb_error_msg("warning: %s has multiple addresses; using %s",
1033 hostname, inet_ntoa(to->sin_addr));
1034 hostname = hi->name;
1043 /* Insure the socket fds won't be 0, 1 or 2 */
1044 do n = xopen(bb_dev_null, O_RDONLY); while (n < 2);
1048 s = xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
1050 #if TRACEROUTE_SO_DEBUG
1051 if (op & USAGE_OP_DEBUG)
1052 (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
1055 if (op & USAGE_OP_BYPASS_ROUTE)
1056 (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
1059 sndsock = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW);
1061 #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE
1062 #if defined(IP_OPTIONS)
1064 unsigned char optlist[MAX_IPOPTLEN];
1067 gwlist[lsrr] = to->sin_addr.s_addr;
1070 /* force 4 byte alignment */
1071 optlist[0] = IPOPT_NOP;
1072 /* loose source route option */
1073 optlist[1] = IPOPT_LSRR;
1074 i = lsrr * sizeof(gwlist[0]);
1076 /* Pointer to LSRR addresses */
1077 optlist[3] = IPOPT_MINOFF;
1078 memcpy(optlist + 4, gwlist, i);
1080 if ((setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS,
1081 (char *)optlist, i + sizeof(gwlist[0]))) < 0) {
1082 bb_perror_msg_and_die("IP_OPTIONS");
1085 #endif /* IP_OPTIONS */
1086 #endif /* CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE */
1089 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
1090 sizeof(packlen)) < 0) {
1091 bb_perror_msg_and_die("SO_SNDBUF");
1095 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
1096 sizeof(on)) < 0 && errno != ENOPROTOOPT) {
1097 bb_perror_msg_and_die("IP_HDRINCL");
1101 if (tos_str && setsockopt(sndsock, IPPROTO_IP, IP_TOS,
1102 (char *)&tos, sizeof(tos)) < 0) {
1103 bb_perror_msg_and_die("setsockopt tos %d", tos);
1107 #if TRACEROUTE_SO_DEBUG
1108 if (op & USAGE_OP_DEBUG)
1109 (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
1112 if (op & USAGE_OP_BYPASS_ROUTE)
1113 (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
1116 /* Revert to non-privileged user after opening sockets */
1120 outip = (struct ip *)xzalloc(packlen);
1122 outip->ip_v = IPVERSION;
1124 outip->ip_tos = tos;
1125 outip->ip_len = htons(packlen);
1126 outip->ip_off = htons(off);
1127 outp = (unsigned char *)(outip + 1);
1128 outip->ip_dst = to->sin_addr;
1130 outip->ip_hl = (outp - (unsigned char *)outip) >> 2;
1131 ident = (getpid() & 0xffff) | 0x8000;
1132 #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP
1134 outip->ip_p = IPPROTO_ICMP;
1136 outicmp = (struct icmp *)outp;
1137 outicmp->icmp_type = ICMP_ECHO;
1138 outicmp->icmp_id = htons(ident);
1140 outdata = (struct outdata *)(outp + 8); /* XXX magic number */
1144 outip->ip_p = IPPROTO_UDP;
1146 outudp = (struct udphdr *)outp;
1147 outudp->source = htons(ident);
1149 htons((u_short)(packlen - (sizeof(*outip) + optlen)));
1150 outdata = (struct outdata *)(outudp + 1);
1153 /* Get the interface address list */
1154 n = ifaddrlist(&al);
1156 /* Look for a specific device */
1157 if (device != NULL) {
1158 for (i = n; i > 0; --i, ++al)
1159 if (strcmp(device, al->device) == 0)
1162 bb_error_msg_and_die("can't find interface %s", device);
1166 /* Determine our source address */
1167 if (source == NULL) {
1169 * If a device was specified, use the interface address.
1170 * Otherwise, try to determine our source address.
1173 setsin(from, al->addr);
1174 findsaddr(to, from);
1176 hi = gethostinfo(source);
1180 * If the device was specified make sure it
1181 * corresponds to the source address specified.
1182 * Otherwise, use the first address (and warn if
1183 * there are more than one).
1185 if (device != NULL) {
1186 for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
1187 if (*ap == al->addr)
1190 bb_error_msg_and_die(
1191 "%s is not on interface %s",
1196 setsin(from, hi->addrs[0]);
1199 "Warning: %s has multiple addresses; using %s",
1200 source, inet_ntoa(from->sin_addr));
1205 outip->ip_src = from->sin_addr;
1207 xbind(sndsock, (struct sockaddr *)from, sizeof(*from));
1210 fprintf(stderr, "traceroute to %s (%s)", hostname, inet_ntoa(to->sin_addr));
1212 fprintf(stderr, " from %s", source);
1213 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
1214 (void)fflush(stderr);
1216 for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
1217 u_int32_t lastaddr = 0;
1218 int gotlastaddr = 0;
1220 int unreachable = 0;
1223 printf("%2d ", ttl);
1224 for (probe = 0; probe < nprobes; ++probe) {
1226 struct timeval t1, t2;
1230 if (sentfirst && pausemsecs > 0)
1231 usleep(pausemsecs * 1000);
1232 (void)gettimeofday(&t1, &tz);
1233 send_probe(++seq, ttl, &t1);
1235 while ((cc = wait_for_reply(s, from, &t1)) != 0) {
1236 (void)gettimeofday(&t2, &tz);
1237 i = packet_ok(packet, cc, from, seq);
1238 /* Skip short packet */
1242 from->sin_addr.s_addr != lastaddr) {
1243 print(packet, cc, from);
1244 lastaddr = from->sin_addr.s_addr;
1247 printf(" %.3f ms", deltaT(&t1, &t2));
1248 ip = (struct ip *)packet;
1249 if (op & USAGE_OP_TTL_FLAG)
1250 printf(" (%d)", ip->ip_ttl);
1252 if (ip->ip_ttl <= 1)
1257 /* time exceeded in transit */
1263 case ICMP_UNREACH_PORT:
1264 if (ip->ip_ttl <= 1)
1269 case ICMP_UNREACH_NET:
1274 case ICMP_UNREACH_HOST:
1279 case ICMP_UNREACH_PROTOCOL:
1284 case ICMP_UNREACH_NEEDFRAG:
1286 printf(" !F-%d", pmtu);
1289 case ICMP_UNREACH_SRCFAIL:
1294 case ICMP_UNREACH_FILTER_PROHIB:
1295 case ICMP_UNREACH_NET_PROHIB: /* misuse */
1300 case ICMP_UNREACH_HOST_PROHIB:
1305 case ICMP_UNREACH_HOST_PRECEDENCE:
1310 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1315 case ICMP_UNREACH_NET_UNKNOWN:
1316 case ICMP_UNREACH_HOST_UNKNOWN:
1321 case ICMP_UNREACH_ISOLATED:
1326 case ICMP_UNREACH_TOSNET:
1327 case ICMP_UNREACH_TOSHOST:
1334 printf(" !<%d>", code);
1341 (void)fflush(stdout);
1345 (unreachable > 0 && unreachable >= nprobes - 1))