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. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * traceroute host - trace the route ip packets follow going to "host".
38 * This program must be run by root or be setuid. (I suggest that
39 * you *don't* make it setuid -- casual use could result in a lot
40 * of unnecessary traffic on our poor, congested nets.)
42 * I stole the idea for this program from Steve Deering. Since
43 * the first release, I've learned that had I attended the right
44 * IETF working group meetings, I also could have stolen it from Guy
45 * Almes or Matt Mathis. I don't know (or care) who came up with
46 * the idea first. I envy the originators' perspicacity and I'm
47 * glad they didn't keep the idea a secret.
49 * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
50 * enhancements to the original distribution.
52 * I've hacked up a round-trip-route version of this that works by
53 * sending a loose-source-routed udp datagram through the destination
54 * back to yourself. Unfortunately, SO many gateways botch source
55 * routing, the thing is almost worthless. Maybe one day...
57 * -- Van Jacobson (van@helios.ee.lbl.gov)
58 * Tue Dec 20 03:50:13 PST 1988
61 #undef CONFIG_FEATURE_TRACEROUTE_VERBOSE
62 //#define CONFIG_FEATURE_TRACEROUTE_VERBOSE
63 #undef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG /* not in documentation man */
71 #include "inet_common.h"
74 #include <netinet/udp.h>
75 #include <netinet/ip.h>
76 #include <netinet/ip_icmp.h>
79 #define MAXPACKET 65535 /* max ip packet size */
80 #ifndef MAXHOSTNAMELEN
81 #define MAXHOSTNAMELEN 64
85 * format of a (udp) probe packet.
90 u_char seq; /* sequence number of this packet */
91 u_char ttl; /* ttl packet left with */
92 struct timeval tv; /* time packet left */
96 * Definitions for internet protocol version 4.
97 * Per RFC 791, September 1981.
104 static u_char packet[512]; /* last inbound (icmp) packet */
105 static struct opacket *outpacket; /* last output (udp) packet */
107 static int s; /* receive (icmp) socket file descriptor */
108 static int sndsock; /* send (udp) socket file descriptor */
110 static struct sockaddr whereto; /* Who to try to reach */
111 static int datalen; /* How much data */
113 static char *hostname;
115 static int max_ttl = 30;
116 static u_short ident;
117 static u_short port = 32768+666; /* start udp dest port # for probe packets */
119 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
122 static int waittime = 5; /* time to wait for response (in seconds) */
123 static int nflag; /* print addresses numerically */
126 * Construct an Internet address representation.
127 * If the nflag has been supplied, give
128 * numeric value, otherwise try for symbolic name.
131 inetname(struct sockaddr_in *from)
134 static char domain[MAXHOSTNAMELEN + 1];
135 char name[MAXHOSTNAMELEN + 1];
136 static int first = 1;
139 if (first && !nflag) {
141 if (getdomainname(domain, MAXHOSTNAMELEN) != 0)
145 if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
146 if(INET_rresolve(name, sizeof(name), from, 0x4000, 0xffffffff) >= 0) {
147 if ((cp = strchr(name, '.')) &&
148 !strcmp(cp + 1, domain))
153 ina = inet_ntoa(from->sin_addr);
157 printf(" %s (%s)", (cp ? cp : ina), ina);
161 print(u_char *buf, int cc, struct sockaddr_in *from)
166 ip = (struct ip *) buf;
167 hlen = ip->ip_hl << 2;
171 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
173 printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
178 deltaT(struct timeval *t1p, struct timeval *t2p)
182 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
183 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
188 wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer)
191 static struct timeval wait;
193 int fromlen = sizeof (*from);
199 * traceroute could hang if someone else has a ping
200 * running and our ICMP reply gets dropped but we don't
201 * realize it because we keep waking up to handle those
202 * other ICMP packets that keep coming in. To fix this,
203 * "reset_timer" will only be true if the last packet that
204 * came in was for us or if this is the first time we're
205 * waiting for a reply since sending out a probe. Note
206 * that this takes advantage of the select() feature on
207 * Linux where the remaining timeout is written to the
208 * struct timeval area.
210 wait.tv_sec = waittime;
214 if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
215 cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
216 (struct sockaddr *)from, &fromlen);
221 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
223 * Convert an ICMP "type" field to a printable string.
225 static inline const char *
228 static const char * const ttab[] = {
229 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
230 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
231 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
232 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
237 return("OUT-OF-RANGE");
244 packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
251 ip = (struct ip *) buf;
252 hlen = ip->ip_hl << 2;
253 if (cc < hlen + ICMP_MINLEN) {
254 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
256 printf("packet too short (%d bytes) from %s\n", cc,
257 inet_ntoa(from->sin_addr));
262 icp = (struct icmp *)(buf + hlen);
263 type = icp->icmp_type; code = icp->icmp_code;
264 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
265 type == ICMP_UNREACH) {
270 hlen = hip->ip_hl << 2;
271 up = (struct udphdr *)((u_char *)hip + hlen);
272 if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
273 up->source == htons(ident) &&
274 up->dest == htons(port+seq))
275 return (type == ICMP_TIMXCEED? -1 : code+1);
277 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
280 u_long *lp = (u_long *)&icp->icmp_ip;
282 printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
283 cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst),
284 type, pr_type(type), icp->icmp_code);
285 for (i = 4; i < cc ; i += sizeof(long))
286 printf("%2d: x%8.8lx\n", i, *lp++);
292 static void /* not inline */
293 send_probe(int seq, int ttl)
295 struct opacket *op = outpacket;
296 struct ip *ip = &op->ip;
297 struct udphdr *up = &op->udp;
302 ip->ip_hl = sizeof(*ip) >> 2;
303 ip->ip_p = IPPROTO_UDP;
304 ip->ip_len = datalen;
306 ip->ip_v = IPVERSION;
307 ip->ip_id = htons(ident+seq);
309 up->source = htons(ident);
310 up->dest = htons(port+seq);
311 up->len = htons((u_short)(datalen - sizeof(struct ip)));
316 (void) gettimeofday(&op->tv, &tz);
318 i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
319 sizeof(struct sockaddr));
320 if (i < 0 || i != datalen) {
323 printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
325 (void) fflush(stdout);
331 #ifndef CONFIG_TRACEROUTE
332 main(int argc, char *argv[])
334 traceroute_main(int argc, char *argv[])
340 struct sockaddr_in from, *to;
341 int ch, i, on, probe, seq, tos, ttl;
343 int options = 0; /* socket options */
349 to = (struct sockaddr_in *)&whereto;
350 while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
353 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
358 max_ttl = atoi(optarg);
360 bb_error_msg_and_die("max ttl must be >1.");
368 bb_error_msg_and_die("port must be >0.");
371 nprobes = atoi(optarg);
373 bb_error_msg_and_die("nprobes must be >0.");
376 options |= SO_DONTROUTE;
380 * set the ip source address of the outbound
381 * probe (e.g., on a multi-homed host).
387 if (tos < 0 || tos > 255)
388 bb_error_msg_and_die("tos must be 0 to 255.");
391 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
396 waittime = atoi(optarg);
398 bb_error_msg_and_die("wait must be >1 sec.");
411 memset(&whereto, 0, sizeof(struct sockaddr));
412 hp = xgethostbyname(*argv);
413 to->sin_family = hp->h_addrtype;
414 memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
415 hostname = (char *)hp->h_name;
417 datalen = atoi(*argv);
418 if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
419 bb_error_msg_and_die("packet size must be 0 <= s < %d.",
420 MAXPACKET - sizeof(struct opacket));
421 datalen += sizeof(struct opacket);
422 outpacket = (struct opacket *)xmalloc((unsigned)datalen);
423 memset(outpacket, 0, datalen);
424 outpacket->ip.ip_dst = to->sin_addr;
425 outpacket->ip.ip_tos = tos;
426 outpacket->ip.ip_v = IPVERSION;
427 outpacket->ip.ip_id = 0;
429 ident = (getpid() & 0xffff) | 0x8000;
431 if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
432 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
434 s = create_icmp_socket();
436 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
437 if (options & SO_DEBUG)
438 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
439 (char *)&on, sizeof(on));
441 if (options & SO_DONTROUTE)
442 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
443 (char *)&on, sizeof(on));
445 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
446 sizeof(datalen)) < 0)
447 bb_perror_msg_and_die("SO_SNDBUF");
450 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
452 bb_perror_msg_and_die("IP_HDRINCL");
454 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
455 if (options & SO_DEBUG)
456 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
457 (char *)&on, sizeof(on));
459 if (options & SO_DONTROUTE)
460 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
461 (char *)&on, sizeof(on));
464 memset(&from, 0, sizeof(struct sockaddr));
465 from.sin_family = AF_INET;
466 from.sin_addr.s_addr = inet_addr(source);
467 if (from.sin_addr.s_addr == -1)
468 bb_error_msg_and_die("unknown host %s", source);
469 outpacket->ip.ip_src = from.sin_addr;
471 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
472 bb_perror_msg_and_die("bind");
476 fprintf(stderr, "traceroute to %s (%s)", hostname,
477 inet_ntoa(to->sin_addr));
479 fprintf(stderr, " from %s", source);
480 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
482 for (ttl = 1; ttl <= max_ttl; ++ttl) {
488 for (probe = 0; probe < nprobes; ++probe) {
490 struct timeval t1, t2;
494 (void) gettimeofday(&t1, &tz);
495 send_probe(++seq, ttl);
497 while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
498 (void) gettimeofday(&t2, &tz);
499 if ((i = packet_ok(packet, cc, &from, seq))) {
501 if (from.sin_addr.s_addr != lastaddr) {
502 print(packet, cc, &from);
503 lastaddr = from.sin_addr.s_addr;
505 printf(" %g ms", deltaT(&t1, &t2));
507 case ICMP_UNREACH_PORT:
508 ip = (struct ip *)packet;
513 case ICMP_UNREACH_NET:
517 case ICMP_UNREACH_HOST:
521 case ICMP_UNREACH_PROTOCOL:
525 case ICMP_UNREACH_NEEDFRAG:
529 case ICMP_UNREACH_SRCFAIL:
540 (void) fflush(stdout);
543 if (got_there || unreachable >= nprobes-1)