]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/traceroute/traceroute.c
This commit was generated by cvs2svn to compensate for changes in r15920,
[FreeBSD/FreeBSD.git] / usr.sbin / traceroute / traceroute.c
1 #ifndef lint
2 static char *rcsid =
3     "@(#)$Header: traceroute.c,v 1.27 95/10/18 00:17:06 leres 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
298         oix = optlist;
299         bzero(optlist, sizeof(optlist));
300
301         argc--, av++;
302         while (argc && *av[0] == '-')  {
303                 while (*++av[0])
304                         switch (*av[0]) {
305                         case 'd':
306                                 options |= SO_DEBUG;
307                                 break;
308                         case 'g':
309                                 argc--, av++;
310                                 if ((lsrr+1) >= ((MAX_IPOPTLEN-IPOPT_MINOFF)/sizeof(u_long))) {
311                                   Fprintf(stderr,"No more than %d gateways\n",
312                                           (u_int)((MAX_IPOPTLEN-IPOPT_MINOFF)/sizeof(u_long))-1);
313                                   exit(1);
314                                 }
315                                 if (lsrr == 0) {
316                                   *oix++ = IPOPT_LSRR;
317                                   oix++;        /* Fill in total length later */
318                                   *oix++ = IPOPT_MINOFF; /* Pointer to LSRR addresses */
319                                 }
320                                 lsrr++;
321                                 if (isdigit(*av[0])) {
322                                   gw = inet_addr(*av);
323                                   if (gw) {
324                                     bcopy(&gw, oix, sizeof(u_long));
325                                   } else {
326                                     Fprintf(stderr, "Unknown host %s\n",av[0]);
327                                     exit(1);
328                                   }
329                                 } else {
330                                   hp = gethostbyname(av[0]);
331                                   if (hp) {
332                                     bcopy(hp->h_addr, oix, sizeof(u_long));
333                                   } else {
334                                     Fprintf(stderr, "Unknown host %s\n",av[0]);
335                                     exit(1);
336                                   }
337                                 }
338                                 oix += sizeof(u_long);
339                                 goto nextarg;
340                         case 'm':
341                                 argc--, av++;
342                                 max_ttl = atoi(av[0]);
343                                 if (max_ttl <= 1) {
344                                         Fprintf(stderr, "max ttl must be >1\n");
345                                         exit(1);
346                                 }
347                                 goto nextarg;
348                         case 'n':
349                                 nflag++;
350                                 break;
351                         case 'p':
352                                 argc--, av++;
353                                 port = atoi(av[0]);
354                                 if (port < 1) {
355                                         Fprintf(stderr, "port must be >0\n");
356                                         exit(1);
357                                 }
358                                 goto nextarg;
359                         case 'q':
360                                 argc--, av++;
361                                 nprobes = atoi(av[0]);
362                                 if (nprobes < 1) {
363                                         Fprintf(stderr, "nprobes must be >0\n");
364                                         exit(1);
365                                 }
366                                 goto nextarg;
367                         case 'r':
368                                 options |= SO_DONTROUTE;
369                                 break;
370                         case 's':
371                                 /*
372                                  * set the ip source address of the outbound
373                                  * probe (e.g., on a multi-homed host).
374                                  */
375                                 argc--, av++;
376                                 source = av[0];
377                                 goto nextarg;
378                         case 't':
379                                 argc--, av++;
380                                 tos = atoi(av[0]);
381                                 if (tos < 0 || tos > 255) {
382                                         Fprintf(stderr, "tos must be 0 to 255\n");
383                                         exit(1);
384                                 }
385                                 goto nextarg;
386                         case 'v':
387                                 verbose++;
388                                 break;
389                         case 'w':
390                                 argc--, av++;
391                                 waittime = atoi(av[0]);
392                                 if (waittime <= 1) {
393                                         Fprintf(stderr, "wait must be >1 sec\n");
394                                         exit(1);
395                                 }
396                                 goto nextarg;
397                         default:
398                                 Printf(usage);
399                                 exit(1);
400                         }
401         nextarg:
402                 argc--, av++;
403         }
404         if (argc != 1)  {
405                 Printf(usage);
406                 exit(1);
407         }
408         setlinebuf (stdout);
409
410         bzero((char *)&whereto, sizeof(struct sockaddr));
411         to->sin_family = AF_INET;
412         to->sin_addr.s_addr = inet_addr(av[0]);
413         if (to->sin_addr.s_addr != -1) {
414                 (void) strcpy(hnamebuf, av[0]);
415                 hostname = hnamebuf;
416         } else {
417                 hp = gethostbyname(av[0]);
418                 if (hp) {
419                         to->sin_family = hp->h_addrtype;
420                         bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
421                         hostname = strdup(hp->h_name);
422                 } else {
423                         Printf("%s: unknown host %s\n", argv[0], av[0]);
424                         exit(1);
425                 }
426         }
427
428         if (argc >= 2)
429                 datalen = atoi(av[1]);
430         if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) {
431                 Fprintf(stderr, "traceroute: packet size must be 0 <= s < %d\n",
432                         (u_int)(MAXPACKET - sizeof(struct opacket)));
433                 exit(1);
434         }
435         datalen += sizeof(struct opacket);
436         outpacket = (struct opacket *)malloc((unsigned)datalen);
437         if (! outpacket) {
438                 perror("traceroute: malloc");
439                 exit(1);
440         }
441         bzero((char *)outpacket, datalen);
442         outpacket->ip.ip_dst = to->sin_addr;
443         outpacket->ip.ip_tos = tos;
444         outpacket->ip.ip_v   = IPVERSION;
445         outpacket->ip.ip_hl  = sizeof(struct ip) >> 2;
446
447         ident = (getpid() & 0xffff) | 0x8000;
448
449         if ((pe = getprotobyname("icmp")) == NULL) {
450                 Fprintf(stderr, "icmp: unknown protocol\n");
451                 exit(10);
452         }
453         if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) {
454                 perror("traceroute: icmp socket");
455                 exit(5);
456         }
457         if (options & SO_DEBUG)
458                 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
459                                   (char *)&on, sizeof(on));
460         if (options & SO_DONTROUTE)
461                 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
462                                   (char *)&on, sizeof(on));
463
464         if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
465                 perror("traceroute: raw socket");
466                 exit(5);
467         }
468
469         if (lsrr > 0) {
470           lsrr++;
471           optlist[IPOPT_OLEN]=IPOPT_MINOFF-1+(lsrr*sizeof(u_long));
472           bcopy((caddr_t)&to->sin_addr, oix, sizeof(u_long));
473           oix += sizeof(u_long);
474           while ((oix - optlist)&3) oix++;              /* Pad to an even boundry */
475
476           if ((pe = getprotobyname("ip")) == NULL) {
477             perror("traceroute: unknown protocol ip\n");
478             exit(10);
479           }
480 #ifdef IP_OPTIONS
481           if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS, optlist, oix-optlist)) < 0) {
482             perror("traceroute: lsrr options");
483             exit(5);
484           }
485 #endif
486         }
487
488 #ifdef SO_SNDBUF
489         if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
490                        sizeof(datalen)) < 0) {
491                 perror("traceroute: SO_SNDBUF");
492                 exit(6);
493         }
494 #endif SO_SNDBUF
495 #ifdef IP_HDRINCL
496         if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
497                        sizeof(on)) < 0) {
498                 perror("traceroute: IP_HDRINCL");
499                 exit(6);
500         }
501 #endif IP_HDRINCL
502         if (options & SO_DEBUG)
503                 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
504                                   (char *)&on, sizeof(on));
505         if (options & SO_DONTROUTE)
506                 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
507                                   (char *)&on, sizeof(on));
508
509         if (source) {
510                 bzero((char *)&from, sizeof(struct sockaddr));
511                 from.sin_family = AF_INET;
512                 from.sin_addr.s_addr = inet_addr(source);
513                 if (from.sin_addr.s_addr == -1) {
514                         Printf("traceroute: unknown host %s\n", source);
515                         exit(1);
516                 }
517                 outpacket->ip.ip_src = from.sin_addr;
518 #ifndef IP_HDRINCL
519                 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) {
520                         perror ("traceroute: bind:");
521                         exit (1);
522                 }
523 #endif IP_HDRINCL
524         }
525
526         Fprintf(stderr, "traceroute to %s (%s)", hostname,
527                 inet_ntoa(to->sin_addr));
528         if (source)
529                 Fprintf(stderr, " from %s", source);
530         Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
531         (void) fflush(stderr);
532
533         for (ttl = 1; ttl <= max_ttl; ++ttl) {
534                 u_long lastaddr = 0;
535                 int got_there = 0;
536                 int unreachable = 0;
537
538                 Printf("%2d ", ttl);
539                 for (probe = 0; probe < nprobes; ++probe) {
540                         int cc;
541                         struct timeval t1, t2;
542                         struct timezone tz;
543                         struct ip *ip;
544
545                         (void) gettimeofday(&t1, &tz);
546                         send_probe(++seq, ttl, &t1);
547                         while ((cc = wait_for_reply(s, &from, &t1)) != 0) {
548                                 (void) gettimeofday(&t2, &tz);
549                                 if ((i = packet_ok(packet, cc, &from, seq))) {
550                                         if (from.sin_addr.s_addr != lastaddr) {
551                                                 print(packet, cc, &from);
552                                                 lastaddr = from.sin_addr.s_addr;
553                                         }
554                                         Printf("  %.3f ms", deltaT(&t1, &t2));
555                                         switch(i - 1) {
556                                         case ICMP_UNREACH_PORT:
557 #ifndef ARCHAIC
558                                                 ip = (struct ip *)packet;
559                                                 if (ip->ip_ttl <= 1)
560                                                         Printf(" !");
561 #endif ARCHAIC
562                                                 ++got_there;
563                                                 break;
564                                         case ICMP_UNREACH_NET:
565                                                 ++unreachable;
566                                                 Printf(" !N");
567                                                 break;
568                                         case ICMP_UNREACH_HOST:
569                                                 ++unreachable;
570                                                 Printf(" !H");
571                                                 break;
572                                         case ICMP_UNREACH_PROTOCOL:
573                                                 ++got_there;
574                                                 Printf(" !P");
575                                                 break;
576                                         case ICMP_UNREACH_NEEDFRAG:
577                                                 ++unreachable;
578                                                 Printf(" !F");
579                                                 break;
580                                         case ICMP_UNREACH_SRCFAIL:
581                                                 ++unreachable;
582                                                 Printf(" !S");
583                                                 break;
584                                         }
585                                         break;
586                                 }
587                         }
588                         if (cc == 0)
589                                 Printf(" *");
590                         (void) fflush(stdout);
591                 }
592                 putchar('\n');
593                 if (got_there || unreachable >= nprobes-1)
594                         exit(0);
595         }
596         exit(0);
597 }
598
599 int
600 wait_for_reply(int sock, struct sockaddr_in *from, struct timeval *sent)
601 {
602         fd_set fds;
603         struct timeval now, wait;
604         int cc = 0;
605         int fromlen = sizeof (*from);
606
607         FD_ZERO(&fds);
608         FD_SET(sock, &fds);
609         gettimeofday(&now, NULL);
610         wait.tv_sec = (sent->tv_sec + waittime) - now.tv_sec;
611         wait.tv_usec = sent->tv_usec - now.tv_usec;
612         if (wait.tv_usec < 0) {
613                 wait.tv_usec += 1000000;
614                 wait.tv_sec--;
615         }
616         if (wait.tv_sec < 0)
617                 wait.tv_sec = wait.tv_usec = 0;
618
619         if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
620                 cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
621                             (struct sockaddr *)from, &fromlen);
622
623         return(cc);
624 }
625
626
627 void
628 send_probe(int seq, int ttl, struct timeval *tp)
629 {
630         struct opacket *op = outpacket;
631         struct ip *ip = &op->ip;
632         struct udphdr *up = &op->udp;
633         int i;
634
635         ip->ip_off = 0;
636         ip->ip_p = IPPROTO_UDP;
637         ip->ip_len = datalen;
638         ip->ip_ttl = ttl;
639
640         up->uh_sport = htons(ident);
641         up->uh_dport = htons(port+seq);
642         up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip)));
643         up->uh_sum = 0;
644
645         op->seq = seq;
646         op->ttl = ttl;
647         op->tv = *tp;
648
649         i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
650                    sizeof(struct sockaddr));
651         if (i < 0 || i != datalen)  {
652                 if (i<0)
653                         perror("sendto");
654                 Printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
655                         datalen, i);
656                 (void) fflush(stdout);
657         }
658 }
659
660 /*
661  * Convert an ICMP "type" field to a printable string.
662  */
663 char *
664 pr_type(u_char t)
665 {
666         static char *ttab[] = {
667         "Echo Reply",   "ICMP 1",       "ICMP 2",       "Dest Unreachable",
668         "Source Quench", "Redirect",    "ICMP 6",       "ICMP 7",
669         "Echo",         "ICMP 9",       "ICMP 10",      "Time Exceeded",
670         "Param Problem", "Timestamp",   "Timestamp Reply", "Info Request",
671         "Info Reply"
672         };
673
674         if(t > 16)
675                 return("OUT-OF-RANGE");
676
677         return(ttab[t]);
678 }
679
680
681 int
682 packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
683 {
684         register struct icmp *icp;
685         u_char type, code;
686         int hlen;
687 #ifndef ARCHAIC
688         struct ip *ip;
689
690         ip = (struct ip *) buf;
691         hlen = ip->ip_hl << 2;
692         if (cc < hlen + ICMP_MINLEN) {
693                 if (verbose)
694                         Printf("packet too short (%d bytes) from %s\n", cc,
695                                 inet_ntoa(from->sin_addr));
696                 return (0);
697         }
698         cc -= hlen;
699         icp = (struct icmp *)(buf + hlen);
700 #else
701         icp = (struct icmp *)buf;
702 #endif ARCHAIC
703         type = icp->icmp_type; code = icp->icmp_code;
704         if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
705             type == ICMP_UNREACH) {
706                 struct ip *hip;
707                 struct udphdr *up;
708
709                 hip = &icp->icmp_ip;
710                 hlen = hip->ip_hl << 2;
711                 up = (struct udphdr *)((u_char *)hip + hlen);
712                 if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
713                     up->uh_sport == htons(ident) &&
714                     up->uh_dport == htons(port+seq))
715                         return (type == ICMP_TIMXCEED? -1 : code+1);
716         }
717 #ifndef ARCHAIC
718         if (verbose) {
719                 int i;
720                 u_long *lp = (u_long *)&icp->icmp_ip;
721
722                 Printf("\n%d bytes from %s to %s", cc,
723                         inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst));
724                 Printf(": icmp type %d (%s) code %d\n", type, pr_type(type),
725                        icp->icmp_code);
726                 for (i = 4; i < cc ; i += sizeof(long))
727                         Printf("%2d: x%8.8lx\n", i, *lp++);
728         }
729 #endif ARCHAIC
730         return(0);
731 }
732
733
734 void
735 print(u_char *buf, int cc, struct sockaddr_in *from)
736 {
737         struct ip *ip;
738         int hlen;
739
740         ip = (struct ip *) buf;
741         hlen = ip->ip_hl << 2;
742         cc -= hlen;
743
744         if (nflag)
745                 Printf(" %s", inet_ntoa(from->sin_addr));
746         else
747                 Printf(" %s (%s)", inetname(from->sin_addr),
748                        inet_ntoa(from->sin_addr));
749
750         if (verbose)
751                 Printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
752 }
753
754
755 #ifdef notyet
756 /*
757  * Checksum routine for Internet Protocol family headers (C Version)
758  */
759 in_cksum(u_short *addr, int len)
760 {
761         register int nleft = len;
762         register u_short *w = addr;
763         register u_short answer;
764         register int sum = 0;
765
766         /*
767          *  Our algorithm is simple, using a 32 bit accumulator (sum),
768          *  we add sequential 16 bit words to it, and at the end, fold
769          *  back all the carry bits from the top 16 bits into the lower
770          *  16 bits.
771          */
772         while (nleft > 1)  {
773                 sum += *w++;
774                 nleft -= 2;
775         }
776
777         /* mop up an odd byte, if necessary */
778         if (nleft == 1)
779                 sum += *(u_char *)w;
780
781         /*
782          * add back carry outs from top 16 bits to low 16 bits
783          */
784         sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
785         sum += (sum >> 16);                     /* add carry */
786         answer = ~sum;                          /* truncate to 16 bits */
787         return (answer);
788 }
789 #endif notyet
790
791 /*
792  * Subtract 2 timeval structs:  out = out - in.
793  * Out is assumed to be >= in.
794  */
795 void
796 tvsub(register struct timeval *out, register struct timeval *in)
797 {
798         if ((out->tv_usec -= in->tv_usec) < 0)   {
799                 out->tv_sec--;
800                 out->tv_usec += 1000000;
801         }
802         out->tv_sec -= in->tv_sec;
803 }
804
805
806 /*
807  * Construct an Internet address representation.
808  * If the nflag has been supplied, give
809  * numeric value, otherwise try for symbolic name.
810  */
811 char *
812 inetname(struct in_addr in)
813 {
814         register char *cp;
815         static char line[50];
816         struct hostent *hp;
817         static char domain[MAXHOSTNAMELEN + 1];
818         static int first = 1;
819
820         if (first && !nflag) {
821                 first = 0;
822                 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
823                     (cp = strchr(domain, '.')))
824                         (void) strcpy(domain, cp + 1);
825                 else
826                         domain[0] = 0;
827         }
828         cp = 0;
829         if (!nflag && in.s_addr != INADDR_ANY) {
830                 hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
831                 if (hp) {
832                         if ((cp = strchr(hp->h_name, '.')) &&
833                             !strcmp(cp + 1, domain))
834                                 *cp = 0;
835                         cp = hp->h_name;
836                 }
837         }
838         if (cp)
839                 (void) strcpy(line, cp);
840         else {
841                 in.s_addr = ntohl(in.s_addr);
842 #define C(x)    ((x) & 0xff)
843                 Sprintf(line, "%lu.%lu.%lu.%lu", C(in.s_addr >> 24),
844                         C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
845         }
846         return (line);
847 }