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

schweikert / fping / 9625181756

22 Jun 2024 11:37AM UTC coverage: 85.469% (+0.4%) from 85.117%
9625181756

push

github

auerswal
configure.ac check required function strftime

1194 of 1397 relevant lines covered (85.47%)

224.12 hits per line

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

86.62
/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 100000 /* 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
#if defined(DEBUG) || defined(_DEBUG)
364
int randomly_lose_flag, trace_flag, print_per_system_flag;
365
int lose_factor;
366
#endif /* DEBUG || _DEBUG */
367

368
unsigned int fwmark = 0;
369

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

372
/*** forward declarations ***/
373

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

406
/************************************************************
407

408
  Function: p_setsockopt
409

410
*************************************************************
411

412
  Inputs:  p_uid: privileged uid. Others as per setsockopt(2)
413

414
  Description:
415

416
  Elevates privileges to p_uid when required, calls
417
  setsockopt, and drops privileges back.
418

419
************************************************************/
420

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

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

431
    res = setsockopt(sockfd, level, optname, optval, optlen);
×
432

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

439
    return res;
×
440
}
441

442
/************************************************************
443

444
  Function: main
445

446
*************************************************************
447

448
  Inputs:  int argc, char** argv
449

450
  Description:
451

452
  Main program entry point
453

454
************************************************************/
455

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

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

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

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

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

497
    memset(&src_addr, 0, sizeof(src_addr));
346✔
498
#ifdef IPV6
499
    memset(&src_addr6, 0, sizeof(src_addr6));
346✔
500
#endif
501

502
    if (!suid && suid != getuid()) {
346✔
503
        /* *temporarily* drop privileges */
504
        if (seteuid(getuid()) == -1)
333✔
505
            perror("cannot setuid");
×
506
    }
101✔
507

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

514
    /* get command line options */
515

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

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

623
        case 't':
12✔
624
            if (!sscanf(optparse_state.optarg, "%f", &opt_value_float))
14✔
625
                usage(1);
3✔
626
            if (opt_value_float < 0) {
12✔
627
                usage(1);
3✔
628
            }
1✔
629
            timeout = opt_value_float * 1000000;
10✔
630
            timeout_flag = 1;
10✔
631
            break;
10✔
632

633
        case 'r':
8✔
634
            if (!sscanf(optparse_state.optarg, "%u", &retry))
10✔
635
                usage(1);
3✔
636
            break;
8✔
637

638
        case 'i':
10✔
639
            if (!sscanf(optparse_state.optarg, "%f", &opt_value_float))
13✔
640
                usage(1);
3✔
641
            if (opt_value_float < 0) {
11✔
642
                usage(1);
3✔
643
            }
1✔
644
            interval = opt_value_float * 1000000;
9✔
645
            break;
9✔
646

647
        case 'p':
58✔
648
            if (!sscanf(optparse_state.optarg, "%f", &opt_value_float))
83✔
649
                usage(1);
3✔
650
            if (opt_value_float < 0) {
81✔
651
                usage(1);
3✔
652
            }
1✔
653
            perhost_interval = opt_value_float * 1000000;
79✔
654

655
            break;
79✔
656

657
        case 'c':
46✔
658
            if (!(count = (unsigned int)atoi(optparse_state.optarg)))
67✔
659
                usage(1);
3✔
660

661
            count_flag = 1;
65✔
662
            break;
65✔
663

664
        case 'C':
16✔
665
            if (!(count = (unsigned int)atoi(optparse_state.optarg)))
22✔
666
                usage(1);
3✔
667

668
            count_flag = 1;
20✔
669
            report_all_rtts_flag = 1;
20✔
670
            break;
20✔
671

672
        case 'b':
6✔
673
            if (!sscanf(optparse_state.optarg, "%u", &ping_data_size))
8✔
674
                usage(1);
3✔
675

676
            break;
6✔
677

678
        case 'h':
2✔
679
            usage(0);
3✔
680
            break;
1✔
681

682
        case 'q':
12✔
683
            verbose_flag = 0;
17✔
684
            quiet_flag = 1;
17✔
685
            break;
17✔
686

687
        case 'Q':
20✔
688
            verbose_flag = 0;
28✔
689
            quiet_flag = 1;
28✔
690
            if (!sscanf(optparse_state.optarg, "%f", &opt_value_float))
28✔
691
                usage(1);
3✔
692
            if (opt_value_float < 0) {
26✔
693
                usage(1);
3✔
694
            }
1✔
695
            report_interval = opt_value_float * 1e9;
24✔
696

697
            /* recognize keyword(s) after number, ignore everything else */
698
            {
699
                char *comma = strchr(optparse_state.optarg, ',');
24✔
700
                if ((comma != NULL) && (strcmp(++comma, "cumulative") == 0)) {
24✔
701
                    cumulative_stats_flag = 1;
6✔
702
                }
2✔
703
            }
704

705
            break;
24✔
706

707
        case 'e':
2✔
708
            elapsed_flag = 1;
3✔
709
            break;
3✔
710

711
        case 'm':
712
            multif_flag = 1;
×
713
            break;
×
714

715
        case 'N':
2✔
716
            netdata_flag = 1;
3✔
717
            break;
3✔
718

719
        case 'n':
4✔
720
            name_flag = 1;
6✔
721
            if (rdns_flag) {
6✔
722
                fprintf(stderr, "%s: use either one of -d or -n\n", prog);
3✔
723
                exit(1);
3✔
724
            }
725
            break;
3✔
726

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

735
        case 'A':
2✔
736
            addr_flag = 1;
3✔
737
            break;
3✔
738

739
        case 'B':
8✔
740
            if (!(backoff = atof(optparse_state.optarg)))
10✔
741
                usage(1);
3✔
742

743
            break;
8✔
744

745
        case 's':
4✔
746
            stats_flag = 1;
6✔
747
            break;
6✔
748

749
        case 'D':
12✔
750
            timestamp_flag = 1;
18✔
751
            break;
18✔
752

753
        case 'R':
4✔
754
            random_data_flag = 1;
5✔
755
            break;
5✔
756

757
        case 'l':
2✔
758
            loop_flag = 1;
3✔
759
            backoff_flag = 0;
3✔
760
            break;
3✔
761

762
        case 'u':
8✔
763
            unreachable_flag = 1;
12✔
764
            break;
12✔
765

766
        case 'a':
10✔
767
            alive_flag = 1;
15✔
768
            break;
15✔
769

770
        case 'H':
6✔
771
            if (!(ttl = (unsigned int)atoi(optparse_state.optarg)))
8✔
772
                usage(1);
3✔
773
            break;
6✔
774

775
#if defined(DEBUG) || defined(_DEBUG)
776
        case 'z':
777
            if (sscanf(optparse_state.optarg, "0x%x", &debugging) != 1)
778
                if (sscanf(optparse_state.optarg, "%u", &debugging) != 1)
779
                    usage(1);
780

781
            break;
782
#endif /* DEBUG || _DEBUG */
783

784
        case 'v':
4✔
785
            printf("%s: Version %s\n", prog, VERSION);
6✔
786
            exit(0);
6✔
787

788
        case 'x':
6✔
789
            if (!(min_reachable = (unsigned int)atoi(optparse_state.optarg)))
8✔
790
                usage(1);
3✔
791
            break;
6✔
792

793
        case 'X':
4✔
794
            if (!(min_reachable = (unsigned int)atoi(optparse_state.optarg)))
5✔
795
                usage(1);
3✔
796
            fast_reachable = 1;
3✔
797
            break;
3✔
798

799
        case 'f':
8✔
800
            filename = optparse_state.optarg;
12✔
801
            break;
12✔
802
#ifdef SO_MARK
803
        case 'k':
4✔
804
            if (!(fwmark = (unsigned int)atol(optparse_state.optarg)))
4✔
805
                usage(1);
2✔
806

807
            if (socket4 >= 0)
2✔
808
                if(-1 == setsockopt(socket4, SOL_SOCKET, SO_MARK, &fwmark, sizeof fwmark))
2✔
809
                    perror("fwmark ipv4");
810

811
#ifdef IPV6
812
            if (socket6 >= 0)
2✔
813
                if(-1 == setsockopt(socket6, SOL_SOCKET, SO_MARK, &fwmark, sizeof fwmark))
2✔
814
                    perror("fwmark ipv6");
815
#endif
816

817
            break;
2✔
818
#endif
819

820
        case 'g':
42✔
821
            /* use IP list generation */
822
            /* mutually exclusive with using file input or command line targets */
823
            generate_flag = 1;
59✔
824
            break;
59✔
825

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

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

863
        case 'T':
2✔
864
            /* This option is ignored for compatibility reasons ("select timeout" is not meaningful anymore) */
865
            break;
3✔
866

867
        case 'O':
4✔
868
            if (sscanf(optparse_state.optarg, "%i", &tos)) {
6✔
869
                if (socket4 >= 0) {
3✔
870
                    if (setsockopt(socket4, IPPROTO_IP, IP_TOS, &tos, sizeof(tos))) {
3✔
871
                        perror("setting type of service octet IP_TOS");
×
872
                    }
873
                }
1✔
874
#if defined(IPV6) && defined(IPV6_TCLASS)
875
                if (socket6 >= 0) {
3✔
876
                    if (setsockopt(socket6, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos))) {
3✔
877
                        perror("setting type of service octet IPV6_TCLASS");
×
878
                    }
879
                }
1✔
880
#endif
881
            }
1✔
882
            else {
883
                usage(1);
3✔
884
            }
885
            break;
4✔
886

887
        case 'o':
6✔
888
            outage_flag = 1;
9✔
889
            break;
9✔
890

891
        case '?':
2✔
892
            fprintf(stderr, "%s: %s\n", argv[0], optparse_state.errmsg);
3✔
893
            fprintf(stderr, "see 'fping -h' for usage information\n");
3✔
894
            exit(1);
3✔
895
            break;
896
        }
897
    }
285✔
898

899
    /* permanently drop privileges */
900
    if (suid != getuid() && setuid(getuid())) {
250✔
901
        perror("fatal: failed to permanently drop privileges");
×
902
        /* continuing would be a security hole */
903
        exit(4);
×
904
    }
905

906
    /* validate various option settings */
907

908
#ifndef IPV6
909
    if (socket4 < 0) {
910
        crash_and_burn("can't create socket (must run as root?)");
911
    }
912
#else
913
    if ((socket4 < 0 && socket6 < 0) || (hints_ai_family == AF_INET6 && socket6 < 0)) {
250✔
914
        crash_and_burn("can't create socket (must run as root?)");
×
915
    }
916
#endif
917

918
    if (ttl > 255) {
250✔
919
        fprintf(stderr, "%s: ttl %u out of range\n", prog, ttl);
3✔
920
        exit(1);
3✔
921
    }
922

923
    if (unreachable_flag && alive_flag) {
247✔
924
        fprintf(stderr, "%s: specify only one of a, u\n", prog);
3✔
925
        exit(1);
3✔
926
    }
927

928
    if (count_flag && loop_flag) {
244✔
929
        fprintf(stderr, "%s: specify only one of c, l\n", prog);
3✔
930
        exit(1);
3✔
931
    }
932

