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