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