• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

schweikert / fping / 10123669438

27 Jul 2024 12:53PM UTC coverage: 85.46% (-0.2%) from 85.622%
10123669438

push

github

auerswal
new option --check-source

Using the new option --check-source discards Echo reply packets
sourced from an address that is different from the specified target
address.  This can be useful on busy monitoring hosts, because it
is possible that two fping processes running at he same time use
the same ICMP Echo Reply Identifier for ICMP Echo messages sent to
different hosts.

This aims to address GH issue #206.

6 of 7 new or added lines in 1 file covered. (85.71%)

2 existing lines in 1 file now uncovered.

1199 of 1403 relevant lines covered (85.46%)

238.09 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.6
/src/fping.c
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 "fping.h"
38
#include "config.h"
39
#include "options.h"
40
#include "optparse.h"
41

42
#include <errno.h>
43
#include <inttypes.h>
44
#include <signal.h>
45
#include <stdarg.h>
46
#include <stdint.h>
47
#include <stdio.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 <sys/socket.h>
64
#include <sys/time.h>
65
#include <sys/types.h>
66

67
#if HAVE_SYS_FILE_H
68
#include <sys/file.h>
69
#endif /* HAVE_SYS_FILE_H */
70

71
#ifdef IPV6
72
#include <netinet/icmp6.h>
73
#endif
74
#include <netinet/in_systm.h>
75

76
#include <netinet/ip.h>
77
#include <netinet/ip_icmp.h>
78

79
#include <arpa/inet.h>
80
#include <ctype.h>
81
#include <netdb.h>
82

83
#include <sys/select.h>
84

85
/*** compatibility ***/
86

87
/* Mac OS X's getaddrinfo() does not fail if we use an invalid combination,
88
 * e.g. AF_INET6 with "127.0.0.1". If we pass AI_UNUSABLE to flags, it behaves
89
 * like other platforms. But AI_UNUSABLE isn't available on other platforms,
90
 * and we can safely use 0 for flags instead.
91
 */
92
#ifndef AI_UNUSABLE
93
#define AI_UNUSABLE 0
94
#endif
95

96
/* MSG_TRUNC available on Linux kernel 2.2+, makes recvmsg return the full
97
 * length of the raw packet received, even if the buffer is smaller */
98
#ifndef MSG_TRUNC
99
#define MSG_TRUNC 0
100
#define RECV_BUFSIZE 4096
101
#else
102
#define RECV_BUFSIZE 128
103
#endif
104

105
/*** externals ***/
106

107
extern char *optarg;
108
extern int optind, opterr;
109
#ifndef h_errno
110
extern int h_errno;
111
#endif
112

113
#ifdef __cplusplus
114
}
115
#endif /* __cplusplus */
116

117
/*** Constants ***/
118

119
/* CLOCK_MONTONIC starts under macOS, OpenBSD and FreeBSD with undefined positive point and can not be use
120
 * see github PR #217
121
 * The configure script detect the predefined operating systems an set CLOCK_REALTIME using over ONLY_CLOCK_REALTIME variable
122
 */
123
#if HAVE_SO_TIMESTAMPNS || ONLY_CLOCK_REALTIME
124
#define CLOCKID CLOCK_REALTIME
125
#endif
126

127
#if !defined(CLOCKID)
128
#if defined(CLOCK_MONOTONIC)
129
#define CLOCKID CLOCK_MONOTONIC
130
#else
131
#define CLOCKID CLOCK_REALTIME
132
#endif
133
#endif
134

135
/*** Ping packet defines ***/
136

137
#define MAX_IP_PACKET 65536 /* (theoretical) max IP packet size */
138
#define SIZE_IP_HDR 40
139
#define SIZE_ICMP_HDR 8 /* from ip_icmp.h */
140
#define MAX_PING_DATA (MAX_IP_PACKET - SIZE_IP_HDR - SIZE_ICMP_HDR)
141

142
#define MAX_GENERATE 131070 /* maximum number of hosts that -g can generate */
143

144
/* sized so as to be like traditional ping */
145
#define DEFAULT_PING_DATA_SIZE 56
146

147
/* maxima and minima */
148
#ifdef FPING_SAFE_LIMITS
149
#define MIN_INTERVAL 1 /* in millisec */
150
#define MIN_PERHOST_INTERVAL 10 /* in millisec */
151
#else
152
#define MIN_INTERVAL 0
153
#define MIN_PERHOST_INTERVAL 0
154
#endif
155

156
/* response time array flags */
157
#define RESP_WAITING -1
158
#define RESP_UNUSED -2
159
#define RESP_ERROR -3
160
#define RESP_TIMEOUT -4
161

162
/* debugging flags */
163
#if defined(DEBUG) || defined(_DEBUG)
164
#define DBG_TRACE 1
165
#define DBG_SENT_TIMES 2
166
#define DBG_RANDOM_LOSE_FEW 4
167
#define DBG_RANDOM_LOSE_MANY 8
168
#define DBG_PRINT_PER_SYSTEM 16
169
#define DBG_REPORT_ALL_RTTS 32
170
#endif /* DEBUG || _DEBUG */
171

172
/* Long names for ICMP packet types */
173
#define ICMP_TYPE_STR_MAX 18
174
char *icmp_type_str[19] = {
175
    "ICMP Echo Reply", /* 0 */
176
    "",
177
    "",
178
    "ICMP Unreachable", /* 3 */
179
    "ICMP Source Quench", /* 4 */
180
    "ICMP Redirect", /* 5 */
181
    "",
182
    "",
183
    "ICMP Echo", /* 8 */
184
    "",
185
    "",
186
    "ICMP Time Exceeded", /* 11 */
187
    "ICMP Parameter Problem", /* 12 */
188
    "ICMP Timestamp Request", /* 13 */
189
    "ICMP Timestamp Reply", /* 14 */
190
    "ICMP Information Request", /* 15 */
191
    "ICMP Information Reply", /* 16 */
192
    "ICMP Mask Request", /* 17 */
193
    "ICMP Mask Reply" /* 18 */
194
};
195

196
char *icmp_unreach_str[16] = {
197
    "ICMP Network Unreachable", /* 0 */
198
    "ICMP Host Unreachable", /* 1 */
199
    "ICMP Protocol Unreachable", /* 2 */
200
    "ICMP Port Unreachable", /* 3 */
201
    "ICMP Unreachable (Fragmentation Needed)", /* 4 */
202
    "ICMP Unreachable (Source Route Failed)", /* 5 */
203
    "ICMP Unreachable (Destination Network Unknown)", /* 6 */
204
    "ICMP Unreachable (Destination Host Unknown)", /* 7 */
205
    "ICMP Unreachable (Source Host Isolated)", /* 8 */
206
    "ICMP Unreachable (Communication with Network Prohibited)", /* 9 */
207
    "ICMP Unreachable (Communication with Host Prohibited)", /* 10 */
208
    "ICMP Unreachable (Network Unreachable For Type Of Service)", /* 11 */
209
    "ICMP Unreachable (Host Unreachable For Type Of Service)", /* 12 */
210
    "ICMP Unreachable (Communication Administratively Prohibited)", /* 13 */
211
    "ICMP Unreachable (Host Precedence Violation)", /* 14 */
212
    "ICMP Unreachable (Precedence cutoff in effect)" /* 15 */
213
};
214

215
#define ICMP_UNREACH_MAXTYPE 15
216

217
struct event;
218
typedef struct host_entry {
219
    int i; /* index into array */
220
    char *name; /* name as given by user */
221
    char *host; /* text description of host */
222
    struct sockaddr_storage saddr; /* internet address */
223
    socklen_t saddr_len;
224
    int64_t timeout; /* time to wait for response */
225
    int64_t last_send_time; /* time of last packet sent */
226
    int num_sent; /* number of ping packets sent (for statistics) */
227
    int num_recv; /* number of pings received (duplicates ignored) */
228
    int num_recv_total; /* number of pings received, including duplicates */
229
    int64_t max_reply; /* longest response time */
230
    int64_t min_reply; /* shortest response time */
231
    int64_t total_time; /* sum of response times */
232
    /* _i -> splits (reset on every report interval) */
233
    int num_sent_i; /* number of ping packets sent */
234
    int num_recv_i; /* number of pings received */
235
    int64_t max_reply_i; /* longest response time */
236
    int64_t min_reply_i; /* shortest response time */
237
    int64_t total_time_i; /* sum of response times */
238
    int64_t *resp_times; /* individual response times */
239

240
    /* to avoid allocating two struct events each time that we send a ping, we
241
     * preallocate here two struct events for each ping that we might send for
242
     * this host. */
243
    struct event *event_storage_ping;
244
    struct event *event_storage_timeout;
245
} HOST_ENTRY;
246

247
int event_storage_count; /* how many events can be stored in host_entry->event_storage_xxx */
248

249
/* basic algorithm to ensure that we have correct data at all times:
250
 *
251
 * 1. when a ping is sent:
252
 *    - two events get added into event_queue:
253
 *      - t+PERIOD: ping event
254
 *      - t+TIMEOUT: timeout event
255
 *
256
 * 2. when a ping is received:
257
 *    - record statistics (increase num_sent and num_received)
258
 *    - remove timeout event (we store the event in seqmap, so that we can retrieve it when the response is received)
259
 *
260
 * 3. when a timeout happens:
261
 *    - record statistics (increase num_sent only)
262
 */
263

264
#define EV_TYPE_PING 1
265
#define EV_TYPE_TIMEOUT 2
266

267
struct event {
268
    struct event *ev_prev;
269
    struct event *ev_next;
270
    int64_t ev_time;
271
    struct host_entry *host;
272
    int ping_index;
273
};
274

275
struct event_queue {
276
    struct event *first;
277
    struct event *last;
278
};
279

280
/*** globals ***/
281

282
HOST_ENTRY **table = NULL; /* array of pointers to items in the list */
283

284
/* we keep two separate queues: a ping queue, for when the next ping should be
285
 * sent, and a timeout queue. the reason for having two separate queues is that
286
 * the ping period and the timeout value are different, so if we put them in
287
 * the same event queue, we would need to scan many more entries when inserting
288
 * into the sorted list.
289
 */
290
struct event_queue event_queue_ping;
291
struct event_queue event_queue_timeout;
292

293
char *prog;
294
int ident4 = 0; /* our icmp identity field */
295
int ident6 = 0;
296
int socket4 = -1;
297
int socktype4 = -1;
298
int using_sock_dgram4 = 0;
299
#ifndef IPV6
300
int hints_ai_family = AF_INET;
301
#else
302
int socket6 = -1;
303
int socktype6 = -1;
304
int hints_ai_family = AF_UNSPEC;
305
#endif
306

307
volatile sig_atomic_t status_snapshot = 0;
308
volatile sig_atomic_t finish_requested = 0;
309

310
unsigned int debugging = 0;
311

312
/* all time-related values are int64_t nanoseconds */
313
unsigned int retry = DEFAULT_RETRY;
314
int64_t timeout = (int64_t)DEFAULT_TIMEOUT * 1000000;
315
int64_t interval = (int64_t)DEFAULT_INTERVAL * 1000000;
316
int64_t perhost_interval = (int64_t)DEFAULT_PERHOST_INTERVAL * 1000000;
317
float backoff = DEFAULT_BACKOFF_FACTOR;
318
unsigned int ping_data_size = DEFAULT_PING_DATA_SIZE;
319
unsigned int count = 1, min_reachable = 0;
320
unsigned int trials;
321
int64_t report_interval = 0;
322
unsigned int ttl = 0;
323
int src_addr_set = 0;
324
struct in_addr src_addr;
325
#ifdef IPV6
326
int src_addr6_set = 0;
327
struct in6_addr src_addr6;
328
#endif
329

330
/* global stats */
331
int64_t max_reply = 0;
332
int64_t min_reply = 0;
333
int64_t total_replies = 0;
334
int64_t sum_replies = 0;
335
int max_hostname_len = 0;
336
int num_hosts = 0; /* total number of hosts */
337
int num_alive = 0, /* total number alive */
338
    num_unreachable = 0, /* total number unreachable */
339
    num_noaddress = 0; /* total number of addresses not found */
340
int num_timeout = 0, /* number of times select timed out */
341
    num_pingsent = 0, /* total pings sent */
342
    num_pingreceived = 0, /* total pings received */
343
    num_othericmprcvd = 0; /* total non-echo-reply ICMP received */
344

345
struct timespec current_time; /* current time (pseudo) */
346
int64_t current_time_ns;
347
int64_t start_time;
348
int64_t end_time;
349
int64_t last_send_time; /* time last ping was sent */
350
int64_t next_report_time; /* time next -Q report is expected */
351

352
/* switches */
353
int generate_flag = 0; /* flag for IP list generation */
354
int verbose_flag, quiet_flag, stats_flag, unreachable_flag, alive_flag;
355
int elapsed_flag, version_flag, count_flag, loop_flag, netdata_flag;
356
int per_recv_flag, report_all_rtts_flag, name_flag, addr_flag, backoff_flag, rdns_flag;
357
int multif_flag, timeout_flag, fast_reachable;
358
int outage_flag = 0;
359
int timestamp_flag = 0;
360
int timestamp_format_flag = 0;
361
int random_data_flag = 0;
362
int cumulative_stats_flag = 0;
363
int check_source_flag = 0;
364
#if defined(DEBUG) || defined(_DEBUG)
365
int randomly_lose_flag, trace_flag, print_per_system_flag;
366
int lose_factor;
367
#endif /* DEBUG || _DEBUG */
368

369
unsigned int fwmark = 0;
370

371
char *filename = NULL; /* file containing hosts to ping */
372

373
/*** forward declarations ***/
374

375
void add_name(char *name);
376
void add_addr(char *name, char *host, struct sockaddr *ipaddr, socklen_t ipaddr_len);
377
char *na_cat(char *name, struct in_addr ipaddr);
378
void crash_and_burn(char *message);
379
void errno_crash_and_burn(char *message);
380
char *get_host_by_address(struct in_addr in);
381
int send_ping(HOST_ENTRY *h, int index);
382
void usage(int);
383
int wait_for_reply(int64_t);
384
void print_per_system_stats(void);
385
void print_per_system_splits(void);
386
void stats_reset_interval(HOST_ENTRY *h);
387
void print_netdata(void);
388
void print_global_stats(void);
389
void main_loop();
390
void signal_handler(int);
391
void finish();
392
const char *sprint_tm(int64_t t);
393
void ev_enqueue(struct event_queue *queue, struct event *event);
394
struct event *ev_dequeue(struct event_queue *queue);
395
void ev_remove(struct event_queue *queue, struct event *event);
396
void add_cidr(char *);
397
void add_range(char *, char *);
398
void add_addr_range_ipv4(unsigned long, unsigned long);
399
void print_warning(char *fmt, ...);
400
int addr_cmp(struct sockaddr *a, struct sockaddr *b);
401
void host_add_ping_event(HOST_ENTRY *h, int index, int64_t ev_time);
402
void host_add_timeout_event(HOST_ENTRY *h, int index, int64_t ev_time);
403
struct event *host_get_timeout_event(HOST_ENTRY *h, int index);
404
void stats_add(HOST_ENTRY *h, int index, int success, int64_t latency);
405
void update_current_time();
406
void print_timestamp_format(int64_t current_time_ns, int timestamp_format);
407

408
/************************************************************
409

410
  Function: p_setsockopt
411

412
*************************************************************
413

414
  Inputs:  p_uid: privileged uid. Others as per setsockopt(2)
415

416
  Description:
417

418
  Elevates privileges to p_uid when required, calls
419
  setsockopt, and drops privileges back.
420

421
************************************************************/
422

423
int p_setsockopt(uid_t p_uid, int sockfd, int level, int optname,
×
424
    const void *optval, socklen_t optlen)
