2 * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 static const char copyright
[] =
24 "@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000\n\
25 The Regents of the University of California. All rights reserved.\n";
26 static const char rcsid
[] =
27 "@(#)$Id: traceroute.c 20492 2007-04-01 11:51:14Z axeld $ (LBL)";
31 * traceroute host - trace the route ip packets follow going to "host".
33 * Attempt to trace the route an ip packet would follow to some
34 * internet host. We find out intermediate hops by launching probe
35 * packets with a small ttl (time to live) then listening for an
36 * icmp "time exceeded" reply from a gateway. We start our probes
37 * with a ttl of one and increase by one until we get an icmp "port
38 * unreachable" (which means we got to "host") or hit a max (which
39 * defaults to 30 hops & can be changed with the -m flag). Three
40 * probes (change with -q flag) are sent at each ttl setting and a
41 * line is printed showing the ttl, address of the gateway and
42 * round trip time of each probe. If the probe answers come from
43 * different gateways, the address of each responding system will
44 * be printed. If there is no response within a 5 sec. timeout
45 * interval (changed with the -w flag), a "*" is printed for that
48 * Probe packets are UDP format. We don't want the destination
49 * host to process them so the destination port is set to an
50 * unlikely value (if some clod on the destination is using that
51 * value, it can be changed with the -p flag).
53 * A sample use might be:
55 * [yak 71]% traceroute nis.nsf.net.
56 * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
57 * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms
58 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
59 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
60 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms
61 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms
62 * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms
63 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms
64 * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms
65 * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms
66 * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms
67 * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms
69 * Note that lines 2 & 3 are the same. This is due to a buggy
70 * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
71 * packets with a zero ttl.
73 * A more interesting example is:
75 * [yak 72]% traceroute allspice.lcs.mit.edu.
76 * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
77 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
78 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms
79 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms
80 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms
81 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms
82 * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms
83 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms
84 * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms
85 * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms
86 * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms
87 * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms
89 * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms
94 * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms
96 * (I start to see why I'm having so much trouble with mail to
97 * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away
98 * either don't send ICMP "time exceeded" messages or send them
99 * with a ttl too small to reach us. 14 - 17 are running the
100 * MIT C Gateway code that doesn't send "time exceeded"s. God
101 * only knows what's going on with 12.
103 * The silent gateway 12 in the above may be the result of a bug in
104 * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3)
105 * sends an unreachable message using whatever ttl remains in the
106 * original datagram. Since, for gateways, the remaining ttl is
107 * zero, the icmp "time exceeded" is guaranteed to not make it back
108 * to us. The behavior of this bug is slightly more interesting
109 * when it appears on the destination system:
111 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
112 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms
113 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms
114 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms
115 * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms
116 * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms
123 * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms !
125 * Notice that there are 12 "gateways" (13 is the final
126 * destination) and exactly the last half of them are "missing".
127 * What's really happening is that rip (a Sun-3 running Sun OS3.5)
128 * is using the ttl from our arriving datagram as the ttl in its
129 * icmp reply. So, the reply will time out on the return path
130 * (with no notice sent to anyone since icmp's aren't sent for
131 * icmp's) until we probe with a ttl that's at least twice the path
132 * length. I.e., rip is really only 7 hops away. A reply that
133 * returns with a ttl of 1 is a clue this problem exists.
134 * Traceroute prints a "!" after the time if the ttl is <= 1.
135 * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
136 * non-standard (HPUX) software, expect to see this problem
137 * frequently and/or take care picking the target host of your
140 * Other possible annotations after the time are !H, !N, !P (got a host,
141 * network or protocol unreachable, respectively), !S or !F (source
142 * route failed or fragmentation needed -- neither of these should
143 * ever occur and the associated gateway is busted if you see one). If
144 * almost all the probes result in some kind of unreachable, traceroute
145 * will give up and exit.
149 * This program must be run by root or be setuid. (I suggest that
150 * you *don't* make it setuid -- casual use could result in a lot
151 * of unnecessary traffic on our poor, congested nets.)
153 * This program requires a kernel mod that does not appear in any
154 * system available from Berkeley: A raw ip socket using proto
155 * IPPROTO_RAW must interpret the data sent as an ip datagram (as
156 * opposed to data to be wrapped in a ip datagram). See the README
157 * file that came with the source to this program for a description
158 * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may
159 * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
160 * MODIFIED TO RUN THIS PROGRAM.
162 * The udp port usage may appear bizarre (well, ok, it is bizarre).
163 * The problem is that an icmp message only contains 8 bytes of
164 * data from the original datagram. 8 bytes is the size of a udp
165 * header so, if we want to associate replies with the original
166 * datagram, the necessary information must be encoded into the
167 * udp header (the ip id could be used but there's no way to
168 * interlock with the kernel's assignment of ip id's and, anyway,
169 * it would have taken a lot more kernel hacking to allow this
170 * code to set the ip id). So, to allow two or more users to
171 * use traceroute simultaneously, we use this task's pid as the
172 * source port (the high bit is set to move the port number out
173 * of the "likely" range). To keep track of which probe is being
174 * replied to (so times and/or hop counts don't get confused by a
175 * reply that was delayed in transit), we increment the destination
176 * port number before each probe.
178 * Don't use this as a coding example. I was trying to find a
179 * routing problem and this code sort-of popped out after 48 hours
180 * without sleep. I was amazed it ever compiled, much less ran.
182 * I stole the idea for this program from Steve Deering. Since
183 * the first release, I've learned that had I attended the right
184 * IETF working group meetings, I also could have stolen it from Guy
185 * Almes or Matt Mathis. I don't know (or care) who came up with
186 * the idea first. I envy the originators' perspicacity and I'm
187 * glad they didn't keep the idea a secret.
189 * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
190 * enhancements to the original distribution.
192 * I've hacked up a round-trip-route version of this that works by
193 * sending a loose-source-routed udp datagram through the destination
194 * back to yourself. Unfortunately, SO many gateways botch source
195 * routing, the thing is almost worthless. Maybe one day...
197 * -- Van Jacobson (van@ee.lbl.gov)
198 * Tue Dec 20 03:50:13 PST 1988
201 #include <sys/param.h>
202 #include <sys/ioctl.h>
203 #ifdef HAVE_SYS_SELECT_H
204 #include <sys/select.h>
206 #include <sys/socket.h>
207 #include <sys/time.h>
209 #include <netinet/in.h>
210 #include <netinet/ip.h>
211 #include <netinet/ip_var.h>
212 #include <netinet/ip_icmp.h>
213 #include <netinet/udp.h>
215 #include <arpa/inet.h>
231 #ifdef HAVE_OS_PROTO_H
232 #include "os-proto.h"
236 #ifndef ICMP_UNREACH_FILTER_PROHIB
237 #define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohibited filter */
239 #ifndef ICMP_UNREACH_HOST_PRECEDENCE
240 #define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host precedence violation */
242 #ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF
243 #define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* precedence cutoff */
246 #include "findsaddr.h"
247 #include "ifaddrlist.h"
248 #include "traceroute.h"
250 /* Maximum number of gateways (include room for one noop) */
251 #define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))
253 #ifndef MAXHOSTNAMELEN
254 #define MAXHOSTNAMELEN 64
257 #define Fprintf (void)fprintf
258 #define Printf (void)printf
260 /* Host name and address list */
267 /* Data section of the probe packet */
269 u_char seq
; /* sequence number of this packet */
270 u_char ttl
; /* ttl packet left with */
271 struct timeval tv
; /* time packet left */
274 #ifndef HAVE_ICMP_NEXTMTU
275 /* Path MTU Discovery (RFC1191) */
282 u_char packet
[512]; /* last inbound (icmp) packet */
284 struct ip
*outip
; /* last output (udp) packet */
285 struct udphdr
*outudp
; /* last output (udp) packet */
286 struct outdata
*outdata
; /* last output (udp) packet */
288 struct icmp
*outicmp
; /* last output (icmp) packet */
290 /* loose source route gateway list (including room for final destination) */
291 u_int32_t gwlist
[NGATEWAYS
+ 1];
293 int s
; /* receive (icmp) socket file descriptor */
294 int sndsock
; /* send (udp/icmp) socket file descriptor */
296 struct sockaddr whereto
; /* Who to try to reach */
297 struct sockaddr wherefrom
; /* Who we are */
298 int packlen
; /* total length of packet */
299 int minpacket
; /* min ip packet size */
300 int maxpacket
= 32 * 1024; /* max ip packet size */
301 int pmtu
; /* Path MTU Discovery (RFC1191) */
308 static const char devnull
[] = "/dev/null";
314 u_short port
= 32768 + 666; /* start udp dest port # for probe packets */
316 int options
; /* socket options */
318 int waittime
= 5; /* time to wait for response (in seconds) */
319 int nflag
; /* print addresses numerically */
320 int useicmp
; /* use icmp echo instead of udp packets */
321 #ifdef CANT_HACK_IPCKSUM
322 int doipcksum
= 0; /* don't calculate ip checksums by default */
324 int doipcksum
= 1; /* calculate ip checksums by default */
326 int optlen
; /* length of ip options */
333 double deltaT(struct timeval
*, struct timeval
*);
334 void freehostinfo(struct hostinfo
*);
335 void getaddr(u_int32_t
*, char *);
336 struct hostinfo
*gethostinfo(char *);
337 u_short
in_cksum(u_short
*, int);
338 char *inetname(struct in_addr
);
339 int main(int, char **);
340 int packet_ok(u_char
*, int, struct sockaddr_in
*, int);
341 char *pr_type(u_char
);
342 void print(u_char
*, int, struct sockaddr_in
*);
343 void send_probe(int, int, struct timeval
*);
344 int str2val(const char *, const char *, int, int);
345 void tvsub(struct timeval
*, struct timeval
*);
346 __dead
void usage(void);
347 int wait_for_reply(int, struct sockaddr_in
*, const struct timeval
*);
353 main(int argc
, char **argv
)
355 register int op
, code
, n
;
357 register const char *err
;
358 register u_char
*outp
;
359 register u_int32_t
*ap
;
360 register struct sockaddr_in
*from
= (struct sockaddr_in
*)&wherefrom
;
361 register struct sockaddr_in
*to
= (struct sockaddr_in
*)&whereto
;
362 register struct hostinfo
*hi
;
364 register struct protoent
*pe
;
365 register int ttl
, probe
, i
;
366 register int seq
= 0;
367 int tos
= 0, settos
= 0;
368 register int lsrr
= 0;
369 register u_short off
= 0;
370 struct ifaddrlist
*al
;
375 else if ((cp
= strrchr(argv
[0], '/')) != NULL
)
381 while ((op
= getopt(argc
, argv
, "dFInrvxf:g:i:m:p:q:s:t:w:z:")) != EOF
)
389 first_ttl
= str2val(optarg
, "first ttl", 1, 255);
397 if (lsrr
>= NGATEWAYS
) {
399 "%s: No more than %d gateways\n",
403 getaddr(gwlist
+ lsrr
, optarg
);
416 max_ttl
= str2val(optarg
, "max ttl", 1, 255);
424 port
= (u_short
)str2val(optarg
, "port",
429 nprobes
= str2val(optarg
, "nprobes", 1, -1);
433 options
|= SO_DONTROUTE
;
438 * set the ip source address of the outbound
439 * probe (e.g., on a multi-homed host).
445 tos
= str2val(optarg
, "tos", 0, 255);
454 doipcksum
= (doipcksum
== 0);
458 waittime
= str2val(optarg
, "wait time",
463 pausemsecs
= str2val(optarg
, "pause msecs",
471 if (first_ttl
> max_ttl
) {
473 "%s: first ttl (%d) may not be greater than max ttl (%d)\n",
474 prog
, first_ttl
, max_ttl
);
479 Fprintf(stderr
, "%s: Warning: ip checksums disabled\n", prog
);
482 optlen
= (lsrr
+ 1) * sizeof(gwlist
[0]);
483 minpacket
= sizeof(*outip
) + sizeof(*outdata
) + optlen
;
485 minpacket
+= 8; /* XXX magic number */
487 minpacket
+= sizeof(*outudp
);
488 packlen
= minpacket
; /* minimum sized packet */
490 /* Process destination and optional packet size */
491 switch (argc
- optind
) {
494 packlen
= str2val(argv
[optind
+ 1],
495 "packet length", minpacket
, maxpacket
);
499 hostname
= argv
[optind
];
500 hi
= gethostinfo(hostname
);
501 setsin(to
, hi
->addrs
[0]);
504 "%s: Warning: %s has multiple addresses; using %s\n",
505 prog
, hostname
, inet_ntoa(to
->sin_addr
));
515 #ifdef HAVE_SETLINEBUF
518 setvbuf(stdout
, NULL
, _IOLBF
, 0);
521 outip
= (struct ip
*)malloc((unsigned)packlen
);
523 Fprintf(stderr
, "%s: malloc: %s\n", prog
, strerror(errno
));
526 memset((char *)outip
, 0, packlen
);
528 outip
->ip_v
= IPVERSION
;
531 #ifdef BYTESWAP_IP_HDR
532 outip
->ip_len
= htons(packlen
);
533 outip
->ip_off
= htons(off
);
535 outip
->ip_len
= packlen
;
538 outp
= (u_char
*)(outip
+ 1);
539 #ifdef HAVE_RAW_OPTIONS
541 register u_char
*optlist
;
547 gwlist
[lsrr
] = to
->sin_addr
.s_addr
;
549 outip
->ip_dst
.s_addr
= gwlist
[0];
551 /* force 4 byte alignment */
552 optlist
[0] = IPOPT_NOP
;
553 /* loose source route option */
554 optlist
[1] = IPOPT_LSRR
;
555 i
= lsrr
* sizeof(gwlist
[0]);
557 /* Pointer to LSRR addresses */
558 optlist
[3] = IPOPT_MINOFF
;
559 memcpy(optlist
+ 4, gwlist
+ 1, i
);
562 outip
->ip_dst
= to
->sin_addr
;
564 outip
->ip_hl
= (outp
- (u_char
*)outip
) >> 2;
565 ident
= (getpid() & 0xffff) | 0x8000;
567 outip
->ip_p
= IPPROTO_ICMP
;
569 outicmp
= (struct icmp
*)outp
;
570 outicmp
->icmp_type
= ICMP_ECHO
;
571 outicmp
->icmp_id
= htons(ident
);
573 outdata
= (struct outdata
*)(outp
+ 8); /* XXX magic number */
575 outip
->ip_p
= IPPROTO_UDP
;
577 outudp
= (struct udphdr
*)outp
;
578 outudp
->uh_sport
= htons(ident
);
580 htons((u_short
)(packlen
- (sizeof(*outip
) + optlen
)));
581 outdata
= (struct outdata
*)(outudp
+ 1);
585 if ((pe
= getprotobyname(cp
)) == NULL
) {
586 Fprintf(stderr
, "%s: unknown protocol %s\n", prog
, cp
);
590 /* Insure the socket fds won't be 0, 1 or 2 */
591 if (open(devnull
, O_RDONLY
) < 0 ||
592 open(devnull
, O_RDONLY
) < 0 ||
593 open(devnull
, O_RDONLY
) < 0) {
594 Fprintf(stderr
, "%s: open \"%s\": %s\n",
595 prog
, devnull
, strerror(errno
));
598 if ((s
= socket(AF_INET
, SOCK_RAW
, pe
->p_proto
)) < 0) {
599 Fprintf(stderr
, "%s: icmp socket: %s\n", prog
, strerror(errno
));
602 if (options
& SO_DEBUG
)
603 (void)setsockopt(s
, SOL_SOCKET
, SO_DEBUG
, (char *)&on
,
605 if (options
& SO_DONTROUTE
)
606 (void)setsockopt(s
, SOL_SOCKET
, SO_DONTROUTE
, (char *)&on
,
610 sndsock
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
);
612 sndsock
= socket(AF_INET
, SOCK_RAW
,
613 useicmp
? IPPROTO_ICMP
: IPPROTO_UDP
);
616 Fprintf(stderr
, "%s: raw socket: %s\n", prog
, strerror(errno
));
620 #if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS)
622 u_char optlist
[MAX_IPOPTLEN
];
625 if ((pe
= getprotobyname(cp
)) == NULL
) {
626 Fprintf(stderr
, "%s: unknown protocol %s\n", prog
, cp
);
631 gwlist
[lsrr
] = to
->sin_addr
.s_addr
;
634 /* force 4 byte alignment */
635 optlist
[0] = IPOPT_NOP
;
636 /* loose source route option */
637 optlist
[1] = IPOPT_LSRR
;
638 i
= lsrr
* sizeof(gwlist
[0]);
640 /* Pointer to LSRR addresses */
641 optlist
[3] = IPOPT_MINOFF
;
642 memcpy(optlist
+ 4, gwlist
, i
);
644 if ((setsockopt(sndsock
, pe
->p_proto
, IP_OPTIONS
,
645 (char *)optlist
, i
+ sizeof(gwlist
[0]))) < 0) {
646 Fprintf(stderr
, "%s: IP_OPTIONS: %s\n",
647 prog
, strerror(errno
));
654 if (setsockopt(sndsock
, SOL_SOCKET
, SO_SNDBUF
, (char *)&packlen
,
655 sizeof(packlen
)) < 0) {
656 Fprintf(stderr
, "%s: SO_SNDBUF: %s\n", prog
, strerror(errno
));
661 if (setsockopt(sndsock
, IPPROTO_IP
, IP_HDRINCL
, (char *)&on
,
663 Fprintf(stderr
, "%s: IP_HDRINCL: %s\n", prog
, strerror(errno
));
668 if (settos
&& setsockopt(sndsock
, IPPROTO_IP
, IP_TOS
,
669 (char *)&tos
, sizeof(tos
)) < 0) {
670 Fprintf(stderr
, "%s: setsockopt tos %d: %s\n",
671 prog
, tos
, strerror(errno
));
676 if (options
& SO_DEBUG
)
677 (void)setsockopt(sndsock
, SOL_SOCKET
, SO_DEBUG
, (char *)&on
,
679 if (options
& SO_DONTROUTE
)
680 (void)setsockopt(sndsock
, SOL_SOCKET
, SO_DONTROUTE
, (char *)&on
,
683 /* Get the interface address list */
684 n
= ifaddrlist(&al
, errbuf
);
686 Fprintf(stderr
, "%s: ifaddrlist: %s\n", prog
, errbuf
);
691 "%s: Can't find any network interfaces\n", prog
);
695 /* Look for a specific device */
696 if (device
!= NULL
) {
697 for (i
= n
; i
> 0; --i
, ++al
)
698 if (strcmp(device
, al
->device
) == 0)
701 Fprintf(stderr
, "%s: Can't find interface %.32s\n",
707 /* Determine our source address */
708 if (source
== NULL
) {
710 * If a device was specified, use the interface address.
711 * Otherwise, try to determine our source address.
714 setsin(from
, al
->addr
);
715 else if ((err
= findsaddr(to
, from
)) != NULL
) {
716 Fprintf(stderr
, "%s: findsaddr: %s\n",
721 hi
= gethostinfo(source
);
725 * If the device was specified make sure it
726 * corresponds to the source address specified.
727 * Otherwise, use the first address (and warn if
728 * there are more than one).
730 if (device
!= NULL
) {
731 for (i
= hi
->n
, ap
= hi
->addrs
; i
> 0; --i
, ++ap
)
736 "%s: %s is not on interface %.32s\n",
737 prog
, source
, device
);
742 setsin(from
, hi
->addrs
[0]);
745 "%s: Warning: %s has multiple addresses; using %s\n",
746 prog
, source
, inet_ntoa(from
->sin_addr
));
751 /* Revert to non-privileged user after opening sockets */
755 outip
->ip_src
= from
->sin_addr
;
757 if (bind(sndsock
, (struct sockaddr
*)from
, sizeof(*from
)) < 0) {
758 Fprintf(stderr
, "%s: bind: %s\n",
759 prog
, strerror(errno
));
764 Fprintf(stderr
, "%s to %s (%s)",
765 prog
, hostname
, inet_ntoa(to
->sin_addr
));
767 Fprintf(stderr
, " from %s", source
);
768 Fprintf(stderr
, ", %d hops max, %d byte packets\n", max_ttl
, packlen
);
769 (void)fflush(stderr
);
771 for (ttl
= first_ttl
; ttl
<= max_ttl
; ++ttl
) {
772 u_int32_t lastaddr
= 0;
779 for (probe
= 0; probe
< nprobes
; ++probe
) {
781 struct timeval t1
, t2
;
783 register struct ip
*ip
;
785 if (sentfirst
&& pausemsecs
> 0)
786 usleep(pausemsecs
* 1000);
787 (void)gettimeofday(&t1
, &tz
);
788 send_probe(++seq
, ttl
, &t1
);
790 while ((cc
= wait_for_reply(s
, from
, &t1
)) != 0) {
791 (void)gettimeofday(&t2
, &tz
);
792 i
= packet_ok(packet
, cc
, from
, seq
);
793 /* Skip short packet */
797 from
->sin_addr
.s_addr
!= lastaddr
) {
798 print(packet
, cc
, from
);
799 lastaddr
= from
->sin_addr
.s_addr
;
802 Printf(" %.3f ms", deltaT(&t1
, &t2
));
805 ip
= (struct ip
*)packet
;
812 /* time exceeded in transit */
818 case ICMP_UNREACH_PORT
:
820 ip
= (struct ip
*)packet
;
827 case ICMP_UNREACH_NET
:
832 case ICMP_UNREACH_HOST
:
837 case ICMP_UNREACH_PROTOCOL
:
842 case ICMP_UNREACH_NEEDFRAG
:
844 Printf(" !F-%d", pmtu
);
847 case ICMP_UNREACH_SRCFAIL
:
852 case ICMP_UNREACH_FILTER_PROHIB
:
857 case ICMP_UNREACH_HOST_PRECEDENCE
:
862 case ICMP_UNREACH_PRECEDENCE_CUTOFF
:
869 Printf(" !<%d>", code
);
876 (void)fflush(stdout
);
880 (unreachable
> 0 && unreachable
>= nprobes
- 1))
887 wait_for_reply(register int sock
, register struct sockaddr_in
*fromp
,
888 register const struct timeval
*tp
)
891 struct timeval now
, wait
;
894 int fromlen
= sizeof(*fromp
);
899 wait
.tv_sec
= tp
->tv_sec
+ waittime
;
900 wait
.tv_usec
= tp
->tv_usec
;
901 (void)gettimeofday(&now
, &tz
);
904 if (select(sock
+ 1, &fds
, NULL
, NULL
, &wait
) > 0)
905 cc
= recvfrom(sock
, (char *)packet
, sizeof(packet
), 0,
906 (struct sockaddr
*)fromp
, &fromlen
);
912 send_probe(register int seq
, int ttl
, register struct timeval
*tp
)
919 outip
->ip_id
= htons(ident
+ seq
);
923 * In most cases, the kernel will recalculate the ip checksum.
924 * But we must do it anyway so that the udp checksum comes out
929 in_cksum((u_short
*)outip
, sizeof(*outip
) + optlen
);
930 if (outip
->ip_sum
== 0)
931 outip
->ip_sum
= 0xffff;
940 outicmp
->icmp_seq
= htons(seq
);
942 outudp
->uh_dport
= htons(port
+ seq
);
945 /* Always calculate checksum for icmp packets */
946 outicmp
->icmp_cksum
= 0;
947 outicmp
->icmp_cksum
= in_cksum((u_short
*)outicmp
,
948 packlen
- (sizeof(*outip
) + optlen
));
949 if (outicmp
->icmp_cksum
== 0)
950 outicmp
->icmp_cksum
= 0xffff;
951 } else if (doipcksum
) {
952 memset(&tip
, 0, sizeof(tip
));
953 tip
.ip_src
= outip
->ip_src
;
954 tip
.ip_dst
= outip
->ip_dst
;
955 tip
.ip_p
= outip
->ip_p
;
956 tip
.ip_len
= outudp
->uh_ulen
;
958 outudp
->uh_sum
= ~in_cksum((u_short
*)&tip
, sizeof(tip
));
959 outudp
->uh_sum
= in_cksum((u_short
*)outudp
,
960 packlen
- (sizeof(*outip
) + optlen
));
961 if (outudp
->uh_sum
== 0)
962 outudp
->uh_sum
= 0xffff;
965 /* XXX undocumented debugging hack */
967 register const u_short
*sp
;
968 register int nshorts
, i
;
970 sp
= (u_short
*)outip
;
971 nshorts
= (u_int
)packlen
/ sizeof(u_short
);
973 Printf("[ %d bytes", packlen
);
974 while (--nshorts
>= 0) {
977 Printf(" %04x", ntohs(*sp
++));
982 Printf(" %02x", *(u_char
*)sp
);
987 #if !defined(IP_HDRINCL) && defined(IP_TTL)
988 if (setsockopt(sndsock
, IPPROTO_IP
, IP_TTL
,
989 (char *)&ttl
, sizeof(ttl
)) < 0) {
990 Fprintf(stderr
, "%s: setsockopt ttl %d: %s\n",
991 prog
, ttl
, strerror(errno
));
997 cc
= sendto(sndsock
, useicmp
? (char *)outicmp
: (char *)outudp
,
998 packlen
- (sizeof(*outip
) + optlen
), 0, &whereto
, sizeof(whereto
));
1000 cc
+= sizeof(*outip
) + optlen
;
1002 cc
= sendto(sndsock
, (char *)outip
,
1003 packlen
, 0, &whereto
, sizeof(whereto
));
1005 if (cc
< 0 || cc
!= packlen
) {
1007 Fprintf(stderr
, "%s: sendto: %s\n",
1008 prog
, strerror(errno
));
1009 Printf("%s: wrote %s %d chars, ret=%d\n",
1010 prog
, hostname
, packlen
, cc
);
1011 (void)fflush(stdout
);
1016 deltaT(struct timeval
*t1p
, struct timeval
*t2p
)
1020 dt
= (double)(t2p
->tv_sec
- t1p
->tv_sec
) * 1000.0 +
1021 (double)(t2p
->tv_usec
- t1p
->tv_usec
) / 1000.0;
1026 * Convert an ICMP "type" field to a printable string.
1029 pr_type(register u_char t
)
1031 static char *ttab
[] = {
1032 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
1033 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
1034 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
1035 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
1040 return("OUT-OF-RANGE");
1046 packet_ok(register u_char
*buf
, int cc
, register struct sockaddr_in
*from
,
1049 register struct icmp
*icp
;
1050 register u_char type
, code
;
1053 register struct ip
*ip
;
1055 ip
= (struct ip
*) buf
;
1056 hlen
= ip
->ip_hl
<< 2;
1057 if (cc
< hlen
+ ICMP_MINLEN
) {
1059 Printf("packet too short (%d bytes) from %s\n", cc
,
1060 inet_ntoa(from
->sin_addr
));
1064 icp
= (struct icmp
*)(buf
+ hlen
);
1066 icp
= (struct icmp
*)buf
;
1068 type
= icp
->icmp_type
;
1069 code
= icp
->icmp_code
;
1070 /* Path MTU Discovery (RFC1191) */
1071 if (code
!= ICMP_UNREACH_NEEDFRAG
)
1074 #ifdef HAVE_ICMP_NEXTMTU
1075 pmtu
= ntohs(icp
->icmp_nextmtu
);
1077 pmtu
= ntohs(((struct my_pmtu
*)&icp
->icmp_void
)->ipm_nextmtu
);
1080 if ((type
== ICMP_TIMXCEED
&& code
== ICMP_TIMXCEED_INTRANS
) ||
1081 type
== ICMP_UNREACH
|| type
== ICMP_ECHOREPLY
) {
1082 register struct ip
*hip
;
1083 register struct udphdr
*up
;
1084 register struct icmp
*hicmp
;
1086 hip
= &icp
->icmp_ip
;
1087 hlen
= hip
->ip_hl
<< 2;
1090 if (type
== ICMP_ECHOREPLY
&&
1091 icp
->icmp_id
== htons(ident
) &&
1092 icp
->icmp_seq
== htons(seq
))
1095 hicmp
= (struct icmp
*)((u_char
*)hip
+ hlen
);
1096 /* XXX 8 is a magic number */
1097 if (hlen
+ 8 <= cc
&&
1098 hip
->ip_p
== IPPROTO_ICMP
&&
1099 hicmp
->icmp_id
== htons(ident
) &&
1100 hicmp
->icmp_seq
== htons(seq
))
1101 return (type
== ICMP_TIMXCEED
? -1 : code
+ 1);
1103 up
= (struct udphdr
*)((u_char
*)hip
+ hlen
);
1104 /* XXX 8 is a magic number */
1105 if (hlen
+ 12 <= cc
&&
1106 hip
->ip_p
== IPPROTO_UDP
&&
1107 up
->uh_sport
== htons(ident
) &&
1108 up
->uh_dport
== htons(port
+ seq
))
1109 return (type
== ICMP_TIMXCEED
? -1 : code
+ 1);
1115 u_int32_t
*lp
= (u_int32_t
*)&icp
->icmp_ip
;
1117 Printf("\n%d bytes from %s to ", cc
, inet_ntoa(from
->sin_addr
));
1118 Printf("%s: icmp type %d (%s) code %d\n",
1119 inet_ntoa(ip
->ip_dst
), type
, pr_type(type
), icp
->icmp_code
);
1120 for (i
= 4; i
< cc
; i
+= sizeof(*lp
))
1121 Printf("%2d: x%8.8x\n", i
, *lp
++);
1129 print(register u_char
*buf
, register int cc
, register struct sockaddr_in
*from
)
1131 register struct ip
*ip
;
1134 ip
= (struct ip
*) buf
;
1135 hlen
= ip
->ip_hl
<< 2;
1139 Printf(" %s", inet_ntoa(from
->sin_addr
));
1141 Printf(" %s (%s)", inetname(from
->sin_addr
),
1142 inet_ntoa(from
->sin_addr
));
1145 Printf(" %d bytes to %s", cc
, inet_ntoa (ip
->ip_dst
));
1149 * Checksum routine for Internet Protocol family headers (C Version)
1152 in_cksum(register u_short
*addr
, register int len
)
1154 register int nleft
= len
;
1155 register u_short
*w
= addr
;
1156 register u_short answer
;
1157 register int sum
= 0;
1160 * Our algorithm is simple, using a 32 bit accumulator (sum),
1161 * we add sequential 16 bit words to it, and at the end, fold
1162 * back all the carry bits from the top 16 bits into the lower
1170 /* mop up an odd byte, if necessary */
1172 sum
+= *(u_char
*)w
;
1175 * add back carry outs from top 16 bits to low 16 bits
1177 sum
= (sum
>> 16) + (sum
& 0xffff); /* add hi 16 to low 16 */
1178 sum
+= (sum
>> 16); /* add carry */
1179 answer
= ~sum
; /* truncate to 16 bits */
1184 * Subtract 2 timeval structs: out = out - in.
1185 * Out is assumed to be >= in.
1188 tvsub(register struct timeval
*out
, register struct timeval
*in
)
1191 if ((out
->tv_usec
-= in
->tv_usec
) < 0) {
1193 out
->tv_usec
+= 1000000;
1195 out
->tv_sec
-= in
->tv_sec
;
1199 * Construct an Internet address representation.
1200 * If the nflag has been supplied, give
1201 * numeric value, otherwise try for symbolic name.
1204 inetname(struct in_addr in
)
1207 register struct hostent
*hp
;
1208 static int first
= 1;
1209 static char domain
[MAXHOSTNAMELEN
+ 1], line
[MAXHOSTNAMELEN
+ 1];
1211 if (first
&& !nflag
) {
1213 if (gethostname(domain
, sizeof(domain
) - 1) < 0)
1216 cp
= strchr(domain
, '.');
1218 hp
= gethostbyname(domain
);
1220 cp
= strchr(hp
->h_name
, '.');
1226 (void)strncpy(domain
, cp
, sizeof(domain
) - 1);
1227 domain
[sizeof(domain
) - 1] = '\0';
1231 if (!nflag
&& in
.s_addr
!= INADDR_ANY
) {
1232 hp
= gethostbyaddr((char *)&in
, sizeof(in
), AF_INET
);
1234 if ((cp
= strchr(hp
->h_name
, '.')) != NULL
&&
1235 strcmp(cp
+ 1, domain
) == 0)
1237 (void)strncpy(line
, hp
->h_name
, sizeof(line
) - 1);
1238 line
[sizeof(line
) - 1] = '\0';
1242 return (inet_ntoa(in
));
1246 gethostinfo(register char *hostname
)
1249 register struct hostent
*hp
;
1250 register struct hostinfo
*hi
;
1252 register u_int32_t addr
, *ap
;
1254 if (strlen(hostname
) > 64) {
1255 Fprintf(stderr
, "%s: hostname \"%.32s...\" is too long\n",
1259 hi
= calloc(1, sizeof(*hi
));
1261 Fprintf(stderr
, "%s: calloc %s\n", prog
, strerror(errno
));
1264 addr
= inet_addr(hostname
);
1265 if ((int32_t)addr
!= -1) {
1266 hi
->name
= strdup(hostname
);
1268 hi
->addrs
= calloc(1, sizeof(hi
->addrs
[0]));
1269 if (hi
->addrs
== NULL
) {
1270 Fprintf(stderr
, "%s: calloc %s\n",
1271 prog
, strerror(errno
));
1274 hi
->addrs
[0] = addr
;
1278 hp
= gethostbyname(hostname
);
1280 Fprintf(stderr
, "%s: unknown host %s\n", prog
, hostname
);
1283 if (hp
->h_addrtype
!= AF_INET
|| hp
->h_length
!= 4) {
1284 Fprintf(stderr
, "%s: bad host %s\n", prog
, hostname
);
1287 hi
->name
= strdup(hp
->h_name
);
1288 for (n
= 0, p
= hp
->h_addr_list
; *p
!= NULL
; ++n
, ++p
)
1291 hi
->addrs
= calloc(n
, sizeof(hi
->addrs
[0]));
1292 if (hi
->addrs
== NULL
) {
1293 Fprintf(stderr
, "%s: calloc %s\n", prog
, strerror(errno
));
1296 for (ap
= hi
->addrs
, p
= hp
->h_addr_list
; *p
!= NULL
; ++ap
, ++p
)
1297 memcpy(ap
, *p
, sizeof(*ap
));
1302 freehostinfo(register struct hostinfo
*hi
)
1304 if (hi
->name
!= NULL
) {
1308 free((char *)hi
->addrs
);
1313 getaddr(register u_int32_t
*ap
, register char *hostname
)
1315 register struct hostinfo
*hi
;
1317 hi
= gethostinfo(hostname
);
1323 setsin(register struct sockaddr_in
*sin
, register u_int32_t addr
)
1326 memset(sin
, 0, sizeof(*sin
));
1327 #ifdef HAVE_SOCKADDR_SA_LEN
1328 sin
->sin_len
= sizeof(*sin
);
1330 sin
->sin_family
= AF_INET
;
1331 sin
->sin_addr
.s_addr
= addr
;
1334 /* String to value with optional min and max. Handles decimal and hex. */
1336 str2val(register const char *str
, register const char *what
,
1337 register int mi
, register int ma
)
1339 register const char *cp
;
1343 if (str
[0] == '0' && (str
[1] == 'x' || str
[1] == 'X')) {
1345 val
= (int)strtol(cp
, &ep
, 16);
1347 val
= (int)strtol(str
, &ep
, 10);
1349 Fprintf(stderr
, "%s: \"%s\" bad value for %s \n",
1353 if (val
< mi
&& mi
>= 0) {
1355 Fprintf(stderr
, "%s: %s must be >= %d\n",
1358 Fprintf(stderr
, "%s: %s must be > %d\n",
1359 prog
, what
, mi
- 1);
1362 if (val
> ma
&& ma
>= 0) {
1363 Fprintf(stderr
, "%s: %s must be <= %d\n", prog
, what
, ma
);
1372 extern char version
[];
1374 Fprintf(stderr
, "Version %s\n", version
);
1376 "Usage: %s [-dFInrvx] [-g gateway] [-i iface] [-f first_ttl]\n"
1377 "\t[-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos]\n"
1378 "\t[-w waittime] [-z pausemsecs] host [packetlen]\n", prog
);