2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
8 * Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * traceroute host - trace the route ip packets follow going to "host".
42 * This program must be run by root or be setuid. (I suggest that
43 * you *don't* make it setuid -- casual use could result in a lot
44 * of unnecessary traffic on our poor, congested nets.)
46 * I stole the idea for this program from Steve Deering. Since
47 * the first release, I've learned that had I attended the right
48 * IETF working group meetings, I also could have stolen it from Guy
49 * Almes or Matt Mathis. I don't know (or care) who came up with
50 * the idea first. I envy the originators' perspicacity and I'm
51 * glad they didn't keep the idea a secret.
53 * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
54 * enhancements to the original distribution.
56 * I've hacked up a round-trip-route version of this that works by
57 * sending a loose-source-routed udp datagram through the destination
58 * back to yourself. Unfortunately, SO many gateways botch source
59 * routing, the thing is almost worthless. Maybe one day...
61 * -- Van Jacobson (van@helios.ee.lbl.gov)
62 * Tue Dec 20 03:50:13 PST 1988
65 #undef BB_FEATURE_TRACEROUTE_VERBOSE
66 //#define BB_FEATURE_TRACEROUTE_VERBOSE
67 #undef BB_FEATURE_TRACEROUTE_SO_DEBUG /* not in documentation man */
75 #include <sys/types.h>
76 #include <sys/socket.h>
79 #include <arpa/inet.h>
80 #include <netinet/udp.h>
81 #include <netinet/ip.h>
82 #include <netinet/ip_icmp.h>
86 #define MAXPACKET 65535 /* max ip packet size */
87 #ifndef MAXHOSTNAMELEN
88 #define MAXHOSTNAMELEN 64
92 * format of a (udp) probe packet.
97 u_char seq; /* sequence number of this packet */
98 u_char ttl; /* ttl packet left with */
99 struct timeval tv; /* time packet left */
103 * Definitions for internet protocol version 4.
104 * Per RFC 791, September 1981.
111 static u_char packet[512]; /* last inbound (icmp) packet */
112 static struct opacket *outpacket; /* last output (udp) packet */
114 static int s; /* receive (icmp) socket file descriptor */
115 static int sndsock; /* send (udp) socket file descriptor */
117 static struct sockaddr whereto; /* Who to try to reach */
118 static int datalen; /* How much data */
120 static char *hostname;
122 static int max_ttl = 30;
123 static u_short ident;
124 static u_short port = 32768+666; /* start udp dest port # for probe packets */
126 #ifdef BB_FEATURE_TRACEROUTE_VERBOSE
129 static int waittime = 5; /* time to wait for response (in seconds) */
130 static int nflag; /* print addresses numerically */
133 * Construct an Internet address representation.
134 * If the nflag has been supplied, give
135 * numeric value, otherwise try for symbolic name.
138 inetname(struct sockaddr_in *from)
142 static char domain[MAXHOSTNAMELEN + 1];
143 static int first = 1;
146 if (first && !nflag) {
148 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
149 (cp = strchr(domain, '.')))
150 (void) strcpy(domain, cp + 1);
155 if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
156 hp = gethostbyaddr((char *)&(from->sin_addr), sizeof (from->sin_addr), AF_INET);
158 if ((cp = strchr(hp->h_name, '.')) &&
159 !strcmp(cp + 1, domain))
161 cp = (char *)hp->h_name;
164 ina = inet_ntoa(from->sin_addr);
168 printf(" %s (%s)", (cp ? cp : ina), ina);
172 print(u_char *buf, int cc, struct sockaddr_in *from)
177 ip = (struct ip *) buf;
178 hlen = ip->ip_hl << 2;
182 #ifdef BB_FEATURE_TRACEROUTE_VERBOSE
184 printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
189 deltaT(struct timeval *t1p, struct timeval *t2p)
193 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
194 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
199 wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer)
202 static struct timeval wait;
204 int fromlen = sizeof (*from);
210 * traceroute could hang if someone else has a ping
211 * running and our ICMP reply gets dropped but we don't
212 * realize it because we keep waking up to handle those
213 * other ICMP packets that keep coming in. To fix this,
214 * "reset_timer" will only be true if the last packet that
215 * came in was for us or if this is the first time we're
216 * waiting for a reply since sending out a probe. Note
217 * that this takes advantage of the select() feature on
218 * Linux where the remaining timeout is written to the
219 * struct timeval area.
221 wait.tv_sec = waittime;
225 if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
226 cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
227 (struct sockaddr *)from, &fromlen);
232 #ifdef BB_FEATURE_TRACEROUTE_VERBOSE
234 * Convert an ICMP "type" field to a printable string.
236 static inline const char *
240 static const char * const ttab[] = {
241 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
242 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
243 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
244 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
249 return("OUT-OF-RANGE");
256 packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
263 ip = (struct ip *) buf;
264 hlen = ip->ip_hl << 2;
265 if (cc < hlen + ICMP_MINLEN) {
266 #ifdef BB_FEATURE_TRACEROUTE_VERBOSE
268 printf("packet too short (%d bytes) from %s\n", cc,
269 inet_ntoa(from->sin_addr));
274 icp = (struct icmp *)(buf + hlen);
275 type = icp->icmp_type; code = icp->icmp_code;
276 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
277 type == ICMP_UNREACH) {
282 hlen = hip->ip_hl << 2;
283 up = (struct udphdr *)((u_char *)hip + hlen);
284 if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
285 up->source == htons(ident) &&
286 up->dest == htons(port+seq))
287 return (type == ICMP_TIMXCEED? -1 : code+1);
289 #ifdef BB_FEATURE_TRACEROUTE_VERBOSE
292 u_long *lp = (u_long *)&icp->icmp_ip;
294 printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
295 cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst),
296 type, pr_type(type), icp->icmp_code);
297 for (i = 4; i < cc ; i += sizeof(long))
298 printf("%2d: x%8.8lx\n", i, *lp++);
304 static void /* not inline */
305 send_probe(int seq, int ttl)
307 struct opacket *op = outpacket;
308 struct ip *ip = &op->ip;
309 struct udphdr *up = &op->udp;
314 ip->ip_hl = sizeof(*ip) >> 2;
315 ip->ip_p = IPPROTO_UDP;
316 ip->ip_len = datalen;
318 ip->ip_v = IPVERSION;
319 ip->ip_id = htons(ident+seq);
321 up->source = htons(ident);
322 up->dest = htons(port+seq);
323 up->len = htons((u_short)(datalen - sizeof(struct ip)));
328 (void) gettimeofday(&op->tv, &tz);
330 i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
331 sizeof(struct sockaddr));
332 if (i < 0 || i != datalen) {
335 printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
337 (void) fflush(stdout);
343 #ifndef BB_TRACEROUTE
346 traceroute_main(argc, argv)
354 struct sockaddr_in from, *to;
355 int ch, i, on, probe, seq, tos, ttl;
357 int options = 0; /* socket options */
363 to = (struct sockaddr_in *)&whereto;
364 while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
367 #ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
372 max_ttl = atoi(optarg);
374 error_msg_and_die("max ttl must be >1.");
382 error_msg_and_die("port must be >0.");
385 nprobes = atoi(optarg);
387 error_msg_and_die("nprobes must be >0.");
390 options |= SO_DONTROUTE;
394 * set the ip source address of the outbound
395 * probe (e.g., on a multi-homed host).
401 if (tos < 0 || tos > 255)
402 error_msg_and_die("tos must be 0 to 255.");
405 #ifdef BB_FEATURE_TRACEROUTE_VERBOSE
410 waittime = atoi(optarg);
412 error_msg_and_die("wait must be >1 sec.");
425 memset(&whereto, 0, sizeof(struct sockaddr));
426 hp = xgethostbyname(*argv);
427 to->sin_family = hp->h_addrtype;
428 memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
429 hostname = (char *)hp->h_name;
431 datalen = atoi(*argv);
432 if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
433 error_msg_and_die("packet size must be 0 <= s < %d.",
434 MAXPACKET - sizeof(struct opacket));
435 datalen += sizeof(struct opacket);
436 outpacket = (struct opacket *)xmalloc((unsigned)datalen);
437 memset(outpacket, 0, datalen);
438 outpacket->ip.ip_dst = to->sin_addr;
439 outpacket->ip.ip_tos = tos;
440 outpacket->ip.ip_v = IPVERSION;
441 outpacket->ip.ip_id = 0;
443 ident = (getpid() & 0xffff) | 0x8000;
445 if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
446 perror_msg_and_die(can_not_create_raw_socket);
448 s = create_icmp_socket();
450 #ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
451 if (options & SO_DEBUG)
452 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
453 (char *)&on, sizeof(on));
455 if (options & SO_DONTROUTE)
456 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
457 (char *)&on, sizeof(on));
459 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
460 sizeof(datalen)) < 0)
461 perror_msg_and_die("SO_SNDBUF");
464 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
466 perror_msg_and_die("IP_HDRINCL");
468 #ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
469 if (options & SO_DEBUG)
470 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
471 (char *)&on, sizeof(on));
473 if (options & SO_DONTROUTE)
474 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
475 (char *)&on, sizeof(on));
478 memset(&from, 0, sizeof(struct sockaddr));
479 from.sin_family = AF_INET;
480 from.sin_addr.s_addr = inet_addr(source);
481 if (from.sin_addr.s_addr == -1)
482 error_msg_and_die("unknown host %s", source);
483 outpacket->ip.ip_src = from.sin_addr;
485 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
486 perror_msg_and_die("bind");
490 fprintf(stderr, "traceroute to %s (%s)", hostname,
491 inet_ntoa(to->sin_addr));
493 fprintf(stderr, " from %s", source);
494 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
496 for (ttl = 1; ttl <= max_ttl; ++ttl) {
502 for (probe = 0; probe < nprobes; ++probe) {
504 struct timeval t1, t2;
508 (void) gettimeofday(&t1, &tz);
509 send_probe(++seq, ttl);
511 while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
512 (void) gettimeofday(&t2, &tz);
513 if ((i = packet_ok(packet, cc, &from, seq))) {
515 if (from.sin_addr.s_addr != lastaddr) {
516 print(packet, cc, &from);
517 lastaddr = from.sin_addr.s_addr;
519 printf(" %g ms", deltaT(&t1, &t2));
521 case ICMP_UNREACH_PORT:
522 ip = (struct ip *)packet;
527 case ICMP_UNREACH_NET:
531 case ICMP_UNREACH_HOST:
535 case ICMP_UNREACH_PROTOCOL:
539 case ICMP_UNREACH_NEEDFRAG:
543 case ICMP_UNREACH_SRCFAIL:
554 (void) fflush(stdout);
557 if (got_there || unreachable >= nprobes-1)