425
{
426
    const uid_t saved_uid = geteuid();
×
427
    int res;
428

429
    if (p_uid != saved_uid && seteuid(p_uid)) {
×
430
        perror("cannot elevate privileges for setsockopt");
×
431
    }
432

433
    res = setsockopt(sockfd, level, optname, optval, optlen);
×
434

435
    if (p_uid != saved_uid && seteuid(saved_uid)) {
×
436
        perror("fatal error: could not drop privileges after setsockopt");
×
437
        /* continuing would be a security hole */
438
        exit(4);
×
439
    }
440

441
    return res;
×
442
}
443

444
/************************************************************
445

446
  Function: main
447

448
*************************************************************
449

450
  Inputs:  int argc, char** argv
451

452
  Description:
453

454
  Main program entry point
455

456
************************************************************/
457

458
int main(int argc, char **argv)
416✔
459
{
460
/* Debug: CPU Performance */
461
#if defined(DEBUG) || defined(_DEBUG)
462
    clock_t perf_cpu_start, perf_cpu_end;
463
    double perf_cpu_time_used;
464
    perf_cpu_start = clock();
465
#endif /* DEBUG || _DEBUG */
466

467
    int c;
468
    const uid_t suid = geteuid();
416✔
469
    int tos = 0;
416✔
470
    struct optparse optparse_state;
471
#ifdef USE_SIGACTION
472
    struct sigaction act;
473
#endif
474

475
    /* pre-parse -h/--help, so that we also can output help information
476
     * without trying to open the socket, which might fail */
477
    prog = argv[0];
416✔
478
    if (argc == 2 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)) {
416✔
479
        usage(0);
3✔
480
    }
1✔
481

482
    socket4 = open_ping_socket_ipv4(&socktype4);
414✔
483
#ifdef __linux__
484
    /* We only treat SOCK_DGRAM differently on Linux, where the IPv4 header
485
     * structure is missing in the message.
486
     */
487
    using_sock_dgram4 = (socktype4 == SOCK_DGRAM);
276✔
488
#endif
489

490
#ifdef IPV6
491
    socket6 = open_ping_socket_ipv6(&socktype6);
414✔
492
    /* if called (sym-linked) via 'fping6', imply '-6'
493
     * for backward compatibility */
494
    if (strstr(prog, "fping6")) {
414✔
495
        hints_ai_family = AF_INET6;
×
496
    }
497
#endif
498

499
    memset(&src_addr, 0, sizeof(src_addr));
414✔
500
#ifdef IPV6
501
    memset(&src_addr6, 0, sizeof(src_addr6));
414✔
502
#endif
503

504
    if (!suid && suid != getuid()) {
414✔
505
        /* *temporarily* drop privileges */
506
        if (seteuid(getuid()) == -1)
392✔
507
            perror("cannot setuid");
×
508
    }
118✔
509

510
    optparse_init(&optparse_state, argv);
414✔
511
    ident4 = ident6 = htons(getpid() & 0xFFFF);
414✔
512
    verbose_flag = 1;
414✔
513
    backoff_flag = 1;
414✔
514
    opterr = 1;
414✔
515

516
    /* get command line options */
517

518
    struct optparse_long longopts[] = {
414✔
519
        { "ipv4", '4', OPTPARSE_NONE },
520
        { "ipv6", '6', OPTPARSE_NONE },
521
        { "alive", 'a', OPTPARSE_NONE },
522
        { "addr", 'A', OPTPARSE_NONE },
523
        { "size", 'b', OPTPARSE_REQUIRED },
524
        { "backoff", 'B', OPTPARSE_REQUIRED },
525
        { "count", 'c', OPTPARSE_REQUIRED },
526
        { "vcount", 'C', OPTPARSE_REQUIRED },
527
        { "rdns", 'd', OPTPARSE_NONE },
528
        { "timestamp", 'D', OPTPARSE_NONE },
529
        { "timestamp-format", '0', OPTPARSE_REQUIRED },
530
        { "elapsed", 'e', OPTPARSE_NONE },
531
        { "file", 'f', OPTPARSE_REQUIRED },
532
        { "generate", 'g', OPTPARSE_NONE },
533
        { "help", 'h', OPTPARSE_NONE },
534
        { "ttl", 'H', OPTPARSE_REQUIRED },
535
        { "interval", 'i', OPTPARSE_REQUIRED },
536
        { "iface", 'I', OPTPARSE_REQUIRED },
537
#ifdef SO_MARK
538
        { "fwmark", 'k', OPTPARSE_REQUIRED },
539
#endif
540
        { "loop", 'l', OPTPARSE_NONE },
541
        { "all", 'm', OPTPARSE_NONE },
542
        { "dontfrag", 'M', OPTPARSE_NONE },
543
        { "name", 'n', OPTPARSE_NONE },
544
        { "netdata", 'N', OPTPARSE_NONE },
545
        { "outage", 'o', OPTPARSE_NONE },
546
        { "tos", 'O', OPTPARSE_REQUIRED },
547
        { "period", 'p', OPTPARSE_REQUIRED },
548
        { "quiet", 'q', OPTPARSE_NONE },
549
        { "squiet", 'Q', OPTPARSE_REQUIRED },
550
        { "retry", 'r', OPTPARSE_REQUIRED },
551
        { "random", 'R', OPTPARSE_NONE },
552
        { "stats", 's', OPTPARSE_NONE },
553
        { "src", 'S', OPTPARSE_REQUIRED },
554
        { "timeout", 't', OPTPARSE_REQUIRED },
555
        { NULL, 'T', OPTPARSE_REQUIRED },
556
        { "unreach", 'u', OPTPARSE_NONE },
557
        { "version", 'v', OPTPARSE_NONE },
558
        { "reachable", 'x', OPTPARSE_REQUIRED },
559
        { "fast-reachable", 'X', OPTPARSE_REQUIRED },
560
        { "check-source", '0', OPTPARSE_NONE },
561
#if defined(DEBUG) || defined(_DEBUG)
562
        { NULL, 'z', OPTPARSE_REQUIRED },
563
#endif
564
        { 0, 0, 0 }
565
    };
566

567
    float opt_value_float;
568
    while ((c = optparse_long(&optparse_state, longopts, NULL)) != EOF) {
1,068✔
569
        switch (c) {
615✔
570
        case '0':
18✔
571
            if(strstr(optparse_state.optlongname, "timestamp-format") != NULL) {
24✔
572
              if(strcmp(optparse_state.optarg, "ctime") == 0) {
15✔
573
                timestamp_format_flag = 1;
3✔
574
              }else if(strcmp(optparse_state.optarg, "iso") == 0) {
13✔
575
                timestamp_format_flag = 2;
3✔
576
              }else if(strcmp(optparse_state.optarg, "rfc3339") == 0) {
10✔
577
                timestamp_format_flag = 3;
3✔
578
              }else{
1✔
579
                usage(1);
6✔
580
              }
581
            } else if (strstr(optparse_state.optlongname, "check-source") != NULL) {
14✔
582
                check_source_flag = 1;
9✔
583
            } else {
1✔
NEW
584
                usage(1);
×
585
            }
586
            break;
20✔
587
        case '4':
16✔
588
#ifdef IPV6
589
            if (hints_ai_family != AF_UNSPEC && hints_ai_family != AF_INET) {
24✔
590
                fprintf(stderr, "%s: can't specify both -4 and -6\n", prog);
3✔
591
                exit(1);
3✔
592
            }
593
            hints_ai_family = AF_INET;
21✔
594
#endif
595
            break;
21✔
596
        case '6':
16✔
597
#ifdef IPV6
598
            if (hints_ai_family != AF_UNSPEC && hints_ai_family != AF_INET6) {
19✔
599
                fprintf(stderr, "%s: can't specify both -4 and -6\n", prog);
3✔
600
                exit(1);
3✔
601
            }
602
            hints_ai_family = AF_INET6;
16✔
603
#else
604
            fprintf(stderr, "%s: IPv6 not supported by this binary\n", prog);
605
            exit(1);
606
#endif
607
            break;
16✔
608
        case 'M':
2✔
609
#ifdef IP_MTU_DISCOVER
610
            if (socket4 >= 0) {
2✔
611
                int val = IP_PMTUDISC_DO;
2✔
612
                if (setsockopt(socket4, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val))) {
2✔
613
                    perror("setsockopt IP_MTU_DISCOVER");
614
                }
615
            }
616
#ifdef IPV6
617
            if (socket6 >= 0) {
2✔
618
                int val = IPV6_PMTUDISC_DO;
2✔
619
                if (setsockopt(socket6, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val, sizeof(val))) {
2✔
620
                    perror("setsockopt IPV6_MTU_DISCOVER");
621
                }
622
            }
623
#endif
624
#else
625
            fprintf(stderr, "%s, -M option not supported on this platform\n", prog);
626
            exit(1);
627
#endif
628
            break;
2✔
629

630
        case 't':
14✔
631
            if (sscanf(optparse_state.optarg, "%f", &opt_value_float) != 1)
16✔
632
                usage(1);
6✔
633
            if (opt_value_float < 0) {
12✔
634
                usage(1);
3✔
635
            }
1✔
636
            timeout = opt_value_float * 1000000;
10✔
637
            timeout_flag = 1;
10✔
638
            break;
10✔
639

640
        case 'r':
10✔
641
            if (sscanf(optparse_state.optarg, "%u", &retry) != 1)
12✔
642
                usage(1);
6✔
643
            break;
8✔
644

645
        case 'i':
12✔
646
            if (sscanf(optparse_state.optarg, "%f", &opt_value_float) != 1)
15✔
647
                usage(1);
6✔
648
            if (opt_value_float < 0) {
11✔
649
                usage(1);
3✔
650
            }
1✔
651
            interval = opt_value_float * 1000000;
9✔
652
            break;
9✔
653

654
        case 'p':
62✔
655
            if (sscanf(optparse_state.optarg, "%f", &opt_value_float) != 1)
88✔
656
                usage(1);
6✔
657
            if (opt_value_float < 0) {
84✔
658
                usage(1);
3✔
659
            }
1✔
660
            perhost_interval = opt_value_float * 1000000;
82✔
661

662
            break;
82✔
663

664
        case 'c':
52✔
665
            if (!(count = (unsigned int)atoi(optparse_state.optarg)))
74✔
666
                usage(1);
6✔
667

668
            count_flag = 1;
70✔
669
            break;
70✔
670

671
        case 'C':
20✔
672
            if (!(count = (unsigned int)atoi(optparse_state.optarg)))
26✔
673
                usage(1);
6✔
674

675
            count_flag = 1;
22✔
676
            report_all_rtts_flag = 1;
22✔
677
            break;
22✔
678

679
        case 'b':
8✔
680
            if (sscanf(optparse_state.optarg, "%u", &ping_data_size) != 1)
10✔
681
                usage(1);
6✔
682

683
            break;
6✔
684

685
        case 'h':
2✔
686
            usage(0);
3✔
687
            break;
1✔
688

689
        case 'q':
12✔
690
            verbose_flag = 0;
17✔
691
            quiet_flag = 1;
17✔
692
            break;
17✔
693

694
        case 'Q':
22✔
695
            verbose_flag = 0;
30✔
696
            quiet_flag = 1;
30✔
697
            if (sscanf(optparse_state.optarg, "%f", &opt_value_float) != 1)
30✔
698
                usage(1);
6✔
699
            if (opt_value_float < 0) {
26✔
700
                usage(1);
3✔
701
            }
1✔
702
            report_interval = opt_value_float * 1e9;
24✔
703

704
            /* recognize keyword(s) after number, ignore everything else */
705
            {
706
                char *comma = strchr(optparse_state.optarg, ',');
24✔
707
                if ((comma != NULL) && (strcmp(++comma, "cumulative") == 0)) {
24✔
708
                    cumulative_stats_flag = 1;
6✔
709
                }
2✔
710
            }
711

712
            break;
24✔
713

714
        case 'e':
2✔
715
            elapsed_flag = 1;
3✔
716
            break;
3✔
717

718
        case 'm':
719
            multif_flag = 1;
×
720
            break;
×
721

722
        case 'N':
2✔
723
            netdata_flag = 1;
3✔
724
            break;
3✔
725

726
        case 'n':
4✔
727
            name_flag = 1;
6✔
728
            if (rdns_flag) {
6✔
729
                fprintf(stderr, "%s: use either one of -d or -n\n", prog);
3✔
730
                exit(1);
3✔
731
            }
732
            break;
3✔
733

734
        case 'd':
4✔
735
            rdns_flag = 1;
6✔
736
            if (name_flag) {
6✔
737
                fprintf(stderr, "%s: use either one of -d or -n\n", prog);
3✔
738
                exit(1);
3✔
739
            }
740
            break;
3✔
741

742
        case 'A':
2✔
743
            addr_flag = 1;
3✔
744
            break;
3✔
745

746
        case 'B':
10✔
747
            if (!(backoff = atof(optparse_state.optarg)))
12✔
748
                usage(1);
6✔
749

750
            break;
8✔
751

752
        case 's':
4✔
753
            stats_flag = 1;
6✔
754
            break;
6✔
755

756
        case 'D':
14✔
757
            timestamp_flag = 1;
21✔
758
            break;
21✔
759

760
        case 'R':
4✔
761
            random_data_flag = 1;
5✔
762
            break;
5✔
763

764
        case 'l':
2✔
765
            loop_flag = 1;
3✔
766
            backoff_flag = 0;
3✔
767
            break;
3✔
768

769
        case 'u':
8✔
770
            unreachable_flag = 1;
12✔
771
            break;
12✔
772

773
        case 'a':
10✔
774
            alive_flag = 1;
15✔
775
            break;
15✔
776

777
        case 'H':
8✔
778
            if (!(ttl = (unsigned int)atoi(optparse_state.optarg)))
10✔
779
                usage(1);
6✔
780
            break;
6✔
781

782
#if defined(DEBUG) || defined(_DEBUG)
783
        case 'z':
784
            if (sscanf(optparse_state.optarg, "0x%x", &debugging) != 1)
785
                if (sscanf(optparse_state.optarg, "%u", &debugging) != 1)
786
                    usage(1);
787

788
            break;
789
#endif /* DEBUG || _DEBUG */
790

791
        case 'v':
4✔
792
            printf("%s: Version %s\n", prog, VERSION);
6✔
793
            exit(0);
6✔
794

795
        case 'x':
8✔
796
            if (!(min_reachable = (unsigned int)atoi(optparse_state.optarg)))
10✔
797
                usage(1);
6✔
798
            break;
6✔
799

800
        case 'X':
6✔
801
            if (!(min_reachable = (unsigned int)atoi(optparse_state.optarg)))
9✔
802
                usage(1);
6✔
803
            fast_reachable = 1;
5✔
804
            break;
5✔
805

806
        case 'f':
8✔
807
            filename = optparse_state.optarg;
12✔
808
            break;
12✔
809
#ifdef SO_MARK
810
        case 'k':
6✔
811
            if (!(fwmark = (unsigned int)atol(optparse_state.optarg)))
6✔
812
                usage(1);
4✔
813

814
            if (socket4 >= 0)
2✔
815
                if(-1 == setsockopt(socket4, SOL_SOCKET, SO_MARK, &fwmark, sizeof fwmark))
2✔
816
                    perror("fwmark ipv4");
817

818
#ifdef IPV6
819
            if (socket6 >= 0)
2✔
820
                if(-1 == setsockopt(socket6, SOL_SOCKET, SO_MARK, &fwmark, sizeof fwmark))
2✔
821
                    perror("fwmark ipv6");
822
#endif
823

824
            break;
2✔
825
#endif
826

827
        case 'g':
44✔
828
            /* use IP list generation */
829
            /* mutually exclusive with using file input or command line targets */
830
            generate_flag = 1;
62✔
831
            break;
62✔
832

833
        case 'S':
10✔
834
            if (inet_pton(AF_INET, optparse_state.optarg, &src_addr)) {
13✔
835
                src_addr_set = 1;
6✔
836
                break;
6✔
837
            }
838
#ifdef IPV6
839
            if (inet_pton(AF_INET6, optparse_state.optarg, &src_addr6)) {
7✔
840
                src_addr6_set = 1;
4✔
841
                break;
4✔
842
            }
843
#endif
844
            fprintf(stderr, "%s: can't parse source address: %s\n", prog, optparse_state.optarg);
3✔
845
            exit(1);
3✔
846

847
        case 'I':
848
#ifdef SO_BINDTODEVICE
849
            if (socket4 >= 0) {
850
                if (p_setsockopt(suid, socket4, SOL_SOCKET, SO_BINDTODEVICE, optparse_state.optarg, strlen(optparse_state.optarg))) {
851
                    perror("binding to specific interface (SO_BINTODEVICE)");
852
                    exit(1);
853
                }
854
            }
855
#ifdef IPV6
856
            if (socket6 >= 0) {
857
                if (p_setsockopt(suid, socket6, SOL_SOCKET, SO_BINDTODEVICE, optparse_state.optarg, strlen(optparse_state.optarg))) {
858
                    perror("binding to specific interface (SO_BINTODEVICE), IPV6");
859
                    exit(1);
860
                }
861
            }
862
#endif
863
#else
864
            printf("%s: cant bind to a particular net interface since SO_BINDTODEVICE is not supported on your os.\n", prog);
865
            exit(3);
866
            ;
867
#endif
868
            break;
869

870
        case 'T':
2✔
871
            /* This option is ignored for compatibility reasons ("select timeout" is not meaningful anymore) */
872
            break;
3✔
873

874
        case 'O':
6✔
875
            if (sscanf(optparse_state.optarg, "%i", &tos) == 1) {
9✔
876
                if (socket4 >= 0) {
3✔
877
                    if (setsockopt(socket4, IPPROTO_IP, IP_TOS, &tos, sizeof(tos))) {
3✔
878
                        perror("setting type of service octet IP_TOS");
×
879
                    }
880
                }
1✔
881
#if defined(IPV6) && defined(IPV6_TCLASS)
882
                if (socket6 >= 0) {
3✔
883
                    if (setsockopt(socket6, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos))) {
3✔
884
                        perror("setting type of service octet IPV6_TCLASS");
×
885
                    }
886
                }
1✔
887
#endif
888
            }
