Remove debugging statement.
[oweals/busybox.git] / traceroute.c
1 /*-
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  */
86 struct 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
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);
109
110 static u_char  packet[512];            /* last inbound (icmp) packet */
111 static struct opacket  *outpacket;     /* last output (udp) packet */
112
113 static int s;                          /* receive (icmp) socket file descriptor */
114 static int sndsock;                    /* send (udp) socket file descriptor */
115
116 static struct sockaddr whereto;        /* Who to try to reach */
117 static int datalen;                    /* How much data */
118
119 static char *hostname;
120
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 */
124
125 static int verbose;
126 static int waittime = 5;               /* time to wait for response (in seconds) */
127 static int nflag;                      /* print addresses numerically */
128
129 int
130 #ifndef BB_TRACEROUTE
131 main(argc, argv)
132 #else
133 traceroute_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
359 static int
360 wait_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
397 static void
398 send_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
436 static double
437 deltaT(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  */
451 static const char *
452 pr_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
470 static int
471 packet_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
527 static void
528 print(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  */
556 static char *
557 inetname(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 }