blob: a02be8a9ed2ab57ec738ae7c605386642487c433 [file] [log] [blame]
Eric Andersen5c58d282001-07-10 16:29:00 +00001/*-
2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Van Jacobson.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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.
23 *
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
34 * SUCH DAMAGE.
35 */
36
37/*
38 * traceroute host - trace the route ip packets follow going to "host".
39 * Notes
40 * -----
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.)
44 *
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.
51 *
52 * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
53 * enhancements to the original distribution.
54 *
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...
59 *
60 * -- Van Jacobson (van@helios.ee.lbl.gov)
61 * Tue Dec 20 03:50:13 PST 1988
62 */
63
64#include <stdio.h>
65#include <errno.h>
66#include <stdlib.h>
67#include <string.h>
68#include <unistd.h>
69#include <sys/time.h>
70#include <netdb.h>
71#include <endian.h>
72#include <arpa/inet.h>
73#include <netinet/udp.h>
74#include <netinet/ip.h>
75#include <netinet/ip_icmp.h>
76
77
78#define MAXPACKET 65535 /* max ip packet size */
79#ifndef MAXHOSTNAMELEN
80#define MAXHOSTNAMELEN 64
81#endif
82
83/*
84 * format of a (udp) probe packet.
85 */
86struct opacket {
87 struct ip ip;
88 struct udphdr udp;
89 u_char seq; /* sequence number of this packet */
90 u_char ttl; /* ttl packet left with */
91 struct timeval tv; /* time packet left */
92};
93
94/*
95 * Definitions for internet protocol version 4.
96 * Per RFC 791, September 1981.
97 */
98#define IPVERSION 4
99
100
101#include "busybox.h"
102
103static int wait_for_reply (int, struct sockaddr_in *, int);
104static void send_probe (int, int);
105static double deltaT (struct timeval *, struct timeval *);
106static int packet_ok (u_char *, int, struct sockaddr_in *, int);
107static void print (u_char *, int, struct sockaddr_in *);
108static char *inetname (struct in_addr);
109
110static u_char packet[512]; /* last inbound (icmp) packet */
111static struct opacket *outpacket; /* last output (udp) packet */
112
113static int s; /* receive (icmp) socket file descriptor */
114static int sndsock; /* send (udp) socket file descriptor */
115
116static struct sockaddr whereto; /* Who to try to reach */
117static int datalen; /* How much data */
118
119static char *hostname;
120
121static int max_ttl = 30;
122static u_short ident;
123static u_short port = 32768+666; /* start udp dest port # for probe packets */
124
125static int verbose;
126static int waittime = 5; /* time to wait for response (in seconds) */
127static int nflag; /* print addresses numerically */
128
129int
130#ifndef BB_TRACEROUTE
131main(argc, argv)
132#else
133traceroute_main(argc, argv)
134#endif
135 int argc;
136 char *argv[];
137{
138 extern char *optarg;
139 extern int optind;
140 struct hostent *hp;
141 struct protoent *pe;
142 struct sockaddr_in from, *to;
143 int ch, i, on, probe, seq, tos, ttl;
144
145 int options = 0; /* socket options */
146 char *source = 0;
147 int nprobes = 3;
148
149 on = 1;
150 seq = tos = 0;
151 to = (struct sockaddr_in *)&whereto;
152 while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
153 switch(ch) {
154 case 'd':
155 options |= SO_DEBUG;
156 break;
157 case 'm':
158 max_ttl = atoi(optarg);
159 if (max_ttl <= 1)
160 error_msg_and_die("max ttl must be >1.");
161 break;
162 case 'n':
163 nflag++;
164 break;
165 case 'p':
166 port = atoi(optarg);
167 if (port < 1)
168 error_msg_and_die("port must be >0.");
169 break;
170 case 'q':
171 nprobes = atoi(optarg);
172 if (nprobes < 1)
173 error_msg_and_die("nprobes must be >0.");
174 break;
175 case 'r':
176 options |= SO_DONTROUTE;
177 break;
178 case 's':
179 /*
180 * set the ip source address of the outbound
181 * probe (e.g., on a multi-homed host).
182 */
183 source = optarg;
184 break;
185 case 't':
186 tos = atoi(optarg);
187 if (tos < 0 || tos > 255)
188 error_msg_and_die("tos must be 0 to 255.");
189 break;
190 case 'v':
191 verbose++;
192 break;
193 case 'w':
194 waittime = atoi(optarg);
195 if (waittime <= 1)
196 error_msg_and_die("wait must be >1 sec.");
197 break;
198 default:
199 show_usage();
200 }
201 argc -= optind;
202 argv += optind;
203
204 if (argc < 1)
205 show_usage();
206
207 setlinebuf (stdout);
208
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)
213 hostname = *argv;
214 else {
215 hp = gethostbyname(*argv);
216 if (hp) {
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;
220 } else {
221 error_msg_and_die("unknown host %s", *argv);
222 }
223 }
224 if (*++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;
236
237 ident = (getpid() & 0xffff) | 0x8000;
238
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));
249
250 if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
251 perror_msg_and_die("raw socket");
252#ifdef SO_SNDBUF
253 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
254 sizeof(datalen)) < 0)
255 perror_msg_and_die("SO_SNDBUF");
256#endif SO_SNDBUF
257#ifdef IP_HDRINCL
258 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
259 sizeof(on)) < 0)
260 perror_msg_and_die("IP_HDRINCL");
261#endif 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));
268
269 if (source) {
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;
276#ifndef IP_HDRINCL
277 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
278 perror_msg_and_die("bind");
279#endif IP_HDRINCL
280 }
281
282 fprintf(stderr, "traceroute to %s (%s)", hostname,
283 inet_ntoa(to->sin_addr));
284 if (source)
285 fprintf(stderr, " from %s", source);
286 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
287 (void) fflush(stderr);
288
289 for (ttl = 1; ttl <= max_ttl; ++ttl) {
290 u_long lastaddr = 0;
291 int got_there = 0;
292 int unreachable = 0;
293
294 printf("%2d ", ttl);
295 for (probe = 0; probe < nprobes; ++probe) {
296 int cc, reset_timer;
297 struct timeval t1, t2;
298 struct timezone tz;
299 struct ip *ip;
300
301 (void) gettimeofday(&t1, &tz);
302 send_probe(++seq, ttl);
303 reset_timer = 1;
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))) {
307 reset_timer = 1;
308 if (from.sin_addr.s_addr != lastaddr) {
309 print(packet, cc, &from);
310 lastaddr = from.sin_addr.s_addr;
311 }
312 printf(" %g ms", deltaT(&t1, &t2));
313 switch(i - 1) {
314 case ICMP_UNREACH_PORT:
315#ifndef ARCHAIC
316 ip = (struct ip *)packet;
317 if (ip->ip_ttl <= 1)
318 printf(" !");
319#endif ARCHAIC
320 ++got_there;
321 break;
322 case ICMP_UNREACH_NET:
323 ++unreachable;
324 printf(" !N");
325 break;
326 case ICMP_UNREACH_HOST:
327 ++unreachable;
328 printf(" !H");
329 break;
330 case ICMP_UNREACH_PROTOCOL:
331 ++got_there;
332 printf(" !P");
333 break;
334 case ICMP_UNREACH_NEEDFRAG:
335 ++unreachable;
336 printf(" !F");
337 break;
338 case ICMP_UNREACH_SRCFAIL:
339 ++unreachable;
340 printf(" !S");
341 break;
342 }
343 break;
344 } else
345 reset_timer = 0;
346 }
347 if (cc == 0)
348 printf(" *");
349 (void) fflush(stdout);
350 }
351 putchar('\n');
352 if (got_there || unreachable >= nprobes-1)
353 exit(0);
354 }
355
356 return 0;
357}
358
359static int
360wait_for_reply(sock, from, reset_timer)
361 int sock;
362 struct sockaddr_in *from;
363 int reset_timer;
364{
365 fd_set fds;
366 static struct timeval wait;
367 int cc = 0;
368 int fromlen = sizeof (*from);
369
370 FD_ZERO(&fds);
371 FD_SET(sock, &fds);
372 if (reset_timer) {
373 /*
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.
384 */
385 wait.tv_sec = waittime;
386 wait.tv_usec = 0;
387 }
388
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);
392
393 return(cc);
394}
395
396
397static void
398send_probe(seq, ttl)
399 int seq, ttl;
400{
401 struct opacket *op = outpacket;
402 struct ip *ip = &op->ip;
403 struct udphdr *up = &op->udp;
404 int i;
405 struct timezone tz;
406
407 ip->ip_off = 0;
408 ip->ip_hl = sizeof(*ip) >> 2;
409 ip->ip_p = IPPROTO_UDP;
410 ip->ip_len = datalen;
411 ip->ip_ttl = ttl;
412 ip->ip_v = IPVERSION;
413 ip->ip_id = htons(ident+seq);
414
415 up->source = htons(ident);
416 up->dest = htons(port+seq);
417 up->len = htons((u_short)(datalen - sizeof(struct ip)));
418 up->check = 0;
419
420 op->seq = seq;
421 op->ttl = ttl;
422 (void) gettimeofday(&op->tv, &tz);
423
424 i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
425 sizeof(struct sockaddr));
426 if (i < 0 || i != datalen) {
427 if (i<0)
428 perror("sendto");
429 printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
430 datalen, i);
431 (void) fflush(stdout);
432 }
433}
434
435
436static double
437deltaT(t1p, t2p)
438 struct timeval *t1p, *t2p;
439{
440 register double dt;
441
442 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
443 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
444 return (dt);
445}
446
447
448/*
449 * Convert an ICMP "type" field to a printable string.
450 */
451static const char *
452pr_type(t)
453 u_char t;
454{
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",
460 "Info Reply"
461 };
462
463 if(t > 16)
464 return("OUT-OF-RANGE");
465
466 return(ttab[t]);
467}
468
469
470static int
471packet_ok(buf, cc, from, seq)
472 u_char *buf;
473 int cc;
474 struct sockaddr_in *from;
475 int seq;
476{
477 register struct icmp *icp;
478 u_char type, code;
479 int hlen;
480#ifndef ARCHAIC
481 struct ip *ip;
482
483 ip = (struct ip *) buf;
484 hlen = ip->ip_hl << 2;
485 if (cc < hlen + ICMP_MINLEN) {
486 if (verbose)
487 printf("packet too short (%d bytes) from %s\n", cc,
488 inet_ntoa(from->sin_addr));
489 return (0);
490 }
491 cc -= hlen;
492 icp = (struct icmp *)(buf + hlen);
493#else
494 icp = (struct icmp *)buf;
495#endif ARCHAIC
496 type = icp->icmp_type; code = icp->icmp_code;
497 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
498 type == ICMP_UNREACH) {
499 struct ip *hip;
500 struct udphdr *up;
501
502 hip = &icp->icmp_ip;
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);
509 }
510#ifndef ARCHAIC
511 if (verbose) {
512 int i;
513 u_long *lp = (u_long *)&icp->icmp_ip;
514
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),
518 icp->icmp_code);
519 for (i = 4; i < cc ; i += sizeof(long))
520 printf("%2d: x%8.8lx\n", i, *lp++);
521 }
522#endif ARCHAIC
523 return(0);
524}
525
526
527static void
528print(buf, cc, from)
529 u_char *buf;
530 int cc;
531 struct sockaddr_in *from;
532{
533 struct ip *ip;
534 int hlen;
535
536 ip = (struct ip *) buf;
537 hlen = ip->ip_hl << 2;
538 cc -= hlen;
539
540 if (nflag)
541 printf(" %s", inet_ntoa(from->sin_addr));
542 else
543 printf(" %s (%s)", inetname(from->sin_addr),
544 inet_ntoa(from->sin_addr));
545
546 if (verbose)
547 printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
548}
549
550
551/*
552 * Construct an Internet address representation.
553 * If the nflag has been supplied, give
554 * numeric value, otherwise try for symbolic name.
555 */
556static char *
557inetname(in)
558 struct in_addr in;
559{
560 register char *cp;
561 static char line[50];
562 struct hostent *hp;
563 static char domain[MAXHOSTNAMELEN + 1];
564 static int first = 1;
565
566 if (first && !nflag) {
567 first = 0;
568 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
569 (cp = index(domain, '.')))
570 (void) strcpy(domain, cp + 1);
571 else
572 domain[0] = 0;
573 }
574 cp = 0;
575 if (!nflag && in.s_addr != INADDR_ANY) {
576 hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
577 if (hp) {
578 if ((cp = index(hp->h_name, '.')) &&
579 !strcmp(cp + 1, domain))
580 *cp = 0;
581 cp = (char *)hp->h_name;
582 }
583 }
584 if (cp)
585 (void) strcpy(line, cp);
586 else {
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));
591 }
592 return (line);
593}