1 /* $NetBSD: traceroute.c,v 1.73 2008/07/17 19:23:17 christos Exp $ */
4 * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that: (1) source code distributions
9 * retain the above copyright notice and this paragraph in its entirety, (2)
10 * distributions including binary code include the above copyright notice and
11 * this paragraph in its entirety in the documentation or other materials
12 * provided with the distribution, and (3) all advertising materials mentioning
13 * features or use of this software display the following acknowledgement:
14 * ``This product includes software developed by the University of California,
15 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16 * the University nor the names of its contributors may be used to endorse
17 * or promote products derived from this software without specific prior
19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24 #include <sys/cdefs.h>
27 static const char rcsid
[] =
28 "@(#)Header: traceroute.c,v 1.49 97/06/13 02:30:23 leres Exp (LBL)";
30 __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997\
31 The Regents of the University of California. All rights reserved.");
32 __RCSID("$NetBSD: traceroute.c,v 1.73 2008/07/17 19:23:17 christos Exp $");
37 * traceroute host - trace the route ip packets follow going to "host".
39 * Attempt to trace the route an ip packet would follow to some
40 * internet host. We find out intermediate hops by launching probe
41 * packets with a small ttl (time to live) then listening for an
42 * icmp "time exceeded" reply from a gateway. We start our probes
43 * with a ttl of one and increase by one until we get an icmp "port
44 * unreachable" (which means we got to "host") or hit a max (which
45 * defaults to 30 hops & can be changed with the -m flag). Three
46 * probes (change with -q flag) are sent at each ttl setting and a
47 * line is printed showing the ttl, address of the gateway and
48 * round trip time of each probe. If the probe answers come from
49 * different gateways, the address of each responding system will
50 * be printed. If there is no response within a 5 sec. timeout
51 * interval (changed with the -w flag), a "*" is printed for that
54 * Probe packets are UDP format. We don't want the destination
55 * host to process them so the destination port is set to an
56 * unlikely value (if some clod on the destination is using that
57 * value, it can be changed with the -p flag).
59 * A sample use might be:
61 * [yak 71]% traceroute nis.nsf.net.
62 * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
63 * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms
64 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
65 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
66 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms
67 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms
68 * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms
69 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms
70 * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms
71 * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms
72 * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms
73 * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms
75 * Note that lines 2 & 3 are the same. This is due to a buggy
76 * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
77 * packets with a zero ttl.
79 * A more interesting example is:
81 * [yak 72]% traceroute allspice.lcs.mit.edu.
82 * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
83 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
84 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms
85 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms
86 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms
87 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms
88 * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms
89 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms
90 * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms
91 * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms
92 * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms
93 * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms
95 * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms
100 * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms
102 * (I start to see why I'm having so much trouble with mail to
103 * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away
104 * either don't send ICMP "time exceeded" messages or send them
105 * with a ttl too small to reach us. 14 - 17 are running the
106 * MIT C Gateway code that doesn't send "time exceeded"s. God
107 * only knows what's going on with 12.
109 * The silent gateway 12 in the above may be the result of a bug in
110 * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3)
111 * sends an unreachable message using whatever ttl remains in the
112 * original datagram. Since, for gateways, the remaining ttl is
113 * zero, the icmp "time exceeded" is guaranteed to not make it back
114 * to us. The behavior of this bug is slightly more interesting
115 * when it appears on the destination system:
117 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
118 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms
119 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms
120 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms
121 * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms
122 * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms
129 * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms !
131 * Notice that there are 12 "gateways" (13 is the final
132 * destination) and exactly the last half of them are "missing".
133 * What's really happening is that rip (a Sun-3 running Sun OS3.5)
134 * is using the ttl from our arriving datagram as the ttl in its
135 * icmp reply. So, the reply will time out on the return path
136 * (with no notice sent to anyone since icmp's aren't sent for
137 * icmp's) until we probe with a ttl that's at least twice the path
138 * length. I.e., rip is really only 7 hops away. A reply that
139 * returns with a ttl of 1 is a clue this problem exists.
140 * Traceroute prints a "!" after the time if the ttl is <= 1.
141 * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
142 * non-standard (HPUX) software, expect to see this problem
143 * frequently and/or take care picking the target host of your
146 * Other possible annotations after the time are !H, !N, !P (got a host,
147 * network or protocol unreachable, respectively), !S or !F (source
148 * route failed or fragmentation needed -- neither of these should
149 * ever occur and the associated gateway is busted if you see one). If
150 * almost all the probes result in some kind of unreachable, traceroute
151 * will give up and exit.
155 * This program must be run by root or be setuid. (I suggest that
156 * you *don't* make it setuid -- casual use could result in a lot
157 * of unnecessary traffic on our poor, congested nets.)
159 * This program requires a kernel mod that does not appear in any
160 * system available from Berkeley: A raw ip socket using proto
161 * IPPROTO_RAW must interpret the data sent as an ip datagram (as
162 * opposed to data to be wrapped in a ip datagram). See the README
163 * file that came with the source to this program for a description
164 * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may
165 * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
166 * MODIFIED TO RUN THIS PROGRAM.
168 * The udp port usage may appear bizarre (well, ok, it is bizarre).
169 * The problem is that an icmp message only contains 8 bytes of
170 * data from the original datagram. 8 bytes is the size of a udp
171 * header so, if we want to associate replies with the original
172 * datagram, the necessary information must be encoded into the
173 * udp header (the ip id could be used but there's no way to
174 * interlock with the kernel's assignment of ip id's and, anyway,
175 * it would have taken a lot more kernel hacking to allow this
176 * code to set the ip id). So, to allow two or more users to
177 * use traceroute simultaneously, we use this task's pid as the
178 * source port (the high bit is set to move the port number out
179 * of the "likely" range). To keep track of which probe is being
180 * replied to (so times and/or hop counts don't get confused by a
181 * reply that was delayed in transit), we increment the destination
182 * port number before each probe.
184 * Don't use this as a coding example. I was trying to find a
185 * routing problem and this code sort-of popped out after 48 hours
186 * without sleep. I was amazed it ever compiled, much less ran.
188 * I stole the idea for this program from Steve Deering. Since
189 * the first release, I've learned that had I attended the right
190 * IETF working group meetings, I also could have stolen it from Guy
191 * Almes or Matt Mathis. I don't know (or care) who came up with
192 * the idea first. I envy the originators' perspicacity and I'm
193 * glad they didn't keep the idea a secret.
195 * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
196 * enhancements to the original distribution.
198 * I've hacked up a round-trip-route version of this that works by
199 * sending a loose-source-routed udp datagram through the destination
200 * back to yourself. Unfortunately, SO many gateways botch source
201 * routing, the thing is almost worthless. Maybe one day...
203 * -- Van Jacobson (van@ee.lbl.gov)
204 * Tue Dec 20 03:50:13 PST 1988
207 #include <sys/param.h>
208 #include <sys/file.h>
209 #include <sys/ioctl.h>
210 #include <sys/socket.h>
211 #include <sys/time.h>
212 #include <sys/sysctl.h>
214 #include <netinet/in_systm.h>
215 #include <netinet/in.h>
216 #include <netinet/ip.h>
217 #include <netinet/ip_var.h>
218 #include <netinet/ip_icmp.h>
219 #include <netinet/udp.h>
220 #include <netinet/udp_var.h>
222 #include <arpa/inet.h>
237 #include <net/route.h>
238 #include <netinet6/ipsec.h>
242 #ifdef HAVE_OS_PROTO_H
243 #include "os-proto.h"
246 #include "ifaddrlist.h"
249 /* Maximum number of gateways (include room for one noop) */
250 #define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))
252 #ifndef MAXHOSTNAMELEN
253 #define MAXHOSTNAMELEN 64
256 #define Fprintf (void)fprintf
257 #define Printf (void)printf
259 /* Host name and address list */
266 /* Data section of the probe packet */
268 u_char seq
; /* sequence number of this packet */
269 u_char ttl
; /* ttl packet left with */
273 } tv
; /* time packet left */
277 * Support for ICMP extensions
279 * http://www.ietf.org/proceedings/01aug/I-D/draft-ietf-mpls-icmp-02.txt
281 #define ICMP_EXT_OFFSET 8 /* ICMP type, code, checksum, unused */ + \
282 128 /* original datagram */
283 #define ICMP_EXT_VERSION 2
285 * ICMP extensions, common header
287 struct icmp_ext_cmn_hdr
{
288 #if BYTE_ORDER == BIG_ENDIAN
289 unsigned char version
:4;
290 unsigned char reserved1
:4;
292 unsigned char reserved1
:4;
293 unsigned char version
:4;
295 unsigned char reserved2
;
296 unsigned short checksum
;
300 * ICMP extensions, object header
302 struct icmp_ext_obj_hdr
{
305 #define MPLS_STACK_ENTRY_CLASS 1
307 #define MPLS_STACK_ENTRY_C_TYPE 1
311 #if BYTE_ORDER == BIG_ENDIAN
324 u_char packet
[512]; /* last inbound (icmp) packet */
326 struct ip
*outip
; /* last output (udp) packet */
327 struct udphdr
*outudp
; /* last output (udp) packet */
328 void *outmark
; /* packed location of struct outdata */
329 struct outdata outsetup
; /* setup and copy for alignment */
331 struct icmp
*outicmp
; /* last output (icmp) packet */
333 /* loose source route gateway list (including room for final destination) */
334 u_int32_t gwlist
[NGATEWAYS
+ 1];
336 int s
; /* receive (icmp) socket file descriptor */
337 int sndsock
; /* send (udp/icmp) socket file descriptor */
339 struct sockaddr whereto
; /* Who to try to reach */
340 struct sockaddr_in wherefrom
; /* Who we are */
341 int packlen
; /* total length of packet */
342 int minpacket
; /* min ip packet size */
343 int maxpacket
= 32 * 1024; /* max ip packet size */
355 in_port_t port
= 32768 + 666; /* start udp dest port # for probe packets */
357 int options
; /* socket options */
359 int waittime
= 5; /* time to wait for response (in seconds) */
360 int nflag
; /* print addresses numerically */
362 int Mflag
; /* show MPLS labels if any */
363 int as_path
; /* print as numbers for each hop */
364 char *as_server
= NULL
;
366 int useicmp
= 0; /* use icmp echo instead of udp packets */
367 #ifdef CANT_HACK_CKSUM
368 int docksum
= 0; /* don't calculate checksums */
370 int docksum
= 1; /* calculate checksums */
372 int optlen
; /* length of ip options */
396 int *mtuptr
= &mtus
[0];
398 int nextmtu
; /* from ICMP error, set by packet_ok(), might be 0 */
405 double deltaT(struct timeval
*, struct timeval
*);
406 void freehostinfo(struct hostinfo
*);
407 void getaddr(u_int32_t
*, char *);
408 struct hostinfo
*gethostinfo(char *);
409 u_int16_t
in_cksum(u_int16_t
*, int);
410 u_int16_t
in_cksum2(u_int16_t
, u_int16_t
*, int);
411 char *inetname(struct in_addr
);
412 int main(int, char **);
413 int packet_ok(u_char
*, int, struct sockaddr_in
*, int);
414 char *pr_type(u_char
);
415 void print(u_char
*, int, struct sockaddr_in
*);
416 void resize_packet(void);
417 void dump_packet(void);
418 void send_probe(int, int, struct timeval
*);
419 void setsin(struct sockaddr_in
*, u_int32_t
);
420 int str2val(const char *, const char *, int, int);
421 void tvsub(struct timeval
*, struct timeval
*);
422 __dead
void usage(void);
423 int wait_for_reply(int, struct sockaddr_in
*, struct timeval
*);
424 void decode_extensions(unsigned char *buf
, int ip_len
);
426 int find_local_ip(struct sockaddr_in
*, struct sockaddr_in
*);
428 #ifdef IPSEC_POLICY_IPSEC
429 int setpolicy(int so
, char *policy
);
434 main(int argc
, char **argv
)
439 struct sockaddr_in
*from
= &wherefrom
;
440 struct sockaddr_in
*to
= (struct sockaddr_in
*)&whereto
;
445 int tos
= 0, settos
= 0, ttl_flag
= 0;
448 struct ifaddrlist
*al
, *al2
;
450 int mib
[4] = { CTL_NET
, PF_INET
, IPPROTO_IP
, IPCTL_DEFTTL
};
451 size_t size
= sizeof(max_ttl
);
453 setprogname(argv
[0]);
454 prog
= getprogname();
456 if ((s
= socket(AF_INET
, SOCK_RAW
, IPPROTO_ICMP
)) < 0) {
457 Fprintf(stderr
, "%s: icmp socket: %s\n", prog
, strerror(errno
));
462 * XXX 'useicmp' will always be zero here. I think the HP-UX users
463 * running our traceroute code will forgive us.
466 sndsock
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
);
468 sndsock
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
469 useicmp
? IPPROTO_ICMP
: IPPROTO_UDP
);
472 Fprintf(stderr
, "%s: raw socket: %s\n", prog
, strerror(errno
));
476 /* Revert to non-privileged user after opening sockets */
479 (void) sysctl(mib
, sizeof(mib
)/sizeof(mib
[0]), &max_ttl
, &size
,
483 while ((op
= getopt(argc
, argv
, "aA:dDFPIMnlrvxf:g:i:m:p:q:s:t:w:")) != -1)
504 first_ttl
= str2val(optarg
, "first ttl", 1, 255);
512 if (lsrr
>= NGATEWAYS
) {
514 "%s: No more than %d gateways\n",
518 getaddr(gwlist
+ lsrr
, optarg
);
535 max_ttl
= str2val(optarg
, "max ttl", 1, 255);
547 port
= str2val(optarg
, "port", 1, -1);
551 nprobes
= str2val(optarg
, "nprobes", 1, -1);
555 options
|= SO_DONTROUTE
;
560 * set the ip source address of the outbound
561 * probe (e.g., on a multi-homed host).
567 tos
= str2val(optarg
, "tos", 0, 255);
576 docksum
= (docksum
== 0);
580 waittime
= str2val(optarg
, "wait time", 2, 24 * 3600);
592 if (first_ttl
> max_ttl
) {
594 "%s: first ttl (%d) may not be greater than max ttl (%d)\n",
595 prog
, first_ttl
, max_ttl
);
600 Fprintf(stderr
, "%s: Warning: ckecksums disabled\n", prog
);
603 optlen
= (lsrr
+ 1) * sizeof(gwlist
[0]);
604 minpacket
= sizeof(*outip
) + sizeof(struct outdata
) + optlen
;
606 minpacket
+= 8; /* XXX magic number */
608 minpacket
+= sizeof(*outudp
);
610 packlen
= minpacket
; /* minimum sized packet */
611 else if (minpacket
> packlen
|| packlen
> maxpacket
) {
612 Fprintf(stderr
, "%s: packet size must be %d <= s <= %d\n",
613 prog
, minpacket
, maxpacket
);
620 /* Process destination and optional packet size */
621 switch (argc
- optind
) {
624 packlen
= str2val(argv
[optind
+ 1],
625 "packet length", minpacket
, -1);
629 hostname
= argv
[optind
];
630 hi
= gethostinfo(hostname
);
631 setsin(to
, hi
->addrs
[0]);
634 "%s: Warning: %s has multiple addresses; using %s\n",
635 prog
, hostname
, inet_ntoa(to
->sin_addr
));
645 #ifdef HAVE_SETLINEBUF
648 setvbuf(stdout
, NULL
, _IOLBF
, 0);
651 outip
= (struct ip
*)malloc((unsigned)packlen
);
653 Fprintf(stderr
, "%s: malloc: %s\n", prog
, strerror(errno
));
656 memset((char *)outip
, 0, packlen
);
658 outip
->ip_v
= IPVERSION
;
661 #ifdef BYTESWAP_IP_LEN
662 outip
->ip_len
= htons(packlen
);
664 outip
->ip_len
= packlen
;
667 outp
= (u_char
*)(outip
+ 1);
668 #ifdef HAVE_RAW_OPTIONS
676 gwlist
[lsrr
] = to
->sin_addr
.s_addr
;
678 outip
->ip_dst
.s_addr
= gwlist
[0];
680 /* force 4 byte alignment */
681 optlist
[0] = IPOPT_NOP
;
682 /* loose source route option */
683 optlist
[1] = IPOPT_LSRR
;
684 i
= lsrr
* sizeof(gwlist
[0]);
686 /* Pointer to LSRR addresses */
687 optlist
[3] = IPOPT_MINOFF
;
688 memcpy(optlist
+ 4, gwlist
+ 1, i
);
691 outip
->ip_dst
= to
->sin_addr
;
693 outip
->ip_hl
= (outp
- (u_char
*)outip
) >> 2;
694 ident
= htons(arc4random() & 0xffff) | 0x8000;
696 outip
->ip_p
= IPPROTO_ICMP
;
698 outicmp
= (struct icmp
*)outp
;
699 outicmp
->icmp_type
= ICMP_ECHO
;
700 outicmp
->icmp_id
= htons(ident
);
702 outmark
= outp
+ 8; /* XXX magic number */
704 outip
->ip_p
= IPPROTO_UDP
;
706 outudp
= (struct udphdr
*)outp
;
707 outudp
->uh_sport
= htons(ident
);
709 htons((u_int16_t
)(packlen
- (sizeof(*outip
) + optlen
)));
710 outmark
= outudp
+ 1;
713 if (options
& SO_DEBUG
)
714 (void)setsockopt(s
, SOL_SOCKET
, SO_DEBUG
, (char *)&on
,
717 #ifdef IPSEC_POLICY_IPSEC
719 * do not raise error even if setsockopt fails, kernel may have ipsec
722 if (setpolicy(s
, "in bypass") < 0)
724 if (setpolicy(s
, "out bypass") < 0)
728 int level
= IPSEC_LEVEL_AVAIL
;
730 (void)setsockopt(s
, IPPROTO_IP
, IP_ESP_TRANS_LEVEL
, &level
,
732 (void)setsockopt(s
, IPPROTO_IP
, IP_ESP_NETWORK_LEVEL
, &level
,
734 #ifdef IP_AUTH_TRANS_LEVEL
735 (void)setsockopt(s
, IPPROTO_IP
, IP_AUTH_TRANS_LEVEL
, &level
,
738 (void)setsockopt(s
, IPPROTO_IP
, IP_AUTH_LEVEL
, &level
,
741 #ifdef IP_AUTH_NETWORK_LEVEL
742 (void)setsockopt(s
, IPPROTO_IP
, IP_AUTH_NETWORK_LEVEL
, &level
,
746 #endif /*IPSEC_POLICY_IPSEC*/
750 #ifdef IPSEC_POLICY_IPSEC
752 * do not raise error even if setsockopt fails, kernel may have ipsec
755 if (setpolicy(sndsock
, "in bypass") < 0)
757 if (setpolicy(sndsock
, "out bypass") < 0)
761 int level
= IPSEC_LEVEL_BYPASS
;
763 (void)setsockopt(sndsock
, IPPROTO_IP
, IP_ESP_TRANS_LEVEL
, &level
,
765 (void)setsockopt(sndsock
, IPPROTO_IP
, IP_ESP_NETWORK_LEVEL
, &level
,
767 #ifdef IP_AUTH_TRANS_LEVEL
768 (void)setsockopt(sndsock
, IPPROTO_IP
, IP_AUTH_TRANS_LEVEL
, &level
,
771 (void)setsockopt(sndsock
, IPPROTO_IP
, IP_AUTH_LEVEL
, &level
,
774 #ifdef IP_AUTH_NETWORK_LEVEL
775 (void)setsockopt(sndsock
, IPPROTO_IP
, IP_AUTH_NETWORK_LEVEL
, &level
,
779 #endif /*IPSEC_POLICY_IPSEC*/
782 #if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS)
784 u_char optlist
[MAX_IPOPTLEN
];
787 gwlist
[lsrr
] = to
->sin_addr
.s_addr
;
790 /* force 4 byte alignment */
791 optlist
[0] = IPOPT_NOP
;
792 /* loose source route option */
793 optlist
[1] = IPOPT_LSRR
;
794 i
= lsrr
* sizeof(gwlist
[0]);
796 /* Pointer to LSRR addresses */
797 optlist
[3] = IPOPT_MINOFF
;
798 memcpy(optlist
+ 4, gwlist
, i
);
800 if ((setsockopt(sndsock
, IPPROTO_IP
, IP_OPTIONS
, optlist
,
801 i
+ sizeof(gwlist
[0]))) < 0) {
802 Fprintf(stderr
, "%s: IP_OPTIONS: %s\n",
803 prog
, strerror(errno
));
810 if (setsockopt(sndsock
, SOL_SOCKET
, SO_SNDBUF
, (char *)&packlen
,
811 sizeof(packlen
)) < 0) {
812 Fprintf(stderr
, "%s: SO_SNDBUF: %s\n", prog
, strerror(errno
));
817 if (setsockopt(sndsock
, IPPROTO_IP
, IP_HDRINCL
, (char *)&on
,
819 Fprintf(stderr
, "%s: IP_HDRINCL: %s\n", prog
, strerror(errno
));
824 if (settos
&& setsockopt(sndsock
, IPPROTO_IP
, IP_TOS
,
825 (char *)&tos
, sizeof(tos
)) < 0) {
826 Fprintf(stderr
, "%s: setsockopt tos %d: %s\n",
827 prog
, tos
, strerror(errno
));
832 if (options
& SO_DEBUG
)
833 (void)setsockopt(sndsock
, SOL_SOCKET
, SO_DEBUG
, (char *)&on
,
835 if (options
& SO_DONTROUTE
)
836 (void)setsockopt(sndsock
, SOL_SOCKET
, SO_DONTROUTE
, (char *)&on
,
839 /* Get the interface address list */
840 n
= ifaddrlist(&al
, errbuf
, sizeof errbuf
);
843 Fprintf(stderr
, "%s: ifaddrlist: %s\n", prog
, errbuf
);
848 "%s: Can't find any network interfaces\n", prog
);
852 /* Look for a specific device */
853 if (device
!= NULL
) {
854 for (i
= n
; i
> 0; --i
, ++al2
)
855 if (strcmp(device
, al2
->device
) == 0)
858 Fprintf(stderr
, "%s: Can't find interface %s\n",
864 /* Determine our source address */
865 if (source
== NULL
) {
867 * If a device was specified, use the interface address.
868 * Otherwise, use the first interface found.
869 * Warn if there are more than one.
871 setsin(from
, al2
->addr
);
872 if (n
> 1 && device
== NULL
&& !find_local_ip(from
, to
)) {
874 "%s: Warning: Multiple interfaces found; using %s @ %s\n",
875 prog
, inet_ntoa(from
->sin_addr
), al2
->device
);
878 hi
= gethostinfo(source
);
881 if (device
== NULL
) {
883 * Use the first interface found.
884 * Warn if there are more than one.
886 setsin(from
, hi
->addrs
[0]);
889 "%s: Warning: %s has multiple addresses; using %s\n",
890 prog
, source
, inet_ntoa(from
->sin_addr
));
893 * Make sure the source specified matches the
896 for (i
= hi
->n
, ap
= hi
->addrs
; i
> 0; --i
, ++ap
)
897 if (*ap
== al2
->addr
)
901 "%s: %s is not on interface %s\n",
902 prog
, source
, device
);
911 * If not root, make sure source address matches a local interface.
912 * (The list of addresses produced by ifaddrlist() automatically
913 * excludes interfaces that are marked down and/or loopback.)
917 for (i
= n
; i
> 0; --i
, ++al2
)
918 if (from
->sin_addr
.s_addr
== al2
->addr
)
921 Fprintf(stderr
, "%s: %s is not a valid local address "
922 "and you are not superuser.\n", prog
,
923 inet_ntoa(from
->sin_addr
));
928 outip
->ip_src
= from
->sin_addr
;
930 if (bind(sndsock
, (struct sockaddr
*)from
, sizeof(*from
)) < 0) {
931 Fprintf(stderr
, "%s: bind: %s\n",
932 prog
, strerror(errno
));
938 asn
= as_setup(as_server
);
940 Fprintf(stderr
, "%s: as_setup failed, AS# lookups disabled\n",
942 (void)fflush(stderr
);
948 Fprintf(stderr
, "%s to %s (%s)",
949 prog
, hostname
, inet_ntoa(to
->sin_addr
));
951 Fprintf(stderr
, " from %s", source
);
952 Fprintf(stderr
, ", %d hops max, %d byte packets\n", max_ttl
, packlen
);
953 (void)fflush(stderr
);
955 for (ttl
= first_ttl
; ttl
<= max_ttl
; ++ttl
) {
956 u_int32_t lastaddr
= 0;
962 for (probe
= 0; probe
< nprobes
; ++probe
) {
964 struct timeval t1
, t2
;
966 (void)gettimeofday(&t1
, NULL
);
967 if (!useicmp
&& htons(port
+ seq
+ 1) == 0)
969 send_probe(++seq
, ttl
, &t1
);
970 while ((cc
= wait_for_reply(s
, from
, &t1
)) != 0) {
971 (void)gettimeofday(&t2
, NULL
);
973 * Since we'll be receiving all ICMP
974 * messages to this host above, we may
975 * never end up with cc=0, so we need
976 * an additional termination check.
978 if (t2
.tv_sec
- t1
.tv_sec
> waittime
) {
982 i
= packet_ok(packet
, cc
, from
, seq
);
983 /* Skip short packet */
986 if (from
->sin_addr
.s_addr
!= lastaddr
) {
987 print(packet
, cc
, from
);
988 lastaddr
= from
->sin_addr
.s_addr
;
990 ip
= (struct ip
*)packet
;
991 Printf(" %.3f ms", deltaT(&t1
, &t2
));
993 Printf(" (ttl = %d)", ip
->ip_ttl
);
1003 /* time exceeded in transit */
1009 case ICMP_UNREACH_PORT
:
1011 if (ip
->ip_ttl
<= 1)
1017 case ICMP_UNREACH_NET
:
1022 case ICMP_UNREACH_HOST
:
1027 case ICMP_UNREACH_PROTOCOL
:
1032 case ICMP_UNREACH_NEEDFRAG
:
1042 case ICMP_UNREACH_SRCFAIL
:
1048 #ifndef ICMP_UNREACH_FILTER_PROHIB
1049 #define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohibited filter */
1051 case ICMP_UNREACH_FILTER_PROHIB
:
1058 Printf(" !<%d>", code
);
1065 else if (cc
&& probe
== nprobes
- 1 && Mflag
)
1066 decode_extensions(packet
, cc
);
1067 (void)fflush(stdout
);
1071 (unreachable
> 0 && unreachable
>= ((nprobes
+ 1) / 2)))
1082 wait_for_reply(int sock
, struct sockaddr_in
*fromp
, struct timeval
*tp
)
1084 struct pollfd set
[1];
1085 struct timeval now
, wait
;
1087 socklen_t fromlen
= sizeof(*fromp
);
1091 set
[0].events
= POLLIN
;
1093 wait
.tv_sec
= tp
->tv_sec
+ waittime
;
1094 wait
.tv_usec
= tp
->tv_usec
;
1095 (void)gettimeofday(&now
, NULL
);
1098 if (wait
.tv_sec
< 0) {
1103 retval
= poll(set
, 1, wait
.tv_sec
* 1000 + wait
.tv_usec
/ 1000);
1105 /* If we continue, we probably just flood the remote host. */
1106 Fprintf(stderr
, "%s: poll: %s\n", prog
, strerror(errno
));
1110 cc
= recvfrom(s
, (char *)packet
, sizeof(packet
), 0,
1111 (struct sockaddr
*)fromp
, &fromlen
);
1118 decode_extensions(unsigned char *buf
, int ip_len
)
1120 struct icmp_ext_cmn_hdr
*cmn_hdr
;
1121 struct icmp_ext_obj_hdr
*obj_hdr
;
1123 struct mpls_header mpls
;
1126 int datalen
, obj_len
;
1129 ip
= (struct ip
*)buf
;
1131 if (ip_len
<= sizeof(struct ip
) + ICMP_EXT_OFFSET
) {
1133 * No support for ICMP extensions on this host
1139 * Move forward to the start of the ICMP extensions, if present
1141 buf
+= (ip
->ip_hl
<< 2) + ICMP_EXT_OFFSET
;
1142 cmn_hdr
= (struct icmp_ext_cmn_hdr
*)buf
;
1144 if (cmn_hdr
->version
!= ICMP_EXT_VERSION
) {
1151 datalen
= ip_len
- ((u_char
*)cmn_hdr
- (u_char
*)ip
);
1154 * Check the checksum, cmn_hdr->checksum == 0 means no checksum'ing
1157 * If the checksum is ok, we'll get 0, as the checksum is calculated
1158 * with the checksum field being 0'd.
1160 if (ntohs(cmn_hdr
->checksum
) &&
1161 in_cksum((u_short
*)cmn_hdr
, datalen
)) {
1166 buf
+= sizeof(*cmn_hdr
);
1167 datalen
-= sizeof(*cmn_hdr
);
1169 while (datalen
> 0) {
1170 obj_hdr
= (struct icmp_ext_obj_hdr
*)buf
;
1171 obj_len
= ntohs(obj_hdr
->length
);
1174 * Sanity check the length field
1176 if (obj_len
> datalen
) {
1183 * Move past the object header
1185 buf
+= sizeof(struct icmp_ext_obj_hdr
);
1186 obj_len
-= sizeof(struct icmp_ext_obj_hdr
);
1188 switch (obj_hdr
->class_num
) {
1189 case MPLS_STACK_ENTRY_CLASS
:
1190 switch (obj_hdr
->c_type
) {
1191 case MPLS_STACK_ENTRY_C_TYPE
:
1192 while (obj_len
>= sizeof(uint32_t)) {
1193 mpls
.mpls_h
= ntohl(*(uint32_t *)buf
);
1195 buf
+= sizeof(uint32_t);
1196 obj_len
-= sizeof(uint32_t);
1198 printf(" [MPLS: Label %d Exp %d]",
1199 mpls
.mpls
.label
, mpls
.mpls
.exp
);
1203 * Something went wrong, and we're at
1204 * a unknown offset into the packet,
1205 * ditch the rest of it.
1212 * Unknown object, skip past it
1214 buf
+= ntohs(obj_hdr
->length
) -
1215 sizeof(struct icmp_ext_obj_hdr
);
1222 * Unknown object, skip past it
1224 buf
+= ntohs(obj_hdr
->length
) -
1225 sizeof(struct icmp_ext_obj_hdr
);
1237 Fprintf(stderr
, "packet data:");
1240 for (p
= useicmp
? (u_char
*)outicmp
: (u_char
*)outudp
, i
= 0; i
<
1241 i
< packlen
- (sizeof(*outip
) + optlen
); i
++)
1243 for (p
= (u_char
*)outip
, i
= 0; i
< packlen
; i
++)
1247 Fprintf(stderr
, "\n ");
1248 Fprintf(stderr
, " %02x", *p
++);
1250 Fprintf(stderr
, "\n");
1254 send_probe(int seq
, int ttl
, struct timeval
*tp
)
1257 struct udpiphdr
* ui
;
1258 int oldmtu
= packlen
;
1261 #ifdef BYTESWAP_IP_LEN
1262 outip
->ip_len
= htons(packlen
);
1264 outip
->ip_len
= packlen
;
1266 outip
->ip_ttl
= ttl
;
1268 outip
->ip_id
= htons(ident
+ seq
);
1272 * In most cases, the kernel will recalculate the ip checksum.
1273 * But we must do it anyway so that the udp checksum comes out
1278 in_cksum((u_int16_t
*)outip
, sizeof(*outip
) + optlen
);
1279 if (outip
->ip_sum
== 0)
1280 outip
->ip_sum
= 0xffff;
1286 outsetup
.tv
.tv32_sec
= htonl(tp
->tv_sec
);
1287 outsetup
.tv
.tv32_usec
= htonl(tp
->tv_usec
);
1288 memcpy(outmark
,&outsetup
,sizeof(outsetup
));
1291 outicmp
->icmp_seq
= htons(seq
);
1293 outudp
->uh_dport
= htons(port
+ seq
);
1295 /* (We can only do the checksum if we know our ip address) */
1298 outicmp
->icmp_cksum
= 0;
1299 outicmp
->icmp_cksum
= in_cksum((u_int16_t
*)outicmp
,
1300 packlen
- (sizeof(*outip
) + optlen
));
1301 if (outicmp
->icmp_cksum
== 0)
1302 outicmp
->icmp_cksum
= 0xffff;
1314 ui
= (struct udpiphdr
*)outip
;
1315 memset(&phdr
, 0, sizeof(phdr
));
1316 phdr
.src
= ui
->ui_src
;
1317 phdr
.dst
= ((struct sockaddr_in
*)&whereto
)->sin_addr
;
1318 phdr
.protocol
= ui
->ui_pr
;
1319 phdr
.len
= outudp
->uh_ulen
;
1321 sum
= in_cksum2(0, (u_int16_t
*)&phdr
, sizeof(phdr
));
1322 sum
= in_cksum2(sum
, (u_int16_t
*)outudp
, ntohs(outudp
->uh_ulen
));
1323 outudp
->uh_sum
= ~sum
;
1324 if (outudp
->uh_sum
== 0)
1325 outudp
->uh_sum
= 0xffff;
1329 /* XXX undocumented debugging hack */
1331 const u_int16_t
*sp
;
1334 sp
= (u_int16_t
*)outip
;
1335 nshorts
= (u_int
)packlen
/ sizeof(u_int16_t
);
1337 Printf("[ %d bytes", packlen
);
1338 while (--nshorts
>= 0) {
1341 Printf(" %04x", ntohs(*sp
++));
1346 Printf(" %02x", *(u_char
*)sp
);
1351 #if !defined(IP_HDRINCL) && defined(IP_TTL)
1352 if (setsockopt(sndsock
, IPPROTO_IP
, IP_TTL
,
1353 (char *)&ttl
, sizeof(ttl
)) < 0) {
1354 Fprintf(stderr
, "%s: setsockopt ttl %d: %s\n",
1355 prog
, ttl
, strerror(errno
));
1363 cc
= sendto(sndsock
, useicmp
? (char *)outicmp
: (char *)outudp
,
1364 packlen
- (sizeof(*outip
) + optlen
), 0, &whereto
, sizeof(whereto
));
1366 cc
+= sizeof(*outip
) + optlen
;
1368 cc
= sendto(sndsock
, (char *)outip
,
1369 packlen
, 0, &whereto
, sizeof(whereto
));
1371 if (cc
< 0 || cc
!= packlen
) {
1374 * An errno of EMSGSIZE means we're writing too big a
1375 * datagram for the interface. We have to just
1376 * decrease the packet size until we find one that
1379 * XXX maybe we should try to read the outgoing if's
1382 if (errno
== EMSGSIZE
) {
1383 packlen
= *mtuptr
++;
1387 Fprintf(stderr
, "%s: sendto: %s\n",
1388 prog
, strerror(errno
));
1391 Printf("%s: wrote %s %d chars, ret=%d\n",
1392 prog
, hostname
, packlen
, cc
);
1393 (void)fflush(stdout
);
1395 if (oldmtu
!= packlen
) {
1396 Printf("message too big, "
1397 "trying new MTU = %d\n", packlen
);
1401 Printf("%2d ", ttl
);
1408 deltaT(struct timeval
*t1p
, struct timeval
*t2p
)
1412 dt
= (double)(t2p
->tv_sec
- t1p
->tv_sec
) * 1000.0 +
1413 (double)(t2p
->tv_usec
- t1p
->tv_usec
) / 1000.0;
1418 * Convert an ICMP "type" field to a printable string.
1423 static char *ttab
[] = {
1424 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
1425 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
1426 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
1427 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
1432 return("OUT-OF-RANGE");
1438 packet_ok(u_char
*buf
, int cc
, struct sockaddr_in
*from
, int seq
)
1446 ip
= (struct ip
*) buf
;
1447 hlen
= ip
->ip_hl
<< 2;
1448 if (cc
< hlen
+ ICMP_MINLEN
) {
1450 Printf("packet too short (%d bytes) from %s\n", cc
,
1451 inet_ntoa(from
->sin_addr
));
1455 icp
= (struct icmp
*)(buf
+ hlen
);
1457 icp
= (struct icmp
*)buf
;
1459 type
= icp
->icmp_type
;
1460 code
= icp
->icmp_code
;
1461 if ((type
== ICMP_TIMXCEED
&& code
== ICMP_TIMXCEED_INTRANS
) ||
1462 type
== ICMP_UNREACH
|| type
== ICMP_ECHOREPLY
) {
1467 hip
= &icp
->icmp_ip
;
1468 hlen
= hip
->ip_hl
<< 2;
1470 nextmtu
= ntohs(icp
->icmp_nextmtu
); /* for frag_err() */
1474 if (type
== ICMP_ECHOREPLY
&&
1475 icp
->icmp_id
== htons(ident
) &&
1476 icp
->icmp_seq
== htons(seq
))
1479 hicmp
= (struct icmp
*)((u_char
*)hip
+ hlen
);
1480 /* XXX 8 is a magic number */
1481 if (hlen
+ 8 <= cc
&&
1482 hip
->ip_p
== IPPROTO_ICMP
&&
1483 hicmp
->icmp_id
== htons(ident
) &&
1484 hicmp
->icmp_seq
== htons(seq
))
1485 return (type
== ICMP_TIMXCEED
? -1 : code
+ 1);
1487 up
= (struct udphdr
*)((u_char
*)hip
+ hlen
);
1488 /* XXX 8 is a magic number */
1489 if (hlen
+ 12 <= cc
&&
1490 hip
->ip_p
== IPPROTO_UDP
&&
1491 up
->uh_sport
== htons(ident
) &&
1492 up
->uh_dport
== htons(port
+ seq
))
1493 return (type
== ICMP_TIMXCEED
? -1 : code
+ 1);
1499 u_int32_t
*lp
= (u_int32_t
*)&icp
->icmp_ip
;
1501 Printf("\n%d bytes from %s to ", cc
, inet_ntoa(from
->sin_addr
));
1502 Printf("%s: icmp type %d (%s) code %d\n",
1503 inet_ntoa(ip
->ip_dst
), type
, pr_type(type
), icp
->icmp_code
);
1504 for (i
= 4; i
< cc
; i
+= sizeof(*lp
))
1505 Printf("%2d: x%8.8x\n", i
, *lp
++);
1511 void resize_packet(void)
1514 outicmp
->icmp_cksum
= 0;
1515 outicmp
->icmp_cksum
= in_cksum((u_int16_t
*)outicmp
,
1516 packlen
- (sizeof(*outip
) + optlen
));
1517 if (outicmp
->icmp_cksum
== 0)
1518 outicmp
->icmp_cksum
= 0xffff;
1521 htons((u_int16_t
)(packlen
- (sizeof(*outip
) + optlen
)));
1526 print(u_char
*buf
, int cc
, struct sockaddr_in
*from
)
1531 ip
= (struct ip
*) buf
;
1532 hlen
= ip
->ip_hl
<< 2;
1536 Printf(" [AS%d]", as_lookup(asn
, &from
->sin_addr
));
1539 Printf(" %s", inet_ntoa(from
->sin_addr
));
1541 Printf(" %s (%s)", inetname(from
->sin_addr
),
1542 inet_ntoa(from
->sin_addr
));
1545 Printf(" %d bytes to %s", cc
, inet_ntoa (ip
->ip_dst
));
1549 in_cksum(u_int16_t
*addr
, int len
)
1552 return ~in_cksum2(0, addr
, len
);
1556 * Checksum routine for Internet Protocol family headers (C Version)
1559 in_cksum2(u_int16_t seed
, u_int16_t
*addr
, int len
)
1562 u_int16_t
*w
= addr
;
1570 * Our algorithm is simple, using a 32 bit accumulator (sum),
1571 * we add sequential 16 bit words to it, and at the end, fold
1572 * back all the carry bits from the top 16 bits into the lower
1580 /* mop up an odd byte, if necessary */
1582 answer
.b
[0] = *(u_char
*)w
;
1588 * add back carry outs from top 16 bits to low 16 bits
1590 sum
= (sum
>> 16) + (sum
& 0xffff); /* add hi 16 to low 16 */
1591 sum
+= (sum
>> 16); /* add carry */
1592 answer
.w
= sum
; /* truncate to 16 bits */
1597 * Subtract 2 timeval structs: out = out - in.
1598 * Out is assumed to be >= in.
1601 tvsub(struct timeval
*out
, struct timeval
*in
)
1604 if ((out
->tv_usec
-= in
->tv_usec
) < 0) {
1606 out
->tv_usec
+= 1000000;
1608 out
->tv_sec
-= in
->tv_sec
;
1612 * Construct an Internet address representation.
1613 * If the nflag has been supplied, give
1614 * numeric value, otherwise try for symbolic name.
1617 inetname(struct in_addr in
)
1621 static int first
= 1;
1622 static char domain
[MAXHOSTNAMELEN
+ 1], line
[MAXHOSTNAMELEN
+ 1];
1624 if (first
&& !nflag
) {
1628 rv
= gethostname(domain
, sizeof domain
);
1629 if (rv
== 0 && (cp
= strchr(domain
, '.')) != NULL
) {
1630 (void)strlcpy(domain
, cp
+ 1, sizeof(domain
));
1634 if (!nflag
&& in
.s_addr
!= INADDR_ANY
) {
1635 hp
= gethostbyaddr((char *)&in
, sizeof(in
), AF_INET
);
1637 if ((cp
= strchr(hp
->h_name
, '.')) != NULL
&&
1638 strcmp(cp
+ 1, domain
) == 0)
1640 (void)strlcpy(line
, hp
->h_name
, sizeof(line
));
1644 return (inet_ntoa(in
));
1648 gethostinfo(char *hostname
)
1652 struct hostinfo
*hi
;
1655 struct in_addr addr
;
1657 hi
= calloc(1, sizeof(*hi
));
1659 Fprintf(stderr
, "%s: calloc %s\n", prog
, strerror(errno
));
1662 if (inet_aton(hostname
, &addr
) != 0) {
1663 hi
->name
= strdup(hostname
);
1665 Fprintf(stderr
, "%s: strdup %s\n", prog
,
1670 hi
->addrs
= calloc(1, sizeof(hi
->addrs
[0]));
1671 if (hi
->addrs
== NULL
) {
1672 Fprintf(stderr
, "%s: calloc %s\n",
1673 prog
, strerror(errno
));
1676 hi
->addrs
[0] = addr
.s_addr
;
1680 hp
= gethostbyname(hostname
);
1682 Fprintf(stderr
, "%s: unknown host %s\n", prog
, hostname
);
1685 if (hp
->h_addrtype
!= AF_INET
|| hp
->h_length
!= 4) {
1686 Fprintf(stderr
, "%s: bad host %s\n", prog
, hostname
);
1689 hi
->name
= strdup(hp
->h_name
);
1691 Fprintf(stderr
, "%s: strdup %s\n", prog
, strerror(errno
));
1694 for (n
= 0, p
= hp
->h_addr_list
; *p
!= NULL
; ++n
, ++p
)
1697 hi
->addrs
= calloc(n
, sizeof(hi
->addrs
[0]));
1698 if (hi
->addrs
== NULL
) {
1699 Fprintf(stderr
, "%s: calloc %s\n", prog
, strerror(errno
));
1702 for (ap
= hi
->addrs
, p
= hp
->h_addr_list
; *p
!= NULL
; ++ap
, ++p
)
1703 memcpy(ap
, *p
, sizeof(*ap
));
1708 freehostinfo(struct hostinfo
*hi
)
1710 if (hi
->name
!= NULL
) {
1714 free((char *)hi
->addrs
);
1719 getaddr(u_int32_t
*ap
, char *hostname
)
1721 struct hostinfo
*hi
;
1723 hi
= gethostinfo(hostname
);
1729 setsin(struct sockaddr_in
*sin
, u_int32_t addr
)
1732 memset(sin
, 0, sizeof(*sin
));
1733 #ifdef HAVE_SOCKADDR_SA_LEN
1734 sin
->sin_len
= sizeof(*sin
);
1736 sin
->sin_family
= AF_INET
;
1737 sin
->sin_addr
.s_addr
= addr
;
1740 /* String to value with optional min and max. Handles decimal and hex. */
1742 str2val(const char *str
, const char *what
, int mi
, int ma
)
1750 if (str
[0] == '0' && (str
[1] == 'x' || str
[1] == 'X')) {
1752 val
= strtol(cp
, &ep
, 16);
1754 val
= strtol(str
, &ep
, 10);
1755 if (errno
|| str
[0] == '\0' || *ep
!= '\0') {
1756 Fprintf(stderr
, "%s: \"%s\" bad value for %s \n",
1760 if (val
< mi
&& mi
>= 0) {
1762 Fprintf(stderr
, "%s: %s must be >= %d\n",
1765 Fprintf(stderr
, "%s: %s must be > %d\n",
1766 prog
, what
, mi
- 1);
1769 if (val
> ma
&& ma
>= 0) {
1770 Fprintf(stderr
, "%s: %s must be <= %d\n", prog
, what
, ma
);
1779 extern char version
[];
1781 Fprintf(stderr
, "Version %s\n", version
);
1782 Fprintf(stderr
, "usage: %s [-adDFPIlMnrvx] [-g gateway] [-i iface] \
1783 [-f first_ttl]\n\t[-m max_ttl] [-p port] [-q nqueries] [-s src_addr] [-t tos]\n\t\
1784 [-w waittime] [-A as_server] host [packetlen]\n",
1790 * Received ICMP unreachable (fragmentation required and DF set).
1791 * If the ICMP error was from a "new" router, it'll contain the next-hop
1792 * MTU that we should use next. Otherwise we'll just keep going in the
1793 * mtus[] table, trying until we hit a valid MTU.
1802 if (nextmtu
> 0 && nextmtu
< packlen
) {
1803 Printf("\nfragmentation required and DF set, "
1804 "next hop MTU = %d\n",
1807 for (i
= 0; mtus
[i
] > 0; i
++) {
1808 if (mtus
[i
] < nextmtu
) {
1809 mtuptr
= &mtus
[i
]; /* next one to try */
1814 Printf("\nfragmentation required and DF set. ");
1816 Printf("\nBogus next hop MTU = %d > last MTU = %d. ",
1818 packlen
= *mtuptr
++;
1819 Printf("Trying new MTU = %d\n", packlen
);
1825 find_local_ip(struct sockaddr_in
*from
, struct sockaddr_in
*to
)
1828 struct sockaddr_in help
;
1831 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
1832 if (sock
< 0) return (0);
1834 help
.sin_family
= AF_INET
;
1836 * At this point the port number doesn't matter
1837 * since it only has to be greater than zero.
1840 help
.sin_addr
.s_addr
= to
->sin_addr
.s_addr
;
1841 if (connect(sock
, (struct sockaddr
*)&help
, sizeof(help
)) < 0) {
1846 help_len
= sizeof(help
);
1847 if (getsockname(sock
, (struct sockaddr
*)&help
, &help_len
) < 0 ||
1848 help_len
!= sizeof(help
) ||
1849 help
.sin_addr
.s_addr
== INADDR_ANY
) {
1855 setsin(from
, help
.sin_addr
.s_addr
);
1860 #ifdef IPSEC_POLICY_IPSEC
1862 setpolicy(so
, policy
)
1868 buf
= ipsec_set_policy(policy
, strlen(policy
));
1870 Fprintf(stderr
, "%s: %s\n", prog
, ipsec_strerror());
1873 (void)setsockopt(so
, IPPROTO_IP
, IP_IPSEC_POLICY
,
1874 buf
, ipsec_get_policylen(buf
));