]> git.saurik.com Git - apple/network_cmds.git/blob - traceroute.tproj/traceroute.c
network_cmds-306.tar.gz
[apple/network_cmds.git] / traceroute.tproj / traceroute.c
1 /*
2 * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
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.
20 */
21
22 #ifndef lint
23 static const char copyright[] =
24 "@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000\n\
25 The Regents of the University of California. All rights reserved.\n";
26 #if 0
27 static const char rcsid[] =
28 "@(#)$Id: traceroute.c,v 1.4 2006/02/07 06:22:57 lindak Exp $ (LBL)";
29 #endif
30 static const char rcsid[] =
31 "$FreeBSD: src/contrib/traceroute/traceroute.c,v 1.26 2004/04/17 18:44:23 pb Exp $";
32 #endif
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
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
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.
60 * traceroute to nis.nsf.net (35.1.1.48), 64 hops max, 56 byte packet
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.
80 * traceroute to allspice.lcs.mit.edu (18.26.0.115), 64 hops max
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 *
201 * -- Van Jacobson (van@ee.lbl.gov)
202 * Tue Dec 20 03:50:13 PST 1988
203 */
204
205 #include <sys/param.h>
206 #include <sys/file.h>
207 #include <sys/ioctl.h>
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>
216
217 #include <netinet/in_systm.h>
218 #include <netinet/in.h>
219 #include <netinet/ip.h>
220 #include <netinet/ip_var.h>
221 #include <netinet/ip_icmp.h>
222 #include <netinet/udp.h>
223 #include <netinet/udp_var.h>
224 #include <netinet/tcp.h>
225 #include <netinet/tcpip.h>
226
227 #include <arpa/inet.h>
228
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>
242 #include <netdb.h>
243 #include <stdio.h>
244 #include <stdlib.h>
245 #include <string.h>
246 #include <unistd.h>
247
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 */
256 #endif
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"
267
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
273 #endif
274
275 #define Fprintf (void)fprintf
276 #define Printf (void)printf
277
278 /* What a GRE packet header looks like */
279 struct 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 */
293 struct hostinfo {
294 char *name;
295 int n;
296 u_int32_t *addrs;
297 };
298
299 /* Data section of the probe packet */
300 struct outdata {
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
306 #ifndef HAVE_ICMP_NEXTMTU
307 /* Path MTU Discovery (RFC1191) */
308 struct my_pmtu {
309 u_short ipm_void;
310 u_short ipm_nextmtu;
311 };
312 #endif
313
314 u_char packet[512]; /* last inbound (icmp) packet */
315
316 struct ip *outip; /* last output ip packet */
317 u_char *outp; /* last output inner protocol packet */
318
319 /* loose source route gateway list (including room for final destination) */
320 u_int32_t gwlist[NGATEWAYS + 1];
321
322 int s; /* receive (icmp) socket file descriptor */
323 int sndsock; /* send (udp) socket file descriptor */
324
325 struct sockaddr whereto; /* Who to try to reach */
326 struct sockaddr wherefrom; /* Who we are */
327 int packlen; /* total length of packet */
328 int protlen; /* length of protocol part of packet */
329 int minpacket; /* min ip packet size */
330 int maxpacket = 32 * 1024; /* max ip packet size */
331 int pmtu; /* Path MTU Discovery (RFC1191) */
332 u_int pausemsecs;
333
334 char *prog;
335 char *source;
336 char *hostname;
337 char *device;
338 static const char devnull[] = "/dev/null";
339
340 int nprobes = 3;
341 int max_ttl;
342 int first_ttl = 1;
343 u_short ident;
344 u_short port; /* protocol specific base "port" */
345
346 int options; /* socket options */
347 int verbose;
348 int waittime = 5; /* time to wait for response (in seconds) */
349 int nflag; /* print addresses numerically */
350 int disable_seq = 0;
351 #ifdef CANT_HACK_IPCKSUM
352 int doipcksum = 0; /* don't calculate ip checksums by default */
353 #else
354 int doipcksum = 1; /* calculate ip checksums by default */
355 #endif
356 int optlen; /* length of ip options */
357
358 extern int optind;
359 extern int opterr;
360 extern char *optarg;
361
362 /* Forwards */
363 double deltaT(struct timeval *, struct timeval *);
364 void freehostinfo(struct hostinfo *);
365 void getaddr(u_int32_t *, char *);
366 struct hostinfo *gethostinfo(char *);
367 u_short in_cksum(u_short *, int);
368 char *inetname(struct in_addr);
369 int main(int, char **);
370 u_short p_cksum(struct ip *, u_short *, int);
371 int packet_ok(u_char *, int, struct sockaddr_in *, int);
372 char *pr_type(u_char);
373 void print(u_char *, int, struct sockaddr_in *);
374 #ifdef IPSEC
375 int setpolicy __P((int so, char *policy));
376 #endif
377 void send_probe(int, int);
378 struct outproto *setproto(char *);
379 int str2val(const char *, const char *, int, int);
380 void tvsub(struct timeval *, struct timeval *);
381 void usage(void);
382 int wait_for_reply(int, struct sockaddr_in *, const struct timeval *);
383 #ifndef HAVE_USLEEP
384 int usleep(u_int);
385 #endif
386
387 void udp_prep(struct outdata *);
388 int udp_check(const u_char *, int);
389 void tcp_prep(struct outdata *);
390 int tcp_check(const u_char *, int);
391 void gre_prep(struct outdata *);
392 int gre_check(const u_char *, int);
393 void gen_prep(struct outdata *);
394 int gen_check(const u_char *, int);
395 void icmp_prep(struct outdata *);
396 int icmp_check(const u_char *, int);
397
398 /* Descriptor structure for each outgoing protocol we support */
399 struct outproto {
400 char *name; /* name of protocol */
401 u_char num; /* IP protocol number */
402 u_short hdrlen; /* max size of protocol header */
403 u_short port; /* default base protocol-specific "port" */
404 void (*prepare)(struct outdata *);
405 /* finish preparing an outgoing packet */
406 int (*check)(const u_char *, int);
407 /* check an incoming packet */
408 };
409
410 /* List of supported protocols. The first one is the default. The last
411 one is the handler for generic protocols not explicitly listed. */
412 struct outproto protos[] = {
413 {
414 "udp",
415 IPPROTO_UDP,
416 sizeof(struct udphdr),
417 32768 + 666,
418 udp_prep,
419 udp_check
420 },
421 {
422 "tcp",
423 IPPROTO_TCP,
424 sizeof(struct tcphdr),
425 32768 + 666,
426 tcp_prep,
427 tcp_check
428 },
429 {
430 "gre",
431 IPPROTO_GRE,
432 sizeof(struct grehdr),
433 GRE_PPTP_PROTO,
434 gre_prep,
435 gre_check
436 },
437 {
438 "icmp",
439 IPPROTO_ICMP,
440 sizeof(struct icmp),
441 0,
442 icmp_prep,
443 icmp_check
444 },
445 {
446 NULL,
447 0,
448 2 * sizeof(u_short),
449 0,
450 gen_prep,
451 gen_check
452 },
453 };
454 struct outproto *proto = &protos[0];
455
456 int
457 main(int argc, char **argv)
458 {
459 register int op, code, n;
460 register char *cp;
461 register const char *err;
462 register u_int32_t *ap;
463 register struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom;
464 register struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
465 register struct hostinfo *hi;
466 int on = 1;
467 register struct protoent *pe;
468 register int ttl, probe, i;
469 register int seq = 0;
470 int tos = 0, settos = 0;
471 register int lsrr = 0;
472 register u_short off = 0;
473 struct ifaddrlist *al;
474 char errbuf[132];
475 int requestPort = -1;
476 int sump = 0;
477 int sockerrno = 0;
478
479 /* Insure the socket fds won't be 0, 1 or 2 */
480 if (open(devnull, O_RDONLY) < 0 ||
481 open(devnull, O_RDONLY) < 0 ||
482 open(devnull, O_RDONLY) < 0) {
483 Fprintf(stderr, "%s: open \"%s\": %s\n",
484 prog, devnull, strerror(errno));
485 exit(1);
486 }
487 /*
488 * Do the setuid-required stuff first, then lose priveleges ASAP.
489 * Do error checking for these two calls where they appeared in
490 * the original code.
491 */
492 cp = "icmp";
493 pe = getprotobyname(cp);
494 if (pe) {
495 if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
496 sockerrno = errno;
497 else if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
498 sockerrno = errno;
499 }
500
501 setuid(getuid());
502
503 #ifdef IPCTL_DEFTTL
504 {
505 int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL };
506 size_t sz = sizeof(max_ttl);
507
508 if (sysctl(mib, 4, &max_ttl, &sz, NULL, 0) == -1) {
509 perror("sysctl(net.inet.ip.ttl)");
510 exit(1);
511 }
512 }
513 #else
514 max_ttl = 30;
515 #endif
516
517 if (argv[0] == NULL)
518 prog = "traceroute";
519 else if ((cp = strrchr(argv[0], '/')) != NULL)
520 prog = cp + 1;
521 else
522 prog = argv[0];
523
524 opterr = 0;
525 while ((op = getopt(argc, argv, "dFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF)
526 switch (op) {
527
528 case 'd':
529 options |= SO_DEBUG;
530 break;
531
532 case 'f':
533 case 'M': /* FreeBSD compat. */
534 first_ttl = str2val(optarg, "first ttl", 1, 255);
535 break;
536
537 case 'F':
538 off = IP_DF;
539 break;
540
541 case 'g':
542 if (lsrr >= NGATEWAYS) {
543 Fprintf(stderr,
544 "%s: No more than %d gateways\n",
545 prog, NGATEWAYS);
546 exit(1);
547 }
548 getaddr(gwlist + lsrr, optarg);
549 ++lsrr;
550 break;
551
552 case 'i':
553 device = optarg;
554 break;
555
556 case 'I':
557 proto = setproto("icmp");
558 break;
559
560 case 'm':
561 max_ttl = str2val(optarg, "max ttl", 1, 255);
562 break;
563
564 case 'N':
565 ++disable_seq;
566 break;
567
568 case 'n':
569 ++nflag;
570 break;
571
572 case 'P':
573 proto = setproto(optarg);
574 break;
575
576 case 'p':
577 requestPort = (u_short)str2val(optarg, "port",
578 1, (1 << 16) - 1);
579 break;
580
581 case 'q':
582 nprobes = str2val(optarg, "nprobes", 1, -1);
583 break;
584
585 case 'r':
586 options |= SO_DONTROUTE;
587 break;
588
589 case 's':
590 /*
591 * set the ip source address of the outbound
592 * probe (e.g., on a multi-homed host).
593 */
594 source = optarg;
595 break;
596
597 case 'S':
598 sump = 1;
599 break;
600
601 case 't':
602 tos = str2val(optarg, "tos", 0, 255);
603 ++settos;
604 break;
605
606 case 'v':
607 ++verbose;
608 break;
609
610 case 'x':
611 doipcksum = (doipcksum == 0);
612 break;
613
614 case 'w':
615 waittime = str2val(optarg, "wait time",
616 2, 24 * 60 * 60);
617 break;
618
619 case 'z':
620 pausemsecs = str2val(optarg, "pause msecs",
621 0, 60 * 60 * 1000);
622 break;
623
624 default:
625 usage();
626 }
627
628 /* Set requested port, if any, else default for this protocol */
629 port = (requestPort != -1) ? requestPort : proto->port;
630
631 if (first_ttl > max_ttl) {
632 Fprintf(stderr,
633 "%s: first ttl (%d) may not be greater than max ttl (%d)\n",
634 prog, first_ttl, max_ttl);
635 exit(1);
636 }
637
638 if (!doipcksum)
639 Fprintf(stderr, "%s: Warning: ip checksums disabled\n", prog);
640
641 if (lsrr > 0)
642 optlen = (lsrr + 1) * sizeof(gwlist[0]);
643 minpacket = sizeof(*outip) + proto->hdrlen + sizeof(struct outdata) + optlen;
644 packlen = minpacket; /* minimum sized packet */
645
646 /* Process destination and optional packet size */
647 switch (argc - optind) {
648
649 case 2:
650 packlen = str2val(argv[optind + 1],
651 "packet length", minpacket, maxpacket);
652 /* Fall through */
653
654 case 1:
655 hostname = argv[optind];
656 hi = gethostinfo(hostname);
657 setsin(to, hi->addrs[0]);
658 if (hi->n > 1)
659 Fprintf(stderr,
660 "%s: Warning: %s has multiple addresses; using %s\n",
661 prog, hostname, inet_ntoa(to->sin_addr));
662 hostname = hi->name;
663 hi->name = NULL;
664 freehostinfo(hi);
665 break;
666
667 default:
668 usage();
669 }
670
671 #ifdef HAVE_SETLINEBUF
672 setlinebuf (stdout);
673 #else
674 setvbuf(stdout, NULL, _IOLBF, 0);
675 #endif
676
677 protlen = packlen - sizeof(*outip) - optlen;
678
679 outip = (struct ip *)malloc((unsigned)packlen);
680 if (outip == NULL) {
681 Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno));
682 exit(1);
683 }
684 memset((char *)outip, 0, packlen);
685
686 outip->ip_v = IPVERSION;
687 if (settos)
688 outip->ip_tos = tos;
689 #ifdef BYTESWAP_IP_HDR
690 outip->ip_len = htons(packlen);
691 outip->ip_off = htons(off);
692 #else
693 outip->ip_len = packlen;
694 outip->ip_off = off;
695 #endif
696 outip->ip_p = proto->num;
697 outp = (u_char *)(outip + 1);
698 #ifdef HAVE_RAW_OPTIONS
699 if (lsrr > 0) {
700 register u_char *optlist;
701
702 optlist = outp;
703 outp += optlen;
704
705 /* final hop */
706 gwlist[lsrr] = to->sin_addr.s_addr;
707
708 outip->ip_dst.s_addr = gwlist[0];
709
710 /* force 4 byte alignment */
711 optlist[0] = IPOPT_NOP;
712 /* loose source route option */
713 optlist[1] = IPOPT_LSRR;
714 i = lsrr * sizeof(gwlist[0]);
715 optlist[2] = i + 3;
716 /* Pointer to LSRR addresses */
717 optlist[3] = IPOPT_MINOFF;
718 memcpy(optlist + 4, gwlist + 1, i);
719 } else
720 #endif
721 outip->ip_dst = to->sin_addr;
722
723 outip->ip_hl = (outp - (u_char *)outip) >> 2;
724 ident = (getpid() & 0xffff) | 0x8000;
725
726 if (pe == NULL) {
727 Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
728 exit(1);
729 }
730 if (s < 0) {
731 errno = sockerrno;
732 Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno));
733 exit(1);
734 }
735 if (options & SO_DEBUG)
736 (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
737 sizeof(on));
738 if (options & SO_DONTROUTE)
739 (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
740 sizeof(on));
741
742 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
743 if (setpolicy(s, "in bypass") < 0)
744 errx(1, "%s", ipsec_strerror());
745
746 if (setpolicy(s, "out bypass") < 0)
747 errx(1, "%s", ipsec_strerror());
748 #endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
749
750 if (sndsock < 0) {
751 errno = sockerrno;
752 Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno));
753 exit(1);
754 }
755
756 #if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS)
757 if (lsrr > 0) {
758 u_char optlist[MAX_IPOPTLEN];
759
760 cp = "ip";
761 if ((pe = getprotobyname(cp)) == NULL) {
762 Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
763 exit(1);
764 }
765
766 /* final hop */
767 gwlist[lsrr] = to->sin_addr.s_addr;
768 ++lsrr;
769
770 /* force 4 byte alignment */
771 optlist[0] = IPOPT_NOP;
772 /* loose source route option */
773 optlist[1] = IPOPT_LSRR;
774 i = lsrr * sizeof(gwlist[0]);
775 optlist[2] = i + 3;
776 /* Pointer to LSRR addresses */
777 optlist[3] = IPOPT_MINOFF;
778 memcpy(optlist + 4, gwlist, i);
779
780 if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS,
781 (char *)optlist, i + sizeof(gwlist[0]))) < 0) {
782 Fprintf(stderr, "%s: IP_OPTIONS: %s\n",
783 prog, strerror(errno));
784 exit(1);
785 }
786 }
787 #endif
788
789 #ifdef SO_SNDBUF
790 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
791 sizeof(packlen)) < 0) {
792 Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno));
793 exit(1);
794 }
795 #endif
796 #ifdef IP_HDRINCL
797 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
798 sizeof(on)) < 0) {
799 Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog, strerror(errno));
800 exit(1);
801 }
802 #else
803 #ifdef IP_TOS
804 if (settos && setsockopt(sndsock, IPPROTO_IP, IP_TOS,
805 (char *)&tos, sizeof(tos)) < 0) {
806 Fprintf(stderr, "%s: setsockopt tos %d: %s\n",
807 prog, tos, strerror(errno));
808 exit(1);
809 }
810 #endif
811 #endif
812 if (options & SO_DEBUG)
813 (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
814 sizeof(on));
815 if (options & SO_DONTROUTE)
816 (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
817 sizeof(on));
818
819 /* Get the interface address list */
820 n = ifaddrlist(&al, errbuf);
821 if (n < 0) {
822 Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf);
823 exit(1);
824 }
825 if (n == 0) {
826 Fprintf(stderr,
827 "%s: Can't find any network interfaces\n", prog);
828 exit(1);
829 }
830
831 /* Look for a specific device */
832 if (device != NULL) {
833 for (i = n; i > 0; --i, ++al)
834 if (strcmp(device, al->device) == 0)
835 break;
836 if (i <= 0) {
837 Fprintf(stderr, "%s: Can't find interface %.32s\n",
838 prog, device);
839 exit(1);
840 }
841 }
842
843 /* Determine our source address */
844 if (source == NULL) {
845 /*
846 * If a device was specified, use the interface address.
847 * Otherwise, try to determine our source address.
848 */
849 if (device != NULL)
850 setsin(from, al->addr);
851 else if ((err = findsaddr(to, from)) != NULL) {
852 Fprintf(stderr, "%s: findsaddr: %s\n",
853 prog, err);
854 exit(1);
855 }
856 } else {
857 hi = gethostinfo(source);
858 source = hi->name;
859 hi->name = NULL;
860 /*
861 * If the device was specified make sure it
862 * corresponds to the source address specified.
863 * Otherwise, use the first address (and warn if
864 * there are more than one).
865 */
866 if (device != NULL) {
867 for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
868 if (*ap == al->addr)
869 break;
870 if (i <= 0) {
871 Fprintf(stderr,
872 "%s: %s is not on interface %.32s\n",
873 prog, source, device);
874 exit(1);
875 }
876 setsin(from, *ap);
877 } else {
878 setsin(from, hi->addrs[0]);
879 if (hi->n > 1)
880 Fprintf(stderr,
881 "%s: Warning: %s has multiple addresses; using %s\n",
882 prog, source, inet_ntoa(from->sin_addr));
883 }
884 freehostinfo(hi);
885 }
886
887 outip->ip_src = from->sin_addr;
888
889 /* Check the source address (-s), if any, is valid */
890 if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) {
891 Fprintf(stderr, "%s: bind: %s\n",
892 prog, strerror(errno));
893 exit (1);
894 }
895
896 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
897 if (setpolicy(sndsock, "in bypass") < 0)
898 errx(1, "%s", ipsec_strerror());
899
900 if (setpolicy(sndsock, "out bypass") < 0)
901 errx(1, "%s", ipsec_strerror());
902 #endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
903
904 Fprintf(stderr, "%s to %s (%s)",
905 prog, hostname, inet_ntoa(to->sin_addr));
906 if (source)
907 Fprintf(stderr, " from %s", source);
908 Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
909 (void)fflush(stderr);
910
911 for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
912 u_int32_t lastaddr = 0;
913 int gotlastaddr = 0;
914 int got_there = 0;
915 int unreachable = 0;
916 int sentfirst = 0;
917 int loss;
918
919 Printf("%2d ", ttl);
920 for (probe = 0, loss = 0; probe < nprobes; ++probe) {
921 register int cc;
922 struct timeval t1, t2;
923 struct timezone tz;
924 register struct ip *ip;
925 struct outdata outdata;
926
927 if (sentfirst && pausemsecs > 0)
928 usleep(pausemsecs * 1000);
929 /* Prepare outgoing data */
930 if (disable_seq) {
931 outdata.seq = seq;
932 } else {
933 outdata.seq = ++seq;
934 }
935 outdata.ttl = ttl;
936
937 /* Avoid alignment problems by copying bytewise: */
938 (void)gettimeofday(&t1, &tz);
939 memcpy(&outdata.tv, &t1, sizeof(outdata.tv));
940
941 /* Finalize and send packet */
942 (*proto->prepare)(&outdata);
943 send_probe(seq, ttl);
944 ++sentfirst;
945
946 /* Wait for a reply */
947 while ((cc = wait_for_reply(s, from, &t1)) != 0) {
948 double T;
949 int precis;
950
951 (void)gettimeofday(&t2, &tz);
952 i = packet_ok(packet, cc, from, seq);
953 /* Skip short packet */
954 if (i == 0)
955 continue;
956 if (!gotlastaddr ||
957 from->sin_addr.s_addr != lastaddr) {
958 print(packet, cc, from);
959 lastaddr = from->sin_addr.s_addr;
960 ++gotlastaddr;
961 }
962 T = deltaT(&t1, &t2);
963 #ifdef SANE_PRECISION
964 if (T >= 1000.0)
965 precis = 0;
966 else if (T >= 100.0)
967 precis = 1;
968 else if (T >= 10.0)
969 precis = 2;
970 else
971 #endif
972 precis = 3;
973 Printf(" %.*f ms", precis, T);
974 if (i == -2) {
975 #ifndef ARCHAIC
976 ip = (struct ip *)packet;
977 if (ip->ip_ttl <= 1)
978 Printf(" !");
979 #endif
980 ++got_there;
981 break;
982 }
983 /* time exceeded in transit */
984 if (i == -1)
985 break;
986 code = i - 1;
987 switch (code) {
988
989 case ICMP_UNREACH_PORT:
990 #ifndef ARCHAIC
991 ip = (struct ip *)packet;
992 if (ip->ip_ttl <= 1)
993 Printf(" !");
994 #endif
995 ++got_there;
996 break;
997
998 case ICMP_UNREACH_NET:
999 ++unreachable;
1000 Printf(" !N");
1001 break;
1002
1003 case ICMP_UNREACH_HOST:
1004 ++unreachable;
1005 Printf(" !H");
1006 break;
1007
1008 case ICMP_UNREACH_PROTOCOL:
1009 ++got_there;
1010 Printf(" !P");
1011 break;
1012
1013 case ICMP_UNREACH_NEEDFRAG:
1014 ++unreachable;
1015 Printf(" !F-%d", pmtu);
1016 break;
1017
1018 case ICMP_UNREACH_SRCFAIL:
1019 ++unreachable;
1020 Printf(" !S");
1021 break;
1022
1023 case ICMP_UNREACH_FILTER_PROHIB:
1024 ++unreachable;
1025 Printf(" !X");
1026 break;
1027
1028 case ICMP_UNREACH_HOST_PRECEDENCE:
1029 ++unreachable;
1030 Printf(" !V");
1031 break;
1032
1033 case ICMP_UNREACH_PRECEDENCE_CUTOFF:
1034 ++unreachable;
1035 Printf(" !C");
1036 break;
1037
1038 default:
1039 ++unreachable;
1040 Printf(" !<%d>", code);
1041 break;
1042 }
1043 break;
1044 }
1045 if (cc == 0) {
1046 loss++;
1047 Printf(" *");
1048 }
1049 (void)fflush(stdout);
1050 }
1051 if (sump) {
1052 Printf(" (%d%% loss)", (loss * 100) / nprobes);
1053 }
1054 putchar('\n');
1055 if (got_there ||
1056 (unreachable > 0 && unreachable >= nprobes - 1))
1057 break;
1058 }
1059 exit(0);
1060 }
1061
1062 int
1063 wait_for_reply(register int sock, register struct sockaddr_in *fromp,
1064 register const struct timeval *tp)
1065 {
1066 fd_set *fdsp;
1067 size_t nfds;
1068 struct timeval now, wait;
1069 struct timezone tz;
1070 register int cc = 0;
1071 register int error;
1072 socklen_t fromlen = sizeof(*fromp);
1073
1074 nfds = howmany(sock + 1, NFDBITS);
1075 if ((fdsp = malloc(nfds * sizeof(fd_mask))) == NULL)
1076 err(1, "malloc");
1077 memset(fdsp, 0, nfds * sizeof(fd_mask));
1078 FD_SET(sock, fdsp);
1079
1080 wait.tv_sec = tp->tv_sec + waittime;
1081 wait.tv_usec = tp->tv_usec;
1082 (void)gettimeofday(&now, &tz);
1083 tvsub(&wait, &now);
1084 if (wait.tv_sec < 0) {
1085 wait.tv_sec = 0;
1086 wait.tv_usec = 1;
1087 }
1088
1089 error = select(sock + 1, fdsp, NULL, NULL, &wait);
1090 if (error == -1 && errno == EINVAL) {
1091 Fprintf(stderr, "%s: botched select() args\n", prog);
1092 exit(1);
1093 }
1094 if (error > 0)
1095 cc = recvfrom(sock, (char *)packet, sizeof(packet), 0,
1096 (struct sockaddr *)fromp, &fromlen);
1097
1098 free(fdsp);
1099 return(cc);
1100 }
1101
1102 void
1103 send_probe(int seq, int ttl)
1104 {
1105 register int cc;
1106
1107 outip->ip_ttl = ttl;
1108 outip->ip_id = htons(ident + seq);
1109
1110 /* XXX undocumented debugging hack */
1111 if (verbose > 1) {
1112 register const u_short *sp;
1113 register int nshorts, i;
1114
1115 sp = (u_short *)outip;
1116 nshorts = (u_int)packlen / sizeof(u_short);
1117 i = 0;
1118 Printf("[ %d bytes", packlen);
1119 while (--nshorts >= 0) {
1120 if ((i++ % 8) == 0)
1121 Printf("\n\t");
1122 Printf(" %04x", ntohs(*sp++));
1123 }
1124 if (packlen & 1) {
1125 if ((i % 8) == 0)
1126 Printf("\n\t");
1127 Printf(" %02x", *(u_char *)sp);
1128 }
1129 Printf("]\n");
1130 }
1131
1132 #if !defined(IP_HDRINCL) && defined(IP_TTL)
1133 if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
1134 (char *)&ttl, sizeof(ttl)) < 0) {
1135 Fprintf(stderr, "%s: setsockopt ttl %d: %s\n",
1136 prog, ttl, strerror(errno));
1137 exit(1);
1138 }
1139 #endif
1140
1141 cc = sendto(sndsock, (char *)outip,
1142 packlen, 0, &whereto, sizeof(whereto));
1143 if (cc < 0 || cc != packlen) {
1144 if (cc < 0)
1145 Fprintf(stderr, "%s: sendto: %s\n",
1146 prog, strerror(errno));
1147 Printf("%s: wrote %s %d chars, ret=%d\n",
1148 prog, hostname, packlen, cc);
1149 (void)fflush(stdout);
1150 }
1151 }
1152
1153 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
1154 int
1155 setpolicy(so, policy)
1156 int so;
1157 char *policy;
1158 {
1159 char *buf;
1160
1161 buf = ipsec_set_policy(policy, strlen(policy));
1162 if (buf == NULL) {
1163 warnx("%s", ipsec_strerror());
1164 return -1;
1165 }
1166 (void)setsockopt(so, IPPROTO_IP, IP_IPSEC_POLICY,
1167 buf, ipsec_get_policylen(buf));
1168
1169 free(buf);
1170
1171 return 0;
1172 }
1173 #endif
1174
1175 double
1176 deltaT(struct timeval *t1p, struct timeval *t2p)
1177 {
1178 register double dt;
1179
1180 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
1181 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
1182 return (dt);
1183 }
1184
1185 /*
1186 * Convert an ICMP "type" field to a printable string.
1187 */
1188 char *
1189 pr_type(register u_char t)
1190 {
1191 static char *ttab[] = {
1192 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
1193 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
1194 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
1195 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
1196 "Info Reply"
1197 };
1198
1199 if (t > 16)
1200 return("OUT-OF-RANGE");
1201
1202 return(ttab[t]);
1203 }
1204
1205 int
1206 packet_ok(register u_char *buf, int cc, register struct sockaddr_in *from,
1207 register int seq)
1208 {
1209 register struct icmp *icp;
1210 register u_char type, code;
1211 register int hlen;
1212 #ifndef ARCHAIC
1213 register struct ip *ip;
1214
1215 ip = (struct ip *) buf;
1216 hlen = ip->ip_hl << 2;
1217 if (cc < hlen + ICMP_MINLEN) {
1218 if (verbose)
1219 Printf("packet too short (%d bytes) from %s\n", cc,
1220 inet_ntoa(from->sin_addr));
1221 return (0);
1222 }
1223 cc -= hlen;
1224 icp = (struct icmp *)(buf + hlen);
1225 #else
1226 icp = (struct icmp *)buf;
1227 #endif
1228 type = icp->icmp_type;
1229 code = icp->icmp_code;
1230 /* Path MTU Discovery (RFC1191) */
1231 if (code != ICMP_UNREACH_NEEDFRAG)
1232 pmtu = 0;
1233 else {
1234 #ifdef HAVE_ICMP_NEXTMTU
1235 pmtu = ntohs(icp->icmp_nextmtu);
1236 #else
1237 pmtu = ntohs(((struct my_pmtu *)&icp->icmp_void)->ipm_nextmtu);
1238 #endif
1239 }
1240 if (type == ICMP_ECHOREPLY
1241 && proto->num == IPPROTO_ICMP
1242 && (*proto->check)((u_char *)icp, (u_char)seq))
1243 return -2;
1244 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
1245 type == ICMP_UNREACH) {
1246 struct ip *hip;
1247 u_char *inner;
1248
1249 hip = &icp->icmp_ip;
1250 hlen = hip->ip_hl << 2;
1251 inner = (u_char *)((u_char *)hip + hlen);
1252 if (hlen + 12 <= cc
1253 && hip->ip_p == proto->num
1254 && (*proto->check)(inner, (u_char)seq))
1255 return (type == ICMP_TIMXCEED ? -1 : code + 1);
1256 }
1257 #ifndef ARCHAIC
1258 if (verbose) {
1259 register int i;
1260 u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
1261
1262 Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr));
1263 Printf("%s: icmp type %d (%s) code %d\n",
1264 inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
1265 for (i = 4; i < cc ; i += sizeof(*lp))
1266 Printf("%2d: x%8.8x\n", i, *lp++);
1267 }
1268 #endif
1269 return(0);
1270 }
1271
1272 void
1273 icmp_prep(struct outdata *outdata)
1274 {
1275 struct icmp *const icmpheader = (struct icmp *) outp;
1276
1277 icmpheader->icmp_type = ICMP_ECHO;
1278 icmpheader->icmp_id = htons(ident);
1279 icmpheader->icmp_seq = htons(outdata->seq);
1280 icmpheader->icmp_cksum = 0;
1281 icmpheader->icmp_cksum = in_cksum((u_short *)icmpheader, protlen);
1282 if (icmpheader->icmp_cksum == 0)
1283 icmpheader->icmp_cksum = 0xffff;
1284 }
1285
1286 int
1287 icmp_check(const u_char *data, int seq)
1288 {
1289 struct icmp *const icmpheader = (struct icmp *) data;
1290
1291 return (icmpheader->icmp_id == htons(ident)
1292 && icmpheader->icmp_seq == htons(seq));
1293 }
1294
1295 void
1296 udp_prep(struct outdata *outdata)
1297 {
1298 struct udphdr *const outudp = (struct udphdr *) outp;
1299
1300 outudp->uh_sport = htons(ident);
1301 outudp->uh_dport = htons(port + outdata->seq);
1302 outudp->uh_ulen = htons((u_short)protlen);
1303 outudp->uh_sum = 0;
1304 if (doipcksum) {
1305 u_short sum = p_cksum(outip, (u_short*)outudp, protlen);
1306 outudp->uh_sum = (sum) ? sum : 0xffff;
1307 }
1308
1309 return;
1310 }
1311
1312 int
1313 udp_check(const u_char *data, int seq)
1314 {
1315 struct udphdr *const udp = (struct udphdr *) data;
1316
1317 return (ntohs(udp->uh_sport) == ident
1318 && ntohs(udp->uh_dport) == port + seq);
1319 }
1320
1321 void
1322 tcp_prep(struct outdata *outdata)
1323 {
1324 struct tcphdr *const tcp = (struct tcphdr *) outp;
1325
1326 tcp->th_sport = htons(ident);
1327 tcp->th_dport = htons(port + outdata->seq);
1328 tcp->th_seq = (tcp->th_sport << 16) | tcp->th_dport;
1329 tcp->th_ack = 0;
1330 tcp->th_off = 5;
1331 tcp->th_flags = TH_SYN;
1332 tcp->th_sum = 0;
1333
1334 if (doipcksum) {
1335 u_short sum = p_cksum(outip, (u_short*)tcp, protlen);
1336 tcp->th_sum = (sum) ? sum : 0xffff;
1337 }
1338 }
1339
1340 int
1341 tcp_check(const u_char *data, int seq)
1342 {
1343 struct tcphdr *const tcp = (struct tcphdr *) data;
1344
1345 return (ntohs(tcp->th_sport) == ident
1346 && ntohs(tcp->th_dport) == port + seq);
1347 }
1348
1349 void
1350 gre_prep(struct outdata *outdata)
1351 {
1352 struct grehdr *const gre = (struct grehdr *) outp;
1353
1354 gre->flags = htons(0x2001);
1355 gre->proto = htons(port);
1356 gre->length = 0;
1357 gre->callId = htons(ident + outdata->seq);
1358 }
1359
1360 int
1361 gre_check(const u_char *data, int seq)
1362 {
1363 struct grehdr *const gre = (struct grehdr *) data;
1364
1365 return(ntohs(gre->proto) == port
1366 && ntohs(gre->callId) == ident + seq);
1367 }
1368
1369 void
1370 gen_prep(struct outdata *outdata)
1371 {
1372 u_int16_t *const ptr = (u_int16_t *) outp;
1373
1374 ptr[0] = htons(ident);
1375 ptr[1] = htons(port + outdata->seq);
1376 }
1377
1378 int
1379 gen_check(const u_char *data, int seq)
1380 {
1381 u_int16_t *const ptr = (u_int16_t *) data;
1382
1383 return(ntohs(ptr[0]) == ident
1384 && ntohs(ptr[1]) == port + seq);
1385 }
1386
1387 void
1388 print(register u_char *buf, register int cc, register struct sockaddr_in *from)
1389 {
1390 register struct ip *ip;
1391 register int hlen;
1392
1393 ip = (struct ip *) buf;
1394 hlen = ip->ip_hl << 2;
1395 cc -= hlen;
1396
1397 if (nflag)
1398 Printf(" %s", inet_ntoa(from->sin_addr));
1399 else
1400 Printf(" %s (%s)", inetname(from->sin_addr),
1401 inet_ntoa(from->sin_addr));
1402
1403 if (verbose)
1404 Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
1405 }
1406
1407 /*
1408 * Checksum routine for UDP and TCP headers.
1409 */
1410 u_short
1411 p_cksum(struct ip *ip, u_short *data, int len)
1412 {
1413 static struct ipovly ipo;
1414 u_short sumh, sumd;
1415 u_long sumt;
1416
1417 ipo.ih_pr = ip->ip_p;
1418 ipo.ih_len = htons(len);
1419 ipo.ih_src = ip->ip_src;
1420 ipo.ih_dst = ip->ip_dst;
1421
1422 sumh = in_cksum((u_short*)&ipo, sizeof(ipo)); /* pseudo ip hdr cksum */
1423 sumd = in_cksum((u_short*)data, len); /* payload data cksum */
1424 sumt = (sumh << 16) | (sumd);
1425
1426 return ~in_cksum((u_short*)&sumt, sizeof(sumt));
1427 }
1428
1429 /*
1430 * Checksum routine for Internet Protocol family headers (C Version)
1431 */
1432 u_short
1433 in_cksum(register u_short *addr, register int len)
1434 {
1435 register int nleft = len;
1436 register u_short *w = addr;
1437 register u_short answer;
1438 register int sum = 0;
1439
1440 /*
1441 * Our algorithm is simple, using a 32 bit accumulator (sum),
1442 * we add sequential 16 bit words to it, and at the end, fold
1443 * back all the carry bits from the top 16 bits into the lower
1444 * 16 bits.
1445 */
1446 while (nleft > 1) {
1447 sum += *w++;
1448 nleft -= 2;
1449 }
1450
1451 /* mop up an odd byte, if necessary */
1452 if (nleft == 1)
1453 sum += *(u_char *)w;
1454
1455 /*
1456 * add back carry outs from top 16 bits to low 16 bits
1457 */
1458 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
1459 sum += (sum >> 16); /* add carry */
1460 answer = ~sum; /* truncate to 16 bits */
1461 return (answer);
1462 }
1463
1464 /*
1465 * Subtract 2 timeval structs: out = out - in.
1466 * Out is assumed to be within about LONG_MAX seconds of in.
1467 */
1468 void
1469 tvsub(register struct timeval *out, register struct timeval *in)
1470 {
1471
1472 if ((out->tv_usec -= in->tv_usec) < 0) {
1473 --out->tv_sec;
1474 out->tv_usec += 1000000;
1475 }
1476 out->tv_sec -= in->tv_sec;
1477 }
1478
1479 /*
1480 * Construct an Internet address representation.
1481 * If the nflag has been supplied, give
1482 * numeric value, otherwise try for symbolic name.
1483 */
1484 char *
1485 inetname(struct in_addr in)
1486 {
1487 register char *cp;
1488 register struct hostent *hp;
1489 static int first = 1;
1490 static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1];
1491
1492 if (first && !nflag) {
1493 first = 0;
1494 if (gethostname(domain, sizeof(domain) - 1) < 0)
1495 domain[0] = '\0';
1496 else {
1497 cp = strchr(domain, '.');
1498 if (cp == NULL) {
1499 hp = gethostbyname(domain);
1500 if (hp != NULL)
1501 cp = strchr(hp->h_name, '.');
1502 }
1503 if (cp == NULL)
1504 domain[0] = '\0';
1505 else {
1506 ++cp;
1507 (void)strncpy(domain, cp, sizeof(domain) - 1);
1508 domain[sizeof(domain) - 1] = '\0';
1509 }
1510 }
1511 }
1512 if (!nflag && in.s_addr != INADDR_ANY) {
1513 hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
1514 if (hp != NULL) {
1515 if ((cp = strchr(hp->h_name, '.')) != NULL &&
1516 strcmp(cp + 1, domain) == 0)
1517 *cp = '\0';
1518 (void)strncpy(line, hp->h_name, sizeof(line) - 1);
1519 line[sizeof(line) - 1] = '\0';
1520 return (line);
1521 }
1522 }
1523 return (inet_ntoa(in));
1524 }
1525
1526 struct hostinfo *
1527 gethostinfo(register char *hostname)
1528 {
1529 register int n;
1530 register struct hostent *hp;
1531 register struct hostinfo *hi;
1532 register char **p;
1533 register u_int32_t addr, *ap;
1534
1535 if (strlen(hostname) > 64) {
1536 Fprintf(stderr, "%s: hostname \"%.32s...\" is too long\n",
1537 prog, hostname);
1538 exit(1);
1539 }
1540 hi = calloc(1, sizeof(*hi));
1541 if (hi == NULL) {
1542 Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
1543 exit(1);
1544 }
1545 addr = inet_addr(hostname);
1546 if ((int32_t)addr != -1) {
1547 hi->name = strdup(hostname);
1548 hi->n = 1;
1549 hi->addrs = calloc(1, sizeof(hi->addrs[0]));
1550 if (hi->addrs == NULL) {
1551 Fprintf(stderr, "%s: calloc %s\n",
1552 prog, strerror(errno));
1553 exit(1);
1554 }
1555 hi->addrs[0] = addr;
1556 return (hi);
1557 }
1558
1559 hp = gethostbyname(hostname);
1560 if (hp == NULL) {
1561 Fprintf(stderr, "%s: unknown host %s\n", prog, hostname);
1562 exit(1);
1563 }
1564 if (hp->h_addrtype != AF_INET || hp->h_length != 4) {
1565 Fprintf(stderr, "%s: bad host %s\n", prog, hostname);
1566 exit(1);
1567 }
1568 hi->name = strdup(hp->h_name);
1569 for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
1570 continue;
1571 hi->n = n;
1572 hi->addrs = calloc(n, sizeof(hi->addrs[0]));
1573 if (hi->addrs == NULL) {
1574 Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
1575 exit(1);
1576 }
1577 for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
1578 memcpy(ap, *p, sizeof(*ap));
1579 return (hi);
1580 }
1581
1582 void
1583 freehostinfo(register struct hostinfo *hi)
1584 {
1585 if (hi->name != NULL) {
1586 free(hi->name);
1587 hi->name = NULL;
1588 }
1589 free((char *)hi->addrs);
1590 free((char *)hi);
1591 }
1592
1593 void
1594 getaddr(register u_int32_t *ap, register char *hostname)
1595 {
1596 register struct hostinfo *hi;
1597
1598 hi = gethostinfo(hostname);
1599 *ap = hi->addrs[0];
1600 freehostinfo(hi);
1601 }
1602
1603 void
1604 setsin(register struct sockaddr_in *sin, register u_int32_t addr)
1605 {
1606
1607 memset(sin, 0, sizeof(*sin));
1608 #ifdef HAVE_SOCKADDR_SA_LEN
1609 sin->sin_len = sizeof(*sin);
1610 #endif
1611 sin->sin_family = AF_INET;
1612 sin->sin_addr.s_addr = addr;
1613 }
1614
1615 /* String to value with optional min and max. Handles decimal and hex. */
1616 int
1617 str2val(register const char *str, register const char *what,
1618 register int mi, register int ma)
1619 {
1620 register const char *cp;
1621 register int val;
1622 char *ep;
1623
1624 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
1625 cp = str + 2;
1626 val = (int)strtol(cp, &ep, 16);
1627 } else
1628 val = (int)strtol(str, &ep, 10);
1629 if (*ep != '\0') {
1630 Fprintf(stderr, "%s: \"%s\" bad value for %s \n",
1631 prog, str, what);
1632 exit(1);
1633 }
1634 if (val < mi && mi >= 0) {
1635 if (mi == 0)
1636 Fprintf(stderr, "%s: %s must be >= %d\n",
1637 prog, what, mi);
1638 else
1639 Fprintf(stderr, "%s: %s must be > %d\n",
1640 prog, what, mi - 1);
1641 exit(1);
1642 }
1643 if (val > ma && ma >= 0) {
1644 Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma);
1645 exit(1);
1646 }
1647 return (val);
1648 }
1649
1650 struct outproto *
1651 setproto(char *pname)
1652 {
1653 struct outproto *proto;
1654 int i;
1655
1656 for (i = 0; protos[i].name != NULL; i++) {
1657 if (strcasecmp(protos[i].name, pname) == 0) {
1658 break;
1659 }
1660 }
1661 proto = &protos[i];
1662 if (proto->name == NULL) { /* generic handler */
1663 struct protoent *pe;
1664 u_long pnum;
1665
1666 /* Determine the IP protocol number */
1667 if ((pe = getprotobyname(pname)) != NULL)
1668 pnum = pe->p_proto;
1669 else
1670 pnum = str2val(optarg, "proto number", 1, 255);
1671 proto->num = pnum;
1672 }
1673 return proto;
1674 }
1675
1676 void
1677 usage(void)
1678 {
1679 extern char version[];
1680
1681 Fprintf(stderr, "Version %s\n", version);
1682 Fprintf(stderr,
1683 "Usage: %s [-dFINnrSvx] [-g gateway] [-i iface] [-f first_ttl]\n"
1684 "\t[-m max_ttl] [-p port] [-P proto] [-q nqueries] [-s src_addr]\n"
1685 "\t[-t tos] [-w waittime] [-z pausemsecs] host [packetlen]\n", prog);
1686 exit(1);
1687 }