1✔
889
            else {
890
                usage(1);
6✔
891
            }
892
            break;
5✔
893

894
        case 'o':
6✔
895
            outage_flag = 1;
9✔
896
            break;
9✔
897

898
        case '?':
4✔
899
            fprintf(stderr, "%s: %s\n", argv[0], optparse_state.errmsg);
6✔
900
            fprintf(stderr, "see 'fping -h' for usage information\n");
6✔
901
            exit(1);
6✔
902
            break;
903
        }
904
    }
316✔
905

906
    /* permanently drop privileges */
907
    if (suid != getuid() && setuid(getuid())) {
265✔
908
        perror("fatal: failed to permanently drop privileges");
×
909
        /* continuing would be a security hole */
910
        exit(4);
×
911
    }
912

913
    /* validate various option settings */
914

915
#ifndef IPV6
916
    if (socket4 < 0) {
917
        crash_and_burn("can't create socket (must run as root?)");
918
    }
919
#else
920
    if ((socket4 < 0 && socket6 < 0) || (hints_ai_family == AF_INET6 && socket6 < 0)) {
265✔
921
        crash_and_burn("can't create socket (must run as root?)");
×
922
    }
923
#endif
924

925
    if (ttl > 255) {
265✔
926
        fprintf(stderr, "%s: ttl %u out of range\n", prog, ttl);
3✔
927
        exit(1);
3✔
928
    }
929

930
    if (unreachable_flag && alive_flag) {
262✔
931
        fprintf(stderr, "%s: specify only one of a, u\n", prog);
3✔
932
        exit(1);
3✔
933
    }
934

935
    if (count_flag && loop_flag) {
259✔
936
        fprintf(stderr, "%s: specify only one of c, l\n", prog);
3✔
937
        exit(1);
3✔
938
    }
939

940
#ifdef FPING_SAFE_LIMITS
941
    if ((interval < (int64_t)MIN_INTERVAL * 1000000 || perhost_interval < (int64_t)MIN_PERHOST_INTERVAL * 1000000)
256✔
942
        && getuid()) {
78✔
943
        fprintf(stderr, "%s: these options are too risky for mere mortals.\n", prog);
6✔
944
        fprintf(stderr, "%s: You need -i >= %u and -p >= %u\n",
8✔
945
            prog, MIN_INTERVAL, MIN_PERHOST_INTERVAL);
2✔
946
        exit(1);
6✔
947
    }
948
#endif
949

950
    if (ping_data_size > MAX_PING_DATA) {
250✔
951
        fprintf(stderr, "%s: data size %u not valid, must be lower than %u\n",
4✔
952
            prog, ping_data_size, (unsigned int)MAX_PING_DATA);
1✔
953
        exit(1);
3✔
954
    }
955

956
    if ((backoff > MAX_BACKOFF_FACTOR) || (backoff < MIN_BACKOFF_FACTOR)) {
247✔
957
        fprintf(stderr, "%s: backoff factor %.1f not valid, must be between %.1f and %.1f\n",
8✔
958
            prog, backoff, MIN_BACKOFF_FACTOR, MAX_BACKOFF_FACTOR);
2✔
959
        exit(1);
6✔
960
    }
961

962
    if (count_flag) {
241✔
963
        if (verbose_flag)
86✔
964
            per_recv_flag = 1;
45✔
965

966
        alive_flag = unreachable_flag = verbose_flag = 0;
86✔
967
    }
26✔
968

969
    if (loop_flag) {
241✔
970
        if (!report_interval)
×
971
            per_recv_flag = 1;
×
972

973
        alive_flag = unreachable_flag = verbose_flag = 0;
×
974
    }
975

976
    if (alive_flag || unreachable_flag || min_reachable)
241✔
977
        verbose_flag = 0;
18✔
978

979
    trials = (count > retry + 1) ? count : retry + 1;
245✔
980

981
    /* auto-tune default timeout for count/loop modes
982
     * see also github #32 */
983
    if (loop_flag || count_flag) {
245✔
984
        if (!timeout_flag) {
86✔
985
            timeout = perhost_interval;
81✔
986
            if (timeout > (int64_t)AUTOTUNE_TIMEOUT_MAX * 1000000) {
81✔
987
                timeout = (int64_t)AUTOTUNE_TIMEOUT_MAX * 1000000;
×
988
            }
989
        }
25✔
990
    }
26✔
991

992
#if defined(DEBUG) || defined(_DEBUG)
993
    if (debugging & DBG_TRACE)
994
        trace_flag = 1;
995

996
    if (debugging & DBG_RANDOM_LOSE_FEW) {
997
        randomly_lose_flag = 1;
998
        lose_factor = 1; /* ie, 1/4 */
999
    }
1000

1001
    if (debugging & DBG_RANDOM_LOSE_MANY) {
1002
        randomly_lose_flag = 1;
1003
        lose_factor = 5; /* ie, 3/4 */
1004
    }
1005

1006
    if (debugging & DBG_PRINT_PER_SYSTEM)
1007
        print_per_system_flag = 1;
1008

1009
    if ((debugging & DBG_REPORT_ALL_RTTS) && !loop_flag)
1010
        report_all_rtts_flag = 1;
1011

1012
    if (trace_flag) {
1013
        fprintf(stderr, "%s:\n  count: %u, retry: %u, interval: %.0f ms\n",
1014
            prog, count, retry, interval / 1e6);
1015
        fprintf(stderr, "  perhost_interval: %.0f ms, timeout: %.0f\n",
1016
            perhost_interval / 1e6, timeout / 1e6);
1017
        fprintf(stderr, "  ping_data_size = %u, trials = %u\n",
1018
            ping_data_size, trials);
1019

1020
        if (verbose_flag)
1021
            fprintf(stderr, "  verbose_flag set\n");
1022
        if (multif_flag)
1023
            fprintf(stderr, "  multif_flag set\n");
1024
        if (name_flag)
1025
            fprintf(stderr, "  name_flag set\n");
1026
        if (addr_flag)
1027
            fprintf(stderr, "  addr_flag set\n");
1028
        if (stats_flag)
1029
            fprintf(stderr, "  stats_flag set\n");
1030
        if (unreachable_flag)
1031
            fprintf(stderr, "  unreachable_flag set\n");
1032
        if (alive_flag)
1033
            fprintf(stderr, "  alive_flag set\n");
1034
        if (elapsed_flag)
1035
            fprintf(stderr, "  elapsed_flag set\n");
1036
        if (version_flag)
1037
            fprintf(stderr, "  version_flag set\n");
1038
        if (count_flag)
1039
            fprintf(stderr, "  count_flag set\n");
1040
        if (loop_flag)
1041
            fprintf(stderr, "  loop_flag set\n");
1042
        if (backoff_flag)
1043
            fprintf(stderr, "  backoff_flag set\n");
1044
        if (per_recv_flag)
1045
            fprintf(stderr, "  per_recv_flag set\n");
1046
        if (report_all_rtts_flag)
1047
            fprintf(stderr, "  report_all_rtts_flag set\n");
1048
        if (randomly_lose_flag)
1049
            fprintf(stderr, "  randomly_lose_flag set\n");
1050
        if (print_per_system_flag)
1051
            fprintf(stderr, "  print_per_system_flag set\n");
1052
        if (outage_flag)
1053
            fprintf(stderr, "  outage_flag set\n");
1054
        if (netdata_flag)
1055
            fprintf(stderr, "  netdata_flag set\n");
1056
    }
1057
#endif /* DEBUG || _DEBUG */
1058

1059
    /* set the TTL, if the -H option was set (otherwise ttl will be = 0) */
1060
    if (ttl > 0) {
245✔
1061
        if (socket4 >= 0) {
3✔
1062
            if (setsockopt(socket4, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl))) {
3✔
1063
                perror("setting time to live");
×
1064
            }
1065
        }
1✔
1066
#ifdef IPV6
1067
        if (socket6 >= 0) {
3✔
1068
            if (setsockopt(socket6, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl))) {
3✔
1069
                perror("setting time to live");
×
1070
            }
1071
        }
1✔
1072
#endif
1073
    }
1✔
1074

1075
#if HAVE_SO_TIMESTAMPNS
1076
    {
1077
        int opt = 1;
172✔
1078
        if (socket4 >= 0) {
172✔
1079
            if (setsockopt(socket4, SOL_SOCKET, SO_TIMESTAMPNS, &opt, sizeof(opt))) {
172✔
1080
                if (setsockopt(socket4, SOL_SOCKET, SO_TIMESTAMP, &opt, sizeof(opt))) {
1081
                    perror("setting SO_TIMESTAMPNS and SO_TIMESTAMP option");
1082
                }
1083
            }
1084
        }
1085
#ifdef IPV6
1086
        if (socket6 >= 0) {
172✔
1087
            if (setsockopt(socket6, SOL_SOCKET, SO_TIMESTAMPNS, &opt, sizeof(opt))) {
172✔
1088
                if (setsockopt(socket6, SOL_SOCKET, SO_TIMESTAMP, &opt, sizeof(opt))) {
1089
                    perror("setting SO_TIMESTAMPNS and SO_TIMESTAMP option (IPv6)");
1090
                }
1091
            }
1092
        }
1093
#endif
1094
    }
1095
#endif
1096

1097
    update_current_time();
245✔
1098
    start_time = current_time_ns;
245✔
1099

1100
    /* handle host names supplied on command line or in a file */
1101
    /* if the generate_flag is on, then generate the IP list */
1102

1103
    argv = &argv[optparse_state.optind];
245✔
1104
    argc -= optparse_state.optind;
245✔
1105

1106
    /* calculate how many ping can be in-flight per host */
1107
    if (count_flag) {
245✔
1108
        event_storage_count = count;
91✔
1109
    }
31✔
1110
    else if (loop_flag) {
154✔
1111
        if (perhost_interval > timeout) {
×
1112
            event_storage_count = 1;
×
1113
        }
1114
        else {
1115
            event_storage_count = 1 + timeout / perhost_interval;
×
1116
        }
1117
    }
1118
    else {
1119
        event_storage_count = 1;
154✔
1120
    }
1121

1122
    /* file and generate are mutually exclusive */
1123
    /* file and command line are mutually exclusive */
1124
    /* generate requires command line parameters beyond the switches */
1125
    if ((*argv && filename) || (filename && generate_flag) || (generate_flag && !*argv))
245✔
1126
        usage(1);
9✔
1127

1128
    /* if no conditions are specified, then assume input from stdin */
1129
    if (!*argv && !filename && !generate_flag)
237✔
1130
        filename = "-";
3✔
1131

1132
    if (*argv && !generate_flag) {
237✔
1133
        while (*argv) {
378✔
1134
            add_name(*argv);
212✔
1135
            ++argv;
212✔
1136
        }
1137
    }
46✔
1138
    else if (filename) {
71✔
1139
        FILE *ping_file;
1140
        char line[132];
1141
        char host[132];
1142

1143
        if (strcmp(filename, "-") == 0)
15✔
1144
            ping_file = fdopen(0, "r");
6✔
1145
        else
1146
            ping_file = fopen(filename, "r");
9✔
1147

1148
        if (!ping_file)
15✔
1149
            errno_crash_and_burn("fopen");
3✔
1150

1151
        while (fgets(line, sizeof(line), ping_file)) {
43✔
1152
            if (sscanf(line, "%s", host) != 1)
30✔
1153
                continue;
3✔
1154

1155
            if ((!*host) || (host[0] == '#')) /* magic to avoid comments */
27✔
1156
                continue;
3✔
1157

1158
            add_name(host);
24✔
1159
        }
1160

1161
        fclose(ping_file);
13✔
1162
    }
5✔
1163
    else if (*argv && generate_flag) {
56✔
1164
        if (argc == 1) {
56✔
1165
            /* one target: we expect a cidr range (n.n.n.n/m) */
1166
            add_cidr(argv[0]);
32✔
1167
        }
10✔
1168
        else if (argc == 2) {
24✔
1169
            add_range(argv[0], argv[1]);
21✔
1170
        }
5✔
1171
        else {
1172
            usage(1);
3✔
1173
        }
1174
    }
16✔
1175
    else {
1176
        usage(1);
×
1177
    }
1178

1179
    if (!num_hosts) {
207✔
1180
        exit(num_noaddress ? 2 : 1);
12✔
1181
    }
1182

1183
    if (socket4 >= 0 && (src_addr_set || socktype4 == SOCK_DGRAM)) {
195✔
1184
        socket_set_src_addr_ipv4(socket4, &src_addr, (socktype4 == SOCK_DGRAM) ? &ident4 : NULL);
6✔
1185
    }
2✔
1186
#ifdef IPV6
1187
    if (socket6 >= 0 && (src_addr6_set || socktype6 == SOCK_DGRAM)) {
193✔
1188
        socket_set_src_addr_ipv6(socket6, &src_addr6, (socktype6 == SOCK_DGRAM) ? &ident6 : NULL);
4✔
1189
    }
1190
#endif
1191

1192
    /* allocate and initialize array to map host nr to host_entry */
1193
    {
1194
        struct event *cursor = event_queue_ping.first;
191✔
1195
        int i = 0;
191✔
1196
        table = (HOST_ENTRY **)calloc(num_hosts, sizeof(HOST_ENTRY *));
191✔
1197
        if (!table)
191✔
1198
            crash_and_burn("Can't malloc array of hosts");
×
1199
        /* initialize table of hosts. we know that we have ping events scheduled
1200
         * for each of them */
1201
        for (cursor = event_queue_ping.first; cursor; cursor = cursor->ev_next) {
461✔
1202
            table[i] = cursor->host;
270✔
1203
            cursor->host->i = i;
270✔
1204
            i++;
270✔
1205
        }
80✔
1206
    }
