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 CONFIG_FEATURE_TRACEROUTE_VERBOSE
66 //#define CONFIG_FEATURE_TRACEROUTE_VERBOSE
67 #undef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG /* not in documentation man */
75 #include "inet_common.h"
78 #include <netinet/udp.h>
79 #include <netinet/ip.h>
80 #include <netinet/ip_icmp.h>
83 /* It turns out that libc5 doesn't have proper icmp support
84 * built into it header files, so we have to supplement it */
85 #if __GNU_LIBRARY__ < 5
86 static const int ICMP_MINLEN = 8; /* abs minimum */
91 u_int32_t ira_preference;
97 u_int8_t icmp_type; /* type of message, see below */
98 u_int8_t icmp_code; /* type sub code */
99 u_int16_t icmp_cksum; /* ones complement checksum of struct */
102 u_char ih_pptr; /* ICMP_PARAMPROB */
103 struct in_addr ih_gwaddr; /* gateway address */
104 struct ih_idseq /* echo datagram */
111 /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
115 u_int16_t ipm_nextmtu;
120 u_int8_t irt_num_addrs;
122 u_int16_t irt_lifetime;
125 #define icmp_pptr icmp_hun.ih_pptr
126 #define icmp_gwaddr icmp_hun.ih_gwaddr
127 #define icmp_id icmp_hun.ih_idseq.icd_id
128 #define icmp_seq icmp_hun.ih_idseq.icd_seq
129 #define icmp_void icmp_hun.ih_void
130 #define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
131 #define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
132 #define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
133 #define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
134 #define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
146 /* options and then 64 bits of data */
148 struct icmp_ra_addr id_radv;
152 #define icmp_otime icmp_dun.id_ts.its_otime
153 #define icmp_rtime icmp_dun.id_ts.its_rtime
154 #define icmp_ttime icmp_dun.id_ts.its_ttime
155 #define icmp_ip icmp_dun.id_ip.idi_ip
156 #define icmp_radv icmp_dun.id_radv
157 #define icmp_mask icmp_dun.id_mask
158 #define icmp_data icmp_dun.id_data
161 #define ICMP_MINLEN 8 /* abs minimum */
162 #define ICMP_UNREACH 3 /* dest unreachable, codes: */
163 #define ICMP_TIMXCEED 11 /* time exceeded, code: */
164 #define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */
165 #define ICMP_UNREACH_NET 0 /* bad net */
166 #define ICMP_UNREACH_HOST 1 /* bad host */
167 #define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */
168 #define ICMP_UNREACH_PORT 3 /* bad port */
169 #define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */
170 #define ICMP_UNREACH_SRCFAIL 5 /* src route failed */
174 #define MAXPACKET 65535 /* max ip packet size */
175 #ifndef MAXHOSTNAMELEN
176 #define MAXHOSTNAMELEN 64
180 * format of a (udp) probe packet.
185 u_char seq; /* sequence number of this packet */
186 u_char ttl; /* ttl packet left with */
187 struct timeval tv; /* time packet left */
191 * Definitions for internet protocol version 4.
192 * Per RFC 791, September 1981.
199 static u_char packet[512]; /* last inbound (icmp) packet */
200 static struct opacket *outpacket; /* last output (udp) packet */
202 static int s; /* receive (icmp) socket file descriptor */
203 static int sndsock; /* send (udp) socket file descriptor */
205 static struct sockaddr whereto; /* Who to try to reach */
206 static int datalen; /* How much data */
208 static char *hostname;
210 static int max_ttl = 30;
211 static u_short ident;
212 static u_short port = 32768+666; /* start udp dest port # for probe packets */
214 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
217 static int waittime = 5; /* time to wait for response (in seconds) */
218 static int nflag; /* print addresses numerically */
221 * Construct an Internet address representation.
222 * If the nflag has been supplied, give
223 * numeric value, otherwise try for symbolic name.
226 inetname(struct sockaddr_in *from)
229 static char domain[MAXHOSTNAMELEN + 1];
230 char name[MAXHOSTNAMELEN + 1];
231 static int first = 1;
234 if (first && !nflag) {
236 if (getdomainname(domain, MAXHOSTNAMELEN) != 0)
240 if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
241 if(INET_rresolve(name, sizeof(name), from, 0x4000, 0xffffffff) >= 0) {
242 if ((cp = strchr(name, '.')) &&
243 !strcmp(cp + 1, domain))
248 ina = inet_ntoa(from->sin_addr);
252 printf(" %s (%s)", (cp ? cp : ina), ina);
256 print(u_char *buf, int cc, struct sockaddr_in *from)
261 ip = (struct ip *) buf;
262 hlen = ip->ip_hl << 2;
266 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
268 printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
273 deltaT(struct timeval *t1p, struct timeval *t2p)
277 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
278 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
283 wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer)
286 static struct timeval wait;
288 int fromlen = sizeof (*from);
294 * traceroute could hang if someone else has a ping
295 * running and our ICMP reply gets dropped but we don't
296 * realize it because we keep waking up to handle those
297 * other ICMP packets that keep coming in. To fix this,
298 * "reset_timer" will only be true if the last packet that
299 * came in was for us or if this is the first time we're
300 * waiting for a reply since sending out a probe. Note
301 * that this takes advantage of the select() feature on
302 * Linux where the remaining timeout is written to the
303 * struct timeval area.
305 wait.tv_sec = waittime;
309 if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
310 cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
311 (struct sockaddr *)from, &fromlen);
316 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
318 * Convert an ICMP "type" field to a printable string.
320 static inline const char *
323 static const char * const ttab[] = {
324 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
325 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
326 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
327 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
332 return("OUT-OF-RANGE");
339 packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
346 ip = (struct ip *) buf;
347 hlen = ip->ip_hl << 2;
348 if (cc < hlen + ICMP_MINLEN) {
349 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
351 printf("packet too short (%d bytes) from %s\n", cc,
352 inet_ntoa(from->sin_addr));
357 icp = (struct icmp *)(buf + hlen);
358 type = icp->icmp_type; code = icp->icmp_code;
359 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
360 type == ICMP_UNREACH) {
365 hlen = hip->ip_hl << 2;
366 up = (struct udphdr *)((u_char *)hip + hlen);
367 if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
368 up->source == htons(ident) &&
369 up->dest == htons(port+seq))
370 return (type == ICMP_TIMXCEED? -1 : code+1);
372 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
375 u_long *lp = (u_long *)&icp->icmp_ip;
377 printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
378 cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst),
379 type, pr_type(type), icp->icmp_code);
380 for (i = 4; i < cc ; i += sizeof(long))
381 printf("%2d: x%8.8lx\n", i, *lp++);
387 static void /* not inline */
388 send_probe(int seq, int ttl)
390 struct opacket *op = outpacket;
391 struct ip *ip = &op->ip;
392 struct udphdr *up = &op->udp;
397 ip->ip_hl = sizeof(*ip) >> 2;
398 ip->ip_p = IPPROTO_UDP;
399 ip->ip_len = datalen;
401 ip->ip_v = IPVERSION;
402 ip->ip_id = htons(ident+seq);
404 up->source = htons(ident);
405 up->dest = htons(port+seq);
406 up->len = htons((u_short)(datalen - sizeof(struct ip)));
411 (void) gettimeofday(&op->tv, &tz);
413 i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
414 sizeof(struct sockaddr));
415 if (i < 0 || i != datalen) {
418 printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
420 (void) fflush(stdout);
426 #ifndef CONFIG_TRACEROUTE
429 traceroute_main(argc, argv)
437 struct sockaddr_in from, *to;
438 int ch, i, on, probe, seq, tos, ttl;
440 int options = 0; /* socket options */
446 to = (struct sockaddr_in *)&whereto;
447 while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
450 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
455 max_ttl = atoi(optarg);
457 error_msg_and_die("max ttl must be >1.");
465 error_msg_and_die("port must be >0.");
468 nprobes = atoi(optarg);
470 error_msg_and_die("nprobes must be >0.");
473 options |= SO_DONTROUTE;
477 * set the ip source address of the outbound
478 * probe (e.g., on a multi-homed host).
484 if (tos < 0 || tos > 255)
485 error_msg_and_die("tos must be 0 to 255.");
488 #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
493 waittime = atoi(optarg);
495 error_msg_and_die("wait must be >1 sec.");
508 memset(&whereto, 0, sizeof(struct sockaddr));
509 hp = xgethostbyname(*argv);
510 to->sin_family = hp->h_addrtype;
511 memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
512 hostname = (char *)hp->h_name;
514 datalen = atoi(*argv);
515 if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
516 error_msg_and_die("packet size must be 0 <= s < %d.",
517 MAXPACKET - sizeof(struct opacket));
518 datalen += sizeof(struct opacket);
519 outpacket = (struct opacket *)xmalloc((unsigned)datalen);
520 memset(outpacket, 0, datalen);
521 outpacket->ip.ip_dst = to->sin_addr;
522 outpacket->ip.ip_tos = tos;
523 outpacket->ip.ip_v = IPVERSION;
524 outpacket->ip.ip_id = 0;
526 ident = (getpid() & 0xffff) | 0x8000;
528 if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
529 perror_msg_and_die(can_not_create_raw_socket);
531 s = create_icmp_socket();
533 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
534 if (options & SO_DEBUG)
535 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
536 (char *)&on, sizeof(on));
538 if (options & SO_DONTROUTE)
539 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
540 (char *)&on, sizeof(on));
542 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
543 sizeof(datalen)) < 0)
544 perror_msg_and_die("SO_SNDBUF");
547 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
549 perror_msg_and_die("IP_HDRINCL");
551 #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
552 if (options & SO_DEBUG)
553 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
554 (char *)&on, sizeof(on));
556 if (options & SO_DONTROUTE)
557 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
558 (char *)&on, sizeof(on));
561 memset(&from, 0, sizeof(struct sockaddr));
562 from.sin_family = AF_INET;
563 from.sin_addr.s_addr = inet_addr(source);
564 if (from.sin_addr.s_addr == -1)
565 error_msg_and_die("unknown host %s", source);
566 outpacket->ip.ip_src = from.sin_addr;
568 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
569 perror_msg_and_die("bind");
573 fprintf(stderr, "traceroute to %s (%s)", hostname,
574 inet_ntoa(to->sin_addr));
576 fprintf(stderr, " from %s", source);
577 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
579 for (ttl = 1; ttl <= max_ttl; ++ttl) {
585 for (probe = 0; probe < nprobes; ++probe) {
587 struct timeval t1, t2;
591 (void) gettimeofday(&t1, &tz);
592 send_probe(++seq, ttl);
594 while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
595 (void) gettimeofday(&t2, &tz);
596 if ((i = packet_ok(packet, cc, &from, seq))) {
598 if (from.sin_addr.s_addr != lastaddr) {
599 print(packet, cc, &from);
600 lastaddr = from.sin_addr.s_addr;
602 printf(" %g ms", deltaT(&t1, &t2));
604 case ICMP_UNREACH_PORT:
605 ip = (struct ip *)packet;
610 case ICMP_UNREACH_NET:
614 case ICMP_UNREACH_HOST:
618 case ICMP_UNREACH_PROTOCOL:
622 case ICMP_UNREACH_NEEDFRAG:
626 case ICMP_UNREACH_SRCFAIL:
637 (void) fflush(stdout);
640 if (got_there || unreachable >= nprobes-1)