]>
Commit | Line | Data |
---|---|---|
b7080c8e | 1 | /* |
2b484d24 | 2 | * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000 |
b7080c8e A |
3 | * The Regents of the University of California. All rights reserved. |
4 | * | |
b7080c8e | 5 | * Redistribution and use in source and binary forms, with or without |
2b484d24 A |
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 | |
16 | * written permission. | |
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. | |
b7080c8e A |
20 | */ |
21 | ||
22 | #ifndef lint | |
2b484d24 A |
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 | #if 0 | |
27 | static const char rcsid[] = | |
28 | "@(#)$Id: traceroute.c,v 1.2 2004/08/08 00:27:54 lindak Exp $ (LBL)"; | |
29 | #endif | |
30 | static const char rcsid[] = | |
31 | "$FreeBSD: src/contrib/traceroute/traceroute.c,v 1.26 2004/04/17 18:44:23 pb Exp $"; | |
32 | #endif | |
b7080c8e A |
33 | |
34 | /* | |
35 | * traceroute host - trace the route ip packets follow going to "host". | |
36 | * | |
37 | * Attempt to trace the route an ip packet would follow to some | |
38 | * internet host. We find out intermediate hops by launching probe | |
39 | * packets with a small ttl (time to live) then listening for an | |
40 | * icmp "time exceeded" reply from a gateway. We start our probes | |
41 | * with a ttl of one and increase by one until we get an icmp "port | |
42 | * unreachable" (which means we got to "host") or hit a max (which | |
2b484d24 A |
43 | * defaults to net.inet.ip.ttl hops & can be changed with the -m flag). |
44 | * Three probes (change with -q flag) are sent at each ttl setting and | |
45 | * a line is printed showing the ttl, address of the gateway and | |
b7080c8e A |
46 | * round trip time of each probe. If the probe answers come from |
47 | * different gateways, the address of each responding system will | |
48 | * be printed. If there is no response within a 5 sec. timeout | |
49 | * interval (changed with the -w flag), a "*" is printed for that | |
50 | * probe. | |
51 | * | |
52 | * Probe packets are UDP format. We don't want the destination | |
53 | * host to process them so the destination port is set to an | |
54 | * unlikely value (if some clod on the destination is using that | |
55 | * value, it can be changed with the -p flag). | |
56 | * | |
57 | * A sample use might be: | |
58 | * | |
59 | * [yak 71]% traceroute nis.nsf.net. | |
2b484d24 | 60 | * traceroute to nis.nsf.net (35.1.1.48), 64 hops max, 56 byte packet |
b7080c8e A |
61 | * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms |
62 | * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms | |
63 | * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms | |
64 | * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms | |
65 | * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms | |
66 | * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms | |
67 | * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms | |
68 | * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms | |
69 | * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms | |
70 | * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms | |
71 | * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms | |
72 | * | |
73 | * Note that lines 2 & 3 are the same. This is due to a buggy | |
74 | * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards | |
75 | * packets with a zero ttl. | |
76 | * | |
77 | * A more interesting example is: | |
78 | * | |
79 | * [yak 72]% traceroute allspice.lcs.mit.edu. | |
2b484d24 | 80 | * traceroute to allspice.lcs.mit.edu (18.26.0.115), 64 hops max |
b7080c8e A |
81 | * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms |
82 | * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms | |
83 | * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms | |
84 | * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms | |
85 | * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms | |
86 | * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms | |
87 | * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms | |
88 | * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms | |
89 | * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms | |
90 | * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms | |
91 | * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms | |
92 | * 12 * * * | |
93 | * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms | |
94 | * 14 * * * | |
95 | * 15 * * * | |
96 | * 16 * * * | |
97 | * 17 * * * | |
98 | * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms | |
99 | * | |
100 | * (I start to see why I'm having so much trouble with mail to | |
101 | * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away | |
102 | * either don't send ICMP "time exceeded" messages or send them | |
103 | * with a ttl too small to reach us. 14 - 17 are running the | |
104 | * MIT C Gateway code that doesn't send "time exceeded"s. God | |
105 | * only knows what's going on with 12. | |
106 | * | |
107 | * The silent gateway 12 in the above may be the result of a bug in | |
108 | * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3) | |
109 | * sends an unreachable message using whatever ttl remains in the | |
110 | * original datagram. Since, for gateways, the remaining ttl is | |
111 | * zero, the icmp "time exceeded" is guaranteed to not make it back | |
112 | * to us. The behavior of this bug is slightly more interesting | |
113 | * when it appears on the destination system: | |
114 | * | |
115 | * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms | |
116 | * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms | |
117 | * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms | |
118 | * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms | |
119 | * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms | |
120 | * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms | |
121 | * 7 * * * | |
122 | * 8 * * * | |
123 | * 9 * * * | |
124 | * 10 * * * | |
125 | * 11 * * * | |
126 | * 12 * * * | |
127 | * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms ! | |
128 | * | |
129 | * Notice that there are 12 "gateways" (13 is the final | |
130 | * destination) and exactly the last half of them are "missing". | |
131 | * What's really happening is that rip (a Sun-3 running Sun OS3.5) | |
132 | * is using the ttl from our arriving datagram as the ttl in its | |
133 | * icmp reply. So, the reply will time out on the return path | |
134 | * (with no notice sent to anyone since icmp's aren't sent for | |
135 | * icmp's) until we probe with a ttl that's at least twice the path | |
136 | * length. I.e., rip is really only 7 hops away. A reply that | |
137 | * returns with a ttl of 1 is a clue this problem exists. | |
138 | * Traceroute prints a "!" after the time if the ttl is <= 1. | |
139 | * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or | |
140 | * non-standard (HPUX) software, expect to see this problem | |
141 | * frequently and/or take care picking the target host of your | |
142 | * probes. | |
143 | * | |
144 | * Other possible annotations after the time are !H, !N, !P (got a host, | |
145 | * network or protocol unreachable, respectively), !S or !F (source | |
146 | * route failed or fragmentation needed -- neither of these should | |
147 | * ever occur and the associated gateway is busted if you see one). If | |
148 | * almost all the probes result in some kind of unreachable, traceroute | |
149 | * will give up and exit. | |
150 | * | |
151 | * Notes | |
152 | * ----- | |
153 | * This program must be run by root or be setuid. (I suggest that | |
154 | * you *don't* make it setuid -- casual use could result in a lot | |
155 | * of unnecessary traffic on our poor, congested nets.) | |
156 | * | |
157 | * This program requires a kernel mod that does not appear in any | |
158 | * system available from Berkeley: A raw ip socket using proto | |
159 | * IPPROTO_RAW must interpret the data sent as an ip datagram (as | |
160 | * opposed to data to be wrapped in a ip datagram). See the README | |
161 | * file that came with the source to this program for a description | |
162 | * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may | |
163 | * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE | |
164 | * MODIFIED TO RUN THIS PROGRAM. | |
165 | * | |
166 | * The udp port usage may appear bizarre (well, ok, it is bizarre). | |
167 | * The problem is that an icmp message only contains 8 bytes of | |
168 | * data from the original datagram. 8 bytes is the size of a udp | |
169 | * header so, if we want to associate replies with the original | |
170 | * datagram, the necessary information must be encoded into the | |
171 | * udp header (the ip id could be used but there's no way to | |
172 | * interlock with the kernel's assignment of ip id's and, anyway, | |
173 | * it would have taken a lot more kernel hacking to allow this | |
174 | * code to set the ip id). So, to allow two or more users to | |
175 | * use traceroute simultaneously, we use this task's pid as the | |
176 | * source port (the high bit is set to move the port number out | |
177 | * of the "likely" range). To keep track of which probe is being | |
178 | * replied to (so times and/or hop counts don't get confused by a | |
179 | * reply that was delayed in transit), we increment the destination | |
180 | * port number before each probe. | |
181 | * | |
182 | * Don't use this as a coding example. I was trying to find a | |
183 | * routing problem and this code sort-of popped out after 48 hours | |
184 | * without sleep. I was amazed it ever compiled, much less ran. | |
185 | * | |
186 | * I stole the idea for this program from Steve Deering. Since | |
187 | * the first release, I've learned that had I attended the right | |
188 | * IETF working group meetings, I also could have stolen it from Guy | |
189 | * Almes or Matt Mathis. I don't know (or care) who came up with | |
190 | * the idea first. I envy the originators' perspicacity and I'm | |
191 | * glad they didn't keep the idea a secret. | |
192 | * | |
193 | * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or | |
194 | * enhancements to the original distribution. | |
195 | * | |
196 | * I've hacked up a round-trip-route version of this that works by | |
197 | * sending a loose-source-routed udp datagram through the destination | |
198 | * back to yourself. Unfortunately, SO many gateways botch source | |
199 | * routing, the thing is almost worthless. Maybe one day... | |
200 | * | |
2b484d24 | 201 | * -- Van Jacobson (van@ee.lbl.gov) |
b7080c8e A |
202 | * Tue Dec 20 03:50:13 PST 1988 |
203 | */ | |
204 | ||
205 | #include <sys/param.h> | |
b7080c8e A |
206 | #include <sys/file.h> |
207 | #include <sys/ioctl.h> | |
2b484d24 A |
208 | #ifdef HAVE_SYS_SELECT_H |
209 | #include <sys/select.h> | |
210 | #endif | |
211 | #include <sys/socket.h> | |
212 | #ifdef HAVE_SYS_SYSCTL_H | |
213 | #include <sys/sysctl.h> | |
214 | #endif | |
215 | #include <sys/time.h> | |
b7080c8e A |
216 | |
217 | #include <netinet/in_systm.h> | |
218 | #include <netinet/in.h> | |
219 | #include <netinet/ip.h> | |
2b484d24 | 220 | #include <netinet/ip_var.h> |
b7080c8e A |
221 | #include <netinet/ip_icmp.h> |
222 | #include <netinet/udp.h> | |
2b484d24 A |
223 | #include <netinet/udp_var.h> |
224 | #include <netinet/tcp.h> | |
225 | #include <netinet/tcpip.h> | |
b7080c8e A |
226 | |
227 | #include <arpa/inet.h> | |
228 | ||
2b484d24 A |
229 | #ifdef IPSEC |
230 | #include <net/route.h> | |
231 | #include <netinet6/ipsec.h> /* XXX */ | |
232 | #endif /* IPSEC */ | |
233 | ||
234 | #include <ctype.h> | |
235 | #include <err.h> | |
236 | #include <errno.h> | |
237 | #include <fcntl.h> | |
238 | #ifdef HAVE_MALLOC_H | |
239 | #include <malloc.h> | |
240 | #endif | |
241 | #include <memory.h> | |
b7080c8e A |
242 | #include <netdb.h> |
243 | #include <stdio.h> | |
b7080c8e A |
244 | #include <stdlib.h> |
245 | #include <string.h> | |
246 | #include <unistd.h> | |
247 | ||
2b484d24 A |
248 | #include "gnuc.h" |
249 | #ifdef HAVE_OS_PROTO_H | |
250 | #include "os-proto.h" | |
251 | #endif | |
252 | ||
253 | /* rfc1716 */ | |
254 | #ifndef ICMP_UNREACH_FILTER_PROHIB | |
255 | #define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohibited filter */ | |
b7080c8e | 256 | #endif |
2b484d24 A |
257 | #ifndef ICMP_UNREACH_HOST_PRECEDENCE |
258 | #define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host precedence violation */ | |
259 | #endif | |
260 | #ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF | |
261 | #define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* precedence cutoff */ | |
262 | #endif | |
263 | ||
264 | #include "findsaddr.h" | |
265 | #include "ifaddrlist.h" | |
266 | #include "traceroute.h" | |
b7080c8e | 267 | |
2b484d24 A |
268 | /* Maximum number of gateways (include room for one noop) */ |
269 | #define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t))) | |
270 | ||
271 | #ifndef MAXHOSTNAMELEN | |
272 | #define MAXHOSTNAMELEN 64 | |
b7080c8e A |
273 | #endif |
274 | ||
275 | #define Fprintf (void)fprintf | |
b7080c8e A |
276 | #define Printf (void)printf |
277 | ||
2b484d24 A |
278 | /* What a GRE packet header looks like */ |
279 | struct grehdr { | |
280 | u_int16_t flags; | |
281 | u_int16_t proto; | |
282 | u_int16_t length; /* PPTP version of these fields */ | |
283 | u_int16_t callId; | |
284 | }; | |
285 | #ifndef IPPROTO_GRE | |
286 | #define IPPROTO_GRE 47 | |
287 | #endif | |
288 | ||
289 | /* For GRE, we prepare what looks like a PPTP packet */ | |
290 | #define GRE_PPTP_PROTO 0x880b | |
291 | ||
292 | /* Host name and address list */ | |
293 | struct hostinfo { | |
294 | char *name; | |
295 | int n; | |
296 | u_int32_t *addrs; | |
297 | }; | |
298 | ||
299 | /* Data section of the probe packet */ | |
300 | struct outdata { | |
b7080c8e A |
301 | u_char seq; /* sequence number of this packet */ |
302 | u_char ttl; /* ttl packet left with */ | |
303 | struct timeval tv; /* time packet left */ | |
304 | }; | |
305 | ||
2b484d24 A |
306 | #ifndef HAVE_ICMP_NEXTMTU |
307 | /* Path MTU Discovery (RFC1191) */ | |
308 | struct my_pmtu { | |
309 | u_short ipm_void; | |
310 | u_short ipm_nextmtu; | |
311 | }; | |
312 | #endif | |
313 | ||
b7080c8e | 314 | u_char packet[512]; /* last inbound (icmp) packet */ |
b7080c8e | 315 | |
2b484d24 A |
316 | struct ip *outip; /* last output ip packet */ |
317 | u_char *outp; /* last output inner protocol packet */ | |
318 | ||
319 | /* loose source route gateway list (including room for final destination) */ | |
320 | u_int32_t gwlist[NGATEWAYS + 1]; | |
b7080c8e A |
321 | |
322 | int s; /* receive (icmp) socket file descriptor */ | |
323 | int sndsock; /* send (udp) socket file descriptor */ | |
b7080c8e A |
324 | |
325 | struct sockaddr whereto; /* Who to try to reach */ | |
2b484d24 A |
326 | struct sockaddr wherefrom; /* Who we are */ |
327 | int packlen; /* total length of packet */ | |
328 | int protlen; /* length of protocol part of packet */ | |
329 | int minpacket; /* min ip packet size */ | |
330 | int maxpacket = 32 * 1024; /* max ip packet size */ | |
331 | int pmtu; /* Path MTU Discovery (RFC1191) */ | |
332 | u_int pausemsecs; | |
333 | ||
334 | char *prog; | |
335 | char *source; | |
b7080c8e | 336 | char *hostname; |
2b484d24 A |
337 | char *device; |
338 | static const char devnull[] = "/dev/null"; | |
b7080c8e A |
339 | |
340 | int nprobes = 3; | |
2b484d24 A |
341 | int max_ttl; |
342 | int first_ttl = 1; | |
b7080c8e | 343 | u_short ident; |
2b484d24 A |
344 | u_short port; /* protocol specific base "port" */ |
345 | ||
b7080c8e A |
346 | int options; /* socket options */ |
347 | int verbose; | |
348 | int waittime = 5; /* time to wait for response (in seconds) */ | |
349 | int nflag; /* print addresses numerically */ | |
2b484d24 A |
350 | #ifdef CANT_HACK_IPCKSUM |
351 | int doipcksum = 0; /* don't calculate ip checksums by default */ | |
352 | #else | |
353 | int doipcksum = 1; /* calculate ip checksums by default */ | |
354 | #endif | |
355 | int optlen; /* length of ip options */ | |
356 | ||
357 | extern int optind; | |
358 | extern int opterr; | |
359 | extern char *optarg; | |
360 | ||
361 | /* Forwards */ | |
362 | double deltaT(struct timeval *, struct timeval *); | |
363 | void freehostinfo(struct hostinfo *); | |
364 | void getaddr(u_int32_t *, char *); | |
365 | struct hostinfo *gethostinfo(char *); | |
366 | u_short in_cksum(u_short *, int); | |
367 | char *inetname(struct in_addr); | |
368 | int main(int, char **); | |
369 | u_short p_cksum(struct ip *, u_short *, int); | |
370 | int packet_ok(u_char *, int, struct sockaddr_in *, int); | |
371 | char *pr_type(u_char); | |
372 | void print(u_char *, int, struct sockaddr_in *); | |
373 | #ifdef IPSEC | |
374 | int setpolicy __P((int so, char *policy)); | |
375 | #endif | |
376 | void send_probe(int, int); | |
377 | struct outproto *setproto(char *); | |
378 | int str2val(const char *, const char *, int, int); | |
379 | void tvsub(struct timeval *, struct timeval *); | |
380 | void usage(void); | |
381 | int wait_for_reply(int, struct sockaddr_in *, const struct timeval *); | |
382 | #ifndef HAVE_USLEEP | |
383 | int usleep(u_int); | |
384 | #endif | |
385 | ||
386 | void udp_prep(struct outdata *); | |
387 | int udp_check(const u_char *, int); | |
388 | void tcp_prep(struct outdata *); | |
389 | int tcp_check(const u_char *, int); | |
390 | void gre_prep(struct outdata *); | |
391 | int gre_check(const u_char *, int); | |
392 | void gen_prep(struct outdata *); | |
393 | int gen_check(const u_char *, int); | |
394 | void icmp_prep(struct outdata *); | |
395 | int icmp_check(const u_char *, int); | |
396 | ||
397 | /* Descriptor structure for each outgoing protocol we support */ | |
398 | struct outproto { | |
399 | char *name; /* name of protocol */ | |
400 | u_char num; /* IP protocol number */ | |
401 | u_short hdrlen; /* max size of protocol header */ | |
402 | u_short port; /* default base protocol-specific "port" */ | |
403 | void (*prepare)(struct outdata *); | |
404 | /* finish preparing an outgoing packet */ | |
405 | int (*check)(const u_char *, int); | |
406 | /* check an incoming packet */ | |
407 | }; | |
408 | ||
409 | /* List of supported protocols. The first one is the default. The last | |
410 | one is the handler for generic protocols not explicitly listed. */ | |
411 | struct outproto protos[] = { | |
412 | { | |
413 | "udp", | |
414 | IPPROTO_UDP, | |
415 | sizeof(struct udphdr), | |
416 | 32768 + 666, | |
417 | udp_prep, | |
418 | udp_check | |
419 | }, | |
420 | { | |
421 | "tcp", | |
422 | IPPROTO_TCP, | |
423 | sizeof(struct tcphdr), | |
424 | 32768 + 666, | |
425 | tcp_prep, | |
426 | tcp_check | |
427 | }, | |
428 | { | |
429 | "gre", | |
430 | IPPROTO_GRE, | |
431 | sizeof(struct grehdr), | |
432 | GRE_PPTP_PROTO, | |
433 | gre_prep, | |
434 | gre_check | |
435 | }, | |
436 | { | |
437 | "icmp", | |
438 | IPPROTO_ICMP, | |
439 | sizeof(struct icmp), | |
440 | 0, | |
441 | icmp_prep, | |
442 | icmp_check | |
443 | }, | |
444 | { | |
445 | NULL, | |
446 | 0, | |
447 | 2 * sizeof(u_short), | |
448 | 0, | |
449 | gen_prep, | |
450 | gen_check | |
451 | }, | |
452 | }; | |
453 | struct outproto *proto = &protos[0]; | |
b7080c8e A |
454 | |
455 | int | |
2b484d24 | 456 | main(int argc, char **argv) |
b7080c8e | 457 | { |
2b484d24 A |
458 | register int op, code, n; |
459 | register char *cp; | |
460 | register const char *err; | |
461 | register u_int32_t *ap; | |
462 | register struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom; | |
463 | register struct sockaddr_in *to = (struct sockaddr_in *)&whereto; | |
464 | register struct hostinfo *hi; | |
465 | int on = 1; | |
466 | register struct protoent *pe; | |
467 | register int ttl, probe, i; | |
468 | register int seq = 0; | |
469 | int tos = 0, settos = 0; | |
470 | register int lsrr = 0; | |
471 | register u_short off = 0; | |
472 | struct ifaddrlist *al; | |
473 | char errbuf[132]; | |
474 | int requestPort = -1; | |
475 | int sump = 0; | |
476 | int sockerrno; | |
477 | ||
478 | /* Insure the socket fds won't be 0, 1 or 2 */ | |
479 | if (open(devnull, O_RDONLY) < 0 || | |
480 | open(devnull, O_RDONLY) < 0 || | |
481 | open(devnull, O_RDONLY) < 0) { | |
482 | Fprintf(stderr, "%s: open \"%s\": %s\n", | |
483 | prog, devnull, strerror(errno)); | |
484 | exit(1); | |
485 | } | |
486 | /* | |
487 | * Do the setuid-required stuff first, then lose priveleges ASAP. | |
488 | * Do error checking for these two calls where they appeared in | |
489 | * the original code. | |
490 | */ | |
491 | cp = "icmp"; | |
492 | pe = getprotobyname(cp); | |
493 | if (pe) { | |
494 | if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) | |
495 | sockerrno = errno; | |
496 | else if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) | |
497 | sockerrno = errno; | |
498 | } | |
499 | ||
500 | setuid(getuid()); | |
501 | ||
502 | #ifdef IPCTL_DEFTTL | |
503 | { | |
504 | int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL }; | |
505 | size_t sz = sizeof(max_ttl); | |
506 | ||
507 | if (sysctl(mib, 4, &max_ttl, &sz, NULL, 0) == -1) { | |
508 | perror("sysctl(net.inet.ip.ttl)"); | |
509 | exit(1); | |
510 | } | |
511 | } | |
512 | #else | |
513 | max_ttl = 30; | |
514 | #endif | |
515 | ||
516 | if (argv[0] == NULL) | |
517 | prog = "traceroute"; | |
518 | else if ((cp = strrchr(argv[0], '/')) != NULL) | |
519 | prog = cp + 1; | |
520 | else | |
521 | prog = argv[0]; | |
522 | ||
523 | opterr = 0; | |
524 | while ((op = getopt(argc, argv, "dFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF) | |
525 | switch (op) { | |
526 | ||
b7080c8e A |
527 | case 'd': |
528 | options |= SO_DEBUG; | |
529 | break; | |
2b484d24 A |
530 | |
531 | case 'f': | |
532 | case 'M': /* FreeBSD compat. */ | |
533 | first_ttl = str2val(optarg, "first ttl", 1, 255); | |
534 | break; | |
535 | ||
536 | case 'F': | |
537 | off = IP_DF; | |
538 | break; | |
539 | ||
540 | case 'g': | |
541 | if (lsrr >= NGATEWAYS) { | |
b7080c8e | 542 | Fprintf(stderr, |
2b484d24 A |
543 | "%s: No more than %d gateways\n", |
544 | prog, NGATEWAYS); | |
b7080c8e A |
545 | exit(1); |
546 | } | |
2b484d24 A |
547 | getaddr(gwlist + lsrr, optarg); |
548 | ++lsrr; | |
549 | break; | |
550 | ||
551 | case 'i': | |
552 | device = optarg; | |
553 | break; | |
554 | ||
555 | case 'I': | |
556 | proto = setproto("icmp"); | |
557 | break; | |
558 | ||
559 | case 'm': | |
560 | max_ttl = str2val(optarg, "max ttl", 1, 255); | |
b7080c8e | 561 | break; |
2b484d24 | 562 | |
b7080c8e | 563 | case 'n': |
2b484d24 | 564 | ++nflag; |
b7080c8e | 565 | break; |
2b484d24 A |
566 | |
567 | case 'P': | |
568 | proto = setproto(optarg); | |
569 | break; | |
570 | ||
b7080c8e | 571 | case 'p': |
2b484d24 A |
572 | requestPort = (u_short)str2val(optarg, "port", |
573 | 1, (1 << 16) - 1); | |
b7080c8e | 574 | break; |
2b484d24 | 575 | |
b7080c8e | 576 | case 'q': |
2b484d24 | 577 | nprobes = str2val(optarg, "nprobes", 1, -1); |
b7080c8e | 578 | break; |
2b484d24 | 579 | |
b7080c8e A |
580 | case 'r': |
581 | options |= SO_DONTROUTE; | |
582 | break; | |
2b484d24 | 583 | |
b7080c8e A |
584 | case 's': |
585 | /* | |
586 | * set the ip source address of the outbound | |
587 | * probe (e.g., on a multi-homed host). | |
588 | */ | |
589 | source = optarg; | |
590 | break; | |
2b484d24 A |
591 | |
592 | case 'S': | |
593 | sump = 1; | |
594 | break; | |
595 | ||
b7080c8e | 596 | case 't': |
2b484d24 A |
597 | tos = str2val(optarg, "tos", 0, 255); |
598 | ++settos; | |
b7080c8e | 599 | break; |
2b484d24 | 600 | |
b7080c8e | 601 | case 'v': |
2b484d24 A |
602 | ++verbose; |
603 | break; | |
604 | ||
605 | case 'x': | |
606 | doipcksum = (doipcksum == 0); | |
b7080c8e | 607 | break; |
2b484d24 | 608 | |
b7080c8e | 609 | case 'w': |
2b484d24 A |
610 | waittime = str2val(optarg, "wait time", |
611 | 2, 24 * 60 * 60); | |
b7080c8e | 612 | break; |
2b484d24 A |
613 | |
614 | case 'z': | |
615 | pausemsecs = str2val(optarg, "pause msecs", | |
616 | 0, 60 * 60 * 1000); | |
617 | break; | |
618 | ||
b7080c8e A |
619 | default: |
620 | usage(); | |
621 | } | |
b7080c8e | 622 | |
2b484d24 A |
623 | /* Set requested port, if any, else default for this protocol */ |
624 | port = (requestPort != -1) ? requestPort : proto->port; | |
b7080c8e | 625 | |
2b484d24 | 626 | if (first_ttl > max_ttl) { |
b7080c8e | 627 | Fprintf(stderr, |
2b484d24 A |
628 | "%s: first ttl (%d) may not be greater than max ttl (%d)\n", |
629 | prog, first_ttl, max_ttl); | |
b7080c8e A |
630 | exit(1); |
631 | } | |
2b484d24 A |
632 | |
633 | if (!doipcksum) | |
634 | Fprintf(stderr, "%s: Warning: ip checksums disabled\n", prog); | |
635 | ||
636 | if (lsrr > 0) | |
637 | optlen = (lsrr + 1) * sizeof(gwlist[0]); | |
638 | minpacket = sizeof(*outip) + proto->hdrlen + sizeof(struct outdata) + optlen; | |
639 | packlen = minpacket; /* minimum sized packet */ | |
640 | ||
641 | /* Process destination and optional packet size */ | |
642 | switch (argc - optind) { | |
643 | ||
644 | case 2: | |
645 | packlen = str2val(argv[optind + 1], | |
646 | "packet length", minpacket, maxpacket); | |
647 | /* Fall through */ | |
648 | ||
649 | case 1: | |
650 | hostname = argv[optind]; | |
651 | hi = gethostinfo(hostname); | |
652 | setsin(to, hi->addrs[0]); | |
653 | if (hi->n > 1) | |
654 | Fprintf(stderr, | |
655 | "%s: Warning: %s has multiple addresses; using %s\n", | |
656 | prog, hostname, inet_ntoa(to->sin_addr)); | |
657 | hostname = hi->name; | |
658 | hi->name = NULL; | |
659 | freehostinfo(hi); | |
660 | break; | |
661 | ||
662 | default: | |
663 | usage(); | |
664 | } | |
665 | ||
666 | #ifdef HAVE_SETLINEBUF | |
667 | setlinebuf (stdout); | |
668 | #else | |
669 | setvbuf(stdout, NULL, _IOLBF, 0); | |
670 | #endif | |
671 | ||
672 | protlen = packlen - sizeof(*outip) - optlen; | |
673 | ||
674 | outip = (struct ip *)malloc((unsigned)packlen); | |
675 | if (outip == NULL) { | |
676 | Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno)); | |
b7080c8e A |
677 | exit(1); |
678 | } | |
2b484d24 A |
679 | memset((char *)outip, 0, packlen); |
680 | ||
681 | outip->ip_v = IPVERSION; | |
682 | if (settos) | |
683 | outip->ip_tos = tos; | |
684 | #ifdef BYTESWAP_IP_HDR | |
685 | outip->ip_len = htons(packlen); | |
686 | outip->ip_off = htons(off); | |
687 | #else | |
688 | outip->ip_len = packlen; | |
689 | outip->ip_off = off; | |
690 | #endif | |
691 | outip->ip_p = proto->num; | |
692 | outp = (u_char *)(outip + 1); | |
693 | #ifdef HAVE_RAW_OPTIONS | |
694 | if (lsrr > 0) { | |
695 | register u_char *optlist; | |
696 | ||
697 | optlist = outp; | |
698 | outp += optlen; | |
699 | ||
700 | /* final hop */ | |
701 | gwlist[lsrr] = to->sin_addr.s_addr; | |
702 | ||
703 | outip->ip_dst.s_addr = gwlist[0]; | |
704 | ||
705 | /* force 4 byte alignment */ | |
706 | optlist[0] = IPOPT_NOP; | |
707 | /* loose source route option */ | |
708 | optlist[1] = IPOPT_LSRR; | |
709 | i = lsrr * sizeof(gwlist[0]); | |
710 | optlist[2] = i + 3; | |
711 | /* Pointer to LSRR addresses */ | |
712 | optlist[3] = IPOPT_MINOFF; | |
713 | memcpy(optlist + 4, gwlist + 1, i); | |
714 | } else | |
715 | #endif | |
716 | outip->ip_dst = to->sin_addr; | |
b7080c8e | 717 | |
2b484d24 | 718 | outip->ip_hl = (outp - (u_char *)outip) >> 2; |
b7080c8e A |
719 | ident = (getpid() & 0xffff) | 0x8000; |
720 | ||
2b484d24 A |
721 | if (pe == NULL) { |
722 | Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp); | |
723 | exit(1); | |
b7080c8e | 724 | } |
2b484d24 A |
725 | if (s < 0) { |
726 | errno = sockerrno; | |
727 | Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno)); | |
728 | exit(1); | |
b7080c8e A |
729 | } |
730 | if (options & SO_DEBUG) | |
2b484d24 A |
731 | (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on, |
732 | sizeof(on)); | |
b7080c8e | 733 | if (options & SO_DONTROUTE) |
2b484d24 A |
734 | (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on, |
735 | sizeof(on)); | |
b7080c8e | 736 | |
2b484d24 A |
737 | #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) |
738 | if (setpolicy(s, "in bypass") < 0) | |
739 | errx(1, "%s", ipsec_strerror()); | |
740 | ||
741 | if (setpolicy(s, "out bypass") < 0) | |
742 | errx(1, "%s", ipsec_strerror()); | |
743 | #endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */ | |
744 | ||
745 | if (sndsock < 0) { | |
746 | errno = sockerrno; | |
747 | Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno)); | |
748 | exit(1); | |
b7080c8e | 749 | } |
2b484d24 A |
750 | |
751 | #if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS) | |
752 | if (lsrr > 0) { | |
753 | u_char optlist[MAX_IPOPTLEN]; | |
754 | ||
755 | cp = "ip"; | |
756 | if ((pe = getprotobyname(cp)) == NULL) { | |
757 | Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp); | |
758 | exit(1); | |
759 | } | |
760 | ||
761 | /* final hop */ | |
762 | gwlist[lsrr] = to->sin_addr.s_addr; | |
763 | ++lsrr; | |
764 | ||
765 | /* force 4 byte alignment */ | |
766 | optlist[0] = IPOPT_NOP; | |
767 | /* loose source route option */ | |
768 | optlist[1] = IPOPT_LSRR; | |
769 | i = lsrr * sizeof(gwlist[0]); | |
770 | optlist[2] = i + 3; | |
771 | /* Pointer to LSRR addresses */ | |
772 | optlist[3] = IPOPT_MINOFF; | |
773 | memcpy(optlist + 4, gwlist, i); | |
774 | ||
775 | if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS, | |
776 | (char *)optlist, i + sizeof(gwlist[0]))) < 0) { | |
777 | Fprintf(stderr, "%s: IP_OPTIONS: %s\n", | |
778 | prog, strerror(errno)); | |
779 | exit(1); | |
780 | } | |
781 | } | |
782 | #endif | |
783 | ||
b7080c8e | 784 | #ifdef SO_SNDBUF |
2b484d24 A |
785 | if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen, |
786 | sizeof(packlen)) < 0) { | |
787 | Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno)); | |
788 | exit(1); | |
b7080c8e | 789 | } |
2b484d24 | 790 | #endif |
b7080c8e A |
791 | #ifdef IP_HDRINCL |
792 | if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on, | |
2b484d24 A |
793 | sizeof(on)) < 0) { |
794 | Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog, strerror(errno)); | |
795 | exit(1); | |
b7080c8e | 796 | } |
2b484d24 A |
797 | #else |
798 | #ifdef IP_TOS | |
799 | if (settos && setsockopt(sndsock, IPPROTO_IP, IP_TOS, | |
800 | (char *)&tos, sizeof(tos)) < 0) { | |
801 | Fprintf(stderr, "%s: setsockopt tos %d: %s\n", | |
802 | prog, tos, strerror(errno)); | |
803 | exit(1); | |
804 | } | |
805 | #endif | |
806 | #endif | |
b7080c8e | 807 | if (options & SO_DEBUG) |
2b484d24 A |
808 | (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on, |
809 | sizeof(on)); | |
b7080c8e | 810 | if (options & SO_DONTROUTE) |
2b484d24 A |
811 | (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on, |
812 | sizeof(on)); | |
813 | ||
814 | /* Get the interface address list */ | |
815 | n = ifaddrlist(&al, errbuf); | |
816 | if (n < 0) { | |
817 | Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf); | |
818 | exit(1); | |
819 | } | |
820 | if (n == 0) { | |
821 | Fprintf(stderr, | |
822 | "%s: Can't find any network interfaces\n", prog); | |
823 | exit(1); | |
824 | } | |
825 | ||
826 | /* Look for a specific device */ | |
827 | if (device != NULL) { | |
828 | for (i = n; i > 0; --i, ++al) | |
829 | if (strcmp(device, al->device) == 0) | |
830 | break; | |
831 | if (i <= 0) { | |
832 | Fprintf(stderr, "%s: Can't find interface %.32s\n", | |
833 | prog, device); | |
b7080c8e A |
834 | exit(1); |
835 | } | |
2b484d24 A |
836 | } |
837 | ||
838 | /* Determine our source address */ | |
839 | if (source == NULL) { | |
840 | /* | |
841 | * If a device was specified, use the interface address. | |
842 | * Otherwise, try to determine our source address. | |
843 | */ | |
844 | if (device != NULL) | |
845 | setsin(from, al->addr); | |
846 | else if ((err = findsaddr(to, from)) != NULL) { | |
847 | Fprintf(stderr, "%s: findsaddr: %s\n", | |
848 | prog, err); | |
849 | exit(1); | |
850 | } | |
851 | } else { | |
852 | hi = gethostinfo(source); | |
853 | source = hi->name; | |
854 | hi->name = NULL; | |
855 | /* | |
856 | * If the device was specified make sure it | |
857 | * corresponds to the source address specified. | |
858 | * Otherwise, use the first address (and warn if | |
859 | * there are more than one). | |
860 | */ | |
861 | if (device != NULL) { | |
862 | for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap) | |
863 | if (*ap == al->addr) | |
864 | break; | |
865 | if (i <= 0) { | |
866 | Fprintf(stderr, | |
867 | "%s: %s is not on interface %.32s\n", | |
868 | prog, source, device); | |
869 | exit(1); | |
870 | } | |
871 | setsin(from, *ap); | |
872 | } else { | |
873 | setsin(from, hi->addrs[0]); | |
874 | if (hi->n > 1) | |
875 | Fprintf(stderr, | |
876 | "%s: Warning: %s has multiple addresses; using %s\n", | |
877 | prog, source, inet_ntoa(from->sin_addr)); | |
b7080c8e | 878 | } |
2b484d24 | 879 | freehostinfo(hi); |
b7080c8e A |
880 | } |
881 | ||
2b484d24 A |
882 | outip->ip_src = from->sin_addr; |
883 | ||
884 | /* Check the source address (-s), if any, is valid */ | |
885 | if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) { | |
886 | Fprintf(stderr, "%s: bind: %s\n", | |
887 | prog, strerror(errno)); | |
888 | exit (1); | |
889 | } | |
890 | ||
891 | #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) | |
892 | if (setpolicy(sndsock, "in bypass") < 0) | |
893 | errx(1, "%s", ipsec_strerror()); | |
894 | ||
895 | if (setpolicy(sndsock, "out bypass") < 0) | |
896 | errx(1, "%s", ipsec_strerror()); | |
897 | #endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */ | |
898 | ||
899 | Fprintf(stderr, "%s to %s (%s)", | |
900 | prog, hostname, inet_ntoa(to->sin_addr)); | |
b7080c8e A |
901 | if (source) |
902 | Fprintf(stderr, " from %s", source); | |
2b484d24 A |
903 | Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen); |
904 | (void)fflush(stderr); | |
b7080c8e | 905 | |
2b484d24 A |
906 | for (ttl = first_ttl; ttl <= max_ttl; ++ttl) { |
907 | u_int32_t lastaddr = 0; | |
908 | int gotlastaddr = 0; | |
b7080c8e A |
909 | int got_there = 0; |
910 | int unreachable = 0; | |
2b484d24 A |
911 | int sentfirst = 0; |
912 | int loss; | |
b7080c8e A |
913 | |
914 | Printf("%2d ", ttl); | |
2b484d24 A |
915 | for (probe = 0, loss = 0; probe < nprobes; ++probe) { |
916 | register int cc; | |
b7080c8e A |
917 | struct timeval t1, t2; |
918 | struct timezone tz; | |
2b484d24 A |
919 | register struct ip *ip; |
920 | struct outdata outdata; | |
921 | ||
922 | if (sentfirst && pausemsecs > 0) | |
923 | usleep(pausemsecs * 1000); | |
924 | /* Prepare outgoing data */ | |
925 | outdata.seq = ++seq; | |
926 | outdata.ttl = ttl; | |
927 | ||
928 | /* Avoid alignment problems by copying bytewise: */ | |
929 | (void)gettimeofday(&t1, &tz); | |
930 | memcpy(&outdata.tv, &t1, sizeof(outdata.tv)); | |
931 | ||
932 | /* Finalize and send packet */ | |
933 | (*proto->prepare)(&outdata); | |
934 | send_probe(seq, ttl); | |
935 | ++sentfirst; | |
936 | ||
937 | /* Wait for a reply */ | |
938 | while ((cc = wait_for_reply(s, from, &t1)) != 0) { | |
939 | double T; | |
940 | int precis; | |
941 | ||
942 | (void)gettimeofday(&t2, &tz); | |
943 | i = packet_ok(packet, cc, from, seq); | |
944 | /* Skip short packet */ | |
945 | if (i == 0) | |
946 | continue; | |
947 | if (!gotlastaddr || | |
948 | from->sin_addr.s_addr != lastaddr) { | |
949 | print(packet, cc, from); | |
950 | lastaddr = from->sin_addr.s_addr; | |
951 | ++gotlastaddr; | |
952 | } | |
953 | T = deltaT(&t1, &t2); | |
954 | #ifdef SANE_PRECISION | |
955 | if (T >= 1000.0) | |
956 | precis = 0; | |
957 | else if (T >= 100.0) | |
958 | precis = 1; | |
959 | else if (T >= 10.0) | |
960 | precis = 2; | |
961 | else | |
962 | #endif | |
963 | precis = 3; | |
964 | Printf(" %.*f ms", precis, T); | |
965 | if (i == -2) { | |
b7080c8e | 966 | #ifndef ARCHAIC |
2b484d24 A |
967 | ip = (struct ip *)packet; |
968 | if (ip->ip_ttl <= 1) | |
969 | Printf(" !"); | |
970 | #endif | |
971 | ++got_there; | |
972 | break; | |
973 | } | |
974 | /* time exceeded in transit */ | |
975 | if (i == -1) | |
976 | break; | |
977 | code = i - 1; | |
978 | switch (code) { | |
979 | ||
980 | case ICMP_UNREACH_PORT: | |
981 | #ifndef ARCHAIC | |
982 | ip = (struct ip *)packet; | |
983 | if (ip->ip_ttl <= 1) | |
984 | Printf(" !"); | |
985 | #endif | |
986 | ++got_there; | |
987 | break; | |
988 | ||
989 | case ICMP_UNREACH_NET: | |
990 | ++unreachable; | |
991 | Printf(" !N"); | |
992 | break; | |
993 | ||
994 | case ICMP_UNREACH_HOST: | |
995 | ++unreachable; | |
996 | Printf(" !H"); | |
997 | break; | |
998 | ||
999 | case ICMP_UNREACH_PROTOCOL: | |
1000 | ++got_there; | |
1001 | Printf(" !P"); | |
1002 | break; | |
1003 | ||
1004 | case ICMP_UNREACH_NEEDFRAG: | |
1005 | ++unreachable; | |
1006 | Printf(" !F-%d", pmtu); | |
1007 | break; | |
1008 | ||
1009 | case ICMP_UNREACH_SRCFAIL: | |
1010 | ++unreachable; | |
1011 | Printf(" !S"); | |
1012 | break; | |
1013 | ||
1014 | case ICMP_UNREACH_FILTER_PROHIB: | |
1015 | ++unreachable; | |
1016 | Printf(" !X"); | |
1017 | break; | |
1018 | ||
1019 | case ICMP_UNREACH_HOST_PRECEDENCE: | |
1020 | ++unreachable; | |
1021 | Printf(" !V"); | |
1022 | break; | |
1023 | ||
1024 | case ICMP_UNREACH_PRECEDENCE_CUTOFF: | |
1025 | ++unreachable; | |
1026 | Printf(" !C"); | |
1027 | break; | |
1028 | ||
1029 | default: | |
1030 | ++unreachable; | |
1031 | Printf(" !<%d>", code); | |
b7080c8e A |
1032 | break; |
1033 | } | |
2b484d24 | 1034 | break; |
b7080c8e | 1035 | } |
2b484d24 A |
1036 | if (cc == 0) { |
1037 | loss++; | |
b7080c8e | 1038 | Printf(" *"); |
2b484d24 A |
1039 | } |
1040 | (void)fflush(stdout); | |
1041 | } | |
1042 | if (sump) { | |
1043 | Printf(" (%d%% loss)", (loss * 100) / nprobes); | |
b7080c8e A |
1044 | } |
1045 | putchar('\n'); | |
2b484d24 A |
1046 | if (got_there || |
1047 | (unreachable > 0 && unreachable >= nprobes - 1)) | |
1048 | break; | |
b7080c8e | 1049 | } |
2b484d24 | 1050 | exit(0); |
b7080c8e A |
1051 | } |
1052 | ||
1053 | int | |
2b484d24 A |
1054 | wait_for_reply(register int sock, register struct sockaddr_in *fromp, |
1055 | register const struct timeval *tp) | |
b7080c8e | 1056 | { |
2b484d24 A |
1057 | fd_set *fdsp; |
1058 | size_t nfds; | |
1059 | struct timeval now, wait; | |
1060 | struct timezone tz; | |
1061 | register int cc = 0; | |
1062 | register int error; | |
1063 | int fromlen = sizeof(*fromp); | |
1064 | ||
1065 | nfds = howmany(sock + 1, NFDBITS); | |
1066 | if ((fdsp = malloc(nfds * sizeof(fd_mask))) == NULL) | |
1067 | err(1, "malloc"); | |
1068 | memset(fdsp, 0, nfds * sizeof(fd_mask)); | |
1069 | FD_SET(sock, fdsp); | |
1070 | ||
1071 | wait.tv_sec = tp->tv_sec + waittime; | |
1072 | wait.tv_usec = tp->tv_usec; | |
1073 | (void)gettimeofday(&now, &tz); | |
1074 | tvsub(&wait, &now); | |
1075 | if (wait.tv_sec < 0) { | |
1076 | wait.tv_sec = 0; | |
1077 | wait.tv_usec = 1; | |
1078 | } | |
b7080c8e | 1079 | |
2b484d24 A |
1080 | error = select(sock + 1, fdsp, NULL, NULL, &wait); |
1081 | if (error == -1 && errno == EINVAL) { | |
1082 | Fprintf(stderr, "%s: botched select() args\n", prog); | |
1083 | exit(1); | |
1084 | } | |
1085 | if (error > 0) | |
1086 | cc = recvfrom(sock, (char *)packet, sizeof(packet), 0, | |
1087 | (struct sockaddr *)fromp, &fromlen); | |
b7080c8e | 1088 | |
2b484d24 | 1089 | free(fdsp); |
b7080c8e A |
1090 | return(cc); |
1091 | } | |
1092 | ||
b7080c8e | 1093 | void |
2b484d24 | 1094 | send_probe(int seq, int ttl) |
b7080c8e | 1095 | { |
2b484d24 A |
1096 | register int cc; |
1097 | ||
1098 | outip->ip_ttl = ttl; | |
1099 | outip->ip_id = htons(ident + seq); | |
1100 | ||
1101 | /* XXX undocumented debugging hack */ | |
1102 | if (verbose > 1) { | |
1103 | register const u_short *sp; | |
1104 | register int nshorts, i; | |
1105 | ||
1106 | sp = (u_short *)outip; | |
1107 | nshorts = (u_int)packlen / sizeof(u_short); | |
1108 | i = 0; | |
1109 | Printf("[ %d bytes", packlen); | |
1110 | while (--nshorts >= 0) { | |
1111 | if ((i++ % 8) == 0) | |
1112 | Printf("\n\t"); | |
1113 | Printf(" %04x", ntohs(*sp++)); | |
1114 | } | |
1115 | if (packlen & 1) { | |
1116 | if ((i % 8) == 0) | |
1117 | Printf("\n\t"); | |
1118 | Printf(" %02x", *(u_char *)sp); | |
1119 | } | |
1120 | Printf("]\n"); | |
1121 | } | |
b7080c8e | 1122 | |
2b484d24 A |
1123 | #if !defined(IP_HDRINCL) && defined(IP_TTL) |
1124 | if (setsockopt(sndsock, IPPROTO_IP, IP_TTL, | |
1125 | (char *)&ttl, sizeof(ttl)) < 0) { | |
1126 | Fprintf(stderr, "%s: setsockopt ttl %d: %s\n", | |
1127 | prog, ttl, strerror(errno)); | |
1128 | exit(1); | |
1129 | } | |
1130 | #endif | |
1131 | ||
1132 | cc = sendto(sndsock, (char *)outip, | |
1133 | packlen, 0, &whereto, sizeof(whereto)); | |
1134 | if (cc < 0 || cc != packlen) { | |
1135 | if (cc < 0) | |
1136 | Fprintf(stderr, "%s: sendto: %s\n", | |
1137 | prog, strerror(errno)); | |
1138 | Printf("%s: wrote %s %d chars, ret=%d\n", | |
1139 | prog, hostname, packlen, cc); | |
1140 | (void)fflush(stdout); | |
b7080c8e A |
1141 | } |
1142 | } | |
1143 | ||
2b484d24 A |
1144 | #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) |
1145 | int | |
1146 | setpolicy(so, policy) | |
1147 | int so; | |
1148 | char *policy; | |
1149 | { | |
1150 | char *buf; | |
1151 | ||
1152 | buf = ipsec_set_policy(policy, strlen(policy)); | |
1153 | if (buf == NULL) { | |
1154 | warnx("%s", ipsec_strerror()); | |
1155 | return -1; | |
1156 | } | |
1157 | (void)setsockopt(so, IPPROTO_IP, IP_IPSEC_POLICY, | |
1158 | buf, ipsec_get_policylen(buf)); | |
1159 | ||
1160 | free(buf); | |
1161 | ||
1162 | return 0; | |
1163 | } | |
1164 | #endif | |
b7080c8e A |
1165 | |
1166 | double | |
2b484d24 | 1167 | deltaT(struct timeval *t1p, struct timeval *t2p) |
b7080c8e A |
1168 | { |
1169 | register double dt; | |
1170 | ||
1171 | dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + | |
1172 | (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; | |
1173 | return (dt); | |
1174 | } | |
1175 | ||
b7080c8e A |
1176 | /* |
1177 | * Convert an ICMP "type" field to a printable string. | |
1178 | */ | |
1179 | char * | |
2b484d24 | 1180 | pr_type(register u_char t) |
b7080c8e A |
1181 | { |
1182 | static char *ttab[] = { | |
1183 | "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable", | |
1184 | "Source Quench", "Redirect", "ICMP 6", "ICMP 7", | |
1185 | "Echo", "ICMP 9", "ICMP 10", "Time Exceeded", | |
1186 | "Param Problem", "Timestamp", "Timestamp Reply", "Info Request", | |
1187 | "Info Reply" | |
1188 | }; | |
1189 | ||
2b484d24 | 1190 | if (t > 16) |
b7080c8e A |
1191 | return("OUT-OF-RANGE"); |
1192 | ||
1193 | return(ttab[t]); | |
1194 | } | |
1195 | ||
b7080c8e | 1196 | int |
2b484d24 A |
1197 | packet_ok(register u_char *buf, int cc, register struct sockaddr_in *from, |
1198 | register int seq) | |
b7080c8e A |
1199 | { |
1200 | register struct icmp *icp; | |
2b484d24 A |
1201 | register u_char type, code; |
1202 | register int hlen; | |
b7080c8e | 1203 | #ifndef ARCHAIC |
2b484d24 | 1204 | register struct ip *ip; |
b7080c8e A |
1205 | |
1206 | ip = (struct ip *) buf; | |
1207 | hlen = ip->ip_hl << 2; | |
1208 | if (cc < hlen + ICMP_MINLEN) { | |
1209 | if (verbose) | |
1210 | Printf("packet too short (%d bytes) from %s\n", cc, | |
1211 | inet_ntoa(from->sin_addr)); | |
1212 | return (0); | |
1213 | } | |
1214 | cc -= hlen; | |
1215 | icp = (struct icmp *)(buf + hlen); | |
1216 | #else | |
1217 | icp = (struct icmp *)buf; | |
2b484d24 A |
1218 | #endif |
1219 | type = icp->icmp_type; | |
1220 | code = icp->icmp_code; | |
1221 | /* Path MTU Discovery (RFC1191) */ | |
1222 | if (code != ICMP_UNREACH_NEEDFRAG) | |
1223 | pmtu = 0; | |
1224 | else { | |
1225 | #ifdef HAVE_ICMP_NEXTMTU | |
1226 | pmtu = ntohs(icp->icmp_nextmtu); | |
1227 | #else | |
1228 | pmtu = ntohs(((struct my_pmtu *)&icp->icmp_void)->ipm_nextmtu); | |
1229 | #endif | |
1230 | } | |
1231 | if (type == ICMP_ECHOREPLY | |
1232 | && proto->num == IPPROTO_ICMP | |
1233 | && (*proto->check)((u_char *)icp, (u_char)seq)) | |
1234 | return -2; | |
b7080c8e A |
1235 | if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || |
1236 | type == ICMP_UNREACH) { | |
1237 | struct ip *hip; | |
2b484d24 | 1238 | u_char *inner; |
b7080c8e A |
1239 | |
1240 | hip = &icp->icmp_ip; | |
1241 | hlen = hip->ip_hl << 2; | |
2b484d24 A |
1242 | inner = (u_char *)((u_char *)hip + hlen); |
1243 | if (hlen + 12 <= cc | |
1244 | && hip->ip_p == proto->num | |
1245 | && (*proto->check)(inner, (u_char)seq)) | |
1246 | return (type == ICMP_TIMXCEED ? -1 : code + 1); | |
b7080c8e A |
1247 | } |
1248 | #ifndef ARCHAIC | |
1249 | if (verbose) { | |
2b484d24 A |
1250 | register int i; |
1251 | u_int32_t *lp = (u_int32_t *)&icp->icmp_ip; | |
1252 | ||
1253 | Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr)); | |
1254 | Printf("%s: icmp type %d (%s) code %d\n", | |
1255 | inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code); | |
1256 | for (i = 4; i < cc ; i += sizeof(*lp)) | |
1257 | Printf("%2d: x%8.8x\n", i, *lp++); | |
b7080c8e | 1258 | } |
2b484d24 | 1259 | #endif |
b7080c8e A |
1260 | return(0); |
1261 | } | |
1262 | ||
2b484d24 A |
1263 | void |
1264 | icmp_prep(struct outdata *outdata) | |
1265 | { | |
1266 | struct icmp *const icmpheader = (struct icmp *) outp; | |
1267 | ||
1268 | icmpheader->icmp_type = ICMP_ECHO; | |
1269 | icmpheader->icmp_id = htons(ident); | |
1270 | icmpheader->icmp_seq = htons(outdata->seq); | |
1271 | icmpheader->icmp_cksum = 0; | |
1272 | icmpheader->icmp_cksum = in_cksum((u_short *)icmpheader, protlen); | |
1273 | if (icmpheader->icmp_cksum == 0) | |
1274 | icmpheader->icmp_cksum = 0xffff; | |
1275 | } | |
1276 | ||
1277 | int | |
1278 | icmp_check(const u_char *data, int seq) | |
1279 | { | |
1280 | struct icmp *const icmpheader = (struct icmp *) data; | |
1281 | ||
1282 | return (icmpheader->icmp_id == htons(ident) | |
1283 | && icmpheader->icmp_seq == htons(seq)); | |
1284 | } | |
1285 | ||
1286 | void | |
1287 | udp_prep(struct outdata *outdata) | |
1288 | { | |
1289 | struct udphdr *const outudp = (struct udphdr *) outp; | |
1290 | ||
1291 | outudp->uh_sport = htons(ident); | |
1292 | outudp->uh_dport = htons(port + outdata->seq); | |
1293 | outudp->uh_ulen = htons((u_short)protlen); | |
1294 | outudp->uh_sum = 0; | |
1295 | if (doipcksum) { | |
1296 | u_short sum = p_cksum(outip, (u_short*)outudp, protlen); | |
1297 | outudp->uh_sum = (sum) ? sum : 0xffff; | |
1298 | } | |
1299 | ||
1300 | return; | |
1301 | } | |
1302 | ||
1303 | int | |
1304 | udp_check(const u_char *data, int seq) | |
1305 | { | |
1306 | struct udphdr *const udp = (struct udphdr *) data; | |
1307 | ||
1308 | return (ntohs(udp->uh_sport) == ident | |
1309 | && ntohs(udp->uh_dport) == port + seq); | |
1310 | } | |
1311 | ||
1312 | void | |
1313 | tcp_prep(struct outdata *outdata) | |
1314 | { | |
1315 | struct tcphdr *const tcp = (struct tcphdr *) outp; | |
1316 | ||
1317 | tcp->th_sport = htons(ident); | |
1318 | tcp->th_dport = htons(port + outdata->seq); | |
1319 | tcp->th_seq = (tcp->th_sport << 16) | tcp->th_dport; | |
1320 | tcp->th_ack = 0; | |
1321 | tcp->th_off = 5; | |
1322 | tcp->th_flags = TH_SYN; | |
1323 | tcp->th_sum = 0; | |
1324 | ||
1325 | if (doipcksum) { | |
1326 | u_short sum = p_cksum(outip, (u_short*)tcp, protlen); | |
1327 | tcp->th_sum = (sum) ? sum : 0xffff; | |
1328 | } | |
1329 | } | |
1330 | ||
1331 | int | |
1332 | tcp_check(const u_char *data, int seq) | |
1333 | { | |
1334 | struct tcphdr *const tcp = (struct tcphdr *) data; | |
1335 | ||
1336 | return (ntohs(tcp->th_sport) == ident | |
1337 | && ntohs(tcp->th_dport) == port + seq); | |
1338 | } | |
b7080c8e A |
1339 | |
1340 | void | |
2b484d24 | 1341 | gre_prep(struct outdata *outdata) |
b7080c8e | 1342 | { |
2b484d24 A |
1343 | struct grehdr *const gre = (struct grehdr *) outp; |
1344 | ||
1345 | gre->flags = htons(0x2001); | |
1346 | gre->proto = htons(port); | |
1347 | gre->length = 0; | |
1348 | gre->callId = htons(ident + outdata->seq); | |
1349 | } | |
1350 | ||
1351 | int | |
1352 | gre_check(const u_char *data, int seq) | |
1353 | { | |
1354 | struct grehdr *const gre = (struct grehdr *) data; | |
1355 | ||
1356 | return(ntohs(gre->proto) == port | |
1357 | && ntohs(gre->callId) == ident + seq); | |
1358 | } | |
1359 | ||
1360 | void | |
1361 | gen_prep(struct outdata *outdata) | |
1362 | { | |
1363 | u_int16_t *const ptr = (u_int16_t *) outp; | |
1364 | ||
1365 | ptr[0] = htons(ident); | |
1366 | ptr[1] = htons(port + outdata->seq); | |
1367 | } | |
1368 | ||
1369 | int | |
1370 | gen_check(const u_char *data, int seq) | |
1371 | { | |
1372 | u_int16_t *const ptr = (u_int16_t *) data; | |
1373 | ||
1374 | return(ntohs(ptr[0]) == ident | |
1375 | && ntohs(ptr[1]) == port + seq); | |
1376 | } | |
1377 | ||
1378 | void | |
1379 | print(register u_char *buf, register int cc, register struct sockaddr_in *from) | |
1380 | { | |
1381 | register struct ip *ip; | |
1382 | register int hlen; | |
b7080c8e A |
1383 | |
1384 | ip = (struct ip *) buf; | |
1385 | hlen = ip->ip_hl << 2; | |
1386 | cc -= hlen; | |
1387 | ||
1388 | if (nflag) | |
1389 | Printf(" %s", inet_ntoa(from->sin_addr)); | |
1390 | else | |
1391 | Printf(" %s (%s)", inetname(from->sin_addr), | |
2b484d24 | 1392 | inet_ntoa(from->sin_addr)); |
b7080c8e A |
1393 | |
1394 | if (verbose) | |
2b484d24 | 1395 | Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst)); |
b7080c8e A |
1396 | } |
1397 | ||
2b484d24 A |
1398 | /* |
1399 | * Checksum routine for UDP and TCP headers. | |
1400 | */ | |
1401 | u_short | |
1402 | p_cksum(struct ip *ip, u_short *data, int len) | |
1403 | { | |
1404 | static struct ipovly ipo; | |
1405 | u_short sumh, sumd; | |
1406 | u_long sumt; | |
1407 | ||
1408 | ipo.ih_pr = ip->ip_p; | |
1409 | ipo.ih_len = htons(len); | |
1410 | ipo.ih_src = ip->ip_src; | |
1411 | ipo.ih_dst = ip->ip_dst; | |
1412 | ||
1413 | sumh = in_cksum((u_short*)&ipo, sizeof(ipo)); /* pseudo ip hdr cksum */ | |
1414 | sumd = in_cksum((u_short*)data, len); /* payload data cksum */ | |
1415 | sumt = (sumh << 16) | (sumd); | |
1416 | ||
1417 | return ~in_cksum((u_short*)&sumt, sizeof(sumt)); | |
1418 | } | |
b7080c8e | 1419 | |
b7080c8e A |
1420 | /* |
1421 | * Checksum routine for Internet Protocol family headers (C Version) | |
1422 | */ | |
1423 | u_short | |
2b484d24 | 1424 | in_cksum(register u_short *addr, register int len) |
b7080c8e A |
1425 | { |
1426 | register int nleft = len; | |
1427 | register u_short *w = addr; | |
1428 | register u_short answer; | |
1429 | register int sum = 0; | |
1430 | ||
1431 | /* | |
1432 | * Our algorithm is simple, using a 32 bit accumulator (sum), | |
1433 | * we add sequential 16 bit words to it, and at the end, fold | |
1434 | * back all the carry bits from the top 16 bits into the lower | |
1435 | * 16 bits. | |
1436 | */ | |
1437 | while (nleft > 1) { | |
1438 | sum += *w++; | |
1439 | nleft -= 2; | |
1440 | } | |
1441 | ||
1442 | /* mop up an odd byte, if necessary */ | |
1443 | if (nleft == 1) | |
1444 | sum += *(u_char *)w; | |
1445 | ||
1446 | /* | |
1447 | * add back carry outs from top 16 bits to low 16 bits | |
1448 | */ | |
1449 | sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ | |
1450 | sum += (sum >> 16); /* add carry */ | |
1451 | answer = ~sum; /* truncate to 16 bits */ | |
1452 | return (answer); | |
1453 | } | |
b7080c8e A |
1454 | |
1455 | /* | |
1456 | * Subtract 2 timeval structs: out = out - in. | |
2b484d24 | 1457 | * Out is assumed to be within about LONG_MAX seconds of in. |
b7080c8e A |
1458 | */ |
1459 | void | |
2b484d24 | 1460 | tvsub(register struct timeval *out, register struct timeval *in) |
b7080c8e | 1461 | { |
2b484d24 | 1462 | |
b7080c8e | 1463 | if ((out->tv_usec -= in->tv_usec) < 0) { |
2b484d24 | 1464 | --out->tv_sec; |
b7080c8e A |
1465 | out->tv_usec += 1000000; |
1466 | } | |
1467 | out->tv_sec -= in->tv_sec; | |
1468 | } | |
1469 | ||
b7080c8e A |
1470 | /* |
1471 | * Construct an Internet address representation. | |
1472 | * If the nflag has been supplied, give | |
1473 | * numeric value, otherwise try for symbolic name. | |
1474 | */ | |
1475 | char * | |
2b484d24 | 1476 | inetname(struct in_addr in) |
b7080c8e A |
1477 | { |
1478 | register char *cp; | |
2b484d24 | 1479 | register struct hostent *hp; |
b7080c8e | 1480 | static int first = 1; |
2b484d24 | 1481 | static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1]; |
b7080c8e A |
1482 | |
1483 | if (first && !nflag) { | |
1484 | first = 0; | |
2b484d24 A |
1485 | if (gethostname(domain, sizeof(domain) - 1) < 0) |
1486 | domain[0] = '\0'; | |
1487 | else { | |
1488 | cp = strchr(domain, '.'); | |
1489 | if (cp == NULL) { | |
1490 | hp = gethostbyname(domain); | |
1491 | if (hp != NULL) | |
1492 | cp = strchr(hp->h_name, '.'); | |
1493 | } | |
1494 | if (cp == NULL) | |
1495 | domain[0] = '\0'; | |
1496 | else { | |
1497 | ++cp; | |
1498 | (void)strncpy(domain, cp, sizeof(domain) - 1); | |
1499 | domain[sizeof(domain) - 1] = '\0'; | |
1500 | } | |
1501 | } | |
b7080c8e | 1502 | } |
b7080c8e | 1503 | if (!nflag && in.s_addr != INADDR_ANY) { |
2b484d24 A |
1504 | hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET); |
1505 | if (hp != NULL) { | |
1506 | if ((cp = strchr(hp->h_name, '.')) != NULL && | |
1507 | strcmp(cp + 1, domain) == 0) | |
1508 | *cp = '\0'; | |
1509 | (void)strncpy(line, hp->h_name, sizeof(line) - 1); | |
1510 | line[sizeof(line) - 1] = '\0'; | |
1511 | return (line); | |
b7080c8e A |
1512 | } |
1513 | } | |
2b484d24 A |
1514 | return (inet_ntoa(in)); |
1515 | } | |
1516 | ||
1517 | struct hostinfo * | |
1518 | gethostinfo(register char *hostname) | |
1519 | { | |
1520 | register int n; | |
1521 | register struct hostent *hp; | |
1522 | register struct hostinfo *hi; | |
1523 | register char **p; | |
1524 | register u_int32_t addr, *ap; | |
1525 | ||
1526 | if (strlen(hostname) > 64) { | |
1527 | Fprintf(stderr, "%s: hostname \"%.32s...\" is too long\n", | |
1528 | prog, hostname); | |
1529 | exit(1); | |
1530 | } | |
1531 | hi = calloc(1, sizeof(*hi)); | |
1532 | if (hi == NULL) { | |
1533 | Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno)); | |
1534 | exit(1); | |
b7080c8e | 1535 | } |
2b484d24 A |
1536 | addr = inet_addr(hostname); |
1537 | if ((int32_t)addr != -1) { | |
1538 | hi->name = strdup(hostname); | |
1539 | hi->n = 1; | |
1540 | hi->addrs = calloc(1, sizeof(hi->addrs[0])); | |
1541 | if (hi->addrs == NULL) { | |
1542 | Fprintf(stderr, "%s: calloc %s\n", | |
1543 | prog, strerror(errno)); | |
1544 | exit(1); | |
1545 | } | |
1546 | hi->addrs[0] = addr; | |
1547 | return (hi); | |
1548 | } | |
1549 | ||
1550 | hp = gethostbyname(hostname); | |
1551 | if (hp == NULL) { | |
1552 | Fprintf(stderr, "%s: unknown host %s\n", prog, hostname); | |
1553 | exit(1); | |
1554 | } | |
1555 | if (hp->h_addrtype != AF_INET || hp->h_length != 4) { | |
1556 | Fprintf(stderr, "%s: bad host %s\n", prog, hostname); | |
1557 | exit(1); | |
1558 | } | |
1559 | hi->name = strdup(hp->h_name); | |
1560 | for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p) | |
1561 | continue; | |
1562 | hi->n = n; | |
1563 | hi->addrs = calloc(n, sizeof(hi->addrs[0])); | |
1564 | if (hi->addrs == NULL) { | |
1565 | Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno)); | |
1566 | exit(1); | |
1567 | } | |
1568 | for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p) | |
1569 | memcpy(ap, *p, sizeof(*ap)); | |
1570 | return (hi); | |
1571 | } | |
1572 | ||
1573 | void | |
1574 | freehostinfo(register struct hostinfo *hi) | |
1575 | { | |
1576 | if (hi->name != NULL) { | |
1577 | free(hi->name); | |
1578 | hi->name = NULL; | |
1579 | } | |
1580 | free((char *)hi->addrs); | |
1581 | free((char *)hi); | |
1582 | } | |
1583 | ||
1584 | void | |
1585 | getaddr(register u_int32_t *ap, register char *hostname) | |
1586 | { | |
1587 | register struct hostinfo *hi; | |
1588 | ||
1589 | hi = gethostinfo(hostname); | |
1590 | *ap = hi->addrs[0]; | |
1591 | freehostinfo(hi); | |
b7080c8e A |
1592 | } |
1593 | ||
1594 | void | |
2b484d24 | 1595 | setsin(register struct sockaddr_in *sin, register u_int32_t addr) |
b7080c8e | 1596 | { |
2b484d24 A |
1597 | |
1598 | memset(sin, 0, sizeof(*sin)); | |
1599 | #ifdef HAVE_SOCKADDR_SA_LEN | |
1600 | sin->sin_len = sizeof(*sin); | |
1601 | #endif | |
1602 | sin->sin_family = AF_INET; | |
1603 | sin->sin_addr.s_addr = addr; | |
1604 | } | |
1605 | ||
1606 | /* String to value with optional min and max. Handles decimal and hex. */ | |
1607 | int | |
1608 | str2val(register const char *str, register const char *what, | |
1609 | register int mi, register int ma) | |
1610 | { | |
1611 | register const char *cp; | |
1612 | register int val; | |
1613 | char *ep; | |
1614 | ||
1615 | if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { | |
1616 | cp = str + 2; | |
1617 | val = (int)strtol(cp, &ep, 16); | |
1618 | } else | |
1619 | val = (int)strtol(str, &ep, 10); | |
1620 | if (*ep != '\0') { | |
1621 | Fprintf(stderr, "%s: \"%s\" bad value for %s \n", | |
1622 | prog, str, what); | |
1623 | exit(1); | |
1624 | } | |
1625 | if (val < mi && mi >= 0) { | |
1626 | if (mi == 0) | |
1627 | Fprintf(stderr, "%s: %s must be >= %d\n", | |
1628 | prog, what, mi); | |
1629 | else | |
1630 | Fprintf(stderr, "%s: %s must be > %d\n", | |
1631 | prog, what, mi - 1); | |
1632 | exit(1); | |
1633 | } | |
1634 | if (val > ma && ma >= 0) { | |
1635 | Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma); | |
1636 | exit(1); | |
1637 | } | |
1638 | return (val); | |
1639 | } | |
1640 | ||
1641 | struct outproto * | |
1642 | setproto(char *pname) | |
1643 | { | |
1644 | struct outproto *proto; | |
1645 | int i; | |
1646 | ||
1647 | for (i = 0; protos[i].name != NULL; i++) { | |
1648 | if (strcasecmp(protos[i].name, pname) == 0) { | |
1649 | break; | |
1650 | } | |
1651 | } | |
1652 | proto = &protos[i]; | |
1653 | if (proto->name == NULL) { /* generic handler */ | |
1654 | struct protoent *pe; | |
1655 | u_long pnum; | |
1656 | ||
1657 | /* Determine the IP protocol number */ | |
1658 | if ((pe = getprotobyname(pname)) != NULL) | |
1659 | pnum = pe->p_proto; | |
1660 | else | |
1661 | pnum = str2val(optarg, "proto number", 1, 255); | |
1662 | proto->num = pnum; | |
1663 | } | |
1664 | return proto; | |
1665 | } | |
1666 | ||
1667 | void | |
1668 | usage(void) | |
1669 | { | |
1670 | extern char version[]; | |
1671 | ||
1672 | Fprintf(stderr, "Version %s\n", version); | |
1673 | Fprintf(stderr, | |
1674 | "Usage: %s [-dFInrSvx] [-g gateway] [-i iface] [-f first_ttl]\n" | |
1675 | "\t[-m max_ttl] [-p port] [-P proto] [-q nqueries] [-s src_addr]\n" | |
1676 | "\t[-t tos] [-w waittime] [-z pausemsecs] host [packetlen]\n", prog); | |
b7080c8e A |
1677 | exit(1); |
1678 | } |