1207

1208
    init_ping_buffer_ipv4(ping_data_size);
191✔
1209
#ifdef IPV6
1210
    init_ping_buffer_ipv6(ping_data_size);
191✔
1211
#endif
1212

1213
#ifdef USE_SIGACTION
1214
    memset(&act, 0, sizeof(act));
191✔
1215
    act.sa_handler = signal_handler;
191✔
1216
    sigemptyset(&act.sa_mask);
191✔
1217
    sigaddset(&act.sa_mask, SIGINT);
191✔
1218
    sigaddset(&act.sa_mask, SIGQUIT);
191✔
1219
    act.sa_flags = SA_RESTART;
191✔
1220
    if (sigaction(SIGQUIT, &act, NULL) || sigaction(SIGINT, &act, NULL)) {
191✔
1221
        crash_and_burn("failure to set signal handler");
24✔
1222
    }
24✔
1223
#else
1224
    signal(SIGINT, signal_handler);
1225
    signal(SIGQUIT, signal_handler);
1226
#endif
1227
    setlinebuf(stdout);
167✔
1228

1229
    if (report_interval) {
167✔
1230
        next_report_time = current_time_ns + report_interval;
24✔
1231
    }
8✔
1232

1233
    last_send_time = 0;
167✔
1234

1235
    seqmap_init();
167✔
1236

1237
    /* main loop */
1238
    main_loop();
167✔
1239

1240
/* Debug: CPU Performance */
1241
#if defined(DEBUG) || defined(_DEBUG)
1242
    perf_cpu_end = clock();
1243
    perf_cpu_time_used = ((double) (perf_cpu_end - perf_cpu_start)) / CLOCKS_PER_SEC;
1244
    printf("[DEBUG] CPU time used: %f sec", perf_cpu_time_used);
1245
#endif /* DEBUG || _DEBUG */
1246

1247
    finish();
167✔
1248

1249
    return 0;
39✔
1250
}
1251

1252
static inline int64_t timespec_ns(struct timespec *a)
3,578✔
1253
{
1254
    return ((int64_t)a->tv_sec * 1000000000) + a->tv_nsec;
3,578✔
1255
}
1256

1257
void add_cidr(char *addr)
31✔
1258
{
1259
    char *addr_end;
1260
    char *mask_str;
1261
    unsigned long mask;
1262
    unsigned long bitmask;
1263
    int ret;
1264
    struct addrinfo addr_hints;
1265
    struct addrinfo *addr_res;
1266
    unsigned long net_addr;
1267
    unsigned long net_last;
1268

1269
    /* Split address from mask */
1270
    addr_end = strchr(addr, '/');
31✔
1271
    if (addr_end == NULL) {
31✔
1272
        usage(1);
3✔
1273
    }
1✔
1274
    *addr_end = '\0';
29✔
1275
    mask_str = addr_end + 1;
29✔
1276
    mask = atoi(mask_str);
29✔
1277

1278
    /* parse address (IPv4 only) */
1279
    memset(&addr_hints, 0, sizeof(struct addrinfo));
29✔
1280
    addr_hints.ai_family = AF_UNSPEC;
29✔
1281
    addr_hints.ai_flags = AI_NUMERICHOST;
29✔
1282
    ret = getaddrinfo(addr, NULL, &addr_hints, &addr_res);
29✔
1283
    if (ret) {
29✔
1284
        fprintf(stderr, "%s, can't parse address %s: %s\n", prog, addr, gai_strerror(ret));
3✔
1285
        exit(1);
3✔
1286
    }
1287
    if (addr_res->ai_family != AF_INET) {
26✔
1288
        fprintf(stderr, "%s: -g works only with IPv4 addresses\n", prog);
5✔
1289
        exit(1);
5✔
1290
    }
1291
    net_addr = ntohl(((struct sockaddr_in *)addr_res->ai_addr)->sin_addr.s_addr);
21✔
1292
    freeaddrinfo(addr_res);
21✔
1293

1294
    /* check mask */
1295
    if (mask < 1 || mask > 32) {
21✔
1296
        fprintf(stderr, "%s: netmask must be between 1 and 32 (is: %s)\n", prog, mask_str);
6✔
1297
        exit(1);
6✔
1298
    }
1299

1300
    /* convert mask integer from 1 to 32 to a bitmask */
1301
    bitmask = ((unsigned long)0xFFFFFFFF) << (32 - mask);
15✔
1302

1303
    /* calculate network range */
1304
    net_addr &= bitmask;
15✔
1305
    net_last = net_addr + ((unsigned long)0x1 << (32 - mask)) - 1;
15✔
1306

1307
    /* exclude network and broadcast address for regular prefixes */
1308
    if (mask < 31) {
15✔
1309
        net_last--;
9✔
1310
        net_addr++;
9✔
1311
    }
3✔
1312

1313
    /* add all hosts in that network (net_addr and net_last inclusive) */
1314
    add_addr_range_ipv4(net_addr, net_last);
15✔
1315
}
13✔
1316

1317
void add_range(char *start, char *end)
21✔
1318
{
1319
    struct addrinfo addr_hints;
1320
    struct addrinfo *addr_res;
1321
    unsigned long start_long;
1322
    unsigned long end_long;
1323
    int ret;
1324

1325
    /* parse start address (IPv4 only) */
1326
    memset(&addr_hints, 0, sizeof(struct addrinfo));
21✔
1327
    addr_hints.ai_family = AF_UNSPEC;
21✔
1328
    addr_hints.ai_flags = AI_NUMERICHOST;
21✔
1329
    ret = getaddrinfo(start, NULL, &addr_hints, &addr_res);
21✔
1330
    if (ret) {
21✔
1331
        fprintf(stderr, "%s: can't parse address %s: %s\n", prog, start, gai_strerror(ret));
3✔
1332
        exit(1);
3✔
1333
    }
1334
    if (addr_res->ai_family != AF_INET) {
18✔
1335
        freeaddrinfo(addr_res);
4✔
1336
        fprintf(stderr, "%s: -g works only with IPv4 addresses\n", prog);
4✔
1337
        exit(1);
4✔
1338
    }
1339
    start_long = ntohl(((struct sockaddr_in *)addr_res->ai_addr)->sin_addr.s_addr);
14✔
1340

1341
    /* parse end address (IPv4 only) */
1342
    memset(&addr_hints, 0, sizeof(struct addrinfo));
14✔
1343
    addr_hints.ai_family = AF_UNSPEC;
14✔
1344
    addr_hints.ai_flags = AI_NUMERICHOST;
14✔
1345
    ret = getaddrinfo(end, NULL, &addr_hints, &addr_res);
14✔
1346
    if (ret) {
14✔
1347
        fprintf(stderr, "%s: can't parse address %s: %s\n", prog, end, gai_strerror(ret));
3✔
1348
        exit(1);
3✔
1349
    }
1350
    if (addr_res->ai_family != AF_INET) {
11✔
1351
        freeaddrinfo(addr_res);
2✔
1352
        fprintf(stderr, "%s: -g works only with IPv4 addresses\n", prog);
2✔
1353
        exit(1);
2✔
1354
    }
1355
    end_long = ntohl(((struct sockaddr_in *)addr_res->ai_addr)->sin_addr.s_addr);
9✔
1356
    freeaddrinfo(addr_res);
9✔
1357

1358
    /* add IPv4 addresses from closed interval [start_long,end_long] */
1359
    add_addr_range_ipv4(start_long, end_long);
9✔
1360
}
7✔
1361

1362
void add_addr_range_ipv4(unsigned long start_long, unsigned long end_long)
24✔
1363
{
1364
    /* check if generator limit is exceeded */
1365
    if (end_long >= start_long + MAX_GENERATE) {
24✔
1366
        fprintf(stderr, "%s: -g parameter generates too many addresses\n", prog);
6✔
1367
        exit(1);
6✔
1368
    }
1369

1370
    /* generate */
1371
    for (; start_long <= end_long; start_long++) {
66✔
1372
        struct in_addr in_addr_tmp;
1373
        char buffer[20];
1374
        in_addr_tmp.s_addr = htonl(start_long);
48✔
1375
        inet_ntop(AF_INET, &in_addr_tmp, buffer, sizeof(buffer));
48✔
1376
        add_name(buffer);
48✔
1377
    }
16✔
1378
}
18✔
1379

1380
void main_loop()
179✔
1381
{
1382
    int64_t lt;
1383
    int64_t wait_time_ns;
1384
    struct event *event;
1385
    struct host_entry *h;
1386

1387
    while (event_queue_ping.first || event_queue_timeout.first) {
1,250✔
1388
        dbg_printf("%s", "# main_loop\n");
1389

1390
        /* timeout event ? */
1391
        if (event_queue_timeout.first && event_queue_timeout.first->ev_time - current_time_ns <= 0) {
1,076✔
1392
            event = ev_dequeue(&event_queue_timeout);
89✔
1393
            h = event->host;
89✔
1394

1395
            dbg_printf("%s [%d]: timeout event\n", h->host, event->ping_index);
1396

1397
            stats_add(h, event->ping_index, 0, -1);
89✔
1398

1399
            if (per_recv_flag) {
89✔
1400
                if (timestamp_flag) {
19✔
1401
                    print_timestamp_format(current_time_ns, timestamp_format_flag);
×
1402
                }
1403
                printf("%-*s : [%d], timed out",
19✔
1404
                    max_hostname_len, h->host, event->ping_index);
5✔
1405
                if (h->num_recv > 0) {
19✔
1406
                    printf(" (%s avg, ", sprint_tm(h->total_time / h->num_recv));
×
1407
                }
1408
                else {
1409
                    printf(" (NaN avg, ");
19✔
1410
                }
1411
                if (h->num_recv <= h->num_sent) {
19✔
1412
                    printf("%d%% loss)",
19✔
1413
                        ((h->num_sent - h->num_recv) * 100) / h->num_sent);
19✔
1414
                }
5✔
1415
                else {
1416
                    printf("%d%% return)",
×
1417
                        (h->num_recv_total * 100) / h->num_sent);
×
1418
                }
1419
                printf("\n");
19✔
1420
            }
5✔
1421

1422
            /* do we need to send a retry? */
1423
            if (!loop_flag && !count_flag) {
89✔
1424
                if (h->num_sent < retry + 1) {
46✔
1425
                    if (backoff_flag) {
30✔
1426
                        h->timeout *= backoff;
30✔
1427
                    }
6✔
1428
                    send_ping(h, event->ping_index);
30✔
1429
                }
6✔
1430
            }
10✔
1431

1432
            /* note: we process first timeout events, because we might need to
1433
             * wait to process ping events, while we for sure never need to
1434
             * wait for timeout events.
1435
             */
1436
            continue;
89✔
1437
        }
1438

1439
        /* ping event ? */
1440
        if (event_queue_ping.first && event_queue_ping.first->ev_time - current_time_ns <= 0) {
1,159✔
1441
            /* Make sure that we don't ping more than once every "interval" */
1442
            lt = current_time_ns - last_send_time;
714✔
1443
            if (lt < interval)
714✔
1444
                goto wait_for_reply;
160✔
1445

1446
            /* Dequeue the event */
1447
            event = ev_dequeue(&event_queue_ping);
554✔
1448
            h = event->host;
554✔
1449

1450
            dbg_printf("%s [%d]: ping event\n", h->host, event->ping_index);
1451

1452
            /* Send the ping */
1453
            send_ping(h, event->ping_index);
554✔
1454

1455
            /* Loop and count mode: schedule next ping */
1456
            if (loop_flag || (count_flag && event->ping_index + 1 < count)) {
554✔
1457
                host_add_ping_event(h, event->ping_index + 1, event->ev_time + perhost_interval);
299✔
1458
            }
97✔
1459
        }
172✔
1460

1461
    wait_for_reply:
382✔
1462

1463
        /* When is the next ping next event? */
1464
        wait_time_ns = -1;
987✔
1465
        if (event_queue_ping.first) {
987✔
1466
            wait_time_ns = event_queue_ping.first->ev_time - current_time_ns;
753✔
1467
            if (wait_time_ns < 0)
753✔
1468
                wait_time_ns = 0;
330✔
1469
            /* make sure that we wait enough, so that the inter-ping delay is
1470
             * bigger than 'interval' */
1471
            if (wait_time_ns < interval) {
753✔
1472
                lt = current_time_ns - last_send_time;
336✔
1473
                if (lt < interval) {
336✔
1474
                    wait_time_ns = interval - lt;
336✔
1475
                }
130✔
1476
            }
130✔
1477

1478
            dbg_printf("next ping event in %.0f ms (%s)\n", wait_time_ns / 1e6, event_queue_ping.first->host->host);
1479
        }
241✔
1480

1481
        /* When is the next timeout event? */
1482
        if (event_queue_timeout.first) {
987✔
1483
            int64_t wait_time_timeout = event_queue_timeout.first->ev_time - current_time_ns;
621✔
1484
            if (wait_time_ns < 0 || wait_time_timeout < wait_time_ns) {
621✔
1485
                wait_time_ns = wait_time_timeout;
242✔
1486
                if (wait_time_ns < 0) {
242✔
1487
                    wait_time_ns = 0;
×
1488
                }
1489
            }
64✔
1490

1491
            dbg_printf("next timeout event in %.0f ms (%s)\n", wait_time_timeout / 1e6, event_queue_timeout.first->host->host);
1492
        }
187✔
1493

1494
        /* When is the next report due? */
1495
        if (report_interval && (loop_flag || count_flag)) {
987✔
1496
            int64_t wait_time_next_report = next_report_time - current_time_ns;
205✔
1497
            if (wait_time_next_report < wait_time_ns) {
205✔
1498
                wait_time_ns = wait_time_next_report;
69✔
1499
                if (wait_time_ns < 0) {
69✔
1500
                    wait_time_ns = 0;
×
1501
                }
1502
            }
23✔
1503

1504
            dbg_printf("next report  event in %0.f ms\n", wait_time_next_report / 1e6);
1505
        }
67✔
1506

1507
        /* if wait_time is still -1, it means that we are waiting for nothing... */
1508
        if (wait_time_ns == -1) {
987✔
1509
            break;
2✔
1510
        }
1511

1512
        /* end of loop was requested by interrupt signal handler */
1513
        if (finish_requested) {
985✔
1514
            break;
3✔
1515
        }
1516

1517
        /* Receive replies */
1518
        /* (this is what sleeps during each loop iteration) */
1519
        dbg_printf("waiting up to %.0f ms\n", wait_time_ns / 1e6);
1520
        if (wait_for_reply(wait_time_ns)) {
982✔
1521
            while (wait_for_reply(0))
862✔
1522
                ; /* process other replies in the queue */
1523
        }
155✔
1524

1525
        update_current_time();
982✔
1526

1527
        if (status_snapshot) {
982✔
1528
            status_snapshot = 0;
×
1529
            print_per_system_splits();
×
1530
        }
1531

1532
        /* Print report */
1533
        if (report_interval && (loop_flag || count_flag) && (current_time_ns >= next_report_time)) {
982✔
1534
            if (netdata_flag)
42✔
1535
                print_netdata();
3✔
1536
            else
1537
                print_per_system_splits();
39✔
1538

1539
            while (current_time_ns >= next_report_time) {
84✔
1540
                next_report_time += report_interval;
42✔
1541
            }
1542
        }
14✔
1543
    }
1544
}
179✔
1545

1546
/************************************************************
1547

1548
  Function: signal_handler
1549

1550
*************************************************************
1551

1552
  Inputs:  int signum
1553

1554
  Description:
1555

1556
  SIGQUIT signal handler - set flag and return
1557
  SIGINT signal handler - set flag and return
1558

1559
************************************************************/
1560