933
#ifdef FPING_SAFE_LIMITS
934
    if ((interval < (int64_t)MIN_INTERVAL * 1000000 || perhost_interval < (int64_t)MIN_PERHOST_INTERVAL * 1000000)
241✔
935
        && getuid()) {
75✔
936
        fprintf(stderr, "%s: these options are too risky for mere mortals.\n", prog);
6✔
937
        fprintf(stderr, "%s: You need -i >= %u and -p >= %u\n",
8✔
938
            prog, MIN_INTERVAL, MIN_PERHOST_INTERVAL);
2✔
939
        exit(1);
6✔
940
    }
941
#endif
942

943
    if (ping_data_size > MAX_PING_DATA) {
235✔
944
        fprintf(stderr, "%s: data size %u not valid, must be lower than %u\n",
4✔
945
            prog, ping_data_size, (unsigned int)MAX_PING_DATA);
1✔
946
        exit(1);
3✔
947
    }
948

949
    if ((backoff > MAX_BACKOFF_FACTOR) || (backoff < MIN_BACKOFF_FACTOR)) {
232✔
950
        fprintf(stderr, "%s: backoff factor %.1f not valid, must be between %.1f and %.1f\n",
8✔
951
            prog, backoff, MIN_BACKOFF_FACTOR, MAX_BACKOFF_FACTOR);
2✔
952
        exit(1);
6✔
953
    }
954

955
    if (count_flag) {
226✔
956
        if (verbose_flag)
79✔
957
            per_recv_flag = 1;
38✔
958

959
        alive_flag = unreachable_flag = verbose_flag = 0;
79✔
960
    }
25✔
961

962
    if (loop_flag) {
226✔
963
        if (!report_interval)
×
964
            per_recv_flag = 1;
×
965

966
        alive_flag = unreachable_flag = verbose_flag = 0;
×
967
    }
968

969
    if (alive_flag || unreachable_flag || min_reachable)
226✔
970
        verbose_flag = 0;
18✔
971

972
    trials = (count > retry + 1) ? count : retry + 1;
230✔
973

974
    /* auto-tune default timeout for count/loop modes
975
     * see also github #32 */
976
    if (loop_flag || count_flag) {
230✔
977
        if (!timeout_flag) {
79✔
978
            timeout = perhost_interval;
74✔
979
            if (timeout > (int64_t)AUTOTUNE_TIMEOUT_MAX * 1000000) {
74✔
980
                timeout = (int64_t)AUTOTUNE_TIMEOUT_MAX * 1000000;
×
981
            }
982
        }
24✔
983
    }
25✔
984

985
#if defined(DEBUG) || defined(_DEBUG)
986
    if (debugging & DBG_TRACE)
987
        trace_flag = 1;
988

989
    if (debugging & DBG_RANDOM_LOSE_FEW) {
990
        randomly_lose_flag = 1;
991
        lose_factor = 1; /* ie, 1/4 */
992
    }
993

994
    if (debugging & DBG_RANDOM_LOSE_MANY) {
995
        randomly_lose_flag = 1;
996
        lose_factor = 5; /* ie, 3/4 */
997
    }
998

999
    if (debugging & DBG_PRINT_PER_SYSTEM)
1000
        print_per_system_flag = 1;
1001

1002
    if ((debugging & DBG_REPORT_ALL_RTTS) && !loop_flag)
1003
        report_all_rtts_flag = 1;
1004

1005
    if (trace_flag) {
1006
        fprintf(stderr, "%s:\n  count: %u, retry: %u, interval: %.0f ms\n",
1007
            prog, count, retry, interval / 1e6);
1008
        fprintf(stderr, "  perhost_interval: %.0f ms, timeout: %.0f\n",
1009
            perhost_interval / 1e6, timeout / 1e6);
1010
        fprintf(stderr, "  ping_data_size = %u, trials = %u\n",
1011
            ping_data_size, trials);
1012

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

1052
    /* set the TTL, if the -H option was set (otherwise ttl will be = 0) */
1053
    if (ttl > 0) {
230✔
1054
        if (socket4 >= 0) {
3✔
1055
            if (setsockopt(socket4, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl))) {
3✔
1056
                perror("setting time to live");
×
1057
            }
1058
        }
1✔
1059
#ifdef IPV6
1060
        if (socket6 >= 0) {
3✔
1061
            if (setsockopt(socket6, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl))) {
3✔
1062
                perror("setting time to live");
×
1063
            }
1064
        }
1✔
1065
#endif
1066
    }
1✔
1067

1068
#if HAVE_SO_TIMESTAMPNS
1069
    {
1070
        int opt = 1;
160✔
1071
        if (socket4 >= 0) {
160✔
1072
            if (setsockopt(socket4, SOL_SOCKET, SO_TIMESTAMPNS, &opt, sizeof(opt))) {
160✔
1073
                if (setsockopt(socket4, SOL_SOCKET, SO_TIMESTAMP, &opt, sizeof(opt))) {
1074
                    perror("setting SO_TIMESTAMPNS and SO_TIMESTAMP option");
1075
                }
1076
            }
1077
        }
1078
#ifdef IPV6
1079
        if (socket6 >= 0) {
160✔
1080
            if (setsockopt(socket6, SOL_SOCKET, SO_TIMESTAMPNS, &opt, sizeof(opt))) {
160✔
1081
                if (setsockopt(socket6, SOL_SOCKET, SO_TIMESTAMP, &opt, sizeof(opt))) {
1082
                    perror("setting SO_TIMESTAMPNS and SO_TIMESTAMP option (IPv6)");
1083
                }
1084
            }
1085
        }
1086
#endif
1087
    }
1088
#endif
1089

1090
    update_current_time();
230✔
1091
    start_time = current_time_ns;
230✔
1092

1093
    /* handle host names supplied on command line or in a file */
1094
    /* if the generate_flag is on, then generate the IP list */
1095

1096
    argv = &argv[optparse_state.optind];
230✔
1097
    argc -= optparse_state.optind;
230✔
1098

1099
    /* calculate how many ping can be in-flight per host */
1100
    if (count_flag) {
230✔
1101
        event_storage_count = count;
84✔
1102
    }
30✔
1103
    else if (loop_flag) {
146✔
1104
        if (perhost_interval > timeout) {
×
1105
            event_storage_count = 1;
×
1106
        }
1107
        else {
1108
            event_storage_count = 1 + timeout / perhost_interval;
×
1109
        }
1110
    }
1111
    else {
1112
        event_storage_count = 1;
146✔
1113
    }
1114

1115
    /* file and generate are mutually exclusive */
1116
    /* file and command line are mutually exclusive */
1117
    /* generate requires command line parameters beyond the switches */
1118
    if ((*argv && filename) || (filename && generate_flag) || (generate_flag && !*argv))
230✔
1119
        usage(1);
9✔
1120

1121
    /* if no conditions are specified, then assume input from stdin */
1122
    if (!*argv && !filename && !generate_flag)
222✔
1123
        filename = "-";
3✔
1124

1125
    if (*argv && !generate_flag) {
222✔
1126
        while (*argv) {
347✔
1127
            add_name(*argv);
193✔
1128
            ++argv;
193✔
1129
        }
1130
    }
44✔
1131
    else if (filename) {
68✔
1132
        FILE *ping_file;
1133
        char line[132];
1134
        char host[132];
1135

1136
        if (strcmp(filename, "-") == 0)
15✔
1137
            ping_file = fdopen(0, "r");
6✔
1138
        else
1139
            ping_file = fopen(filename, "r");
9✔
1140

1141
        if (!ping_file)
15✔
1142
            errno_crash_and_burn("fopen");
3✔
1143

1144
        while (fgets(line, sizeof(line), ping_file)) {
43✔
1145
            if (sscanf(line, "%s", host) != 1)
30✔
1146
                continue;
3✔
1147

1148
            if ((!*host) || (host[0] == '#')) /* magic to avoid comments */
27✔
1149
                continue;
3✔
1150

1151
            add_name(host);
24✔
1152
        }
1153

1154
        fclose(ping_file);
13✔
1155
    }
5✔
1156
    else if (*argv && generate_flag) {
53✔
1157
        if (argc == 1) {
53✔
1158
            /* one target: we expect a cidr range (n.n.n.n/m) */
1159
            add_cidr(argv[0]);
29✔
1160
        }
9✔
1161
        else if (argc == 2) {
24✔
1162
            add_range(argv[0], argv[1]);
21✔
1163
        }
5✔
1164
        else {
1165
            usage(1);
3✔
1166
        }
1167
    }
15✔
1168
    else {
1169
        usage(1);
×
1170
    }
1171

1172
    if (!num_hosts) {
194✔
1173
        exit(num_noaddress ? 2 : 1);
12✔
1174
    }
1175

1176
    if (socket4 >= 0 && (src_addr_set || socktype4 == SOCK_DGRAM)) {
182✔
1177
        socket_set_src_addr_ipv4(socket4, &src_addr, (socktype4 == SOCK_DGRAM) ? &ident4 : NULL);
6✔
1178
    }
2✔
1179
#ifdef IPV6
1180
    if (socket6 >= 0 && (src_addr6_set || socktype6 == SOCK_DGRAM)) {
180✔
1181
        socket_set_src_addr_ipv6(socket6, &src_addr6, (socktype6 == SOCK_DGRAM) ? &ident6 : NULL);
4✔
1182
    }
1183
#endif
1184

1185
    /* allocate and initialize array to map host nr to host_entry */
1186
    {
1187
        struct event *cursor = event_queue_ping.first;
178✔
1188
        int i = 0;
178✔
1189
        table = (HOST_ENTRY **)calloc(num_hosts, sizeof(HOST_ENTRY *));
178✔
1190
        if (!table)
178✔
1191
            crash_and_burn("Can't malloc array of hosts");
×
1192
        /* initialize table of hosts. we know that we have ping events scheduled
1193
         * for each of them */
1194
        for (cursor = event_queue_ping.first; cursor; cursor = cursor->ev_next) {
429✔
1195
            table[i] = cursor->host;
251✔
1196
            cursor->host->i = i;
251✔
1197
            i++;
251✔
1198
        }
77✔
1199
    }
1200

1201
    init_ping_buffer_ipv4(ping_data_size);
178✔
1202
#ifdef IPV6
1203
    init_ping_buffer_ipv6(ping_data_size);
178✔
1204
#endif
1205

1206
#ifdef USE_SIGACTION
1207
    memset(&act, 0, sizeof(act));
178✔
1208
    act.sa_handler = signal_handler;
178✔
1209
    sigemptyset(&act.sa_mask);
178✔
1210
    sigaddset(&act.sa_mask, SIGINT);
178✔
1211
    sigaddset(&act.sa_mask, SIGQUIT);
178✔
1212
    act.sa_flags = SA_RESTART;
178✔
1213
    if (sigaction(SIGQUIT, &act, NULL) || sigaction(SIGINT, &act, NULL)) {
178✔
1214
        crash_and_burn("failure to set signal handler");
22✔
1215
    }
22✔
1216
#else
1217
    signal(SIGINT, signal_handler);
1218
    signal(SIGQUIT, signal_handler);
1219
#endif
1220
    setlinebuf(stdout);
156✔
1221

