Annotation of src/sbin/ping/ping.c, Revision 1.101.2.4
1.101.2.4! yamt 1: /* $NetBSD: ping.c,v 1.101.2.3 2013/01/23 00:05:33 yamt Exp $ */
1.13 cgd 2:
1.1 cgd 3: /*
1.8 mycroft 4: * Copyright (c) 1989, 1993
5: * The Regents of the University of California. All rights reserved.
1.1 cgd 6: *
7: * This code is derived from software contributed to Berkeley by
8: * Mike Muuss.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
1.73 agc 18: * 3. Neither the name of the University nor the names of its contributors
1.1 cgd 19: * may be used to endorse or promote products derived from this software
20: * without specific prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32: * SUCH DAMAGE.
33: */
1.41 christos 34:
1.1 cgd 35: /*
36: * P I N G . C
37: *
1.30 christos 38: * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
1.1 cgd 39: * measure round-trip-delays and packet loss across network paths.
40: *
41: * Author -
42: * Mike Muuss
43: * U. S. Army Ballistic Research Laboratory
44: * December, 1983
1.22 christos 45: * Modified at Uc Berkeley
46: * Record Route and verbose headers - Phil Dykstra, BRL, March 1988.
47: * Multicast options (ttl, if, loop) - Steve Deering, Stanford, August 1988.
48: * ttl, duplicate detection - Cliff Frost, UCB, April 1989
49: * Pad pattern - Cliff Frost (from Tom Ferrin, UCSF), April 1989
1.1 cgd 50: *
51: * Status -
52: * Public Domain. Distribution Unlimited.
1.22 christos 53: *
1.1 cgd 54: * Bugs -
55: * More statistics could always be gathered.
56: * This program has to run SUID to ROOT to access the ICMP socket.
57: */
58:
1.32 lukem 59: #include <sys/cdefs.h>
1.22 christos 60: #ifndef lint
1.101.2.4! yamt 61: __RCSID("$NetBSD: ping.c,v 1.101.2.3 2013/01/23 00:05:33 yamt Exp $");
1.22 christos 62: #endif
63:
64: #include <stdio.h>
1.60 yamt 65: #include <stddef.h>
1.22 christos 66: #include <errno.h>
1.81 christos 67: #include <signal.h>
1.22 christos 68: #include <sys/time.h>
69: #include <sys/types.h>
1.1 cgd 70: #include <sys/param.h>
71: #include <sys/socket.h>
72: #include <sys/file.h>
1.41 christos 73: #include <termios.h>
1.22 christos 74: #include <stdlib.h>
75: #include <unistd.h>
1.67 mycroft 76: #include <poll.h>
1.22 christos 77: #include <limits.h>
1.44 jwise 78: #include <math.h>
1.22 christos 79: #include <string.h>
80: #include <err.h>
1.1 cgd 81:
82: #include <netinet/in_systm.h>
83: #include <netinet/in.h>
84: #include <netinet/ip.h>
85: #include <netinet/ip_icmp.h>
86: #include <netinet/ip_var.h>
1.12 cgd 87: #include <arpa/inet.h>
1.22 christos 88: #include <ctype.h>
1.1 cgd 89: #include <netdb.h>
90:
1.50 itojun 91: #ifdef IPSEC
1.101.2.1 yamt 92: #include <netipsec/ipsec.h>
1.50 itojun 93: #endif /*IPSEC*/
94:
1.92 pooka 95: #include "prog_ops.h"
1.91 pooka 96:
1.22 christos 97: #define FLOOD_INTVL 0.01 /* default flood output interval */
1.61 yamt 98: #define MAXPACKET (IP_MAXPACKET-60-8) /* max packet size */
1.7 hpeyerl 99:
1.22 christos 100: #define F_VERBOSE 0x0001
101: #define F_QUIET 0x0002 /* minimize all output */
102: #define F_SEMI_QUIET 0x0004 /* ignore our ICMP errors */
103: #define F_FLOOD 0x0008 /* flood-ping */
104: #define F_RECORD_ROUTE 0x0010 /* record route */
105: #define F_SOURCE_ROUTE 0x0020 /* loose source route */
106: #define F_PING_FILLED 0x0040 /* is buffer filled with user data? */
107: #define F_PING_RANDOM 0x0080 /* use random data */
108: #define F_NUMERIC 0x0100 /* do not do gethostbyaddr() calls */
109: #define F_TIMING 0x0200 /* room for a timestamp */
1.30 christos 110: #define F_DF 0x0400 /* set IP DF bit */
111: #define F_SOURCE_ADDR 0x0800 /* set source IP address/interface */
112: #define F_ONCE 0x1000 /* exit(0) after receiving 1 reply */
113: #define F_MCAST 0x2000 /* multicast target */
114: #define F_MCAST_NOLOOP 0x4000 /* no multicast loopback */
1.49 sommerfe 115: #define F_AUDIBLE 0x8000 /* audible output */
1.99 christos 116: #define F_TIMING64 0x10000 /* 64 bit time, nanoseconds */
1.50 itojun 117: #ifdef IPSEC
118: #ifdef IPSEC_POLICY_IPSEC
1.101.2.2 yamt 119: #define F_POLICY 0x20000
1.50 itojun 120: #else
1.101.2.2 yamt 121: #define F_AUTHHDR 0x20000
122: #define F_ENCRYPT 0x40000
1.50 itojun 123: #endif /*IPSEC_POLICY_IPSEC*/
124: #endif /*IPSEC*/
1.22 christos 125:
1.41 christos 126:
1.22 christos 127: /* MAX_DUP_CHK is the number of bits in received table, the
128: * maximum number of received sequence numbers we can track to check
129: * for duplicates.
1.1 cgd 130: */
1.22 christos 131: #define MAX_DUP_CHK (8 * 2048)
1.98 joerg 132: static u_char rcvd_tbl[MAX_DUP_CHK/8];
133: static int nrepeats = 0;
1.22 christos 134: #define A(seq) rcvd_tbl[(seq/8)%sizeof(rcvd_tbl)] /* byte in array */
135: #define B(seq) (1 << (seq & 0x07)) /* bit in byte */
136: #define SET(seq) (A(seq) |= B(seq))
137: #define CLR(seq) (A(seq) &= (~B(seq)))
138: #define TST(seq) (A(seq) & B(seq))
139:
1.75 itojun 140: struct tv32 {
141: int32_t tv32_sec;
142: int32_t tv32_usec;
143: };
1.22 christos 144:
145:
1.98 joerg 146: static u_char *packet;
147: static int packlen;
148: static int pingflags = 0, options;
149: static int pongflags = 0;
150: static char *fill_pat;
1.22 christos 151:
1.98 joerg 152: static int s; /* Socket file descriptor */
153: static int sloop; /* Socket file descriptor/loopback */
1.22 christos 154:
1.99 christos 155: #define PHDR_LEN sizeof(struct tv32) /* size of timestamp header */
156: #define PHDR64_LEN sizeof(struct timespec) /* size of timestamp header */
1.98 joerg 157: static struct sockaddr_in whereto, send_addr; /* Who to ping */
158: static struct sockaddr_in src_addr; /* from where */
159: static struct sockaddr_in loc_addr; /* 127.1 */
1.99 christos 160: static int datalen; /* How much data */
161: static int phdrlen;
1.22 christos 162:
1.59 cgd 163: #ifndef __NetBSD__
164: static char *progname;
165: #define getprogname() (progname)
166: #define setprogname(name) ((void)(progname = (name)))
1.30 christos 167: #endif
1.22 christos 168:
1.98 joerg 169: static char hostname[MAXHOSTNAMELEN];
1.22 christos 170:
171: static struct {
172: struct ip o_ip;
1.30 christos 173: char o_opt[MAX_IPOPTLEN];
1.22 christos 174: union {
1.60 yamt 175: u_char u_buf[MAXPACKET+offsetof(struct icmp, icmp_data)];
1.30 christos 176: struct icmp u_icmp;
1.22 christos 177: } o_u;
178: } out_pack;
1.30 christos 179: #define opack_icmp out_pack.o_u.u_icmp
1.98 joerg 180: static struct ip *opack_ip;
1.30 christos 181:
1.98 joerg 182: static char optspace[MAX_IPOPTLEN]; /* record route space */
183: static int optlen;
1.30 christos 184:
1.98 joerg 185: static int npackets; /* total packets to send */
186: static int preload; /* number of packets to "preload" */
187: static int ntransmitted; /* output sequence # = #sent */
188: static int ident; /* our ID, in network byte order */
189:
190: static int nreceived; /* # of packets we got back */
191:
192: static double interval; /* interval between packets */
1.99 christos 193: static struct timespec interval_tv;
1.98 joerg 194: static double tmin = 999999999.0;
195: static double tmax = 0.0;
196: static double tsum = 0.0; /* sum of all times */
197: static double tsumsq = 0.0;
198: static double maxwait = 0.0;
199:
200: static int bufspace = IP_MAXPACKET;
201:
1.99 christos 202: static struct timespec now, clear_cache, last_tx, next_tx, first_tx;
203: static struct timespec last_rx, first_rx;
1.98 joerg 204: static int lastrcvd = 1; /* last ping sent has been received */
1.22 christos 205:
1.99 christos 206: static struct timespec jiggle_time;
1.22 christos 207: static int jiggle_cnt, total_jiggled, jiggle_direction = -1;
208:
1.98 joerg 209: __dead static void doit(void);
1.22 christos 210: static void prefinish(int);
211: static void prtsig(int);
1.98 joerg 212: __dead static void finish(int);
1.22 christos 213: static void summary(int);
214: static void pinger(void);
215: static void fill(void);
216: static void rnd_fill(void);
1.99 christos 217: static double diffsec(struct timespec *, struct timespec *);
218: #if 0
219: static void timespecadd(struct timespec *, struct timespec *);
220: #endif
221: static void sec_to_timespec(const double, struct timespec *);
222: static double timespec_to_sec(const struct timespec *);
1.22 christos 223: static void pr_pack(u_char *, int, struct sockaddr_in *);
1.65 itojun 224: static u_int16_t in_cksum(u_int16_t *, u_int);
1.57 is 225: static void pr_saddr(u_char *);
1.22 christos 226: static char *pr_addr(struct in_addr *);
227: static void pr_iph(struct icmp *, int);
228: static void pr_retip(struct icmp *, int);
229: static int pr_icmph(struct icmp *, struct sockaddr_in *, int);
230: static void jiggle(int), jiggle_flush(int);
1.30 christos 231: static void gethost(const char *, const char *,
232: struct sockaddr_in *, char *, int);
1.98 joerg 233: __dead static void usage(void);
1.1 cgd 234:
1.12 cgd 235: int
1.22 christos 236: main(int argc, char *argv[])
1.1 cgd 237: {
1.30 christos 238: int c, i, on = 1, hostind = 0;
239: long l;
1.99 christos 240: int len = -1, compat = 0;
1.30 christos 241: u_char ttl = 0;
242: u_long tos = 0;
1.22 christos 243: char *p;
1.50 itojun 244: #ifdef IPSEC
245: #ifdef IPSEC_POLICY_IPSEC
1.55 itojun 246: char *policy_in = NULL;
247: char *policy_out = NULL;
1.50 itojun 248: #endif
249: #endif
1.81 christos 250: #ifdef SIGINFO
251: struct sigaction sa;
252: #endif
1.1 cgd 253:
1.92 pooka 254: if (prog_init && prog_init() == -1)
255: err(1, "init failed");
1.91 pooka 256:
1.92 pooka 257: if ((s = prog_socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
1.83 elad 258: err(1, "Cannot create socket");
1.92 pooka 259: if ((sloop = prog_socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
1.83 elad 260: err(1, "Cannot create socket");
261:
1.87 seanb 262: /*
263: * sloop is never read on. This prevents packets from
264: * queueing in its recv buffer.
265: */
1.92 pooka 266: if (prog_shutdown(sloop, SHUT_RD) == -1)
1.87 seanb 267: warn("Cannot shutdown for read");
268:
1.93 pooka 269: if (prog_setuid(prog_getuid()) == -1)
1.85 elad 270: err(1, "setuid");
1.83 elad 271:
1.59 cgd 272: setprogname(argv[0]);
273:
1.50 itojun 274: #ifndef IPSEC
275: #define IPSECOPT
276: #else
277: #ifdef IPSEC_POLICY_IPSEC
278: #define IPSECOPT "E:"
279: #else
280: #define IPSECOPT "AE"
281: #endif /*IPSEC_POLICY_IPSEC*/
282: #endif
1.30 christos 283: while ((c = getopt(argc, argv,
1.99 christos 284: "ac:CdDfg:h:i:I:l:Lnop:PqQrRs:t:T:vw:" IPSECOPT)) != -1) {
1.50 itojun 285: #undef IPSECOPT
1.22 christos 286: switch (c) {
1.49 sommerfe 287: case 'a':
288: pingflags |= F_AUDIBLE;
289: break;
1.99 christos 290: case 'C':
291: compat = 1;
292: break;
1.1 cgd 293: case 'c':
1.22 christos 294: npackets = strtol(optarg, &p, 0);
295: if (*p != '\0' || npackets <= 0)
296: errx(1, "Bad/invalid number of packets");
297: break;
298: case 'D':
1.30 christos 299: pingflags |= F_DF;
1.1 cgd 300: break;
301: case 'd':
1.22 christos 302: options |= SO_DEBUG;
1.1 cgd 303: break;
304: case 'f':
1.22 christos 305: pingflags |= F_FLOOD;
1.8 mycroft 306: break;
1.30 christos 307: case 'h':
308: hostind = optind-1;
309: break;
1.1 cgd 310: case 'i': /* wait between sending packets */
1.22 christos 311: interval = strtod(optarg, &p);
312: if (*p != '\0' || interval <= 0)
1.30 christos 313: errx(1, "Bad/invalid interval %s", optarg);
1.8 mycroft 314: break;
1.1 cgd 315: case 'l':
1.22 christos 316: preload = strtol(optarg, &p, 0);
317: if (*p != '\0' || preload < 0)
1.30 christos 318: errx(1, "Bad/invalid preload value %s",
319: optarg);
1.1 cgd 320: break;
321: case 'n':
1.22 christos 322: pingflags |= F_NUMERIC;
1.1 cgd 323: break;
1.25 christos 324: case 'o':
325: pingflags |= F_ONCE;
326: break;
1.1 cgd 327: case 'p': /* fill buffer with user pattern */
1.22 christos 328: if (pingflags & F_PING_RANDOM)
329: errx(1, "Only one of -P and -p allowed");
330: pingflags |= F_PING_FILLED;
331: fill_pat = optarg;
332: break;
333: case 'P':
334: if (pingflags & F_PING_FILLED)
335: errx(1, "Only one of -P and -p allowed");
336: pingflags |= F_PING_RANDOM;
337: break;
1.1 cgd 338: case 'q':
1.22 christos 339: pingflags |= F_QUIET;
1.1 cgd 340: break;
1.22 christos 341: case 'Q':
342: pingflags |= F_SEMI_QUIET;
1.1 cgd 343: break;
344: case 'r':
1.22 christos 345: options |= SO_DONTROUTE;
1.19 ghudson 346: break;
1.1 cgd 347: case 's': /* size of packet to send */
1.89 lukem 348: l = strtol(optarg, &p, 0);
349: if (*p != '\0' || l < 0)
1.30 christos 350: errx(1, "Bad/invalid packet size %s", optarg);
1.89 lukem 351: if (l > MAXPACKET)
1.22 christos 352: errx(1, "packet size is too large");
1.99 christos 353: len = (int)l;
1.22 christos 354: break;
355: case 'v':
356: pingflags |= F_VERBOSE;
357: break;
358: case 'R':
359: pingflags |= F_RECORD_ROUTE;
360: break;
361: case 'L':
1.30 christos 362: pingflags |= F_MCAST_NOLOOP;
1.8 mycroft 363: break;
364: case 't':
1.30 christos 365: tos = strtoul(optarg, &p, 0);
366: if (*p != '\0' || tos > 0xFF)
367: errx(1, "bad tos value: %s", optarg);
1.22 christos 368: break;
369: case 'T':
1.30 christos 370: l = strtol(optarg, &p, 0);
371: if (*p != '\0' || l > 255 || l <= 0)
372: errx(1, "ttl out of range");
373: ttl = (u_char)l; /* cannot check >255 otherwise */
1.22 christos 374: break;
375: case 'I':
1.30 christos 376: pingflags |= F_SOURCE_ADDR;
377: gethost("-I", optarg, &src_addr, 0, 0);
1.1 cgd 378: break;
1.22 christos 379: case 'g':
380: pingflags |= F_SOURCE_ROUTE;
1.30 christos 381: gethost("-g", optarg, &send_addr, 0, 0);
1.1 cgd 382: break;
1.19 ghudson 383: case 'w':
1.22 christos 384: maxwait = strtod(optarg, &p);
385: if (*p != '\0' || maxwait <= 0)
1.30 christos 386: errx(1, "Bad/invalid maxwait time %s", optarg);
1.19 ghudson 387: break;
1.50 itojun 388: #ifdef IPSEC
389: #ifdef IPSEC_POLICY_IPSEC
390: case 'E':
391: pingflags |= F_POLICY;
1.70 itojun 392: if (!strncmp("in", optarg, 2)) {
1.55 itojun 393: policy_in = strdup(optarg);
1.70 itojun 394: if (!policy_in)
395: err(1, "strdup");
396: } else if (!strncmp("out", optarg, 3)) {
1.55 itojun 397: policy_out = strdup(optarg);
1.70 itojun 398: if (!policy_out)
399: err(1, "strdup");
400: } else
1.55 itojun 401: errx(1, "invalid security policy");
1.50 itojun 402: break;
403: #else
404: case 'A':
405: pingflags |= F_AUTHHDR;
406: break;
407: case 'E':
408: pingflags |= F_ENCRYPT;
409: break;
410: #endif /*IPSEC_POLICY_IPSEC*/
411: #endif /*IPSEC*/
1.1 cgd 412: default:
413: usage();
1.22 christos 414: break;
1.1 cgd 415: }
1.22 christos 416: }
1.8 mycroft 417:
1.22 christos 418: if (interval == 0)
419: interval = (pingflags & F_FLOOD) ? FLOOD_INTVL : 1.0;
1.28 christos 420: #ifndef sgi
1.93 pooka 421: if (pingflags & F_FLOOD && prog_getuid())
1.39 tv 422: errx(1, "Must be superuser to use -f");
1.93 pooka 423: if (interval < 1.0 && prog_getuid())
1.28 christos 424: errx(1, "Must be superuser to use < 1 sec ping interval");
1.93 pooka 425: if (preload > 0 && prog_getuid())
1.39 tv 426: errx(1, "Must be superuser to use -l");
1.28 christos 427: #endif
1.99 christos 428: sec_to_timespec(interval, &interval_tv);
1.22 christos 429:
1.49 sommerfe 430: if ((pingflags & (F_AUDIBLE|F_FLOOD)) == (F_AUDIBLE|F_FLOOD))
431: warnx("Sorry, no audible output for flood pings");
432:
1.22 christos 433: if (npackets != 0) {
434: npackets += preload;
435: } else {
436: npackets = INT_MAX;
437: }
438:
1.30 christos 439: if (hostind == 0) {
440: if (optind != argc-1)
441: usage();
1.22 christos 442: else
1.30 christos 443: hostind = optind;
1.22 christos 444: }
1.30 christos 445: else if (hostind >= argc - 1)
446: usage();
1.22 christos 447:
1.30 christos 448: gethost("", argv[hostind], &whereto, hostname, sizeof(hostname));
449: if (IN_MULTICAST(ntohl(whereto.sin_addr.s_addr)))
450: pingflags |= F_MCAST;
1.22 christos 451: if (!(pingflags & F_SOURCE_ROUTE))
452: (void) memcpy(&send_addr, &whereto, sizeof(send_addr));
453:
454: loc_addr.sin_family = AF_INET;
1.71 itojun 455: loc_addr.sin_len = sizeof(struct sockaddr_in);
1.95 christos 456: loc_addr.sin_addr.s_addr = htonl((127 << 24) + 1);
1.22 christos 457:
1.99 christos 458: if (len != -1)
459: datalen = len;
460: else
461: datalen = 64;
462: if (!compat && datalen >= (int)PHDR64_LEN) { /* can we time them? */
463: pingflags |= F_TIMING64;
464: phdrlen = PHDR64_LEN;
465: } else if (datalen >= (int)PHDR_LEN) { /* can we time them? */
1.22 christos 466: pingflags |= F_TIMING;
1.99 christos 467: phdrlen = PHDR_LEN;
468: } else
469: phdrlen = 0;
470:
1.22 christos 471: packlen = datalen + 60 + 76; /* MAXIP + MAXICMP */
1.101.2.3 yamt 472: datalen -= phdrlen;
1.95 christos 473: if ((packet = malloc(packlen)) == NULL)
1.22 christos 474: err(1, "Out of memory");
475:
476: if (pingflags & F_PING_FILLED) {
477: fill();
478: } else if (pingflags & F_PING_RANDOM) {
479: rnd_fill();
480: } else {
1.99 christos 481: for (i = phdrlen; i < datalen; i++)
1.22 christos 482: opack_icmp.icmp_data[i] = i;
483: }
1.1 cgd 484:
1.77 kleink 485: ident = arc4random() & 0xFFFF;
1.1 cgd 486:
1.22 christos 487: if (options & SO_DEBUG) {
1.92 pooka 488: if (prog_setsockopt(s, SOL_SOCKET, SO_DEBUG,
1.41 christos 489: (char *)&on, sizeof(on)) == -1)
1.30 christos 490: warn("Can't turn on socket debugging");
1.22 christos 491: }
492: if (options & SO_DONTROUTE) {
1.92 pooka 493: if (prog_setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
1.41 christos 494: (char *)&on, sizeof(on)) == -1)
1.30 christos 495: warn("SO_DONTROUTE");
1.22 christos 496: }
497:
1.50 itojun 498: if (options & SO_DEBUG) {
1.92 pooka 499: if (prog_setsockopt(sloop, SOL_SOCKET, SO_DEBUG,
1.50 itojun 500: (char *)&on, sizeof(on)) == -1)
501: warn("Can't turn on socket debugging");
502: }
503: if (options & SO_DONTROUTE) {
1.92 pooka 504: if (prog_setsockopt(sloop, SOL_SOCKET, SO_DONTROUTE,
1.50 itojun 505: (char *)&on, sizeof(on)) == -1)
506: warn("SO_DONTROUTE");
507: }
508:
1.30 christos 509: if (pingflags & F_SOURCE_ROUTE) {
510: optspace[IPOPT_OPTVAL] = IPOPT_LSRR;
511: optspace[IPOPT_OLEN] = optlen = 7;
512: optspace[IPOPT_OFFSET] = IPOPT_MINOFF;
1.41 christos 513: (void)memcpy(&optspace[IPOPT_MINOFF-1], &whereto.sin_addr,
514: sizeof(whereto.sin_addr));
1.30 christos 515: optspace[optlen++] = IPOPT_NOP;
516: }
517: if (pingflags & F_RECORD_ROUTE) {
518: optspace[optlen+IPOPT_OPTVAL] = IPOPT_RR;
519: optspace[optlen+IPOPT_OLEN] = (MAX_IPOPTLEN -1-optlen);
520: optspace[optlen+IPOPT_OFFSET] = IPOPT_MINOFF;
521: optlen = MAX_IPOPTLEN;
522: }
523: /* this leaves opack_ip 0(mod 4) aligned */
524: opack_ip = (struct ip *)((char *)&out_pack.o_ip
525: + sizeof(out_pack.o_opt)
526: - optlen);
527: (void) memcpy(opack_ip + 1, optspace, optlen);
528:
1.92 pooka 529: if (prog_setsockopt(s,IPPROTO_IP,IP_HDRINCL,
530: (char *) &on, sizeof(on)) < 0)
1.30 christos 531: err(1, "Can't set special IP header");
532:
533: opack_ip->ip_v = IPVERSION;
534: opack_ip->ip_hl = (sizeof(struct ip)+optlen) >> 2;
535: opack_ip->ip_tos = tos;
536: opack_ip->ip_off = (pingflags & F_DF) ? IP_DF : 0;
537: opack_ip->ip_ttl = ttl ? ttl : MAXTTL;
538: opack_ip->ip_p = IPPROTO_ICMP;
539: opack_ip->ip_src = src_addr.sin_addr;
540: opack_ip->ip_dst = send_addr.sin_addr;
541:
542: if (pingflags & F_MCAST) {
543: if (pingflags & F_MCAST_NOLOOP) {
544: u_char loop = 0;
1.92 pooka 545: if (prog_setsockopt(s, IPPROTO_IP,
546: IP_MULTICAST_LOOP,
1.30 christos 547: (char *) &loop, 1) < 0)
548: err(1, "Can't disable multicast loopback");
1.22 christos 549: }
1.1 cgd 550:
1.30 christos 551: if (ttl != 0
1.92 pooka 552: && prog_setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL,
1.30 christos 553: (char *) &ttl, 1) < 0)
1.22 christos 554: err(1, "Can't set multicast time-to-live");
1.30 christos 555:
556: if ((pingflags & F_SOURCE_ADDR)
1.92 pooka 557: && prog_setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
1.30 christos 558: (char *) &src_addr.sin_addr,
559: sizeof(src_addr.sin_addr)) < 0)
1.22 christos 560: err(1, "Can't set multicast source interface");
1.30 christos 561:
562: } else if (pingflags & F_SOURCE_ADDR) {
1.92 pooka 563: if (prog_setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
1.30 christos 564: (char *) &src_addr.sin_addr,
565: sizeof(src_addr.sin_addr)) < 0)
566: err(1, "Can't set source interface/address");
1.22 christos 567: }
1.50 itojun 568: #ifdef IPSEC
569: #ifdef IPSEC_POLICY_IPSEC
570: {
571: char *buf;
572: if (pingflags & F_POLICY) {
1.55 itojun 573: if (policy_in != NULL) {
574: buf = ipsec_set_policy(policy_in, strlen(policy_in));
575: if (buf == NULL)
1.57 is 576: errx(1, "%s", ipsec_strerror());
1.92 pooka 577: if (prog_setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
1.55 itojun 578: buf, ipsec_get_policylen(buf)) < 0) {
579: err(1, "ipsec policy cannot be configured");
580: }
581: free(buf);
582: }
583: if (policy_out != NULL) {
584: buf = ipsec_set_policy(policy_out, strlen(policy_out));
585: if (buf == NULL)
1.57 is 586: errx(1, "%s", ipsec_strerror());
1.92 pooka 587: if (prog_setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
1.55 itojun 588: buf, ipsec_get_policylen(buf)) < 0) {
589: err(1, "ipsec policy cannot be configured");
590: }
591: free(buf);
592: }
1.50 itojun 593: }
1.55 itojun 594: buf = ipsec_set_policy("out bypass", strlen("out bypass"));
595: if (buf == NULL)
1.57 is 596: errx(1, "%s", ipsec_strerror());
1.92 pooka 597: if (prog_setsockopt(sloop, IPPROTO_IP, IP_IPSEC_POLICY,
1.55 itojun 598: buf, ipsec_get_policylen(buf)) < 0) {
1.52 itojun 599: #if 0
1.50 itojun 600: warnx("ipsec is not configured");
1.52 itojun 601: #else
602: /* ignore it, should be okay */
603: #endif
604: }
1.50 itojun 605: free(buf);
606: }
607: #else
608: {
609: int optval;
610: if (pingflags & F_AUTHHDR) {
611: optval = IPSEC_LEVEL_REQUIRE;
612: #ifdef IP_AUTH_TRANS_LEVEL
1.92 pooka 613: (void)prog_setsockopt(s, IPPROTO_IP, IP_AUTH_TRANS_LEVEL,
1.50 itojun 614: (char *)&optval, sizeof(optval));
615: #else
1.92 pooka 616: (void)prog_setsockopt(s, IPPROTO_IP, IP_AUTH_LEVEL,
1.50 itojun 617: (char *)&optval, sizeof(optval));
618: #endif
619: }
620: if (pingflags & F_ENCRYPT) {
621: optval = IPSEC_LEVEL_REQUIRE;
1.92 pooka 622: (void)prog_setsockopt(s, IPPROTO_IP, IP_ESP_TRANS_LEVEL,
1.50 itojun 623: (char *)&optval, sizeof(optval));
624: }
625: optval = IPSEC_LEVEL_BYPASS;
626: #ifdef IP_AUTH_TRANS_LEVEL
1.92 pooka 627: (void)prog_setsockopt(sloop, IPPROTO_IP, IP_AUTH_TRANS_LEVEL,
1.50 itojun 628: (char *)&optval, sizeof(optval));
629: #else
1.92 pooka 630: (void)prog_setsockopt(sloop, IPPROTO_IP, IP_AUTH_LEVEL,
1.50 itojun 631: (char *)&optval, sizeof(optval));
632: #endif
1.92 pooka 633: (void)prog_setsockopt(sloop, IPPROTO_IP, IP_ESP_TRANS_LEVEL,
1.50 itojun 634: (char *)&optval, sizeof(optval));
635: }
636: #endif /*IPSEC_POLICY_IPSEC*/
637: #endif /*IPSEC*/
1.8 mycroft 638:
1.30 christos 639: (void)printf("PING %s (%s): %d data bytes\n", hostname,
1.101.2.3 yamt 640: inet_ntoa(whereto.sin_addr), datalen + phdrlen);
1.22 christos 641:
642: /* When pinging the broadcast address, you can get a lot
643: * of answers. Doing something so evil is useful if you
644: * are trying to stress the ethernet, or just want to
645: * fill the arp cache to get some stuff for /etc/ethers.
1.1 cgd 646: */
1.92 pooka 647: while (0 > prog_setsockopt(s, SOL_SOCKET, SO_RCVBUF,
1.22 christos 648: (char*)&bufspace, sizeof(bufspace))) {
1.60 yamt 649: if ((bufspace -= 4096) <= 0)
1.22 christos 650: err(1, "Cannot set the receive buffer size");
651: }
1.1 cgd 652:
1.30 christos 653: /* make it possible to send giant probes, but do not worry now
654: * if it fails, since we probably won't send giant probes.
655: */
1.92 pooka 656: (void)prog_setsockopt(s, SOL_SOCKET, SO_SNDBUF,
1.30 christos 657: (char*)&bufspace, sizeof(bufspace));
1.22 christos 658:
659: (void)signal(SIGINT, prefinish);
1.48 mjl 660:
1.22 christos 661: #ifdef SIGINFO
1.81 christos 662: sa.sa_handler = prtsig;
663: sa.sa_flags = SA_NOKERNINFO;
664: sigemptyset(&sa.sa_mask);
665: (void)sigaction(SIGINFO, &sa, NULL);
1.22 christos 666: #else
667: (void)signal(SIGQUIT, prtsig);
668: #endif
669: (void)signal(SIGCONT, prtsig);
670:
671: /* fire off them quickies */
672: for (i = 0; i < preload; i++) {
1.99 christos 673: clock_gettime(CLOCK_MONOTONIC, &now);
1.1 cgd 674: pinger();
1.22 christos 675: }
676:
677: doit();
678: return 0;
679: }
680:
681:
682: static void
683: doit(void)
684: {
685: int cc;
686: struct sockaddr_in from;
1.78 mrg 687: socklen_t fromlen;
1.30 christos 688: double sec, last, d_last;
1.67 mycroft 689: struct pollfd fdmaskp[1];
1.1 cgd 690:
1.99 christos 691: (void)clock_gettime(CLOCK_MONOTONIC, &clear_cache);
1.30 christos 692: if (maxwait != 0) {
1.99 christos 693: last = timespec_to_sec(&clear_cache) + maxwait;
1.30 christos 694: d_last = 0;
695: } else {
696: last = 0;
697: d_last = 365*24*60*60;
698: }
1.1 cgd 699:
1.30 christos 700: do {
1.99 christos 701: clock_gettime(CLOCK_MONOTONIC, &now);
1.22 christos 702:
1.30 christos 703: if (last != 0)
1.99 christos 704: d_last = last - timespec_to_sec(&now);
1.22 christos 705:
1.30 christos 706: if (ntransmitted < npackets && d_last > 0) {
1.22 christos 707: /* send if within 100 usec or late for next packet */
1.95 christos 708: sec = diffsec(&next_tx, &now);
1.75 itojun 709: if (sec <= 0.0001 ||
710: (lastrcvd && (pingflags & F_FLOOD))) {
1.22 christos 711: pinger();
1.95 christos 712: sec = diffsec(&next_tx, &now);
1.22 christos 713: }
714: if (sec < 0.0)
715: sec = 0.0;
1.30 christos 716: if (d_last < sec)
717: sec = d_last;
1.22 christos 718:
719: } else {
720: /* For the last response, wait twice as long as the
721: * worst case seen, or 10 times as long as the
722: * maximum interpacket interval, whichever is longer.
723: */
1.75 itojun 724: sec = MAX(2 * tmax, 10 * interval) -
725: diffsec(&now, &last_tx);
1.30 christos 726: if (d_last < sec)
727: sec = d_last;
1.22 christos 728: if (sec <= 0)
1.30 christos 729: break;
1.22 christos 730: }
731:
1.67 mycroft 732: fdmaskp[0].fd = s;
733: fdmaskp[0].events = POLLIN;
1.92 pooka 734: cc = prog_poll(fdmaskp, 1, (int)(sec * 1000));
1.22 christos 735: if (cc <= 0) {
736: if (cc < 0) {
737: if (errno == EINTR)
738: continue;
739: jiggle_flush(1);
1.68 mycroft 740: err(1, "poll");
1.22 christos 741: }
742: continue;
1.1 cgd 743: }
1.22 christos 744:
745: fromlen = sizeof(from);
1.92 pooka 746: cc = prog_recvfrom(s, (char *) packet, packlen,
1.30 christos 747: 0, (struct sockaddr *)&from,
1.22 christos 748: &fromlen);
749: if (cc < 0) {
750: if (errno != EINTR) {
751: jiggle_flush(1);
1.30 christos 752: warn("recvfrom");
1.22 christos 753: (void)fflush(stderr);
754: }
1.1 cgd 755: continue;
756: }
1.99 christos 757: clock_gettime(CLOCK_MONOTONIC, &now);
1.22 christos 758: pr_pack(packet, cc, &from);
1.30 christos 759:
760: } while (nreceived < npackets
761: && (nreceived == 0 || !(pingflags & F_ONCE)));
762:
763: finish(0);
1.22 christos 764: }
765:
766:
767: static void
768: jiggle_flush(int nl) /* new line if there are dots */
769: {
770: int serrno = errno;
771:
772: if (jiggle_cnt > 0) {
773: total_jiggled += jiggle_cnt;
774: jiggle_direction = 1;
775: do {
776: (void)putchar('.');
777: } while (--jiggle_cnt > 0);
778:
779: } else if (jiggle_cnt < 0) {
780: total_jiggled -= jiggle_cnt;
781: jiggle_direction = -1;
782: do {
783: (void)putchar('\b');
784: } while (++jiggle_cnt < 0);
785: }
786:
787: if (nl) {
788: if (total_jiggled != 0)
789: (void)putchar('\n');
790: total_jiggled = 0;
791: jiggle_direction = -1;
1.1 cgd 792: }
1.22 christos 793:
794: (void)fflush(stdout);
795: (void)fflush(stderr);
796: jiggle_time = now;
797: errno = serrno;
1.1 cgd 798: }
799:
1.22 christos 800:
801: /* jiggle the cursor for flood-ping
1.1 cgd 802: */
1.22 christos 803: static void
804: jiggle(int delta)
1.1 cgd 805: {
1.22 christos 806: double dt;
1.1 cgd 807:
1.22 christos 808: if (pingflags & F_QUIET)
809: return;
810:
811: /* do not back up into messages */
812: if (total_jiggled+jiggle_cnt+delta < 0)
813: return;
814:
815: jiggle_cnt += delta;
816:
817: /* flush the FLOOD dots when things are quiet
818: * or occassionally to make the cursor jiggle.
819: */
820: dt = diffsec(&last_tx, &jiggle_time);
821: if (dt > 0.2 || (dt >= 0.15 && delta*jiggle_direction < 0))
822: jiggle_flush(0);
1.1 cgd 823: }
824:
1.22 christos 825:
1.1 cgd 826: /*
1.22 christos 827: * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
1.30 christos 828: * will be added on by the kernel. The ID field is our UNIX process ID,
1.99 christos 829: * and the sequence number is an ascending integer. The first phdrlen bytes
1.1 cgd 830: * of the data portion are used to hold a UNIX "timeval" struct in VAX
1.99 christos 831: * byte-order, to compute the round-trip time, or a UNIX "timespec" in native
832: * format.
1.1 cgd 833: */
1.22 christos 834: static void
835: pinger(void)
1.1 cgd 836: {
1.75 itojun 837: struct tv32 tv32;
1.30 christos 838: int i, cc, sw;
1.22 christos 839:
840: opack_icmp.icmp_code = 0;
1.65 itojun 841: opack_icmp.icmp_seq = htons((u_int16_t)(ntransmitted));
1.30 christos 842:
843: /* clear the cached route in the kernel after an ICMP
844: * response such as a Redirect is seen to stop causing
845: * more such packets. Also clear the cached route
846: * periodically in case of routing changes that make
847: * black holes come and go.
848: */
1.22 christos 849: if (clear_cache.tv_sec != now.tv_sec) {
850: opack_icmp.icmp_type = ICMP_ECHOREPLY;
851: opack_icmp.icmp_id = ~ident;
852: opack_icmp.icmp_cksum = 0;
1.65 itojun 853: opack_icmp.icmp_cksum = in_cksum((u_int16_t *)&opack_icmp,
1.99 christos 854: phdrlen);
1.30 christos 855: sw = 0;
1.92 pooka 856: if (prog_setsockopt(sloop,IPPROTO_IP,IP_HDRINCL,
1.30 christos 857: (char *)&sw,sizeof(sw)) < 0)
858: err(1, "Can't turn off special IP header");
1.92 pooka 859: if (prog_sendto(sloop, (char *) &opack_icmp,
1.101.2.3 yamt 860: ICMP_MINLEN, MSG_DONTROUTE,
1.30 christos 861: (struct sockaddr *)&loc_addr,
1.34 christos 862: sizeof(struct sockaddr_in)) < 0) {
863: /*
864: * XXX: we only report this as a warning in verbose
865: * mode because people get confused when they see
866: * this error when they are running in single user
867: * mode and they have not configured lo0
868: */
869: if (pingflags & F_VERBOSE)
870: warn("failed to clear cached route");
871: }
1.30 christos 872: sw = 1;
1.92 pooka 873: if (prog_setsockopt(sloop,IPPROTO_IP,IP_HDRINCL,
1.30 christos 874: (char *)&sw, sizeof(sw)) < 0)
875: err(1, "Can't set special IP header");
876:
1.99 christos 877: (void)clock_gettime(CLOCK_MONOTONIC, &clear_cache);
1.22 christos 878: }
1.30 christos 879:
1.22 christos 880: opack_icmp.icmp_type = ICMP_ECHO;
881: opack_icmp.icmp_id = ident;
1.99 christos 882:
883: if (pingflags & F_TIMING) {
884: tv32.tv32_sec = (uint32_t)htonl(now.tv_sec);
885: tv32.tv32_usec = htonl(now.tv_nsec / 1000);
1.75 itojun 886: (void) memcpy(&opack_icmp.icmp_data[0], &tv32, sizeof(tv32));
1.99 christos 887: } else if (pingflags & F_TIMING64)
888: (void) memcpy(&opack_icmp.icmp_data[0], &now, sizeof(now));
889:
1.101.2.3 yamt 890: cc = MAX(datalen, ICMP_MINLEN) + phdrlen;
1.22 christos 891: opack_icmp.icmp_cksum = 0;
1.65 itojun 892: opack_icmp.icmp_cksum = in_cksum((u_int16_t *)&opack_icmp, cc);
1.22 christos 893:
1.30 christos 894: cc += opack_ip->ip_hl<<2;
895: opack_ip->ip_len = cc;
1.92 pooka 896: i = prog_sendto(s, (char *) opack_ip, cc, 0,
1.30 christos 897: (struct sockaddr *)&send_addr, sizeof(struct sockaddr_in));
1.22 christos 898: if (i != cc) {
899: jiggle_flush(1);
900: if (i < 0)
1.30 christos 901: warn("sendto");
1.22 christos 902: else
1.30 christos 903: warnx("wrote %s %d chars, ret=%d", hostname, cc, i);
1.22 christos 904: (void)fflush(stderr);
905: }
906: lastrcvd = 0;
907:
908: CLR(ntransmitted);
909: ntransmitted++;
910:
911: last_tx = now;
912: if (next_tx.tv_sec == 0) {
913: first_tx = now;
914: next_tx = now;
915: }
1.1 cgd 916:
1.22 christos 917: /* Transmit regularly, at always the same microsecond in the
918: * second when going at one packet per second.
919: * If we are at most 100 ms behind, send extras to get caught up.
920: * Otherwise, skip packets we were too slow to send.
921: */
922: if (diffsec(&next_tx, &now) <= interval) {
923: do {
1.99 christos 924: timespecadd(&next_tx, &interval_tv, &next_tx);
1.22 christos 925: } while (diffsec(&next_tx, &now) < -0.1);
926: }
1.1 cgd 927:
1.22 christos 928: if (pingflags & F_FLOOD)
929: jiggle(1);
1.1 cgd 930:
1.22 christos 931: /* While the packet is going out, ready buffer for the next
932: * packet. Use a fast but not very good random number generator.
933: */
934: if (pingflags & F_PING_RANDOM)
935: rnd_fill();
936: }
1.1 cgd 937:
938:
1.22 christos 939: static void
1.30 christos 940: pr_pack_sub(int cc,
941: char *addr,
942: int seqno,
943: int dupflag,
944: int ttl,
1.22 christos 945: double triptime)
946: {
947: jiggle_flush(1);
1.1 cgd 948:
1.22 christos 949: if (pingflags & F_FLOOD)
950: return;
1.1 cgd 951:
1.22 christos 952: (void)printf("%d bytes from %s: icmp_seq=%u", cc, addr, seqno);
1.30 christos 953: if (dupflag)
954: (void)printf(" DUP!");
1.22 christos 955: (void)printf(" ttl=%d", ttl);
1.101.2.4! yamt 956: if (pingflags & (F_TIMING|F_TIMING64)) {
! 957: const unsigned int prec = (pingflags & F_TIMING64) != 0 ? 6 : 3;
! 958:
! 959: (void)printf(" time=%.*f ms", prec, triptime*1000.0);
! 960: }
1.49 sommerfe 961:
962: /*
963: * Send beep to stderr, since that's more likely than stdout
964: * to go to a terminal..
965: */
966: if (pingflags & F_AUDIBLE && !dupflag)
967: (void)fprintf(stderr,"\a");
1.1 cgd 968: }
969:
1.22 christos 970:
1.1 cgd 971: /*
1.22 christos 972: * Print out the packet, if it came from us. This logic is necessary
1.1 cgd 973: * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
974: * which arrive ('tis only fair). This permits multiple copies of this
975: * program to be run without having intermingled output (or statistics!).
976: */
1.22 christos 977: static void
1.30 christos 978: pr_pack(u_char *buf,
1.41 christos 979: int tot_len,
1.22 christos 980: struct sockaddr_in *from)
1.1 cgd 981: {
1.22 christos 982: struct ip *ip;
1.32 lukem 983: struct icmp *icp;
1.41 christos 984: int i, j, net_len;
1.32 lukem 985: u_char *cp;
1.1 cgd 986: static int old_rrlen;
987: static char old_rr[MAX_IPOPTLEN];
1.22 christos 988: int hlen, dupflag = 0, dumped;
989: double triptime = 0.0;
990: #define PR_PACK_SUB() {if (!dumped) { \
991: dumped = 1; \
1.41 christos 992: pr_pack_sub(net_len, inet_ntoa(from->sin_addr), \
1.65 itojun 993: ntohs((u_int16_t)icp->icmp_seq), \
1.22 christos 994: dupflag, ip->ip_ttl, triptime);}}
1.1 cgd 995:
996: /* Check the IP header */
1.22 christos 997: ip = (struct ip *) buf;
1.1 cgd 998: hlen = ip->ip_hl << 2;
1.41 christos 999: if (tot_len < hlen + ICMP_MINLEN) {
1.22 christos 1000: if (pingflags & F_VERBOSE) {
1001: jiggle_flush(1);
1.30 christos 1002: (void)printf("packet too short (%d bytes) from %s\n",
1.41 christos 1003: tot_len, inet_ntoa(from->sin_addr));
1.22 christos 1004: }
1.1 cgd 1005: return;
1006: }
1007:
1008: /* Now the ICMP part */
1.22 christos 1009: dumped = 0;
1.41 christos 1010: net_len = tot_len - hlen;
1.1 cgd 1011: icp = (struct icmp *)(buf + hlen);
1.22 christos 1012: if (icp->icmp_type == ICMP_ECHOREPLY
1013: && icp->icmp_id == ident) {
1.99 christos 1014:
1.65 itojun 1015: if (icp->icmp_seq == htons((u_int16_t)(ntransmitted-1)))
1.22 christos 1016: lastrcvd = 1;
1017: last_rx = now;
1018: if (first_rx.tv_sec == 0)
1019: first_rx = last_rx;
1020: nreceived++;
1.101.2.4! yamt 1021: if (pingflags & (F_TIMING|F_TIMING64)) {
! 1022: struct timespec tv;
1.75 itojun 1023:
1.101.2.4! yamt 1024: if (pingflags & F_TIMING) {
! 1025: struct tv32 tv32;
! 1026:
! 1027: (void)memcpy(&tv32, icp->icmp_data, sizeof(tv32));
! 1028: tv.tv_sec = (uint32_t)ntohl(tv32.tv32_sec);
! 1029: tv.tv_nsec = ntohl(tv32.tv32_usec) * 1000;
! 1030: } else if (pingflags & F_TIMING64)
! 1031: (void)memcpy(&tv, icp->icmp_data, sizeof(tv));
! 1032: else
! 1033: memset(&tv, 0, sizeof(tv)); /* XXX: gcc */
1.99 christos 1034:
1.26 christos 1035: triptime = diffsec(&last_rx, &tv);
1.1 cgd 1036: tsum += triptime;
1.44 jwise 1037: tsumsq += triptime * triptime;
1.1 cgd 1038: if (triptime < tmin)
1039: tmin = triptime;
1040: if (triptime > tmax)
1041: tmax = triptime;
1042: }
1043:
1.65 itojun 1044: if (TST(ntohs((u_int16_t)icp->icmp_seq))) {
1.22 christos 1045: nrepeats++, nreceived--;
1046: dupflag=1;
1.30 christos 1047: } else {
1.65 itojun 1048: SET(ntohs((u_int16_t)icp->icmp_seq));
1.30 christos 1049: }
1.1 cgd 1050:
1.41 christos 1051: if (tot_len != opack_ip->ip_len) {
1052: PR_PACK_SUB();
1.88 christos 1053: switch (opack_ip->ip_len - tot_len) {
1054: case MAX_IPOPTLEN:
1055: if ((pongflags & F_RECORD_ROUTE) != 0)
1056: break;
1057: if ((pingflags & F_RECORD_ROUTE) == 0)
1058: goto out;
1059: pongflags |= F_RECORD_ROUTE;
1060: (void)printf("\nremote host does not "
1061: "support record route");
1062: break;
1063: case 8:
1064: if ((pongflags & F_SOURCE_ROUTE) != 0)
1065: break;
1066: if ((pingflags & F_SOURCE_ROUTE) == 0)
1067: goto out;
1068: pongflags |= F_SOURCE_ROUTE;
1069: (void)printf("\nremote host does not "
1070: "support source route");
1071: break;
1072: default:
1073: out:
1074: (void)printf("\nwrong total length %d "
1075: "instead of %d", tot_len, opack_ip->ip_len);
1076: break;
1077: }
1.66 matt 1078: }
1079:
1080: if (!dupflag) {
1081: static u_int16_t last_seqno = 0xffff;
1082: u_int16_t seqno = ntohs((u_int16_t)icp->icmp_seq);
1083: u_int16_t gap = seqno - (last_seqno + 1);
1084: if (gap > 0 && gap < 0x8000 &&
1085: (pingflags & F_VERBOSE)) {
1086: (void)printf("[*** sequence gap of %u "
1087: "packets from %u ... %u ***]\n", gap,
1088: (u_int16_t) (last_seqno + 1),
1089: (u_int16_t) (seqno - 1));
1090: if (pingflags & F_QUIET)
1091: summary(0);
1092: }
1093:
1094: if (gap < 0x8000)
1095: last_seqno = seqno;
1.41 christos 1096: }
1097:
1.22 christos 1098: if (pingflags & F_QUIET)
1.1 cgd 1099: return;
1100:
1.22 christos 1101: if (!(pingflags & F_FLOOD))
1102: PR_PACK_SUB();
1103:
1104: /* check the data */
1.101.2.3 yamt 1105: if ((size_t)(tot_len - hlen) >
1106: offsetof(struct icmp, icmp_data) + datalen
1.22 christos 1107: && !(pingflags & F_PING_RANDOM)
1.99 christos 1108: && memcmp(icp->icmp_data + phdrlen,
1109: opack_icmp.icmp_data + phdrlen,
1110: datalen - phdrlen)) {
1111: for (i = phdrlen; i < datalen; i++) {
1.54 mycroft 1112: if (icp->icmp_data[i] !=
1113: opack_icmp.icmp_data[i])
1.1 cgd 1114: break;
1.22 christos 1115: }
1116: PR_PACK_SUB();
1117: (void)printf("\nwrong data byte #%d should have been"
1.54 mycroft 1118: " %#x but was %#x", i,
1119: (u_char)opack_icmp.icmp_data[i],
1.22 christos 1120: (u_char)icp->icmp_data[i]);
1.99 christos 1121: for (i = phdrlen; i < datalen; i++) {
1.101.2.3 yamt 1122: if ((i % 16) == 0)
1.22 christos 1123: (void)printf("\n\t");
1.30 christos 1124: (void)printf("%2x ",(u_char)icp->icmp_data[i]);
1.1 cgd 1125: }
1126: }
1.22 christos 1127:
1.1 cgd 1128: } else {
1.41 christos 1129: if (!pr_icmph(icp, from, net_len))
1.1 cgd 1130: return;
1.22 christos 1131: dumped = 2;
1.1 cgd 1132: }
1133:
1134: /* Display any IP options */
1.22 christos 1135: cp = buf + sizeof(struct ip);
1136: while (hlen > (int)sizeof(struct ip)) {
1.1 cgd 1137: switch (*cp) {
1138: case IPOPT_EOL:
1139: hlen = 0;
1140: break;
1141: case IPOPT_LSRR:
1142: hlen -= 2;
1143: j = *++cp;
1144: ++cp;
1.22 christos 1145: j -= IPOPT_MINOFF;
1146: if (j <= 0)
1147: continue;
1148: if (dumped <= 1) {
1149: j = ((j+3)/4)*4;
1150: hlen -= j;
1151: cp += j;
1152: break;
1153: }
1154: PR_PACK_SUB();
1155: (void)printf("\nLSRR: ");
1156: for (;;) {
1.57 is 1157: pr_saddr(cp);
1.22 christos 1158: cp += 4;
1.1 cgd 1159: hlen -= 4;
1160: j -= 4;
1.22 christos 1161: if (j <= 0)
1.1 cgd 1162: break;
1163: (void)putchar('\n');
1164: }
1165: break;
1166: case IPOPT_RR:
1.22 christos 1167: j = *++cp; /* get length */
1168: i = *++cp; /* and pointer */
1.1 cgd 1169: hlen -= 2;
1170: if (i > j)
1171: i = j;
1172: i -= IPOPT_MINOFF;
1173: if (i <= 0)
1174: continue;
1.22 christos 1175: if (dumped <= 1) {
1176: if (i == old_rrlen
1.30 christos 1177: && !memcmp(cp, old_rr, i)) {
1.22 christos 1178: if (dumped)
1179: (void)printf("\t(same route)");
1180: j = ((i+3)/4)*4;
1181: hlen -= j;
1182: cp += j;
1183: break;
1184: }
1185: old_rrlen = i;
1.30 christos 1186: (void) memcpy(old_rr, cp, i);
1.22 christos 1187: }
1188: if (!dumped) {
1189: jiggle_flush(1);
1190: (void)printf("RR: ");
1191: dumped = 1;
1192: } else {
1193: (void)printf("\nRR: ");
1.1 cgd 1194: }
1195: for (;;) {
1.57 is 1196: pr_saddr(cp);
1.22 christos 1197: cp += 4;
1.1 cgd 1198: hlen -= 4;
1199: i -= 4;
1200: if (i <= 0)
1201: break;
1202: (void)putchar('\n');
1203: }
1204: break;
1205: case IPOPT_NOP:
1.22 christos 1206: if (dumped <= 1)
1207: break;
1208: PR_PACK_SUB();
1.1 cgd 1209: (void)printf("\nNOP");
1210: break;
1.22 christos 1211: #ifdef sgi
1212: case IPOPT_SECURITY: /* RFC 1108 RIPSO BSO */
1213: case IPOPT_ESO: /* RFC 1108 RIPSO ESO */
1214: case IPOPT_CIPSO: /* Commercial IPSO */
1215: if ((sysconf(_SC_IP_SECOPTS)) > 0) {
1216: i = (unsigned)cp[1];
1217: hlen -= i - 1;
1218: PR_PACK_SUB();
1219: (void)printf("\nSEC:");
1220: while (i--) {
1221: (void)printf(" %02x", *cp++);
1222: }
1223: cp--;
1224: break;
1225: }
1226: #endif
1.1 cgd 1227: default:
1.22 christos 1228: PR_PACK_SUB();
1.32 lukem 1229: (void)printf("\nunknown option 0x%x", *cp);
1.1 cgd 1230: break;
1231: }
1.22 christos 1232: hlen--;
1233: cp++;
1234: }
1235:
1236: if (dumped) {
1.1 cgd 1237: (void)putchar('\n');
1238: (void)fflush(stdout);
1.22 christos 1239: } else {
1240: jiggle(-1);
1241: }
1242: }
1243:
1244:
1245: /* Compute the IP checksum
1246: * This assumes the packet is less than 32K long.
1247: */
1.65 itojun 1248: static u_int16_t
1249: in_cksum(u_int16_t *p, u_int len)
1.22 christos 1250: {
1.65 itojun 1251: u_int32_t sum = 0;
1.22 christos 1252: int nwords = len >> 1;
1253:
1254: while (nwords-- != 0)
1255: sum += *p++;
1256:
1257: if (len & 1) {
1258: union {
1.65 itojun 1259: u_int16_t w;
1260: u_int8_t c[2];
1.22 christos 1261: } u;
1262: u.c[0] = *(u_char *)p;
1263: u.c[1] = 0;
1264: sum += u.w;
1.1 cgd 1265: }
1.22 christos 1266:
1267: /* end-around-carry */
1268: sum = (sum >> 16) + (sum & 0xffff);
1269: sum += (sum >> 16);
1270: return (~sum);
1.1 cgd 1271: }
1272:
1.22 christos 1273:
1.1 cgd 1274: /*
1.99 christos 1275: * compute the difference of two timespecs in seconds
1.1 cgd 1276: */
1.22 christos 1277: static double
1.99 christos 1278: diffsec(struct timespec *timenow,
1279: struct timespec *then)
1.22 christos 1280: {
1.97 christos 1281: if (timenow->tv_sec == 0)
1282: return -1;
1.99 christos 1283: return (timenow->tv_sec - then->tv_sec)
1284: * 1.0 + (timenow->tv_nsec - then->tv_nsec) / 1000000000.0;
1.22 christos 1285: }
1286:
1287:
1.99 christos 1288: #if 0
1.22 christos 1289: static void
1.99 christos 1290: timespecadd(struct timespec *t1,
1291: struct timespec *t2)
1.22 christos 1292: {
1293:
1294: t1->tv_sec += t2->tv_sec;
1.99 christos 1295: if ((t1->tv_nsec += t2->tv_nsec) >= 1000000000) {
1.22 christos 1296: t1->tv_sec++;
1.99 christos 1297: t1->tv_nsec -= 1000000000;
1.22 christos 1298: }
1299: }
1.99 christos 1300: #endif
1.22 christos 1301:
1302:
1303: static void
1.99 christos 1304: sec_to_timespec(const double sec, struct timespec *tp)
1.22 christos 1305: {
1.30 christos 1306: tp->tv_sec = sec;
1.99 christos 1307: tp->tv_nsec = (sec - tp->tv_sec) * 1000000000.0;
1.22 christos 1308: }
1.1 cgd 1309:
1.41 christos 1310:
1.22 christos 1311: static double
1.99 christos 1312: timespec_to_sec(const struct timespec *tp)
1.22 christos 1313: {
1.99 christos 1314: return tp->tv_sec + tp->tv_nsec / 1000000000.0;
1.1 cgd 1315: }
1316:
1.22 christos 1317:
1.1 cgd 1318: /*
1.22 christos 1319: * Print statistics.
1320: * Heavily buffered STDIO is used here, so that all the statistics
1321: * will be written with 1 sys-write call. This is nice when more
1322: * than one copy of the program is running on a terminal; it prevents
1323: * the statistics output from becomming intermingled.
1.1 cgd 1324: */
1.22 christos 1325: static void
1326: summary(int header)
1.1 cgd 1327: {
1.22 christos 1328: jiggle_flush(1);
1.8 mycroft 1329:
1.22 christos 1330: if (header)
1331: (void)printf("\n----%s PING Statistics----\n", hostname);
1332: (void)printf("%d packets transmitted, ", ntransmitted);
1333: (void)printf("%d packets received, ", nreceived);
1.1 cgd 1334: if (nrepeats)
1.22 christos 1335: (void)printf("+%d duplicates, ", nrepeats);
1336: if (ntransmitted) {
1.1 cgd 1337: if (nreceived > ntransmitted)
1.64 itojun 1338: (void)printf("-- somebody's duplicating packets!");
1.1 cgd 1339: else
1.41 christos 1340: (void)printf("%.1f%% packet loss",
1341: (((ntransmitted-nreceived)*100.0) /
1.22 christos 1342: ntransmitted));
1343: }
1344: (void)printf("\n");
1.101 christos 1345: if (nreceived && (pingflags & (F_TIMING|F_TIMING64))) {
1.44 jwise 1346: double n = nreceived + nrepeats;
1347: double avg = (tsum / n);
1.47 sommerfe 1348: double variance = 0.0;
1.101.2.4! yamt 1349: const unsigned int prec = (pingflags & F_TIMING64) != 0 ? 6 : 3;
1.47 sommerfe 1350: if (n>1)
1351: variance = (tsumsq - n*avg*avg) /(n-1);
1.44 jwise 1352:
1353: printf("round-trip min/avg/max/stddev = "
1.101.2.4! yamt 1354: "%.*f/%.*f/%.*f/%.*f ms\n",
! 1355: prec, tmin * 1000.0,
! 1356: prec, avg * 1000.0,
! 1357: prec, tmax * 1000.0,
! 1358: prec, sqrt(variance) * 1000.0);
1.22 christos 1359: if (pingflags & F_FLOOD) {
1360: double r = diffsec(&last_rx, &first_rx);
1361: double t = diffsec(&last_tx, &first_tx);
1362: if (r == 0)
1363: r = 0.0001;
1364: if (t == 0)
1365: t = 0.0001;
1366: (void)printf(" %.1f packets/sec sent, "
1.30 christos 1367: " %.1f packets/sec received\n",
1.22 christos 1368: ntransmitted/t, nreceived/r);
1369: }
1.8 mycroft 1370: }
1.21 cgd 1371: }
1372:
1.22 christos 1373:
1374: /*
1375: * Print statistics when SIGINFO is received.
1376: */
1377: /* ARGSUSED */
1378: static void
1.62 lukem 1379: prtsig(int dummy)
1.22 christos 1380: {
1.82 yamt 1381:
1.22 christos 1382: summary(0);
1.81 christos 1383: #ifndef SIGINFO
1.22 christos 1384: (void)signal(SIGQUIT, prtsig);
1385: #endif
1386: }
1387:
1388:
1.21 cgd 1389: /*
1.22 christos 1390: * On the first SIGINT, allow any outstanding packets to dribble in
1.21 cgd 1391: */
1.22 christos 1392: static void
1.62 lukem 1393: prefinish(int dummy)
1.21 cgd 1394: {
1.22 christos 1395: if (lastrcvd /* quit now if caught up */
1396: || nreceived == 0) /* or if remote is dead */
1397: finish(0);
1398:
1.62 lukem 1399: (void)signal(dummy, finish); /* do this only the 1st time */
1.21 cgd 1400:
1.22 christos 1401: if (npackets > ntransmitted) /* let the normal limit work */
1402: npackets = ntransmitted;
1.21 cgd 1403: }
1404:
1405: /*
1.22 christos 1406: * Print statistics and give up.
1.21 cgd 1407: */
1.22 christos 1408: /* ARGSUSED */
1409: static void
1.62 lukem 1410: finish(int dummy)
1.21 cgd 1411: {
1.81 christos 1412: #ifdef SIGINFO
1413: (void)signal(SIGINFO, SIG_DFL);
1.22 christos 1414: #else
1415: (void)signal(SIGQUIT, SIG_DFL);
1416: #endif
1417:
1418: summary(1);
1.30 christos 1419: exit(nreceived > 0 ? 0 : 2);
1.22 christos 1420: }
1421:
1422:
1423: static int /* 0=do not print it */
1.30 christos 1424: ck_pr_icmph(struct icmp *icp,
1425: struct sockaddr_in *from,
1426: int cc,
1.22 christos 1427: int override) /* 1=override VERBOSE if interesting */
1428: {
1429: int hlen;
1.41 christos 1430: struct ip ipb, *ip = &ipb;
1431: struct icmp icp2b, *icp2 = &icp2b;
1.22 christos 1432: int res;
1.21 cgd 1433:
1.22 christos 1434: if (pingflags & F_VERBOSE) {
1435: res = 1;
1436: jiggle_flush(1);
1437: } else {
1438: res = 0;
1439: }
1.21 cgd 1440:
1.41 christos 1441: (void) memcpy(ip, icp->icmp_data, sizeof(*ip));
1442: hlen = ip->ip_hl << 2;
1443: if (ip->ip_p == IPPROTO_ICMP
1.22 christos 1444: && hlen + 6 <= cc) {
1.41 christos 1445: (void) memcpy(icp2, &icp->icmp_data[hlen], sizeof(*icp2));
1446: if (icp2->icmp_id == ident) {
1.22 christos 1447: /* remember to clear route cached in kernel
1.41 christos 1448: * if this non-Echo-Reply ICMP message was for one
1449: * of our packets.
1.22 christos 1450: */
1451: clear_cache.tv_sec = 0;
1452:
1453: if (!res && override
1454: && (pingflags & (F_QUIET|F_SEMI_QUIET)) == 0) {
1455: jiggle_flush(1);
1.30 christos 1456: (void)printf("%d bytes from %s: ",
1.22 christos 1457: cc, pr_addr(&from->sin_addr));
1458: res = 1;
1459: }
1460: }
1461: }
1462:
1463: return res;
1.1 cgd 1464: }
1465:
1466:
1467: /*
1.22 christos 1468: * Print a descriptive string about an ICMP header other than an echo reply.
1.1 cgd 1469: */
1.22 christos 1470: static int /* 0=printed nothing */
1.30 christos 1471: pr_icmph(struct icmp *icp,
1472: struct sockaddr_in *from,
1.22 christos 1473: int cc)
1.1 cgd 1474: {
1.22 christos 1475: switch (icp->icmp_type ) {
1.1 cgd 1476: case ICMP_UNREACH:
1.22 christos 1477: if (!ck_pr_icmph(icp, from, cc, 1))
1478: return 0;
1479: switch (icp->icmp_code) {
1.1 cgd 1480: case ICMP_UNREACH_NET:
1.22 christos 1481: (void)printf("Destination Net Unreachable");
1.1 cgd 1482: break;
1483: case ICMP_UNREACH_HOST:
1.22 christos 1484: (void)printf("Destination Host Unreachable");
1.1 cgd 1485: break;
1486: case ICMP_UNREACH_PROTOCOL:
1.22 christos 1487: (void)printf("Destination Protocol Unreachable");
1.1 cgd 1488: break;
1489: case ICMP_UNREACH_PORT:
1.22 christos 1490: (void)printf("Destination Port Unreachable");
1.1 cgd 1491: break;
1492: case ICMP_UNREACH_NEEDFRAG:
1.30 christos 1493: (void)printf("frag needed and DF set. Next MTU=%d",
1.36 kleink 1494: ntohs(icp->icmp_nextmtu));
1.1 cgd 1495: break;
1496: case ICMP_UNREACH_SRCFAIL:
1.22 christos 1497: (void)printf("Source Route Failed");
1498: break;
1499: case ICMP_UNREACH_NET_UNKNOWN:
1500: (void)printf("Unreachable unknown net");
1501: break;
1502: case ICMP_UNREACH_HOST_UNKNOWN:
1503: (void)printf("Unreachable unknown host");
1504: break;
1505: case ICMP_UNREACH_ISOLATED:
1506: (void)printf("Unreachable host isolated");
1507: break;
1508: case ICMP_UNREACH_NET_PROHIB:
1509: (void)printf("Net prohibited access");
1510: break;
1511: case ICMP_UNREACH_HOST_PROHIB:
1512: (void)printf("Host prohibited access");
1513: break;
1514: case ICMP_UNREACH_TOSNET:
1515: (void)printf("Bad TOS for net");
1516: break;
1517: case ICMP_UNREACH_TOSHOST:
1518: (void)printf("Bad TOS for host");
1519: break;
1520: case 13:
1521: (void)printf("Communication prohibited");
1522: break;
1523: case 14:
1524: (void)printf("Host precedence violation");
1525: break;
1526: case 15:
1527: (void)printf("Precedence cutoff");
1.1 cgd 1528: break;
1529: default:
1.30 christos 1530: (void)printf("Bad Destination Unreachable Code: %d",
1.22 christos 1531: icp->icmp_code);
1.1 cgd 1532: break;
1533: }
1534: /* Print returned IP header information */
1.22 christos 1535: pr_retip(icp, cc);
1.1 cgd 1536: break;
1.22 christos 1537:
1.1 cgd 1538: case ICMP_SOURCEQUENCH:
1.22 christos 1539: if (!ck_pr_icmph(icp, from, cc, 1))
1540: return 0;
1541: (void)printf("Source Quench");
1542: pr_retip(icp, cc);
1.1 cgd 1543: break;
1.22 christos 1544:
1.1 cgd 1545: case ICMP_REDIRECT:
1.22 christos 1546: if (!ck_pr_icmph(icp, from, cc, 1))
1547: return 0;
1548: switch (icp->icmp_code) {
1.1 cgd 1549: case ICMP_REDIRECT_NET:
1.41 christos 1550: (void)printf("Redirect Network");
1.1 cgd 1551: break;
1552: case ICMP_REDIRECT_HOST:
1.41 christos 1553: (void)printf("Redirect Host");
1.1 cgd 1554: break;
1555: case ICMP_REDIRECT_TOSNET:
1.41 christos 1556: (void)printf("Redirect Type of Service and Network");
1.1 cgd 1557: break;
1558: case ICMP_REDIRECT_TOSHOST:
1.41 christos 1559: (void)printf("Redirect Type of Service and Host");
1.1 cgd 1560: break;
1561: default:
1.41 christos 1562: (void)printf("Redirect--Bad Code: %d", icp->icmp_code);
1.1 cgd 1563: break;
1564: }
1.41 christos 1565: (void)printf(" New router addr: %s",
1.22 christos 1566: pr_addr(&icp->icmp_hun.ih_gwaddr));
1567: pr_retip(icp, cc);
1568: break;
1569:
1570: case ICMP_ECHO:
1571: if (!ck_pr_icmph(icp, from, cc, 0))
1572: return 0;
1.30 christos 1573: (void)printf("Echo Request: ID=%d seq=%d",
1.41 christos 1574: ntohs(icp->icmp_id), ntohs(icp->icmp_seq));
1.22 christos 1575: break;
1576:
1577: case ICMP_ECHOREPLY:
1578: /* displaying other's pings is too noisey */
1579: #if 0
1580: if (!ck_pr_icmph(icp, from, cc, 0))
1581: return 0;
1.30 christos 1582: (void)printf("Echo Reply: ID=%d seq=%d",
1.41 christos 1583: ntohs(icp->icmp_id), ntohs(icp->icmp_seq));
1.22 christos 1584: break;
1.1 cgd 1585: #else
1.22 christos 1586: return 0;
1.1 cgd 1587: #endif
1.22 christos 1588:
1589: case ICMP_ROUTERADVERT:
1590: if (!ck_pr_icmph(icp, from, cc, 0))
1591: return 0;
1592: (void)printf("Router Discovery Advert");
1.1 cgd 1593: break;
1.22 christos 1594:
1595: case ICMP_ROUTERSOLICIT:
1596: if (!ck_pr_icmph(icp, from, cc, 0))
1597: return 0;
1598: (void)printf("Router Discovery Solicit");
1.1 cgd 1599: break;
1.22 christos 1600:
1.1 cgd 1601: case ICMP_TIMXCEED:
1.22 christos 1602: if (!ck_pr_icmph(icp, from, cc, 1))
1603: return 0;
1604: switch (icp->icmp_code ) {
1.1 cgd 1605: case ICMP_TIMXCEED_INTRANS:
1.22 christos 1606: (void)printf("Time To Live exceeded");
1.1 cgd 1607: break;
1608: case ICMP_TIMXCEED_REASS:
1.22 christos 1609: (void)printf("Frag reassembly time exceeded");
1.1 cgd 1610: break;
1611: default:
1.30 christos 1612: (void)printf("Time exceeded, Bad Code: %d",
1.22 christos 1613: icp->icmp_code);
1.1 cgd 1614: break;
1615: }
1.22 christos 1616: pr_retip(icp, cc);
1.1 cgd 1617: break;
1.22 christos 1618:
1.1 cgd 1619: case ICMP_PARAMPROB:
1.22 christos 1620: if (!ck_pr_icmph(icp, from, cc, 1))
1621: return 0;
1.30 christos 1622: (void)printf("Parameter problem: pointer = 0x%02x",
1.22 christos 1623: icp->icmp_hun.ih_pptr);
1624: pr_retip(icp, cc);
1.1 cgd 1625: break;
1.22 christos 1626:
1.1 cgd 1627: case ICMP_TSTAMP:
1.22 christos 1628: if (!ck_pr_icmph(icp, from, cc, 0))
1629: return 0;
1630: (void)printf("Timestamp");
1.1 cgd 1631: break;
1.22 christos 1632:
1.1 cgd 1633: case ICMP_TSTAMPREPLY:
1.22 christos 1634: if (!ck_pr_icmph(icp, from, cc, 0))
1635: return 0;
1636: (void)printf("Timestamp Reply");
1.1 cgd 1637: break;
1.22 christos 1638:
1.1 cgd 1639: case ICMP_IREQ:
1.22 christos 1640: if (!ck_pr_icmph(icp, from, cc, 0))
1641: return 0;
1642: (void)printf("Information Request");
1.1 cgd 1643: break;
1.22 christos 1644:
1.1 cgd 1645: case ICMP_IREQREPLY:
1.22 christos 1646: if (!ck_pr_icmph(icp, from, cc, 0))
1647: return 0;
1648: (void)printf("Information Reply");
1.1 cgd 1649: break;
1.22 christos 1650:
1.1 cgd 1651: case ICMP_MASKREQ:
1.22 christos 1652: if (!ck_pr_icmph(icp, from, cc, 0))
1653: return 0;
1654: (void)printf("Address Mask Request");
1.1 cgd 1655: break;
1.22 christos 1656:
1.1 cgd 1657: case ICMP_MASKREPLY:
1.22 christos 1658: if (!ck_pr_icmph(icp, from, cc, 0))
1659: return 0;
1660: (void)printf("Address Mask Reply");
1.1 cgd 1661: break;
1.22 christos 1662:
1.1 cgd 1663: default:
1.22 christos 1664: if (!ck_pr_icmph(icp, from, cc, 0))
1665: return 0;
1666: (void)printf("Bad ICMP type: %d", icp->icmp_type);
1667: if (pingflags & F_VERBOSE)
1668: pr_iph(icp, cc);
1.1 cgd 1669: }
1.22 christos 1670:
1671: return 1;
1.1 cgd 1672: }
1673:
1.22 christos 1674:
1.1 cgd 1675: /*
1.22 christos 1676: * Print an IP header with options.
1.1 cgd 1677: */
1.22 christos 1678: static void
1.30 christos 1679: pr_iph(struct icmp *icp,
1.22 christos 1680: int cc)
1.1 cgd 1681: {
1.22 christos 1682: int hlen;
1683: u_char *cp;
1.41 christos 1684: struct ip ipb, *ip = &ipb;
1.26 christos 1685:
1.41 christos 1686: (void) memcpy(ip, icp->icmp_data, sizeof(*ip));
1.1 cgd 1687:
1.41 christos 1688: hlen = ip->ip_hl << 2;
1.30 christos 1689: cp = (u_char *) &icp->icmp_data[20]; /* point to options */
1.1 cgd 1690:
1.22 christos 1691: (void)printf("\n Vr HL TOS Len ID Flg off TTL Pro cks Src Dst\n");
1.30 christos 1692: (void)printf(" %1x %1x %02x %04x %04x",
1.41 christos 1693: ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id);
1.30 christos 1694: (void)printf(" %1x %04x",
1.41 christos 1695: ((ip->ip_off)&0xe000)>>13, (ip->ip_off)&0x1fff);
1.30 christos 1696: (void)printf(" %02x %02x %04x",
1.41 christos 1697: ip->ip_ttl, ip->ip_p, ip->ip_sum);
1.30 christos 1698: (void)printf(" %15s ",
1.41 christos 1699: inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr));
1700: (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr));
1.22 christos 1701: /* dump any option bytes */
1702: while (hlen-- > 20 && cp < (u_char*)icp+cc) {
1.1 cgd 1703: (void)printf("%02x", *cp++);
1704: }
1705: }
1706:
1707: /*
1.22 christos 1708: * Print an ASCII host address starting from a string of bytes.
1.1 cgd 1709: */
1.22 christos 1710: static void
1.57 is 1711: pr_saddr(u_char *cp)
1.22 christos 1712: {
1.32 lukem 1713: n_long l;
1.22 christos 1714: struct in_addr addr;
1715:
1716: l = (u_char)*++cp;
1717: l = (l<<8) + (u_char)*++cp;
1718: l = (l<<8) + (u_char)*++cp;
1719: l = (l<<8) + (u_char)*++cp;
1720: addr.s_addr = htonl(l);
1.57 is 1721: (void)printf("\t%s", (l == 0) ? "0.0.0.0" : pr_addr(&addr));
1.22 christos 1722: }
1723:
1724:
1725: /*
1726: * Return an ASCII host address
1727: * as a dotted quad and optionally with a hostname
1728: */
1729: static char *
1730: pr_addr(struct in_addr *addr) /* in network order */
1731: {
1732: struct hostent *hp;
1733: static char buf[MAXHOSTNAMELEN+4+16+1];
1734:
1735: if ((pingflags & F_NUMERIC)
1736: || !(hp = gethostbyaddr((char *)addr, sizeof(*addr), AF_INET))) {
1.37 mycroft 1737: (void)snprintf(buf, sizeof(buf), "%s", inet_ntoa(*addr));
1.22 christos 1738: } else {
1.37 mycroft 1739: (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name,
1740: inet_ntoa(*addr));
1.22 christos 1741: }
1742:
1743: return buf;
1.1 cgd 1744: }
1745:
1746: /*
1.22 christos 1747: * Dump some info on a returned (via ICMP) IP packet.
1.1 cgd 1748: */
1.22 christos 1749: static void
1.30 christos 1750: pr_retip(struct icmp *icp,
1.22 christos 1751: int cc)
1.1 cgd 1752: {
1.22 christos 1753: int hlen;
1.30 christos 1754: u_char *cp;
1.41 christos 1755: struct ip ipb, *ip = &ipb;
1.26 christos 1756:
1.41 christos 1757: (void) memcpy(ip, icp->icmp_data, sizeof(*ip));
1.22 christos 1758:
1759: if (pingflags & F_VERBOSE)
1760: pr_iph(icp, cc);
1.1 cgd 1761:
1.41 christos 1762: hlen = ip->ip_hl << 2;
1.30 christos 1763: cp = (u_char *) &icp->icmp_data[hlen];
1.1 cgd 1764:
1.41 christos 1765: if (ip->ip_p == IPPROTO_TCP) {
1.22 christos 1766: if (pingflags & F_VERBOSE)
1.30 christos 1767: (void)printf("\n TCP: from port %u, to port %u",
1.22 christos 1768: (*cp*256+*(cp+1)), (*(cp+2)*256+*(cp+3)));
1.41 christos 1769: } else if (ip->ip_p == IPPROTO_UDP) {
1.22 christos 1770: if (pingflags & F_VERBOSE)
1.30 christos 1771: (void)printf("\n UDP: from port %u, to port %u",
1.22 christos 1772: (*cp*256+*(cp+1)), (*(cp+2)*256+*(cp+3)));
1.41 christos 1773: } else if (ip->ip_p == IPPROTO_ICMP) {
1.26 christos 1774: struct icmp icp2;
1775: (void) memcpy(&icp2, cp, sizeof(icp2));
1776: if (icp2.icmp_type == ICMP_ECHO) {
1777: if (pingflags & F_VERBOSE)
1.30 christos 1778: (void)printf("\n ID=%u icmp_seq=%u",
1.65 itojun 1779: ntohs((u_int16_t)icp2.icmp_id),
1780: ntohs((u_int16_t)icp2.icmp_seq));
1.26 christos 1781: else
1.30 christos 1782: (void)printf(" for icmp_seq=%u",
1.65 itojun 1783: ntohs((u_int16_t)icp2.icmp_seq));
1.26 christos 1784: }
1.22 christos 1785: }
1.1 cgd 1786: }
1787:
1.22 christos 1788: static void
1789: fill(void)
1.1 cgd 1790: {
1.32 lukem 1791: int i, j, k;
1.22 christos 1792: char *cp;
1.1 cgd 1793: int pat[16];
1794:
1.22 christos 1795: for (cp = fill_pat; *cp != '\0'; cp++) {
1.43 christos 1796: if (!isxdigit((unsigned char)*cp))
1.22 christos 1797: break;
1798: }
1799: if (cp == fill_pat || *cp != '\0' || (cp-fill_pat) > 16*2) {
1800: (void)fflush(stdout);
1.30 christos 1801: errx(1, "\"-p %s\": patterns must be specified with"
1802: " 1-32 hex digits\n",
1803: fill_pat);
1.22 christos 1804: }
1805:
1.30 christos 1806: i = sscanf(fill_pat,
1807: "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
1808: &pat[0], &pat[1], &pat[2], &pat[3],
1809: &pat[4], &pat[5], &pat[6], &pat[7],
1810: &pat[8], &pat[9], &pat[10], &pat[11],
1.22 christos 1811: &pat[12], &pat[13], &pat[14], &pat[15]);
1812:
1.99 christos 1813: for (k = phdrlen, j = 0; k <= datalen; k++) {
1.22 christos 1814: opack_icmp.icmp_data[k] = pat[j];
1815: if (++j >= i)
1816: j = 0;
1817: }
1818:
1819: if (!(pingflags & F_QUIET)) {
1.1 cgd 1820: (void)printf("PATTERN: 0x");
1.22 christos 1821: for (j=0; j<i; j++)
1.30 christos 1822: (void)printf("%02x",
1.99 christos 1823: (u_char)opack_icmp.icmp_data[phdrlen + j]);
1.1 cgd 1824: (void)printf("\n");
1825: }
1.22 christos 1826:
1.1 cgd 1827: }
1828:
1.22 christos 1829:
1830: static void
1831: rnd_fill(void)
1832: {
1.41 christos 1833: static u_int32_t rnd;
1.22 christos 1834: int i;
1835:
1.99 christos 1836: for (i = phdrlen; i < datalen; i++) {
1.41 christos 1837: rnd = (3141592621U * rnd + 663896637U);
1838: opack_icmp.icmp_data[i] = rnd>>24;
1.22 christos 1839: }
1840: }
1841:
1.41 christos 1842:
1.22 christos 1843: static void
1.30 christos 1844: gethost(const char *arg,
1845: const char *name,
1846: struct sockaddr_in *sa,
1847: char *realname,
1848: int realname_len)
1.22 christos 1849: {
1.30 christos 1850: struct hostent *hp;
1.22 christos 1851:
1.33 cgd 1852: (void)memset(sa, 0, sizeof(*sa));
1.30 christos 1853: sa->sin_family = AF_INET;
1.69 itojun 1854: sa->sin_len = sizeof(struct sockaddr_in);
1.22 christos 1855:
1.30 christos 1856: /* If it is an IP address, try to convert it to a name to
1857: * have something nice to display.
1858: */
1859: if (inet_aton(name, &sa->sin_addr) != 0) {
1860: if (realname) {
1861: if (pingflags & F_NUMERIC)
1862: hp = 0;
1863: else
1864: hp = gethostbyaddr((char *)&sa->sin_addr,
1865: sizeof(sa->sin_addr),
1866: AF_INET);
1.69 itojun 1867: (void)strlcpy(realname, hp ? hp->h_name : name,
1868: realname_len);
1.30 christos 1869: }
1.22 christos 1870: return;
1.30 christos 1871: }
1872:
1873: hp = gethostbyname(name);
1874: if (!hp)
1875: errx(1, "Cannot resolve \"%s\" (%s)",name,hstrerror(h_errno));
1876:
1877: if (hp->h_addrtype != AF_INET)
1878: errx(1, "%s only supported with IP", arg);
1879:
1.41 christos 1880: (void)memcpy(&sa->sin_addr, hp->h_addr, sizeof(sa->sin_addr));
1.30 christos 1881:
1.69 itojun 1882: if (realname)
1883: (void)strlcpy(realname, hp->h_name, realname_len);
1.22 christos 1884: }
1885:
1886:
1887: static void
1888: usage(void)
1.1 cgd 1889: {
1.50 itojun 1890: #ifdef IPSEC
1891: #ifdef IPSEC_POLICY_IPSEC
1892: #define IPSECOPT "\n [-E policy] "
1893: #else
1894: #define IPSECOPT "\n [-AE] "
1895: #endif /*IPSEC_POLICY_IPSEC*/
1896: #else
1897: #define IPSECOPT ""
1898: #endif /*IPSEC*/
1.42 enami 1899:
1.74 jmmv 1900: (void)fprintf(stderr, "usage: \n"
1.100 wiz 1901: "%s [-aCDdfLnoPQqRrv] [-c count] [-g gateway] [-h host]"
1902: " [-I addr] [-i interval]\n"
1903: " [-l preload] [-p pattern] [-s size] [-T ttl] [-t tos]"
1.50 itojun 1904: " [-w maxwait] " IPSECOPT "host\n",
1.59 cgd 1905: getprogname());
1.1 cgd 1906: exit(1);
1907: }
CVSweb <webmaster@jp.NetBSD.org>