1 /*
2 * fping: fast-ping, file-ping, favorite-ping, funky-ping
3 *
4 * Ping a list of target hosts in a round robin fashion.
5 * A better ping overall.
6 *
7 * fping website: http://www.fping.org
8 *
9 * Current maintainer of fping: David Schweikert
10 * Please send suggestions and patches to: david@schweikert.ch
11 *
12 *
13 * Original author: Roland Schemers <schemers@stanford.edu>
14 * IPv6 Support: Jeroen Massar <jeroen@unfix.org / jeroen@ipng.nl>
15 * Improved main loop: David Schweikert <david@schweikert.ch>
16 * Debian Merge, TOS settings: Tobi Oetiker <tobi@oetiker.ch>
17 * Bugfixes, byte order & senseful seq.-numbers: Stephan Fuhrmann (stephan.fuhrmann AT 1und1.de)
18 *
19 *
20 * Redistribution and use in source and binary forms are permitted
21 * provided that the above copyright notice and this paragraph are
22 * duplicated in all such forms and that any documentation,
23 * advertising materials, and other materials related to such
24 * distribution and use acknowledge that the software was developed
25 * by Stanford University. The name of the University may not be used
26 * to endorse or promote products derived from this software without
27 * specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
29 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
30 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
31 */
32
33 #ifdef __cplusplus
34 extern "C" {
35 #endif /* __cplusplus */
36
37 #include "config.h"
38 #include "fping.h"
39 #include "options.h"
40 #include "optparse.h"
41
42 #include <inttypes.h>
43 #include <errno.h>
44 #include <signal.h>
45 #include <stdarg.h>
46 #include <stdio.h>
47 #include <stdint.h>
48 #include <time.h>
49
50 #include "seqmap.h"
51
52 #ifdef HAVE_UNISTD_H
53 #include <unistd.h>
54 #endif /* HAVE_UNISTD_H */
55
56 #ifdef HAVE_STDLIB_H
57 #include <stdlib.h>
58 #endif /* HAVE_STDLIB_H */
59
60 #include <stddef.h>
61 #include <string.h>
62
63 #include <time.h>
64
65 #include <sys/socket.h>
66 #include <sys/time.h>
67 #include <sys/types.h>
68
69 #if HAVE_SYS_FILE_H
70 #include <sys/file.h>
71 #endif /* HAVE_SYS_FILE_H */
72
73 #ifdef IPV6
74 #include <netinet/icmp6.h>
75 #endif
76 #include <netinet/in_systm.h>
77
78 #include <netinet/ip.h>
79 #include <netinet/ip_icmp.h>
80
81 #include <arpa/inet.h>
82 #include <ctype.h>
83 #include <netdb.h>
84
85 #include <sys/select.h>
86
87 /*** compatibility ***/
88
89 /* Mac OS X's getaddrinfo() does not fail if we use an invalid combination,
90 * e.g. AF_INET6 with "127.0.0.1". If we pass AI_UNUSABLE to flags, it behaves
91 * like other platforms. But AI_UNUSABLE isn't available on other platforms,
92 * and we can safely use 0 for flags instead.
93 */
94 #ifndef AI_UNUSABLE
95 #define AI_UNUSABLE 0
96 #endif
97
98 /* MSG_TRUNC available on Linux kernel 2.2+, makes recvmsg return the full
99 * length of the raw packet received, even if the buffer is smaller */
100 #ifndef MSG_TRUNC
101 #define MSG_TRUNC 0
102 #define RECV_BUFSIZE 4096
103 #else
104 #define RECV_BUFSIZE 128
105 #endif
106
107 /*** externals ***/
108
109 extern char* optarg;
110 extern int optind, opterr;
111 #ifndef h_errno
112 extern int h_errno;
113 #endif
114
115 #ifdef __cplusplus
116 }
117 #endif /* __cplusplus */
118
119 /*** Constants ***/
120
121 #if HAVE_SO_TIMESTAMPNS
122 #define CLOCKID CLOCK_REALTIME
123 #endif
124
125 #if !defined(CLOCKID)
126 #if defined(CLOCK_MONOTONIC)
127 #define CLOCKID CLOCK_MONOTONIC
128 #else
129 #define CLOCKID CLOCK_REALTIME
130 #endif
131 #endif
132
133 /*** Ping packet defines ***/
134
135 #define MAX_IP_PACKET 65536 /* (theoretical) max IP packet size */
136 #define SIZE_IP_HDR 40
137 #define SIZE_ICMP_HDR 8 /* from ip_icmp.h */
138 #define MAX_PING_DATA (MAX_IP_PACKET - SIZE_IP_HDR - SIZE_ICMP_HDR)
139
140 #define MAX_GENERATE 100000 /* maximum number of hosts that -g can generate */
141
142 /* sized so as to be like traditional ping */
143 #define DEFAULT_PING_DATA_SIZE 56
144
145 /* maxima and minima */
146 #ifdef FPING_SAFE_LIMITS
147 #define MIN_INTERVAL 1 /* in millisec */
148 #define MIN_PERHOST_INTERVAL 10 /* in millisec */
149 #else
150 #define MIN_INTERVAL 0
151 #define MIN_PERHOST_INTERVAL 0
152 #endif
153
154 /* response time array flags */
155 #define RESP_WAITING -1
156 #define RESP_UNUSED -2
157 #define RESP_ERROR -3
158 #define RESP_TIMEOUT -4
159
160 /* debugging flags */
161 #if defined(DEBUG) || defined(_DEBUG)
162 #define DBG_TRACE 1
163 #define DBG_SENT_TIMES 2
164 #define DBG_RANDOM_LOSE_FEW 4
165 #define DBG_RANDOM_LOSE_MANY 8
166 #define DBG_PRINT_PER_SYSTEM 16
167 #define DBG_REPORT_ALL_RTTS 32
168 #endif /* DEBUG || _DEBUG */
169
170 /* Long names for ICMP packet types */
171 #define ICMP_TYPE_STR_MAX 18
172 char* icmp_type_str[19] = {
173 "ICMP Echo Reply", /* 0 */
174 "",
175 "",
176 "ICMP Unreachable", /* 3 */
177 "ICMP Source Quench", /* 4 */
178 "ICMP Redirect", /* 5 */
179 "",
180 "",
181 "ICMP Echo", /* 8 */
182 "",
183 "",
184 "ICMP Time Exceeded", /* 11 */
185 "ICMP Parameter Problem", /* 12 */
186 "ICMP Timestamp Request", /* 13 */
187 "ICMP Timestamp Reply", /* 14 */
188 "ICMP Information Request", /* 15 */
189 "ICMP Information Reply", /* 16 */
190 "ICMP Mask Request", /* 17 */
191 "ICMP Mask Reply" /* 18 */
192 };
193
194 char* icmp_unreach_str[16] = {
195 "ICMP Network Unreachable", /* 0 */
196 "ICMP Host Unreachable", /* 1 */
197 "ICMP Protocol Unreachable", /* 2 */
198 "ICMP Port Unreachable", /* 3 */
199 "ICMP Unreachable (Fragmentation Needed)", /* 4 */
200 "ICMP Unreachable (Source Route Failed)", /* 5 */
201 "ICMP Unreachable (Destination Network Unknown)", /* 6 */
202 "ICMP Unreachable (Destination Host Unknown)", /* 7 */
203 "ICMP Unreachable (Source Host Isolated)", /* 8 */
204 "ICMP Unreachable (Communication with Network Prohibited)", /* 9 */
205 "ICMP Unreachable (Communication with Host Prohibited)", /* 10 */
206 "ICMP Unreachable (Network Unreachable For Type Of Service)", /* 11 */
207 "ICMP Unreachable (Host Unreachable For Type Of Service)", /* 12 */
208 "ICMP Unreachable (Communication Administratively Prohibited)", /* 13 */
209 "ICMP Unreachable (Host Precedence Violation)", /* 14 */
210 "ICMP Unreachable (Precedence cutoff in effect)" /* 15 */
211 };
212
213 #define ICMP_UNREACH_MAXTYPE 15
214
215 struct event;
216 typedef struct host_entry {
217 int i; /* index into array */
218 char* name; /* name as given by user */
219 char* host; /* text description of host */
220 struct sockaddr_storage saddr; /* internet address */
221 socklen_t saddr_len;
222 int64_t timeout; /* time to wait for response */
223 int64_t last_send_time; /* time of last packet sent */
224 int num_sent; /* number of ping packets sent (for statistics) */
225 int num_recv; /* number of pings received (duplicates ignored) */
226 int num_recv_total; /* number of pings received, including duplicates */
227 int64_t max_reply; /* longest response time */
228 int64_t min_reply; /* shortest response time */
229 int64_t total_time; /* sum of response times */
230 /* _i -> splits (reset on every report interval) */
231 int num_sent_i; /* number of ping packets sent */
232 int num_recv_i; /* number of pings received */
233 int64_t max_reply_i; /* longest response time */
234 int64_t min_reply_i; /* shortest response time */
235 int64_t total_time_i; /* sum of response times */
236 int64_t* resp_times; /* individual response times */
237
238 /* to avoid allocating two struct events each time that we send a ping, we
239 * preallocate here two struct events for each ping that we might send for
240 * this host. */
241 struct event *event_storage_ping;
242 struct event *event_storage_timeout;
243 } HOST_ENTRY;
244
245 int event_storage_count; /* how many events can be stored in host_entry->event_storage_xxx */
246
247 /* basic algorithm to ensure that we have correct data at all times:
248 *
249 * 1. when a ping is sent:
250 * - two events get added into event_queue:
251 * - t+PERIOD: ping event
252 * - t+TIMEOUT: timeout event
253 *
254 * 2. when a ping is received:
255 * - record statistics (increase num_sent and num_received)
256 * - remove timeout event (we store the event in seqmap, so that we can retrieve it when the response is received)
257 *
258 * 3. when a timeout happens:
259 * - record statistics (increase num_sent only)
260 */
261
262 #define EV_TYPE_PING 1
263 #define EV_TYPE_TIMEOUT 2
264
265 struct event {
266 struct event *ev_prev;
267 struct event *ev_next;
268 int64_t ev_time;
269 struct host_entry *host;
270 int ping_index;
271 };
272
273 struct event_queue {
274 struct event *first;
275 struct event *last;
276 };
277
278 /*** globals ***/
279
280 HOST_ENTRY** table = NULL; /* array of pointers to items in the list */
281
282 /* we keep two separate queues: a ping queue, for when the next ping should be
283 * sent, and a timeout queue. the reason for having two separate queues is that
284 * the ping period and the timeout value are different, so if we put them in
285 * the same event queue, we would need to scan many more entries when inserting
286 * into the sorted list.
287 */
288 struct event_queue event_queue_ping;
289 struct event_queue event_queue_timeout;
290
291 char* prog;
292 int ident4 = 0; /* our icmp identity field */
293 int ident6 = 0;
294 int socket4 = -1;
295 int socktype4 = -1;
296 int using_sock_dgram4 = 0;
297 #ifndef IPV6
298 int hints_ai_family = AF_INET;
299 #else
300 int socket6 = -1;
301 int socktype6 = -1;
302 int hints_ai_family = AF_UNSPEC;
303 #endif
304
305 volatile sig_atomic_t status_snapshot = 0;
306 volatile sig_atomic_t finish_requested = 0;
307
308 unsigned int debugging = 0;
309
310 /* all time-related values are int64_t nanoseconds */
311 unsigned int retry = DEFAULT_RETRY;
312 int64_t timeout = (int64_t) DEFAULT_TIMEOUT * 1000000;
313 int64_t interval = (int64_t) DEFAULT_INTERVAL * 1000000;
314 int64_t perhost_interval = (int64_t) DEFAULT_PERHOST_INTERVAL * 1000000;
315 float backoff = DEFAULT_BACKOFF_FACTOR;
316 unsigned int ping_data_size = DEFAULT_PING_DATA_SIZE;
317 unsigned int count = 1, min_reachable = 0;
318 unsigned int trials;
319 int64_t report_interval = 0;
320 unsigned int ttl = 0;
321 int src_addr_set = 0;
322 struct in_addr src_addr;
323 #ifdef IPV6
324 int src_addr6_set = 0;
325 struct in6_addr src_addr6;
326 #endif
327
328 /* global stats */
329 int64_t max_reply = 0;
330 int64_t min_reply = 0;
331 int64_t total_replies = 0;
332 int64_t sum_replies = 0;
333 int max_hostname_len = 0;
334 int num_hosts = 0; /* total number of hosts */
335 int num_alive = 0, /* total number alive */
336 num_unreachable = 0, /* total number unreachable */
337 num_noaddress = 0; /* total number of addresses not found */
338 int num_timeout = 0, /* number of times select timed out */
339 num_pingsent = 0, /* total pings sent */
340 num_pingreceived = 0, /* total pings received */
341 num_othericmprcvd = 0; /* total non-echo-reply ICMP received */
342
343 struct timespec current_time; /* current time (pseudo) */
344 int64_t current_time_ns;
345 int64_t start_time;
346 int64_t end_time;
347 int64_t last_send_time; /* time last ping was sent */
348 int64_t next_report_time; /* time next -Q report is expected */
349
350 /* switches */
351 int generate_flag = 0; /* flag for IP list generation */
352 int verbose_flag, quiet_flag, stats_flag, unreachable_flag, alive_flag;
353 int elapsed_flag, version_flag, count_flag, loop_flag, netdata_flag;
354 int per_recv_flag, report_all_rtts_flag, name_flag, addr_flag, backoff_flag, rdns_flag;
355 int multif_flag, timeout_flag;
356 int outage_flag = 0;
357 int timestamp_flag = 0;
358 int random_data_flag = 0;
359 #if defined(DEBUG) || defined(_DEBUG)
360 int randomly_lose_flag, trace_flag, print_per_system_flag;
361 int lose_factor;
362 #endif /* DEBUG || _DEBUG */
363
364 char* filename = NULL; /* file containing hosts to ping */
365
366 /*** forward declarations ***/
367
368 void add_name(char* name);
369 void add_addr(char* name, char* host, struct sockaddr* ipaddr, socklen_t ipaddr_len);
370 char* na_cat(char* name, struct in_addr ipaddr);
371 void crash_and_burn(char* message);
372 void errno_crash_and_burn(char* message);
373 char* get_host_by_address(struct in_addr in);
374 int send_ping(HOST_ENTRY* h, int index);
375 void usage(int);
376 int wait_for_reply(int64_t);
377 void print_per_system_stats(void);
378 void print_per_system_splits(void);
379 void print_netdata(void);
380 void print_global_stats(void);
381 void main_loop();
382 void signal_handler(int);
383 void finish();
384 const char* sprint_tm(int64_t t);
385 void ev_enqueue(struct event_queue *queue, struct event *event);
386 struct event *ev_dequeue(struct event_queue *queue);
387 void ev_remove(struct event_queue *queue, struct event *event);
388 void add_cidr(char*);
389 void add_range(char*, char*);
390 void print_warning(char* fmt, ...);
391 int addr_cmp(struct sockaddr* a, struct sockaddr* b);
392 void host_add_ping_event(HOST_ENTRY *h, int index, int64_t ev_time);
393 void host_add_timeout_event(HOST_ENTRY *h, int index, int64_t ev_time);
394 struct event *host_get_timeout_event(HOST_ENTRY *h, int index);
395 void stats_add(HOST_ENTRY *h, int index, int success, int64_t latency);
396 void update_current_time();
397
398 /************************************************************
399
400 Function: main
401
402 *************************************************************
403
404 Inputs: int argc, char** argv
405
406 Description:
407
408 Main program entry point
409
410 ************************************************************/
411
main(int argc,char ** argv)412 int main(int argc, char** argv)
413 {
414 int c;
415 uid_t uid;
416 int tos = 0;
417 struct optparse optparse_state;
418 #ifdef USE_SIGACTION
419 struct sigaction act;
420 #endif
421
422 /* pre-parse -h/--help, so that we also can output help information
423 * without trying to open the socket, which might fail */
424 prog = argv[0];
425 if(argc == 2 && ( strcmp(argv[1],"-h")==0 || strcmp(argv[1],"--help")==0 )) {
426 usage(0);
427 }
428
429 socket4 = open_ping_socket_ipv4(&socktype4);
430 #ifdef __linux__
431 /* We only treat SOCK_DGRAM differently on Linux, where the IPv4 header
432 * structure is missing in the message.
433 */
434 using_sock_dgram4 = (socktype4 == SOCK_DGRAM);
435 #endif
436
437 #ifdef IPV6
438 socket6 = open_ping_socket_ipv6(&socktype6);
439 /* if called (sym-linked) via 'fping6', imply '-6'
440 * for backward compatibility */
441 if (strstr(prog, "fping6")) {
442 hints_ai_family = AF_INET6;
443 }
444 #endif
445
446 memset(&src_addr, 0, sizeof(src_addr));
447 #ifdef IPV6
448 memset(&src_addr6, 0, sizeof(src_addr6));
449 #endif
450
451 if ((uid = getuid())) {
452 /* drop privileges */
453 if (setuid(getuid()) == -1)
454 perror("cannot setuid");
455 }
456
457 optparse_init(&optparse_state, argv);
458 ident4 = ident6 = htons(getpid() & 0xFFFF);
459 verbose_flag = 1;
460 backoff_flag = 1;
461 opterr = 1;
462
463 /* get command line options */
464
465 struct optparse_long longopts[] = {
466 { "ipv4", '4', OPTPARSE_NONE },
467 { "ipv6", '6', OPTPARSE_NONE },
468 { "alive", 'a', OPTPARSE_NONE },
469 { "addr", 'A', OPTPARSE_NONE },
470 { "size", 'b', OPTPARSE_REQUIRED },
471 { "backoff", 'B', OPTPARSE_REQUIRED },
472 { "count", 'c', OPTPARSE_REQUIRED },
473 { "vcount", 'C', OPTPARSE_REQUIRED },
474 { "rdns", 'd', OPTPARSE_NONE },
475 { "timestamp", 'D', OPTPARSE_NONE },
476 { "elapsed", 'e', OPTPARSE_NONE },
477 { "file", 'f', OPTPARSE_REQUIRED },
478 { "generate", 'g', OPTPARSE_NONE },
479 { "help", 'h', OPTPARSE_NONE },
480 { "ttl", 'H', OPTPARSE_REQUIRED },
481 { "interval", 'i', OPTPARSE_REQUIRED },
482 { "iface", 'I', OPTPARSE_REQUIRED },
483 { "loop", 'l', OPTPARSE_NONE },
484 { "all", 'm', OPTPARSE_NONE },
485 { "dontfrag", 'M', OPTPARSE_NONE },
486 { "name", 'n', OPTPARSE_NONE },
487 { "netdata", 'N', OPTPARSE_NONE },
488 { "outage", 'o', OPTPARSE_NONE },
489 { "tos", 'O', OPTPARSE_REQUIRED },
490 { "period", 'p', OPTPARSE_REQUIRED },
491 { "quiet", 'q', OPTPARSE_NONE },
492 { "squiet", 'Q', OPTPARSE_REQUIRED },
493 { "retry", 'r', OPTPARSE_REQUIRED },
494 { "random", 'R', OPTPARSE_NONE },
495 { "stats", 's', OPTPARSE_NONE },
496 { "src", 'S', OPTPARSE_REQUIRED },
497 { "timeout", 't', OPTPARSE_REQUIRED },
498 { NULL, 'T', OPTPARSE_REQUIRED },
499 { "unreach", 'u', OPTPARSE_NONE },
500 { "version", 'v', OPTPARSE_NONE },
501 { "reachable", 'x', OPTPARSE_REQUIRED },
502 #if defined(DEBUG) || defined(_DEBUG)
503 { NULL, 'z', OPTPARSE_REQUIRED },
504 #endif
505 { 0, 0, 0 }
506 };
507
508 float opt_value_float;
509 while ((c = optparse_long(&optparse_state, longopts, NULL)) != EOF) {
510 switch (c) {
511 case '4':
512 #ifdef IPV6
513 if (hints_ai_family != AF_UNSPEC) {
514 fprintf(stderr, "%s: can't specify both -4 and -6\n", prog);
515 exit(1);
516 }
517 hints_ai_family = AF_INET;
518 #endif
519 break;
520 case '6':
521 #ifdef IPV6
522 if (hints_ai_family != AF_UNSPEC && hints_ai_family != AF_INET6) {
523 fprintf(stderr, "%s: can't specify both -4 and -6\n", prog);
524 exit(1);
525 }
526 hints_ai_family = AF_INET6;
527 #else
528 fprintf(stderr, "%s: IPv6 not supported by this binary\n", prog);
529 exit(1);
530 #endif
531 break;
532 case 'M':
533 #ifdef IP_MTU_DISCOVER
534 if (socket4 >= 0) {
535 int val = IP_PMTUDISC_DO;
536 if (setsockopt(socket4, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val))) {
537 perror("setsockopt IP_MTU_DISCOVER");
538 }
539 }
540 #ifdef IPV6
541 if (socket6 >= 0) {
542 int val = IPV6_PMTUDISC_DO;
543 if (setsockopt(socket6, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val, sizeof(val))) {
544 perror("setsockopt IPV6_MTU_DISCOVER");
545 }
546 }
547 #endif
548 #else
549 fprintf(stderr, "%s, -M option not supported on this platform\n", prog);
550 exit(1);
551 #endif
552 break;
553
554 case 't':
555 if (!sscanf(optparse_state.optarg, "%f", &opt_value_float))
556 usage(1);
557 if (opt_value_float < 0) {
558 usage(1);
559 }
560 timeout = opt_value_float * 1000000;
561 timeout_flag = 1;
562 break;
563
564 case 'r':
565 if (!sscanf(optparse_state.optarg, "%u", &retry))
566 usage(1);
567 break;
568
569 case 'i':
570 if (!sscanf(optparse_state.optarg, "%f", &opt_value_float))
571 usage(1);
572 if (opt_value_float < 0) {
573 usage(1);
574 }
575 interval = opt_value_float * 1000000;
576 break;
577
578 case 'p':
579 if (!sscanf(optparse_state.optarg, "%f", &opt_value_float))
580 usage(1);
581 if (opt_value_float < 0) {
582 usage(1);
583 }
584 perhost_interval = opt_value_float * 1000000;
585
586 break;
587
588 case 'c':
589 if (!(count = (unsigned int)atoi(optparse_state.optarg)))
590 usage(1);
591
592 count_flag = 1;
593 break;
594
595 case 'C':
596 if (!(count = (unsigned int)atoi(optparse_state.optarg)))
597 usage(1);
598
599 count_flag = 1;
600 report_all_rtts_flag = 1;
601 break;
602
603 case 'b':
604 if (!sscanf(optparse_state.optarg, "%u", &ping_data_size))
605 usage(1);
606
607 break;
608
609 case 'h':
610 usage(0);
611 break;
612
613 case 'q':
614 verbose_flag = 0;
615 quiet_flag = 1;
616 break;
617
618 case 'Q':
619 verbose_flag = 0;
620 quiet_flag = 1;
621 if (!sscanf(optparse_state.optarg, "%f", &opt_value_float))
622 usage(1);
623 if (opt_value_float < 0) {
624 usage(1);
625 }
626 report_interval = opt_value_float * 1e9;
627
628 break;
629
630 case 'e':
631 elapsed_flag = 1;
632 break;
633
634 case 'm':
635 multif_flag = 1;
636 break;
637
638 case 'N':
639 netdata_flag = 1;
640 break;
641
642 case 'n':
643 name_flag = 1;
644 if (rdns_flag) {
645 fprintf(stderr, "%s: use either one of -d or -n\n", prog);
646 exit(1);
647 }
648 break;
649
650 case 'd':
651 rdns_flag = 1;
652 if (name_flag) {
653 fprintf(stderr, "%s: use either one of -d or -n\n", prog);
654 exit(1);
655 }
656 break;
657
658 case 'A':
659 addr_flag = 1;
660 break;
661
662 case 'B':
663 if (!(backoff = atof(optparse_state.optarg)))
664 usage(1);
665
666 break;
667
668 case 's':
669 stats_flag = 1;
670 break;
671
672 case 'D':
673 timestamp_flag = 1;
674 break;
675
676 case 'R':
677 random_data_flag = 1;
678 break;
679
680 case 'l':
681 loop_flag = 1;
682 backoff_flag = 0;
683 break;
684
685 case 'u':
686 unreachable_flag = 1;
687 break;
688
689 case 'a':
690 alive_flag = 1;
691 break;
692
693 case 'H':
694 if (!(ttl = (unsigned int)atoi(optparse_state.optarg)))
695 usage(1);
696 break;
697
698 #if defined(DEBUG) || defined(_DEBUG)
699 case 'z':
700 if (sscanf(optparse_state.optarg, "0x%x", &debugging) != 1)
701 if (sscanf(optparse_state.optarg, "%u", &debugging) != 1)
702 usage(1);
703
704 break;
705 #endif /* DEBUG || _DEBUG */
706
707 case 'v':
708 printf("%s: Version %s\n", prog, VERSION);
709 exit(0);
710
711 case 'x':
712 if (!(min_reachable = (unsigned int)atoi(optparse_state.optarg)))
713 usage(1);
714 break;
715
716 case 'f':
717 filename = optparse_state.optarg;
718 break;
719
720 case 'g':
721 /* use IP list generation */
722 /* mutually exclusive with using file input or command line targets */
723 generate_flag = 1;
724 break;
725
726 case 'S':
727 if (inet_pton(AF_INET, optparse_state.optarg, &src_addr)) {
728 src_addr_set = 1;
729 break;
730 }
731 #ifdef IPV6
732 if (inet_pton(AF_INET6, optparse_state.optarg, &src_addr6)) {
733 src_addr6_set = 1;
734 break;
735 }
736 #endif
737 fprintf(stderr, "%s: can't parse source address: %s\n", prog, optparse_state.optarg);
738 exit(1);
739
740 case 'I':
741 #ifdef SO_BINDTODEVICE
742 if (socket4 >= 0) {
743 if (setsockopt(socket4, SOL_SOCKET, SO_BINDTODEVICE, optparse_state.optarg, strlen(optparse_state.optarg))) {
744 perror("binding to specific interface (SO_BINTODEVICE)");
745 exit(1);
746 }
747 }
748 #ifdef IPV6
749 if (socket6 >= 0) {
750 if (setsockopt(socket6, SOL_SOCKET, SO_BINDTODEVICE, optparse_state.optarg, strlen(optparse_state.optarg))) {
751 perror("binding to specific interface (SO_BINTODEVICE), IPV6");
752 exit(1);
753 }
754 }
755 #endif
756 #else
757 printf("%s: cant bind to a particular net interface since SO_BINDTODEVICE is not supported on your os.\n", prog);
758 exit(3);
759 ;
760 #endif
761 break;
762
763 case 'T':
764 /* This option is ignored for compatibility reasons ("select timeout" is not meaningful anymore) */
765 break;
766
767 case 'O':
768 if (sscanf(optparse_state.optarg, "%i", &tos)) {
769 if (socket4 >= 0) {
770 if (setsockopt(socket4, IPPROTO_IP, IP_TOS, &tos, sizeof(tos))) {
771 perror("setting type of service octet IP_TOS");
772 }
773 }
774 #if defined(IPV6) && defined(IPV6_TCLASS)
775 if (socket6 >= 0) {
776 if (setsockopt(socket6, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos))) {
777 perror("setting type of service octet IPV6_TCLASS");
778 }
779 }
780 #endif
781 }
782 else {
783 usage(1);
784 }
785 break;
786
787 case 'o':
788 outage_flag = 1;
789 break;
790
791 case '?':
792 fprintf(stderr, "%s: %s\n", argv[0], optparse_state.errmsg);
793 fprintf(stderr, "see 'fping -h' for usage information\n");
794 exit(1);
795 break;
796 }
797 }
798
799 /* validate various option settings */
800
801 #ifndef IPV6
802 if (socket4 < 0) {
803 #else
804 if ((socket4 < 0 && socket6 < 0) || (hints_ai_family == AF_INET6 && socket6 < 0)) {
805 #endif
806 crash_and_burn("can't create socket (must run as root?)");
807 }
808
809 if (ttl > 255) {
810 fprintf(stderr, "%s: ttl %u out of range\n", prog, ttl);
811 exit(1);
812 }
813
814 if (unreachable_flag && alive_flag) {
815 fprintf(stderr, "%s: specify only one of a, u\n", prog);
816 exit(1);
817 }
818
819 if (count_flag && loop_flag) {
820 fprintf(stderr, "%s: specify only one of c, l\n", prog);
821 exit(1);
822 }
823
824 #ifdef FPING_SAFE_LIMITS
825 if ((interval < (int64_t) MIN_INTERVAL * 1000000 || perhost_interval < (int64_t) MIN_PERHOST_INTERVAL * 1000000)
826 && getuid()) {
827 fprintf(stderr, "%s: these options are too risky for mere mortals.\n", prog);
828 fprintf(stderr, "%s: You need -i >= %u and -p >= %u\n",
829 prog, MIN_INTERVAL, MIN_PERHOST_INTERVAL);
830 exit(1);
831 }
832 #endif
833
834 if (ping_data_size > MAX_PING_DATA) {
835 fprintf(stderr, "%s: data size %u not valid, must be lower than %u\n",
836 prog, ping_data_size, (unsigned int)MAX_PING_DATA);
837 exit(1);
838 }
839
840 if ((backoff > MAX_BACKOFF_FACTOR) || (backoff < MIN_BACKOFF_FACTOR)) {
841 fprintf(stderr, "%s: backoff factor %.1f not valid, must be between %.1f and %.1f\n",
842 prog, backoff, MIN_BACKOFF_FACTOR, MAX_BACKOFF_FACTOR);
843 exit(1);
844 }
845
846 if (alive_flag || unreachable_flag || min_reachable)
847 verbose_flag = 0;
848
849 if (count_flag) {
850 if (verbose_flag)
851 per_recv_flag = 1;
852
853 alive_flag = unreachable_flag = verbose_flag = 0;
854 }
855
856 if (loop_flag) {
857 if (!report_interval)
858 per_recv_flag = 1;
859
860 alive_flag = unreachable_flag = verbose_flag = 0;
861 }
862
863 trials = (count > retry + 1) ? count : retry + 1;
864
865 /* auto-tune default timeout for count/loop modes
866 * see also github #32 */
867 if (loop_flag || count_flag) {
868 if (!timeout_flag) {
869 timeout = perhost_interval;
870 if (timeout > (int64_t) AUTOTUNE_TIMEOUT_MAX * 1000000) {
871 timeout = (int64_t) AUTOTUNE_TIMEOUT_MAX * 1000000;
872 }
873 }
874 }
875
876 #if defined(DEBUG) || defined(_DEBUG)
877 if (debugging & DBG_TRACE)
878 trace_flag = 1;
879
880 if (debugging & DBG_RANDOM_LOSE_FEW) {
881 randomly_lose_flag = 1;
882 lose_factor = 1; /* ie, 1/4 */
883 }
884
885 if (debugging & DBG_RANDOM_LOSE_MANY) {
886 randomly_lose_flag = 1;
887 lose_factor = 5; /* ie, 3/4 */
888 }
889
890 if (debugging & DBG_PRINT_PER_SYSTEM)
891 print_per_system_flag = 1;
892
893 if ((debugging & DBG_REPORT_ALL_RTTS) && !loop_flag)
894 report_all_rtts_flag = 1;
895
896 if (trace_flag) {
897 fprintf(stderr, "%s:\n count: %u, retry: %u, interval: %.0f ms\n",
898 prog, count, retry, interval / 1e6);
899 fprintf(stderr, " perhost_interval: %.0f ms, timeout: %.0f\n",
900 perhost_interval / 1e6, timeout / 1e6);
901 fprintf(stderr, " ping_data_size = %u, trials = %u\n",
902 ping_data_size, trials);
903
904 if (verbose_flag)
905 fprintf(stderr, " verbose_flag set\n");
906 if (multif_flag)
907 fprintf(stderr, " multif_flag set\n");
908 if (name_flag)
909 fprintf(stderr, " name_flag set\n");
910 if (addr_flag)
911 fprintf(stderr, " addr_flag set\n");
912 if (stats_flag)
913 fprintf(stderr, " stats_flag set\n");
914 if (unreachable_flag)
915 fprintf(stderr, " unreachable_flag set\n");
916 if (alive_flag)
917 fprintf(stderr, " alive_flag set\n");
918 if (elapsed_flag)
919 fprintf(stderr, " elapsed_flag set\n");
920 if (version_flag)
921 fprintf(stderr, " version_flag set\n");
922 if (count_flag)
923 fprintf(stderr, " count_flag set\n");
924 if (loop_flag)
925 fprintf(stderr, " loop_flag set\n");
926 if (backoff_flag)
927 fprintf(stderr, " backoff_flag set\n");
928 if (per_recv_flag)
929 fprintf(stderr, " per_recv_flag set\n");
930 if (report_all_rtts_flag)
931 fprintf(stderr, " report_all_rtts_flag set\n");
932 if (randomly_lose_flag)
933 fprintf(stderr, " randomly_lose_flag set\n");
934 if (print_per_system_flag)
935 fprintf(stderr, " print_per_system_flag set\n");
936 if (outage_flag)
937 fprintf(stderr, " outage_flag set\n");
938 if (netdata_flag)
939 fprintf(stderr, " netdata_flag set\n");
940 }
941 #endif /* DEBUG || _DEBUG */
942
943 /* set the TTL, if the -H option was set (otherwise ttl will be = 0) */
944 if (ttl > 0) {
945 if (socket4 >= 0) {
946 if (setsockopt(socket4, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl))) {
947 perror("setting time to live");
948 }
949 }
950 #ifdef IPV6
951 if (socket6 >= 0) {
952 if (setsockopt(socket6, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl))) {
953 perror("setting time to live");
954 }
955 }
956 #endif
957 }
958
959 #if HAVE_SO_TIMESTAMPNS
960 {
961 int opt = 1;
962 if (socket4 >= 0) {
963 if (setsockopt(socket4, SOL_SOCKET, SO_TIMESTAMPNS, &opt, sizeof(opt))) {
964 perror("setting SO_TIMESTAMPNS option");
965 }
966 }
967 #ifdef IPV6
968 if (socket6 >= 0) {
969 if (setsockopt(socket6, SOL_SOCKET, SO_TIMESTAMPNS, &opt, sizeof(opt))) {
970 perror("setting SO_TIMESTAMPNS option (IPv6)");
971 }
972 }
973 #endif
974 }
975 #endif
976
977 update_current_time();
978 start_time = current_time_ns;
979
980 /* handle host names supplied on command line or in a file */
981 /* if the generate_flag is on, then generate the IP list */
982
983 argv = &argv[optparse_state.optind];
984 argc -= optparse_state.optind;
985
986 /* calculate how many ping can be in-flight per host */
987 if(count_flag) {
988 event_storage_count = count;
989 }
990 else if(loop_flag) {
991 if(perhost_interval > timeout) {
992 event_storage_count = 1;
993 }
994 else {
995 event_storage_count = 1 + timeout / perhost_interval;
996 }
997 }
998 else {
999 event_storage_count = 1;
1000 }
1001
1002 /* file and generate are mutually exclusive */
1003 /* file and command line are mutually exclusive */
1004 /* generate requires command line parameters beyond the switches */
1005 if ((*argv && filename) || (filename && generate_flag) || (generate_flag && !*argv))
1006 usage(1);
1007
1008 /* if no conditions are specified, then assume input from stdin */
1009 if (!*argv && !filename && !generate_flag)
1010 filename = "-";
1011
1012 if (*argv && !generate_flag) {
1013 while (*argv) {
1014 add_name(*argv);
1015 ++argv;
1016 }
1017 }
1018 else if (filename) {
1019 FILE* ping_file;
1020 char line[132];
1021 char host[132];
1022
1023 if (strcmp(filename, "-") == 0)
1024 ping_file = fdopen(0, "r");
1025 else
1026 ping_file = fopen(filename, "r");
1027
1028 if (!ping_file)
1029 errno_crash_and_burn("fopen");
1030
1031 while (fgets(line, sizeof(line), ping_file)) {
1032 if (sscanf(line, "%s", host) != 1)
1033 continue;
1034
1035 if ((!*host) || (host[0] == '#')) /* magic to avoid comments */
1036 continue;
1037
1038 add_name(host);
1039 }
1040
1041 fclose(ping_file);
1042 }
1043 else if (*argv && generate_flag) {
1044 if (argc == 1) {
1045 /* one target: we expect a cidr range (n.n.n.n/m) */
1046 add_cidr(argv[0]);
1047 }
1048 else if (argc == 2) {
1049 add_range(argv[0], argv[1]);
1050 }
1051 else {
1052 usage(1);
1053 }
1054 }
1055 else {
1056 usage(1);
1057 }
1058
1059 if (!num_hosts) {
1060 exit(num_noaddress ? 2 : 1);
1061 }
1062
1063 if (src_addr_set && socket4 >= 0) {
1064 socket_set_src_addr_ipv4(socket4, &src_addr, (socktype4 == SOCK_DGRAM) ? &ident4 : NULL);
1065 }
1066 #ifdef IPV6
1067 if (src_addr6_set && socket6 >= 0) {
1068 socket_set_src_addr_ipv6(socket6, &src_addr6, (socktype6 == SOCK_DGRAM) ? &ident6 : NULL);
1069 }
1070 #endif
1071
1072 /* allocate and initialize array to map host nr to host_entry */
1073 {
1074 struct event *cursor = event_queue_ping.first;
1075 int i= 0;
1076 table = (HOST_ENTRY**)calloc(num_hosts, sizeof(HOST_ENTRY *));
1077 if (!table)
1078 crash_and_burn("Can't malloc array of hosts");
1079 /* initialize table of hosts. we know that we have ping events scheduled
1080 * for each of them */
1081 for (cursor = event_queue_ping.first; cursor; cursor = cursor->ev_next) {
1082 table[i] = cursor->host;
1083 cursor->host->i = i;
1084 i++;
1085 }
1086 }
1087
1088 init_ping_buffer_ipv4(ping_data_size);
1089 #ifdef IPV6
1090 init_ping_buffer_ipv6(ping_data_size);
1091 #endif
1092
1093 #ifdef USE_SIGACTION
1094 memset(&act, 0, sizeof(act));
1095 act.sa_handler = signal_handler;
1096 sigemptyset(&act.sa_mask);
1097 sigaddset(&act.sa_mask, SIGINT);
1098 sigaddset(&act.sa_mask, SIGQUIT);
1099 act.sa_flags = SA_RESTART;
1100 if (sigaction(SIGQUIT, &act, NULL) || sigaction(SIGINT, &act, NULL)) {
1101 crash_and_burn("failure to set signal handler");
1102 }
1103 #else
1104 signal(SIGINT, signal_handler);
1105 signal(SIGQUIT, signal_handler);
1106 #endif
1107 setlinebuf(stdout);
1108
1109 if (report_interval) {
1110 next_report_time = current_time_ns + report_interval;
1111 }
1112
1113 last_send_time = 0;
1114
1115 seqmap_init();
1116
1117 /* main loop */
1118 main_loop();
1119
1120 finish();
1121
1122 return 0;
1123 }
1124
1125 static inline int64_t timespec_ns(struct timespec* a)
1126 {
1127 return ((int64_t) a->tv_sec * 1000000000) + a->tv_nsec;
1128 }
1129
1130 void add_cidr(char* addr)
1131 {
1132 char* addr_end;
1133 char* mask_str;
1134 unsigned long mask;
1135 unsigned long bitmask;
1136 int ret;
1137 struct addrinfo addr_hints;
1138 struct addrinfo* addr_res;
1139 unsigned long net_addr;
1140 unsigned long net_last;
1141
1142 /* Split address from mask */
1143 addr_end = strchr(addr, '/');
1144 if (addr_end == NULL) {
1145 usage(1);
1146 }
1147 *addr_end = '\0';
1148 mask_str = addr_end + 1;
1149 mask = atoi(mask_str);
1150
1151 /* parse address (IPv4 only) */
1152 memset(&addr_hints, 0, sizeof(struct addrinfo));
1153 addr_hints.ai_family = AF_UNSPEC;
1154 addr_hints.ai_flags = AI_NUMERICHOST;
1155 ret = getaddrinfo(addr, NULL, &addr_hints, &addr_res);
1156 if (ret) {
1157 fprintf(stderr, "%s, can't parse address %s: %s\n", prog, addr, gai_strerror(ret));
1158 exit(1);
1159 }
1160 if (addr_res->ai_family != AF_INET) {
1161 fprintf(stderr, "%s: -g works only with IPv4 addresses\n", prog);
1162 exit(1);
1163 }
1164 net_addr = ntohl(((struct sockaddr_in*)addr_res->ai_addr)->sin_addr.s_addr);
1165
1166 /* check mask */
1167 if (mask < 1 || mask > 32) {
1168 fprintf(stderr, "%s: netmask must be between 1 and 32 (is: %s)\n", prog, mask_str);
1169 exit(1);
1170 }
1171
1172 /* convert mask integer from 1 to 32 to a bitmask */
1173 bitmask = ((unsigned long)0xFFFFFFFF) << (32 - mask);
1174
1175 /* calculate network range */
1176 net_addr &= bitmask;
1177 net_last = net_addr + ((unsigned long)0x1 << (32 - mask)) - 1;
1178
1179 /* exclude network and broadcast address for regular prefixes */
1180 if (mask < 31) {
1181 net_last--;
1182 net_addr++;
1183 }
1184
1185 /* add all hosts in that network (net_addr and net_last inclusive) */
1186 for (; net_addr <= net_last; net_addr++) {
1187 struct in_addr in_addr_tmp;
1188 char buffer[20];
1189 in_addr_tmp.s_addr = htonl(net_addr);
1190 inet_ntop(AF_INET, &in_addr_tmp, buffer, sizeof(buffer));
1191 add_name(buffer);
1192 }
1193
1194 freeaddrinfo(addr_res);
1195 }
1196
1197 void add_range(char* start, char* end)
1198 {
1199 struct addrinfo addr_hints;
1200 struct addrinfo* addr_res;
1201 unsigned long start_long;
1202 unsigned long end_long;
1203 int ret;
1204
1205 /* parse start address (IPv4 only) */
1206 memset(&addr_hints, 0, sizeof(struct addrinfo));
1207 addr_hints.ai_family = AF_UNSPEC;
1208 addr_hints.ai_flags = AI_NUMERICHOST;
1209 ret = getaddrinfo(start, NULL, &addr_hints, &addr_res);
1210 if (ret) {
1211 fprintf(stderr, "%s: can't parse address %s: %s\n", prog, start, gai_strerror(ret));
1212 exit(1);
1213 }
1214 if (addr_res->ai_family != AF_INET) {
1215 freeaddrinfo(addr_res);
1216 fprintf(stderr, "%s: -g works only with IPv4 addresses\n", prog);
1217 exit(1);
1218 }
1219 start_long = ntohl(((struct sockaddr_in*)addr_res->ai_addr)->sin_addr.s_addr);
1220
1221 /* parse end address (IPv4 only) */
1222 memset(&addr_hints, 0, sizeof(struct addrinfo));
1223 addr_hints.ai_family = AF_UNSPEC;
1224 addr_hints.ai_flags = AI_NUMERICHOST;
1225 ret = getaddrinfo(end, NULL, &addr_hints, &addr_res);
1226 if (ret) {
1227 fprintf(stderr, "%s: can't parse address %s: %s\n", prog, end, gai_strerror(ret));
1228 exit(1);
1229 }
1230 if (addr_res->ai_family != AF_INET) {
1231 freeaddrinfo(addr_res);
1232 fprintf(stderr, "%s: -g works only with IPv4 addresses\n", prog);
1233 exit(1);
1234 }
1235 end_long = ntohl(((struct sockaddr_in*)addr_res->ai_addr)->sin_addr.s_addr);
1236 freeaddrinfo(addr_res);
1237
1238 if (end_long > start_long + MAX_GENERATE) {
1239 fprintf(stderr, "%s: -g parameter generates too many addresses\n", prog);
1240 exit(1);
1241 }
1242
1243 /* generate */
1244 for (; start_long <= end_long; start_long++) {
1245 struct in_addr in_addr_tmp;
1246 char buffer[20];
1247 in_addr_tmp.s_addr = htonl(start_long);
1248 inet_ntop(AF_INET, &in_addr_tmp, buffer, sizeof(buffer));
1249 add_name(buffer);
1250 }
1251 }
1252
1253 void main_loop()
1254 {
1255 int64_t lt;
1256 int64_t wait_time_ns;
1257 struct event *event;
1258 struct host_entry *h;
1259
1260 while (event_queue_ping.first || event_queue_timeout.first) {
1261 dbg_printf("%s", "# main_loop\n");
1262
1263 /* timeout event ? */
1264 if (event_queue_timeout.first &&
1265 event_queue_timeout.first->ev_time - current_time_ns <= 0)
1266 {
1267 event = ev_dequeue(&event_queue_timeout);
1268 h = event->host;
1269
1270 dbg_printf("%s [%d]: timeout event\n", h->host, event->ping_index);
1271
1272 stats_add(h, event->ping_index, 0, -1);
1273
1274 if (per_recv_flag) {
1275 if (timestamp_flag) {
1276 printf("[%.5f] ", (double)current_time_ns / 1e9);
1277 }
1278 printf("%-*s : [%d], timed out",
1279 max_hostname_len, h->host, event->ping_index);
1280 if(h->num_recv > 0) {
1281 printf(" (%s avg, ", sprint_tm(h->total_time / h->num_recv));
1282 }
1283 else {
1284 printf(" (NaN avg, ");
1285 }
1286 if (h->num_recv <= h->num_sent) {
1287 printf("%d%% loss)",
1288 ((h->num_sent - h->num_recv) * 100) / h->num_sent);
1289 }
1290 else {
1291 printf("%d%% return)",
1292 (h->num_recv_total * 100) / h->num_sent);
1293 }
1294 printf("\n");
1295 }
1296
1297 /* do we need to send a retry? */
1298 if (!loop_flag && !count_flag) {
1299 if (h->num_sent < retry + 1) {
1300 if (backoff_flag) {
1301 h->timeout *= backoff;
1302 }
1303 send_ping(h, event->ping_index);
1304 }
1305 }
1306
1307 /* note: we process first timeout events, because we might need to
1308 * wait to process ping events, while we for sure never need to
1309 * wait for timeout events.
1310 */
1311 continue;
1312 }
1313
1314 /* ping event ? */
1315 if (event_queue_ping.first &&
1316 event_queue_ping.first->ev_time - current_time_ns <= 0)
1317 {
1318 /* Make sure that we don't ping more than once every "interval" */
1319 lt = current_time_ns - last_send_time;
1320 if (lt < interval)
1321 goto wait_for_reply;
1322
1323 /* Dequeue the event */
1324 event = ev_dequeue(&event_queue_ping);
1325 h = event->host;
1326
1327 dbg_printf("%s [%d]: ping event\n", h->host, event->ping_index);
1328
1329 /* Send the ping */
1330 send_ping(h, event->ping_index);
1331
1332 /* Loop and count mode: schedule next ping */
1333 if (loop_flag || (count_flag && event->ping_index+1 < count)) {
1334 host_add_ping_event(h, event->ping_index+1, event->ev_time + perhost_interval);
1335 }
1336 }
1337
1338 wait_for_reply:
1339
1340 /* When is the next ping next event? */
1341 wait_time_ns = -1;
1342 if (event_queue_ping.first) {
1343 wait_time_ns = event_queue_ping.first->ev_time - current_time_ns;
1344 if (wait_time_ns < 0)
1345 wait_time_ns = 0;
1346 /* make sure that we wait enough, so that the inter-ping delay is
1347 * bigger than 'interval' */
1348 if (wait_time_ns < interval) {
1349 lt = current_time_ns - last_send_time;
1350 if (lt < interval) {
1351 wait_time_ns = interval - lt;
1352 }
1353 }
1354
1355 dbg_printf("next ping event in %.0f ms (%s)\n", wait_time_ns / 1e6, event_queue_ping.first->host->host);
1356 }
1357
1358 /* When is the next timeout event? */
1359 if (event_queue_timeout.first) {
1360 int64_t wait_time_timeout = event_queue_timeout.first->ev_time - current_time_ns;
1361 if(wait_time_ns < 0 || wait_time_timeout < wait_time_ns) {
1362 wait_time_ns = wait_time_timeout;
1363 if (wait_time_ns < 0) {
1364 wait_time_ns = 0;
1365 }
1366 }
1367
1368 dbg_printf("next timeout event in %.0f ms (%s)\n", wait_time_timeout / 1e6, event_queue_timeout.first->host->host);
1369 }
1370
1371 /* When is the next report due? */
1372 if (report_interval && (loop_flag || count_flag)) {
1373 int64_t wait_time_next_report = next_report_time - current_time_ns;
1374 if (wait_time_next_report < wait_time_ns) {
1375 wait_time_ns = wait_time_next_report;
1376 if (wait_time_ns < 0) {
1377 wait_time_ns = 0;
1378 }
1379 }
1380
1381 dbg_printf("next report event in %0.f ms\n", wait_time_next_report / 1e6);
1382 }
1383
1384 /* if wait_time is still -1, it means that we are waiting for nothing... */
1385 if(wait_time_ns == -1) {
1386 break;
1387 }
1388
1389 /* end of loop was requested by interrupt signal handler */
1390 if (finish_requested) {
1391 break;
1392 }
1393
1394 /* Receive replies */
1395 /* (this is what sleeps during each loop iteration) */
1396 dbg_printf("waiting up to %.0f ms\n", wait_time_ns / 1e6);
1397 if (wait_for_reply(wait_time_ns)) {
1398 while (wait_for_reply(0))
1399 ; /* process other replies in the queue */
1400 }
1401
1402 update_current_time();
1403
1404 if (status_snapshot) {
1405 status_snapshot = 0;
1406 print_per_system_splits();
1407 }
1408
1409 /* Print report */
1410 if (report_interval && (loop_flag || count_flag) && (current_time_ns >= next_report_time)) {
1411 if (netdata_flag)
1412 print_netdata();
1413 else
1414 print_per_system_splits();
1415
1416 while (current_time_ns >= next_report_time) {
1417 next_report_time += report_interval;
1418 }
1419 }
1420 }
1421 }
1422
1423 /************************************************************
1424
1425 Function: signal_handler
1426
1427 *************************************************************
1428
1429 Inputs: int signum
1430
1431 Description:
1432
1433 SIGQUIT signal handler - set flag and return
1434 SIGINT signal handler - set flag and return
1435
1436 ************************************************************/
1437
1438 void signal_handler(int signum)
1439 {
1440 switch (signum) {
1441 case SIGINT:
1442 finish_requested = 1;
1443 break;
1444
1445 case SIGQUIT:
1446 status_snapshot = 1;
1447 break;
1448 }
1449 }
1450
1451 /************************************************************
1452
1453 Function: update_current_time
1454
1455 *************************************************************/
1456
1457 void update_current_time()
1458 {
1459 clock_gettime(CLOCKID, ¤t_time);
1460 current_time_ns = timespec_ns(¤t_time);
1461 }
1462
1463
1464 /************************************************************
1465
1466 Function: finish
1467
1468 *************************************************************
1469
1470 Inputs: void (none)
1471
1472 Description:
1473
1474 Main program clean up and exit point
1475
1476 ************************************************************/
1477
1478 void finish()
1479 {
1480 int i;
1481 HOST_ENTRY* h;
1482
1483 update_current_time();
1484 end_time = current_time_ns;
1485
1486 /* tot up unreachables */
1487 for (i = 0; i < num_hosts; i++) {
1488 h = table[i];
1489
1490 if (!h->num_recv) {
1491 num_unreachable++;
1492
1493 if (verbose_flag || unreachable_flag) {
1494 printf("%s", h->host);
1495
1496 if (verbose_flag)
1497 printf(" is unreachable");
1498
1499 printf("\n");
1500 }
1501 }
1502 }
1503
1504 if (count_flag || loop_flag)
1505 print_per_system_stats();
1506 #if defined(DEBUG) || defined(_DEBUG)
1507 else if (print_per_system_flag)
1508 print_per_system_stats();
1509 #endif /* DEBUG || _DEBUG */
1510
1511 if (stats_flag)
1512 print_global_stats();
1513
1514 if (min_reachable) {
1515 if ((num_hosts-num_unreachable) >= min_reachable) {
1516 printf("Enough hosts reachable (required: %d, reachable: %d)\n", min_reachable, num_hosts-num_unreachable);
1517 exit(0);
1518 } else {
1519 printf("Not enough hosts reachable (required: %d, reachable: %d)\n", min_reachable, num_hosts-num_unreachable);
1520 exit(1);
1521 }
1522 }
1523
1524 if (num_noaddress)
1525 exit(2);
1526 else if (num_alive != num_hosts)
1527 exit(1);
1528
1529 exit(0);
1530 }
1531
1532 /************************************************************
1533
1534 Function: print_per_system_stats
1535
1536 *************************************************************
1537
1538 Inputs: void (none)
1539
1540 Description:
1541
1542
1543 ************************************************************/
1544
1545 void print_per_system_stats(void)
1546 {
1547 int i, j, avg, outage_ms;
1548 HOST_ENTRY* h;
1549 int64_t resp;
1550
1551 if (verbose_flag || per_recv_flag)
1552 fprintf(stderr, "\n");
1553
1554 for (i = 0; i < num_hosts; i++) {
1555 h = table[i];
1556 fprintf(stderr, "%-*s :", max_hostname_len, h->host);
1557
1558 if (report_all_rtts_flag) {
1559 for (j = 0; j < h->num_sent; j++) {
1560 if ((resp = h->resp_times[j]) >= 0)
1561 fprintf(stderr, " %s", sprint_tm(resp));
1562 else
1563 fprintf(stderr, " -");
1564 }
1565
1566 fprintf(stderr, "\n");
1567 }
1568 else {
1569 if (h->num_recv <= h->num_sent) {
1570 fprintf(stderr, " xmt/rcv/%%loss = %d/%d/%d%%",
1571 h->num_sent, h->num_recv, h->num_sent > 0 ? ((h->num_sent - h->num_recv) * 100) / h->num_sent : 0);
1572
1573 if (outage_flag) {
1574 /* Time outage total */
1575 outage_ms = (h->num_sent - h->num_recv) * perhost_interval / 1e6;
1576 fprintf(stderr, ", outage(ms) = %d", outage_ms);
1577 }
1578 }
1579 else {
1580 fprintf(stderr, " xmt/rcv/%%return = %d/%d/%d%%",
1581 h->num_sent, h->num_recv,
1582 ((h->num_recv * 100) / h->num_sent));
1583 }
1584
1585 if (h->num_recv) {
1586 avg = h->total_time / h->num_recv;
1587 fprintf(stderr, ", min/avg/max = %s", sprint_tm(h->min_reply));
1588 fprintf(stderr, "/%s", sprint_tm(avg));
1589 fprintf(stderr, "/%s", sprint_tm(h->max_reply));
1590 }
1591
1592 fprintf(stderr, "\n");
1593 }
1594 }
1595 }
1596
1597 /************************************************************
1598
1599 Function: print_netdata
1600
1601 *************************************************************
1602
1603 Inputs: void (none)
1604
1605 Description:
1606
1607
1608 ************************************************************/
1609
1610 void print_netdata(void)
1611 {
1612 static int sent_charts = 0;
1613
1614 int i;
1615 int64_t avg;
1616 HOST_ENTRY* h;
1617
1618 for (i = 0; i < num_hosts; i++) {
1619 h = table[i];
1620
1621 if (!sent_charts) {
1622 printf("CHART fping.%s_packets '' 'FPing Packets for host %s' packets '%s' fping.packets line 110020 %.0f\n", h->name, h->host, h->name, report_interval / 1e9);
1623 printf("DIMENSION xmt sent absolute 1 1\n");
1624 printf("DIMENSION rcv received absolute 1 1\n");
1625 }
1626
1627 printf("BEGIN fping.%s_packets\n", h->name);
1628 printf("SET xmt = %d\n", h->num_sent_i);
1629 printf("SET rcv = %d\n", h->num_recv_i);
1630 printf("END\n");
1631
1632 if (!sent_charts) {
1633 printf("CHART fping.%s_quality '' 'FPing Quality for host %s' percentage '%s' fping.quality area 110010 %.0f\n", h->name, h->host, h->name, report_interval / 1e9);
1634 printf("DIMENSION returned '' absolute 1 1\n");
1635 /* printf("DIMENSION lost '' absolute 1 1\n"); */
1636 }
1637
1638 printf("BEGIN fping.%s_quality\n", h->name);
1639 /*
1640 if( h->num_recv_i <= h->num_sent_i )
1641 printf("SET lost = %d\n", h->num_sent_i > 0 ? ( ( h->num_sent_i - h->num_recv_i ) * 100 ) / h->num_sent_i : 0 );
1642 else
1643 printf("SET lost = 0\n");
1644 */
1645
1646 printf("SET returned = %d\n", h->num_sent_i > 0 ? ((h->num_recv_i * 100) / h->num_sent_i) : 0);
1647 printf("END\n");
1648
1649 if (!sent_charts) {
1650 printf("CHART fping.%s_latency '' 'FPing Latency for host %s' ms '%s' fping.latency area 110000 %.0f\n", h->name, h->host, h->name, report_interval / 1e9);
1651 printf("DIMENSION min minimum absolute 1 1000000\n");
1652 printf("DIMENSION max maximum absolute 1 1000000\n");
1653 printf("DIMENSION avg average absolute 1 1000000\n");
1654 }
1655
1656 printf("BEGIN fping.%s_latency\n", h->name);
1657 if (h->num_recv_i) {
1658 avg = h->total_time_i / h->num_recv_i;
1659 printf("SET min = %ld\n", h->min_reply_i);
1660 printf("SET avg = %ld\n", avg);
1661 printf("SET max = %ld\n", h->max_reply_i);
1662 }
1663 printf("END\n");
1664
1665 h->num_sent_i = h->num_recv_i = h->max_reply_i = h->min_reply_i = h->total_time_i = 0;
1666 }
1667
1668 sent_charts = 1;
1669 }
1670
1671 /************************************************************
1672
1673 Function: print_per_system_splits
1674
1675 *************************************************************
1676
1677 Inputs: void (none)
1678
1679 Description:
1680
1681
1682 ************************************************************/
1683
1684 void print_per_system_splits(void)
1685 {
1686 int i, avg, outage_ms_i;
1687 HOST_ENTRY* h;
1688 struct tm* curr_tm;
1689
1690 if (verbose_flag || per_recv_flag)
1691 fprintf(stderr, "\n");
1692
1693 update_current_time();
1694 curr_tm = localtime((time_t*)¤t_time.tv_sec);
1695 fprintf(stderr, "[%2.2d:%2.2d:%2.2d]\n", curr_tm->tm_hour,
1696 curr_tm->tm_min, curr_tm->tm_sec);
1697
1698 for (i = 0; i < num_hosts; i++) {
1699 h = table[i];
1700 fprintf(stderr, "%-*s :", max_hostname_len, h->host);
1701
1702 if (h->num_recv_i <= h->num_sent_i) {
1703 fprintf(stderr, " xmt/rcv/%%loss = %d/%d/%d%%",
1704 h->num_sent_i, h->num_recv_i, h->num_sent_i > 0 ? ((h->num_sent_i - h->num_recv_i) * 100) / h->num_sent_i : 0);
1705
1706 if (outage_flag) {
1707 /* Time outage */
1708 outage_ms_i = (h->num_sent_i - h->num_recv_i) * perhost_interval / 1e6;
1709 fprintf(stderr, ", outage(ms) = %d", outage_ms_i);
1710 }
1711 }
1712 else {
1713 fprintf(stderr, " xmt/rcv/%%return = %d/%d/%d%%",
1714 h->num_sent_i, h->num_recv_i, h->num_sent_i > 0 ? ((h->num_recv_i * 100) / h->num_sent_i) : 0);
1715 }
1716
1717 if (h->num_recv_i) {
1718 avg = h->total_time_i / h->num_recv_i;
1719 fprintf(stderr, ", min/avg/max = %s", sprint_tm(h->min_reply_i));
1720 fprintf(stderr, "/%s", sprint_tm(avg));
1721 fprintf(stderr, "/%s", sprint_tm(h->max_reply_i));
1722 }
1723
1724 fprintf(stderr, "\n");
1725 h->num_sent_i = h->num_recv_i = h->max_reply_i = h->min_reply_i = h->total_time_i = 0;
1726 }
1727 }
1728
1729 /************************************************************
1730
1731 Function: print_global_stats
1732
1733 *************************************************************
1734
1735 Inputs: void (none)
1736
1737 Description:
1738
1739
1740 ************************************************************/
1741
1742 void print_global_stats(void)
1743 {
1744 fprintf(stderr, "\n");
1745 fprintf(stderr, " %7d targets\n", num_hosts);
1746 fprintf(stderr, " %7d alive\n", num_alive);
1747 fprintf(stderr, " %7d unreachable\n", num_unreachable);
1748 fprintf(stderr, " %7d unknown addresses\n", num_noaddress);
1749 fprintf(stderr, "\n");
1750 fprintf(stderr, " %7d timeouts (waiting for response)\n", num_timeout);
1751 fprintf(stderr, " %7d ICMP Echos sent\n", num_pingsent);
1752 fprintf(stderr, " %7d ICMP Echo Replies received\n", num_pingreceived);
1753 fprintf(stderr, " %7d other ICMP received\n", num_othericmprcvd);
1754 fprintf(stderr, "\n");
1755
1756 if (total_replies == 0) {
1757 min_reply = 0;
1758 max_reply = 0;
1759 total_replies = 1;
1760 sum_replies = 0;
1761 }
1762
1763 fprintf(stderr, " %s ms (min round trip time)\n", sprint_tm(min_reply));
1764 fprintf(stderr, " %s ms (avg round trip time)\n",
1765 sprint_tm(sum_replies / total_replies));
1766 fprintf(stderr, " %s ms (max round trip time)\n", sprint_tm(max_reply));
1767 fprintf(stderr, " %12.3f sec (elapsed real time)\n",
1768 (end_time - start_time) / 1e9);
1769 fprintf(stderr, "\n");
1770 }
1771
1772 /************************************************************
1773
1774 Function: send_ping
1775
1776 *************************************************************
1777
1778 Inputs: int s, HOST_ENTRY *h
1779
1780 Description:
1781
1782 Compose and transmit an ICMP_ECHO REQUEST packet. The IP packet
1783 will be added on by the kernel. The ID field is our UNIX process ID,
1784 and the sequence number is an index into an array of outstanding
1785 ping requests. The sequence number will later be used to quickly
1786 figure out who the ping reply came from.
1787
1788 ************************************************************/
1789
1790 int send_ping(HOST_ENTRY* h, int index)
1791 {
1792 int n;
1793 int myseq;
1794 int ret = 1;
1795
1796 update_current_time();
1797 h->last_send_time = current_time_ns;
1798 myseq = seqmap_add(h->i, index, current_time_ns);
1799
1800 dbg_printf("%s [%d]: send ping\n", h->host, index);
1801
1802 if (h->saddr.ss_family == AF_INET && socket4 >= 0) {
1803 n = socket_sendto_ping_ipv4(socket4, (struct sockaddr*)&h->saddr, h->saddr_len, myseq, ident4);
1804 }
1805 #ifdef IPV6
1806 else if (h->saddr.ss_family == AF_INET6 && socket6 >= 0) {
1807 n = socket_sendto_ping_ipv6(socket6, (struct sockaddr*)&h->saddr, h->saddr_len, myseq, ident6);
1808 }
1809 #endif
1810 else {
1811 return 0;
1812 }
1813
1814 /* error sending? */
1815 if (
1816 (n < 0)
1817 #if defined(EHOSTDOWN)
1818 && errno != EHOSTDOWN
1819 #endif
1820 ) {
1821 if (verbose_flag) {
1822 print_warning("%s: error while sending ping: %s\n", h->host, strerror(errno));
1823 }
1824 else {
1825 dbg_printf("%s: error while sending ping: %s\n", h->host, strerror(errno));
1826 }
1827
1828 h->num_sent++;
1829 h->num_sent_i++;
1830 if (!loop_flag)
1831 h->resp_times[index] = RESP_ERROR;
1832
1833 ret = 0;
1834 }
1835 else {
1836 /* schedule timeout */
1837 host_add_timeout_event(h, index, current_time_ns + h->timeout);
1838
1839 /* mark this trial as outstanding */
1840 if (!loop_flag) {
1841 h->resp_times[index] = RESP_WAITING;
1842 }
1843 }
1844
1845 num_pingsent++;
1846 last_send_time = h->last_send_time;
1847
1848 return (ret);
1849 }
1850
1851 int socket_can_read(struct timeval* timeout)
1852 {
1853 int nfound;
1854 fd_set readset;
1855 int socketmax;
1856
1857 #ifndef IPV6
1858 socketmax = socket4;
1859 #else
1860 socketmax = socket4 > socket6 ? socket4 : socket6;
1861 #endif
1862
1863 select_again:
1864 FD_ZERO(&readset);
1865 if(socket4 >= 0) FD_SET(socket4, &readset);
1866 #ifdef IPV6
1867 if(socket6 >= 0) FD_SET(socket6, &readset);
1868 #endif
1869
1870 nfound = select(socketmax + 1, &readset, NULL, NULL, timeout);
1871 if (nfound < 0) {
1872 if (errno == EINTR) {
1873 /* interrupted system call: redo the select */
1874 goto select_again;
1875 }
1876 else {
1877 perror("select");
1878 }
1879 }
1880
1881 if (nfound > 0) {
1882 if (socket4 >= 0 && FD_ISSET(socket4, &readset)) {
1883 return socket4;
1884 }
1885 #ifdef IPV6
1886 if (socket6 >= 0 && FD_ISSET(socket6, &readset)) {
1887 return socket6;
1888 }
1889 #endif
1890 }
1891
1892 return -1;
1893 }
1894
1895 int receive_packet(int64_t wait_time,
1896 int64_t* reply_timestamp,
1897 struct sockaddr* reply_src_addr,
1898 size_t reply_src_addr_len,
1899 char* reply_buf,
1900 size_t reply_buf_len)
1901 {
1902 struct timeval to;
1903 int s = 0;
1904 int recv_len;
1905 static unsigned char msg_control[40];
1906 struct iovec msg_iov = {
1907 reply_buf,
1908 reply_buf_len
1909 };
1910 struct msghdr recv_msghdr = {
1911 reply_src_addr,
1912 reply_src_addr_len,
1913 &msg_iov,
1914 1,
1915 &msg_control,
1916 sizeof(msg_control),
1917 0
1918 };
1919 #if HAVE_SO_TIMESTAMPNS
1920 struct cmsghdr* cmsg;
1921 #endif
1922
1923 /* Wait for a socket to become ready */
1924 if (wait_time) {
1925 to.tv_sec = wait_time / UINT64_C(1000000000);
1926 to.tv_usec = (wait_time % UINT64_C(1000000000)) / 1000 + 1;
1927 }
1928 else {
1929 to.tv_sec = 0;
1930 to.tv_usec = 0;
1931 }
1932 s = socket_can_read(&to);
1933 if (s == -1) {
1934 return 0; /* timeout */
1935 }
1936
1937 recv_len = recvmsg(s, &recv_msghdr, MSG_TRUNC);
1938 if (recv_len <= 0) {
1939 return 0;
1940 }
1941
1942 #if HAVE_SO_TIMESTAMPNS
1943 /* ancilliary data */
1944 {
1945 struct timespec reply_timestamp_ts;
1946 for (cmsg = CMSG_FIRSTHDR(&recv_msghdr);
1947 cmsg != NULL;
1948 cmsg = CMSG_NXTHDR(&recv_msghdr, cmsg))
1949 {
1950 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPNS) {
1951 memcpy(&reply_timestamp_ts, CMSG_DATA(cmsg), sizeof(reply_timestamp_ts));
1952 *reply_timestamp = timespec_ns(&reply_timestamp_ts);
1953 }
1954 }
1955 }
1956 #endif
1957
1958 #if defined(DEBUG) || defined(_DEBUG)
1959 if (randomly_lose_flag) {
1960 if ((random() & 0x07) <= lose_factor)
1961 return 0;
1962 }
1963 #endif
1964
1965 return recv_len;
1966 }
1967
1968 /* stats_add: update host statistics for a single packet that was received (or timed out)
1969 * h: host entry to update
1970 * index: if in count mode: index number for this ping packet (-1 otherwise)
1971 * success: 1 if response received, 0 otherwise
1972 * latency: response time, in ns
1973 */
1974 void stats_add(HOST_ENTRY *h, int index, int success, int64_t latency)
1975 {
1976 /* sent count - we update only on receive/timeout, so that we don't get
1977 * weird loss percentage, just because a packet was note recived yet.
1978 */
1979 h->num_sent++;
1980 h->num_sent_i++;
1981
1982 if(!success) {
1983 if(!loop_flag && index>=0) {
1984 h->resp_times[index] = RESP_TIMEOUT;
1985 }
1986 num_timeout++;
1987 return;
1988 }
1989
1990 /* received count */
1991 h->num_recv++;
1992 h->num_recv_i++;
1993
1994 /* maximum */
1995 if (!h->max_reply || latency > h->max_reply) {
1996 h->max_reply = latency;
1997 }
1998 if (!h->max_reply_i || latency > h->max_reply_i) {
1999 h->max_reply_i = latency;
2000 }
2001
2002 /* minimum */
2003 if (!h->min_reply || latency < h->min_reply) {
2004 h->min_reply = latency;
2005 }
2006 if (!h->min_reply_i || latency < h->min_reply_i) {
2007 h->min_reply_i = latency;
2008 }
2009
2010 /* total time (for average) */
2011 h->total_time += latency;
2012 h->total_time_i += latency;
2013
2014 /* response time per-packet (count mode) */
2015 if(!loop_flag && index>=0) {
2016 h->resp_times[index] = latency;
2017 }
2018 }
2019
2020 /* stats_reset_interval: reset interval statistics
2021 * h: host entry to update
2022 */
2023 void stats_reset_interval(HOST_ENTRY *h)
2024 {
2025 h->num_sent_i = 0;
2026 h->num_recv_i = 0;
2027 h->max_reply_i = 0;
2028 h->min_reply_i = 0;
2029 h->total_time_i = 0;
2030 }
2031
2032 int decode_icmp_ipv4(
2033 struct sockaddr* response_addr,
2034 size_t response_addr_len,
2035 char* reply_buf,
2036 size_t reply_buf_len,
2037 unsigned short* id,
2038 unsigned short* seq)
2039 {
2040 struct icmp* icp;
2041 int hlen = 0;
2042
2043 if (!using_sock_dgram4) {
2044 struct ip* ip = (struct ip*)reply_buf;
2045
2046 #if defined(__alpha__) && __STDC__ && !defined(__GLIBC__)
2047 /* The alpha headers are decidedly broken.
2048 * Using an ANSI compiler, it provides ip_vhl instead of ip_hl and
2049 * ip_v. So, to get ip_hl, we mask off the bottom four bits.
2050 */
2051 hlen = (ip->ip_vhl & 0x0F) << 2;
2052 #else
2053 hlen = ip->ip_hl << 2;
2054 #endif
2055 }
2056
2057
2058 if (reply_buf_len < hlen + ICMP_MINLEN) {
2059 /* too short */
2060 if (verbose_flag) {
2061 char buf[INET6_ADDRSTRLEN];
2062 getnameinfo((struct sockaddr*)&response_addr, sizeof(response_addr), buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
2063 printf("received packet too short for ICMP (%d bytes from %s)\n", (int)reply_buf_len, buf);
2064 }
2065 return -1;
2066 }
2067
2068 icp = (struct icmp*)(reply_buf + hlen);
2069
2070 if (icp->icmp_type != ICMP_ECHOREPLY) {
2071 /* Handle other ICMP packets */
2072 struct icmp* sent_icmp;
2073 SEQMAP_VALUE* seqmap_value;
2074 char addr_ascii[INET6_ADDRSTRLEN];
2075 HOST_ENTRY* h;
2076
2077 /* reply icmp packet (hlen + ICMP_MINLEN) followed by "sent packet" (ip + icmp headers) */
2078 if (reply_buf_len < hlen + ICMP_MINLEN + sizeof(struct ip) + ICMP_MINLEN) {
2079 /* discard ICMP message if we can't tell that it was caused by us (i.e. if the "sent packet" is not included). */
2080 return -1;
2081 }
2082
2083 sent_icmp = (struct icmp*)(reply_buf + hlen + ICMP_MINLEN + sizeof(struct ip));
2084
2085 if (sent_icmp->icmp_type != ICMP_ECHO || sent_icmp->icmp_id != ident4) {
2086 /* not caused by us */
2087 return -1;
2088 }
2089
2090 seqmap_value = seqmap_fetch(ntohs(sent_icmp->icmp_seq), current_time_ns);
2091 if (seqmap_value == NULL) {
2092 return -1;
2093 }
2094
2095 getnameinfo(response_addr, response_addr_len, addr_ascii, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
2096
2097 switch (icp->icmp_type) {
2098 case ICMP_UNREACH:
2099 h = table[seqmap_value->host_nr];
2100 if (icp->icmp_code > ICMP_UNREACH_MAXTYPE) {
2101 print_warning("ICMP Unreachable (Invalid Code) from %s for ICMP Echo sent to %s",
2102 addr_ascii, h->host);
2103 }
2104 else {
2105 print_warning("%s from %s for ICMP Echo sent to %s",
2106 icmp_unreach_str[icp->icmp_code], addr_ascii, h->host);
2107 }
2108
2109 print_warning("\n");
2110 num_othericmprcvd++;
2111 break;
2112
2113 case ICMP_SOURCEQUENCH:
2114 case ICMP_REDIRECT:
2115 case ICMP_TIMXCEED:
2116 case ICMP_PARAMPROB:
2117 h = table[seqmap_value->host_nr];
2118 if (icp->icmp_type <= ICMP_TYPE_STR_MAX) {
2119 print_warning("%s from %s for ICMP Echo sent to %s",
2120 icmp_type_str[icp->icmp_type], addr_ascii, h->host);
2121 }
2122 else {
2123 print_warning("ICMP %d from %s for ICMP Echo sent to %s",
2124 icp->icmp_type, addr_ascii, h->host);
2125 }
2126 print_warning("\n");
2127 num_othericmprcvd++;
2128 break;
2129 }
2130
2131 return -1;
2132 }
2133
2134 *id = icp->icmp_id;
2135 *seq = ntohs(icp->icmp_seq);
2136
2137 return hlen;
2138 }
2139
2140 #ifdef IPV6
2141 int decode_icmp_ipv6(
2142 struct sockaddr* response_addr,
2143 size_t response_addr_len,
2144 char* reply_buf,
2145 size_t reply_buf_len,
2146 unsigned short* id,
2147 unsigned short* seq)
2148 {
2149 struct icmp6_hdr* icp;
2150
2151 if (reply_buf_len < sizeof(struct icmp6_hdr)) {
2152 if (verbose_flag) {
2153 char buf[INET6_ADDRSTRLEN];
2154 getnameinfo((struct sockaddr*)&response_addr, sizeof(response_addr), buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
2155 printf("received packet too short for ICMP (%d bytes from %s)\n", (int)reply_buf_len, buf);
2156 }
2157 return 0; /* too short */
2158 }
2159
2160 icp = (struct icmp6_hdr*)reply_buf;
2161
2162 if (icp->icmp6_type != ICMP6_ECHO_REPLY) {
2163 /* Handle other ICMP packets */
2164 struct icmp6_hdr* sent_icmp;
2165 SEQMAP_VALUE* seqmap_value;
2166 char addr_ascii[INET6_ADDRSTRLEN];
2167 HOST_ENTRY* h;
2168
2169 /* reply icmp packet (ICMP_MINLEN) followed by "sent packet" (ip + icmp headers) */
2170 if (reply_buf_len < ICMP_MINLEN + sizeof(struct ip) + ICMP_MINLEN) {
2171 /* discard ICMP message if we can't tell that it was caused by us (i.e. if the "sent packet" is not included). */
2172 return 0;
2173 }
2174
2175 sent_icmp = (struct icmp6_hdr*)(reply_buf + sizeof(struct icmp6_hdr) + sizeof(struct ip));
2176
2177 if (sent_icmp->icmp6_type != ICMP_ECHO || sent_icmp->icmp6_id != ident6) {
2178 /* not caused by us */
2179 return 0;
2180 }
2181
2182 seqmap_value = seqmap_fetch(ntohs(sent_icmp->icmp6_seq), current_time_ns);
2183 if (seqmap_value == NULL) {
2184 return 0;
2185 }
2186
2187 getnameinfo(response_addr, response_addr_len, addr_ascii, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
2188
2189 switch (icp->icmp6_type) {
2190 case ICMP_UNREACH:
2191 h = table[seqmap_value->host_nr];
2192 if (icp->icmp6_code > ICMP_UNREACH_MAXTYPE) {
2193 print_warning("ICMP Unreachable (Invalid Code) from %s for ICMP Echo sent to %s",
2194 addr_ascii, h->host);
2195 }
2196 else {
2197 print_warning("%s from %s for ICMP Echo sent to %s",
2198 icmp_unreach_str[icp->icmp6_code], addr_ascii, h->host);
2199 }
2200
2201 print_warning("\n");
2202 num_othericmprcvd++;
2203 break;
2204
2205 case ICMP_SOURCEQUENCH:
2206 case ICMP_REDIRECT:
2207 case ICMP_TIMXCEED:
2208 case ICMP_PARAMPROB:
2209 h = table[seqmap_value->host_nr];
2210 if (icp->icmp6_type <= ICMP_TYPE_STR_MAX) {
2211 print_warning("%s from %s for ICMP Echo sent to %s",
2212 icmp_type_str[icp->icmp6_type], addr_ascii, h->host);
2213 }
2214 else {
2215 print_warning("ICMP %d from %s for ICMP Echo sent to %s",
2216 icp->icmp6_type, addr_ascii, h->host);
2217 }
2218 print_warning("\n");
2219 num_othericmprcvd++;
2220 break;
2221 }
2222
2223 return 0;
2224 }
2225
2226 *id = icp->icmp6_id;
2227 *seq = ntohs(icp->icmp6_seq);
2228
2229 return 1;
2230 }
2231 #endif
2232
2233 int wait_for_reply(int64_t wait_time)
2234 {
2235 int result;
2236 static char buffer[RECV_BUFSIZE];
2237 struct sockaddr_storage response_addr;
2238 int n, avg;
2239 HOST_ENTRY* h;
2240 int64_t this_reply;
2241 int this_count;
2242 int64_t recv_time=0;
2243 SEQMAP_VALUE* seqmap_value;
2244 unsigned short id;
2245 unsigned short seq;
2246
2247 /* Receive packet */
2248 result = receive_packet(wait_time, /* max. wait time, in ns */
2249 &recv_time, /* reply_timestamp */
2250 (struct sockaddr*)&response_addr, /* reply_src_addr */
2251 sizeof(response_addr), /* reply_src_addr_len */
2252 buffer, /* reply_buf */
2253 sizeof(buffer) /* reply_buf_len */
2254 );
2255
2256 if (result <= 0) {
2257 return 0;
2258 }
2259
2260 update_current_time();
2261 if(recv_time==0) recv_time = current_time_ns;
2262
2263 /* Process ICMP packet and retrieve id/seq */
2264 if (response_addr.ss_family == AF_INET) {
2265 int ip_hlen = decode_icmp_ipv4(
2266 (struct sockaddr*)&response_addr,
2267 sizeof(response_addr),
2268 buffer,
2269 sizeof(buffer),
2270 &id,
2271 &seq);
2272 if (ip_hlen < 0) {
2273 return 1;
2274 }
2275 if (id != ident4) {
2276 return 1; /* packet received, but not the one we are looking for! */
2277 }
2278 if (!using_sock_dgram4) {
2279 /* do not include IP header in returned size, to be consistent with ping(8) and also
2280 * with fping with IPv6 hosts */
2281 result -= ip_hlen;
2282 }
2283 }
2284 #ifdef IPV6
2285 else if (response_addr.ss_family == AF_INET6) {
2286 if (!decode_icmp_ipv6(
2287 (struct sockaddr*)&response_addr,
2288 sizeof(response_addr),
2289 buffer,
2290 sizeof(buffer),
2291 &id,
2292 &seq)) {
2293 return 1;
2294 }
2295 if (id != ident6) {
2296 return 1; /* packet received, but not the one we are looking for! */
2297 }
2298 }
2299 #endif
2300 else {
2301 return 1;
2302 }
2303
2304 seqmap_value = seqmap_fetch(seq, current_time_ns);
2305 if (seqmap_value == NULL) {
2306 return 1;
2307 }
2308
2309 /* find corresponding host_entry */
2310 n = seqmap_value->host_nr;
2311 h = table[n];
2312 this_count = seqmap_value->ping_count;
2313 this_reply = recv_time - seqmap_value->ping_ts;
2314
2315 /* update stats that include invalid replies */
2316 h->num_recv_total++;
2317 num_pingreceived++;
2318
2319 dbg_printf("received [%d] from %s\n", this_count, h->host);
2320
2321 /* discard duplicates */
2322 if (!loop_flag && h->resp_times[this_count] >= 0) {
2323 if (!per_recv_flag) {
2324 fprintf(stderr, "%s : duplicate for [%d], %d bytes, %s ms",
2325 h->host, this_count, result, sprint_tm(this_reply));
2326
2327 if (addr_cmp((struct sockaddr*)&response_addr, (struct sockaddr*)&h->saddr)) {
2328 char buf[INET6_ADDRSTRLEN];
2329 getnameinfo((struct sockaddr*)&response_addr, sizeof(response_addr), buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
2330 fprintf(stderr, " [<- %s]", buf);
2331 }
2332 fprintf(stderr, "\n");
2333 }
2334 return 1;
2335 }
2336
2337 /* discard reply if delay is larger than timeout
2338 * (see also: github #32) */
2339 if (this_reply > h->timeout) {
2340 return 1;
2341 }
2342
2343 /* update stats */
2344 stats_add(h, this_count, 1, this_reply);
2345 // TODO: move to stats_add?
2346 if (!max_reply || this_reply > max_reply)
2347 max_reply = this_reply;
2348 if (!min_reply || this_reply < min_reply)
2349 min_reply = this_reply;
2350 sum_replies += this_reply;
2351 total_replies++;
2352
2353 /* initialize timeout to initial timeout (without backoff) */
2354 h->timeout = timeout;
2355
2356 /* remove timeout event */
2357 struct event *timeout_event = host_get_timeout_event(h, this_count);
2358 if(timeout_event) {
2359 ev_remove(&event_queue_timeout, timeout_event);
2360 }
2361
2362 /* print "is alive" */
2363 if (h->num_recv == 1) {
2364 num_alive++;
2365 if (verbose_flag || alive_flag) {
2366 printf("%s", h->host);
2367
2368 if (verbose_flag)
2369 printf(" is alive");
2370
2371 if (elapsed_flag)
2372 printf(" (%s ms)", sprint_tm(this_reply));
2373
2374 if (addr_cmp((struct sockaddr*)&response_addr, (struct sockaddr*)&h->saddr)) {
2375 char buf[INET6_ADDRSTRLEN];
2376 getnameinfo((struct sockaddr*)&response_addr, sizeof(response_addr), buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
2377 fprintf(stderr, " [<- %s]", buf);
2378 }
2379
2380 printf("\n");
2381 }
2382 }
2383
2384 /* print received ping (unless --quiet) */
2385 if (per_recv_flag) {
2386 if (timestamp_flag) {
2387 printf("[%.5f] ", (double)recv_time / 1e9);
2388 }
2389 avg = h->total_time / h->num_recv;
2390 printf("%-*s : [%d], %d bytes, %s ms",
2391 max_hostname_len, h->host, this_count, result, sprint_tm(this_reply));
2392 printf(" (%s avg, ", sprint_tm(avg));
2393
2394 if (h->num_recv <= h->num_sent) {
2395 printf("%d%% loss)",
2396 ((h->num_sent - h->num_recv) * 100) / h->num_sent);
2397 }
2398 else {
2399 printf("%d%% return)",
2400 (h->num_recv_total * 100) / h->num_sent);
2401 }
2402
2403 if (addr_cmp((struct sockaddr*)&response_addr, (struct sockaddr*)&h->saddr)) {
2404 char buf[INET6_ADDRSTRLEN];
2405 getnameinfo((struct sockaddr*)&response_addr, sizeof(response_addr), buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
2406 fprintf(stderr, " [<- %s]", buf);
2407 }
2408
2409 printf("\n");
2410 }
2411
2412 return 1;
2413 }
2414
2415 /************************************************************
2416
2417 Function: add_name
2418
2419 *************************************************************
2420
2421 Inputs: char* name
2422
2423 Description:
2424
2425 process input name for addition to target list
2426 name can turn into multiple targets via multiple interfaces (-m)
2427 or via NIS groups
2428
2429 ************************************************************/
2430
2431 void add_name(char* name)
2432 {
2433 struct addrinfo *res0, *res, hints;
2434 int ret_ga;
2435 char* printname;
2436 char namebuf[256];
2437 char addrbuf[256];
2438
2439 /* getaddrinfo */
2440 memset(&hints, 0, sizeof(struct addrinfo));
2441 hints.ai_flags = AI_UNUSABLE;
2442 hints.ai_socktype = SOCK_RAW;
2443 hints.ai_family = hints_ai_family;
2444 if (hints_ai_family == AF_INET) {
2445 hints.ai_protocol = IPPROTO_ICMP;
2446 }
2447 #ifdef IPV6
2448 else if (hints_ai_family == AF_INET6) {
2449 hints.ai_protocol = IPPROTO_ICMPV6;
2450 }
2451 #endif
2452 else {
2453 hints.ai_socktype = SOCK_STREAM;
2454 hints.ai_protocol = 0;
2455 }
2456 ret_ga = getaddrinfo(name, NULL, &hints, &res0);
2457 if (ret_ga) {
2458 if (!quiet_flag)
2459 print_warning("%s: %s\n", name, gai_strerror(ret_ga));
2460 num_noaddress++;
2461 return;
2462 }
2463
2464 /* NOTE: we could/should loop with res on all addresses like this:
2465 * for (res = res0; res; res = res->ai_next) {
2466 * We don't do it yet, however, because is is an incompatible change
2467 * (need to implement a separate option for this)
2468 */
2469 for (res = res0; res; res = res->ai_next) {
2470 /* name_flag: addr -> name lookup requested) */
2471 if (name_flag || rdns_flag) {
2472 int do_rdns = rdns_flag ? 1 : 0;
2473 if (name_flag) {
2474 /* Was it a numerical address? Only then do a rdns-query */
2475 struct addrinfo* nres;
2476 hints.ai_flags = AI_NUMERICHOST;
2477 if (getaddrinfo(name, NULL, &hints, &nres) == 0) {
2478 do_rdns = 1;
2479 freeaddrinfo(nres);
2480 }
2481 }
2482
2483 if (do_rdns && getnameinfo(res->ai_addr, res->ai_addrlen, namebuf, sizeof(namebuf) / sizeof(char), NULL, 0, 0) == 0) {
2484 printname = namebuf;
2485 }
2486 else {
2487 printname = name;
2488 }
2489 }
2490 else {
2491 printname = name;
2492 }
2493
2494 /* addr_flag: name -> addr lookup requested */
2495 if (addr_flag) {
2496 int ret;
2497 ret = getnameinfo(res->ai_addr, res->ai_addrlen, addrbuf,
2498 sizeof(addrbuf) / sizeof(char), NULL, 0, NI_NUMERICHOST);
2499 if (ret) {
2500 if (!quiet_flag) {
2501 print_warning("%s: can't forward-lookup address (%s)\n", name, gai_strerror(ret));
2502 }
2503 continue;
2504 }
2505
2506 if (name_flag || rdns_flag) {
2507 char nameaddrbuf[512+3];
2508 snprintf(nameaddrbuf, sizeof(nameaddrbuf) / sizeof(char), "%s (%s)", printname, addrbuf);
2509 add_addr(name, nameaddrbuf, res->ai_addr, res->ai_addrlen);
2510 }
2511 else {
2512 add_addr(name, addrbuf, res->ai_addr, res->ai_addrlen);
2513 }
2514 }
2515 else {
2516 add_addr(name, printname, res->ai_addr, res->ai_addrlen);
2517 }
2518
2519 if (!multif_flag) {
2520 break;
2521 }
2522 }
2523
2524 freeaddrinfo(res0);
2525 }
2526
2527 /************************************************************
2528
2529 Function: add_addr
2530
2531 *************************************************************
2532
2533 Description:
2534
2535 add single address to list of hosts to be pinged
2536
2537 ************************************************************/
2538
2539 void add_addr(char* name, char* host, struct sockaddr* ipaddr, socklen_t ipaddr_len)
2540 {
2541 HOST_ENTRY* p;
2542 int n;
2543 int64_t *i;
2544
2545 p = (HOST_ENTRY*)calloc(1, sizeof(HOST_ENTRY));
2546 if (!p)
2547 crash_and_burn("can't allocate HOST_ENTRY");
2548
2549 p->name = strdup(name);
2550 p->host = strdup(host);
2551 memcpy(&p->saddr, ipaddr, ipaddr_len);
2552 p->saddr_len = ipaddr_len;
2553 p->timeout = timeout;
2554 p->min_reply = 0;
2555
2556 if (netdata_flag) {
2557 char* s = p->name;
2558 while (*s) {
2559 if (!isalnum(*s))
2560 *s = '_';
2561 s++;
2562 }
2563 }
2564
2565 if (strlen(p->host) > max_hostname_len)
2566 max_hostname_len = strlen(p->host);
2567
2568 /* array for response time results */
2569 if (!loop_flag) {
2570 i = (int64_t*)malloc(trials * sizeof(int64_t));
2571 if (!i)
2572 crash_and_burn("can't allocate resp_times array");
2573
2574 for (n = 1; n < trials; n++)
2575 i[n] = RESP_UNUSED;
2576
2577 p->resp_times = i;
2578 }
2579
2580 /* allocate event storage */
2581 p->event_storage_ping = (struct event *) calloc(event_storage_count, sizeof(struct event));
2582 p->event_storage_timeout = (struct event *) calloc(event_storage_count, sizeof(struct event));
2583
2584 /* schedule first ping */
2585 host_add_ping_event(p, 0, current_time_ns);
2586
2587 num_hosts++;
2588 }
2589
2590 /************************************************************
2591
2592 Function: crash_and_burn
2593
2594 *************************************************************
2595
2596 Inputs: char* message
2597
2598 Description:
2599
2600 ************************************************************/
2601
2602 void crash_and_burn(char* message)
2603 {
2604 if (verbose_flag)
2605 fprintf(stderr, "%s: %s\n", prog, message);
2606
2607 exit(4);
2608 }
2609
2610 /************************************************************
2611
2612 Function: errno_crash_and_burn
2613
2614 *************************************************************
2615
2616 Inputs: char* message
2617
2618 Description:
2619
2620 ************************************************************/
2621
2622 void errno_crash_and_burn(char* message)
2623 {
2624 fprintf(stderr, "%s: %s : %s\n", prog, message, strerror(errno));
2625 exit(4);
2626 }
2627
2628 /************************************************************
2629
2630 Function: print_warning
2631
2632 Description: fprintf(stderr, ...), unless running with -q
2633
2634 *************************************************************/
2635
2636 void print_warning(char* format, ...)
2637 {
2638 va_list args;
2639 if (!quiet_flag) {
2640 va_start(args, format);
2641 vfprintf(stderr, format, args);
2642 va_end(args);
2643 }
2644 }
2645
2646 /************************************************************
2647
2648 Function: sprint_tm
2649
2650 *************************************************************
2651
2652 render nanosecond int64_t value into milliseconds string with three digits of
2653 precision.
2654
2655 ************************************************************/
2656
2657 const char* sprint_tm(int64_t ns)
2658 {
2659 static char buf[10];
2660 double t = (double)ns / 1e6;
2661
2662 if (t < 0.0) {
2663 /* negative (unexpected) */
2664 sprintf(buf, "%.2g", t);
2665 }
2666 else if (t < 1.0) {
2667 /* <= 0.99 ms */
2668 sprintf(buf, "%.3f", t);
2669 }
2670 else if (t < 10.0) {
2671 /* 1.00 - 9.99 ms */
2672 sprintf(buf, "%.2f", t);
2673 }
2674 else if (t < 100.0) {
2675 /* 10.0 - 99.9 ms */
2676 sprintf(buf, "%.1f", t);
2677 }
2678 else if (t < 1000000.0) {
2679 /* 100 - 1'000'000 ms */
2680 sprintf(buf, "%.0f", t);
2681 }
2682 else {
2683 sprintf(buf, "%.3e", t);
2684 }
2685
2686 return (buf);
2687 }
2688
2689 /************************************************************
2690
2691 Function: addr_cmp
2692
2693 *************************************************************/
2694 int addr_cmp(struct sockaddr* a, struct sockaddr* b)
2695 {
2696 if (a->sa_family != b->sa_family) {
2697 return a->sa_family - b->sa_family;
2698 }
2699 else {
2700 if (a->sa_family == AF_INET) {
2701 return ((struct sockaddr_in*)a)->sin_addr.s_addr - ((struct sockaddr_in*)b)->sin_addr.s_addr;
2702 }
2703 else if (a->sa_family == AF_INET6) {
2704 return memcmp(&((struct sockaddr_in6*)a)->sin6_addr,
2705 &((struct sockaddr_in6*)b)->sin6_addr,
2706 sizeof(((struct sockaddr_in6*)a)->sin6_addr));
2707 }
2708 }
2709
2710 return 0;
2711 }
2712
2713 void host_add_ping_event(HOST_ENTRY *h, int index, int64_t ev_time)
2714 {
2715 struct event *event = &h->event_storage_ping[index % event_storage_count];
2716 event->host = h;
2717 event->ping_index = index;
2718 event->ev_time = ev_time;
2719 ev_enqueue(&event_queue_ping, event);
2720
2721 dbg_printf("%s [%d]: add ping event in %.0f ms\n",
2722 event->host->host, index, (ev_time - current_time_ns) / 1e6);
2723 }
2724
2725 void host_add_timeout_event(HOST_ENTRY *h, int index, int64_t ev_time)
2726 {
2727 struct event *event = &h->event_storage_timeout[index % event_storage_count];
2728 event->host = h;
2729 event->ping_index = index;
2730 event->ev_time = ev_time;
2731 ev_enqueue(&event_queue_timeout, event);
2732
2733 dbg_printf("%s [%d]: add timeout event in %.0f ms\n",
2734 event->host->host, index, (ev_time - current_time_ns) / 1e6);
2735 }
2736
2737 struct event *host_get_timeout_event(HOST_ENTRY *h, int index)
2738 {
2739 return &h->event_storage_timeout[index % event_storage_count];
2740 }
2741
2742
2743 /************************************************************
2744
2745 Function: ev_enqueue
2746
2747 Enqueue an event
2748
2749 The queue is sorted by event->ev_time, so that queue->first always points to
2750 the earliest event.
2751
2752 We start scanning the queue from the tail, because we assume
2753 that new events mostly get inserted with a event time higher
2754 than the others.
2755
2756 *************************************************************/
2757 void ev_enqueue(struct event_queue *queue, struct event* event)
2758 {
2759 struct event* i;
2760 struct event* i_prev;
2761
2762 /* Empty list */
2763 if (queue->last == NULL) {
2764 event->ev_next = NULL;
2765 event->ev_prev = NULL;
2766 queue->first = event;
2767 queue->last = event;
2768 return;
2769 }
2770
2771 /* Insert on tail? */
2772 if (event->ev_time - queue->last->ev_time >= 0) {
2773 event->ev_next = NULL;
2774 event->ev_prev = queue->last;
2775 queue->last->ev_next = event;
2776 queue->last = event;
2777 return;
2778 }
2779
2780 /* Find insertion point */
2781 i = queue->last;
2782 while (1) {
2783 i_prev = i->ev_prev;
2784 if (i_prev == NULL || event->ev_time - i_prev->ev_time >= 0) {
2785 event->ev_prev = i_prev;
2786 event->ev_next = i;
2787 i->ev_prev = event;
2788 if (i_prev != NULL) {
2789 i_prev->ev_next = event;
2790 }
2791 else {
2792 queue->first = event;
2793 }
2794 return;
2795 }
2796 i = i_prev;
2797 }
2798 }
2799
2800 /************************************************************
2801
2802 Function: ev_dequeue
2803
2804 *************************************************************/
2805 struct event *ev_dequeue(struct event_queue *queue)
2806 {
2807 struct event *dequeued;
2808
2809 if (queue->first == NULL) {
2810 return NULL;
2811 }
2812 dequeued = queue->first;
2813 ev_remove(queue, dequeued);
2814
2815 return dequeued;
2816 }
2817
2818 /************************************************************
2819
2820 Function: ev_remove
2821
2822 *************************************************************/
2823 void ev_remove(struct event_queue *queue, struct event *event)
2824 {
2825 if (queue->first == event) {
2826 queue->first = event->ev_next;
2827 }
2828 if (queue->last == event) {
2829 queue->last = event->ev_prev;
2830 }
2831 if (event->ev_prev) {
2832 event->ev_prev->ev_next = event->ev_next;
2833 }
2834 if (event->ev_next) {
2835 event->ev_next->ev_prev = event->ev_prev;
2836 }
2837 event->ev_prev = NULL;
2838 event->ev_next = NULL;
2839 }
2840
2841 /************************************************************
2842
2843 Function: usage
2844
2845 *************************************************************
2846
2847 Inputs: int: 0 if output on request, 1 if output because of wrong argument
2848
2849 Description:
2850
2851 ************************************************************/
2852
2853 void usage(int is_error)
2854 {
2855 FILE* out = is_error ? stderr : stdout;
2856 fprintf(out, "Usage: %s [options] [targets...]\n", prog);
2857 fprintf(out, "\n");
2858 fprintf(out, "Probing options:\n");
2859 fprintf(out, " -4, --ipv4 only ping IPv4 addresses\n");
2860 fprintf(out, " -6, --ipv6 only ping IPv6 addresses\n");
2861 fprintf(out, " -b, --size=BYTES amount of ping data to send, in bytes (default: %d)\n", DEFAULT_PING_DATA_SIZE);
2862 fprintf(out, " -B, --backoff=N set exponential backoff factor to N (default: 1.5)\n");
2863 fprintf(out, " -c, --count=N count mode: send N pings to each target\n");
2864 fprintf(out, " -f, --file=FILE read list of targets from a file ( - means stdin)\n");
2865 fprintf(out, " -g, --generate generate target list (only if no -f specified)\n");
2866 fprintf(out, " (give start and end IP in the target list, or a CIDR address)\n");
2867 fprintf(out, " (ex. %s -g 192.168.1.0 192.168.1.255 or %s -g 192.168.1.0/24)\n", prog, prog);
2868 fprintf(out, " -H, --ttl=N set the IP TTL value (Time To Live hops)\n");
2869 #ifdef SO_BINDTODEVICE
2870 fprintf(out, " -I, --iface=IFACE bind to a particular interface\n");
2871 #endif
2872 fprintf(out, " -l, --loop loop mode: send pings forever\n");
2873 fprintf(out, " -m, --all use all IPs of provided hostnames (e.g. IPv4 and IPv6), use with -A\n");
2874 fprintf(out, " -M, --dontfrag set the Don't Fragment flag\n");
2875 fprintf(out, " -O, --tos=N set the type of service (tos) flag on the ICMP packets\n");
2876 fprintf(out, " -p, --period=MSEC interval between ping packets to one target (in ms)\n");
2877 fprintf(out, " (in loop and count modes, default: %.0f ms)\n", perhost_interval / 1e6);
2878 fprintf(out, " -r, --retry=N number of retries (default: %d)\n", DEFAULT_RETRY);
2879 fprintf(out, " -R, --random random packet data (to foil link data compression)\n");
2880 fprintf(out, " -S, --src=IP set source address\n");
2881 fprintf(out, " -t, --timeout=MSEC individual target initial timeout (default: %.0f ms,\n", timeout / 1e6);
2882 fprintf(out, " except with -l/-c/-C, where it's the -p period up to 2000 ms)\n");
2883 fprintf(out, "\n");
2884 fprintf(out, "Output options:\n");
2885 fprintf(out, " -a, --alive show targets that are alive\n");
2886 fprintf(out, " -A, --addr show targets by address\n");
2887 fprintf(out, " -C, --vcount=N same as -c, report results in verbose format\n");
2888 fprintf(out, " -D, --timestamp print timestamp before each output line\n");
2889 fprintf(out, " -e, --elapsed show elapsed time on return packets\n");
2890 fprintf(out, " -i, --interval=MSEC interval between sending ping packets (default: %.0f ms)\n", interval / 1e6);
2891 fprintf(out, " -n, --name show targets by name (-d is equivalent)\n");
2892 fprintf(out, " -N, --netdata output compatible for netdata (-l -Q are required)\n");
2893 fprintf(out, " -o, --outage show the accumulated outage time (lost packets * packet interval)\n");
2894 fprintf(out, " -q, --quiet quiet (don't show per-target/per-ping results)\n");
2895 fprintf(out, " -Q, --squiet=SECS same as -q, but show summary every n seconds\n");
2896 fprintf(out, " -s, --stats print final stats\n");
2897 fprintf(out, " -u, --unreach show targets that are unreachable\n");
2898 fprintf(out, " -v, --version show version\n");
2899 fprintf(out, " -x, --reachable=N shows if >=N hosts are reachable or not\n");
2900 exit(is_error);
2901 }
2902