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 #define MAXPACKET_ICMP 512
81 #ifndef MAXHOSTNAMELEN
82 #define MAXHOSTNAMELEN 64
86 * format of a (udp) probe packet.
91 u_char seq; /* sequence number of this packet */
92 u_char ttl; /* ttl packet left with */
93 struct timeval tv; /* time packet left */
97 * Definitions for internet protocol version 4.
98 * Per RFC 791, September 1981.
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, u_char *packet, int size)
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, size, 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;
344 int options = 0; /* socket options */
347 packet = xmalloc (MAXPACKET_ICMP);
351 to = (struct sockaddr_in *)&whereto;
352 while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
355 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
360 max_ttl = atoi(optarg);
362 bb_error_msg_and_die("max ttl must be >1.");
370 bb_error_msg_and_die("port must be >0.");
373 nprobes = atoi(optarg);
375 bb_error_msg_and_die("nprobes must be >0.");
378 options |= SO_DONTROUTE;
382 * set the ip source address of the outbound
383 * probe (e.g., on a multi-homed host).
389 if (tos < 0 || tos > 255)
390 bb_error_msg_and_die("tos must be 0 to 255.");
393 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
398 waittime = atoi(optarg);
400 bb_error_msg_and_die("wait must be >1 sec.");
413 memset(&whereto, 0, sizeof(struct sockaddr));
414 hp = xgethostbyname(*argv);
415 to->sin_family = hp->h_addrtype;
416 memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
417 hostname = (char *)hp->h_name;
419 datalen = atoi(*argv);
420 if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
421 bb_error_msg_and_die("packet size must be 0 <= s < %d.",
422 MAXPACKET - sizeof(struct opacket));
423 datalen += sizeof(struct opacket);
424 outpacket = (struct opacket *)xmalloc((unsigned)datalen);
425 memset(outpacket, 0, datalen);
426 outpacket->ip.ip_dst = to->sin_addr;
427 outpacket->ip.ip_tos = tos;
428 outpacket->ip.ip_v = IPVERSION;
429 outpacket->ip.ip_id = 0;
431 ident = (getpid() & 0xffff) | 0x8000;
433 if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
434 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
436 s = create_icmp_socket();
438 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
439 if (options & SO_DEBUG)
440 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
441 (char *)&on, sizeof(on));
443 if (options & SO_DONTROUTE)
444 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
445 (char *)&on, sizeof(on));
447 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
448 sizeof(datalen)) < 0)
449 bb_perror_msg_and_die("SO_SNDBUF");
452 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
454 bb_perror_msg_and_die("IP_HDRINCL");
456 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
457 if (options & SO_DEBUG)
458 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
459 (char *)&on, sizeof(on));
461 if (options & SO_DONTROUTE)
462 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
463 (char *)&on, sizeof(on));
466 memset(&from, 0, sizeof(struct sockaddr));
467 from.sin_family = AF_INET;
468 from.sin_addr.s_addr = inet_addr(source);
469 if (from.sin_addr.s_addr == -1)
470 bb_error_msg_and_die("unknown host %s", source);
471 outpacket->ip.ip_src = from.sin_addr;
473 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
474 bb_perror_msg_and_die("bind");
478 fprintf(stderr, "traceroute to %s (%s)", hostname,
479 inet_ntoa(to->sin_addr));
481 fprintf(stderr, " from %s", source);
482 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
484 for (ttl = 1; ttl <= max_ttl; ++ttl) {
490 for (probe = 0; probe < nprobes; ++probe) {
492 struct timeval t1, t2;
496 (void) gettimeofday(&t1, &tz);
497 send_probe(++seq, ttl);
499 while ((cc = wait_for_reply(s, &from, reset_timer, packet, MAXPACKET_ICMP)) != 0) {
500 (void) gettimeofday(&t2, &tz);
501 if ((i = packet_ok(packet, cc, &from, seq))) {
503 if (from.sin_addr.s_addr != lastaddr) {
504 print(packet, cc, &from);
505 lastaddr = from.sin_addr.s_addr;
507 printf(" %g ms", deltaT(&t1, &t2));
509 case ICMP_UNREACH_PORT:
510 ip = (struct ip *)packet;
515 case ICMP_UNREACH_NET:
519 case ICMP_UNREACH_HOST:
523 case ICMP_UNREACH_PROTOCOL:
527 case ICMP_UNREACH_NEEDFRAG:
531 case ICMP_UNREACH_SRCFAIL:
542 (void) fflush(stdout);
545 if (got_there || unreachable >= nprobes-1)