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