]>
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[] = | |
b8dff150 | 28 | "@(#)$Id: traceroute.c,v 1.4 2006/02/07 06:22:57 lindak Exp $ (LBL)"; |
2b484d24 A |
29 | #endif |
30 | static const char rcsid[] = | |
9c859447 | 31 | "$FreeBSD: src/contrib/traceroute/traceroute.c,v 1.35 2008/02/20 23:29:52 rpaulo Exp $"; |
2b484d24 | 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" | |
9c859447 | 266 | #include "as.h" |
2b484d24 | 267 | #include "traceroute.h" |
b7080c8e | 268 | |
2b484d24 A |
269 | /* Maximum number of gateways (include room for one noop) */ |
270 | #define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t))) | |
271 | ||
272 | #ifndef MAXHOSTNAMELEN | |
273 | #define MAXHOSTNAMELEN 64 | |
b7080c8e A |
274 | #endif |
275 | ||
276 | #define Fprintf (void)fprintf | |
b7080c8e A |
277 | #define Printf (void)printf |
278 | ||
2b484d24 A |
279 | /* What a GRE packet header looks like */ |
280 | struct grehdr { | |
281 | u_int16_t flags; | |
282 | u_int16_t proto; | |
283 | u_int16_t length; /* PPTP version of these fields */ | |
284 | u_int16_t callId; | |
285 | }; | |
286 | #ifndef IPPROTO_GRE | |
287 | #define IPPROTO_GRE 47 | |
288 | #endif | |
289 | ||
290 | /* For GRE, we prepare what looks like a PPTP packet */ | |
291 | #define GRE_PPTP_PROTO 0x880b | |
292 | ||
293 | /* Host name and address list */ | |
294 | struct hostinfo { | |
295 | char *name; | |
296 | int n; | |
297 | u_int32_t *addrs; | |
298 | }; | |
299 | ||
300 | /* Data section of the probe packet */ | |
301 | struct outdata { | |
b7080c8e A |
302 | u_char seq; /* sequence number of this packet */ |
303 | u_char ttl; /* ttl packet left with */ | |
304 | struct timeval tv; /* time packet left */ | |
305 | }; | |
306 | ||
2b484d24 A |
307 | #ifndef HAVE_ICMP_NEXTMTU |
308 | /* Path MTU Discovery (RFC1191) */ | |
309 | struct my_pmtu { | |
310 | u_short ipm_void; | |
311 | u_short ipm_nextmtu; | |
312 | }; | |
313 | #endif | |
314 | ||
b7080c8e | 315 | u_char packet[512]; /* last inbound (icmp) packet */ |
b7080c8e | 316 | |
2b484d24 A |
317 | struct ip *outip; /* last output ip packet */ |
318 | u_char *outp; /* last output inner protocol packet */ | |
319 | ||
9c859447 A |
320 | struct ip *hip = NULL; /* Quoted IP header */ |
321 | int hiplen = 0; | |
322 | ||
2b484d24 A |
323 | /* loose source route gateway list (including room for final destination) */ |
324 | u_int32_t gwlist[NGATEWAYS + 1]; | |
b7080c8e A |
325 | |
326 | int s; /* receive (icmp) socket file descriptor */ | |
327 | int sndsock; /* send (udp) socket file descriptor */ | |
b7080c8e A |
328 | |
329 | struct sockaddr whereto; /* Who to try to reach */ | |
2b484d24 A |
330 | struct sockaddr wherefrom; /* Who we are */ |
331 | int packlen; /* total length of packet */ | |
332 | int protlen; /* length of protocol part of packet */ | |
333 | int minpacket; /* min ip packet size */ | |
334 | int maxpacket = 32 * 1024; /* max ip packet size */ | |
335 | int pmtu; /* Path MTU Discovery (RFC1191) */ | |
336 | u_int pausemsecs; | |
337 | ||
338 | char *prog; | |
339 | char *source; | |
b7080c8e | 340 | char *hostname; |
2b484d24 A |
341 | char *device; |
342 | static const char devnull[] = "/dev/null"; | |
b7080c8e | 343 | |
9c859447 | 344 | int nprobes = -1; |
2b484d24 A |
345 | int max_ttl; |
346 | int first_ttl = 1; | |
b7080c8e | 347 | u_short ident; |
2b484d24 A |
348 | u_short port; /* protocol specific base "port" */ |
349 | ||
b7080c8e A |
350 | int options; /* socket options */ |
351 | int verbose; | |
352 | int waittime = 5; /* time to wait for response (in seconds) */ | |
353 | int nflag; /* print addresses numerically */ | |
9c859447 A |
354 | int as_path; /* print as numbers for each hop */ |
355 | char *as_server = NULL; | |
356 | void *asn; | |
2b484d24 A |
357 | #ifdef CANT_HACK_IPCKSUM |
358 | int doipcksum = 0; /* don't calculate ip checksums by default */ | |
359 | #else | |
360 | int doipcksum = 1; /* calculate ip checksums by default */ | |
361 | #endif | |
362 | int optlen; /* length of ip options */ | |
9c859447 A |
363 | int fixedPort = 0; /* Use fixed destination port for TCP and UDP */ |
364 | int printdiff = 0; /* Print the difference between sent and quoted */ | |
2b484d24 A |
365 | |
366 | extern int optind; | |
367 | extern int opterr; | |
368 | extern char *optarg; | |
369 | ||
370 | /* Forwards */ | |
371 | double deltaT(struct timeval *, struct timeval *); | |
372 | void freehostinfo(struct hostinfo *); | |
373 | void getaddr(u_int32_t *, char *); | |
374 | struct hostinfo *gethostinfo(char *); | |
375 | u_short in_cksum(u_short *, int); | |
376 | char *inetname(struct in_addr); | |
377 | int main(int, char **); | |
378 | u_short p_cksum(struct ip *, u_short *, int); | |
379 | int packet_ok(u_char *, int, struct sockaddr_in *, int); | |
380 | char *pr_type(u_char); | |
381 | void print(u_char *, int, struct sockaddr_in *); | |
382 | #ifdef IPSEC | |
383 | int setpolicy __P((int so, char *policy)); | |
384 | #endif | |
385 | void send_probe(int, int); | |
386 | struct outproto *setproto(char *); | |
387 | int str2val(const char *, const char *, int, int); | |
388 | void tvsub(struct timeval *, struct timeval *); | |
389 | void usage(void); | |
390 | int wait_for_reply(int, struct sockaddr_in *, const struct timeval *); | |
9c859447 | 391 | void pkt_compare(const u_char *, int, const u_char *, int); |
2b484d24 A |
392 | #ifndef HAVE_USLEEP |
393 | int usleep(u_int); | |
394 | #endif | |
395 | ||
396 | void udp_prep(struct outdata *); | |
397 | int udp_check(const u_char *, int); | |
398 | void tcp_prep(struct outdata *); | |
399 | int tcp_check(const u_char *, int); | |
400 | void gre_prep(struct outdata *); | |
401 | int gre_check(const u_char *, int); | |
402 | void gen_prep(struct outdata *); | |
403 | int gen_check(const u_char *, int); | |
404 | void icmp_prep(struct outdata *); | |
405 | int icmp_check(const u_char *, int); | |
406 | ||
407 | /* Descriptor structure for each outgoing protocol we support */ | |
408 | struct outproto { | |
409 | char *name; /* name of protocol */ | |
9c859447 | 410 | const char *key; /* An ascii key for the bytes of the header */ |
2b484d24 A |
411 | u_char num; /* IP protocol number */ |
412 | u_short hdrlen; /* max size of protocol header */ | |
413 | u_short port; /* default base protocol-specific "port" */ | |
414 | void (*prepare)(struct outdata *); | |
415 | /* finish preparing an outgoing packet */ | |
416 | int (*check)(const u_char *, int); | |
417 | /* check an incoming packet */ | |
418 | }; | |
419 | ||
420 | /* List of supported protocols. The first one is the default. The last | |
421 | one is the handler for generic protocols not explicitly listed. */ | |
422 | struct outproto protos[] = { | |
423 | { | |
424 | "udp", | |
9c859447 | 425 | "spt dpt len sum", |
2b484d24 A |
426 | IPPROTO_UDP, |
427 | sizeof(struct udphdr), | |
428 | 32768 + 666, | |
429 | udp_prep, | |
430 | udp_check | |
431 | }, | |
432 | { | |
433 | "tcp", | |
9c859447 | 434 | "spt dpt seq ack xxflwin sum urp", |
2b484d24 A |
435 | IPPROTO_TCP, |
436 | sizeof(struct tcphdr), | |
437 | 32768 + 666, | |
438 | tcp_prep, | |
439 | tcp_check | |
440 | }, | |
441 | { | |
442 | "gre", | |
9c859447 | 443 | "flg pro len clid", |
2b484d24 A |
444 | IPPROTO_GRE, |
445 | sizeof(struct grehdr), | |
446 | GRE_PPTP_PROTO, | |
447 | gre_prep, | |
448 | gre_check | |
449 | }, | |
450 | { | |
451 | "icmp", | |
9c859447 | 452 | "typ cod sum ", |
2b484d24 A |
453 | IPPROTO_ICMP, |
454 | sizeof(struct icmp), | |
455 | 0, | |
456 | icmp_prep, | |
457 | icmp_check | |
458 | }, | |
459 | { | |
9c859447 | 460 | NULL, |
2b484d24 A |
461 | NULL, |
462 | 0, | |
463 | 2 * sizeof(u_short), | |
464 | 0, | |
465 | gen_prep, | |
466 | gen_check | |
467 | }, | |
468 | }; | |
469 | struct outproto *proto = &protos[0]; | |
b7080c8e | 470 | |
9c859447 A |
471 | const char *ip_hdr_key = "vhtslen id off tlprsum srcip dstip opts"; |
472 | ||
b7080c8e | 473 | int |
2b484d24 | 474 | main(int argc, char **argv) |
b7080c8e | 475 | { |
2b484d24 A |
476 | register int op, code, n; |
477 | register char *cp; | |
478 | register const char *err; | |
479 | register u_int32_t *ap; | |
480 | register struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom; | |
481 | register struct sockaddr_in *to = (struct sockaddr_in *)&whereto; | |
482 | register struct hostinfo *hi; | |
483 | int on = 1; | |
484 | register struct protoent *pe; | |
485 | register int ttl, probe, i; | |
486 | register int seq = 0; | |
487 | int tos = 0, settos = 0; | |
488 | register int lsrr = 0; | |
489 | register u_short off = 0; | |
490 | struct ifaddrlist *al; | |
491 | char errbuf[132]; | |
492 | int requestPort = -1; | |
493 | int sump = 0; | |
b8dff150 | 494 | int sockerrno = 0; |
2b484d24 A |
495 | |
496 | /* Insure the socket fds won't be 0, 1 or 2 */ | |
497 | if (open(devnull, O_RDONLY) < 0 || | |
498 | open(devnull, O_RDONLY) < 0 || | |
499 | open(devnull, O_RDONLY) < 0) { | |
500 | Fprintf(stderr, "%s: open \"%s\": %s\n", | |
501 | prog, devnull, strerror(errno)); | |
502 | exit(1); | |
503 | } | |
504 | /* | |
505 | * Do the setuid-required stuff first, then lose priveleges ASAP. | |
506 | * Do error checking for these two calls where they appeared in | |
507 | * the original code. | |
508 | */ | |
509 | cp = "icmp"; | |
510 | pe = getprotobyname(cp); | |
511 | if (pe) { | |
512 | if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) | |
513 | sockerrno = errno; | |
514 | else if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) | |
515 | sockerrno = errno; | |
516 | } | |
517 | ||
518 | setuid(getuid()); | |
519 | ||
520 | #ifdef IPCTL_DEFTTL | |
521 | { | |
522 | int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL }; | |
523 | size_t sz = sizeof(max_ttl); | |
524 | ||
525 | if (sysctl(mib, 4, &max_ttl, &sz, NULL, 0) == -1) { | |
526 | perror("sysctl(net.inet.ip.ttl)"); | |
527 | exit(1); | |
528 | } | |
529 | } | |
530 | #else | |
531 | max_ttl = 30; | |
532 | #endif | |
533 | ||
534 | if (argv[0] == NULL) | |
535 | prog = "traceroute"; | |
536 | else if ((cp = strrchr(argv[0], '/')) != NULL) | |
537 | prog = cp + 1; | |
538 | else | |
539 | prog = argv[0]; | |
540 | ||
541 | opterr = 0; | |
9c859447 | 542 | while ((op = getopt(argc, argv, "aA:edDFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF) |
2b484d24 | 543 | switch (op) { |
9c859447 A |
544 | case 'a': |
545 | as_path = 1; | |
546 | break; | |
547 | ||
548 | case 'A': | |
549 | as_path = 1; | |
550 | as_server = optarg; | |
551 | break; | |
552 | ||
b7080c8e A |
553 | case 'd': |
554 | options |= SO_DEBUG; | |
555 | break; | |
2b484d24 | 556 | |
9c859447 A |
557 | case 'D': |
558 | printdiff = 1; | |
559 | break; | |
560 | ||
561 | case 'e': | |
562 | fixedPort = 1; | |
563 | break; | |
564 | ||
2b484d24 A |
565 | case 'f': |
566 | case 'M': /* FreeBSD compat. */ | |
567 | first_ttl = str2val(optarg, "first ttl", 1, 255); | |
568 | break; | |
569 | ||
570 | case 'F': | |
571 | off = IP_DF; | |
572 | break; | |
573 | ||
574 | case 'g': | |
575 | if (lsrr >= NGATEWAYS) { | |
b7080c8e | 576 | Fprintf(stderr, |
2b484d24 A |
577 | "%s: No more than %d gateways\n", |
578 | prog, NGATEWAYS); | |
b7080c8e A |
579 | exit(1); |
580 | } | |
2b484d24 A |
581 | getaddr(gwlist + lsrr, optarg); |
582 | ++lsrr; | |
583 | break; | |
584 | ||
585 | case 'i': | |
586 | device = optarg; | |
587 | break; | |
588 | ||
589 | case 'I': | |
590 | proto = setproto("icmp"); | |
591 | break; | |
592 | ||
593 | case 'm': | |
594 | max_ttl = str2val(optarg, "max ttl", 1, 255); | |
b7080c8e | 595 | break; |
2b484d24 | 596 | |
b7080c8e | 597 | case 'n': |
2b484d24 | 598 | ++nflag; |
b7080c8e | 599 | break; |
2b484d24 A |
600 | |
601 | case 'P': | |
602 | proto = setproto(optarg); | |
603 | break; | |
604 | ||
b7080c8e | 605 | case 'p': |
2b484d24 A |
606 | requestPort = (u_short)str2val(optarg, "port", |
607 | 1, (1 << 16) - 1); | |
b7080c8e | 608 | break; |
2b484d24 | 609 | |
b7080c8e | 610 | case 'q': |
2b484d24 | 611 | nprobes = str2val(optarg, "nprobes", 1, -1); |
b7080c8e | 612 | break; |
2b484d24 | 613 | |
b7080c8e A |
614 | case 'r': |
615 | options |= SO_DONTROUTE; | |
616 | break; | |
2b484d24 | 617 | |
b7080c8e A |
618 | case 's': |
619 | /* | |
620 | * set the ip source address of the outbound | |
621 | * probe (e.g., on a multi-homed host). | |
622 | */ | |
623 | source = optarg; | |
624 | break; | |
2b484d24 A |
625 | |
626 | case 'S': | |
627 | sump = 1; | |
628 | break; | |
629 | ||
b7080c8e | 630 | case 't': |
2b484d24 A |
631 | tos = str2val(optarg, "tos", 0, 255); |
632 | ++settos; | |
b7080c8e | 633 | break; |
2b484d24 | 634 | |
b7080c8e | 635 | case 'v': |
2b484d24 A |
636 | ++verbose; |
637 | break; | |
638 | ||
639 | case 'x': | |
640 | doipcksum = (doipcksum == 0); | |
b7080c8e | 641 | break; |
2b484d24 | 642 | |
b7080c8e | 643 | case 'w': |
2b484d24 | 644 | waittime = str2val(optarg, "wait time", |
9c859447 | 645 | 1, 24 * 60 * 60); |
b7080c8e | 646 | break; |
2b484d24 A |
647 | |
648 | case 'z': | |
649 | pausemsecs = str2val(optarg, "pause msecs", | |
650 | 0, 60 * 60 * 1000); | |
651 | break; | |
652 | ||
b7080c8e A |
653 | default: |
654 | usage(); | |
655 | } | |
b7080c8e | 656 | |
2b484d24 A |
657 | /* Set requested port, if any, else default for this protocol */ |
658 | port = (requestPort != -1) ? requestPort : proto->port; | |
b7080c8e | 659 | |
9c859447 A |
660 | if (nprobes == -1) |
661 | nprobes = printdiff ? 1 : 3; | |
662 | ||
2b484d24 | 663 | if (first_ttl > max_ttl) { |
b7080c8e | 664 | Fprintf(stderr, |
2b484d24 A |
665 | "%s: first ttl (%d) may not be greater than max ttl (%d)\n", |
666 | prog, first_ttl, max_ttl); | |
b7080c8e A |
667 | exit(1); |
668 | } | |
2b484d24 A |
669 | |
670 | if (!doipcksum) | |
671 | Fprintf(stderr, "%s: Warning: ip checksums disabled\n", prog); | |
672 | ||
673 | if (lsrr > 0) | |
674 | optlen = (lsrr + 1) * sizeof(gwlist[0]); | |
675 | minpacket = sizeof(*outip) + proto->hdrlen + sizeof(struct outdata) + optlen; | |
676 | packlen = minpacket; /* minimum sized packet */ | |
677 | ||
678 | /* Process destination and optional packet size */ | |
679 | switch (argc - optind) { | |
680 | ||
681 | case 2: | |
682 | packlen = str2val(argv[optind + 1], | |
683 | "packet length", minpacket, maxpacket); | |
684 | /* Fall through */ | |
685 | ||
686 | case 1: | |
687 | hostname = argv[optind]; | |
688 | hi = gethostinfo(hostname); | |
689 | setsin(to, hi->addrs[0]); | |
690 | if (hi->n > 1) | |
691 | Fprintf(stderr, | |
692 | "%s: Warning: %s has multiple addresses; using %s\n", | |
693 | prog, hostname, inet_ntoa(to->sin_addr)); | |
694 | hostname = hi->name; | |
695 | hi->name = NULL; | |
696 | freehostinfo(hi); | |
697 | break; | |
698 | ||
699 | default: | |
700 | usage(); | |
701 | } | |
702 | ||
703 | #ifdef HAVE_SETLINEBUF | |
704 | setlinebuf (stdout); | |
705 | #else | |
706 | setvbuf(stdout, NULL, _IOLBF, 0); | |
707 | #endif | |
708 | ||
709 | protlen = packlen - sizeof(*outip) - optlen; | |
710 | ||
711 | outip = (struct ip *)malloc((unsigned)packlen); | |
712 | if (outip == NULL) { | |
713 | Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno)); | |
b7080c8e A |
714 | exit(1); |
715 | } | |
2b484d24 A |
716 | memset((char *)outip, 0, packlen); |
717 | ||
718 | outip->ip_v = IPVERSION; | |
719 | if (settos) | |
720 | outip->ip_tos = tos; | |
721 | #ifdef BYTESWAP_IP_HDR | |
722 | outip->ip_len = htons(packlen); | |
723 | outip->ip_off = htons(off); | |
724 | #else | |
725 | outip->ip_len = packlen; | |
726 | outip->ip_off = off; | |
727 | #endif | |
728 | outip->ip_p = proto->num; | |
729 | outp = (u_char *)(outip + 1); | |
730 | #ifdef HAVE_RAW_OPTIONS | |
731 | if (lsrr > 0) { | |
732 | register u_char *optlist; | |
733 | ||
734 | optlist = outp; | |
735 | outp += optlen; | |
736 | ||
737 | /* final hop */ | |
738 | gwlist[lsrr] = to->sin_addr.s_addr; | |
739 | ||
740 | outip->ip_dst.s_addr = gwlist[0]; | |
741 | ||
742 | /* force 4 byte alignment */ | |
743 | optlist[0] = IPOPT_NOP; | |
744 | /* loose source route option */ | |
745 | optlist[1] = IPOPT_LSRR; | |
746 | i = lsrr * sizeof(gwlist[0]); | |
747 | optlist[2] = i + 3; | |
748 | /* Pointer to LSRR addresses */ | |
749 | optlist[3] = IPOPT_MINOFF; | |
750 | memcpy(optlist + 4, gwlist + 1, i); | |
751 | } else | |
752 | #endif | |
753 | outip->ip_dst = to->sin_addr; | |
b7080c8e | 754 | |
2b484d24 | 755 | outip->ip_hl = (outp - (u_char *)outip) >> 2; |
b7080c8e A |
756 | ident = (getpid() & 0xffff) | 0x8000; |
757 | ||
2b484d24 A |
758 | if (pe == NULL) { |
759 | Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp); | |
760 | exit(1); | |
b7080c8e | 761 | } |
2b484d24 A |
762 | if (s < 0) { |
763 | errno = sockerrno; | |
764 | Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno)); | |
765 | exit(1); | |
b7080c8e A |
766 | } |
767 | if (options & SO_DEBUG) | |
2b484d24 A |
768 | (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on, |
769 | sizeof(on)); | |
b7080c8e | 770 | if (options & SO_DONTROUTE) |
2b484d24 A |
771 | (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on, |
772 | sizeof(on)); | |
b7080c8e | 773 | |
2b484d24 A |
774 | #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) |
775 | if (setpolicy(s, "in bypass") < 0) | |
776 | errx(1, "%s", ipsec_strerror()); | |
777 | ||
778 | if (setpolicy(s, "out bypass") < 0) | |
779 | errx(1, "%s", ipsec_strerror()); | |
780 | #endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */ | |
781 | ||
782 | if (sndsock < 0) { | |
783 | errno = sockerrno; | |
784 | Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno)); | |
785 | exit(1); | |
b7080c8e | 786 | } |
2b484d24 A |
787 | |
788 | #if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS) | |
789 | if (lsrr > 0) { | |
790 | u_char optlist[MAX_IPOPTLEN]; | |
791 | ||
792 | cp = "ip"; | |
793 | if ((pe = getprotobyname(cp)) == NULL) { | |
794 | Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp); | |
795 | exit(1); | |
796 | } | |
797 | ||
798 | /* final hop */ | |
799 | gwlist[lsrr] = to->sin_addr.s_addr; | |
800 | ++lsrr; | |
801 | ||
802 | /* force 4 byte alignment */ | |
803 | optlist[0] = IPOPT_NOP; | |
804 | /* loose source route option */ | |
805 | optlist[1] = IPOPT_LSRR; | |
806 | i = lsrr * sizeof(gwlist[0]); | |
807 | optlist[2] = i + 3; | |
808 | /* Pointer to LSRR addresses */ | |
809 | optlist[3] = IPOPT_MINOFF; | |
810 | memcpy(optlist + 4, gwlist, i); | |
811 | ||
812 | if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS, | |
813 | (char *)optlist, i + sizeof(gwlist[0]))) < 0) { | |
814 | Fprintf(stderr, "%s: IP_OPTIONS: %s\n", | |
815 | prog, strerror(errno)); | |
816 | exit(1); | |
817 | } | |
818 | } | |
819 | #endif | |
820 | ||
b7080c8e | 821 | #ifdef SO_SNDBUF |
2b484d24 A |
822 | if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen, |
823 | sizeof(packlen)) < 0) { | |
824 | Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno)); | |
825 | exit(1); | |
b7080c8e | 826 | } |
2b484d24 | 827 | #endif |
b7080c8e A |
828 | #ifdef IP_HDRINCL |
829 | if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on, | |
2b484d24 A |
830 | sizeof(on)) < 0) { |
831 | Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog, strerror(errno)); | |
832 | exit(1); | |
b7080c8e | 833 | } |
2b484d24 A |
834 | #else |
835 | #ifdef IP_TOS | |
836 | if (settos && setsockopt(sndsock, IPPROTO_IP, IP_TOS, | |
837 | (char *)&tos, sizeof(tos)) < 0) { | |
838 | Fprintf(stderr, "%s: setsockopt tos %d: %s\n", | |
839 | prog, tos, strerror(errno)); | |
840 | exit(1); | |
841 | } | |
842 | #endif | |
843 | #endif | |
b7080c8e | 844 | if (options & SO_DEBUG) |
2b484d24 A |
845 | (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on, |
846 | sizeof(on)); | |
b7080c8e | 847 | if (options & SO_DONTROUTE) |
2b484d24 A |
848 | (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on, |
849 | sizeof(on)); | |
850 | ||
851 | /* Get the interface address list */ | |
852 | n = ifaddrlist(&al, errbuf); | |
853 | if (n < 0) { | |
854 | Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf); | |
855 | exit(1); | |
856 | } | |
857 | if (n == 0) { | |
858 | Fprintf(stderr, | |
859 | "%s: Can't find any network interfaces\n", prog); | |
860 | exit(1); | |
861 | } | |
862 | ||
863 | /* Look for a specific device */ | |
864 | if (device != NULL) { | |
865 | for (i = n; i > 0; --i, ++al) | |
866 | if (strcmp(device, al->device) == 0) | |
867 | break; | |
868 | if (i <= 0) { | |
869 | Fprintf(stderr, "%s: Can't find interface %.32s\n", | |
870 | prog, device); | |
b7080c8e A |
871 | exit(1); |
872 | } | |
2b484d24 A |
873 | } |
874 | ||
875 | /* Determine our source address */ | |
876 | if (source == NULL) { | |
877 | /* | |
878 | * If a device was specified, use the interface address. | |
879 | * Otherwise, try to determine our source address. | |
880 | */ | |
881 | if (device != NULL) | |
882 | setsin(from, al->addr); | |
883 | else if ((err = findsaddr(to, from)) != NULL) { | |
884 | Fprintf(stderr, "%s: findsaddr: %s\n", | |
885 | prog, err); | |
886 | exit(1); | |
887 | } | |
888 | } else { | |
889 | hi = gethostinfo(source); | |
890 | source = hi->name; | |
891 | hi->name = NULL; | |
892 | /* | |
893 | * If the device was specified make sure it | |
894 | * corresponds to the source address specified. | |
895 | * Otherwise, use the first address (and warn if | |
896 | * there are more than one). | |
897 | */ | |
898 | if (device != NULL) { | |
899 | for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap) | |
900 | if (*ap == al->addr) | |
901 | break; | |
902 | if (i <= 0) { | |
903 | Fprintf(stderr, | |
904 | "%s: %s is not on interface %.32s\n", | |
905 | prog, source, device); | |
906 | exit(1); | |
907 | } | |
908 | setsin(from, *ap); | |
909 | } else { | |
910 | setsin(from, hi->addrs[0]); | |
911 | if (hi->n > 1) | |
912 | Fprintf(stderr, | |
913 | "%s: Warning: %s has multiple addresses; using %s\n", | |
914 | prog, source, inet_ntoa(from->sin_addr)); | |
b7080c8e | 915 | } |
2b484d24 | 916 | freehostinfo(hi); |
b7080c8e A |
917 | } |
918 | ||
2b484d24 A |
919 | outip->ip_src = from->sin_addr; |
920 | ||
921 | /* Check the source address (-s), if any, is valid */ | |
922 | if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) { | |
923 | Fprintf(stderr, "%s: bind: %s\n", | |
924 | prog, strerror(errno)); | |
925 | exit (1); | |
926 | } | |
927 | ||
9c859447 A |
928 | if (as_path) { |
929 | asn = as_setup(as_server); | |
930 | if (asn == NULL) { | |
931 | Fprintf(stderr, "%s: as_setup failed, AS# lookups" | |
932 | " disabled\n", prog); | |
933 | (void)fflush(stderr); | |
934 | as_path = 0; | |
935 | } | |
936 | } | |
937 | ||
2b484d24 A |
938 | #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) |
939 | if (setpolicy(sndsock, "in bypass") < 0) | |
940 | errx(1, "%s", ipsec_strerror()); | |
941 | ||
942 | if (setpolicy(sndsock, "out bypass") < 0) | |
943 | errx(1, "%s", ipsec_strerror()); | |
944 | #endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */ | |
945 | ||
946 | Fprintf(stderr, "%s to %s (%s)", | |
947 | prog, hostname, inet_ntoa(to->sin_addr)); | |
b7080c8e A |
948 | if (source) |
949 | Fprintf(stderr, " from %s", source); | |
2b484d24 A |
950 | Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen); |
951 | (void)fflush(stderr); | |
b7080c8e | 952 | |
2b484d24 A |
953 | for (ttl = first_ttl; ttl <= max_ttl; ++ttl) { |
954 | u_int32_t lastaddr = 0; | |
955 | int gotlastaddr = 0; | |
b7080c8e A |
956 | int got_there = 0; |
957 | int unreachable = 0; | |
2b484d24 A |
958 | int sentfirst = 0; |
959 | int loss; | |
b7080c8e A |
960 | |
961 | Printf("%2d ", ttl); | |
2b484d24 A |
962 | for (probe = 0, loss = 0; probe < nprobes; ++probe) { |
963 | register int cc; | |
b7080c8e A |
964 | struct timeval t1, t2; |
965 | struct timezone tz; | |
2b484d24 A |
966 | register struct ip *ip; |
967 | struct outdata outdata; | |
968 | ||
969 | if (sentfirst && pausemsecs > 0) | |
970 | usleep(pausemsecs * 1000); | |
971 | /* Prepare outgoing data */ | |
9c859447 | 972 | outdata.seq = ++seq; |
2b484d24 A |
973 | outdata.ttl = ttl; |
974 | ||
975 | /* Avoid alignment problems by copying bytewise: */ | |
976 | (void)gettimeofday(&t1, &tz); | |
977 | memcpy(&outdata.tv, &t1, sizeof(outdata.tv)); | |
978 | ||
979 | /* Finalize and send packet */ | |
980 | (*proto->prepare)(&outdata); | |
981 | send_probe(seq, ttl); | |
982 | ++sentfirst; | |
983 | ||
984 | /* Wait for a reply */ | |
985 | while ((cc = wait_for_reply(s, from, &t1)) != 0) { | |
986 | double T; | |
987 | int precis; | |
988 | ||
989 | (void)gettimeofday(&t2, &tz); | |
990 | i = packet_ok(packet, cc, from, seq); | |
991 | /* Skip short packet */ | |
992 | if (i == 0) | |
993 | continue; | |
994 | if (!gotlastaddr || | |
995 | from->sin_addr.s_addr != lastaddr) { | |
9c859447 | 996 | if (gotlastaddr) printf("\n "); |
2b484d24 A |
997 | print(packet, cc, from); |
998 | lastaddr = from->sin_addr.s_addr; | |
999 | ++gotlastaddr; | |
1000 | } | |
1001 | T = deltaT(&t1, &t2); | |
1002 | #ifdef SANE_PRECISION | |
1003 | if (T >= 1000.0) | |
1004 | precis = 0; | |
1005 | else if (T >= 100.0) | |
1006 | precis = 1; | |
1007 | else if (T >= 10.0) | |
1008 | precis = 2; | |
1009 | else | |
1010 | #endif | |
1011 | precis = 3; | |
1012 | Printf(" %.*f ms", precis, T); | |
9c859447 A |
1013 | if (printdiff) { |
1014 | Printf("\n"); | |
1015 | Printf("%*.*s%s\n", | |
1016 | -(outip->ip_hl << 3), | |
1017 | outip->ip_hl << 3, | |
1018 | ip_hdr_key, | |
1019 | proto->key); | |
1020 | pkt_compare((void *)outip, packlen, | |
1021 | (void *)hip, hiplen); | |
1022 | } | |
2b484d24 | 1023 | if (i == -2) { |
b7080c8e | 1024 | #ifndef ARCHAIC |
2b484d24 A |
1025 | ip = (struct ip *)packet; |
1026 | if (ip->ip_ttl <= 1) | |
1027 | Printf(" !"); | |
1028 | #endif | |
1029 | ++got_there; | |
1030 | break; | |
1031 | } | |
1032 | /* time exceeded in transit */ | |
1033 | if (i == -1) | |
1034 | break; | |
1035 | code = i - 1; | |
1036 | switch (code) { | |
1037 | ||
1038 | case ICMP_UNREACH_PORT: | |
1039 | #ifndef ARCHAIC | |
1040 | ip = (struct ip *)packet; | |
1041 | if (ip->ip_ttl <= 1) | |
1042 | Printf(" !"); | |
1043 | #endif | |
1044 | ++got_there; | |
1045 | break; | |
1046 | ||
1047 | case ICMP_UNREACH_NET: | |
1048 | ++unreachable; | |
1049 | Printf(" !N"); | |
1050 | break; | |
1051 | ||
1052 | case ICMP_UNREACH_HOST: | |
1053 | ++unreachable; | |
1054 | Printf(" !H"); | |
1055 | break; | |
1056 | ||
1057 | case ICMP_UNREACH_PROTOCOL: | |
1058 | ++got_there; | |
1059 | Printf(" !P"); | |
1060 | break; | |
1061 | ||
1062 | case ICMP_UNREACH_NEEDFRAG: | |
1063 | ++unreachable; | |
1064 | Printf(" !F-%d", pmtu); | |
1065 | break; | |
1066 | ||
1067 | case ICMP_UNREACH_SRCFAIL: | |
1068 | ++unreachable; | |
1069 | Printf(" !S"); | |
1070 | break; | |
1071 | ||
9c859447 A |
1072 | case ICMP_UNREACH_NET_UNKNOWN: |
1073 | ++unreachable; | |
1074 | Printf(" !U"); | |
1075 | break; | |
1076 | ||
1077 | case ICMP_UNREACH_HOST_UNKNOWN: | |
1078 | ++unreachable; | |
1079 | Printf(" !W"); | |
1080 | break; | |
1081 | ||
1082 | case ICMP_UNREACH_ISOLATED: | |
1083 | ++unreachable; | |
1084 | Printf(" !I"); | |
1085 | break; | |
1086 | ||
1087 | case ICMP_UNREACH_NET_PROHIB: | |
1088 | ++unreachable; | |
1089 | Printf(" !A"); | |
1090 | break; | |
1091 | ||
1092 | case ICMP_UNREACH_HOST_PROHIB: | |
1093 | ++unreachable; | |
1094 | Printf(" !Z"); | |
1095 | break; | |
1096 | ||
1097 | case ICMP_UNREACH_TOSNET: | |
1098 | ++unreachable; | |
1099 | Printf(" !Q"); | |
1100 | break; | |
1101 | ||
1102 | case ICMP_UNREACH_TOSHOST: | |
1103 | ++unreachable; | |
1104 | Printf(" !T"); | |
1105 | break; | |
1106 | ||
2b484d24 A |
1107 | case ICMP_UNREACH_FILTER_PROHIB: |
1108 | ++unreachable; | |
1109 | Printf(" !X"); | |
1110 | break; | |
1111 | ||
1112 | case ICMP_UNREACH_HOST_PRECEDENCE: | |
1113 | ++unreachable; | |
1114 | Printf(" !V"); | |
1115 | break; | |
1116 | ||
1117 | case ICMP_UNREACH_PRECEDENCE_CUTOFF: | |
1118 | ++unreachable; | |
1119 | Printf(" !C"); | |
1120 | break; | |
1121 | ||
1122 | default: | |
1123 | ++unreachable; | |
1124 | Printf(" !<%d>", code); | |
b7080c8e A |
1125 | break; |
1126 | } | |
2b484d24 | 1127 | break; |
b7080c8e | 1128 | } |
2b484d24 A |
1129 | if (cc == 0) { |
1130 | loss++; | |
b7080c8e | 1131 | Printf(" *"); |
2b484d24 A |
1132 | } |
1133 | (void)fflush(stdout); | |
1134 | } | |
1135 | if (sump) { | |
1136 | Printf(" (%d%% loss)", (loss * 100) / nprobes); | |
b7080c8e A |
1137 | } |
1138 | putchar('\n'); | |
2b484d24 A |
1139 | if (got_there || |
1140 | (unreachable > 0 && unreachable >= nprobes - 1)) | |
1141 | break; | |
b7080c8e | 1142 | } |
9c859447 A |
1143 | if (as_path) |
1144 | as_shutdown(asn); | |
2b484d24 | 1145 | exit(0); |
b7080c8e A |
1146 | } |
1147 | ||
1148 | int | |
2b484d24 A |
1149 | wait_for_reply(register int sock, register struct sockaddr_in *fromp, |
1150 | register const struct timeval *tp) | |
b7080c8e | 1151 | { |
2b484d24 A |
1152 | fd_set *fdsp; |
1153 | size_t nfds; | |
1154 | struct timeval now, wait; | |
1155 | struct timezone tz; | |
1156 | register int cc = 0; | |
1157 | register int error; | |
b8dff150 | 1158 | socklen_t fromlen = sizeof(*fromp); |
2b484d24 A |
1159 | |
1160 | nfds = howmany(sock + 1, NFDBITS); | |
1161 | if ((fdsp = malloc(nfds * sizeof(fd_mask))) == NULL) | |
1162 | err(1, "malloc"); | |
1163 | memset(fdsp, 0, nfds * sizeof(fd_mask)); | |
1164 | FD_SET(sock, fdsp); | |
1165 | ||
1166 | wait.tv_sec = tp->tv_sec + waittime; | |
1167 | wait.tv_usec = tp->tv_usec; | |
1168 | (void)gettimeofday(&now, &tz); | |
1169 | tvsub(&wait, &now); | |
1170 | if (wait.tv_sec < 0) { | |
1171 | wait.tv_sec = 0; | |
1172 | wait.tv_usec = 1; | |
1173 | } | |
b7080c8e | 1174 | |
2b484d24 A |
1175 | error = select(sock + 1, fdsp, NULL, NULL, &wait); |
1176 | if (error == -1 && errno == EINVAL) { | |
1177 | Fprintf(stderr, "%s: botched select() args\n", prog); | |
1178 | exit(1); | |
1179 | } | |
1180 | if (error > 0) | |
1181 | cc = recvfrom(sock, (char *)packet, sizeof(packet), 0, | |
1182 | (struct sockaddr *)fromp, &fromlen); | |
b7080c8e | 1183 | |
2b484d24 | 1184 | free(fdsp); |
b7080c8e A |
1185 | return(cc); |
1186 | } | |
1187 | ||
b7080c8e | 1188 | void |
2b484d24 | 1189 | send_probe(int seq, int ttl) |
b7080c8e | 1190 | { |
2b484d24 A |
1191 | register int cc; |
1192 | ||
1193 | outip->ip_ttl = ttl; | |
1194 | outip->ip_id = htons(ident + seq); | |
1195 | ||
1196 | /* XXX undocumented debugging hack */ | |
1197 | if (verbose > 1) { | |
1198 | register const u_short *sp; | |
1199 | register int nshorts, i; | |
1200 | ||
1201 | sp = (u_short *)outip; | |
1202 | nshorts = (u_int)packlen / sizeof(u_short); | |
1203 | i = 0; | |
1204 | Printf("[ %d bytes", packlen); | |
1205 | while (--nshorts >= 0) { | |
1206 | if ((i++ % 8) == 0) | |
1207 | Printf("\n\t"); | |
1208 | Printf(" %04x", ntohs(*sp++)); | |
1209 | } | |
1210 | if (packlen & 1) { | |
1211 | if ((i % 8) == 0) | |
1212 | Printf("\n\t"); | |
1213 | Printf(" %02x", *(u_char *)sp); | |
1214 | } | |
1215 | Printf("]\n"); | |
1216 | } | |
b7080c8e | 1217 | |
2b484d24 A |
1218 | #if !defined(IP_HDRINCL) && defined(IP_TTL) |
1219 | if (setsockopt(sndsock, IPPROTO_IP, IP_TTL, | |
1220 | (char *)&ttl, sizeof(ttl)) < 0) { | |
1221 | Fprintf(stderr, "%s: setsockopt ttl %d: %s\n", | |
1222 | prog, ttl, strerror(errno)); | |
1223 | exit(1); | |
1224 | } | |
1225 | #endif | |
1226 | ||
1227 | cc = sendto(sndsock, (char *)outip, | |
1228 | packlen, 0, &whereto, sizeof(whereto)); | |
1229 | if (cc < 0 || cc != packlen) { | |
1230 | if (cc < 0) | |
1231 | Fprintf(stderr, "%s: sendto: %s\n", | |
1232 | prog, strerror(errno)); | |
1233 | Printf("%s: wrote %s %d chars, ret=%d\n", | |
1234 | prog, hostname, packlen, cc); | |
1235 | (void)fflush(stdout); | |
b7080c8e A |
1236 | } |
1237 | } | |
1238 | ||
2b484d24 A |
1239 | #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) |
1240 | int | |
1241 | setpolicy(so, policy) | |
1242 | int so; | |
1243 | char *policy; | |
1244 | { | |
1245 | char *buf; | |
1246 | ||
1247 | buf = ipsec_set_policy(policy, strlen(policy)); | |
1248 | if (buf == NULL) { | |
1249 | warnx("%s", ipsec_strerror()); | |
1250 | return -1; | |
1251 | } | |
1252 | (void)setsockopt(so, IPPROTO_IP, IP_IPSEC_POLICY, | |
1253 | buf, ipsec_get_policylen(buf)); | |
1254 | ||
1255 | free(buf); | |
1256 | ||
1257 | return 0; | |
1258 | } | |
1259 | #endif | |
b7080c8e A |
1260 | |
1261 | double | |
2b484d24 | 1262 | deltaT(struct timeval *t1p, struct timeval *t2p) |
b7080c8e A |
1263 | { |
1264 | register double dt; | |
1265 | ||
1266 | dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + | |
1267 | (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; | |
1268 | return (dt); | |
1269 | } | |
1270 | ||
b7080c8e A |
1271 | /* |
1272 | * Convert an ICMP "type" field to a printable string. | |
1273 | */ | |
1274 | char * | |
2b484d24 | 1275 | pr_type(register u_char t) |
b7080c8e A |
1276 | { |
1277 | static char *ttab[] = { | |
1278 | "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable", | |
1279 | "Source Quench", "Redirect", "ICMP 6", "ICMP 7", | |
1280 | "Echo", "ICMP 9", "ICMP 10", "Time Exceeded", | |
1281 | "Param Problem", "Timestamp", "Timestamp Reply", "Info Request", | |
1282 | "Info Reply" | |
1283 | }; | |
1284 | ||
2b484d24 | 1285 | if (t > 16) |
b7080c8e A |
1286 | return("OUT-OF-RANGE"); |
1287 | ||
1288 | return(ttab[t]); | |
1289 | } | |
1290 | ||
b7080c8e | 1291 | int |
2b484d24 A |
1292 | packet_ok(register u_char *buf, int cc, register struct sockaddr_in *from, |
1293 | register int seq) | |
b7080c8e A |
1294 | { |
1295 | register struct icmp *icp; | |
2b484d24 A |
1296 | register u_char type, code; |
1297 | register int hlen; | |
b7080c8e | 1298 | #ifndef ARCHAIC |
2b484d24 | 1299 | register struct ip *ip; |
b7080c8e A |
1300 | |
1301 | ip = (struct ip *) buf; | |
1302 | hlen = ip->ip_hl << 2; | |
1303 | if (cc < hlen + ICMP_MINLEN) { | |
1304 | if (verbose) | |
1305 | Printf("packet too short (%d bytes) from %s\n", cc, | |
1306 | inet_ntoa(from->sin_addr)); | |
1307 | return (0); | |
1308 | } | |
1309 | cc -= hlen; | |
1310 | icp = (struct icmp *)(buf + hlen); | |
1311 | #else | |
1312 | icp = (struct icmp *)buf; | |
2b484d24 A |
1313 | #endif |
1314 | type = icp->icmp_type; | |
1315 | code = icp->icmp_code; | |
1316 | /* Path MTU Discovery (RFC1191) */ | |
1317 | if (code != ICMP_UNREACH_NEEDFRAG) | |
1318 | pmtu = 0; | |
1319 | else { | |
1320 | #ifdef HAVE_ICMP_NEXTMTU | |
1321 | pmtu = ntohs(icp->icmp_nextmtu); | |
1322 | #else | |
1323 | pmtu = ntohs(((struct my_pmtu *)&icp->icmp_void)->ipm_nextmtu); | |
1324 | #endif | |
1325 | } | |
1326 | if (type == ICMP_ECHOREPLY | |
1327 | && proto->num == IPPROTO_ICMP | |
1328 | && (*proto->check)((u_char *)icp, (u_char)seq)) | |
1329 | return -2; | |
b7080c8e A |
1330 | if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || |
1331 | type == ICMP_UNREACH) { | |
2b484d24 | 1332 | u_char *inner; |
b7080c8e A |
1333 | |
1334 | hip = &icp->icmp_ip; | |
9c859447 | 1335 | hiplen = ((u_char *)icp + cc) - (u_char *)hip; |
b7080c8e | 1336 | hlen = hip->ip_hl << 2; |
2b484d24 A |
1337 | inner = (u_char *)((u_char *)hip + hlen); |
1338 | if (hlen + 12 <= cc | |
1339 | && hip->ip_p == proto->num | |
1340 | && (*proto->check)(inner, (u_char)seq)) | |
1341 | return (type == ICMP_TIMXCEED ? -1 : code + 1); | |
b7080c8e A |
1342 | } |
1343 | #ifndef ARCHAIC | |
1344 | if (verbose) { | |
2b484d24 A |
1345 | register int i; |
1346 | u_int32_t *lp = (u_int32_t *)&icp->icmp_ip; | |
1347 | ||
1348 | Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr)); | |
1349 | Printf("%s: icmp type %d (%s) code %d\n", | |
1350 | inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code); | |
1351 | for (i = 4; i < cc ; i += sizeof(*lp)) | |
1352 | Printf("%2d: x%8.8x\n", i, *lp++); | |
b7080c8e | 1353 | } |
2b484d24 | 1354 | #endif |
b7080c8e A |
1355 | return(0); |
1356 | } | |
1357 | ||
2b484d24 A |
1358 | void |
1359 | icmp_prep(struct outdata *outdata) | |
1360 | { | |
1361 | struct icmp *const icmpheader = (struct icmp *) outp; | |
1362 | ||
1363 | icmpheader->icmp_type = ICMP_ECHO; | |
1364 | icmpheader->icmp_id = htons(ident); | |
1365 | icmpheader->icmp_seq = htons(outdata->seq); | |
1366 | icmpheader->icmp_cksum = 0; | |
1367 | icmpheader->icmp_cksum = in_cksum((u_short *)icmpheader, protlen); | |
1368 | if (icmpheader->icmp_cksum == 0) | |
1369 | icmpheader->icmp_cksum = 0xffff; | |
1370 | } | |
1371 | ||
1372 | int | |
1373 | icmp_check(const u_char *data, int seq) | |
1374 | { | |
1375 | struct icmp *const icmpheader = (struct icmp *) data; | |
1376 | ||
1377 | return (icmpheader->icmp_id == htons(ident) | |
1378 | && icmpheader->icmp_seq == htons(seq)); | |
1379 | } | |
1380 | ||
1381 | void | |
1382 | udp_prep(struct outdata *outdata) | |
1383 | { | |
1384 | struct udphdr *const outudp = (struct udphdr *) outp; | |
1385 | ||
9c859447 A |
1386 | outudp->uh_sport = htons(ident + (fixedPort ? outdata->seq : 0)); |
1387 | outudp->uh_dport = htons(port + (fixedPort ? 0 : outdata->seq)); | |
2b484d24 A |
1388 | outudp->uh_ulen = htons((u_short)protlen); |
1389 | outudp->uh_sum = 0; | |
1390 | if (doipcksum) { | |
1391 | u_short sum = p_cksum(outip, (u_short*)outudp, protlen); | |
1392 | outudp->uh_sum = (sum) ? sum : 0xffff; | |
1393 | } | |
1394 | ||
1395 | return; | |
1396 | } | |
1397 | ||
1398 | int | |
1399 | udp_check(const u_char *data, int seq) | |
1400 | { | |
1401 | struct udphdr *const udp = (struct udphdr *) data; | |
1402 | ||
9c859447 A |
1403 | return (ntohs(udp->uh_sport) == ident + (fixedPort ? seq : 0) && |
1404 | ntohs(udp->uh_dport) == port + (fixedPort ? 0 : seq)); | |
2b484d24 A |
1405 | } |
1406 | ||
1407 | void | |
1408 | tcp_prep(struct outdata *outdata) | |
1409 | { | |
1410 | struct tcphdr *const tcp = (struct tcphdr *) outp; | |
1411 | ||
1412 | tcp->th_sport = htons(ident); | |
9c859447 A |
1413 | tcp->th_dport = htons(port + (fixedPort ? 0 : outdata->seq)); |
1414 | tcp->th_seq = (tcp->th_sport << 16) | (tcp->th_dport + | |
1415 | (fixedPort ? outdata->seq : 0)); | |
2b484d24 A |
1416 | tcp->th_ack = 0; |
1417 | tcp->th_off = 5; | |
1418 | tcp->th_flags = TH_SYN; | |
1419 | tcp->th_sum = 0; | |
1420 | ||
1421 | if (doipcksum) { | |
1422 | u_short sum = p_cksum(outip, (u_short*)tcp, protlen); | |
1423 | tcp->th_sum = (sum) ? sum : 0xffff; | |
1424 | } | |
1425 | } | |
1426 | ||
1427 | int | |
1428 | tcp_check(const u_char *data, int seq) | |
1429 | { | |
1430 | struct tcphdr *const tcp = (struct tcphdr *) data; | |
1431 | ||
1432 | return (ntohs(tcp->th_sport) == ident | |
9c859447 A |
1433 | && ntohs(tcp->th_dport) == port + (fixedPort ? 0 : seq)) |
1434 | && tcp->th_seq == ((ident << 16) | (port + seq)); | |
2b484d24 | 1435 | } |
b7080c8e A |
1436 | |
1437 | void | |
2b484d24 | 1438 | gre_prep(struct outdata *outdata) |
b7080c8e | 1439 | { |
2b484d24 A |
1440 | struct grehdr *const gre = (struct grehdr *) outp; |
1441 | ||
1442 | gre->flags = htons(0x2001); | |
1443 | gre->proto = htons(port); | |
1444 | gre->length = 0; | |
1445 | gre->callId = htons(ident + outdata->seq); | |
1446 | } | |
1447 | ||
1448 | int | |
1449 | gre_check(const u_char *data, int seq) | |
1450 | { | |
1451 | struct grehdr *const gre = (struct grehdr *) data; | |
1452 | ||
1453 | return(ntohs(gre->proto) == port | |
1454 | && ntohs(gre->callId) == ident + seq); | |
1455 | } | |
1456 | ||
1457 | void | |
1458 | gen_prep(struct outdata *outdata) | |
1459 | { | |
1460 | u_int16_t *const ptr = (u_int16_t *) outp; | |
1461 | ||
1462 | ptr[0] = htons(ident); | |
1463 | ptr[1] = htons(port + outdata->seq); | |
1464 | } | |
1465 | ||
1466 | int | |
1467 | gen_check(const u_char *data, int seq) | |
1468 | { | |
1469 | u_int16_t *const ptr = (u_int16_t *) data; | |
1470 | ||
1471 | return(ntohs(ptr[0]) == ident | |
1472 | && ntohs(ptr[1]) == port + seq); | |
1473 | } | |
1474 | ||
1475 | void | |
1476 | print(register u_char *buf, register int cc, register struct sockaddr_in *from) | |
1477 | { | |
1478 | register struct ip *ip; | |
1479 | register int hlen; | |
b7080c8e A |
1480 | |
1481 | ip = (struct ip *) buf; | |
1482 | hlen = ip->ip_hl << 2; | |
1483 | cc -= hlen; | |
1484 | ||
9c859447 A |
1485 | if (as_path) |
1486 | Printf(" [AS%d]", as_lookup(asn, &from->sin_addr)); | |
1487 | ||
b7080c8e A |
1488 | if (nflag) |
1489 | Printf(" %s", inet_ntoa(from->sin_addr)); | |
1490 | else | |
1491 | Printf(" %s (%s)", inetname(from->sin_addr), | |
2b484d24 | 1492 | inet_ntoa(from->sin_addr)); |
b7080c8e A |
1493 | |
1494 | if (verbose) | |
2b484d24 | 1495 | Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst)); |
b7080c8e A |
1496 | } |
1497 | ||
2b484d24 A |
1498 | /* |
1499 | * Checksum routine for UDP and TCP headers. | |
1500 | */ | |
1501 | u_short | |
1502 | p_cksum(struct ip *ip, u_short *data, int len) | |
1503 | { | |
1504 | static struct ipovly ipo; | |
1505 | u_short sumh, sumd; | |
9c859447 | 1506 | u_int32_t sumt; |
2b484d24 A |
1507 | |
1508 | ipo.ih_pr = ip->ip_p; | |
1509 | ipo.ih_len = htons(len); | |
1510 | ipo.ih_src = ip->ip_src; | |
1511 | ipo.ih_dst = ip->ip_dst; | |
1512 | ||
1513 | sumh = in_cksum((u_short*)&ipo, sizeof(ipo)); /* pseudo ip hdr cksum */ | |
1514 | sumd = in_cksum((u_short*)data, len); /* payload data cksum */ | |
1515 | sumt = (sumh << 16) | (sumd); | |
1516 | ||
1517 | return ~in_cksum((u_short*)&sumt, sizeof(sumt)); | |
1518 | } | |
b7080c8e | 1519 | |
b7080c8e A |
1520 | /* |
1521 | * Checksum routine for Internet Protocol family headers (C Version) | |
1522 | */ | |
1523 | u_short | |
2b484d24 | 1524 | in_cksum(register u_short *addr, register int len) |
b7080c8e A |
1525 | { |
1526 | register int nleft = len; | |
1527 | register u_short *w = addr; | |
1528 | register u_short answer; | |
1529 | register int sum = 0; | |
1530 | ||
1531 | /* | |
1532 | * Our algorithm is simple, using a 32 bit accumulator (sum), | |
1533 | * we add sequential 16 bit words to it, and at the end, fold | |
1534 | * back all the carry bits from the top 16 bits into the lower | |
1535 | * 16 bits. | |
1536 | */ | |
1537 | while (nleft > 1) { | |
1538 | sum += *w++; | |
1539 | nleft -= 2; | |
1540 | } | |
1541 | ||
1542 | /* mop up an odd byte, if necessary */ | |
1543 | if (nleft == 1) | |
1544 | sum += *(u_char *)w; | |
1545 | ||
1546 | /* | |
1547 | * add back carry outs from top 16 bits to low 16 bits | |
1548 | */ | |
1549 | sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ | |
1550 | sum += (sum >> 16); /* add carry */ | |
1551 | answer = ~sum; /* truncate to 16 bits */ | |
1552 | return (answer); | |
1553 | } | |
b7080c8e A |
1554 | |
1555 | /* | |
1556 | * Subtract 2 timeval structs: out = out - in. | |
2b484d24 | 1557 | * Out is assumed to be within about LONG_MAX seconds of in. |
b7080c8e A |
1558 | */ |
1559 | void | |
2b484d24 | 1560 | tvsub(register struct timeval *out, register struct timeval *in) |
b7080c8e | 1561 | { |
2b484d24 | 1562 | |
b7080c8e | 1563 | if ((out->tv_usec -= in->tv_usec) < 0) { |
2b484d24 | 1564 | --out->tv_sec; |
b7080c8e A |
1565 | out->tv_usec += 1000000; |
1566 | } | |
1567 | out->tv_sec -= in->tv_sec; | |
1568 | } | |
1569 | ||
b7080c8e A |
1570 | /* |
1571 | * Construct an Internet address representation. | |
1572 | * If the nflag has been supplied, give | |
1573 | * numeric value, otherwise try for symbolic name. | |
1574 | */ | |
1575 | char * | |
2b484d24 | 1576 | inetname(struct in_addr in) |
b7080c8e A |
1577 | { |
1578 | register char *cp; | |
2b484d24 | 1579 | register struct hostent *hp; |
b7080c8e | 1580 | static int first = 1; |
2b484d24 | 1581 | static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1]; |
b7080c8e A |
1582 | |
1583 | if (first && !nflag) { | |
1584 | first = 0; | |
2b484d24 A |
1585 | if (gethostname(domain, sizeof(domain) - 1) < 0) |
1586 | domain[0] = '\0'; | |
1587 | else { | |
1588 | cp = strchr(domain, '.'); | |
1589 | if (cp == NULL) { | |
1590 | hp = gethostbyname(domain); | |
1591 | if (hp != NULL) | |
1592 | cp = strchr(hp->h_name, '.'); | |
1593 | } | |
1594 | if (cp == NULL) | |
1595 | domain[0] = '\0'; | |
1596 | else { | |
1597 | ++cp; | |
1598 | (void)strncpy(domain, cp, sizeof(domain) - 1); | |
1599 | domain[sizeof(domain) - 1] = '\0'; | |
1600 | } | |
1601 | } | |
b7080c8e | 1602 | } |
b7080c8e | 1603 | if (!nflag && in.s_addr != INADDR_ANY) { |
2b484d24 A |
1604 | hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET); |
1605 | if (hp != NULL) { | |
1606 | if ((cp = strchr(hp->h_name, '.')) != NULL && | |
1607 | strcmp(cp + 1, domain) == 0) | |
1608 | *cp = '\0'; | |
1609 | (void)strncpy(line, hp->h_name, sizeof(line) - 1); | |
1610 | line[sizeof(line) - 1] = '\0'; | |
1611 | return (line); | |
b7080c8e A |
1612 | } |
1613 | } | |
2b484d24 A |
1614 | return (inet_ntoa(in)); |
1615 | } | |
1616 | ||
1617 | struct hostinfo * | |
1618 | gethostinfo(register char *hostname) | |
1619 | { | |
1620 | register int n; | |
1621 | register struct hostent *hp; | |
1622 | register struct hostinfo *hi; | |
1623 | register char **p; | |
1624 | register u_int32_t addr, *ap; | |
1625 | ||
1626 | if (strlen(hostname) > 64) { | |
1627 | Fprintf(stderr, "%s: hostname \"%.32s...\" is too long\n", | |
1628 | prog, hostname); | |
1629 | exit(1); | |
1630 | } | |
1631 | hi = calloc(1, sizeof(*hi)); | |
1632 | if (hi == NULL) { | |
1633 | Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno)); | |
1634 | exit(1); | |
b7080c8e | 1635 | } |
2b484d24 A |
1636 | addr = inet_addr(hostname); |
1637 | if ((int32_t)addr != -1) { | |
1638 | hi->name = strdup(hostname); | |
1639 | hi->n = 1; | |
1640 | hi->addrs = calloc(1, sizeof(hi->addrs[0])); | |
1641 | if (hi->addrs == NULL) { | |
1642 | Fprintf(stderr, "%s: calloc %s\n", | |
1643 | prog, strerror(errno)); | |
1644 | exit(1); | |
1645 | } | |
1646 | hi->addrs[0] = addr; | |
1647 | return (hi); | |
1648 | } | |
1649 | ||
1650 | hp = gethostbyname(hostname); | |
1651 | if (hp == NULL) { | |
1652 | Fprintf(stderr, "%s: unknown host %s\n", prog, hostname); | |
1653 | exit(1); | |
1654 | } | |
1655 | if (hp->h_addrtype != AF_INET || hp->h_length != 4) { | |
1656 | Fprintf(stderr, "%s: bad host %s\n", prog, hostname); | |
1657 | exit(1); | |
1658 | } | |
1659 | hi->name = strdup(hp->h_name); | |
1660 | for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p) | |
1661 | continue; | |
1662 | hi->n = n; | |
1663 | hi->addrs = calloc(n, sizeof(hi->addrs[0])); | |
1664 | if (hi->addrs == NULL) { | |
1665 | Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno)); | |
1666 | exit(1); | |
1667 | } | |
1668 | for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p) | |
1669 | memcpy(ap, *p, sizeof(*ap)); | |
1670 | return (hi); | |
1671 | } | |
1672 | ||
1673 | void | |
1674 | freehostinfo(register struct hostinfo *hi) | |
1675 | { | |
1676 | if (hi->name != NULL) { | |
1677 | free(hi->name); | |
1678 | hi->name = NULL; | |
1679 | } | |
1680 | free((char *)hi->addrs); | |
1681 | free((char *)hi); | |
1682 | } | |
1683 | ||
1684 | void | |
1685 | getaddr(register u_int32_t *ap, register char *hostname) | |
1686 | { | |
1687 | register struct hostinfo *hi; | |
1688 | ||
1689 | hi = gethostinfo(hostname); | |
1690 | *ap = hi->addrs[0]; | |
1691 | freehostinfo(hi); | |
b7080c8e A |
1692 | } |
1693 | ||
1694 | void | |
2b484d24 | 1695 | setsin(register struct sockaddr_in *sin, register u_int32_t addr) |
b7080c8e | 1696 | { |
2b484d24 A |
1697 | |
1698 | memset(sin, 0, sizeof(*sin)); | |
1699 | #ifdef HAVE_SOCKADDR_SA_LEN | |
1700 | sin->sin_len = sizeof(*sin); | |
1701 | #endif | |
1702 | sin->sin_family = AF_INET; | |
1703 | sin->sin_addr.s_addr = addr; | |
1704 | } | |
1705 | ||
1706 | /* String to value with optional min and max. Handles decimal and hex. */ | |
1707 | int | |
1708 | str2val(register const char *str, register const char *what, | |
1709 | register int mi, register int ma) | |
1710 | { | |
1711 | register const char *cp; | |
1712 | register int val; | |
1713 | char *ep; | |
1714 | ||
1715 | if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { | |
1716 | cp = str + 2; | |
1717 | val = (int)strtol(cp, &ep, 16); | |
1718 | } else | |
1719 | val = (int)strtol(str, &ep, 10); | |
1720 | if (*ep != '\0') { | |
1721 | Fprintf(stderr, "%s: \"%s\" bad value for %s \n", | |
1722 | prog, str, what); | |
1723 | exit(1); | |
1724 | } | |
1725 | if (val < mi && mi >= 0) { | |
1726 | if (mi == 0) | |
1727 | Fprintf(stderr, "%s: %s must be >= %d\n", | |
1728 | prog, what, mi); | |
1729 | else | |
1730 | Fprintf(stderr, "%s: %s must be > %d\n", | |
1731 | prog, what, mi - 1); | |
1732 | exit(1); | |
1733 | } | |
1734 | if (val > ma && ma >= 0) { | |
1735 | Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma); | |
1736 | exit(1); | |
1737 | } | |
1738 | return (val); | |
1739 | } | |
1740 | ||
1741 | struct outproto * | |
1742 | setproto(char *pname) | |
1743 | { | |
1744 | struct outproto *proto; | |
1745 | int i; | |
1746 | ||
1747 | for (i = 0; protos[i].name != NULL; i++) { | |
1748 | if (strcasecmp(protos[i].name, pname) == 0) { | |
1749 | break; | |
1750 | } | |
1751 | } | |
1752 | proto = &protos[i]; | |
1753 | if (proto->name == NULL) { /* generic handler */ | |
1754 | struct protoent *pe; | |
9c859447 | 1755 | u_int32_t pnum; |
2b484d24 A |
1756 | |
1757 | /* Determine the IP protocol number */ | |
1758 | if ((pe = getprotobyname(pname)) != NULL) | |
1759 | pnum = pe->p_proto; | |
1760 | else | |
1761 | pnum = str2val(optarg, "proto number", 1, 255); | |
1762 | proto->num = pnum; | |
1763 | } | |
1764 | return proto; | |
1765 | } | |
1766 | ||
9c859447 A |
1767 | void |
1768 | pkt_compare(const u_char *a, int la, const u_char *b, int lb) { | |
1769 | int l; | |
1770 | int i; | |
1771 | ||
1772 | for (i = 0; i < la; i++) | |
1773 | Printf("%02x", (unsigned int)a[i]); | |
1774 | Printf("\n"); | |
1775 | l = (la <= lb) ? la : lb; | |
1776 | for (i = 0; i < l; i++) | |
1777 | if (a[i] == b[i]) | |
1778 | Printf("__"); | |
1779 | else | |
1780 | Printf("%02x", (unsigned int)b[i]); | |
1781 | for (; i < lb; i++) | |
1782 | Printf("%02x", (unsigned int)b[i]); | |
1783 | Printf("\n"); | |
1784 | } | |
1785 | ||
1786 | ||
2b484d24 A |
1787 | void |
1788 | usage(void) | |
1789 | { | |
1790 | extern char version[]; | |
1791 | ||
1792 | Fprintf(stderr, "Version %s\n", version); | |
1793 | Fprintf(stderr, | |
9c859447 A |
1794 | "Usage: %s [-adDeFInrSvx] [-A as_server] [-f first_ttl] [-g gateway] [-i iface]\n" |
1795 | "\t[-M first_ttl] [-m max_ttl] [-p port] [-P proto] [-q nqueries] [-s src_addr]\n" | |
2b484d24 | 1796 | "\t[-t tos] [-w waittime] [-z pausemsecs] host [packetlen]\n", prog); |
b7080c8e A |
1797 | exit(1); |
1798 | } |