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