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