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 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * traceroute host - trace the route ip packets follow going to "host".
41 * This program must be run by root or be setuid. (I suggest that
42 * you *don't* make it setuid -- casual use could result in a lot
43 * of unnecessary traffic on our poor, congested nets.)
45 * I stole the idea for this program from Steve Deering. Since
46 * the first release, I've learned that had I attended the right
47 * IETF working group meetings, I also could have stolen it from Guy
48 * Almes or Matt Mathis. I don't know (or care) who came up with
49 * the idea first. I envy the originators' perspicacity and I'm
50 * glad they didn't keep the idea a secret.
52 * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
53 * enhancements to the original distribution.
55 * I've hacked up a round-trip-route version of this that works by
56 * sending a loose-source-routed udp datagram through the destination
57 * back to yourself. Unfortunately, SO many gateways botch source
58 * routing, the thing is almost worthless. Maybe one day...
60 * -- Van Jacobson (van@helios.ee.lbl.gov)
61 * Tue Dec 20 03:50:13 PST 1988
72 #include <arpa/inet.h>
73 #include <netinet/udp.h>
74 #include <netinet/ip.h>
75 #include <netinet/ip_icmp.h>
78 #define MAXPACKET 65535 /* max ip packet size */
79 #ifndef MAXHOSTNAMELEN
80 #define MAXHOSTNAMELEN 64
84 * format of a (udp) probe packet.
89 u_char seq; /* sequence number of this packet */
90 u_char ttl; /* ttl packet left with */
91 struct timeval tv; /* time packet left */
95 * Definitions for internet protocol version 4.
96 * Per RFC 791, September 1981.
103 static int wait_for_reply (int, struct sockaddr_in *, int);
104 static void send_probe (int, int);
105 static double deltaT (struct timeval *, struct timeval *);
106 static int packet_ok (u_char *, int, struct sockaddr_in *, int);
107 static void print (u_char *, int, struct sockaddr_in *);
108 static char *inetname (struct in_addr);
110 static u_char packet[512]; /* last inbound (icmp) packet */
111 static struct opacket *outpacket; /* last output (udp) packet */
113 static int s; /* receive (icmp) socket file descriptor */
114 static int sndsock; /* send (udp) socket file descriptor */
116 static struct sockaddr whereto; /* Who to try to reach */
117 static int datalen; /* How much data */
119 static char *hostname;
121 static int max_ttl = 30;
122 static u_short ident;
123 static u_short port = 32768+666; /* start udp dest port # for probe packets */
126 static int waittime = 5; /* time to wait for response (in seconds) */
127 static int nflag; /* print addresses numerically */
130 #ifndef BB_TRACEROUTE
133 traceroute_main(argc, argv)
142 struct sockaddr_in from, *to;
143 int ch, i, on, probe, seq, tos, ttl;
145 int options = 0; /* socket options */
151 to = (struct sockaddr_in *)&whereto;
152 while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
158 max_ttl = atoi(optarg);
160 error_msg_and_die("max ttl must be >1.");
168 error_msg_and_die("port must be >0.");
171 nprobes = atoi(optarg);
173 error_msg_and_die("nprobes must be >0.");
176 options |= SO_DONTROUTE;
180 * set the ip source address of the outbound
181 * probe (e.g., on a multi-homed host).
187 if (tos < 0 || tos > 255)
188 error_msg_and_die("tos must be 0 to 255.");
194 waittime = atoi(optarg);
196 error_msg_and_die("wait must be >1 sec.");
209 (void) bzero((char *)&whereto, sizeof(struct sockaddr));
210 to->sin_family = AF_INET;
211 to->sin_addr.s_addr = inet_addr(*argv);
212 if (to->sin_addr.s_addr != -1)
215 hp = gethostbyname(*argv);
217 to->sin_family = hp->h_addrtype;
218 bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
219 hostname = (char *)hp->h_name;
221 error_msg_and_die("unknown host %s", *argv);
225 datalen = atoi(*argv);
226 if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
227 error_msg_and_die("packet size must be 0 <= s < %d.",
228 MAXPACKET - sizeof(struct opacket));
229 datalen += sizeof(struct opacket);
230 outpacket = (struct opacket *)xmalloc((unsigned)datalen);
231 (void) bzero((char *)outpacket, datalen);
232 outpacket->ip.ip_dst = to->sin_addr;
233 outpacket->ip.ip_tos = tos;
234 outpacket->ip.ip_v = IPVERSION;
235 outpacket->ip.ip_id = 0;
237 ident = (getpid() & 0xffff) | 0x8000;
239 if ((pe = getprotobyname("icmp")) == NULL)
240 error_msg_and_die("icmp: unknown protocol");
241 if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
242 perror_msg_and_die("icmp socket");
243 if (options & SO_DEBUG)
244 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
245 (char *)&on, sizeof(on));
246 if (options & SO_DONTROUTE)
247 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
248 (char *)&on, sizeof(on));
250 if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
251 perror_msg_and_die("raw socket");
253 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
254 sizeof(datalen)) < 0)
255 perror_msg_and_die("SO_SNDBUF");
258 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
260 perror_msg_and_die("IP_HDRINCL");
262 if (options & SO_DEBUG)
263 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
264 (char *)&on, sizeof(on));
265 if (options & SO_DONTROUTE)
266 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
267 (char *)&on, sizeof(on));
270 (void) bzero((char *)&from, sizeof(struct sockaddr));
271 from.sin_family = AF_INET;
272 from.sin_addr.s_addr = inet_addr(source);
273 if (from.sin_addr.s_addr == -1)
274 error_msg_and_die("unknown host %s", source);
275 outpacket->ip.ip_src = from.sin_addr;
277 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
278 perror_msg_and_die("bind");
282 fprintf(stderr, "traceroute to %s (%s)", hostname,
283 inet_ntoa(to->sin_addr));
285 fprintf(stderr, " from %s", source);
286 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
287 (void) fflush(stderr);
289 for (ttl = 1; ttl <= max_ttl; ++ttl) {
295 for (probe = 0; probe < nprobes; ++probe) {
297 struct timeval t1, t2;
301 (void) gettimeofday(&t1, &tz);
302 send_probe(++seq, ttl);
304 while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
305 (void) gettimeofday(&t2, &tz);
306 if ((i = packet_ok(packet, cc, &from, seq))) {
308 if (from.sin_addr.s_addr != lastaddr) {
309 print(packet, cc, &from);
310 lastaddr = from.sin_addr.s_addr;
312 printf(" %g ms", deltaT(&t1, &t2));
314 case ICMP_UNREACH_PORT:
316 ip = (struct ip *)packet;
322 case ICMP_UNREACH_NET:
326 case ICMP_UNREACH_HOST:
330 case ICMP_UNREACH_PROTOCOL:
334 case ICMP_UNREACH_NEEDFRAG:
338 case ICMP_UNREACH_SRCFAIL:
349 (void) fflush(stdout);
352 if (got_there || unreachable >= nprobes-1)
360 wait_for_reply(sock, from, reset_timer)
362 struct sockaddr_in *from;
366 static struct timeval wait;
368 int fromlen = sizeof (*from);
374 * traceroute could hang if someone else has a ping
375 * running and our ICMP reply gets dropped but we don't
376 * realize it because we keep waking up to handle those
377 * other ICMP packets that keep coming in. To fix this,
378 * "reset_timer" will only be true if the last packet that
379 * came in was for us or if this is the first time we're
380 * waiting for a reply since sending out a probe. Note
381 * that this takes advantage of the select() feature on
382 * Linux where the remaining timeout is written to the
383 * struct timeval area.
385 wait.tv_sec = waittime;
389 if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
390 cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
391 (struct sockaddr *)from, &fromlen);
401 struct opacket *op = outpacket;
402 struct ip *ip = &op->ip;
403 struct udphdr *up = &op->udp;
408 ip->ip_hl = sizeof(*ip) >> 2;
409 ip->ip_p = IPPROTO_UDP;
410 ip->ip_len = datalen;
412 ip->ip_v = IPVERSION;
413 ip->ip_id = htons(ident+seq);
415 up->source = htons(ident);
416 up->dest = htons(port+seq);
417 up->len = htons((u_short)(datalen - sizeof(struct ip)));
422 (void) gettimeofday(&op->tv, &tz);
424 i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
425 sizeof(struct sockaddr));
426 if (i < 0 || i != datalen) {
429 printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
431 (void) fflush(stdout);
438 struct timeval *t1p, *t2p;
442 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
443 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
449 * Convert an ICMP "type" field to a printable string.
455 static const char * const ttab[] = {
456 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
457 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
458 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
459 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
464 return("OUT-OF-RANGE");
471 packet_ok(buf, cc, from, seq)
474 struct sockaddr_in *from;
477 register struct icmp *icp;
483 ip = (struct ip *) buf;
484 hlen = ip->ip_hl << 2;
485 if (cc < hlen + ICMP_MINLEN) {
487 printf("packet too short (%d bytes) from %s\n", cc,
488 inet_ntoa(from->sin_addr));
492 icp = (struct icmp *)(buf + hlen);
494 icp = (struct icmp *)buf;
496 type = icp->icmp_type; code = icp->icmp_code;
497 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
498 type == ICMP_UNREACH) {
503 hlen = hip->ip_hl << 2;
504 up = (struct udphdr *)((u_char *)hip + hlen);
505 if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
506 up->source == htons(ident) &&
507 up->dest == htons(port+seq))
508 return (type == ICMP_TIMXCEED? -1 : code+1);
513 u_long *lp = (u_long *)&icp->icmp_ip;
515 printf("\n%d bytes from %s to %s", cc,
516 inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst));
517 printf(": icmp type %d (%s) code %d\n", type, pr_type(type),
519 for (i = 4; i < cc ; i += sizeof(long))
520 printf("%2d: x%8.8lx\n", i, *lp++);
531 struct sockaddr_in *from;
536 ip = (struct ip *) buf;
537 hlen = ip->ip_hl << 2;
541 printf(" %s", inet_ntoa(from->sin_addr));
543 printf(" %s (%s)", inetname(from->sin_addr),
544 inet_ntoa(from->sin_addr));
547 printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
552 * Construct an Internet address representation.
553 * If the nflag has been supplied, give
554 * numeric value, otherwise try for symbolic name.
561 static char line[50];
563 static char domain[MAXHOSTNAMELEN + 1];
564 static int first = 1;
566 if (first && !nflag) {
568 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
569 (cp = index(domain, '.')))
570 (void) strcpy(domain, cp + 1);
575 if (!nflag && in.s_addr != INADDR_ANY) {
576 hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
578 if ((cp = index(hp->h_name, '.')) &&
579 !strcmp(cp + 1, domain))
581 cp = (char *)hp->h_name;
585 (void) strcpy(line, cp);
587 in.s_addr = ntohl(in.s_addr);
588 #define C(x) ((x) & 0xff)
589 sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
590 C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));