1222
    if (report_interval) {
156✔
1223
        next_report_time = current_time_ns + report_interval;
24✔
1224
    }
8✔
1225

1226
    last_send_time = 0;
156✔
1227

1228
    seqmap_init();
156✔
1229

1230
    /* main loop */
1231
    main_loop();
156✔
1232

1233
/* Debug: CPU Performance */
1234
#if defined(DEBUG) || defined(_DEBUG)
1235
    perf_cpu_end = clock();
1236
    perf_cpu_time_used = ((double) (perf_cpu_end - perf_cpu_start)) / CLOCKS_PER_SEC;
1237
    printf("[DEBUG] CPU time used: %f sec", perf_cpu_time_used);
1238
#endif /* DEBUG || _DEBUG */
1239

1240
    finish();
156✔
1241

1242
    return 0;
38✔
1243
}
1244

1245
static inline int64_t timespec_ns(struct timespec *a)
3,373✔
1246
{
1247
    return ((int64_t)a->tv_sec * 1000000000) + a->tv_nsec;
3,373✔
1248
}
1249

1250
void add_cidr(char *addr)
28✔
1251
{
1252
    char *addr_end;
1253
    char *mask_str;
1254
    unsigned long mask;
1255
    unsigned long bitmask;
1256
    int ret;
1257
    struct addrinfo addr_hints;
1258
    struct addrinfo *addr_res;
1259
    unsigned long net_addr;
1260
    unsigned long net_last;
1261

1262
    /* Split address from mask */
1263
    addr_end = strchr(addr, '/');
28✔
1264
    if (addr_end == NULL) {
28✔
1265
        usage(1);
3✔
1266
    }
1✔
1267
    *addr_end = '\0';
26✔
1268
    mask_str = addr_end + 1;
26✔
1269
    mask = atoi(mask_str);
26✔
1270

1271
    /* parse address (IPv4 only) */
1272
    memset(&addr_hints, 0, sizeof(struct addrinfo));
26✔
1273
    addr_hints.ai_family = AF_UNSPEC;
26✔
1274
    addr_hints.ai_flags = AI_NUMERICHOST;
26✔
1275
    ret = getaddrinfo(addr, NULL, &addr_hints, &addr_res);
26✔
1276
    if (ret) {
26✔
1277
        fprintf(stderr, "%s, can't parse address %s: %s\n", prog, addr, gai_strerror(ret));
3✔
1278
        exit(1);
3✔
1279
    }
1280
    if (addr_res->ai_family != AF_INET) {
23✔
1281
        fprintf(stderr, "%s: -g works only with IPv4 addresses\n", prog);
5✔
1282
        exit(1);
5✔
1283
    }
1284
    net_addr = ntohl(((struct sockaddr_in *)addr_res->ai_addr)->sin_addr.s_addr);
18✔
1285

1286
    /* check mask */
1287
    if (mask < 1 || mask > 32) {
18✔
1288
        fprintf(stderr, "%s: netmask must be between 1 and 32 (is: %s)\n", prog, mask_str);
6✔
1289
        exit(1);
6✔
1290
    }
1291

1292
    /* convert mask integer from 1 to 32 to a bitmask */
1293
    bitmask = ((unsigned long)0xFFFFFFFF) << (32 - mask);
12✔
1294

1295
    /* calculate network range */
1296
    net_addr &= bitmask;
12✔
1297
    net_last = net_addr + ((unsigned long)0x1 << (32 - mask)) - 1;
12✔
1298

1299
    /* exclude network and broadcast address for regular prefixes */
1300
    if (mask < 31) {
12✔
1301
        net_last--;
6✔
1302
        net_addr++;
6✔
1303
    }
2✔
1304

1305
    /* add all hosts in that network (net_addr and net_last inclusive) */
1306
    for (; net_addr <= net_last; net_addr++) {
45✔
1307
        struct in_addr in_addr_tmp;
1308
        char buffer[20];
1309
        in_addr_tmp.s_addr = htonl(net_addr);
33✔
1310
        inet_ntop(AF_INET, &in_addr_tmp, buffer, sizeof(buffer));
33✔
1311
        add_name(buffer);
33✔
1312
    }
11✔
1313

1314
    freeaddrinfo(addr_res);
12✔
1315
}
12✔
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
    if (end_long > start_long + MAX_GENERATE) {
9✔
1359
        fprintf(stderr, "%s: -g parameter generates too many addresses\n", prog);
3✔
1360
        exit(1);
3✔
1361
    }
1362

1363
    /* generate */
1364
    for (; start_long <= end_long; start_long++) {
21✔
1365
        struct in_addr in_addr_tmp;
1366
        char buffer[20];
1367
        in_addr_tmp.s_addr = htonl(start_long);
15✔
1368
        inet_ntop(AF_INET, &in_addr_tmp, buffer, sizeof(buffer));
15✔
1369
        add_name(buffer);
15✔
1370
    }
5✔
1371
}
6✔
1372

