2 * Copyright (c) 2004-2009 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000
31 * The Regents of the University of California. All rights reserved.
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that: (1) source code distributions
35 * retain the above copyright notice and this paragraph in its entirety, (2)
36 * distributions including binary code include the above copyright notice and
37 * this paragraph in its entirety in the documentation or other materials
38 * provided with the distribution, and (3) all advertising materials mentioning
39 * features or use of this software display the following acknowledgement:
40 * ``This product includes software developed by the University of California,
41 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
42 * the University nor the names of its contributors may be used to endorse
43 * or promote products derived from this software without specific prior
45 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
46 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
47 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
51 static const char copyright
[] =
52 "@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000\n\
53 The Regents of the University of California. All rights reserved.\n";
55 static const char rcsid
[] =
56 "@(#)$Id: traceroute.c,v 1.4 2006/02/07 06:22:57 lindak Exp $ (LBL)";
58 static const char rcsid
[] =
59 "$FreeBSD: src/contrib/traceroute/traceroute.c,v 1.35 2008/02/20 23:29:52 rpaulo Exp $";
63 * traceroute host - trace the route ip packets follow going to "host".
65 * Attempt to trace the route an ip packet would follow to some
66 * internet host. We find out intermediate hops by launching probe
67 * packets with a small ttl (time to live) then listening for an
68 * icmp "time exceeded" reply from a gateway. We start our probes
69 * with a ttl of one and increase by one until we get an icmp "port
70 * unreachable" (which means we got to "host") or hit a max (which
71 * defaults to net.inet.ip.ttl hops & can be changed with the -m flag).
72 * Three probes (change with -q flag) are sent at each ttl setting and
73 * a line is printed showing the ttl, address of the gateway and
74 * round trip time of each probe. If the probe answers come from
75 * different gateways, the address of each responding system will
76 * be printed. If there is no response within a 5 sec. timeout
77 * interval (changed with the -w flag), a "*" is printed for that
80 * Probe packets are UDP format. We don't want the destination
81 * host to process them so the destination port is set to an
82 * unlikely value (if some clod on the destination is using that
83 * value, it can be changed with the -p flag).
85 * A sample use might be:
87 * [yak 71]% traceroute nis.nsf.net.
88 * traceroute to nis.nsf.net (35.1.1.48), 64 hops max, 56 byte packet
89 * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms
90 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
91 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
92 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms
93 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms
94 * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms
95 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms
96 * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms
97 * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms
98 * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms
99 * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms
101 * Note that lines 2 & 3 are the same. This is due to a buggy
102 * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
103 * packets with a zero ttl.
105 * A more interesting example is:
107 * [yak 72]% traceroute allspice.lcs.mit.edu.
108 * traceroute to allspice.lcs.mit.edu (18.26.0.115), 64 hops max
109 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
110 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms
111 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms
112 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms
113 * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms
114 * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms
115 * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms
116 * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms
117 * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms
118 * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms
119 * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms
121 * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms
126 * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms
128 * (I start to see why I'm having so much trouble with mail to
129 * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away
130 * either don't send ICMP "time exceeded" messages or send them
131 * with a ttl too small to reach us. 14 - 17 are running the
132 * MIT C Gateway code that doesn't send "time exceeded"s. God
133 * only knows what's going on with 12.
135 * The silent gateway 12 in the above may be the result of a bug in
136 * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3)
137 * sends an unreachable message using whatever ttl remains in the
138 * original datagram. Since, for gateways, the remaining ttl is
139 * zero, the icmp "time exceeded" is guaranteed to not make it back
140 * to us. The behavior of this bug is slightly more interesting
141 * when it appears on the destination system:
143 * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
144 * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms
145 * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms
146 * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms
147 * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms
148 * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms
155 * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms !
157 * Notice that there are 12 "gateways" (13 is the final
158 * destination) and exactly the last half of them are "missing".
159 * What's really happening is that rip (a Sun-3 running Sun OS3.5)
160 * is using the ttl from our arriving datagram as the ttl in its
161 * icmp reply. So, the reply will time out on the return path
162 * (with no notice sent to anyone since icmp's aren't sent for
163 * icmp's) until we probe with a ttl that's at least twice the path
164 * length. I.e., rip is really only 7 hops away. A reply that
165 * returns with a ttl of 1 is a clue this problem exists.
166 * Traceroute prints a "!" after the time if the ttl is <= 1.
167 * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
168 * non-standard (HPUX) software, expect to see this problem
169 * frequently and/or take care picking the target host of your
172 * Other possible annotations after the time are !H, !N, !P (got a host,
173 * network or protocol unreachable, respectively), !S or !F (source
174 * route failed or fragmentation needed -- neither of these should
175 * ever occur and the associated gateway is busted if you see one). If
176 * almost all the probes result in some kind of unreachable, traceroute
177 * will give up and exit.
181 * This program must be run by root or be setuid. (I suggest that
182 * you *don't* make it setuid -- casual use could result in a lot
183 * of unnecessary traffic on our poor, congested nets.)
185 * This program requires a kernel mod that does not appear in any
186 * system available from Berkeley: A raw ip socket using proto
187 * IPPROTO_RAW must interpret the data sent as an ip datagram (as
188 * opposed to data to be wrapped in a ip datagram). See the README
189 * file that came with the source to this program for a description
190 * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may
191 * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
192 * MODIFIED TO RUN THIS PROGRAM.
194 * The udp port usage may appear bizarre (well, ok, it is bizarre).
195 * The problem is that an icmp message only contains 8 bytes of
196 * data from the original datagram. 8 bytes is the size of a udp
197 * header so, if we want to associate replies with the original
198 * datagram, the necessary information must be encoded into the
199 * udp header (the ip id could be used but there's no way to
200 * interlock with the kernel's assignment of ip id's and, anyway,
201 * it would have taken a lot more kernel hacking to allow this
202 * code to set the ip id). So, to allow two or more users to
203 * use traceroute simultaneously, we use this task's pid as the
204 * source port (the high bit is set to move the port number out
205 * of the "likely" range). To keep track of which probe is being
206 * replied to (so times and/or hop counts don't get confused by a
207 * reply that was delayed in transit), we increment the destination
208 * port number before each probe.
210 * Don't use this as a coding example. I was trying to find a
211 * routing problem and this code sort-of popped out after 48 hours
212 * without sleep. I was amazed it ever compiled, much less ran.
214 * I stole the idea for this program from Steve Deering. Since
215 * the first release, I've learned that had I attended the right
216 * IETF working group meetings, I also could have stolen it from Guy
217 * Almes or Matt Mathis. I don't know (or care) who came up with
218 * the idea first. I envy the originators' perspicacity and I'm
219 * glad they didn't keep the idea a secret.
221 * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
222 * enhancements to the original distribution.
224 * I've hacked up a round-trip-route version of this that works by
225 * sending a loose-source-routed udp datagram through the destination
226 * back to yourself. Unfortunately, SO many gateways botch source
227 * routing, the thing is almost worthless. Maybe one day...
229 * -- Van Jacobson (van@ee.lbl.gov)
230 * Tue Dec 20 03:50:13 PST 1988
233 #include <sys/param.h>
234 #include <sys/file.h>
235 #include <sys/ioctl.h>
236 #ifdef HAVE_SYS_SELECT_H
237 #include <sys/select.h>
239 #include <sys/socket.h>
240 #ifdef HAVE_SYS_SYSCTL_H
241 #include <sys/sysctl.h>
243 #include <sys/time.h>
245 #include <netinet/in_systm.h>
246 #include <netinet/in.h>
247 #include <netinet/ip.h>
248 #include <netinet/ip_var.h>
249 #include <netinet/ip_icmp.h>
250 #include <netinet/udp.h>
251 #include <netinet/udp_var.h>
252 #include <netinet/tcp.h>
253 #include <netinet/tcpip.h>
255 #include <arpa/inet.h>
258 #include <net/route.h>
259 #include <netinet6/ipsec.h> /* XXX */
277 #ifdef HAVE_OS_PROTO_H
278 #include "os-proto.h"
282 #ifndef ICMP_UNREACH_FILTER_PROHIB
283 #define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohibited filter */
285 #ifndef ICMP_UNREACH_HOST_PRECEDENCE
286 #define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host precedence violation */
288 #ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF
289 #define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* precedence cutoff */
292 #include "findsaddr.h"
293 #include "ifaddrlist.h"
295 #include "traceroute.h"
297 /* Maximum number of gateways (include room for one noop) */
298 #define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))
300 #ifndef MAXHOSTNAMELEN
301 #define MAXHOSTNAMELEN 64
304 #define Fprintf (void)fprintf
305 #define Printf (void)printf
307 /* What a GRE packet header looks like */
311 u_int16_t length
; /* PPTP version of these fields */
315 #define IPPROTO_GRE 47
318 /* For GRE, we prepare what looks like a PPTP packet */
319 #define GRE_PPTP_PROTO 0x880b
321 /* Host name and address list */
328 /* Data section of the probe packet */
330 u_char seq
; /* sequence number of this packet */
331 u_char ttl
; /* ttl packet left with */
332 struct timeval tv
; /* time packet left */
335 #ifndef HAVE_ICMP_NEXTMTU
336 /* Path MTU Discovery (RFC1191) */
343 u_char packet
[512]; /* last inbound (icmp) packet */
345 struct ip
*outip
; /* last output ip packet */
346 u_char
*outp
; /* last output inner protocol packet */
348 struct ip
*hip
= NULL
; /* Quoted IP header */
351 /* loose source route gateway list (including room for final destination) */
352 u_int32_t gwlist
[NGATEWAYS
+ 1];
354 int s
; /* receive (icmp) socket file descriptor */
355 int sndsock
; /* send (udp) socket file descriptor */
357 struct sockaddr whereto
; /* Who to try to reach */
358 struct sockaddr wherefrom
; /* Who we are */
359 int packlen
; /* total length of packet */
360 int protlen
; /* length of protocol part of packet */
361 int minpacket
; /* min ip packet size */
362 int maxpacket
= 32 * 1024; /* max ip packet size */
363 int pmtu
; /* Path MTU Discovery (RFC1191) */
370 static const char devnull
[] = "/dev/null";
376 u_short port
; /* protocol specific base "port" */
378 int options
; /* socket options */
380 int waittime
= 5; /* time to wait for response (in seconds) */
381 int nflag
; /* print addresses numerically */
382 int as_path
; /* print as numbers for each hop */
383 char *as_server
= NULL
;
385 #ifdef CANT_HACK_IPCKSUM
386 int doipcksum
= 0; /* don't calculate ip checksums by default */
388 int doipcksum
= 1; /* calculate ip checksums by default */
390 int optlen
; /* length of ip options */
391 int fixedPort
= 0; /* Use fixed destination port for TCP and UDP */
392 int printdiff
= 0; /* Print the difference between sent and quoted */
399 double deltaT(struct timeval
*, struct timeval
*);
400 void freehostinfo(struct hostinfo
*);
401 void getaddr(u_int32_t
*, char *);
402 struct hostinfo
*gethostinfo(char *);
403 u_short
in_cksum(u_short
*, int);
404 char *inetname(struct in_addr
);
405 int main(int, char **);
406 u_short
p_cksum(struct ip
*, u_short
*, int);
407 int packet_ok(u_char
*, int, struct sockaddr_in
*, int);
408 char *pr_type(u_char
);
409 void print(u_char
*, int, struct sockaddr_in
*);
411 int setpolicy
__P((int so
, char *policy
));
413 void send_probe(int, int);
414 struct outproto
*setproto(char *);
415 int str2val(const char *, const char *, int, int);
416 void tvsub(struct timeval
*, struct timeval
*);
418 int wait_for_reply(int, struct sockaddr_in
*, const struct timeval
*);
419 void pkt_compare(const u_char
*, int, const u_char
*, int);
424 void udp_prep(struct outdata
*);
425 int udp_check(const u_char
*, int);
426 void tcp_prep(struct outdata
*);
427 int tcp_check(const u_char
*, int);
428 void gre_prep(struct outdata
*);
429 int gre_check(const u_char
*, int);
430 void gen_prep(struct outdata
*);
431 int gen_check(const u_char
*, int);
432 void icmp_prep(struct outdata
*);
433 int icmp_check(const u_char
*, int);
435 /* Descriptor structure for each outgoing protocol we support */
437 char *name
; /* name of protocol */
438 const char *key
; /* An ascii key for the bytes of the header */
439 u_char num
; /* IP protocol number */
440 u_short hdrlen
; /* max size of protocol header */
441 u_short port
; /* default base protocol-specific "port" */
442 void (*prepare
)(struct outdata
*);
443 /* finish preparing an outgoing packet */
444 int (*check
)(const u_char
*, int);
445 /* check an incoming packet */
448 /* List of supported protocols. The first one is the default. The last
449 one is the handler for generic protocols not explicitly listed. */
450 struct outproto protos
[] = {
455 sizeof(struct udphdr
),
462 "spt dpt seq ack xxflwin sum urp",
464 sizeof(struct tcphdr
),
473 sizeof(struct grehdr
),
497 struct outproto
*proto
= &protos
[0];
499 const char *ip_hdr_key
= "vhtslen id off tlprsum srcip dstip opts";
502 main(int argc
, char **argv
)
504 register int op
, code
, n
;
506 register const char *err
;
507 register u_int32_t
*ap
;
508 register struct sockaddr_in
*from
= (struct sockaddr_in
*)&wherefrom
;
509 register struct sockaddr_in
*to
= (struct sockaddr_in
*)&whereto
;
510 register struct hostinfo
*hi
;
512 register struct protoent
*pe
;
513 register int ttl
, probe
, i
;
514 register int seq
= 0;
515 int tos
= 0, settos
= 0;
516 register int lsrr
= 0;
517 register u_short off
= 0;
518 struct ifaddrlist
*al
;
520 int requestPort
= -1;
524 /* Insure the socket fds won't be 0, 1 or 2 */
525 if (open(devnull
, O_RDONLY
) < 0 ||
526 open(devnull
, O_RDONLY
) < 0 ||
527 open(devnull
, O_RDONLY
) < 0) {
528 Fprintf(stderr
, "%s: open \"%s\": %s\n",
529 prog
, devnull
, strerror(errno
));
533 * Do the setuid-required stuff first, then lose priveleges ASAP.
534 * Do error checking for these two calls where they appeared in
538 pe
= getprotobyname(cp
);
540 if ((s
= socket(AF_INET
, SOCK_RAW
, pe
->p_proto
)) < 0)
542 else if ((sndsock
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
)) < 0)
550 int mib
[4] = { CTL_NET
, PF_INET
, IPPROTO_IP
, IPCTL_DEFTTL
};
551 size_t sz
= sizeof(max_ttl
);
553 if (sysctl(mib
, 4, &max_ttl
, &sz
, NULL
, 0) == -1) {
554 perror("sysctl(net.inet.ip.ttl)");
564 else if ((cp
= strrchr(argv
[0], '/')) != NULL
)
570 while ((op
= getopt(argc
, argv
, "aA:edDFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF
)
594 case 'M': /* FreeBSD compat. */
595 first_ttl
= str2val(optarg
, "first ttl", 1, 255);
603 if (lsrr
>= NGATEWAYS
) {
605 "%s: No more than %d gateways\n",
609 getaddr(gwlist
+ lsrr
, optarg
);
618 proto
= setproto("icmp");
622 max_ttl
= str2val(optarg
, "max ttl", 1, 255);
630 proto
= setproto(optarg
);
634 requestPort
= (u_short
)str2val(optarg
, "port",
639 nprobes
= str2val(optarg
, "nprobes", 1, -1);
643 options
|= SO_DONTROUTE
;
648 * set the ip source address of the outbound
649 * probe (e.g., on a multi-homed host).
659 tos
= str2val(optarg
, "tos", 0, 255);
668 doipcksum
= (doipcksum
== 0);
672 waittime
= str2val(optarg
, "wait time",
677 pausemsecs
= str2val(optarg
, "pause msecs",
685 /* Set requested port, if any, else default for this protocol */
686 port
= (requestPort
!= -1) ? requestPort
: proto
->port
;
689 nprobes
= printdiff
? 1 : 3;
691 if (first_ttl
> max_ttl
) {
693 "%s: first ttl (%d) may not be greater than max ttl (%d)\n",
694 prog
, first_ttl
, max_ttl
);
699 Fprintf(stderr
, "%s: Warning: ip checksums disabled\n", prog
);
702 optlen
= (lsrr
+ 1) * sizeof(gwlist
[0]);
703 minpacket
= sizeof(*outip
) + proto
->hdrlen
+ sizeof(struct outdata
) + optlen
;
704 packlen
= minpacket
; /* minimum sized packet */
706 /* Process destination and optional packet size */
707 switch (argc
- optind
) {
710 packlen
= str2val(argv
[optind
+ 1],
711 "packet length", minpacket
, maxpacket
);
715 hostname
= argv
[optind
];
716 hi
= gethostinfo(hostname
);
717 setsin(to
, hi
->addrs
[0]);
720 "%s: Warning: %s has multiple addresses; using %s\n",
721 prog
, hostname
, inet_ntoa(to
->sin_addr
));
731 #ifdef HAVE_SETLINEBUF
734 setvbuf(stdout
, NULL
, _IOLBF
, 0);
737 protlen
= packlen
- sizeof(*outip
) - optlen
;
739 outip
= (struct ip
*)malloc((unsigned)packlen
);
741 Fprintf(stderr
, "%s: malloc: %s\n", prog
, strerror(errno
));
744 memset((char *)outip
, 0, packlen
);
746 outip
->ip_v
= IPVERSION
;
749 #ifdef BYTESWAP_IP_HDR
750 outip
->ip_len
= htons(packlen
);
751 outip
->ip_off
= htons(off
);
753 outip
->ip_len
= packlen
;
756 outip
->ip_p
= proto
->num
;
757 outp
= (u_char
*)(outip
+ 1);
758 #ifdef HAVE_RAW_OPTIONS
760 register u_char
*optlist
;
766 gwlist
[lsrr
] = to
->sin_addr
.s_addr
;
768 outip
->ip_dst
.s_addr
= gwlist
[0];
770 /* force 4 byte alignment */
771 optlist
[0] = IPOPT_NOP
;
772 /* loose source route option */
773 optlist
[1] = IPOPT_LSRR
;
774 i
= lsrr
* sizeof(gwlist
[0]);
776 /* Pointer to LSRR addresses */
777 optlist
[3] = IPOPT_MINOFF
;
778 memcpy(optlist
+ 4, gwlist
+ 1, i
);
781 outip
->ip_dst
= to
->sin_addr
;
783 outip
->ip_hl
= (outp
- (u_char
*)outip
) >> 2;
784 ident
= (getpid() & 0xffff) | 0x8000;
787 Fprintf(stderr
, "%s: unknown protocol %s\n", prog
, cp
);
792 Fprintf(stderr
, "%s: icmp socket: %s\n", prog
, strerror(errno
));
795 if (options
& SO_DEBUG
)
796 (void)setsockopt(s
, SOL_SOCKET
, SO_DEBUG
, (char *)&on
,
798 if (options
& SO_DONTROUTE
)
799 (void)setsockopt(s
, SOL_SOCKET
, SO_DONTROUTE
, (char *)&on
,
802 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
803 if (setpolicy(s
, "in bypass") < 0)
804 errx(1, "%s", ipsec_strerror());
806 if (setpolicy(s
, "out bypass") < 0)
807 errx(1, "%s", ipsec_strerror());
808 #endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
812 Fprintf(stderr
, "%s: raw socket: %s\n", prog
, strerror(errno
));
816 #if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS)
818 u_char optlist
[MAX_IPOPTLEN
];
821 if ((pe
= getprotobyname(cp
)) == NULL
) {
822 Fprintf(stderr
, "%s: unknown protocol %s\n", prog
, cp
);
827 gwlist
[lsrr
] = to
->sin_addr
.s_addr
;
830 /* force 4 byte alignment */
831 optlist
[0] = IPOPT_NOP
;
832 /* loose source route option */
833 optlist
[1] = IPOPT_LSRR
;
834 i
= lsrr
* sizeof(gwlist
[0]);
836 /* Pointer to LSRR addresses */
837 optlist
[3] = IPOPT_MINOFF
;
838 memcpy(optlist
+ 4, gwlist
, i
);
840 if ((setsockopt(sndsock
, pe
->p_proto
, IP_OPTIONS
,
841 (char *)optlist
, i
+ sizeof(gwlist
[0]))) < 0) {
842 Fprintf(stderr
, "%s: IP_OPTIONS: %s\n",
843 prog
, strerror(errno
));
850 if (setsockopt(sndsock
, SOL_SOCKET
, SO_SNDBUF
, (char *)&packlen
,
851 sizeof(packlen
)) < 0) {
852 Fprintf(stderr
, "%s: SO_SNDBUF: %s\n", prog
, strerror(errno
));
857 if (setsockopt(sndsock
, IPPROTO_IP
, IP_HDRINCL
, (char *)&on
,
859 Fprintf(stderr
, "%s: IP_HDRINCL: %s\n", prog
, strerror(errno
));
864 if (settos
&& setsockopt(sndsock
, IPPROTO_IP
, IP_TOS
,
865 (char *)&tos
, sizeof(tos
)) < 0) {
866 Fprintf(stderr
, "%s: setsockopt tos %d: %s\n",
867 prog
, tos
, strerror(errno
));
872 if (options
& SO_DEBUG
)
873 (void)setsockopt(sndsock
, SOL_SOCKET
, SO_DEBUG
, (char *)&on
,
875 if (options
& SO_DONTROUTE
)
876 (void)setsockopt(sndsock
, SOL_SOCKET
, SO_DONTROUTE
, (char *)&on
,
879 /* Get the interface address list */
880 n
= ifaddrlist(&al
, errbuf
, sizeof(errbuf
));
882 Fprintf(stderr
, "%s: ifaddrlist: %s\n", prog
, errbuf
);
887 "%s: Can't find any network interfaces\n", prog
);
891 /* Look for a specific device */
892 if (device
!= NULL
) {
893 for (i
= n
; i
> 0; --i
, ++al
)
894 if (strcmp(device
, al
->device
) == 0)
897 Fprintf(stderr
, "%s: Can't find interface %.32s\n",
903 /* Determine our source address */
904 if (source
== NULL
) {
906 * If a device was specified, use the interface address.
907 * Otherwise, try to determine our source address.
910 setsin(from
, al
->addr
);
911 else if ((err
= findsaddr(to
, from
)) != NULL
) {
912 Fprintf(stderr
, "%s: findsaddr: %s\n",
917 hi
= gethostinfo(source
);
921 * If the device was specified make sure it
922 * corresponds to the source address specified.
923 * Otherwise, use the first address (and warn if
924 * there are more than one).
926 if (device
!= NULL
) {
927 for (i
= hi
->n
, ap
= hi
->addrs
; i
> 0; --i
, ++ap
)
932 "%s: %s is not on interface %.32s\n",
933 prog
, source
, device
);
938 setsin(from
, hi
->addrs
[0]);
941 "%s: Warning: %s has multiple addresses; using %s\n",
942 prog
, source
, inet_ntoa(from
->sin_addr
));
947 outip
->ip_src
= from
->sin_addr
;
949 /* Check the source address (-s), if any, is valid */
950 if (bind(sndsock
, (struct sockaddr
*)from
, sizeof(*from
)) < 0) {
951 Fprintf(stderr
, "%s: bind: %s\n",
952 prog
, strerror(errno
));
957 asn
= as_setup(as_server
);
959 Fprintf(stderr
, "%s: as_setup failed, AS# lookups"
960 " disabled\n", prog
);
961 (void)fflush(stderr
);
966 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
967 if (setpolicy(sndsock
, "in bypass") < 0)
968 errx(1, "%s", ipsec_strerror());
970 if (setpolicy(sndsock
, "out bypass") < 0)
971 errx(1, "%s", ipsec_strerror());
972 #endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
974 Fprintf(stderr
, "%s to %s (%s)",
975 prog
, hostname
, inet_ntoa(to
->sin_addr
));
977 Fprintf(stderr
, " from %s", source
);
978 Fprintf(stderr
, ", %d hops max, %d byte packets\n", max_ttl
, packlen
);
979 (void)fflush(stderr
);
981 for (ttl
= first_ttl
; ttl
<= max_ttl
; ++ttl
) {
982 u_int32_t lastaddr
= 0;
990 for (probe
= 0, loss
= 0; probe
< nprobes
; ++probe
) {
992 struct timeval t1
, t2
;
994 register struct ip
*ip
;
995 struct outdata outdata
;
997 if (sentfirst
&& pausemsecs
> 0)
998 usleep(pausemsecs
* 1000);
999 /* Prepare outgoing data */
1000 outdata
.seq
= ++seq
;
1003 /* Avoid alignment problems by copying bytewise: */
1004 (void)gettimeofday(&t1
, &tz
);
1005 memcpy(&outdata
.tv
, &t1
, sizeof(outdata
.tv
));
1007 /* Finalize and send packet */
1008 (*proto
->prepare
)(&outdata
);
1009 send_probe(seq
, ttl
);
1012 /* Wait for a reply */
1013 while ((cc
= wait_for_reply(s
, from
, &t1
)) != 0) {
1017 (void)gettimeofday(&t2
, &tz
);
1018 i
= packet_ok(packet
, cc
, from
, seq
);
1019 /* Skip short packet */
1023 from
->sin_addr
.s_addr
!= lastaddr
) {
1024 if (gotlastaddr
) printf("\n ");
1025 print(packet
, cc
, from
);
1026 lastaddr
= from
->sin_addr
.s_addr
;
1029 T
= deltaT(&t1
, &t2
);
1030 #ifdef SANE_PRECISION
1033 else if (T
>= 100.0)
1040 Printf(" %.*f ms", precis
, T
);
1044 -(outip
->ip_hl
<< 3),
1048 pkt_compare((void *)outip
, packlen
,
1049 (void *)hip
, hiplen
);
1053 ip
= (struct ip
*)packet
;
1054 if (ip
->ip_ttl
<= 1)
1060 /* time exceeded in transit */
1066 case ICMP_UNREACH_PORT
:
1068 ip
= (struct ip
*)packet
;
1069 if (ip
->ip_ttl
<= 1)
1075 case ICMP_UNREACH_NET
:
1080 case ICMP_UNREACH_HOST
:
1085 case ICMP_UNREACH_PROTOCOL
:
1090 case ICMP_UNREACH_NEEDFRAG
:
1092 Printf(" !F-%d", pmtu
);
1095 case ICMP_UNREACH_SRCFAIL
:
1100 case ICMP_UNREACH_NET_UNKNOWN
:
1105 case ICMP_UNREACH_HOST_UNKNOWN
:
1110 case ICMP_UNREACH_ISOLATED
:
1115 case ICMP_UNREACH_NET_PROHIB
:
1120 case ICMP_UNREACH_HOST_PROHIB
:
1125 case ICMP_UNREACH_TOSNET
:
1130 case ICMP_UNREACH_TOSHOST
:
1135 case ICMP_UNREACH_FILTER_PROHIB
:
1140 case ICMP_UNREACH_HOST_PRECEDENCE
:
1145 case ICMP_UNREACH_PRECEDENCE_CUTOFF
:
1152 Printf(" !<%d>", code
);
1161 (void)fflush(stdout
);
1164 Printf(" (%d%% loss)", (loss
* 100) / nprobes
);
1168 (unreachable
> 0 && unreachable
>= nprobes
- 1))
1177 wait_for_reply(register int sock
, register struct sockaddr_in
*fromp
,
1178 register const struct timeval
*tp
)
1182 struct timeval now
, wait
;
1184 register int cc
= 0;
1186 socklen_t fromlen
= sizeof(*fromp
);
1188 nfds
= howmany(sock
+ 1, NFDBITS
);
1189 if ((fdsp
= malloc(nfds
* sizeof(fd_mask
))) == NULL
)
1191 memset(fdsp
, 0, nfds
* sizeof(fd_mask
));
1194 wait
.tv_sec
= tp
->tv_sec
+ waittime
;
1195 wait
.tv_usec
= tp
->tv_usec
;
1196 (void)gettimeofday(&now
, &tz
);
1198 if (wait
.tv_sec
< 0) {
1203 error
= select(sock
+ 1, fdsp
, NULL
, NULL
, &wait
);
1204 if (error
== -1 && errno
== EINVAL
) {
1205 Fprintf(stderr
, "%s: botched select() args\n", prog
);
1209 cc
= recvfrom(sock
, (char *)packet
, sizeof(packet
), 0,
1210 (struct sockaddr
*)fromp
, &fromlen
);
1217 send_probe(int seq
, int ttl
)
1221 outip
->ip_ttl
= ttl
;
1222 outip
->ip_id
= htons(ident
+ seq
);
1224 /* XXX undocumented debugging hack */
1226 register const u_short
*sp
;
1227 register int nshorts
, i
;
1229 sp
= (u_short
*)outip
;
1230 nshorts
= (u_int
)packlen
/ sizeof(u_short
);
1232 Printf("[ %d bytes", packlen
);
1233 while (--nshorts
>= 0) {
1236 Printf(" %04x", ntohs(*sp
++));
1241 Printf(" %02x", *(u_char
*)sp
);
1246 #if !defined(IP_HDRINCL) && defined(IP_TTL)
1247 if (setsockopt(sndsock
, IPPROTO_IP
, IP_TTL
,
1248 (char *)&ttl
, sizeof(ttl
)) < 0) {
1249 Fprintf(stderr
, "%s: setsockopt ttl %d: %s\n",
1250 prog
, ttl
, strerror(errno
));
1255 cc
= sendto(sndsock
, (char *)outip
,
1256 packlen
, 0, &whereto
, sizeof(whereto
));
1257 if (cc
< 0 || cc
!= packlen
) {
1259 Fprintf(stderr
, "%s: sendto: %s\n",
1260 prog
, strerror(errno
));
1261 Printf("%s: wrote %s %d chars, ret=%d\n",
1262 prog
, hostname
, packlen
, cc
);
1263 (void)fflush(stdout
);
1267 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
1269 setpolicy(so
, policy
)
1275 buf
= ipsec_set_policy(policy
, strlen(policy
));
1277 warnx("%s", ipsec_strerror());
1280 (void)setsockopt(so
, IPPROTO_IP
, IP_IPSEC_POLICY
,
1281 buf
, ipsec_get_policylen(buf
));
1290 deltaT(struct timeval
*t1p
, struct timeval
*t2p
)
1294 dt
= (double)(t2p
->tv_sec
- t1p
->tv_sec
) * 1000.0 +
1295 (double)(t2p
->tv_usec
- t1p
->tv_usec
) / 1000.0;
1300 * Convert an ICMP "type" field to a printable string.
1303 pr_type(register u_char t
)
1305 static char *ttab
[] = {
1306 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
1307 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
1308 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
1309 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
1314 return("OUT-OF-RANGE");
1320 packet_ok(register u_char
*buf
, int cc
, register struct sockaddr_in
*from
,
1323 register struct icmp
*icp
;
1324 register u_char type
, code
;
1327 register struct ip
*ip
;
1329 ip
= (struct ip
*) buf
;
1330 hlen
= ip
->ip_hl
<< 2;
1331 if (cc
< hlen
+ ICMP_MINLEN
) {
1333 Printf("packet too short (%d bytes) from %s\n", cc
,
1334 inet_ntoa(from
->sin_addr
));
1338 icp
= (struct icmp
*)(buf
+ hlen
);
1340 icp
= (struct icmp
*)buf
;
1342 type
= icp
->icmp_type
;
1343 code
= icp
->icmp_code
;
1344 /* Path MTU Discovery (RFC1191) */
1345 if (code
!= ICMP_UNREACH_NEEDFRAG
)
1348 #ifdef HAVE_ICMP_NEXTMTU
1349 pmtu
= ntohs(icp
->icmp_nextmtu
);
1351 pmtu
= ntohs(((struct my_pmtu
*)&icp
->icmp_void
)->ipm_nextmtu
);
1354 if (type
== ICMP_ECHOREPLY
1355 && proto
->num
== IPPROTO_ICMP
1356 && (*proto
->check
)((u_char
*)icp
, (u_char
)seq
))
1358 if ((type
== ICMP_TIMXCEED
&& code
== ICMP_TIMXCEED_INTRANS
) ||
1359 type
== ICMP_UNREACH
) {
1362 hip
= &icp
->icmp_ip
;
1363 hiplen
= ((u_char
*)icp
+ cc
) - (u_char
*)hip
;
1364 hlen
= hip
->ip_hl
<< 2;
1365 inner
= (u_char
*)((u_char
*)hip
+ hlen
);
1367 && hip
->ip_p
== proto
->num
1368 && (*proto
->check
)(inner
, (u_char
)seq
))
1369 return (type
== ICMP_TIMXCEED
? -1 : code
+ 1);
1374 u_int32_t
*lp
= (u_int32_t
*)&icp
->icmp_ip
;
1376 Printf("\n%d bytes from %s to ", cc
, inet_ntoa(from
->sin_addr
));
1377 Printf("%s: icmp type %d (%s) code %d\n",
1378 inet_ntoa(ip
->ip_dst
), type
, pr_type(type
), icp
->icmp_code
);
1379 for (i
= 4; i
< cc
; i
+= sizeof(*lp
))
1380 Printf("%2d: x%8.8x\n", i
, *lp
++);
1387 icmp_prep(struct outdata
*outdata
)
1389 struct icmp
*const icmpheader
= (struct icmp
*) outp
;
1391 icmpheader
->icmp_type
= ICMP_ECHO
;
1392 icmpheader
->icmp_id
= htons(ident
);
1393 icmpheader
->icmp_seq
= htons(outdata
->seq
);
1394 icmpheader
->icmp_cksum
= 0;
1395 icmpheader
->icmp_cksum
= in_cksum((u_short
*)icmpheader
, protlen
);
1396 if (icmpheader
->icmp_cksum
== 0)
1397 icmpheader
->icmp_cksum
= 0xffff;
1401 icmp_check(const u_char
*data
, int seq
)
1403 struct icmp
*const icmpheader
= (struct icmp
*) data
;
1405 return (icmpheader
->icmp_id
== htons(ident
)
1406 && icmpheader
->icmp_seq
== htons(seq
));
1410 udp_prep(struct outdata
*outdata
)
1412 struct udphdr
*const outudp
= (struct udphdr
*) outp
;
1414 outudp
->uh_sport
= htons(ident
+ (fixedPort
? outdata
->seq
: 0));
1415 outudp
->uh_dport
= htons(port
+ (fixedPort
? 0 : outdata
->seq
));
1416 outudp
->uh_ulen
= htons((u_short
)protlen
);
1419 u_short sum
= p_cksum(outip
, (u_short
*)outudp
, protlen
);
1420 outudp
->uh_sum
= (sum
) ? sum
: 0xffff;
1427 udp_check(const u_char
*data
, int seq
)
1429 struct udphdr
*const udp
= (struct udphdr
*) data
;
1431 return (ntohs(udp
->uh_sport
) == ident
+ (fixedPort
? seq
: 0) &&
1432 ntohs(udp
->uh_dport
) == port
+ (fixedPort
? 0 : seq
));
1436 tcp_prep(struct outdata
*outdata
)
1438 struct tcphdr
*const tcp
= (struct tcphdr
*) outp
;
1440 tcp
->th_sport
= htons(ident
);
1441 tcp
->th_dport
= htons(port
+ (fixedPort
? 0 : outdata
->seq
));
1442 tcp
->th_seq
= (tcp
->th_sport
<< 16) | (tcp
->th_dport
+
1443 (fixedPort
? outdata
->seq
: 0));
1446 tcp
->th_flags
= TH_SYN
;
1450 u_short sum
= p_cksum(outip
, (u_short
*)tcp
, protlen
);
1451 tcp
->th_sum
= (sum
) ? sum
: 0xffff;
1456 tcp_check(const u_char
*data
, int seq
)
1458 struct tcphdr
*const tcp
= (struct tcphdr
*) data
;
1460 return (ntohs(tcp
->th_sport
) == ident
1461 && ntohs(tcp
->th_dport
) == port
+ (fixedPort
? 0 : seq
))
1462 && tcp
->th_seq
== ((ident
<< 16) | (port
+ seq
));
1466 gre_prep(struct outdata
*outdata
)
1468 struct grehdr
*const gre
= (struct grehdr
*) outp
;
1470 gre
->flags
= htons(0x2001);
1471 gre
->proto
= htons(port
);
1473 gre
->callId
= htons(ident
+ outdata
->seq
);
1477 gre_check(const u_char
*data
, int seq
)
1479 struct grehdr
*const gre
= (struct grehdr
*) data
;
1481 return(ntohs(gre
->proto
) == port
1482 && ntohs(gre
->callId
) == ident
+ seq
);
1486 gen_prep(struct outdata
*outdata
)
1488 u_int16_t
*const ptr
= (u_int16_t
*) outp
;
1490 ptr
[0] = htons(ident
);
1491 ptr
[1] = htons(port
+ outdata
->seq
);
1495 gen_check(const u_char
*data
, int seq
)
1497 u_int16_t
*const ptr
= (u_int16_t
*) data
;
1499 return(ntohs(ptr
[0]) == ident
1500 && ntohs(ptr
[1]) == port
+ seq
);
1504 print(register u_char
*buf
, register int cc
, register struct sockaddr_in
*from
)
1506 register struct ip
*ip
;
1509 ip
= (struct ip
*) buf
;
1510 hlen
= ip
->ip_hl
<< 2;
1514 Printf(" [AS%d]", as_lookup(asn
, &from
->sin_addr
));
1517 Printf(" %s", inet_ntoa(from
->sin_addr
));
1519 Printf(" %s (%s)", inetname(from
->sin_addr
),
1520 inet_ntoa(from
->sin_addr
));
1523 Printf(" %d bytes to %s", cc
, inet_ntoa (ip
->ip_dst
));
1527 * Checksum routine for UDP and TCP headers.
1530 p_cksum(struct ip
*ip
, u_short
*data
, int len
)
1532 static struct ipovly ipo
;
1536 ipo
.ih_pr
= ip
->ip_p
;
1537 ipo
.ih_len
= htons(len
);
1538 ipo
.ih_src
= ip
->ip_src
;
1539 ipo
.ih_dst
= ip
->ip_dst
;
1541 sumh
= in_cksum((u_short
*)&ipo
, sizeof(ipo
)); /* pseudo ip hdr cksum */
1542 sumd
= in_cksum((u_short
*)data
, len
); /* payload data cksum */
1543 sumt
= (sumh
<< 16) | (sumd
);
1545 return ~in_cksum((u_short
*)&sumt
, sizeof(sumt
));
1549 * Checksum routine for Internet Protocol family headers (C Version)
1552 in_cksum(register u_short
*addr
, register int len
)
1554 register int nleft
= len
;
1555 register u_short
*w
= addr
;
1556 register u_short answer
;
1557 register int sum
= 0;
1560 * Our algorithm is simple, using a 32 bit accumulator (sum),
1561 * we add sequential 16 bit words to it, and at the end, fold
1562 * back all the carry bits from the top 16 bits into the lower
1570 /* mop up an odd byte, if necessary */
1572 sum
+= *(u_char
*)w
;
1575 * add back carry outs from top 16 bits to low 16 bits
1577 sum
= (sum
>> 16) + (sum
& 0xffff); /* add hi 16 to low 16 */
1578 sum
+= (sum
>> 16); /* add carry */
1579 answer
= ~sum
; /* truncate to 16 bits */
1584 * Subtract 2 timeval structs: out = out - in.
1585 * Out is assumed to be within about LONG_MAX seconds of in.
1588 tvsub(register struct timeval
*out
, register struct timeval
*in
)
1591 if ((out
->tv_usec
-= in
->tv_usec
) < 0) {
1593 out
->tv_usec
+= 1000000;
1595 out
->tv_sec
-= in
->tv_sec
;
1599 * Construct an Internet address representation.
1600 * If the nflag has been supplied, give
1601 * numeric value, otherwise try for symbolic name.
1604 inetname(struct in_addr in
)
1607 register struct hostent
*hp
;
1608 static int first
= 1;
1609 static char domain
[MAXHOSTNAMELEN
+ 1], line
[MAXHOSTNAMELEN
+ 1];
1611 if (first
&& !nflag
) {
1613 if (gethostname(domain
, sizeof(domain
) - 1) < 0)
1616 cp
= strchr(domain
, '.');
1618 hp
= gethostbyname(domain
);
1620 cp
= strchr(hp
->h_name
, '.');
1626 (void)strncpy(domain
, cp
, sizeof(domain
) - 1);
1627 domain
[sizeof(domain
) - 1] = '\0';
1631 if (!nflag
&& in
.s_addr
!= INADDR_ANY
) {
1632 hp
= gethostbyaddr((char *)&in
, sizeof(in
), AF_INET
);
1634 if ((cp
= strchr(hp
->h_name
, '.')) != NULL
&&
1635 strcmp(cp
+ 1, domain
) == 0)
1637 (void)strncpy(line
, hp
->h_name
, sizeof(line
) - 1);
1638 line
[sizeof(line
) - 1] = '\0';
1642 return (inet_ntoa(in
));
1646 gethostinfo(register char *hostname
)
1649 register struct hostent
*hp
;
1650 register struct hostinfo
*hi
;
1652 register u_int32_t addr
, *ap
;
1654 if (strlen(hostname
) > 64) {
1655 Fprintf(stderr
, "%s: hostname \"%.32s...\" is too long\n",
1659 hi
= calloc(1, sizeof(*hi
));
1661 Fprintf(stderr
, "%s: calloc %s\n", prog
, strerror(errno
));
1664 addr
= inet_addr(hostname
);
1665 if ((int32_t)addr
!= -1) {
1666 hi
->name
= strdup(hostname
);
1668 hi
->addrs
= calloc(1, sizeof(hi
->addrs
[0]));
1669 if (hi
->addrs
== NULL
) {
1670 Fprintf(stderr
, "%s: calloc %s\n",
1671 prog
, strerror(errno
));
1674 hi
->addrs
[0] = addr
;
1678 hp
= gethostbyname(hostname
);
1680 Fprintf(stderr
, "%s: unknown host %s\n", prog
, hostname
);
1683 if (hp
->h_addrtype
!= AF_INET
|| hp
->h_length
!= 4) {
1684 Fprintf(stderr
, "%s: bad host %s\n", prog
, hostname
);
1687 hi
->name
= strdup(hp
->h_name
);
1688 for (n
= 0, p
= hp
->h_addr_list
; *p
!= NULL
; ++n
, ++p
)
1691 hi
->addrs
= calloc(n
, sizeof(hi
->addrs
[0]));
1692 if (hi
->addrs
== NULL
) {
1693 Fprintf(stderr
, "%s: calloc %s\n", prog
, strerror(errno
));
1696 for (ap
= hi
->addrs
, p
= hp
->h_addr_list
; *p
!= NULL
; ++ap
, ++p
)
1697 memcpy(ap
, *p
, sizeof(*ap
));
1702 freehostinfo(register struct hostinfo
*hi
)
1704 if (hi
->name
!= NULL
) {
1708 free((char *)hi
->addrs
);
1713 getaddr(register u_int32_t
*ap
, register char *hostname
)
1715 register struct hostinfo
*hi
;
1717 hi
= gethostinfo(hostname
);
1723 setsin(register struct sockaddr_in
*sin
, register u_int32_t addr
)
1726 memset(sin
, 0, sizeof(*sin
));
1727 #ifdef HAVE_SOCKADDR_SA_LEN
1728 sin
->sin_len
= sizeof(*sin
);
1730 sin
->sin_family
= AF_INET
;
1731 sin
->sin_addr
.s_addr
= addr
;
1734 /* String to value with optional min and max. Handles decimal and hex. */
1736 str2val(register const char *str
, register const char *what
,
1737 register int mi
, register int ma
)
1739 register const char *cp
;
1743 if (str
[0] == '0' && (str
[1] == 'x' || str
[1] == 'X')) {
1745 val
= (int)strtol(cp
, &ep
, 16);
1747 val
= (int)strtol(str
, &ep
, 10);
1749 Fprintf(stderr
, "%s: \"%s\" bad value for %s \n",
1753 if (val
< mi
&& mi
>= 0) {
1755 Fprintf(stderr
, "%s: %s must be >= %d\n",
1758 Fprintf(stderr
, "%s: %s must be > %d\n",
1759 prog
, what
, mi
- 1);
1762 if (val
> ma
&& ma
>= 0) {
1763 Fprintf(stderr
, "%s: %s must be <= %d\n", prog
, what
, ma
);
1770 setproto(char *pname
)
1772 struct outproto
*proto
;
1775 for (i
= 0; protos
[i
].name
!= NULL
; i
++) {
1776 if (strcasecmp(protos
[i
].name
, pname
) == 0) {
1781 if (proto
->name
== NULL
) { /* generic handler */
1782 struct protoent
*pe
;
1785 /* Determine the IP protocol number */
1786 if ((pe
= getprotobyname(pname
)) != NULL
)
1789 pnum
= str2val(optarg
, "proto number", 1, 255);
1796 pkt_compare(const u_char
*a
, int la
, const u_char
*b
, int lb
) {
1800 for (i
= 0; i
< la
; i
++)
1801 Printf("%02x", (unsigned int)a
[i
]);
1803 l
= (la
<= lb
) ? la
: lb
;
1804 for (i
= 0; i
< l
; i
++)
1808 Printf("%02x", (unsigned int)b
[i
]);
1810 Printf("%02x", (unsigned int)b
[i
]);
1818 extern char version
[];
1820 Fprintf(stderr
, "Version %s\n", version
);
1822 "Usage: %s [-adDeFInrSvx] [-A as_server] [-f first_ttl] [-g gateway] [-i iface]\n"
1823 "\t[-M first_ttl] [-m max_ttl] [-p port] [-P proto] [-q nqueries] [-s src_addr]\n"
1824 "\t[-t tos] [-w waittime] [-z pausemsecs] host [packetlen]\n", prog
);