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