]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/traceroute/traceroute.c
This commit was generated by cvs2svn to compensate for changes in r14561,
[FreeBSD/FreeBSD.git] / usr.sbin / traceroute / 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 #ifndef lint
38 static char copyright[] =
39 "@(#) Copyright (c) 1990, 1993\n\
40         The Regents of the University of California.  All rights reserved.\n";
41 #endif /* not lint */
42
43 #ifndef lint
44 static char sccsid[] = "@(#)traceroute.c        8.1 (Berkeley) 6/6/93";
45 #endif /* not lint */
46
47 /*
48  * traceroute host  - trace the route ip packets follow going to "host".
49  *
50  * Attempt to trace the route an ip packet would follow to some
51  * internet host.  We find out intermediate hops by launching probe
52  * packets with a small ttl (time to live) then listening for an
53  * icmp "time exceeded" reply from a gateway.  We start our probes
54  * with a ttl of one and increase by one until we get an icmp "port
55  * unreachable" (which means we got to "host") or hit a max (which
56  * defaults to 30 hops & can be changed with the -m flag).  Three
57  * probes (change with -q flag) are sent at each ttl setting and a
58  * line is printed showing the ttl, address of the gateway and
59  * round trip time of each probe.  If the probe answers come from
60  * different gateways, the address of each responding system will
61  * be printed.  If there is no response within a 5 sec. timeout
62  * interval (changed with the -w flag), a "*" is printed for that
63  * probe.
64  *
65  * Probe packets are UDP format.  We don't want the destination
66  * host to process them so the destination port is set to an
67  * unlikely value (if some clod on the destination is using that
68  * value, it can be changed with the -p flag).
69  *
70  * A sample use might be:
71  *
72  *     [yak 71]% traceroute nis.nsf.net.
73  *     traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
74  *      1  helios.ee.lbl.gov (128.3.112.1)  19 ms  19 ms  0 ms
75  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
76  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
77  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  39 ms
78  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  39 ms  39 ms  39 ms
79  *      6  128.32.197.4 (128.32.197.4)  40 ms  59 ms  59 ms
80  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  59 ms
81  *      8  129.140.70.13 (129.140.70.13)  99 ms  99 ms  80 ms
82  *      9  129.140.71.6 (129.140.71.6)  139 ms  239 ms  319 ms
83  *     10  129.140.81.7 (129.140.81.7)  220 ms  199 ms  199 ms
84  *     11  nic.merit.edu (35.1.1.48)  239 ms  239 ms  239 ms
85  *
86  * Note that lines 2 & 3 are the same.  This is due to a buggy
87  * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
88  * packets with a zero ttl.
89  *
90  * A more interesting example is:
91  *
92  *     [yak 72]% traceroute allspice.lcs.mit.edu.
93  *     traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
94  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
95  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  19 ms  19 ms
96  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  19 ms
97  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  19 ms  39 ms  39 ms
98  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  20 ms  39 ms  39 ms
99  *      6  128.32.197.4 (128.32.197.4)  59 ms  119 ms  39 ms
100  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  39 ms
101  *      8  129.140.70.13 (129.140.70.13)  80 ms  79 ms  99 ms
102  *      9  129.140.71.6 (129.140.71.6)  139 ms  139 ms  159 ms
103  *     10  129.140.81.7 (129.140.81.7)  199 ms  180 ms  300 ms
104  *     11  129.140.72.17 (129.140.72.17)  300 ms  239 ms  239 ms
105  *     12  * * *
106  *     13  128.121.54.72 (128.121.54.72)  259 ms  499 ms  279 ms
107  *     14  * * *
108  *     15  * * *
109  *     16  * * *
110  *     17  * * *
111  *     18  ALLSPICE.LCS.MIT.EDU (18.26.0.115)  339 ms  279 ms  279 ms
112  *
113  * (I start to see why I'm having so much trouble with mail to
114  * MIT.)  Note that the gateways 12, 14, 15, 16 & 17 hops away
115  * either don't send ICMP "time exceeded" messages or send them
116  * with a ttl too small to reach us.  14 - 17 are running the
117  * MIT C Gateway code that doesn't send "time exceeded"s.  God
118  * only knows what's going on with 12.
119  *
120  * The silent gateway 12 in the above may be the result of a bug in
121  * the 4.[23]BSD network code (and its derivatives):  4.x (x <= 3)
122  * sends an unreachable message using whatever ttl remains in the
123  * original datagram.  Since, for gateways, the remaining ttl is
124  * zero, the icmp "time exceeded" is guaranteed to not make it back
125  * to us.  The behavior of this bug is slightly more interesting
126  * when it appears on the destination system:
127  *
128  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
129  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  39 ms
130  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  39 ms  19 ms
131  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  19 ms
132  *      5  ccn-nerif35.Berkeley.EDU (128.32.168.35)  39 ms  39 ms  39 ms
133  *      6  csgw.Berkeley.EDU (128.32.133.254)  39 ms  59 ms  39 ms
134  *      7  * * *
135  *      8  * * *
136  *      9  * * *
137  *     10  * * *
138  *     11  * * *
139  *     12  * * *
140  *     13  rip.Berkeley.EDU (128.32.131.22)  59 ms !  39 ms !  39 ms !
141  *
142  * Notice that there are 12 "gateways" (13 is the final
143  * destination) and exactly the last half of them are "missing".
144  * What's really happening is that rip (a Sun-3 running Sun OS3.5)
145  * is using the ttl from our arriving datagram as the ttl in its
146  * icmp reply.  So, the reply will time out on the return path
147  * (with no notice sent to anyone since icmp's aren't sent for
148  * icmp's) until we probe with a ttl that's at least twice the path
149  * length.  I.e., rip is really only 7 hops away.  A reply that
150  * returns with a ttl of 1 is a clue this problem exists.
151  * Traceroute prints a "!" after the time if the ttl is <= 1.
152  * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
153  * non-standard (HPUX) software, expect to see this problem
154  * frequently and/or take care picking the target host of your
155  * probes.
156  *
157  * Other possible annotations after the time are !H, !N, !P (got a host,
158  * network or protocol unreachable, respectively), !S or !F (source
159  * route failed or fragmentation needed -- neither of these should
160  * ever occur and the associated gateway is busted if you see one).  If
161  * almost all the probes result in some kind of unreachable, traceroute
162  * will give up and exit.
163  *
164  * Notes
165  * -----
166  * This program must be run by root or be setuid.  (I suggest that
167  * you *don't* make it setuid -- casual use could result in a lot
168  * of unnecessary traffic on our poor, congested nets.)
169  *
170  * This program requires a kernel mod that does not appear in any
171  * system available from Berkeley:  A raw ip socket using proto
172  * IPPROTO_RAW must interpret the data sent as an ip datagram (as
173  * opposed to data to be wrapped in a ip datagram).  See the README
174  * file that came with the source to this program for a description
175  * of the mods I made to /sys/netinet/raw_ip.c.  Your mileage may
176  * vary.  But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
177  * MODIFIED TO RUN THIS PROGRAM.
178  *
179  * The udp port usage may appear bizarre (well, ok, it is bizarre).
180  * The problem is that an icmp message only contains 8 bytes of
181  * data from the original datagram.  8 bytes is the size of a udp
182  * header so, if we want to associate replies with the original
183  * datagram, the necessary information must be encoded into the
184  * udp header (the ip id could be used but there's no way to
185  * interlock with the kernel's assignment of ip id's and, anyway,
186  * it would have taken a lot more kernel hacking to allow this
187  * code to set the ip id).  So, to allow two or more users to
188  * use traceroute simultaneously, we use this task's pid as the
189  * source port (the high bit is set to move the port number out
190  * of the "likely" range).  To keep track of which probe is being
191  * replied to (so times and/or hop counts don't get confused by a
192  * reply that was delayed in transit), we increment the destination
193  * port number before each probe.
194  *
195  * Don't use this as a coding example.  I was trying to find a
196  * routing problem and this code sort-of popped out after 48 hours
197  * without sleep.  I was amazed it ever compiled, much less ran.
198  *
199  * I stole the idea for this program from Steve Deering.  Since
200  * the first release, I've learned that had I attended the right
201  * IETF working group meetings, I also could have stolen it from Guy
202  * Almes or Matt Mathis.  I don't know (or care) who came up with
203  * the idea first.  I envy the originators' perspicacity and I'm
204  * glad they didn't keep the idea a secret.
205  *
206  * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
207  * enhancements to the original distribution.
208  *
209  * I've hacked up a round-trip-route version of this that works by
210  * sending a loose-source-routed udp datagram through the destination
211  * back to yourself.  Unfortunately, SO many gateways botch source
212  * routing, the thing is almost worthless.  Maybe one day...
213  *
214  *  -- Van Jacobson (van@helios.ee.lbl.gov)
215  *     Tue Dec 20 03:50:13 PST 1988
216  */
217
218 #include <sys/param.h>
219 #include <sys/time.h>
220 #include <sys/socket.h>
221 #include <sys/file.h>
222 #include <sys/ioctl.h>
223
224 #include <netinet/in_systm.h>
225 #include <netinet/in.h>
226 #include <netinet/ip.h>
227 #include <netinet/ip_icmp.h>
228 #include <netinet/udp.h>
229
230 #include <arpa/inet.h>
231
232 #include <netdb.h>
233 #include <stdio.h>
234 #include <errno.h>
235 #include <stdlib.h>
236 #include <string.h>
237 #include <unistd.h>
238
239 #define MAXPACKET       65535   /* max ip packet size */
240 #ifndef MAXHOSTNAMELEN
241 #define MAXHOSTNAMELEN  64
242 #endif
243
244 #ifndef FD_SET
245 #define NFDBITS         (8*sizeof(fd_set))
246 #define FD_SETSIZE      NFDBITS
247 #define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
248 #define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
249 #define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
250 #define FD_ZERO(p)      bzero((char *)(p), sizeof(*(p)))
251 #endif
252
253 #define Fprintf (void)fprintf
254 #define Sprintf (void)sprintf
255 #define Printf (void)printf
256
257 /*
258  * format of a (udp) probe packet.
259  */
260 struct opacket {
261         struct ip ip;
262         struct udphdr udp;
263         u_char seq;             /* sequence number of this packet */
264         u_char ttl;             /* ttl packet left with */
265         struct timeval tv;      /* time packet left */
266 };
267
268 u_char  packet[512];            /* last inbound (icmp) packet */
269 struct opacket  *outpacket;     /* last output (udp) packet */
270
271 int wait_for_reply __P((int, struct sockaddr_in *, struct timeval *));
272 void send_probe __P((int, int));
273 double deltaT __P((struct timeval *, struct timeval *));
274 int packet_ok __P((u_char *, int, struct sockaddr_in *, int));
275 void print __P((u_char *, int, struct sockaddr_in *));
276 void tvsub __P((struct timeval *, struct timeval *));
277 char *inetname __P((struct in_addr));
278 void usage __P(());
279
280 int s;                          /* receive (icmp) socket file descriptor */
281 int sndsock;                    /* send (udp) socket file descriptor */
282 struct timezone tz;             /* leftover */
283
284 struct sockaddr whereto;        /* Who to try to reach */
285 int datalen;                    /* How much data */
286
287 char *source = 0;
288 char *hostname;
289
290 int nprobes = 3;
291 int max_ttl = 30;
292 u_short ident;
293 u_short port = 32768+666;       /* start udp dest port # for probe packets */
294 int options;                    /* socket options */
295 int verbose;
296 int waittime = 5;               /* time to wait for response (in seconds) */
297 int nflag;                      /* print addresses numerically */
298
299 int
300 main(argc, argv)
301         int argc;
302         char *argv[];
303 {
304         extern char *optarg;
305         extern int optind;
306         struct hostent *hp;
307         struct protoent *pe;
308         struct sockaddr_in from, *to;
309         int ch, i, on, probe, seq, tos, ttl;
310
311         on = 1;
312         seq = tos = 0;
313         to = (struct sockaddr_in *)&whereto;
314         while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
315                 switch(ch) {
316                 case 'd':
317                         options |= SO_DEBUG;
318                         break;
319                 case 'm':
320                         max_ttl = atoi(optarg);
321                         if (max_ttl <= 1) {
322                                 Fprintf(stderr,
323                                     "traceroute: max ttl must be >1.\n");
324                                 exit(1);
325                         }
326                         break;
327                 case 'n':
328                         nflag++;
329                         break;
330                 case 'p':
331                         port = atoi(optarg);
332                         if (port < 1) {
333                                 Fprintf(stderr,
334                                     "traceroute: port must be >0.\n");
335                                 exit(1);
336                         }
337                         break;
338                 case 'q':
339                         nprobes = atoi(optarg);
340                         if (nprobes < 1) {
341                                 Fprintf(stderr,
342                                     "traceroute: nprobes must be >0.\n");
343                                 exit(1);
344                         }
345                         break;
346                 case 'r':
347                         options |= SO_DONTROUTE;
348                         break;
349                 case 's':
350                         /*
351                          * set the ip source address of the outbound
352                          * probe (e.g., on a multi-homed host).
353                          */
354                         source = optarg;
355                         break;
356                 case 't':
357                         tos = atoi(optarg);
358                         if (tos < 0 || tos > 255) {
359                                 Fprintf(stderr,
360                                     "traceroute: tos must be 0 to 255.\n");
361                                 exit(1);
362                         }
363                         break;
364                 case 'v':
365                         verbose++;
366                         break;
367                 case 'w':
368                         waittime = atoi(optarg);
369                         if (waittime <= 1) {
370                                 Fprintf(stderr,
371                                     "traceroute: wait must be >1 sec.\n");
372                                 exit(1);
373                         }
374                         break;
375                 default:
376                         usage();
377                 }
378         argc -= optind;
379         argv += optind;
380
381         if (argc < 1)
382                 usage();
383
384         setlinebuf (stdout);
385
386         (void) bzero((char *)&whereto, sizeof(struct sockaddr));
387         to->sin_family = AF_INET;
388         to->sin_addr.s_addr = inet_addr(*argv);
389         if (to->sin_addr.s_addr != -1)
390                 hostname = *argv;
391         else {
392                 hp = gethostbyname(*argv);
393                 if (hp) {
394                         to->sin_family = hp->h_addrtype;
395                         bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
396                         hostname = strdup(hp->h_name);
397                 } else {
398                         (void)fprintf(stderr,
399                             "traceroute: unknown host %s\n", *argv);
400                         exit(1);
401                 }
402         }
403         if (*++argv)
404                 datalen = atoi(*argv);
405         if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) {
406                 Fprintf(stderr,
407                     "traceroute: packet size must be 0 <= s < %ld.\n",
408                     MAXPACKET - sizeof(struct opacket));
409                 exit(1);
410         }
411         datalen += sizeof(struct opacket);
412         outpacket = (struct opacket *)malloc((unsigned)datalen);
413         if (! outpacket) {
414                 perror("traceroute: malloc");
415                 exit(1);
416         }
417         (void) bzero((char *)outpacket, datalen);
418         outpacket->ip.ip_dst = to->sin_addr;
419         outpacket->ip.ip_tos = tos;
420         outpacket->ip.ip_v = IPVERSION;
421         outpacket->ip.ip_id = 0;
422
423         ident = (getpid() & 0xffff) | 0x8000;
424
425         if ((pe = getprotobyname("icmp")) == NULL) {
426                 Fprintf(stderr, "icmp: unknown protocol\n");
427                 exit(10);
428         }
429         if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) {
430                 perror("traceroute: icmp socket");
431                 exit(5);
432         }
433         if (options & SO_DEBUG)
434                 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
435                                   (char *)&on, sizeof(on));
436         if (options & SO_DONTROUTE)
437                 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
438                                   (char *)&on, sizeof(on));
439
440         if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
441                 perror("traceroute: raw socket");
442                 exit(5);
443         }
444 #ifdef SO_SNDBUF
445         if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
446                        sizeof(datalen)) < 0) {
447                 perror("traceroute: SO_SNDBUF");
448                 exit(6);
449         }
450 #endif SO_SNDBUF
451 #ifdef IP_HDRINCL
452         if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
453                        sizeof(on)) < 0) {
454                 perror("traceroute: IP_HDRINCL");
455                 exit(6);
456         }
457 #endif IP_HDRINCL
458         if (options & SO_DEBUG)
459                 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
460                                   (char *)&on, sizeof(on));
461         if (options & SO_DONTROUTE)
462                 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
463                                   (char *)&on, sizeof(on));
464
465         if (source) {
466                 (void) bzero((char *)&from, sizeof(struct sockaddr));
467                 from.sin_family = AF_INET;
468                 from.sin_addr.s_addr = inet_addr(source);
469                 if (from.sin_addr.s_addr == -1) {
470                         Printf("traceroute: unknown host %s\n", source);
471                         exit(1);
472                 }
473                 outpacket->ip.ip_src = from.sin_addr;
474 #ifndef IP_HDRINCL
475                 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) {
476                         perror ("traceroute: bind:");
477                         exit (1);
478                 }
479 #endif IP_HDRINCL
480         }
481
482         Fprintf(stderr, "traceroute to %s (%s)", hostname,
483                 inet_ntoa(to->sin_addr));
484         if (source)
485                 Fprintf(stderr, " from %s", source);
486         Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
487         (void) fflush(stderr);
488
489         for (ttl = 1; ttl <= max_ttl; ++ttl) {
490                 u_long lastaddr = 0;
491                 int got_there = 0;
492                 int unreachable = 0;
493
494                 Printf("%2d ", ttl);
495                 for (probe = 0; probe < nprobes; ++probe) {
496                         int cc;
497                         struct timeval t1, t2;
498                         struct timezone tz;
499                         struct ip *ip;
500
501                         (void) gettimeofday(&t1, &tz);
502                         send_probe(++seq, ttl);
503                         while (cc = wait_for_reply(s, &from, &t1)) {
504                                 (void) gettimeofday(&t2, &tz);
505                                 if ((i = packet_ok(packet, cc, &from, seq))) {
506                                         if (from.sin_addr.s_addr != lastaddr) {
507                                                 print(packet, cc, &from);
508                                                 lastaddr = from.sin_addr.s_addr;
509                                         }
510                                         Printf("  %.3f ms", deltaT(&t1, &t2));
511                                         switch(i - 1) {
512                                         case ICMP_UNREACH_PORT:
513 #ifndef ARCHAIC
514                                                 ip = (struct ip *)packet;
515                                                 if (ip->ip_ttl <= 1)
516                                                         Printf(" !");
517 #endif ARCHAIC
518                                                 ++got_there;
519                                                 break;
520                                         case ICMP_UNREACH_NET:
521                                                 ++unreachable;
522                                                 Printf(" !N");
523                                                 break;
524                                         case ICMP_UNREACH_HOST:
525                                                 ++unreachable;
526                                                 Printf(" !H");
527                                                 break;
528                                         case ICMP_UNREACH_PROTOCOL:
529                                                 ++got_there;
530                                                 Printf(" !P");
531                                                 break;
532                                         case ICMP_UNREACH_NEEDFRAG:
533                                                 ++unreachable;
534                                                 Printf(" !F");
535                                                 break;
536                                         case ICMP_UNREACH_SRCFAIL:
537                                                 ++unreachable;
538                                                 Printf(" !S");
539                                                 break;
540                                         }
541                                         break;
542                                 }
543                         }
544                         if (cc == 0)
545                                 Printf(" *");
546                         (void) fflush(stdout);
547                 }
548                 putchar('\n');
549                 if (got_there || unreachable >= nprobes-1)
550                         exit(0);
551         }
552 }
553
554 int
555 wait_for_reply(sock, from, sent)
556         int sock;
557         struct sockaddr_in *from;
558         struct timeval *sent;
559 {
560         fd_set fds;
561         struct timeval now, wait;
562         int cc = 0;
563         int fromlen = sizeof (*from);
564
565         FD_ZERO(&fds);
566         FD_SET(sock, &fds);
567         gettimeofday(&now, NULL);
568         wait.tv_sec = (sent->tv_sec + waittime) - now.tv_sec;
569         wait.tv_usec =  sent->tv_usec - now.tv_usec;
570         if (wait.tv_usec < 0) {
571                 wait.tv_usec += 1000000;
572                 wait.tv_sec--;
573         }
574         if (wait.tv_sec < 0)
575                 wait.tv_sec = wait.tv_usec = 0;
576
577         if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
578                 cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
579                             (struct sockaddr *)from, &fromlen);
580
581         return(cc);
582 }
583
584
585 void
586 send_probe(seq, ttl)
587         int seq, ttl;
588 {
589         struct opacket *op = outpacket;
590         struct ip *ip = &op->ip;
591         struct udphdr *up = &op->udp;
592         int i;
593
594         ip->ip_off = 0;
595         ip->ip_hl = sizeof(*ip) >> 2;
596         ip->ip_p = IPPROTO_UDP;
597         ip->ip_len = datalen;
598         ip->ip_ttl = ttl;
599         ip->ip_v = IPVERSION;
600         ip->ip_id = htons(ident+seq);
601
602         up->uh_sport = htons(ident);
603         up->uh_dport = htons(port+seq);
604         up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip)));
605         up->uh_sum = 0;
606
607         op->seq = seq;
608         op->ttl = ttl;
609         (void) gettimeofday(&op->tv, &tz);
610
611         i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
612                    sizeof(struct sockaddr));
613         if (i < 0 || i != datalen)  {
614                 if (i<0)
615                         perror("sendto");
616                 Printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
617                         datalen, i);
618                 (void) fflush(stdout);
619         }
620 }
621
622
623 double
624 deltaT(t1p, t2p)
625         struct timeval *t1p, *t2p;
626 {
627         register double dt;
628
629         dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
630              (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
631         return (dt);
632 }
633
634
635 /*
636  * Convert an ICMP "type" field to a printable string.
637  */
638 char *
639 pr_type(t)
640         u_char t;
641 {
642         static char *ttab[] = {
643         "Echo Reply",   "ICMP 1",       "ICMP 2",       "Dest Unreachable",
644         "Source Quench", "Redirect",    "ICMP 6",       "ICMP 7",
645         "Echo",         "ICMP 9",       "ICMP 10",      "Time Exceeded",
646         "Param Problem", "Timestamp",   "Timestamp Reply", "Info Request",
647         "Info Reply"
648         };
649
650         if(t > 16)
651                 return("OUT-OF-RANGE");
652
653         return(ttab[t]);
654 }
655
656
657 int
658 packet_ok(buf, cc, from, seq)
659         u_char *buf;
660         int cc;
661         struct sockaddr_in *from;
662         int seq;
663 {
664         register struct icmp *icp;
665         u_char type, code;
666         int hlen;
667 #ifndef ARCHAIC
668         struct ip *ip;
669
670         ip = (struct ip *) buf;
671         hlen = ip->ip_hl << 2;
672         if (cc < hlen + ICMP_MINLEN) {
673                 if (verbose)
674                         Printf("packet too short (%d bytes) from %s\n", cc,
675                                 inet_ntoa(from->sin_addr));
676                 return (0);
677         }
678         cc -= hlen;
679         icp = (struct icmp *)(buf + hlen);
680 #else
681         icp = (struct icmp *)buf;
682 #endif ARCHAIC
683         type = icp->icmp_type; code = icp->icmp_code;
684         if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
685             type == ICMP_UNREACH) {
686                 struct ip *hip;
687                 struct udphdr *up;
688
689                 hip = &icp->icmp_ip;
690                 hlen = hip->ip_hl << 2;
691                 up = (struct udphdr *)((u_char *)hip + hlen);
692                 if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
693                     up->uh_sport == htons(ident) &&
694                     up->uh_dport == htons(port+seq))
695                         return (type == ICMP_TIMXCEED? -1 : code+1);
696         }
697 #ifndef ARCHAIC
698         if (verbose) {
699                 int i;
700                 u_long *lp = (u_long *)&icp->icmp_ip;
701
702                 Printf("\n%d bytes from %s to %s", cc,
703                         inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst));
704                 Printf(": icmp type %d (%s) code %d\n", type, pr_type(type),
705                        icp->icmp_code);
706                 for (i = 4; i < cc ; i += sizeof(long))
707                         Printf("%2d: x%8.8lx\n", i, *lp++);
708         }
709 #endif ARCHAIC
710         return(0);
711 }
712
713
714 void
715 print(buf, cc, from)
716         u_char *buf;
717         int cc;
718         struct sockaddr_in *from;
719 {
720         struct ip *ip;
721         int hlen;
722
723         ip = (struct ip *) buf;
724         hlen = ip->ip_hl << 2;
725         cc -= hlen;
726
727         if (nflag)
728                 Printf(" %s", inet_ntoa(from->sin_addr));
729         else
730                 Printf(" %s (%s)", inetname(from->sin_addr),
731                        inet_ntoa(from->sin_addr));
732
733         if (verbose)
734                 Printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
735 }
736
737
738 #ifdef notyet
739 /*
740  * Checksum routine for Internet Protocol family headers (C Version)
741  */
742 u_short
743 in_cksum(addr, len)
744         u_short *addr;
745         int len;
746 {
747         register int nleft = len;
748         register u_short *w = addr;
749         register u_short answer;
750         register int sum = 0;
751
752         /*
753          *  Our algorithm is simple, using a 32 bit accumulator (sum),
754          *  we add sequential 16 bit words to it, and at the end, fold
755          *  back all the carry bits from the top 16 bits into the lower
756          *  16 bits.
757          */
758         while (nleft > 1)  {
759                 sum += *w++;
760                 nleft -= 2;
761         }
762
763         /* mop up an odd byte, if necessary */
764         if (nleft == 1)
765                 sum += *(u_char *)w;
766
767         /*
768          * add back carry outs from top 16 bits to low 16 bits
769          */
770         sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
771         sum += (sum >> 16);                     /* add carry */
772         answer = ~sum;                          /* truncate to 16 bits */
773         return (answer);
774 }
775 #endif notyet
776
777 /*
778  * Subtract 2 timeval structs:  out = out - in.
779  * Out is assumed to be >= in.
780  */
781 void
782 tvsub(out, in)
783         register struct timeval *out, *in;
784 {
785         if ((out->tv_usec -= in->tv_usec) < 0)   {
786                 out->tv_sec--;
787                 out->tv_usec += 1000000;
788         }
789         out->tv_sec -= in->tv_sec;
790 }
791
792
793 /*
794  * Construct an Internet address representation.
795  * If the nflag has been supplied, give
796  * numeric value, otherwise try for symbolic name.
797  */
798 char *
799 inetname(in)
800         struct in_addr in;
801 {
802         register char *cp;
803         static char line[50];
804         struct hostent *hp;
805         static char domain[MAXHOSTNAMELEN + 1];
806         static int first = 1;
807
808         if (first && !nflag) {
809                 first = 0;
810                 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
811                     (cp = index(domain, '.')))
812                         (void) strcpy(domain, cp + 1);
813                 else
814                         domain[0] = 0;
815         }
816         cp = 0;
817         if (!nflag && in.s_addr != INADDR_ANY) {
818                 hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
819                 if (hp) {
820                         if ((cp = index(hp->h_name, '.')) &&
821                             !strcmp(cp + 1, domain))
822                                 *cp = 0;
823                         cp = hp->h_name;
824                 }
825         }
826         if (cp)
827                 (void) strcpy(line, cp);
828         else {
829                 in.s_addr = ntohl(in.s_addr);
830 #define C(x)    ((x) & 0xff)
831                 Sprintf(line, "%lu.%lu.%lu.%lu", C(in.s_addr >> 24),
832                         C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
833         }
834         return (line);
835 }
836
837 void
838 usage()
839 {
840         (void)fprintf(stderr,
841 "usage: traceroute [-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\t\
842 [-s src_addr] [-t tos] [-w wait] host [data size]\n");
843         exit(1);
844 }