1561
void signal_handler(int signum)
×
1562
{
1563
    switch (signum) {
×
1564
    case SIGINT:
1565
        finish_requested = 1;
×
1566
        break;
×
1567

1568
    case SIGQUIT:
1569
        status_snapshot = 1;
×
1570
        break;
×
1571
    }
1572
}
×
1573

1574
/************************************************************
1575

1576
  Function: update_current_time
1577

1578
*************************************************************/
1579

1580
void update_current_time()
2,886✔
1581
{
1582
    clock_gettime(CLOCKID, &current_time);
2,886✔
1583
    current_time_ns = timespec_ns(&current_time);
2,886✔
1584
}
2,886✔
1585

1586
/************************************************************
1587

1588
  Function: finish
1589

1590
*************************************************************
1591

1592
  Inputs:  void (none)
1593

1594
  Description:
1595

1596
  Main program clean up and exit point
1597

1598
************************************************************/
1599

1600
void finish()
179✔
1601
{
1602
    int i;
1603
    HOST_ENTRY *h;
1604

1605
    update_current_time();
179✔
1606
    end_time = current_time_ns;
179✔
1607

1608
    /* tot up unreachables */
1609
    for (i = 0; i < num_hosts; i++) {
449✔
1610
        h = table[i];
270✔
1611

1612
        if (!h->num_recv) {
270✔
1613
            num_unreachable++;
46✔
1614

1615
            if (verbose_flag || unreachable_flag) {
46✔
1616
                printf("%s", h->host);
10✔
1617

1618
                if (verbose_flag)
10✔
1619
                    printf(" is unreachable");
7✔
1620

1621
                printf("\n");
10✔
1622
            }
2✔
1623
        }
12✔
1624
    }
80✔
1625

1626
    if (count_flag || loop_flag)
179✔
1627
        print_per_system_stats();
86✔
1628
#if defined(DEBUG) || defined(_DEBUG)
1629
    else if (print_per_system_flag)
1630
        print_per_system_stats();
1631
#endif /* DEBUG || _DEBUG */
1632

1633
    if (stats_flag)
179✔
1634
        print_global_stats();
6✔
1635

1636
    if (min_reachable) {
179✔
1637
        if ((num_hosts - num_unreachable) >= min_reachable) {
9✔
1638
            printf("Enough hosts reachable (required: %d, reachable: %d)\n", min_reachable, num_hosts - num_unreachable);
6✔
1639
            exit(0);
6✔
1640
        }
1641
        else {
1642
            printf("Not enough hosts reachable (required: %d, reachable: %d)\n", min_reachable, num_hosts - num_unreachable);
3✔
1643
            exit(1);
3✔
1644
        }
1645
    }
1646

1647
    if (num_noaddress)
170✔
1648
        exit(2);
×
1649
    else if (num_alive != num_hosts)
170✔
1650
        exit(1);
25✔
1651

1652
    exit(0);
145✔
1653
}
1654

1655
/************************************************************
1656

1657
  Function: print_per_system_stats
1658

1659
*************************************************************
1660

1661
  Inputs:  void (none)
1662

1663
  Description:
1664

1665

1666
************************************************************/
1667

1668
void print_per_system_stats(void)
86✔
1669
{
1670
    int i, j, avg, outage_ms;
1671
    HOST_ENTRY *h;
1672
    int64_t resp;
1673

1674
    if (verbose_flag || per_recv_flag)
86✔
1675
        fprintf(stderr, "\n");
45✔
1676

1677
    for (i = 0; i < num_hosts; i++) {
200✔
1678
        h = table[i];
114✔
1679
        fprintf(stderr, "%-*s :", max_hostname_len, h->host);
114✔
1680

1681
        if (report_all_rtts_flag) {
114✔
1682
            for (j = 0; j < h->num_sent; j++) {
226✔
1683
                if ((resp = h->resp_times[j]) >= 0)
190✔
1684
                    fprintf(stderr, " %s", sprint_tm(resp));
182✔
1685
                else
1686
                    fprintf(stderr, " -");
8✔
1687
            }
60✔
1688

1689
            fprintf(stderr, "\n");
36✔
1690
        }
10✔
1691
        else {
1692
            if (h->num_recv <= h->num_sent) {
78✔
1693
                fprintf(stderr, " xmt/rcv/%%loss = %d/%d/%d%%",
102✔
1694
                    h->num_sent, h->num_recv, h->num_sent > 0 ? ((h->num_sent - h->num_recv) * 100) / h->num_sent : 0);
78✔
1695

1696
                if (outage_flag) {
78✔
1697
                    /* Time outage total */
1698
                    outage_ms = (h->num_sent - h->num_recv) * perhost_interval / 1e6;
9✔
1699
                    fprintf(stderr, ", outage(ms) = %d", outage_ms);
9✔
1700
                }
3✔
1701
            }
24✔
1702
            else {
1703
                fprintf(stderr, " xmt/rcv/%%return = %d/%d/%d%%",
×
1704
                    h->num_sent, h->num_recv,
1705
                    h->num_sent > 0 ? ((h->num_recv * 100) / h->num_sent) : 0);
×
1706
            }
1707

1708
            if (h->num_recv) {
78✔
1709
                avg = h->total_time / h->num_recv;
67✔
1710
                fprintf(stderr, ", min/avg/max = %s", sprint_tm(h->min_reply));
67✔
1711
                fprintf(stderr, "/%s", sprint_tm(avg));
67✔
1712
                fprintf(stderr, "/%s", sprint_tm(h->max_reply));
67✔
1713
            }
21✔
1714

1715
            fprintf(stderr, "\n");
78✔
1716
        }
1717
    }
34✔
1718
}
86✔
1719

1720
/************************************************************
1721

1722
  Function: print_netdata
1723

1724
*************************************************************
1725

1726
  Inputs:  void (none)
1727

1728
  Description:
1729

1730

1731
************************************************************/
1732

1733
void print_netdata(void)
3✔
1734
{
1735
    static int sent_charts = 0;
1736

1737
    int i;
1738
    int64_t avg;
1739
    HOST_ENTRY *h;
1740

1741
    for (i = 0; i < num_hosts; i++) {
6✔
1742
        h = table[i];
3✔
1743

1744
        if (!sent_charts) {
3✔
1745
            printf("CHART fping.%s_packets '' 'FPing Packets' packets '%s' fping.packets line 110020 %.0f\n", h->name, h->host, report_interval / 1e9);
3✔
1746
            printf("DIMENSION xmt sent absolute 1 1\n");
3✔
1747
            printf("DIMENSION rcv received absolute 1 1\n");
3✔
1748
        }
1✔
1749

1750
        printf("BEGIN fping.%s_packets\n", h->name);
3✔
1751
        printf("SET xmt = %d\n", h->num_sent_i);
3✔
1752
        printf("SET rcv = %d\n", h->num_recv_i);
3✔
1753
        printf("END\n");
3✔
1754

1755
        if (!sent_charts) {
3✔
1756
            printf("CHART fping.%s_quality '' 'FPing Quality' percentage '%s' fping.quality area 110010 %.0f\n", h->name, h->host, report_interval / 1e9);
3✔
1757
            printf("DIMENSION returned '' absolute 1 1\n");
3✔
1758
            /* printf("DIMENSION lost '' absolute 1 1\n"); */
1759
        }
1✔
1760

1761
        printf("BEGIN fping.%s_quality\n", h->name);
3✔
1762
        /*
1763
        if( h->num_recv_i <= h->num_sent_i )
1764
            printf("SET lost = %d\n", h->num_sent_i > 0 ? ( ( h->num_sent_i - h->num_recv_i ) * 100 ) / h->num_sent_i : 0 );
1765
        else
1766
            printf("SET lost = 0\n");
1767
*/
1768

1769
        printf("SET returned = %d\n", h->num_sent_i > 0 ? ((h->num_recv_i * 100) / h->num_sent_i) : 0);
3✔
1770
        printf("END\n");
3✔
1771

1772
        if (!sent_charts) {
3✔
1773
            printf("CHART fping.%s_latency '' 'FPing Latency' ms '%s' fping.latency area 110000 %.0f\n", h->name, h->host, report_interval / 1e9);
3✔
1774
            printf("DIMENSION min minimum absolute 1 1000000\n");
3✔
1775
            printf("DIMENSION max maximum absolute 1 1000000\n");
3✔
1776
            printf("DIMENSION avg average absolute 1 1000000\n");
3✔
1777
        }
1✔
1778

1779
        printf("BEGIN fping.%s_latency\n", h->name);
3✔
1780
        if (h->num_recv_i) {
3✔
1781
            avg = h->total_time_i / h->num_recv_i;
3✔
1782
            printf("SET min = %" PRId64 "\n", h->min_reply_i);
3✔
1783
            printf("SET avg = %" PRId64 "\n", avg);
3✔
1784
            printf("SET max = %" PRId64 "\n", h->max_reply_i);
3✔
1785
        }
1✔
1786
        printf("END\n");
3✔
1787

1788
        stats_reset_interval(h);
3✔
1789
    }
1✔
1790

1791
    sent_charts = 1;
3✔
1792
}
3✔
1793

1794
/************************************************************
1795

1796
  Function: print_per_system_splits
1797

1798
*************************************************************
1799

1800
  Inputs:  void (none)
1801

1802
  Description:
1803

1804

1805
************************************************************/
1806

1807
void print_per_system_splits(void)
39✔
1808
{
1809
    int i, avg, outage_ms_i;
1810
    HOST_ENTRY *h;
1811
    struct tm *curr_tm;
1812

1813
    if (verbose_flag || per_recv_flag)
39✔
1814
        fprintf(stderr, "\n");
×
1815

1816
    update_current_time();
39✔
1817
    curr_tm = localtime((time_t *)&current_time.tv_sec);
39✔
1818
    fprintf(stderr, "[%2.2d:%2.2d:%2.2d]\n", curr_tm->tm_hour,
52✔
1819
        curr_tm->tm_min, curr_tm->tm_sec);
13✔
1820

1821
    for (i = 0; i < num_hosts; i++) {
78✔
1822
        h = table[i];
39✔
1823
        fprintf(stderr, "%-*s :", max_hostname_len, h->host);
39✔
1824

1825
        if (h->num_recv_i <= h->num_sent_i) {
39✔
1826
            fprintf(stderr, " xmt/rcv/%%loss = %d/%d/%d%%",
52✔
1827
                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);
39✔
1828

1829
            if (outage_flag) {
39✔
1830
                /* Time outage  */
1831
                outage_ms_i = (h->num_sent_i - h->num_recv_i) * perhost_interval / 1e6;
12✔
1832
                fprintf(stderr, ", outage(ms) = %d", outage_ms_i);
12✔
1833
            }
4✔
1834
        }
13✔
1835
        else {
1836
            fprintf(stderr, " xmt/rcv/%%return = %d/%d/%d%%",
×
1837
                h->num_sent_i, h->num_recv_i, h->num_sent_i > 0 ? ((h->num_recv_i * 100) / h->num_sent_i) : 0);
×
1838
        }
1839

1840
        if (h->num_recv_i) {
39✔
1841
            avg = h->total_time_i / h->num_recv_i;
27✔
1842
            fprintf(stderr, ", min/avg/max = %s", sprint_tm(h->min_reply_i));
27✔
1843
            fprintf(stderr, "/%s", sprint_tm(avg));
27✔
1844
            fprintf(stderr, "/%s", sprint_tm(h->max_reply_i));
27✔
1845
        }
9✔
1846

1847
        fprintf(stderr, "\n");
39✔
1848
        if (!cumulative_stats_flag) {
39✔
1849
            stats_reset_interval(h);
27✔
1850
        }
9✔
1851
    }
13✔
1852
}
39✔
1853

1854
/************************************************************
1855

1856
  Function: print_global_stats
1857

1858
*************************************************************
1859

1860
  Inputs:  void (none)
1861

1862
  Description:
1863

1864

1865
************************************************************/
1866

1867
void print_global_stats(void)
6✔
1868
{
1869
    fprintf(stderr, "\n");
6✔
1870
    fprintf(stderr, " %7d targets\n", num_hosts);
6✔
1871
    fprintf(stderr, " %7d alive\n", num_alive);
6✔
1872
    fprintf(stderr, " %7d unreachable\n", num_unreachable);
6✔
1873
    fprintf(stderr, " %7d unknown addresses\n", num_noaddress);
6✔
1874
    fprintf(stderr, "\n");
6✔
1875
    fprintf(stderr, " %7d timeouts (waiting for response)\n", num_timeout);
6✔
1876
    fprintf(stderr, " %7d ICMP Echos sent\n", num_pingsent);
6✔
1877
    fprintf(stderr, " %7d ICMP Echo Replies received\n", num_pingreceived);
6✔
1878
    fprintf(stderr, " %7d other ICMP received\n", num_othericmprcvd);
6✔
1879
    fprintf(stderr, "\n");
6✔
1880

1881
    if (total_replies == 0) {
6✔
1882
        min_reply = 0;
3✔
1883
        max_reply = 0;
3✔
1884
        total_replies = 1;
3✔
1885
        sum_replies = 0;
3✔
1886
    }
1✔
1887

1888
    fprintf(stderr, " %s ms (min round trip time)\n", sprint_tm(min_reply));
6✔
1889
    fprintf(stderr, " %s ms (avg round trip time)\n",
8✔
1890
        sprint_tm(sum_replies / total_replies));
2✔
1891
    fprintf(stderr, " %s ms (max round trip time)\n", sprint_tm(max_reply));
6✔
1892
    fprintf(stderr, " %12.3f sec (elapsed real time)\n",
8✔
1893
        (end_time - start_time) / 1e9);
6✔
1894
    fprintf(stderr, "\n");
6✔
1895
}
6✔
1896

1897
/************************************************************
1898

1899
  Function: send_ping
1900

1901
*************************************************************
1902

1903
  Inputs:  int s, HOST_ENTRY *h
1904

1905
  Description:
1906

1907
  Compose and transmit an ICMP_ECHO REQUEST packet.  The IP packet
1908
  will be added on by the kernel.  The ID field is our UNIX process ID,
1909
  and the sequence number is an index into an array of outstanding
1910
  ping requests. The sequence number will later be used to quickly
1911
  figure out who the ping reply came from.
1912

1913
************************************************************/
1914

1915
int send_ping(HOST_ENTRY *h, int index)
584✔
1916
{
1917
    int n;
1918
    int myseq;
1919
    int ret = 1;
584✔
1920

1921
    update_current_time();
584✔
1922
    h->last_send_time = current_time_ns;
584✔
1923
    myseq = seqmap_add(h->i, index, current_time_ns);
584✔
1924

1925
    dbg_printf("%s [%d]: send ping\n", h->host, index);
1926

1927
    if (h->saddr.ss_family == AF_INET && socket4 >= 0) {
584✔
1928
        n = socket_sendto_ping_ipv4(socket4, (struct sockaddr *)&h->saddr, h->saddr_len, myseq, ident4);
513✔
1929
    }
163✔
1930
#ifdef IPV6
1931
    else if (h->saddr.ss_family == AF_INET6 && socket6 >= 0) {
71✔
1932
        n = socket_sendto_ping_ipv6(socket6, (struct sockaddr *)&h->saddr, h->saddr_len, myseq, ident6);
71✔
1933
    }
15✔
1934
#endif
1935
    else {
1936
        return 0;
×
1937
    }
1938

1939
    /* error sending? */
1940
    if (
406✔
1941
        (n < 0)
178✔
1942
#if defined(EHOSTDOWN)
1943
        && errno != EHOSTDOWN
184✔
1944
#endif
1945
    ) {
1946
        if (verbose_flag) {
6✔
1947
            print_warning("%s: error while sending ping: %s\n", h->host, strerror(errno));
×
1948
        }
1949
        else {
1950
            dbg_printf("%s: error while sending ping: %s\n", h->host, strerror(errno));
1951
        }
1952

1953
        h->num_sent++;
6✔
1954
        h->num_sent_i++;
6✔
1955
        if (!loop_flag)
6✔
1956
            h->resp_times[index] = RESP_ERROR;
6✔
1957

1958
        ret = 0;
6✔
1959
    }
1960
    else {
1961
        /* schedule timeout */
1962
        host_add_timeout_event(h, index, current_time_ns + h->timeout);
578✔
1963

1964
        /* mark this trial as outstanding */
1965
        if (!loop_flag) {
578✔
1966
            h->resp_times[index] = RESP_WAITING;
578✔
1967
        }
178✔
1968
    }
1969

1970
    num_pingsent++;
584✔
1971
    last_send_time = h->last_send_time;
584✔
1972

1973
    return (ret);
584✔
1974
}
178✔
1975