1373
void main_loop()
167✔
1374
{
1375
    int64_t lt;
1376
    int64_t wait_time_ns;
1377
    struct event *event;
1378
    struct host_entry *h;
1379

1380
    while (event_queue_ping.first || event_queue_timeout.first) {
1,176✔
1381
        dbg_printf("%s", "# main_loop\n");
1382

1383
        /* timeout event ? */
1384
        if (event_queue_timeout.first && event_queue_timeout.first->ev_time - current_time_ns <= 0) {
1,014✔
1385
            event = ev_dequeue(&event_queue_timeout);
77✔
1386
            h = event->host;
77✔
1387

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

1390
            stats_add(h, event->ping_index, 0, -1);
77✔
1391

1392
            if (per_recv_flag) {
77✔
1393
                if (timestamp_flag) {
15✔
1394
                    print_timestamp_format(current_time_ns, timestamp_format_flag);
×
1395
                }
1396
                printf("%-*s : [%d], timed out",
15✔
1397
                    max_hostname_len, h->host, event->ping_index);
5✔
1398
                if (h->num_recv > 0) {
15✔
1399
                    printf(" (%s avg, ", sprint_tm(h->total_time / h->num_recv));
×
1400
                }
1401
                else {
1402
                    printf(" (NaN avg, ");
15✔
1403
                }
1404
                if (h->num_recv <= h->num_sent) {
15✔
1405
                    printf("%d%% loss)",
15✔
1406
                        ((h->num_sent - h->num_recv) * 100) / h->num_sent);
15✔
1407
                }
5✔
1408
                else {
1409
                    printf("%d%% return)",
×
1410
                        (h->num_recv_total * 100) / h->num_sent);
×
1411
                }
1412
                printf("\n");
15✔
1413
            }
5✔
1414

1415
            /* do we need to send a retry? */
1416
            if (!loop_flag && !count_flag) {
77✔
1417
                if (h->num_sent < retry + 1) {
38✔
1418
                    if (backoff_flag) {
24✔
1419
                        h->timeout *= backoff;
24✔
1420
                    }
6✔
1421
                    send_ping(h, event->ping_index);
24✔
1422
                }
6✔
1423
            }
10✔
1424

1425
            /* note: we process first timeout events, because we might need to
1426
             * wait to process ping events, while we for sure never need to
1427
             * wait for timeout events.
1428
             */
1429
            continue;
77✔
1430
        }
1431

1432
        /* ping event ? */
1433
        if (event_queue_ping.first && event_queue_ping.first->ev_time - current_time_ns <= 0) {
1,105✔
1434
            /* Make sure that we don't ping more than once every "interval" */
1435
            lt = current_time_ns - last_send_time;
687✔
1436
            if (lt < interval)
687✔
1437
                goto wait_for_reply;
155✔
1438

1439
            /* Dequeue the event */
1440
            event = ev_dequeue(&event_queue_ping);
532✔
1441
            h = event->host;
532✔
1442

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

1445
            /* Send the ping */
1446
            send_ping(h, event->ping_index);
532✔
1447

1448
            /* Loop and count mode: schedule next ping */
1449
            if (loop_flag || (count_flag && event->ping_index + 1 < count)) {
532✔
1450
                host_add_ping_event(h, event->ping_index + 1, event->ev_time + perhost_interval);
296✔
1451
            }
96✔
1452
        }
168✔
1453

1454
    wait_for_reply:
346✔
1455

1456
        /* When is the next ping next event? */
1457
        wait_time_ns = -1;
937✔
1458
        if (event_queue_ping.first) {
937✔
1459
            wait_time_ns = event_queue_ping.first->ev_time - current_time_ns;
732✔
1460
            if (wait_time_ns < 0)
732✔
1461
                wait_time_ns = 0;
319✔
1462
            /* make sure that we wait enough, so that the inter-ping delay is
1463
             * bigger than 'interval' */
1464
            if (wait_time_ns < interval) {
732✔
1465
                lt = current_time_ns - last_send_time;
324✔
1466
                if (lt < interval) {
324✔
1467
                    wait_time_ns = interval - lt;
324✔
1468
                }
130✔
1469
            }
130✔
1470

1471
            dbg_printf("next ping event in %.0f ms (%s)\n", wait_time_ns / 1e6, event_queue_ping.first->host->host);
1472
        }
237✔
1473

1474
        /* When is the next timeout event? */
1475
        if (event_queue_timeout.first) {
937✔
1476
            int64_t wait_time_timeout = event_queue_timeout.first->ev_time - current_time_ns;
580✔
1477
            if (wait_time_ns < 0 || wait_time_timeout < wait_time_ns) {
580✔
1478
                wait_time_ns = wait_time_timeout;
212✔
1479
                if (wait_time_ns < 0) {
212✔
1480
                    wait_time_ns = 0;
×
1481
                }
1482
            }
62✔
1483

1484
            dbg_printf("next timeout event in %.0f ms (%s)\n", wait_time_timeout / 1e6, event_queue_timeout.first->host->host);
1485
        }
182✔
1486

1487
        /* When is the next report due? */
1488
        if (report_interval && (loop_flag || count_flag)) {
937✔
1489
            int64_t wait_time_next_report = next_report_time - current_time_ns;
204✔
1490
            if (wait_time_next_report < wait_time_ns) {
204✔
1491
                wait_time_ns = wait_time_next_report;
69✔
1492
                if (wait_time_ns < 0) {
69✔
1493
                    wait_time_ns = 0;
×
1494
                }
1495
            }
23✔
1496

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

1500
        /* if wait_time is still -1, it means that we are waiting for nothing... */
1501
        if (wait_time_ns == -1) {
937✔
1502
            break;
2✔
1503
        }
1504

1505
        /* end of loop was requested by interrupt signal handler */
1506
        if (finish_requested) {
935✔
1507
            break;
3✔
1508
        }
1509

1510
        /* Receive replies */
1511
        /* (this is what sleeps during each loop iteration) */
1512
        dbg_printf("waiting up to %.0f ms\n", wait_time_ns / 1e6);
1513
        if (wait_for_reply(wait_time_ns)) {
932✔
1514
            while (wait_for_reply(0))
810✔
1515
                ; /* process other replies in the queue */
1516
        }
151✔
1517

1518
        update_current_time();
932✔
1519

1520
        if (status_snapshot) {
932✔
1521
            status_snapshot = 0;
×
1522
            print_per_system_splits();
×
1523
        }
1524

1525
        /* Print report */
1526
        if (report_interval && (loop_flag || count_flag) && (current_time_ns >= next_report_time)) {
932✔
1527
            if (netdata_flag)
42✔
1528
                print_netdata();
3✔
1529
            else
1530
                print_per_system_splits();
39✔
1531

1532
            while (current_time_ns >= next_report_time) {
84✔
1533
                next_report_time += report_interval;
42✔
1534
            }
1535
        }
14✔
1536
    }
1537
}
167✔
1538

1539
/************************************************************
1540

1541
  Function: signal_handler
1542

1543
*************************************************************
1544

1545
  Inputs:  int signum
1546

1547
  Description:
1548

1549
  SIGQUIT signal handler - set flag and return
1550
  SIGINT signal handler - set flag and return
1551

1552
************************************************************/
1553

1554
void signal_handler(int signum)
×
1555
{
1556
    switch (signum) {
×
1557
    case SIGINT:
1558
        finish_requested = 1;
×
1559
        break;
×
1560

1561
    case SIGQUIT:
1562
        status_snapshot = 1;
×
1563
        break;
×
1564
    }
1565
}
×
1566

1567
/************************************************************
1568

1569
  Function: update_current_time
1570

1571
*************************************************************/
1572

1573
void update_current_time()
2,729✔
1574
{
1575
    clock_gettime(CLOCKID, &current_time);
2,729✔
1576
    current_time_ns = timespec_ns(&current_time);
2,729✔
1577
}
2,729✔
1578

1579
/************************************************************
1580

1581
  Function: finish
1582

1583
*************************************************************
1584

1585
  Inputs:  void (none)
1586

1587
  Description:
1588

1589
  Main program clean up and exit point
1590

1591
************************************************************/
1592

1593
void finish()
167✔
1594
{
1595
    int i;
1596
    HOST_ENTRY *h;
1597

1598
    update_current_time();
167✔
1599
    end_time = current_time_ns;
167✔
1600

1601
    /* tot up unreachables */
1602
    for (i = 0; i < num_hosts; i++) {
418✔
1603
        h = table[i];
251✔
1604

1605
        if (!h->num_recv) {
251✔
1606
            num_unreachable++;
40✔
1607

1608
            if (verbose_flag || unreachable_flag) {
40✔
1609
                printf("%s", h->host);
8✔
1610

1611
                if (verbose_flag)
8✔
1612
                    printf(" is unreachable");
5✔
1613

1614
                printf("\n");
8✔
1615
            }
2✔
1616
        }
12✔
1617
    }
77✔
1618

1619
    if (count_flag || loop_flag)
167✔
1620
        print_per_system_stats();
79✔
1621
#if defined(DEBUG) || defined(_DEBUG)
1622
    else if (print_per_system_flag)
1623
        print_per_system_stats();
1624
#endif /* DEBUG || _DEBUG */
1625

1626
    if (stats_flag)
167✔
1627
        print_global_stats();
6✔
1628

1629
    if (min_reachable) {
167✔
1630
        if ((num_hosts - num_unreachable) >= min_reachable) {
9✔
1631
            printf("Enough hosts reachable (required: %d, reachable: %d)\n", min_reachable, num_hosts - num_unreachable);
6✔
1632
            exit(0);
6✔
1633
        }
1634
        else {
1635
            printf("Not enough hosts reachable (required: %d, reachable: %d)\n", min_reachable, num_hosts - num_unreachable);
3✔
1636
            exit(1);
3✔
1637
        }
1638
    }
1639

1640
    if (num_noaddress)
158✔
1641
        exit(2);
×
1642
    else if (num_alive != num_hosts)
158✔
1643
        exit(1);
19✔
1644

1645
    exit(0);
139✔
1646
}
1647

1648
/************************************************************
1649

1650
  Function: print_per_system_stats
1651

1652
*************************************************************
1653

1654
  Inputs:  void (none)
1655

1656
  Description:
1657

1658

1659
************************************************************/
1660

1661
void print_per_system_stats(void)
79✔
1662
{
1663
    int i, j, avg, outage_ms;
1664
    HOST_ENTRY *h;
1665
    int64_t resp;
1666

1667
    if (verbose_flag || per_recv_flag)
79✔
1668
        fprintf(stderr, "\n");
38✔
1669

1670
    for (i = 0; i < num_hosts; i++) {
182✔
1671
        h = table[i];
103✔
1672
        fprintf(stderr, "%-*s :", max_hostname_len, h->host);
103✔
1673

1674
        if (report_all_rtts_flag) {
103✔
1675
            for (j = 0; j < h->num_sent; j++) {
218✔
1676
                if ((resp = h->resp_times[j]) >= 0)
186✔
1677
                    fprintf(stderr, " %s", sprint_tm(resp));
180✔
1678
                else
1679
                    fprintf(stderr, " -");
6✔
1680
            }
60✔
1681

1682
            fprintf(stderr, "\n");
32✔
1683
        }
10✔
1684
        else {
1685
            if (h->num_recv <= h->num_sent) {
71✔
1686
                fprintf(stderr, " xmt/rcv/%%loss = %d/%d/%d%%",
94✔
1687
                    h->num_sent, h->num_recv, h->num_sent > 0 ? ((h->num_sent - h->num_recv) * 100) / h->num_sent : 0);
71✔
1688

1689
                if (outage_flag) {
71✔
1690
                    /* Time outage total */
1691
                    outage_ms = (h->num_sent - h->num_recv) * perhost_interval / 1e6;
9✔
1692
                    fprintf(stderr, ", outage(ms) = %d", outage_ms);
9✔
1693
                }
3✔
1694
            }
23✔
1695
            else {
1696
                fprintf(stderr, " xmt/rcv/%%return = %d/%d/%d%%",
×
1697
                    h->num_sent, h->num_recv,
1698
                    h->num_sent > 0 ? ((h->num_recv * 100) / h->num_sent) : 0);
×
1699
            }
1700

1701
            if (h->num_recv) {
71✔
1702
                avg = h->total_time / h->num_recv;
62✔
1703
                fprintf(stderr, ", min/avg/max = %s", sprint_tm(h->min_reply));
62✔
1704
                fprintf(stderr, "/%s", sprint_tm(avg));
62✔
1705
                fprintf(stderr, "/%s", sprint_tm(h->max_reply));
62✔
1706
            }
20✔
1707

1708
            fprintf(stderr, "\n");
71✔
1709
        }
1710
    }
33✔
1711
}
79✔
1712

1713
/************************************************************
1714

1715
  Function: print_netdata
1716

1717
*************************************************************
1718

1719
  Inputs:  void (none)
1720

1721
  Description:
1722

1723

1724
************************************************************/
1725

1726
void print_netdata(void)
3✔
1727
{
1728
    static int sent_charts = 0;
1729

1730
    int i;
1731
    int64_t avg;
1732
    HOST_ENTRY *h;
1733

1734
    for (i = 0; i < num_hosts; i++) {
6✔
1735
        h = table[i];
3✔
1736

1737
        if (!sent_charts) {
3✔
1738
            printf("CHART fping.%s_packets '' 'FPing Packets' packets '%s' fping.packets line 110020 %.0f\n", h->name, h->host, report_interval / 1e9);
3✔
1739
            printf("DIMENSION xmt sent absolute 1 1\n");
3✔
1740
            printf("DIMENSION rcv received absolute 1 1\n");
3✔
1741
        }
1✔
1742

1743
        printf("BEGIN fping.%s_packets\n", h->name);
3✔
1744
        printf("SET xmt = %d\n", h->num_sent_i);
3✔
1745
        printf("SET rcv = %d\n", h->num_recv_i);
3✔
1746
        printf("END\n");
3✔
1747

1748
        if (!sent_charts) {
3✔
1749
            printf("CHART fping.%s_quality '' 'FPing Quality' percentage '%s' fping.quality area 110010 %.0f\n", h->name, h->host, report_interval / 1e9);
3✔
1750
            printf("DIMENSION returned '' absolute 1 1\n");
3✔
1751
            /* printf("DIMENSION lost '' absolute 1 1\n"); */
1752
        }
1✔
1753

1754
        printf("BEGIN fping.%s_quality\n", h->name);
3✔
1755
        /*
1756
        if( h->num_recv_i <= h->num_sent_i )
1757
            printf("SET lost = %d\n", h->num_sent_i > 0 ? ( ( h->num_sent_i - h->num_recv_i ) * 100 ) / h->num_sent_i : 0 );
1758
        else
1759
            printf("SET lost = 0\n");
1760
*/
1761

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

1765
        if (!sent_charts) {
3✔
1766
            printf("CHART fping.%s_latency '' 'FPing Latency' ms '%s' fping.latency area 110000 %.0f\n", h->name, h->host, report_interval / 1e9);
3✔
1767
            printf("DIMENSION min minimum absolute 1 1000000\n");
3✔
1768
            printf("DIMENSION max maximum absolute 1 1000000\n");
3✔
1769
            printf("DIMENSION avg average absolute 1 1000000\n");
3✔
1770
        }
1✔
1771

1772
        printf("BEGIN fping.%s_latency\n", h->name);
3✔
1773
        if (h->num_recv_i) {
3✔
1774
            avg = h->total_time_i / h->num_recv_i;
3✔
1775
            printf("SET min = %" PRId64 "\n", h->min_reply_i);
3✔
1776
            printf("SET avg = %" PRId64 "\n", avg);
3✔
1777
            printf("SET max = %" PRId64 "\n", h->max_reply_i);
3✔
1778
        }
1✔
1779
        printf("END\n");
3✔
1780

1781
        stats_reset_interval(h);
3✔
1782
    }
1✔
1783

1784
    sent_charts = 1;
3✔
1785
}
3✔
1786

1787
/************************************************************
1788

1789
  Function: print_per_system_splits
1790

1791
*************************************************************
1792

1793
  Inputs:  void (none)
1794

1795
  Description:
1796

1797

1798
************************************************************/
1799

1800
void print_per_system_splits(void)
39✔
1801
{
1802
    int i, avg, outage_ms_i;
1803
    HOST_ENTRY *h;
1804
    struct tm *curr_tm;
1805

1806
    if (verbose_flag || per_recv_flag)
39✔
1807
        fprintf(stderr, "\n");
×
1808

1809
    update_current_time();
39✔
1810
    curr_tm = localtime((time_t *)&current_time.tv_sec);
39✔
1811
    fprintf(stderr, "[%2.2d:%2.2d:%2.2d]\n", curr_tm->tm_hour,
52✔
1812
        curr_tm->tm_min, curr_tm->tm_sec);
13✔
1813

1814
    for (i = 0; i < num_hosts; i++) {
78✔
1815
        h = table[i];
39✔
1816
        fprintf(stderr, "%-*s :", max_hostname_len, h->host);
39✔
1817

1818
        if (h->num_recv_i <= h->num_sent_i) {
39✔
1819
            fprintf(stderr, " xmt/rcv/%%loss = %d/%d/%d%%",
52✔
1820
                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✔
1821

1822
            if (outage_flag) {
39✔
1823
                /* Time outage  */
1824
                outage_ms_i = (h->num_sent_i - h->num_recv_i) * perhost_interval / 1e6;
12✔
1825
                fprintf(stderr, ", outage(ms) = %d", outage_ms_i);
12✔
1826
            }
4✔
1827
        }
13✔
1828
        else {
1829
            fprintf(stderr, " xmt/rcv/%%return = %d/%d/%d%%",
×
1830
                h->num_sent_i, h->num_recv_i, h->num_sent_i > 0 ? ((h->num_recv_i * 100) / h->num_sent_i) : 0);
×
1831
        }
1832

1833
        if (h->num_recv_i) {
39✔
1834
            avg = h->total_time_i / h->num_recv_i;
27✔
1835
            fprintf(stderr, ", min/avg/max = %s", sprint_tm(h->min_reply_i));
27✔
1836
            fprintf(stderr, "/%s", sprint_tm(avg));
27✔
1837
            fprintf(stderr, "/%s", sprint_tm(h->max_reply_i));
27✔
1838
        }
9✔
1839

1840
        fprintf(stderr, "\n");
39✔
1841
        if (!cumulative_stats_flag) {
39✔
1842
            stats_reset_interval(h);
27✔
1843
        }
9✔
1844
    }
13✔
1845
}
39✔
1846

1847
/************************************************************
1848

1849
  Function: print_global_stats
1850

1851
*************************************************************
1852

1853
  Inputs:  void (none)
1854

1855
  Description:
1856

1857

1858
************************************************************/
1859

1860
void print_global_stats(void)
6✔
1861
{
1862
    fprintf(stderr, "\n");
6✔
1863
    fprintf(stderr, " %7d targets\n", num_hosts);
6✔
1864
    fprintf(stderr, " %7d alive\n", num_alive);
6✔
1865
    fprintf(stderr, " %7d unreachable\n", num_unreachable);
6✔
1866
    fprintf(stderr, " %7d unknown addresses\n", num_noaddress);
6✔
1867
    fprintf(stderr, "\n");
6✔
1868
    fprintf(stderr, " %7d timeouts (waiting for response)\n", num_timeout);
6✔
1869
    fprintf(stderr, " %7d ICMP Echos sent\n", num_pingsent);
6✔
1870
    fprintf(stderr, " %7d ICMP Echo Replies received\n", num_pingreceived);
6✔
1871
    fprintf(stderr, " %7d other ICMP received\n", num_othericmprcvd);
6✔
1872
    fprintf(stderr, "\n");
6✔
1873

1874
    if (total_replies == 0) {
6✔
1875
        min_reply = 0;
3✔
1876
        max_reply = 0;
3✔
1877
        total_replies = 1;
3✔
1878
        sum_replies = 0;
3✔
1879
    }
1✔
1880

1881
    fprintf(stderr, " %s ms (min round trip time)\n", sprint_tm(min_reply));
6✔
1882
    fprintf(stderr, " %s ms (avg round trip time)\n",
8✔
1883
        sprint_tm(sum_replies / total_replies));
2✔
1884
    fprintf(stderr, " %s ms (max round trip time)\n", sprint_tm(max_reply));
6✔
1885
    fprintf(stderr, " %12.3f sec (elapsed real time)\n",
8✔
1886
        (end_time - start_time) / 1e9);
6✔
1887
    fprintf(stderr, "\n");
6✔
1888
}
6✔
1889

1890
/************************************************************
1891

1892
  Function: send_ping
1893

1894
*************************************************************
1895

1896
  Inputs:  int s, HOST_ENTRY *h
1897

1898
  Description:
1899

1900
  Compose and transmit an ICMP_ECHO REQUEST packet.  The IP packet
1901
  will be added on by the kernel.  The ID field is our UNIX process ID,
1902
  and the sequence number is an index into an array of outstanding
1903
  ping requests. The sequence number will later be used to quickly
1904
  figure out who the ping reply came from.
1905

1906
************************************************************/
1907

1908
int send_ping(HOST_ENTRY *h, int index)
556✔
1909
{
1910
    int n;
1911
    int myseq;
1912
    int ret = 1;
556✔
1913

1914
    update_current_time();
556✔
1915
    h->last_send_time = current_time_ns;
556✔
1916
    myseq = seqmap_add(h->i, index, current_time_ns);
556✔
1917

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

1920
    if (h->saddr.ss_family == AF_INET && socket4 >= 0) {
556✔
1921
        n = socket_sendto_ping_ipv4(socket4, (struct sockaddr *)&h->saddr, h->saddr_len, myseq, ident4);
497✔
1922
    }
159✔
1923
#ifdef IPV6
1924
    else if (h->saddr.ss_family == AF_INET6 && socket6 >= 0) {
59✔
1925
        n = socket_sendto_ping_ipv6(socket6, (struct sockaddr *)&h->saddr, h->saddr_len, myseq, ident6);
59✔
1926
    }
15✔
1927
#endif
1928
    else {
1929
        return 0;
×
1930
    }
1931

1932
    /* error sending? */
1933
    if (
382✔
1934
        (n < 0)
174✔
1935
#if defined(EHOSTDOWN)
1936
        && errno != EHOSTDOWN
180✔
1937
#endif
1938
    ) {
1939
        if (verbose_flag) {
6✔
1940
            print_warning("%s: error while sending ping: %s\n", h->host, strerror(errno));
×
1941
        }
1942
        else {
1943
            dbg_printf("%s: error while sending ping: %s\n", h->host, strerror(errno));
1944
        }
1945

1946
        h->num_sent++;
6✔
1947
        h->num_sent_i++;
6✔
1948
        if (!loop_flag)
6✔
1949
            h->resp_times[index] = RESP_ERROR;
6✔
1950

1951
        ret = 0;
6✔
1952
    }
1953
    else {
1954
        /* schedule timeout */
1955
        host_add_timeout_event(h, index, current_time_ns + h->timeout);
550✔
1956

1957
        /* mark this trial as outstanding */
1958
        if (!loop_flag) {
550✔
1959
            h->resp_times[index] = RESP_WAITING;
550✔
1960
        }
174✔
1961
    }
1962

1963
    num_pingsent++;
556✔
1964
    last_send_time = h->last_send_time;
556✔
1965

1966
    return (ret);
556✔
1967
}
174✔
1968

1969
int socket_can_read(struct timeval *timeout)
1,742✔
1970
{
1971
    int nfound;
1972
    fd_set readset;
1973
    int socketmax;
1974

1975
#ifndef IPV6
1976
    socketmax = socket4;
1977
#else
1978
    socketmax = socket4 > socket6 ? socket4 : socket6;
1,742✔
1979
#endif
1980

1981
select_again:
1,280✔
1982
    FD_ZERO(&readset);
11,998✔
1983
    if (socket4 >= 0)
1,742✔
1984
        FD_SET(socket4, &readset);
1,742✔
1985
#ifdef IPV6
1986
    if (socket6 >= 0)
1,742✔
1987
        FD_SET(socket6, &readset);
1,742✔
1988
#endif
1989

1990
    nfound = select(socketmax + 1, &readset, NULL, NULL, timeout);
1,742✔
1991
    if (nfound < 0) {
1,742✔
1992
        if (errno == EINTR) {
×
1993
            /* interrupted system call: redo the select */
1994
            goto select_again;
×
1995
        }
1996
        else {
1997
            perror("select");
×
1998
        }
1999
    }
2000

2001
    if (nfound > 0) {
1,742✔
2002
        if (socket4 >= 0 && FD_ISSET(socket4, &readset)) {
810✔
2003
            return socket4;
692✔
2004
        }
2005
#ifdef IPV6
2006
        if (socket6 >= 0 && FD_ISSET(socket6, &readset)) {
118✔
2007
            return socket6;
118✔
2008
        }
2009
#endif
2010
    }
2011

2012
    return -1;
932✔
2013
}
462✔
2014

2015
int receive_packet(int64_t wait_time,
1,742✔
2016
    int64_t *reply_timestamp,
2017
    struct sockaddr *reply_src_addr,
2018
    size_t reply_src_addr_len,
2019
    char *reply_buf,
2020
    size_t reply_buf_len)
2021
{
2022
    struct timeval to;
2023
    int s = 0;
1,742✔
2024
    int recv_len;
2025
    static unsigned char msg_control[40];
2026
    struct iovec msg_iov = {
2,666✔
2027
        reply_buf,
462✔
2028
        reply_buf_len
462✔
2029
    };
2030
    struct msghdr recv_msghdr = {0};
1,742✔
2031
    recv_msghdr.msg_name = reply_src_addr;
1,742✔
2032
    recv_msghdr.msg_namelen = reply_src_addr_len;
1,742✔
2033
    recv_msghdr.msg_iov = &msg_iov;
1,742✔
2034
    recv_msghdr.msg_iovlen = 1;
1,742✔
2035
    recv_msghdr.msg_control = &msg_control;
1,742✔
2036
    recv_msghdr.msg_controllen = sizeof(msg_control);
1,742✔
2037
#if HAVE_SO_TIMESTAMPNS
2038
    struct cmsghdr *cmsg;
2039
#endif
2040

2041
    /* Wait for a socket to become ready */
2042
    if (wait_time) {
1,742✔
2043
        to.tv_sec = wait_time / UINT64_C(1000000000);
932✔
2044
        to.tv_usec = (wait_time % UINT64_C(1000000000)) / 1000 + 1;
932✔
2045
    }
296✔
2046
    else {
2047
        to.tv_sec = 0;
810✔
2048
        to.tv_usec = 0;
810✔
2049
    }
2050
    s = socket_can_read(&to);
1,742✔
2051
    if (s == -1) {
1,742✔
2052
        return 0; /* timeout */
932✔
2053
    }
2054

2055
    recv_len = recvmsg(s, &recv_msghdr, MSG_TRUNC);
810✔
2056
    if (recv_len <= 0) {
810✔
2057
        return 0;
×
2058
    }
2059

2060
#if HAVE_SO_TIMESTAMPNS
2061
    /* ancilliary data */
2062
    {
2063
        struct timespec reply_timestamp_ts;
2064
        for (cmsg = CMSG_FIRSTHDR(&recv_msghdr);
966✔
2065
             cmsg != NULL;
644✔
2066
             cmsg = CMSG_NXTHDR(&recv_msghdr, cmsg)) {
644✔
2067
            if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPNS) {
644✔
2068
                memcpy(&reply_timestamp_ts, CMSG_DATA(cmsg), sizeof(reply_timestamp_ts));
644✔
2069
                *reply_timestamp = timespec_ns(&reply_timestamp_ts);
644✔
2070
            }
2071
        }
2072
    }
2073
#endif
2074

2075
#if defined(DEBUG) || defined(_DEBUG)
2076
    if (randomly_lose_flag) {
2077
        if ((random() & 0x07) <= lose_factor)
2078
            return 0;
2079
    }
2080
#endif
2081

2082
    return recv_len;
810✔
2083
}
462✔
2084

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

2099
    if (!success) {
550✔
2100
        if (!loop_flag && index >= 0) {
77✔
2101
            h->resp_times[index] = RESP_TIMEOUT;
77✔
2102
        }
23✔
2103
        num_timeout++;
77✔
2104
        return;
77✔
2105
    }
2106

2107
    /* received count */
2108
    h->num_recv++;
473✔
2109
    h->num_recv_i++;
473✔
2110

2111
    /* maximum */
2112
    if (!h->max_reply || latency > h->max_reply) {
473✔
2113
        h->max_reply = latency;
321✔
2114
    }
106✔
2115
    if (!h->max_reply_i || latency > h->max_reply_i) {
473✔
2116
        h->max_reply_i = latency;
342✔
2117
    }
112✔
2118

2119
    /* minimum */
2120
    if (!h->min_reply || latency < h->min_reply) {
473✔
2121
        h->min_reply = latency;
248✔
2122
    }
77✔
2123
    if (!h->min_reply_i || latency < h->min_reply_i) {
473✔
2124
        h->min_reply_i = latency;
273✔
2125
    }
86✔
2126

2127
    /* total time (for average) */
2128
    h->total_time += latency;
473✔
2129
    h->total_time_i += latency;
473✔
2130

2131
    /* response time per-packet (count mode) */
2132
    if (!loop_flag && index >= 0) {
473✔
2133
        h->resp_times[index] = latency;
473✔
2134
    }
151✔
2135
}
174✔
2136

