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 */
77 #include <arpa/inet.h>
78 #include <netinet/udp.h>
79 #include <netinet/ip.h>
80 #include <netinet/ip_icmp.h>
83 #define MAXPACKET 65535 /* max ip packet size */
84 #ifndef MAXHOSTNAMELEN
85 #define MAXHOSTNAMELEN 64
89 * format of a (udp) probe packet.
94 u_char seq; /* sequence number of this packet */
95 u_char ttl; /* ttl packet left with */
96 struct timeval tv; /* time packet left */
100 * Definitions for internet protocol version 4.
101 * Per RFC 791, September 1981.
108 static u_char packet[512]; /* last inbound (icmp) packet */
109 static struct opacket *outpacket; /* last output (udp) packet */
111 static int s; /* receive (icmp) socket file descriptor */
112 static int sndsock; /* send (udp) socket file descriptor */
114 static struct sockaddr whereto; /* Who to try to reach */
115 static int datalen; /* How much data */
117 static char *hostname;
119 static int max_ttl = 30;
120 static u_short ident;
121 static u_short port = 32768+666; /* start udp dest port # for probe packets */
123 #ifdef BB_FEATURE_TRACEROUTE_VERBOSE
126 static int waittime = 5; /* time to wait for response (in seconds) */
127 static int nflag; /* print addresses numerically */
130 * Construct an Internet address representation.
131 * If the nflag has been supplied, give
132 * numeric value, otherwise try for symbolic name.
135 inetname(struct sockaddr_in *from)
139 static char domain[MAXHOSTNAMELEN + 1];
140 static int first = 1;
143 if (first && !nflag) {
145 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
146 (cp = strchr(domain, '.')))
147 (void) strcpy(domain, cp + 1);
152 if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
153 hp = gethostbyaddr((char *)&(from->sin_addr), sizeof (from->sin_addr), AF_INET);
155 if ((cp = strchr(hp->h_name, '.')) &&
156 !strcmp(cp + 1, domain))
158 cp = (char *)hp->h_name;
161 ina = inet_ntoa(from->sin_addr);
165 printf(" %s (%s)", (cp ? cp : ina), ina);
169 print(u_char *buf, int cc, struct sockaddr_in *from)
174 ip = (struct ip *) buf;
175 hlen = ip->ip_hl << 2;
179 #ifdef BB_FEATURE_TRACEROUTE_VERBOSE
181 printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
186 deltaT(struct timeval *t1p, struct timeval *t2p)
190 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
191 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
196 wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer)
199 static struct timeval wait;
201 int fromlen = sizeof (*from);
207 * traceroute could hang if someone else has a ping
208 * running and our ICMP reply gets dropped but we don't
209 * realize it because we keep waking up to handle those
210 * other ICMP packets that keep coming in. To fix this,
211 * "reset_timer" will only be true if the last packet that
212 * came in was for us or if this is the first time we're
213 * waiting for a reply since sending out a probe. Note
214 * that this takes advantage of the select() feature on
215 * Linux where the remaining timeout is written to the
216 * struct timeval area.
218 wait.tv_sec = waittime;
222 if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
223 cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
224 (struct sockaddr *)from, &fromlen);
229 #ifdef BB_FEATURE_TRACEROUTE_VERBOSE
231 * Convert an ICMP "type" field to a printable string.
233 static inline const char *
237 static const char * const ttab[] = {
238 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
239 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
240 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
241 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
246 return("OUT-OF-RANGE");
253 packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
260 ip = (struct ip *) buf;
261 hlen = ip->ip_hl << 2;
262 if (cc < hlen + ICMP_MINLEN) {
263 #ifdef BB_FEATURE_TRACEROUTE_VERBOSE
265 printf("packet too short (%d bytes) from %s\n", cc,
266 inet_ntoa(from->sin_addr));
271 icp = (struct icmp *)(buf + hlen);
272 type = icp->icmp_type; code = icp->icmp_code;
273 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
274 type == ICMP_UNREACH) {
279 hlen = hip->ip_hl << 2;
280 up = (struct udphdr *)((u_char *)hip + hlen);
281 if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
282 up->source == htons(ident) &&
283 up->dest == htons(port+seq))
284 return (type == ICMP_TIMXCEED? -1 : code+1);
286 #ifdef BB_FEATURE_TRACEROUTE_VERBOSE
289 u_long *lp = (u_long *)&icp->icmp_ip;
291 printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
292 cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst),
293 type, pr_type(type), icp->icmp_code);
294 for (i = 4; i < cc ; i += sizeof(long))
295 printf("%2d: x%8.8lx\n", i, *lp++);
301 static void /* not inline */
302 send_probe(int seq, int ttl)
304 struct opacket *op = outpacket;
305 struct ip *ip = &op->ip;
306 struct udphdr *up = &op->udp;
311 ip->ip_hl = sizeof(*ip) >> 2;
312 ip->ip_p = IPPROTO_UDP;
313 ip->ip_len = datalen;
315 ip->ip_v = IPVERSION;
316 ip->ip_id = htons(ident+seq);
318 up->source = htons(ident);
319 up->dest = htons(port+seq);
320 up->len = htons((u_short)(datalen - sizeof(struct ip)));
325 (void) gettimeofday(&op->tv, &tz);
327 i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
328 sizeof(struct sockaddr));
329 if (i < 0 || i != datalen) {
332 printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
334 (void) fflush(stdout);
340 #ifndef BB_TRACEROUTE
343 traceroute_main(argc, argv)
351 struct sockaddr_in from, *to;
352 int ch, i, on, probe, seq, tos, ttl;
354 int options = 0; /* socket options */
360 to = (struct sockaddr_in *)&whereto;
361 while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
364 #ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
369 max_ttl = atoi(optarg);
371 error_msg_and_die("max ttl must be >1.");
379 error_msg_and_die("port must be >0.");
382 nprobes = atoi(optarg);
384 error_msg_and_die("nprobes must be >0.");
387 options |= SO_DONTROUTE;
391 * set the ip source address of the outbound
392 * probe (e.g., on a multi-homed host).
398 if (tos < 0 || tos > 255)
399 error_msg_and_die("tos must be 0 to 255.");
402 #ifdef BB_FEATURE_TRACEROUTE_VERBOSE
407 waittime = atoi(optarg);
409 error_msg_and_die("wait must be >1 sec.");
422 memset(&whereto, 0, sizeof(struct sockaddr));
423 hp = xgethostbyname(*argv);
424 to->sin_family = hp->h_addrtype;
425 memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
426 hostname = (char *)hp->h_name;
428 datalen = atoi(*argv);
429 if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
430 error_msg_and_die("packet size must be 0 <= s < %d.",
431 MAXPACKET - sizeof(struct opacket));
432 datalen += sizeof(struct opacket);
433 outpacket = (struct opacket *)xmalloc((unsigned)datalen);
434 memset(outpacket, 0, datalen);
435 outpacket->ip.ip_dst = to->sin_addr;
436 outpacket->ip.ip_tos = tos;
437 outpacket->ip.ip_v = IPVERSION;
438 outpacket->ip.ip_id = 0;
440 ident = (getpid() & 0xffff) | 0x8000;
442 if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
443 perror_msg_and_die(can_not_create_raw_socket);
445 s = create_icmp_socket();
447 #ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
448 if (options & SO_DEBUG)
449 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
450 (char *)&on, sizeof(on));
452 if (options & SO_DONTROUTE)
453 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
454 (char *)&on, sizeof(on));
456 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
457 sizeof(datalen)) < 0)
458 perror_msg_and_die("SO_SNDBUF");
461 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
463 perror_msg_and_die("IP_HDRINCL");
465 #ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
466 if (options & SO_DEBUG)
467 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
468 (char *)&on, sizeof(on));
470 if (options & SO_DONTROUTE)
471 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
472 (char *)&on, sizeof(on));
475 memset(&from, 0, sizeof(struct sockaddr));
476 from.sin_family = AF_INET;
477 from.sin_addr.s_addr = inet_addr(source);
478 if (from.sin_addr.s_addr == -1)
479 error_msg_and_die("unknown host %s", source);
480 outpacket->ip.ip_src = from.sin_addr;
482 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
483 perror_msg_and_die("bind");
487 fprintf(stderr, "traceroute to %s (%s)", hostname,
488 inet_ntoa(to->sin_addr));
490 fprintf(stderr, " from %s", source);
491 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
493 for (ttl = 1; ttl <= max_ttl; ++ttl) {
499 for (probe = 0; probe < nprobes; ++probe) {
501 struct timeval t1, t2;
505 (void) gettimeofday(&t1, &tz);
506 send_probe(++seq, ttl);
508 while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
509 (void) gettimeofday(&t2, &tz);
510 if ((i = packet_ok(packet, cc, &from, seq))) {
512 if (from.sin_addr.s_addr != lastaddr) {
513 print(packet, cc, &from);
514 lastaddr = from.sin_addr.s_addr;
516 printf(" %g ms", deltaT(&t1, &t2));
518 case ICMP_UNREACH_PORT:
519 ip = (struct ip *)packet;
524 case ICMP_UNREACH_NET:
528 case ICMP_UNREACH_HOST:
532 case ICMP_UNREACH_PROTOCOL:
536 case ICMP_UNREACH_NEEDFRAG:
540 case ICMP_UNREACH_SRCFAIL:
551 (void) fflush(stdout);
554 if (got_there || unreachable >= nprobes-1)