1976
int socket_can_read(struct timeval *timeout)
1,844✔
1977
{
1978
    int nfound;
1979
    fd_set readset;
1980
    int socketmax;
1981

1982
#ifndef IPV6
1983
    socketmax = socket4;
1984
#else
1985
    socketmax = socket4 > socket6 ? socket4 : socket6;
1,844✔
1986
#endif
1987

1988
select_again:
1,372✔
1989
    FD_ZERO(&readset);
12,820✔
1990
    if (socket4 >= 0)
1,844✔
1991
        FD_SET(socket4, &readset);
1,844✔
1992
#ifdef IPV6
1993
    if (socket6 >= 0)
1,844✔
1994
        FD_SET(socket6, &readset);
1,844✔
1995
#endif
1996

1997
    nfound = select(socketmax + 1, &readset, NULL, NULL, timeout);
1,844✔
1998
    if (nfound < 0) {
1,844✔
1999
        if (errno == EINTR) {
×
2000
            /* interrupted system call: redo the select */
2001
            goto select_again;
×
2002
        }
2003
        else {
2004
            perror("select");
×
2005
        }
2006
    }
2007

2008
    if (nfound > 0) {
1,844✔
2009
        if (socket4 >= 0 && FD_ISSET(socket4, &readset)) {
862✔
2010
            return socket4;
720✔
2011
        }
2012
#ifdef IPV6
2013
        if (socket6 >= 0 && FD_ISSET(socket6, &readset)) {
142✔
2014
            return socket6;
142✔
2015
        }
2016
#endif
2017
    }
2018

2019
    return -1;
982✔
2020
}
472✔
2021

2022
int receive_packet(int64_t wait_time,
1,844✔
2023
    int64_t *reply_timestamp,
2024
    struct sockaddr *reply_src_addr,
2025
    size_t reply_src_addr_len,
2026
    char *reply_buf,
2027
    size_t reply_buf_len)
2028
{
2029
    struct timeval to;
2030
    int s = 0;
1,844✔
2031
    int recv_len;
2032
    static unsigned char msg_control[40];
2033
    struct iovec msg_iov = {
2,788✔
2034
        reply_buf,
472✔
2035
        reply_buf_len
472✔
2036
    };
2037
    struct msghdr recv_msghdr = {0};
1,844✔
2038
    recv_msghdr.msg_name = reply_src_addr;
1,844✔
2039
    recv_msghdr.msg_namelen = reply_src_addr_len;
1,844✔
2040
    recv_msghdr.msg_iov = &msg_iov;
1,844✔
2041
    recv_msghdr.msg_iovlen = 1;
1,844✔
2042
    recv_msghdr.msg_control = &msg_control;
1,844✔
2043
    recv_msghdr.msg_controllen = sizeof(msg_control);
1,844✔
2044
#if HAVE_SO_TIMESTAMPNS
2045
    struct cmsghdr *cmsg;
2046
#endif
2047

2048
    /* Wait for a socket to become ready */
2049
    if (wait_time) {
1,844✔
2050
        to.tv_sec = wait_time / UINT64_C(1000000000);
982✔
2051
        to.tv_usec = (wait_time % UINT64_C(1000000000)) / 1000 + 1;
982✔
2052
    }
302✔
2053
    else {
2054
        to.tv_sec = 0;
862✔
2055
        to.tv_usec = 0;
862✔
2056
    }
2057
    s = socket_can_read(&to);
1,844✔
2058
    if (s == -1) {
1,844✔
2059
        return 0; /* timeout */
982✔
2060
    }
2061

2062
    recv_len = recvmsg(s, &recv_msghdr, MSG_TRUNC);
862✔
2063
    if (recv_len <= 0) {
862✔
2064
        return 0;
×
2065
    }
2066

2067
#if HAVE_SO_TIMESTAMPNS
2068
    /* ancilliary data */
2069
    {
2070
        struct timespec reply_timestamp_ts;
2071
        for (cmsg = CMSG_FIRSTHDR(&recv_msghdr);
1,038✔
2072
             cmsg != NULL;
692✔
2073
             cmsg = CMSG_NXTHDR(&recv_msghdr, cmsg)) {
692✔
2074
            if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPNS) {
692✔
2075
                memcpy(&reply_timestamp_ts, CMSG_DATA(cmsg), sizeof(reply_timestamp_ts));
692✔
2076
                *reply_timestamp = timespec_ns(&reply_timestamp_ts);
692✔
2077
            }
2078
        }
2079
    }
2080
#endif
2081

2082
#if defined(DEBUG) || defined(_DEBUG)
2083
    if (randomly_lose_flag) {
2084
        if ((random() & 0x07) <= lose_factor)
2085
            return 0;
2086
    }
2087
#endif
2088

2089
    return recv_len;
862✔
2090
}
472✔
2091

2092
/* stats_add: update host statistics for a single packet that was received (or timed out)
2093
 * h: host entry to update
2094
 * index: if in count mode: index number for this ping packet (-1 otherwise)
2095
 * success: 1 if response received, 0 otherwise
2096
 * latency: response time, in ns
2097
 */
2098
void stats_add(HOST_ENTRY *h, int index, int success, int64_t latency)
578✔
2099
{
2100
    /* sent count - we update only on receive/timeout, so that we don't get
2101
     * weird loss percentage, just because a packet was note recived yet.
2102
     */
2103
    h->num_sent++;
578✔
2104
    h->num_sent_i++;
578✔
2105

2106
    if (!success) {
578✔
2107
        if (!loop_flag && index >= 0) {
89✔
2108
            h->resp_times[index] = RESP_TIMEOUT;
89✔
2109
        }
23✔
2110
        num_timeout++;
89✔
2111
        return;
89✔
2112
    }
2113

2114
    /* received count */
2115
    h->num_recv++;
489✔
2116
    h->num_recv_i++;
489✔
2117

2118
    /* maximum */
2119
    if (!h->max_reply || latency > h->max_reply) {
489✔
2120
        h->max_reply = latency;
321✔
2121
    }
96✔
2122
    if (!h->max_reply_i || latency > h->max_reply_i) {
489✔
2123
        h->max_reply_i = latency;
339✔
2124
    }
104✔
2125

2126
    /* minimum */
2127
    if (!h->min_reply || latency < h->min_reply) {
489✔
2128
        h->min_reply = latency;
264✔
2129
    }
82✔
2130
    if (!h->min_reply_i || latency < h->min_reply_i) {
489✔
2131
        h->min_reply_i = latency;
289✔
2132
    }
89✔
2133

2134
    /* total time (for average) */
2135
    h->total_time += latency;
489✔
2136
    h->total_time_i += latency;
489✔
2137

2138
    /* response time per-packet (count mode) */
2139
    if (!loop_flag && index >= 0) {
489✔
2140
        h->resp_times[index] = latency;
489✔
2141
    }
155✔
2142
}
178✔
2143

2144
/* stats_reset_interval: reset interval statistics
2145
 * h: host entry to update
2146
 */
2147
void stats_reset_interval(HOST_ENTRY *h)
30✔
2148
{
2149
    h->num_sent_i = 0;
30✔
2150
    h->num_recv_i = 0;
30✔
2151
    h->max_reply_i = 0;
30✔
2152
    h->min_reply_i = 0;
30✔
2153
    h->total_time_i = 0;
30✔
2154
}
30✔
2155

2156
int decode_icmp_ipv4(
720✔
2157
    struct sockaddr *response_addr,
2158
    size_t response_addr_len,
2159
    char *reply_buf,
2160
    size_t reply_buf_len,
2161
    unsigned short *id,
2162
    unsigned short *seq)
