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