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