2163
{
2164
    struct icmp *icp;
2165
    int hlen = 0;
720✔
2166

2167
    if (!using_sock_dgram4) {
720✔
2168
        struct ip *ip = (struct ip *)reply_buf;
720✔
2169

2170
#if defined(__alpha__) && __STDC__ && !defined(__GLIBC__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
2171
        /* The alpha headers are decidedly broken.
2172
         * Using an ANSI compiler, it provides ip_vhl instead of ip_hl and
2173
         * ip_v.  So, to get ip_hl, we mask off the bottom four bits.
2174
         */
2175
        hlen = (ip->ip_vhl & 0x0F) << 2;
2176
#else
2177
        hlen = ip->ip_hl << 2;
720✔
2178
#endif
2179
    }
140✔
2180

2181
    if (reply_buf_len < hlen + ICMP_MINLEN) {
720✔
2182
        /* too short */
2183
        if (verbose_flag) {
×
2184
            char buf[INET6_ADDRSTRLEN];
2185
            getnameinfo(response_addr, response_addr_len, buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
×
2186
            printf("received packet too short for ICMP (%d bytes from %s)\n", (int)reply_buf_len, buf);
×
2187
        }
2188
        return -1;
×
2189
    }
2190

2191
    icp = (struct icmp *)(reply_buf + hlen);
720✔
2192

2193
    if (icp->icmp_type != ICMP_ECHOREPLY) {
720✔
2194
        /* Handle other ICMP packets */
2195
        struct icmp *sent_icmp;
2196
        SEQMAP_VALUE *seqmap_value;
2197
        char addr_ascii[INET6_ADDRSTRLEN];
2198
        HOST_ENTRY *h;
2199

2200
        /* reply icmp packet (hlen + ICMP_MINLEN) followed by "sent packet" (ip + icmp headers) */
2201
        if (reply_buf_len < hlen + ICMP_MINLEN + sizeof(struct ip) + ICMP_MINLEN) {
290✔
2202
            /* discard ICMP message if we can't tell that it was caused by us (i.e. if the "sent packet" is not included). */
2203
            return -1;
×
2204
        }
2205

2206
        sent_icmp = (struct icmp *)(reply_buf + hlen + ICMP_MINLEN + sizeof(struct ip));
290✔
2207

2208
        if (sent_icmp->icmp_type != ICMP_ECHO || sent_icmp->icmp_id != ident4) {
290✔
2209
            /* not caused by us */
2210
            return -1;
290✔
2211
        }
2212

2213
        seqmap_value = seqmap_fetch(ntohs(sent_icmp->icmp_seq), current_time_ns);
×
2214
        if (seqmap_value == NULL) {
×
2215
            return -1;
×
2216
        }
2217

2218
        getnameinfo(response_addr, response_addr_len, addr_ascii, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
×
2219

2220
        switch (icp->icmp_type) {
×
2221
        case ICMP_UNREACH:
2222
            h = table[seqmap_value->host_nr];
×
2223
            if (icp->icmp_code > ICMP_UNREACH_MAXTYPE) {
×
2224
                print_warning("ICMP Unreachable (Invalid Code) from %s for ICMP Echo sent to %s",
×
2225
                    addr_ascii, h->host);
2226
            }
2227
            else {
2228
                print_warning("%s from %s for ICMP Echo sent to %s",
×
2229
                    icmp_unreach_str[icp->icmp_code], addr_ascii, h->host);
×
2230
            }
2231

2232
            print_warning("\n");
×
2233
            num_othericmprcvd++;
×
2234
            break;
×
2235

2236
        case ICMP_SOURCEQUENCH:
2237
        case ICMP_REDIRECT:
2238
        case ICMP_TIMXCEED:
2239
        case ICMP_PARAMPROB:
2240
            h = table[seqmap_value->host_nr];
×
2241
            if (icp->icmp_type <= ICMP_TYPE_STR_MAX) {
×
2242
                print_warning("%s from %s for ICMP Echo sent to %s",
×
2243
                    icmp_type_str[icp->icmp_type], addr_ascii, h->host);
×
2244
            }
2245
            else {
2246
                print_warning("ICMP %d from %s for ICMP Echo sent to %s",
×
2247
                    icp->icmp_type, addr_ascii, h->host);
×
2248
            }
2249
            print_warning("\n");
×
2250
            num_othericmprcvd++;
×
2251
            break;
×
2252
        }
2253

2254
        return -1;
×
2255
    }
2256

2257
    *id = icp->icmp_id;
430✔
2258
    *seq = ntohs(icp->icmp_seq);
430✔
2259

2260
    return hlen;
430✔
2261
}
140✔
2262

2263
#ifdef IPV6
2264
int decode_icmp_ipv6(
142✔
2265
    struct sockaddr *response_addr,
2266
    size_t response_addr_len,
2267
    char *reply_buf,
2268
    size_t reply_buf_len,
2269
    unsigned short *id,
2270
    unsigned short *seq)
2271
{
2272
    struct icmp6_hdr *icp;
2273

2274
    if (reply_buf_len < sizeof(struct icmp6_hdr)) {
142✔
2275
        if (verbose_flag) {
×
2276
            char buf[INET6_ADDRSTRLEN];
2277
            getnameinfo(response_addr, response_addr_len, buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
×
2278
            printf("received packet too short for ICMP (%d bytes from %s)\n", (int)reply_buf_len, buf);
×
2279
        }
2280
        return 0; /* too short */
×
2281
    }
2282

2283
    icp = (struct icmp6_hdr *)reply_buf;
142✔
2284

2285
    if (icp->icmp6_type != ICMP6_ECHO_REPLY) {
142✔
2286
        /* Handle other ICMP packets */
2287
        struct icmp6_hdr *sent_icmp;
2288
        SEQMAP_VALUE *seqmap_value;
2289
        char addr_ascii[INET6_ADDRSTRLEN];
2290
        HOST_ENTRY *h;
2291

2292
        /* reply icmp packet (ICMP_MINLEN) followed by "sent packet" (ip + icmp headers) */
2293
        if (reply_buf_len < ICMP_MINLEN + sizeof(struct ip) + ICMP_MINLEN) {
71✔
2294
            /* discard ICMP message if we can't tell that it was caused by us (i.e. if the "sent packet" is not included). */
2295
            return 0;
×
2296
        }
2297

2298
        sent_icmp = (struct icmp6_hdr *)(reply_buf + sizeof(struct icmp6_hdr) + sizeof(struct ip));
71✔
2299

2300
        if (sent_icmp->icmp6_type != ICMP_ECHO || sent_icmp->icmp6_id != ident6) {
71✔
2301
            /* not caused by us */
2302
            return 0;
71✔
2303
        }
2304

2305
        seqmap_value = seqmap_fetch(ntohs(sent_icmp->icmp6_seq), current_time_ns);
×
2306
        if (seqmap_value == NULL) {
×
2307
            return 0;
×
2308
        }
2309

2310
        getnameinfo(response_addr, response_addr_len, addr_ascii, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
×
2311

2312
        switch (icp->icmp6_type) {
×
2313
        case ICMP_UNREACH:
2314
            h = table[seqmap_value->host_nr];
×
2315
            if (icp->icmp6_code > ICMP_UNREACH_MAXTYPE) {
×
2316
                print_warning("ICMP Unreachable (Invalid Code) from %s for ICMP Echo sent to %s",
×
2317
                    addr_ascii, h->host);
2318
            }
2319
            else {
2320
                print_warning("%s from %s for ICMP Echo sent to %s",
×
2321
                    icmp_unreach_str[icp->icmp6_code], addr_ascii, h->host);
×
2322
            }
2323

2324
            print_warning("\n");
×
2325
            num_othericmprcvd++;
×
2326
            break;
×
2327

2328
        case ICMP_SOURCEQUENCH:
2329
        case ICMP_REDIRECT:
2330
        case ICMP_TIMXCEED:
2331
        case ICMP_PARAMPROB:
2332
            h = table[seqmap_value->host_nr];
×
2333
            if (icp->icmp6_type <= ICMP_TYPE_STR_MAX) {
×
2334
                print_warning("%s from %s for ICMP Echo sent to %s",
×
2335
                    icmp_type_str[icp->icmp6_type], addr_ascii, h->host);
×
2336
            }
2337
            else {
2338
                print_warning("ICMP %d from %s for ICMP Echo sent to %s",
×
2339
                    icp->icmp6_type, addr_ascii, h->host);
×
2340
            }
2341
            print_warning("\n");
×
2342
            num_othericmprcvd++;
×
2343
            break;
×
2344
        }
2345

2346
        return 0;
×
2347
    }
2348

2349
    *id = icp->icmp6_id;
71✔
2350
    *seq = ntohs(icp->icmp6_seq);
71✔
2351

2352
    return 1;
71✔
2353
}
30✔
2354
#endif
2355

2356
int wait_for_reply(int64_t wait_time)
1,844✔
2357
{
2358
    int result;
2359
    static char buffer[RECV_BUFSIZE];
2360
    struct sockaddr_storage response_addr;
2361
    int n, avg;
2362
    HOST_ENTRY *h;
2363
    int64_t this_reply;
2364
    int this_count;
2365
    int64_t recv_time = 0;
1,844✔
2366
    SEQMAP_VALUE *seqmap_value;
2367
    unsigned short id;
2368
    unsigned short seq;
2369

2370
    /* Receive packet */
2371
    result = receive_packet(wait_time, /* max. wait time, in ns */
1,844✔
2372
        &recv_time, /* reply_timestamp */
2373
        (struct sockaddr *)&response_addr, /* reply_src_addr */
2374
        sizeof(response_addr), /* reply_src_addr_len */
2375
        buffer, /* reply_buf */
2376
        sizeof(buffer) /* reply_buf_len */
2377
    );
2378

2379
    if (result <= 0) {
1,844✔
2380
        return 0;
982✔
2381
    }
2382

2383
    update_current_time();
862✔
2384
    if (recv_time == 0)
862✔
2385
        recv_time = current_time_ns;
170✔
2386

2387
    /* Process ICMP packet and retrieve id/seq */
2388
    if (response_addr.ss_family == AF_INET) {
862✔
2389
        int ip_hlen = decode_icmp_ipv4(
720✔
2390
            (struct sockaddr *)&response_addr,
2391
            sizeof(response_addr),
2392
            buffer,
2393
            sizeof(buffer),
2394
            &id,
2395
            &seq);
2396
        if (ip_hlen < 0) {
720✔
2397
            return 1;
290✔
2398
        }
2399
        if (id != ident4) {
430✔
2400
            return 1; /* packet received, but not the one we are looking for! */
×
2401
        }
2402
        if (!using_sock_dgram4) {
430✔
2403
            /* do not include IP header in returned size, to be consistent with ping(8) and also
2404
             * with fping with IPv6 hosts */
2405
            result -= ip_hlen;
430✔
2406
        }
140✔
2407
    }
140✔
2408
#ifdef IPV6
2409
    else if (response_addr.ss_family == AF_INET6) {
142✔
2410
        if (!decode_icmp_ipv6(
142✔
2411
                (struct sockaddr *)&response_addr,
2412
                sizeof(response_addr),
2413
                buffer,
2414
                sizeof(buffer),
2415
                &id,
2416
                &seq)) {
2417
            return 1;
71✔
2418
        }
2419
        if (id != ident6) {
71✔
2420
            return 1; /* packet received, but not the one we are looking for! */
×
2421
        }
2422
    }
15✔
2423
#endif
2424
    else {
2425
        return 1;
×
2426
    }
2427

2428
    seqmap_value = seqmap_fetch(seq, current_time_ns);
501✔
2429
    if (seqmap_value == NULL) {
501✔
2430
        return 1;
×
2431
    }
2432

2433
    /* find corresponding host_entry */
2434
    n = seqmap_value->host_nr;
501✔
2435
    h = table[n];
501✔
2436
    this_count = seqmap_value->ping_count;
501✔
2437
    this_reply = recv_time - seqmap_value->ping_ts;
501✔
2438

2439
    /* update stats that include invalid replies */
2440
    h->num_recv_total++;
501✔
2441
    num_pingreceived++;
501✔
2442

2443
    dbg_printf("received [%d] from %s\n", this_count, h->host);
2444

2445
    /* optionally require reply source equal to target address */
2446
    if (check_source_flag && addr_cmp((struct sockaddr *)&response_addr, (struct sockaddr *)&h->saddr)) {
501✔
2447
        dbg_printf("discarding reply from wrong source address\n");
2448
        return 1;
12✔
2449
    }
2450

2451
    /* discard duplicates */
2452
    if (!loop_flag && h->resp_times[this_count] >= 0) {
489✔
2453
        if (!per_recv_flag) {
×
2454
            fprintf(stderr, "%s : duplicate for [%d], %d bytes, %s ms",
×
2455
                h->host, this_count, result, sprint_tm(this_reply));
2456

2457
            if (addr_cmp((struct sockaddr *)&response_addr, (struct sockaddr *)&h->saddr)) {
×
2458
                char buf[INET6_ADDRSTRLEN];
2459
                getnameinfo((struct sockaddr *)&response_addr, sizeof(response_addr), buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
×
2460
                fprintf(stderr, " [<- %s]", buf);
×
2461
            }
2462
            fprintf(stderr, "\n");
×
2463
        }
2464
        return 1;
×
2465
    }
2466

2467
    /* discard reply if delay is larger than timeout
2468
     * (see also: github #32) */
2469
    if (this_reply > h->timeout) {
489✔
2470
        return 1;
×
2471
    }
2472

2473
    /* update stats */
2474
    stats_add(h, this_count, 1, this_reply);
489✔
2475
    // TODO: move to stats_add?
2476
    if (!max_reply || this_reply > max_reply)
489✔
2477
        max_reply = this_reply;
272✔
2478
    if (!min_reply || this_reply < min_reply)
489✔
2479
        min_reply = this_reply;
205✔
2480
    sum_replies += this_reply;
489✔
2481
    total_replies++;
489✔
2482

2483
    /* initialize timeout to initial timeout (without backoff) */
2484
    h->timeout = timeout;
489✔
2485

2486
    /* remove timeout event */
2487
    struct event *timeout_event = host_get_timeout_event(h, this_count);
489✔
2488
    if (timeout_event) {
489✔
2489
        ev_remove(&event_queue_timeout, timeout_event);
489✔
2490
    }
155✔
2491

2492
    /* print "is alive" */
2493
    if (h->num_recv == 1) {
489✔
2494
        num_alive++;
224✔
2495
        if (fast_reachable && num_alive >= min_reachable)
224✔
2496
                finish_requested = 1;
3✔
2497

2498
        if (verbose_flag || alive_flag) {
224✔
2499
            printf("%s", h->host);
113✔
2500

2501
            if (verbose_flag)
113✔
2502
                printf(" is alive");
107✔
2503

2504
            if (elapsed_flag)
113✔
2505
                printf(" (%s ms)", sprint_tm(this_reply));
3✔
2506

2507
            if (addr_cmp((struct sockaddr *)&response_addr, (struct sockaddr *)&h->saddr)) {
113✔
2508
                char buf[INET6_ADDRSTRLEN];
2509
                getnameinfo((struct sockaddr *)&response_addr, sizeof(response_addr), buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
2✔
2510
                fprintf(stderr, " [<- %s]", buf);
2✔
2511
            }
2512

2513
            printf("\n");
113✔
2514
        }
33✔
2515
    }
68✔
2516

2517
    /* print received ping (unless --quiet) */
2518
    if (per_recv_flag) {
489✔
2519
        if (timestamp_flag) {
115✔
2520
            print_timestamp_format(recv_time, timestamp_format_flag);
30✔
2521
        }
10✔
2522
        avg = h->total_time / h->num_recv;
115✔
2523
        printf("%-*s : [%d], %d bytes, %s ms",
115✔
2524
            max_hostname_len, h->host, this_count, result, sprint_tm(this_reply));
37✔
2525
        printf(" (%s avg, ", sprint_tm(avg));
115✔
2526

2527
        if (h->num_recv <= h->num_sent) {
115✔
2528
            printf("%d%% loss)",
115✔
2529
                ((h->num_sent - h->num_recv) * 100) / h->num_sent);
115✔
2530
        }
37✔
2531
        else {
2532
            printf("%d%% return)",
×
2533
                (h->num_recv_total * 100) / h->num_sent);
×
2534
        }
2535

2536
        if (addr_cmp((struct sockaddr *)&response_addr, (struct sockaddr *)&h->saddr)) {
115✔
2537
            char buf[INET6_ADDRSTRLEN];
2538
            getnameinfo((struct sockaddr *)&response_addr, sizeof(response_addr), buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
×
2539
            fprintf(stderr, " [<- %s]", buf);
×
2540
        }
2541

2542
        printf("\n");
115✔
2543
    }
37✔
2544

2545
    return 1;
489✔
2546
}
472✔
2547

2548
/************************************************************
2549

2550
  Function: add_name
2551

2552
*************************************************************
2553

2554
  Inputs:  char* name
2555

2556
  Description:
2557

2558
  process input name for addition to target list
2559
  name can turn into multiple targets via multiple interfaces (-m)
2560
  or via NIS groups
2561

2562
************************************************************/
2563

2564
void add_name(char *name)
284✔
2565
{
2566
    struct addrinfo *res0, *res, hints;
2567
    int ret_ga;
2568
    char *printname;
2569
    char namebuf[256];
2570
    char addrbuf[256];
2571

2572
    /* getaddrinfo */
2573
    memset(&hints, 0, sizeof(struct addrinfo));
284✔
2574
    hints.ai_flags = AI_UNUSABLE;
284✔
2575
    hints.ai_socktype = SOCK_RAW;
284✔
2576
    hints.ai_family = hints_ai_family;
284✔
2577
    if (hints_ai_family == AF_INET) {
284✔
2578
        hints.ai_protocol = IPPROTO_ICMP;
21✔
2579
    }
7✔
2580
#ifdef IPV6
2581
    else if (hints_ai_family == AF_INET6) {
263✔
2582
        hints.ai_protocol = IPPROTO_ICMPV6;
5✔
2583
    }
1✔
2584
#endif
2585
    else {
2586
        hints.ai_socktype = SOCK_STREAM;
258✔
2587
        hints.ai_protocol = 0;
258✔
2588
    }
2589
    ret_ga = getaddrinfo(name, NULL, &hints, &res0);
284✔
2590
    if (ret_ga) {
284✔
2591
        if (!quiet_flag)
9✔
2592
            print_warning("%s: %s\n", name, gai_strerror(ret_ga));
9✔
2593
        num_noaddress++;
9✔
2594
        return;
9✔
2595
    }
2596

2597
    /* NOTE: we could/should loop with res on all addresses like this:
2598
     * for (res = res0; res; res = res->ai_next) {
2599
     * We don't do it yet, however, because is is an incompatible change
2600
     * (need to implement a separate option for this)
2601
     */
2602
    for (res = res0; res; res = res->ai_next) {
275✔
2603
        /* name_flag: addr -> name lookup requested) */
2604
        if (name_flag || rdns_flag) {
275✔
2605
            int do_rdns = rdns_flag ? 1 : 0;
×
2606
            if (name_flag) {
×
2607
                /* Was it a numerical address? Only then do a rdns-query */
2608
                struct addrinfo *nres;
2609
                hints.ai_flags = AI_NUMERICHOST;
×
2610
                if (getaddrinfo(name, NULL, &hints, &nres) == 0) {
×
2611
                    do_rdns = 1;
×
2612
                    freeaddrinfo(nres);
×
2613
                }
2614
            }
2615

2616
            if (do_rdns && getnameinfo(res->ai_addr, res->ai_addrlen, namebuf, sizeof(namebuf) / sizeof(char), NULL, 0, 0) == 0) {
×
2617
                printname = namebuf;
×
2618
            }
2619
            else {
2620
                printname = name;
×
2621
            }
2622
        }
2623
        else {
2624
            printname = name;
275✔
2625
        }
2626

2627
        /* addr_flag: name -> addr lookup requested */
2628
        if (addr_flag) {
275✔
2629
            int ret;
2630
            ret = getnameinfo(res->ai_addr, res->ai_addrlen, addrbuf,
3✔
2631
                sizeof(addrbuf) / sizeof(char), NULL, 0, NI_NUMERICHOST);
2632
            if (ret) {
3✔
2633
                if (!quiet_flag) {
×
2634
                    print_warning("%s: can't forward-lookup address (%s)\n", name, gai_strerror(ret));
×
2635
                }
2636
                continue;
×
2637
            }
2638

2639
            if (name_flag || rdns_flag) {
3✔
2640
                char nameaddrbuf[512 + 3];
2641
                snprintf(nameaddrbuf, sizeof(nameaddrbuf) / sizeof(char), "%s (%s)", printname, addrbuf);
×
2642
                add_addr(name, nameaddrbuf, res->ai_addr, res->ai_addrlen);
×
2643
            }
2644
            else {
2645
                add_addr(name, addrbuf, res->ai_addr, res->ai_addrlen);
3✔
2646
            }
2647
        }
1✔
2648
        else {
2649
            add_addr(name, printname, res->ai_addr, res->ai_addrlen);
272✔
2650
        }
2651

2652
        if (!multif_flag) {
275✔
2653
            break;
275✔
2654
        }
2655
    }
2656

2657
    freeaddrinfo(res0);
275✔
2658
}
84✔
2659

2660
/************************************************************
2661

2662
  Function: add_addr
2663

2664
*************************************************************
2665

2666
  Description:
2667

2668
  add single address to list of hosts to be pinged
2669

2670
************************************************************/
2671

2672
void add_addr(char *name, char *host, struct sockaddr *ipaddr, socklen_t ipaddr_len)
275✔
2673
{
2674
    HOST_ENTRY *p;
2675
    int n;
2676
    int64_t *i;
2677

2678
    p = (HOST_ENTRY *)calloc(1, sizeof(HOST_ENTRY));
275✔
2679
    if (!p)
275✔
2680
        crash_and_burn("can't allocate HOST_ENTRY");
×
2681

2682
    p->name = strdup(name);
275✔
2683
    p->host = strdup(host);
275✔
2684
    memcpy(&p->saddr, ipaddr, ipaddr_len);
275✔
2685
    p->saddr_len = ipaddr_len;
275✔
2686
    p->timeout = timeout;
275✔
2687
    p->min_reply = 0;
275✔
2688

2689
    if (netdata_flag) {
275✔
2690
        char *s = p->name;
3✔
2691
        while (*s) {
30✔
2692
            if (!isalnum(*s))
27✔
2693
                *s = '_';
9✔
2694
            s++;
27✔
2695
        }
2696
    }
1✔
2697

2698
    if (strlen(p->host) > max_hostname_len)
275✔
2699
        max_hostname_len = strlen(p->host);
193✔
2700

2701
    /* array for response time results */
2702
    if (!loop_flag) {
275✔
2703
        i = (int64_t *)malloc(trials * sizeof(int64_t));
275✔
2704
        if (!i)
275✔
2705
            crash_and_burn("can't allocate resp_times array");
×
2706

2707
        for (n = 1; n < trials; n++)
1,187✔
2708
            i[n] = RESP_UNUSED;
912✔
2709

2710
        p->resp_times = i;
275✔
2711
    }
81✔
2712

2713
    /* allocate event storage */
2714
    p->event_storage_ping = (struct event *)calloc(event_storage_count, sizeof(struct event));
275✔
2715
    p->event_storage_timeout = (struct event *)calloc(event_storage_count, sizeof(struct event));
275✔
2716

2717
    /* schedule first ping */
2718
    host_add_ping_event(p, 0, current_time_ns);
275✔
2719

2720
    num_hosts++;
275✔
2721
}
275✔
2722

2723
/************************************************************
2724

2725
  Function: crash_and_burn
2726

2727
*************************************************************
2728

2729
  Inputs:  char* message
2730

2731
  Description:
2732

2733
************************************************************/
2734

2735
void crash_and_burn(char *message)
×
2736
{
2737
    fprintf(stderr, "%s: %s\n", prog, message);
×
2738
    exit(4);
×
2739
}
2740

2741
/************************************************************
2742

2743
  Function: errno_crash_and_burn
2744

2745
*************************************************************
2746

2747
  Inputs:  char* message
2748

2749
  Description:
2750

2751
************************************************************/
2752

2753
void errno_crash_and_burn(char *message)
8✔
2754
{
2755
    fprintf(stderr, "%s: %s : %s\n", prog, message, strerror(errno));
8✔
2756
    exit(4);
8✔
2757
}
2758

2759
/************************************************************
2760

2761
  Function: print_warning
2762

2763
  Description: fprintf(stderr, ...), unless running with -q
2764

2765
*************************************************************/
2766

2767
void print_warning(char *format, ...)
9✔
2768
{
2769
    va_list args;
2770
    if (!quiet_flag) {
9✔
2771
        va_start(args, format);
9✔
2772
        vfprintf(stderr, format, args);
9✔
2773
        va_end(args);
9✔
2774
    }
3✔
2775
}
9✔
2776

2777
/************************************************************
2778

2779
  Function: sprint_tm
2780

2781
*************************************************************
2782

2783
  render nanosecond int64_t value into milliseconds string with three digits of
2784
  precision.
2785

2786
************************************************************/
2787

2788
const char *sprint_tm(int64_t ns)
715✔
2789
{
2790
    static char buf[10];
2791
    double t = (double)ns / 1e6;
715✔
2792

2793
    if (t < 0.0) {
715✔
2794
        /* negative (unexpected) */
2795
        sprintf(buf, "%.2g", t);
×
2796
    }
2797
    else if (t < 1.0) {
715✔
2798
        /* <= 0.99 ms */
2799
        sprintf(buf, "%.3f", t);
715✔
2800
    }
231✔
UNCOV
2801
    else if (t < 10.0) {
×
2802
        /* 1.00 - 9.99 ms */
UNCOV
2803
        sprintf(buf, "%.2f", t);
×
2804
    }
2805
    else if (t < 100.0) {
×
2806
        /* 10.0 - 99.9 ms */
2807
        sprintf(buf, "%.1f", t);
×
2808
    }
2809
    else if (t < 1000000.0) {
×
2810
        /* 100 - 1'000'000 ms */
2811
        sprintf(buf, "%.0f", t);
×
2812
    }
2813
    else {
2814
        sprintf(buf, "%.3e", t);
×
2815
    }
2816

2817
    return (buf);
715✔
2818
}
2819

2820
/************************************************************
2821

2822
  Function: addr_cmp
2823

2824
*************************************************************/
2825
int addr_cmp(struct sockaddr *a, struct sockaddr *b)
250✔
2826
{
2827
    if (a->sa_family != b->sa_family) {
250✔
2828
        return a->sa_family - b->sa_family;
×
2829
    }
2830
    else {
2831
        if (a->sa_family == AF_INET) {
250✔
2832
            return ((struct sockaddr_in *)a)->sin_addr.s_addr - ((struct sockaddr_in *)b)->sin_addr.s_addr;
206✔
2833
        }
2834
        else if (a->sa_family == AF_INET6) {
44✔
2835
            return memcmp(&((struct sockaddr_in6 *)a)->sin6_addr,
52✔
2836
                &((struct sockaddr_in6 *)b)->sin6_addr,
44✔
2837
                sizeof(((struct sockaddr_in6 *)a)->sin6_addr));
2838
        }
2839
    }
2840

2841
    return 0;
×
2842
}
72✔
2843

2844
void host_add_ping_event(HOST_ENTRY *h, int index, int64_t ev_time)
574✔
2845
{
2846
    struct event *event = &h->event_storage_ping[index % event_storage_count];
574✔
2847
    event->host = h;
574✔
2848
    event->ping_index = index;
574✔
2849
    event->ev_time = ev_time;
574✔
2850
    ev_enqueue(&event_queue_ping, event);
574✔
2851

2852
    dbg_printf("%s [%d]: add ping event in %.0f ms\n",
2853
        event->host->host, index, (ev_time - current_time_ns) / 1e6);
2854
}
574✔
2855

2856
void host_add_timeout_event(HOST_ENTRY *h, int index, int64_t ev_time)
578✔
2857
{
2858
    struct event *event = &h->event_storage_timeout[index % event_storage_count];
578✔
2859
    event->host = h;
578✔
2860
    event->ping_index = index;
578✔
2861
    event->ev_time = ev_time;
578✔
2862
    ev_enqueue(&event_queue_timeout, event);
578✔
2863

2864
    dbg_printf("%s [%d]: add timeout event in %.0f ms\n",
2865
        event->host->host, index, (ev_time - current_time_ns) / 1e6);
2866
}
578✔
2867

2868
struct event *host_get_timeout_event(HOST_ENTRY *h, int index)
489✔
2869
{
2870
    return &h->event_storage_timeout[index % event_storage_count];
489✔
2871
}
2872

2873
/************************************************************
2874

2875
  Function: ev_enqueue
2876

2877
  Enqueue an event
2878

2879
  The queue is sorted by event->ev_time, so that queue->first always points to
2880
  the earliest event.
2881

2882
  We start scanning the queue from the tail, because we assume
2883
  that new events mostly get inserted with a event time higher
2884
  than the others.
2885

2886
*************************************************************/
2887
void ev_enqueue(struct event_queue *queue, struct event *event)
1,152✔
2888
{
2889
    struct event *i;
2890
    struct event *i_prev;
2891

2892
    /* Empty list */
2893
    if (queue->last == NULL) {
1,152✔
2894
        event->ev_next = NULL;
884✔
2895
        event->ev_prev = NULL;
884✔
2896
        queue->first = event;
884✔
2897
        queue->last = event;
884✔
2898
        return;
884✔
2899
    }
2900

2901
    /* Insert on tail? */
2902
    if (event->ev_time - queue->last->ev_time >= 0) {
268✔
2903
        event->ev_next = NULL;
268✔
2904
        event->ev_prev = queue->last;
268✔
2905
        queue->last->ev_next = event;
268✔
2906
        queue->last = event;
268✔
2907
        return;
268✔
2908
    }
2909

2910
    /* Find insertion point */
2911
    i = queue->last;
×
2912
    while (1) {
2913
        i_prev = i->ev_prev;
×
2914
        if (i_prev == NULL || event->ev_time - i_prev->ev_time >= 0) {
×
2915
            event->ev_prev = i_prev;
×
2916
            event->ev_next = i;
×
2917
            i->ev_prev = event;
×
2918
            if (i_prev != NULL) {
×
2919
                i_prev->ev_next = event;
×
2920
            }
2921
            else {
2922
                queue->first = event;
×
2923
            }
2924
            return;
×
2925
        }
2926
        i = i_prev;
×
2927
    }
2928
}
356✔
2929

2930
/************************************************************
2931

2932
  Function: ev_dequeue
2933

2934
*************************************************************/
2935
struct event *ev_dequeue(struct event_queue *queue)
643✔
2936
{
2937
    struct event *dequeued;
2938

2939
    if (queue->first == NULL) {
643✔
2940
        return NULL;
×
2941
    }
2942
    dequeued = queue->first;
643✔
2943
    ev_remove(queue, dequeued);
643✔
2944

2945
    return dequeued;
643✔
2946
}
195✔
2947

2948
/************************************************************
2949

2950
  Function: ev_remove
2951

2952
*************************************************************/
2953
void ev_remove(struct event_queue *queue, struct event *event)
1,132✔
2954
{
2955
    if (queue->first == event) {
1,132✔
2956
        queue->first = event->ev_next;
1,123✔
2957
    }
347✔
2958
    if (queue->last == event) {
1,132✔
2959
        queue->last = event->ev_prev;
885✔
2960
    }
269✔
2961
    if (event->ev_prev) {
1,132✔
2962
        event->ev_prev->ev_next = event->ev_next;
9✔
2963
    }
3✔
2964
    if (event->ev_next) {
1,132✔
2965
        event->ev_next->ev_prev = event->ev_prev;
247✔
2966
    }
81✔
2967
    event->ev_prev = NULL;
1,132✔
2968
    event->ev_next = NULL;
1,132✔
2969
}
1,132✔
2970

2971
/************************************************************
2972

2973
  Function: print_human_readable_time from current_time_ns
2974

2975
*************************************************************/
2976
void print_timestamp_format(int64_t current_time_ns, int timestamp_format)
30✔
2977
{
2978
    char time_buffer[100];
2979
    time_t current_time_s;
2980
    struct tm *local_time;
2981

2982
    current_time_s = current_time_ns / 1000000000;
30✔
2983
    local_time = localtime(&current_time_s);
30✔
2984
    switch(timestamp_format) {
30✔
2985
        case 1:
4✔
2986
            // timestamp-format ctime
2987
            strftime(time_buffer, sizeof(time_buffer), "%c", local_time);
6✔
2988
            printf("[%s] ", time_buffer);
6✔
2989
            break;
6✔
2990
        case 2:
4✔
2991
            // timestamp-format iso
2992
            strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%dT%T%z", local_time);
6✔
2993
            printf("[%s] ", time_buffer);
6✔
2994
            break;
6✔
2995
        case 3:
4✔
2996
            // timestamp-format rfc3339
2997
            strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%d %H:%M:%S", local_time);
6✔
2998
            printf("[%s] ", time_buffer);
6✔
2999
            break;
6✔
3000
        default:
8✔
3001
            printf("[%.5f] ", (double)current_time_ns / 1e9);
12✔
3002
    }
4✔
3003
}
30✔
3004

3005
/************************************************************
3006

3007
  Function: usage
3008

3009
*************************************************************
3010

3011
  Inputs:  int: 0 if output on request, 1 if output because of wrong argument
3012

3013
  Description:
3014

3015
************************************************************/
3016

3017
void usage(int is_error)
115✔
3018
{
3019
    FILE *out = is_error ? stderr : stdout;
115✔
3020
    fprintf(out, "Usage: %s [options] [targets...]\n", prog);
115✔
3021
    fprintf(out, "\n");
115✔
3022
    fprintf(out, "Probing options:\n");
115✔
3023
    fprintf(out, "   -4, --ipv4         only ping IPv4 addresses\n");
115✔
3024
    fprintf(out, "   -6, --ipv6         only ping IPv6 addresses\n");
115✔
3025
    fprintf(out, "   -b, --size=BYTES   amount of ping data to send, in bytes (default: %d)\n", DEFAULT_PING_DATA_SIZE);
115✔
3026
    fprintf(out, "   -B, --backoff=N    set exponential backoff factor to N (default: 1.5)\n");
115✔
3027
    fprintf(out, "   -c, --count=N      count mode: send N pings to each target and report stats\n");
115✔
3028
    fprintf(out, "   -f, --file=FILE    read list of targets from a file ( - means stdin)\n");
115✔
3029
    fprintf(out, "   -g, --generate     generate target list (only if no -f specified),\n");
115✔
3030
    fprintf(out, "                      limited to at most %d targets\n", MAX_GENERATE);
115✔
3031
    fprintf(out, "                      (give start and end IP in the target list, or a CIDR address)\n");
115✔
3032
    fprintf(out, "                      (ex. %s -g 192.168.1.0 192.168.1.255 or %s -g 192.168.1.0/24)\n", prog, prog);
115✔
3033
    fprintf(out, "   -H, --ttl=N        set the IP TTL value (Time To Live hops)\n");
115✔
3034
    fprintf(out, "   -i, --interval=MSEC  interval between sending ping packets (default: %.0f ms)\n", interval / 1e6);
115✔
3035
#ifdef SO_BINDTODEVICE
3036
    fprintf(out, "   -I, --iface=IFACE  bind to a particular interface\n");
78✔
3037
#endif
3038
#ifdef SO_MARK
3039
    fprintf(out, "   -k, --fwmark=FWMARK set the routing mark\n");
78✔
3040
#endif
3041
    fprintf(out, "   -l, --loop         loop mode: send pings forever\n");
115✔
3042
    fprintf(out, "   -m, --all          use all IPs of provided hostnames (e.g. IPv4 and IPv6), use with -A\n");
115✔
3043
    fprintf(out, "   -M, --dontfrag     set the Don't Fragment flag\n");
115✔
3044
    fprintf(out, "   -O, --tos=N        set the type of service (tos) flag on the ICMP packets\n");
115✔
3045
    fprintf(out, "   -p, --period=MSEC  interval between ping packets to one target (in ms)\n");
115✔
3046
    fprintf(out, "                      (in loop and count modes, default: %.0f ms)\n", perhost_interval / 1e6);
115✔
3047
    fprintf(out, "   -r, --retry=N      number of retries (default: %d)\n", DEFAULT_RETRY);
115✔
3048
    fprintf(out, "   -R, --random       random packet data (to foil link data compression)\n");
115✔
3049
    fprintf(out, "   -S, --src=IP       set source address\n");
115✔
3050
    fprintf(out, "   -t, --timeout=MSEC individual target initial timeout (default: %.0f ms,\n", timeout / 1e6);
115✔
3051
    fprintf(out, "                      except with -l/-c/-C, where it's the -p period up to 2000 ms)\n");
115✔
3052
    fprintf(out, "       --check-source discard replies not from target address\n");
115✔
3053
    fprintf(out, "\n");
115✔
3054
    fprintf(out, "Output options:\n");
115✔
3055
    fprintf(out, "   -a, --alive        show targets that are alive\n");
115✔
3056
    fprintf(out, "   -A, --addr         show targets by address\n");
115✔
3057
    fprintf(out, "   -C, --vcount=N     same as -c, report results (not stats) in verbose format\n");
115✔
3058
    fprintf(out, "   -d, --rdns         show targets by name (force reverse-DNS lookup)\n");
115✔
3059
    fprintf(out, "   -D, --timestamp    print timestamp before each output line\n");
115✔
3060
    fprintf(out, "       --timestamp-format=FORMAT  show timestamp in the given format (-D required): ctime|iso|rfc3339\n");
115✔
3061
    fprintf(out, "   -e, --elapsed      show elapsed time on return packets\n");
115✔
3062
    fprintf(out, "   -n, --name         show targets by name (reverse-DNS lookup for target IPs)\n");
115✔
3063
    fprintf(out, "   -N, --netdata      output compatible for netdata (-l -Q are required)\n");
115✔
3064
    fprintf(out, "   -o, --outage       show the accumulated outage time (lost packets * packet interval)\n");
115✔
3065
    fprintf(out, "   -q, --quiet        quiet (don't show per-target/per-ping results)\n");
115✔
3066
    fprintf(out, "   -Q, --squiet=SECS[,cumulative]  same as -q, but add interval summary every SECS seconds,\n");
115✔
3067
    fprintf(out, "                                   with 'cumulative', print stats since beginning\n");
115✔
3068
    fprintf(out, "   -s, --stats        print final stats\n");
115✔
3069
    fprintf(out, "   -u, --unreach      show targets that are unreachable\n");
115✔
3070
    fprintf(out, "   -v, --version      show version\n");
115✔
3071
    fprintf(out, "   -x, --reachable=N  shows if >=N hosts are reachable or not\n");
115✔
3072
    fprintf(out, "   -X, --fast-reachable=N exits true immediately when N hosts are found\n");
115✔
3073
    exit(is_error);
115✔
3074
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc