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 /* It turns out that libc5 doesn't have proper icmp support
80 * built into it header files, so we have to supplement it */
81 #if __GNU_LIBRARY__ < 5
82 static const int ICMP_MINLEN = 8; /* abs minimum */
87 u_int32_t ira_preference;
93 u_int8_t icmp_type; /* type of message, see below */
94 u_int8_t icmp_code; /* type sub code */
95 u_int16_t icmp_cksum; /* ones complement checksum of struct */
98 u_char ih_pptr; /* ICMP_PARAMPROB */
99 struct in_addr ih_gwaddr; /* gateway address */
100 struct ih_idseq /* echo datagram */
107 /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
111 u_int16_t ipm_nextmtu;
116 u_int8_t irt_num_addrs;
118 u_int16_t irt_lifetime;
121 #define icmp_pptr icmp_hun.ih_pptr
122 #define icmp_gwaddr icmp_hun.ih_gwaddr
123 #define icmp_id icmp_hun.ih_idseq.icd_id
124 #define icmp_seq icmp_hun.ih_idseq.icd_seq
125 #define icmp_void icmp_hun.ih_void
126 #define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
127 #define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
128 #define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
129 #define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
130 #define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
142 /* options and then 64 bits of data */
144 struct icmp_ra_addr id_radv;
148 #define icmp_otime icmp_dun.id_ts.its_otime
149 #define icmp_rtime icmp_dun.id_ts.its_rtime
150 #define icmp_ttime icmp_dun.id_ts.its_ttime
151 #define icmp_ip icmp_dun.id_ip.idi_ip
152 #define icmp_radv icmp_dun.id_radv
153 #define icmp_mask icmp_dun.id_mask
154 #define icmp_data icmp_dun.id_data
157 #define ICMP_MINLEN 8 /* abs minimum */
158 #define ICMP_UNREACH 3 /* dest unreachable, codes: */
159 #define ICMP_TIMXCEED 11 /* time exceeded, code: */
160 #define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */
161 #define ICMP_UNREACH_NET 0 /* bad net */
162 #define ICMP_UNREACH_HOST 1 /* bad host */
163 #define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */
164 #define ICMP_UNREACH_PORT 3 /* bad port */
165 #define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */
166 #define ICMP_UNREACH_SRCFAIL 5 /* src route failed */
170 #define MAXPACKET 65535 /* max ip packet size */
171 #ifndef MAXHOSTNAMELEN
172 #define MAXHOSTNAMELEN 64
176 * format of a (udp) probe packet.
181 u_char seq; /* sequence number of this packet */
182 u_char ttl; /* ttl packet left with */
183 struct timeval tv; /* time packet left */
187 * Definitions for internet protocol version 4.
188 * Per RFC 791, September 1981.
195 static u_char packet[512]; /* last inbound (icmp) packet */
196 static struct opacket *outpacket; /* last output (udp) packet */
198 static int s; /* receive (icmp) socket file descriptor */
199 static int sndsock; /* send (udp) socket file descriptor */
201 static struct sockaddr whereto; /* Who to try to reach */
202 static int datalen; /* How much data */
204 static char *hostname;
206 static int max_ttl = 30;
207 static u_short ident;
208 static u_short port = 32768+666; /* start udp dest port # for probe packets */
210 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
213 static int waittime = 5; /* time to wait for response (in seconds) */
214 static int nflag; /* print addresses numerically */
217 * Construct an Internet address representation.
218 * If the nflag has been supplied, give
219 * numeric value, otherwise try for symbolic name.
222 inetname(struct sockaddr_in *from)
225 static char domain[MAXHOSTNAMELEN + 1];
226 char name[MAXHOSTNAMELEN + 1];
227 static int first = 1;
230 if (first && !nflag) {
232 if (getdomainname(domain, MAXHOSTNAMELEN) != 0)
236 if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
237 if(INET_rresolve(name, sizeof(name), from, 0x4000, 0xffffffff) >= 0) {
238 if ((cp = strchr(name, '.')) &&
239 !strcmp(cp + 1, domain))
244 ina = inet_ntoa(from->sin_addr);
248 printf(" %s (%s)", (cp ? cp : ina), ina);
252 print(u_char *buf, int cc, struct sockaddr_in *from)
257 ip = (struct ip *) buf;
258 hlen = ip->ip_hl << 2;
262 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
264 printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
269 deltaT(struct timeval *t1p, struct timeval *t2p)
273 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
274 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
279 wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer)
282 static struct timeval wait;
284 int fromlen = sizeof (*from);
290 * traceroute could hang if someone else has a ping
291 * running and our ICMP reply gets dropped but we don't
292 * realize it because we keep waking up to handle those
293 * other ICMP packets that keep coming in. To fix this,
294 * "reset_timer" will only be true if the last packet that
295 * came in was for us or if this is the first time we're
296 * waiting for a reply since sending out a probe. Note
297 * that this takes advantage of the select() feature on
298 * Linux where the remaining timeout is written to the
299 * struct timeval area.
301 wait.tv_sec = waittime;
305 if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
306 cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
307 (struct sockaddr *)from, &fromlen);
312 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
314 * Convert an ICMP "type" field to a printable string.
316 static inline const char *
319 static const char * const ttab[] = {
320 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
321 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
322 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
323 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
328 return("OUT-OF-RANGE");
335 packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
342 ip = (struct ip *) buf;
343 hlen = ip->ip_hl << 2;
344 if (cc < hlen + ICMP_MINLEN) {
345 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
347 printf("packet too short (%d bytes) from %s\n", cc,
348 inet_ntoa(from->sin_addr));
353 icp = (struct icmp *)(buf + hlen);
354 type = icp->icmp_type; code = icp->icmp_code;
355 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
356 type == ICMP_UNREACH) {
361 hlen = hip->ip_hl << 2;
362 up = (struct udphdr *)((u_char *)hip + hlen);
363 if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
364 up->source == htons(ident) &&
365 up->dest == htons(port+seq))
366 return (type == ICMP_TIMXCEED? -1 : code+1);
368 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
371 u_long *lp = (u_long *)&icp->icmp_ip;
373 printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
374 cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst),
375 type, pr_type(type), icp->icmp_code);
376 for (i = 4; i < cc ; i += sizeof(long))
377 printf("%2d: x%8.8lx\n", i, *lp++);
383 static void /* not inline */
384 send_probe(int seq, int ttl)
386 struct opacket *op = outpacket;
387 struct ip *ip = &op->ip;
388 struct udphdr *up = &op->udp;
393 ip->ip_hl = sizeof(*ip) >> 2;
394 ip->ip_p = IPPROTO_UDP;
395 ip->ip_len = datalen;
397 ip->ip_v = IPVERSION;
398 ip->ip_id = htons(ident+seq);
400 up->source = htons(ident);
401 up->dest = htons(port+seq);
402 up->len = htons((u_short)(datalen - sizeof(struct ip)));
407 (void) gettimeofday(&op->tv, &tz);
409 i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
410 sizeof(struct sockaddr));
411 if (i < 0 || i != datalen) {
414 printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
416 (void) fflush(stdout);
422 #ifndef CONFIG_TRACEROUTE
423 main(int argc, char *argv[])
425 traceroute_main(int argc, char *argv[])
431 struct sockaddr_in from, *to;
432 int ch, i, on, probe, seq, tos, ttl;
434 int options = 0; /* socket options */
440 to = (struct sockaddr_in *)&whereto;
441 while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
444 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
449 max_ttl = atoi(optarg);
451 error_msg_and_die("max ttl must be >1.");
459 error_msg_and_die("port must be >0.");
462 nprobes = atoi(optarg);
464 error_msg_and_die("nprobes must be >0.");
467 options |= SO_DONTROUTE;
471 * set the ip source address of the outbound
472 * probe (e.g., on a multi-homed host).
478 if (tos < 0 || tos > 255)
479 error_msg_and_die("tos must be 0 to 255.");
482 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
487 waittime = atoi(optarg);
489 error_msg_and_die("wait must be >1 sec.");
502 memset(&whereto, 0, sizeof(struct sockaddr));
503 hp = xgethostbyname(*argv);
504 to->sin_family = hp->h_addrtype;
505 memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
506 hostname = (char *)hp->h_name;
508 datalen = atoi(*argv);
509 if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
510 error_msg_and_die("packet size must be 0 <= s < %d.",
511 MAXPACKET - sizeof(struct opacket));
512 datalen += sizeof(struct opacket);
513 outpacket = (struct opacket *)xmalloc((unsigned)datalen);
514 memset(outpacket, 0, datalen);
515 outpacket->ip.ip_dst = to->sin_addr;
516 outpacket->ip.ip_tos = tos;
517 outpacket->ip.ip_v = IPVERSION;
518 outpacket->ip.ip_id = 0;
520 ident = (getpid() & 0xffff) | 0x8000;
522 if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
523 perror_msg_and_die(can_not_create_raw_socket);
525 s = create_icmp_socket();
527 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
528 if (options & SO_DEBUG)
529 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
530 (char *)&on, sizeof(on));
532 if (options & SO_DONTROUTE)
533 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
534 (char *)&on, sizeof(on));
536 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
537 sizeof(datalen)) < 0)
538 perror_msg_and_die("SO_SNDBUF");
541 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
543 perror_msg_and_die("IP_HDRINCL");
545 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
546 if (options & SO_DEBUG)
547 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
548 (char *)&on, sizeof(on));
550 if (options & SO_DONTROUTE)
551 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
552 (char *)&on, sizeof(on));
555 memset(&from, 0, sizeof(struct sockaddr));
556 from.sin_family = AF_INET;
557 from.sin_addr.s_addr = inet_addr(source);
558 if (from.sin_addr.s_addr == -1)
559 error_msg_and_die("unknown host %s", source);
560 outpacket->ip.ip_src = from.sin_addr;
562 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
563 perror_msg_and_die("bind");
567 fprintf(stderr, "traceroute to %s (%s)", hostname,
568 inet_ntoa(to->sin_addr));
570 fprintf(stderr, " from %s", source);
571 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
573 for (ttl = 1; ttl <= max_ttl; ++ttl) {
579 for (probe = 0; probe < nprobes; ++probe) {
581 struct timeval t1, t2;
585 (void) gettimeofday(&t1, &tz);
586 send_probe(++seq, ttl);
588 while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
589 (void) gettimeofday(&t2, &tz);
590 if ((i = packet_ok(packet, cc, &from, seq))) {
592 if (from.sin_addr.s_addr != lastaddr) {
593 print(packet, cc, &from);
594 lastaddr = from.sin_addr.s_addr;
596 printf(" %g ms", deltaT(&t1, &t2));
598 case ICMP_UNREACH_PORT:
599 ip = (struct ip *)packet;
604 case ICMP_UNREACH_NET:
608 case ICMP_UNREACH_HOST:
612 case ICMP_UNREACH_PROTOCOL:
616 case ICMP_UNREACH_NEEDFRAG:
620 case ICMP_UNREACH_SRCFAIL:
631 (void) fflush(stdout);
634 if (got_there || unreachable >= nprobes-1)