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 in_addr in)
138 static char line[50];
140 static char domain[MAXHOSTNAMELEN + 1];
141 static int first = 1;
143 if (first && !nflag) {
145 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
146 (cp = index(domain, '.')))
147 (void) strcpy(domain, cp + 1);
152 if (!nflag && in.s_addr != INADDR_ANY) {
153 hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
155 if ((cp = index(hp->h_name, '.')) &&
156 !strcmp(cp + 1, domain))
158 cp = (char *)hp->h_name;
162 (void) strcpy(line, cp);
164 in.s_addr = ntohl(in.s_addr);
165 strcpy(line, inet_ntoa(in));
171 print(u_char *buf, int cc, struct sockaddr_in *from)
176 ip = (struct ip *) buf;
177 hlen = ip->ip_hl << 2;
181 printf(" %s", inet_ntoa(from->sin_addr));
183 printf(" %s (%s)", inetname(from->sin_addr),
184 inet_ntoa(from->sin_addr));
186 #ifdef BB_FEATURE_TRACEROUTE_VERBOSE
188 printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
193 deltaT(struct timeval *t1p, struct timeval *t2p)
197 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
198 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
203 wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer)
206 static struct timeval wait;
208 int fromlen = sizeof (*from);
214 * traceroute could hang if someone else has a ping
215 * running and our ICMP reply gets dropped but we don't
216 * realize it because we keep waking up to handle those
217 * other ICMP packets that keep coming in. To fix this,
218 * "reset_timer" will only be true if the last packet that
219 * came in was for us or if this is the first time we're
220 * waiting for a reply since sending out a probe. Note
221 * that this takes advantage of the select() feature on
222 * Linux where the remaining timeout is written to the
223 * struct timeval area.
225 wait.tv_sec = waittime;
229 if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
230 cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
231 (struct sockaddr *)from, &fromlen);
236 #ifdef BB_FEATURE_TRACEROUTE_VERBOSE
238 * Convert an ICMP "type" field to a printable string.
240 static inline const char *
244 static const char * const ttab[] = {
245 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
246 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
247 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
248 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
253 return("OUT-OF-RANGE");
260 packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
267 ip = (struct ip *) buf;
268 hlen = ip->ip_hl << 2;
269 if (cc < hlen + ICMP_MINLEN) {
270 #ifdef BB_FEATURE_TRACEROUTE_VERBOSE
272 printf("packet too short (%d bytes) from %s\n", cc,
273 inet_ntoa(from->sin_addr));
278 icp = (struct icmp *)(buf + hlen);
279 type = icp->icmp_type; code = icp->icmp_code;
280 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
281 type == ICMP_UNREACH) {
286 hlen = hip->ip_hl << 2;
287 up = (struct udphdr *)((u_char *)hip + hlen);
288 if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
289 up->source == htons(ident) &&
290 up->dest == htons(port+seq))
291 return (type == ICMP_TIMXCEED? -1 : code+1);
293 #ifdef BB_FEATURE_TRACEROUTE_VERBOSE
296 u_long *lp = (u_long *)&icp->icmp_ip;
298 printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
299 cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst),
300 type, pr_type(type), icp->icmp_code);
301 for (i = 4; i < cc ; i += sizeof(long))
302 printf("%2d: x%8.8lx\n", i, *lp++);
308 static void /* not inline */
309 send_probe(int seq, int ttl)
311 struct opacket *op = outpacket;
312 struct ip *ip = &op->ip;
313 struct udphdr *up = &op->udp;
318 ip->ip_hl = sizeof(*ip) >> 2;
319 ip->ip_p = IPPROTO_UDP;
320 ip->ip_len = datalen;
322 ip->ip_v = IPVERSION;
323 ip->ip_id = htons(ident+seq);
325 up->source = htons(ident);
326 up->dest = htons(port+seq);
327 up->len = htons((u_short)(datalen - sizeof(struct ip)));
332 (void) gettimeofday(&op->tv, &tz);
334 i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
335 sizeof(struct sockaddr));
336 if (i < 0 || i != datalen) {
339 printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
341 (void) fflush(stdout);
347 #ifndef BB_TRACEROUTE
350 traceroute_main(argc, argv)
358 struct sockaddr_in from, *to;
359 int ch, i, on, probe, seq, tos, ttl;
361 int options = 0; /* socket options */
367 to = (struct sockaddr_in *)&whereto;
368 while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
371 #ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
376 max_ttl = atoi(optarg);
378 error_msg_and_die("max ttl must be >1.");
386 error_msg_and_die("port must be >0.");
389 nprobes = atoi(optarg);
391 error_msg_and_die("nprobes must be >0.");
394 options |= SO_DONTROUTE;
398 * set the ip source address of the outbound
399 * probe (e.g., on a multi-homed host).
405 if (tos < 0 || tos > 255)
406 error_msg_and_die("tos must be 0 to 255.");
409 #ifdef BB_FEATURE_TRACEROUTE_VERBOSE
414 waittime = atoi(optarg);
416 error_msg_and_die("wait must be >1 sec.");
429 memset(&whereto, 0, sizeof(struct sockaddr));
430 hp = xgethostbyname(*argv);
431 to->sin_family = hp->h_addrtype;
432 memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
433 hostname = (char *)hp->h_name;
435 datalen = atoi(*argv);
436 if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
437 error_msg_and_die("packet size must be 0 <= s < %d.",
438 MAXPACKET - sizeof(struct opacket));
439 datalen += sizeof(struct opacket);
440 outpacket = (struct opacket *)xmalloc((unsigned)datalen);
441 memset(outpacket, 0, datalen);
442 outpacket->ip.ip_dst = to->sin_addr;
443 outpacket->ip.ip_tos = tos;
444 outpacket->ip.ip_v = IPVERSION;
445 outpacket->ip.ip_id = 0;
447 ident = (getpid() & 0xffff) | 0x8000;
449 if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
450 perror_msg_and_die(can_not_create_raw_socket);
452 s = create_icmp_socket();
454 #ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
455 if (options & SO_DEBUG)
456 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
457 (char *)&on, sizeof(on));
459 if (options & SO_DONTROUTE)
460 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
461 (char *)&on, sizeof(on));
463 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
464 sizeof(datalen)) < 0)
465 perror_msg_and_die("SO_SNDBUF");
468 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
470 perror_msg_and_die("IP_HDRINCL");
472 #ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
473 if (options & SO_DEBUG)
474 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
475 (char *)&on, sizeof(on));
477 if (options & SO_DONTROUTE)
478 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
479 (char *)&on, sizeof(on));
482 memset(&from, 0, sizeof(struct sockaddr));
483 from.sin_family = AF_INET;
484 from.sin_addr.s_addr = inet_addr(source);
485 if (from.sin_addr.s_addr == -1)
486 error_msg_and_die("unknown host %s", source);
487 outpacket->ip.ip_src = from.sin_addr;
489 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
490 perror_msg_and_die("bind");
494 fprintf(stderr, "traceroute to %s (%s)", hostname,
495 inet_ntoa(to->sin_addr));
497 fprintf(stderr, " from %s", source);
498 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
500 for (ttl = 1; ttl <= max_ttl; ++ttl) {
506 for (probe = 0; probe < nprobes; ++probe) {
508 struct timeval t1, t2;
512 (void) gettimeofday(&t1, &tz);
513 send_probe(++seq, ttl);
515 while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
516 (void) gettimeofday(&t2, &tz);
517 if ((i = packet_ok(packet, cc, &from, seq))) {
519 if (from.sin_addr.s_addr != lastaddr) {
520 print(packet, cc, &from);
521 lastaddr = from.sin_addr.s_addr;
523 printf(" %g ms", deltaT(&t1, &t2));
525 case ICMP_UNREACH_PORT:
526 ip = (struct ip *)packet;
531 case ICMP_UNREACH_NET:
535 case ICMP_UNREACH_HOST:
539 case ICMP_UNREACH_PROTOCOL:
543 case ICMP_UNREACH_NEEDFRAG:
547 case ICMP_UNREACH_SRCFAIL:
558 (void) fflush(stdout);
561 if (got_there || unreachable >= nprobes-1)