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 /* last inbound (icmp) packet */
105 static u_char packet[512] __attribute__ ((aligned));
106 static struct opacket *outpacket; /* last output (udp) packet */
108 static int s; /* receive (icmp) socket file descriptor */
109 static int sndsock; /* send (udp) socket file descriptor */
111 static struct sockaddr whereto; /* Who to try to reach */
112 static int datalen; /* How much data */
114 static char *hostname;
116 static int max_ttl = 30;
117 static u_short ident;
118 static u_short port = 32768+666; /* start udp dest port # for probe packets */
120 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
123 static int waittime = 5; /* time to wait for response (in seconds) */
124 static int nflag; /* print addresses numerically */
127 * Construct an Internet address representation.
128 * If the nflag has been supplied, give
129 * numeric value, otherwise try for symbolic name.
132 inetname(struct sockaddr_in *from)
135 static char domain[MAXHOSTNAMELEN + 1];
136 char name[MAXHOSTNAMELEN + 1];
137 static int first = 1;
140 if (first && !nflag) {
142 if (getdomainname(domain, MAXHOSTNAMELEN) != 0)
146 if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
147 if(INET_rresolve(name, sizeof(name), from, 0x4000, 0xffffffff) >= 0) {
148 if ((cp = strchr(name, '.')) &&
149 !strcmp(cp + 1, domain))
154 ina = inet_ntoa(from->sin_addr);
158 printf(" %s (%s)", (cp ? cp : ina), ina);
162 print(u_char *buf, int cc, struct sockaddr_in *from)
167 ip = (struct ip *) buf;
168 hlen = ip->ip_hl << 2;
172 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
174 printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
179 deltaT(struct timeval *t1p, struct timeval *t2p)
183 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
184 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
189 wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer)
192 static struct timeval wait;
194 int fromlen = sizeof (*from);
200 * traceroute could hang if someone else has a ping
201 * running and our ICMP reply gets dropped but we don't
202 * realize it because we keep waking up to handle those
203 * other ICMP packets that keep coming in. To fix this,
204 * "reset_timer" will only be true if the last packet that
205 * came in was for us or if this is the first time we're
206 * waiting for a reply since sending out a probe. Note
207 * that this takes advantage of the select() feature on
208 * Linux where the remaining timeout is written to the
209 * struct timeval area.
211 wait.tv_sec = waittime;
215 if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
216 cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
217 (struct sockaddr *)from, &fromlen);
222 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
224 * Convert an ICMP "type" field to a printable string.
226 static inline const char *
229 static const char * const ttab[] = {
230 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
231 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
232 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
233 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
238 return("OUT-OF-RANGE");
245 packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
252 ip = (struct ip *) buf;
253 hlen = ip->ip_hl << 2;
254 if (cc < hlen + ICMP_MINLEN) {
255 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
257 printf("packet too short (%d bytes) from %s\n", cc,
258 inet_ntoa(from->sin_addr));
263 icp = (struct icmp *)(buf + hlen);
264 type = icp->icmp_type; code = icp->icmp_code;
265 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
266 type == ICMP_UNREACH) {
271 hlen = hip->ip_hl << 2;
272 up = (struct udphdr *)((u_char *)hip + hlen);
273 if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
274 up->source == htons(ident) &&
275 up->dest == htons(port+seq))
276 return (type == ICMP_TIMXCEED? -1 : code+1);
278 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
281 u_long *lp = (u_long *)&icp->icmp_ip;
283 printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
284 cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst),
285 type, pr_type(type), icp->icmp_code);
286 for (i = 4; i < cc ; i += sizeof(long))
287 printf("%2d: x%8.8lx\n", i, *lp++);
293 static void /* not inline */
294 send_probe(int seq, int ttl)
296 struct opacket *op = outpacket;
297 struct ip *ip = &op->ip;
298 struct udphdr *up = &op->udp;
303 ip->ip_hl = sizeof(*ip) >> 2;
304 ip->ip_p = IPPROTO_UDP;
305 ip->ip_len = datalen;
307 ip->ip_v = IPVERSION;
308 ip->ip_id = htons(ident+seq);
310 up->source = htons(ident);
311 up->dest = htons(port+seq);
312 up->len = htons((u_short)(datalen - sizeof(struct ip)));
317 (void) gettimeofday(&op->tv, &tz);
319 i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
320 sizeof(struct sockaddr));
321 if (i < 0 || i != datalen) {
324 printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
326 (void) fflush(stdout);
332 #ifndef CONFIG_TRACEROUTE
333 main(int argc, char *argv[])
335 traceroute_main(int argc, char *argv[])
341 struct sockaddr_in from, *to;
342 int ch, i, on, probe, seq, tos, ttl;
344 int options = 0; /* socket options */
350 to = (struct sockaddr_in *)&whereto;
351 while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
354 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
359 max_ttl = atoi(optarg);
361 bb_error_msg_and_die("max ttl must be >1.");
369 bb_error_msg_and_die("port must be >0.");
372 nprobes = atoi(optarg);
374 bb_error_msg_and_die("nprobes must be >0.");
377 options |= SO_DONTROUTE;
381 * set the ip source address of the outbound
382 * probe (e.g., on a multi-homed host).
388 if (tos < 0 || tos > 255)
389 bb_error_msg_and_die("tos must be 0 to 255.");
392 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
397 waittime = atoi(optarg);
399 bb_error_msg_and_die("wait must be >1 sec.");
412 memset(&whereto, 0, sizeof(struct sockaddr));
413 hp = xgethostbyname(*argv);
414 to->sin_family = hp->h_addrtype;
415 memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
416 hostname = (char *)hp->h_name;
418 datalen = atoi(*argv);
419 if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
420 bb_error_msg_and_die("packet size must be 0 <= s < %d.",
421 (int)(MAXPACKET - sizeof(struct opacket)));
422 datalen += sizeof(struct opacket);
423 outpacket = (struct opacket *)xmalloc((unsigned)datalen);
424 memset(outpacket, 0, datalen);
425 outpacket->ip.ip_dst = to->sin_addr;
426 outpacket->ip.ip_tos = tos;
427 outpacket->ip.ip_v = IPVERSION;
428 outpacket->ip.ip_id = 0;
430 ident = (getpid() & 0xffff) | 0x8000;
432 if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
433 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
435 s = create_icmp_socket();
437 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
438 if (options & SO_DEBUG)
439 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
440 (char *)&on, sizeof(on));
442 if (options & SO_DONTROUTE)
443 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
444 (char *)&on, sizeof(on));
446 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
447 sizeof(datalen)) < 0)
448 bb_perror_msg_and_die("SO_SNDBUF");
451 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
453 bb_perror_msg_and_die("IP_HDRINCL");
455 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
456 if (options & SO_DEBUG)
457 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
458 (char *)&on, sizeof(on));
460 if (options & SO_DONTROUTE)
461 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
462 (char *)&on, sizeof(on));
465 memset(&from, 0, sizeof(struct sockaddr));
466 from.sin_family = AF_INET;
467 from.sin_addr.s_addr = inet_addr(source);
468 if (from.sin_addr.s_addr == -1)
469 bb_error_msg_and_die("unknown host %s", source);
470 outpacket->ip.ip_src = from.sin_addr;
472 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
473 bb_perror_msg_and_die("bind");
477 fprintf(stderr, "traceroute to %s (%s)", hostname,
478 inet_ntoa(to->sin_addr));
480 fprintf(stderr, " from %s", source);
481 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
483 for (ttl = 1; ttl <= max_ttl; ++ttl) {
489 for (probe = 0; probe < nprobes; ++probe) {
491 struct timeval t1, t2;
495 (void) gettimeofday(&t1, &tz);
496 send_probe(++seq, ttl);
498 while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
499 (void) gettimeofday(&t2, &tz);
500 if ((i = packet_ok(packet, cc, &from, seq))) {
502 if (from.sin_addr.s_addr != lastaddr) {
503 print(packet, cc, &from);
504 lastaddr = from.sin_addr.s_addr;
506 printf(" %g ms", deltaT(&t1, &t2));
508 case ICMP_UNREACH_PORT:
509 ip = (struct ip *)packet;
514 case ICMP_UNREACH_NET:
518 case ICMP_UNREACH_HOST:
522 case ICMP_UNREACH_PROTOCOL:
526 case ICMP_UNREACH_NEEDFRAG:
530 case ICMP_UNREACH_SRCFAIL:
541 (void) fflush(stdout);
544 if (got_there || unreachable >= nprobes-1)