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