2137
/* stats_reset_interval: reset interval statistics
2138
 * h: host entry to update
2139
 */
2140
void stats_reset_interval(HOST_ENTRY *h)
30✔
2141
{
2142
    h->num_sent_i = 0;
30✔
2143
    h->num_recv_i = 0;
30✔
2144
    h->max_reply_i = 0;
30✔
2145
    h->min_reply_i = 0;
30✔
2146
    h->total_time_i = 0;
30✔
2147
}
30✔
2148

2149
int decode_icmp_ipv4(
692✔
2150
    struct sockaddr *response_addr,
2151
    size_t response_addr_len,
2152
    char *reply_buf,
2153
    size_t reply_buf_len,
2154
    unsigned short *id,
2155
    unsigned short *seq)
2156
{
2157
    struct icmp *icp;
2158
    int hlen = 0;
692✔
2159

2160
    if (!using_sock_dgram4) {
692✔
2161
        struct ip *ip = (struct ip *)reply_buf;
692✔
2162

2163
#if defined(__alpha__) && __STDC__ && !defined(__GLIBC__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
2164
        /* The alpha headers are decidedly broken.
2165
         * Using an ANSI compiler, it provides ip_vhl instead of ip_hl and
2166
         * ip_v.  So, to get ip_hl, we mask off the bottom four bits.
2167
         */
2168
        hlen = (ip->ip_vhl & 0x0F) << 2;
2169
#else
2170
        hlen = ip->ip_hl << 2;
692✔
2171
#endif
2172
    }
136✔
2173

2174
    if (reply_buf_len < hlen + ICMP_MINLEN) {
692✔
2175
        /* too short */
2176
        if (verbose_flag) {
×
2177
            char buf[INET6_ADDRSTRLEN];
2178
            getnameinfo(response_addr, response_addr_len, buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
×
2179
            printf("received packet too short for ICMP (%d bytes from %s)\n", (int)reply_buf_len, buf);
×
2180
        }
2181
        return -1;
×
2182
    }
2183

2184
    icp = (struct icmp *)(reply_buf + hlen);
692✔
2185

2186
    if (icp->icmp_type != ICMP_ECHOREPLY) {
692✔
2187
        /* Handle other ICMP packets */
2188
        struct icmp *sent_icmp;
2189
        SEQMAP_VALUE *seqmap_value;
2190
        char addr_ascii[INET6_ADDRSTRLEN];
2191
        HOST_ENTRY *h;
2192

2193
        /* reply icmp packet (hlen + ICMP_MINLEN) followed by "sent packet" (ip + icmp headers) */
2194
        if (reply_buf_len < hlen + ICMP_MINLEN + sizeof(struct ip) + ICMP_MINLEN) {
278✔
2195
            /* discard ICMP message if we can't tell that it was caused by us (i.e. if the "sent packet" is not included). */
2196
            return -1;
×
2197
        }
2198

2199
        sent_icmp = (struct icmp *)(reply_buf + hlen + ICMP_MINLEN + sizeof(struct ip));
278✔
2200

2201
        if (sent_icmp->icmp_type != ICMP_ECHO || sent_icmp->icmp_id != ident4) {
278✔
2202
            /* not caused by us */
2203
            return -1;
278✔
2204
        }
2205

2206
        seqmap_value = seqmap_fetch(ntohs(sent_icmp->icmp_seq), current_time_ns);
×
2207
        if (seqmap_value == NULL) {
×
2208
            return -1;
×
2209
        }
2210

2211
        getnameinfo(response_addr, response_addr_len, addr_ascii, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
×
2212

2213
        switch (icp->icmp_type) {
×
2214
        case ICMP_UNREACH:
2215
            h = table[seqmap_value->host_nr];
×
2216
            if (icp->icmp_code > ICMP_UNREACH_MAXTYPE) {
×
2217
                print_warning("ICMP Unreachable (Invalid Code) from %s for ICMP Echo sent to %s",
×
2218
                    addr_ascii, h->host);
2219
            }
2220
            else {
2221
                print_warning("%s from %s for ICMP Echo sent to %s",
×
2222
                    icmp_unreach_str[icp->icmp_code], addr_ascii, h->host);
×
2223
            }
2224

2225
            print_warning("\n");
×
2226
            num_othericmprcvd++;
×
2227
            break;
×
2228

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

2247
        return -1;
×
2248
    }
2249

2250
    *id = icp->icmp_id;
414✔
2251
    *seq = ntohs(icp->icmp_seq);
414✔
2252

2253
    return hlen;
414✔
2254
}
136✔
2255

2256
#ifdef IPV6
2257
int decode_icmp_ipv6(
118✔
2258
    struct sockaddr *response_addr,
2259
    size_t response_addr_len,
2260
    char *reply_buf,
2261
    size_t reply_buf_len,
2262
    unsigned short *id,
2263
    unsigned short *seq)
2264
{
2265
    struct icmp6_hdr *icp;
2266

2267
    if (reply_buf_len < sizeof(struct icmp6_hdr)) {
118✔
2268
        if (verbose_flag) {
×
2269
            char buf[INET6_ADDRSTRLEN];
2270
            getnameinfo(response_addr, response_addr_len, buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
×
2271
            printf("received packet too short for ICMP (%d bytes from %s)\n", (int)reply_buf_len, buf);
×
2272
        }
2273
        return 0; /* too short */
×
2274
    }
2275

2276
    icp = (struct icmp6_hdr *)reply_buf;
118✔
2277

2278
    if (icp->icmp6_type != ICMP6_ECHO_REPLY) {
118✔
2279
        /* Handle other ICMP packets */
2280
        struct icmp6_hdr *sent_icmp;
2281
        SEQMAP_VALUE *seqmap_value;
2282
        char addr_ascii[INET6_ADDRSTRLEN];
2283
        HOST_ENTRY *h;
2284

2285
        /* reply icmp packet (ICMP_MINLEN) followed by "sent packet" (ip + icmp headers) */
2286
        if (reply_buf_len < ICMP_MINLEN + sizeof(struct ip) + ICMP_MINLEN) {
59✔
2287
            /* discard ICMP message if we can't tell that it was caused by us (i.e. if the "sent packet" is not included). */
2288
            return 0;
×
2289
        }
2290

2291
        sent_icmp = (struct icmp6_hdr *)(reply_buf + sizeof(struct icmp6_hdr) + sizeof(struct ip));
59✔
2292

2293
        if (sent_icmp->icmp6_type != ICMP_ECHO || sent_icmp->icmp6_id != ident6) {
59✔
2294
            /* not caused by us */
2295
            return 0;
59✔
2296
        }
2297

2298
        seqmap_value = seqmap_fetch(ntohs(sent_icmp->icmp6_seq), current_time_ns);
×
2299
        if (seqmap_value == NULL) {
×
2300
            return 0;
×
2301
        }
2302

2303
        getnameinfo(response_addr, response_addr_len, addr_ascii, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
×
2304

2305
        switch (icp->icmp6_type) {
×
2306
        case ICMP_UNREACH:
2307
            h = table[seqmap_value->host_nr];
×
2308
            if (icp->icmp6_code > ICMP_UNREACH_MAXTYPE) {
×
2309
                print_warning("ICMP Unreachable (Invalid Code) from %s for ICMP Echo sent to %s",
×
2310
                    addr_ascii, h->host);
2311
            }
2312
            else {
2313
                print_warning("%s from %s for ICMP Echo sent to %s",
×
2314
                    icmp_unreach_str[icp->icmp6_code], addr_ascii, h->host);
×
2315
            }
2316

2317
            print_warning("\n");
×
2318
            num_othericmprcvd++;
×
2319
            break;
×
2320

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

2339
        return 0;
×
2340
    }
2341

2342
    *id = icp->icmp6_id;
59✔
2343
    *seq = ntohs(icp->icmp6_seq);
59✔
2344

2345
    return 1;
59✔
2346
}
30✔
2347
#endif
2348

2349
int wait_for_reply(int64_t wait_time)
1,742✔
2350
{
2351
    int result;
2352
    static char buffer[RECV_BUFSIZE];
2353
    struct sockaddr_storage response_addr;
2354
    int n, avg;
2355
    HOST_ENTRY *h;
2356
    int64_t this_reply;
2357
    int this_count;
2358
    int64_t recv_time = 0;
1,742✔
2359
    SEQMAP_VALUE *seqmap_value;
2360
    unsigned short id;
2361
    unsigned short seq;
2362

2363
    /* Receive packet */
2364
    result = receive_packet(wait_time, /* max. wait time, in ns */
1,742✔
2365
        &recv_time, /* reply_timestamp */
2366
        (struct sockaddr *)&response_addr, /* reply_src_addr */
2367
        sizeof(response_addr), /* reply_src_addr_len */
2368
        buffer, /* reply_buf */
2369
        sizeof(buffer) /* reply_buf_len */
2370
    );
2371

2372
    if (result <= 0) {
1,742✔
2373
        return 0;
932✔
2374
    }
2375

2376
    update_current_time();
810✔
2377
    if (recv_time == 0)
810✔
2378
        recv_time = current_time_ns;
166✔
2379

2380
    /* Process ICMP packet and retrieve id/seq */
2381
    if (response_addr.ss_family == AF_INET) {
810✔
2382
        int ip_hlen = decode_icmp_ipv4(
692✔
2383
            (struct sockaddr *)&response_addr,
2384
            sizeof(response_addr),
2385
            buffer,
2386
            sizeof(buffer),
2387
            &id,
2388
            &seq);
2389
        if (ip_hlen < 0) {
692✔
2390
            return 1;
278✔
2391
        }
2392
        if (id != ident4) {
414✔
2393
            return 1; /* packet received, but not the one we are looking for! */
×
2394
        }
2395
        if (!using_sock_dgram4) {
414✔
2396
            /* do not include IP header in returned size, to be consistent with ping(8) and also
2397
             * with fping with IPv6 hosts */
2398
            result -= ip_hlen;
414✔
2399
        }
136✔
2400
    }
136✔
2401
#ifdef IPV6
2402
    else if (response_addr.ss_family == AF_INET6) {
118✔
2403
        if (!decode_icmp_ipv6(
118✔
2404
                (struct sockaddr *)&response_addr,
2405
                sizeof(response_addr),
2406
                buffer,
2407
                sizeof(buffer),
2408
                &id,
2409
                &seq)) {
2410
            return 1;
59✔
2411
        }
2412
        if (id != ident6) {
59✔
2413
            return 1; /* packet received, but not the one we are looking for! */
×
2414
        }
2415
    }
15✔
2416
#endif
2417
    else {
2418
        return 1;
×
2419
    }
2420

2421
    seqmap_value = seqmap_fetch(seq, current_time_ns);
473✔
2422
    if (seqmap_value == NULL) {
473✔
2423
        return 1;
×
2424
    }
2425

2426
    /* find corresponding host_entry */
2427
    n = seqmap_value->host_nr;
473✔
2428
    h = table[n];
473✔
2429
    this_count = seqmap_value->ping_count;
473✔
2430
    this_reply = recv_time - seqmap_value->ping_ts;
473✔
2431

2432
    /* update stats that include invalid replies */
2433
    h->num_recv_total++;
473✔
2434
    num_pingreceived++;
473✔
2435

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

2438
    /* discard duplicates */
2439
    if (!loop_flag && h->resp_times[this_count] >= 0) {
473✔
2440
        if (!per_recv_flag) {
×
2441
            fprintf(stderr, "%s : duplicate for [%d], %d bytes, %s ms",
×
2442
                h->host, this_count, result, sprint_tm(this_reply));
2443

2444
            if (addr_cmp((struct sockaddr *)&response_addr, (struct sockaddr *)&h->saddr)) {
×
2445
                char buf[INET6_ADDRSTRLEN];
2446
                getnameinfo((struct sockaddr *)&response_addr, sizeof(response_addr), buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
×
2447
                fprintf(stderr, " [<- %s]", buf);
×
2448
            }
2449
            fprintf(stderr, "\n");
×
2450
        }
2451
        return 1;
×
2452
    }
2453

2454
    /* discard reply if delay is larger than timeout
2455
     * (see also: github #32) */
2456
    if (this_reply > h->timeout) {
473✔
2457
        return 1;
×
2458
    }
2459

2460
    /* update stats */
2461
    stats_add(h, this_count, 1, this_reply);
473✔
2462
    // TODO: move to stats_add?
2463
    if (!max_reply || this_reply > max_reply)
473✔
2464
        max_reply = this_reply;
273✔
2465
    if (!min_reply || this_reply < min_reply)
473✔
2466
        min_reply = this_reply;
198✔
2467
    sum_replies += this_reply;
473✔
2468
    total_replies++;
473✔
2469

2470
    /* initialize timeout to initial timeout (without backoff) */
2471
    h->timeout = timeout;
473✔
2472

2473
    /* remove timeout event */
2474
    struct event *timeout_event = host_get_timeout_event(h, this_count);
473✔
2475
    if (timeout_event) {
473✔
2476
        ev_remove(&event_queue_timeout, timeout_event);
473✔
2477
    }
151✔
2478

2479
    /* print "is alive" */
2480
    if (h->num_recv == 1) {
473✔
2481
        num_alive++;
211✔
2482
        if (fast_reachable && num_alive >= min_reachable)
211✔
2483
                finish_requested = 1;
3✔
2484

2485
        if (verbose_flag || alive_flag) {
211✔
2486
            printf("%s", h->host);
107✔
2487

2488
            if (verbose_flag)
107✔
2489
                printf(" is alive");
101✔
2490

2491
            if (elapsed_flag)
107✔
2492
                printf(" (%s ms)", sprint_tm(this_reply));
3✔
2493

2494
            if (addr_cmp((struct sockaddr *)&response_addr, (struct sockaddr *)&h->saddr)) {
107✔
2495
                char buf[INET6_ADDRSTRLEN];
2496
                getnameinfo((struct sockaddr *)&response_addr, sizeof(response_addr), buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
2✔
2497
                fprintf(stderr, " [<- %s]", buf);
2✔
2498
            }
2499

2500
            printf("\n");
107✔
2501
        }
31✔
2502
    }
65✔
2503

2504
    /* print received ping (unless --quiet) */
2505
    if (per_recv_flag) {
473✔
2506
        if (timestamp_flag) {
105✔
2507
            print_timestamp_format(recv_time, timestamp_format_flag);
24✔
2508
        }
8✔
2509
        avg = h->total_time / h->num_recv;
105✔
2510
        printf("%-*s : [%d], %d bytes, %s ms",
105✔
2511
            max_hostname_len, h->host, this_count, result, sprint_tm(this_reply));
35✔
2512
        printf(" (%s avg, ", sprint_tm(avg));
105✔
2513

2514
        if (h->num_recv <= h->num_sent) {
105✔
2515
            printf("%d%% loss)",
105✔
2516
                ((h->num_sent - h->num_recv) * 100) / h->num_sent);
105✔
2517
        }
35✔
2518
        else {
2519
            printf("%d%% return)",
×
2520
                (h->num_recv_total * 100) / h->num_sent);
×
2521
        }
2522

2523
        if (addr_cmp((struct sockaddr *)&response_addr, (struct sockaddr *)&h->saddr)) {
105✔
2524
            char buf[INET6_ADDRSTRLEN];
2525
            getnameinfo((struct sockaddr *)&response_addr, sizeof(response_addr), buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
×
2526
            fprintf(stderr, " [<- %s]", buf);
×
2527
        }
2528

2529
        printf("\n");
105✔
2530
    }
35✔
2531

2532
    return 1;
473✔
2533
}
462✔
2534

2535
/************************************************************
2536

2537
  Function: add_name
2538

2539
*************************************************************
2540

2541
  Inputs:  char* name
2542

2543
  Description:
2544

2545
  process input name for addition to target list
2546
  name can turn into multiple targets via multiple interfaces (-m)
2547
  or via NIS groups
2548

2549
************************************************************/
2550

2551
void add_name(char *name)
265✔
2552
{
2553
    struct addrinfo *res0, *res, hints;
2554
    int ret_ga;
2555
    char *printname;
2556
    char namebuf[256];
2557
    char addrbuf[256];
2558

2559
    /* getaddrinfo */
2560
    memset(&hints, 0, sizeof(struct addrinfo));
265✔
2561
    hints.ai_flags = AI_UNUSABLE;
265✔
2562
    hints.ai_socktype = SOCK_RAW;
265✔
2563
    hints.ai_family = hints_ai_family;
265✔
2564
    if (hints_ai_family == AF_INET) {
265✔
2565
        hints.ai_protocol = IPPROTO_ICMP;
21✔
2566
    }
7✔
2567
#ifdef IPV6
2568
    else if (hints_ai_family == AF_INET6) {
244✔
2569
        hints.ai_protocol = IPPROTO_ICMPV6;
5✔
2570
    }
1✔
2571
#endif
2572
    else {
2573
        hints.ai_socktype = SOCK_STREAM;
239✔
2574
        hints.ai_protocol = 0;
239✔
2575
    }
2576
    ret_ga = getaddrinfo(name, NULL, &hints, &res0);
265✔
2577
    if (ret_ga) {
265✔
2578
        if (!quiet_flag)
9✔
2579
            print_warning("%s: %s\n", name, gai_strerror(ret_ga));
9✔
2580
        num_noaddress++;
9✔
2581
        return;
9✔
2582
    }
2583

2584
    /* NOTE: we could/should loop with res on all addresses like this:
2585
     * for (res = res0; res; res = res->ai_next) {
2586
     * We don't do it yet, however, because is is an incompatible change
2587
     * (need to implement a separate option for this)
2588
     */
2589
    for (res = res0; res; res = res->ai_next) {
256✔
2590
        /* name_flag: addr -> name lookup requested) */
2591
        if (name_flag || rdns_flag) {
256✔
2592
            int do_rdns = rdns_flag ? 1 : 0;
×
2593
            if (name_flag) {
×
2594
                /* Was it a numerical address? Only then do a rdns-query */
2595
                struct addrinfo *nres;
2596
                hints.ai_flags = AI_NUMERICHOST;
×
2597
                if (getaddrinfo(name, NULL, &hints, &nres) == 0) {
×
2598
                    do_rdns = 1;
×
2599
                    freeaddrinfo(nres);
×
2600
                }
2601
            }
2602

2603
            if (do_rdns && getnameinfo(res->ai_addr, res->ai_addrlen, namebuf, sizeof(namebuf) / sizeof(char), NULL, 0, 0) == 0) {
×
2604
                printname = namebuf;
×
2605
            }
2606
            else {
2607
                printname = name;
×
2608
            }
2609
        }
2610
        else {
2611
            printname = name;
256✔
2612
        }
2613

2614
        /* addr_flag: name -> addr lookup requested */
2615
        if (addr_flag) {
256✔
2616
            int ret;
2617
            ret = getnameinfo(res->ai_addr, res->ai_addrlen, addrbuf,
3✔
2618
                sizeof(addrbuf) / sizeof(char), NULL, 0, NI_NUMERICHOST);
2619
            if (ret) {
3✔
2620
                if (!quiet_flag) {
×
2621
                    print_warning("%s: can't forward-lookup address (%s)\n", name, gai_strerror(ret));
×
2622
                }
2623
                continue;
×
2624
            }
2625

2626
            if (name_flag || rdns_flag) {
3✔
2627
                char nameaddrbuf[512 + 3];
2628
                snprintf(nameaddrbuf, sizeof(nameaddrbuf) / sizeof(char), "%s (%s)", printname, addrbuf);
×
2629
                add_addr(name, nameaddrbuf, res->ai_addr, res->ai_addrlen);
×
2630
            }
2631
            else {
2632
                add_addr(name, addrbuf, res->ai_addr, res->ai_addrlen);
3✔
2633
            }
2634
        }
1✔
2635
        else {
2636
            add_addr(name, printname, res->ai_addr, res->ai_addrlen);
253✔
2637
        }
2638

2639
        if (!multif_flag) {
256✔
2640
            break;
256✔
2641
        }
2642
    }
2643

2644
    freeaddrinfo(res0);
256✔
2645
}
81✔
2646

2647
/************************************************************
2648

2649
  Function: add_addr
2650

2651
*************************************************************
2652

2653
  Description:
2654

2655
  add single address to list of hosts to be pinged
2656

2657
************************************************************/
2658

2659
void add_addr(char *name, char *host, struct sockaddr *ipaddr, socklen_t ipaddr_len)
256✔
2660
{
2661
    HOST_ENTRY *p;
2662
    int n;
2663
    int64_t *i;
2664

2665
    p = (HOST_ENTRY *)calloc(1, sizeof(HOST_ENTRY));
256✔
2666
    if (!p)
256✔
2667
        crash_and_burn("can't allocate HOST_ENTRY");
×
2668

2669
    p->name = strdup(name);
256✔
2670
    p->host = strdup(host);
256✔
2671
    memcpy(&p->saddr, ipaddr, ipaddr_len);
256✔
2672
    p->saddr_len = ipaddr_len;
256✔
2673
    p->timeout = timeout;
256✔
2674
    p->min_reply = 0;
256✔
2675

2676
    if (netdata_flag) {
256✔
2677
        char *s = p->name;
3✔
2678
        while (*s) {
30✔
2679
            if (!isalnum(*s))
27✔
2680
                *s = '_';
9✔
2681
            s++;
27✔
2682
        }
2683
    }
1✔
2684

2685
    if (strlen(p->host) > max_hostname_len)
256✔
2686
        max_hostname_len = strlen(p->host);
181✔
2687

2688
    /* array for response time results */
2689
    if (!loop_flag) {
256✔
2690
        i = (int64_t *)malloc(trials * sizeof(int64_t));
256✔
2691
        if (!i)
256✔
2692
            crash_and_burn("can't allocate resp_times array");
×
2693

2694
        for (n = 1; n < trials; n++)
1,111✔
2695
            i[n] = RESP_UNUSED;
855✔
2696

2697
        p->resp_times = i;
256✔
2698
    }
78✔
2699

2700
    /* allocate event storage */
2701
    p->event_storage_ping = (struct event *)calloc(event_storage_count, sizeof(struct event));
256✔
2702
    p->event_storage_timeout = (struct event *)calloc(event_storage_count, sizeof(struct event));
256✔
2703

2704
    /* schedule first ping */
2705
    host_add_ping_event(p, 0, current_time_ns);
256✔
2706

2707
    num_hosts++;
256✔
2708
}
256✔
2709

2710
/************************************************************
2711

2712
  Function: crash_and_burn
2713

2714
*************************************************************
2715

2716
  Inputs:  char* message
2717

2718
  Description:
2719

2720
************************************************************/
2721

2722
void crash_and_burn(char *message)
×
2723
{
2724
    fprintf(stderr, "%s: %s\n", prog, message);
×
2725
    exit(4);
×
2726
}
2727

2728
/************************************************************
2729

2730
  Function: errno_crash_and_burn
2731

2732
*************************************************************
2733

2734
  Inputs:  char* message
2735

2736
  Description:
2737

2738
************************************************************/
2739

2740
void errno_crash_and_burn(char *message)
8✔
2741
{
2742
    fprintf(stderr, "%s: %s : %s\n", prog, message, strerror(errno));
8✔
2743
    exit(4);
8✔
2744
}
2745

2746
/************************************************************
2747

2748
  Function: print_warning
2749

2750
  Description: fprintf(stderr, ...), unless running with -q
2751

2752
*************************************************************/
2753

2754
void print_warning(char *format, ...)
9✔
2755
{
2756
    va_list args;
2757
    if (!quiet_flag) {
9✔
2758
        va_start(args, format);
9✔
2759
        vfprintf(stderr, format, args);
9✔
2760
        va_end(args);
9✔
2761
    }
3✔
2762
}
9✔
2763

2764
/************************************************************
2765

2766
  Function: sprint_tm
2767

2768
*************************************************************
2769

2770
  render nanosecond int64_t value into milliseconds string with three digits of
2771
  precision.
2772

2773
************************************************************/
2774

2775
const char *sprint_tm(int64_t ns)
678✔
2776
{
2777
    static char buf[10];
2778
    double t = (double)ns / 1e6;
678✔
2779

2780
    if (t < 0.0) {
678✔
2781
        /* negative (unexpected) */
2782
        sprintf(buf, "%.2g", t);
×
2783
    }
2784
    else if (t < 1.0) {
678✔
2785
        /* <= 0.99 ms */
2786
        sprintf(buf, "%.3f", t);
678✔
2787
    }
224✔
2788
    else if (t < 10.0) {
×
2789
        /* 1.00 - 9.99 ms */
2790
        sprintf(buf, "%.2f", t);
×
2791
    }
2792
    else if (t < 100.0) {
×
2793
        /* 10.0 - 99.9 ms */
2794
        sprintf(buf, "%.1f", t);
×
2795
    }
2796
    else if (t < 1000000.0) {
×
2797
        /* 100 - 1'000'000 ms */
2798
        sprintf(buf, "%.0f", t);
×
2799
    }
2800
    else {
2801
        sprintf(buf, "%.3e", t);
×
2802
    }
2803

2804
    return (buf);
678✔
2805
}
2806

2807
/************************************************************
2808

2809
  Function: addr_cmp
2810

2811
*************************************************************/
2812
int addr_cmp(struct sockaddr *a, struct sockaddr *b)
212✔
2813
{
2814
    if (a->sa_family != b->sa_family) {
212✔
2815
        return a->sa_family - b->sa_family;
×
2816
    }
2817
    else {
2818
        if (a->sa_family == AF_INET) {
212✔
2819
            return ((struct sockaddr_in *)a)->sin_addr.s_addr - ((struct sockaddr_in *)b)->sin_addr.s_addr;
180✔
2820
        }
2821
        else if (a->sa_family == AF_INET6) {
32✔
2822
            return memcmp(&((struct sockaddr_in6 *)a)->sin6_addr,
40✔
2823
                &((struct sockaddr_in6 *)b)->sin6_addr,
32✔
2824
                sizeof(((struct sockaddr_in6 *)a)->sin6_addr));
2825
        }
2826
    }
2827

2828
    return 0;
×
2829
}
66✔
2830

2831
void host_add_ping_event(HOST_ENTRY *h, int index, int64_t ev_time)
552✔
2832
{
2833
    struct event *event = &h->event_storage_ping[index % event_storage_count];
552✔
2834
    event->host = h;
552✔
2835
    event->ping_index = index;
552✔
2836
    event->ev_time = ev_time;
552✔
2837
    ev_enqueue(&event_queue_ping, event);
552✔
2838

2839
    dbg_printf("%s [%d]: add ping event in %.0f ms\n",
2840
        event->host->host, index, (ev_time - current_time_ns) / 1e6);
2841
}
552✔
2842

2843
void host_add_timeout_event(HOST_ENTRY *h, int index, int64_t ev_time)
550✔
2844
{
2845
    struct event *event = &h->event_storage_timeout[index % event_storage_count];
550✔
2846
    event->host = h;
550✔
2847
    event->ping_index = index;
550✔
2848
    event->ev_time = ev_time;
550✔
2849
    ev_enqueue(&event_queue_timeout, event);
550✔
2850

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

2855
struct event *host_get_timeout_event(HOST_ENTRY *h, int index)
473✔
2856
{
2857
    return &h->event_storage_timeout[index % event_storage_count];
473✔
2858
}
2859

2860
/************************************************************
2861

2862
  Function: ev_enqueue
2863

2864
  Enqueue an event
2865

2866
  The queue is sorted by event->ev_time, so that queue->first always points to
2867
  the earliest event.
2868

2869
  We start scanning the queue from the tail, because we assume
2870
  that new events mostly get inserted with a event time higher
2871
  than the others.
2872

2873
*************************************************************/
2874
void ev_enqueue(struct event_queue *queue, struct event *event)
1,102✔
2875
{
2876
    struct event *i;
2877
    struct event *i_prev;
2878

2879
    /* Empty list */
2880
    if (queue->last == NULL) {
1,102✔
2881
        event->ev_next = NULL;
842✔
2882
        event->ev_prev = NULL;
842✔
2883
        queue->first = event;
842✔
2884
        queue->last = event;
842✔
2885
        return;
842✔
2886
    }
2887

2888
    /* Insert on tail? */
2889
    if (event->ev_time - queue->last->ev_time >= 0) {
260✔
2890
        event->ev_next = NULL;
260✔
2891
        event->ev_prev = queue->last;
260✔
2892
        queue->last->ev_next = event;
260✔
2893
        queue->last = event;
260✔
2894
        return;
260✔
2895
    }
2896

2897
    /* Find insertion point */
2898
    i = queue->last;
×
2899
    while (1) {
2900
        i_prev = i->ev_prev;
×
2901
        if (i_prev == NULL || event->ev_time - i_prev->ev_time >= 0) {
×
2902
            event->ev_prev = i_prev;
×
2903
            event->ev_next = i;
×
2904
            i->ev_prev = event;
×
2905
            if (i_prev != NULL) {
×
2906
                i_prev->ev_next = event;
×
2907
            }
2908
            else {
2909
                queue->first = event;
×
2910
            }
2911
            return;
×
2912
        }
2913
        i = i_prev;
×
2914
    }
2915
}
348✔
2916

2917
/************************************************************
2918

2919
  Function: ev_dequeue
2920

2921
*************************************************************/
2922
struct event *ev_dequeue(struct event_queue *queue)
609✔
2923
{
2924
    struct event *dequeued;
2925

2926
    if (queue->first == NULL) {
609✔
2927
        return NULL;
×
2928
    }
2929
    dequeued = queue->first;
609✔
2930
    ev_remove(queue, dequeued);
609✔
2931

2932
    return dequeued;
609✔
2933
}
191✔
2934

2935
/************************************************************
2936

2937
  Function: ev_remove
2938

2939
*************************************************************/
2940
void ev_remove(struct event_queue *queue, struct event *event)
1,082✔
2941
{
2942
    if (queue->first == event) {
1,082✔
2943
        queue->first = event->ev_next;
1,073✔
2944
    }
339✔
2945
    if (queue->last == event) {
1,082✔
2946
        queue->last = event->ev_prev;
843✔
2947
    }
263✔
2948
    if (event->ev_prev) {
1,082✔
2949
        event->ev_prev->ev_next = event->ev_next;
9✔
2950
    }
3✔
2951
    if (event->ev_next) {
1,082✔
2952
        event->ev_next->ev_prev = event->ev_prev;
239✔
2953
    }
79✔
2954
    event->ev_prev = NULL;
1,082✔
2955
    event->ev_next = NULL;
1,082✔
2956
}
1,082✔
2957

2958
/************************************************************
2959

2960
  Function: print_human_readable_time from current_time_ns
2961

2962
*************************************************************/
2963
void print_timestamp_format(int64_t current_time_ns, int timestamp_format)
24✔
2964
{
2965
    char time_buffer[100];
2966
    time_t current_time_s;
2967
    struct tm *local_time;
2968

2969
    current_time_s = current_time_ns / 1000000000;
24✔
2970
    local_time = localtime(&current_time_s);
24✔
2971
    switch(timestamp_format) {
24✔
2972
        case 1:
4✔
2973
            // timestamp-format ctime
2974
            strftime(time_buffer, sizeof(time_buffer), "%c", local_time);
6✔
2975
            printf("[%s] ", time_buffer);
6✔
2976
            break;
6✔
2977
        case 2:
4✔
2978
            // timestamp-format iso
2979
            strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%dT%T%z", local_time);
6✔
2980
            printf("[%s] ", time_buffer);
6✔
2981
            break;
6✔
2982
        case 3:
4✔
2983
            // timestamp-format rfc3339
2984
            strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%d %H:%M:%S", local_time);
6✔
2985
            printf("[%s] ", time_buffer);
6✔
2986
            break;
6✔
2987
        default:
4✔
2988
            printf("[%.5f] ", (double)current_time_ns / 1e9);
6✔
2989
    }
2✔
2990
}
24✔
2991

2992
/************************************************************
2993

2994
  Function: usage
2995

2996
*************************************************************
2997

2998
  Inputs:  int: 0 if output on request, 1 if output because of wrong argument
2999

3000
  Description:
3001

3002
************************************************************/
3003

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