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

schweikert / fping / 9910980692

12 Jul 2024 04:19PM UTC coverage: 85.469% (-0.2%) from 85.622%
9910980692

push

github

auerswal
adjust generator limit to allow an IPv4 /15

1194 of 1397 relevant lines covered (85.47%)

229.88 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 131070 /* maximum number of hosts that -g can generate */
143

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

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

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

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

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

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

215
#define ICMP_UNREACH_MAXTYPE 15
216

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

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

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

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

264
#define EV_TYPE_PING 1
265
#define EV_TYPE_TIMEOUT 2
266

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

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

280
/*** globals ***/
281

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

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

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

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

310
unsigned int debugging = 0;
311

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

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

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

352
/* switches */
353
int generate_flag = 0; /* flag for IP list generation */
354
int verbose_flag, quiet_flag, stats_flag, unreachable_flag, alive_flag;
355
int elapsed_flag, version_flag, count_flag, loop_flag, netdata_flag;
356
int per_recv_flag, report_all_rtts_flag, name_flag, addr_flag, backoff_flag, rdns_flag;
357
int multif_flag, timeout_flag, fast_reachable;
358
int outage_flag = 0;
359
int timestamp_flag = 0;
360
int timestamp_format_flag = 0;
361
int random_data_flag = 0;
362
int cumulative_stats_flag = 0;
363
#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 add_addr_range_ipv4(unsigned long, unsigned long);
398
void print_warning(char *fmt, ...);
399
int addr_cmp(struct sockaddr *a, struct sockaddr *b);
400
void host_add_ping_event(HOST_ENTRY *h, int index, int64_t ev_time);
401
void host_add_timeout_event(HOST_ENTRY *h, int index, int64_t ev_time);
402
struct event *host_get_timeout_event(HOST_ENTRY *h, int index);
403
void stats_add(HOST_ENTRY *h, int index, int success, int64_t latency);
404
void update_current_time();
405
void print_timestamp_format(int64_t current_time_ns, int timestamp_format);
406

407
/************************************************************
408

409
  Function: p_setsockopt
410

411
*************************************************************
412

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

415
  Description:
416

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

420
************************************************************/
421

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

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

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

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

440
    return res;
×
441
}
442

443
/************************************************************
444

445
  Function: main
446

447
*************************************************************
448

449
  Inputs:  int argc, char** argv
450

451
  Description:
452

453
  Main program entry point
454

455
************************************************************/
456

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

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

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

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

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

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

503
    if (!suid && suid != getuid()) {
402✔
504
        /* *temporarily* drop privileges */
505
        if (seteuid(getuid()) == -1)
380✔
506
            perror("cannot setuid");
×
507
    }
116✔
508

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

515
    /* get command line options */
516

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

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

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

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

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

648
        case 'p':
62✔
649
            if (sscanf(optparse_state.optarg, "%f", &opt_value_float) != 1)
88✔
650
                usage(1);
6✔
651
            if (opt_value_float < 0) {
84✔
652
                usage(1);
3✔
653
            }
1✔
654
            perhost_interval = opt_value_float * 1000000;
82✔
655

656
            break;
82✔
657

658
        case 'c':
50✔
659
            if (!(count = (unsigned int)atoi(optparse_state.optarg)))
72✔
660
                usage(1);
6✔
661

662
            count_flag = 1;
68✔
663
            break;
68✔
664

665
        case 'C':
18✔
666
            if (!(count = (unsigned int)atoi(optparse_state.optarg)))
24✔
667
                usage(1);
6✔
668

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

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

677
            break;
6✔
678

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

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

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

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

706
            break;
24✔
707

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

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

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

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

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

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

740
        case 'B':
10✔
741
            if (!(backoff = atof(optparse_state.optarg)))
12✔
742
                usage(1);
6✔
743

744
            break;
8✔
745

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

750
        case 'D':
14✔
751
            timestamp_flag = 1;
21✔
752
            break;
21✔
753

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

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

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

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

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

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

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

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

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

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

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

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

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

818
            break;
2✔
819
#endif
820

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

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

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

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

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

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

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

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

907
    /* validate various option settings */
908

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

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

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

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

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

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

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

956
    if (count_flag) {
232✔
957
        if (verbose_flag)
82✔
958
            per_recv_flag = 1;
41✔
959

960
        alive_flag = unreachable_flag = verbose_flag = 0;
82✔
961
    }
26✔
962

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

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

970
    if (alive_flag || unreachable_flag || min_reachable)
232✔
971
        verbose_flag = 0;
18✔
972

973
    trials = (count > retry + 1) ? count : retry + 1;
236✔
974

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

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

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

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

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

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

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

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

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

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

1091
    update_current_time();
236✔
1092
    start_time = current_time_ns;
236✔
1093

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

1097
    argv = &argv[optparse_state.optind];
236✔
1098
    argc -= optparse_state.optind;
236✔
1099

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

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

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

1126
    if (*argv && !generate_flag) {
228✔
1127
        while (*argv) {
353✔
1128
            add_name(*argv);
196✔
1129
            ++argv;
196✔
1130
        }
1131
    }
45✔
1132
    else if (filename) {
71✔
1133
        FILE *ping_file;
1134
        char line[132];
1135
        char host[132];
1136

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

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

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

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

1152
            add_name(host);
24✔
1153
        }
1154

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

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

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

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

1202
    init_ping_buffer_ipv4(ping_data_size);
182✔
1203
#ifdef IPV6
1204
    init_ping_buffer_ipv6(ping_data_size);
182✔
1205
#endif
1206

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

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

1227
    last_send_time = 0;
158✔
1228

1229
    seqmap_init();
158✔
1230

1231
    /* main loop */
1232
    main_loop();
158✔
1233

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

1241
    finish();
158✔
1242

1243
    return 0;
38✔
1244
}
1245

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

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

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

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

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

1294
    /* convert mask integer from 1 to 32 to a bitmask */
1295
    bitmask = ((unsigned long)0xFFFFFFFF) << (32 - mask);
15✔
1296

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

1301
    /* exclude network and broadcast address for regular prefixes */
1302
    if (mask < 31) {
15✔
1303
        net_last--;
9✔
1304
        net_addr++;
9✔
1305
    }
3✔
1306

1307
    /* add all hosts in that network (net_addr and net_last inclusive) */
1308
    add_addr_range_ipv4(net_addr, net_last);
15✔
1309
}
13✔
1310

1311
void add_range(char *start, char *end)
21✔
1312
{
1313
    struct addrinfo addr_hints;
1314
    struct addrinfo *addr_res;
1315
    unsigned long start_long;
1316
    unsigned long end_long;
1317
    int ret;
1318

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

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

1352
    /* add IPv4 addresses from closed interval [start_long,end_long] */
1353
    add_addr_range_ipv4(start_long, end_long);
9✔
1354
}
7✔
1355

1356
void add_addr_range_ipv4(unsigned long start_long, unsigned long end_long)
24✔
1357
{
1358
    /* check if generator limit is exceeded */
1359
    if (end_long >= start_long + MAX_GENERATE) {
24✔
1360
        fprintf(stderr, "%s: -g parameter generates too many addresses\n", prog);
6✔
1361
        exit(1);
6✔
1362
    }
1363

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

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

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

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

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

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

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

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

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

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

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

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

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

1449
            /* Loop and count mode: schedule next ping */
1450
            if (loop_flag || (count_flag && event->ping_index + 1 < count)) {
538✔
1451
                host_add_ping_event(h, event->ping_index + 1, event->ev_time + perhost_interval);
299✔
1452
            }
97✔
1453
        }
170✔
1454

1455
    wait_for_reply:
352✔
1456

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

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

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

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

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

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

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

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

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

1519
        update_current_time();
941✔
1520

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

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

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

1540
/************************************************************
1541

1542
  Function: signal_handler
1543

1544
*************************************************************
1545

1546
  Inputs:  int signum
1547

1548
  Description:
1549

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

1553
************************************************************/
1554

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

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

1568
/************************************************************
1569

1570
  Function: update_current_time
1571

1572
*************************************************************/
1573

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

1580
/************************************************************
1581

1582
  Function: finish
1583

1584
*************************************************************
1585

1586
  Inputs:  void (none)
1587

1588
  Description:
1589

1590
  Main program clean up and exit point
1591

1592
************************************************************/
1593

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

1599
    update_current_time();
170✔
1600
    end_time = current_time_ns;
170✔
1601

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

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

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

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

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

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

1627
    if (stats_flag)
170✔
1628
        print_global_stats();
6✔
1629

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

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

1646
    exit(0);
142✔
1647
}
1648

1649
/************************************************************
1650

1651
  Function: print_per_system_stats
1652

1653
*************************************************************
1654

1655
  Inputs:  void (none)
1656

1657
  Description:
1658

1659

1660
************************************************************/
1661

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

1668
    if (verbose_flag || per_recv_flag)
82✔
1669
        fprintf(stderr, "\n");
41✔
1670

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

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

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

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

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

1709
            fprintf(stderr, "\n");
74✔
1710
        }
1711
    }
34✔
1712
}
82✔
1713

1714
/************************************************************
1715

1716
  Function: print_netdata
1717

1718
*************************************************************
1719

1720
  Inputs:  void (none)
1721

1722
  Description:
1723

1724

1725
************************************************************/
1726

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

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

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

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

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

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

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

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

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

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

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

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

1788
/************************************************************
1789

1790
  Function: print_per_system_splits
1791

1792
*************************************************************
1793

1794
  Inputs:  void (none)
1795

1796
  Description:
1797

1798

1799
************************************************************/
1800

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

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

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

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

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

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

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

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

1848
/************************************************************
1849

1850
  Function: print_global_stats
1851

1852
*************************************************************
1853

1854
  Inputs:  void (none)
1855

1856
  Description:
1857

1858

1859
************************************************************/
1860

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

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

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

1891
/************************************************************
1892

1893
  Function: send_ping
1894

1895
*************************************************************
1896

1897
  Inputs:  int s, HOST_ENTRY *h
1898

1899
  Description:
1900

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

1907
************************************************************/
1908

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

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

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

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

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

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

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

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

1964
    num_pingsent++;
562✔
1965
    last_send_time = h->last_send_time;
562✔
1966

1967
    return (ret);
562✔
1968
}
176✔
1969

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

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

1982
select_again:
1,296✔
1983
    FD_ZERO(&readset);
12,129✔
1984
    if (socket4 >= 0)
1,761✔
1985
        FD_SET(socket4, &readset);
1,761✔
1986
#ifdef IPV6
1987
    if (socket6 >= 0)
1,761✔
1988
        FD_SET(socket6, &readset);
1,761✔
1989
#endif
1990

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

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

2013
    return -1;
941✔
2014
}
465✔
2015

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

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

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

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

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

2083
    return recv_len;
820✔
2084
}
465✔
2085

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

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

2108
    /* received count */
2109
    h->num_recv++;
479✔
2110
    h->num_recv_i++;
479✔
2111

2112
    /* maximum */
2113
    if (!h->max_reply || latency > h->max_reply) {
479✔
2114
        h->max_reply = latency;
312✔
2115
    }
94✔
2116
    if (!h->max_reply_i || latency > h->max_reply_i) {
479✔
2117
        h->max_reply_i = latency;
330✔
2118
    }
100✔
2119

2120
    /* minimum */
2121
    if (!h->min_reply || latency < h->min_reply) {
479✔
2122
        h->min_reply = latency;
261✔
2123
    }
88✔
2124
    if (!h->min_reply_i || latency < h->min_reply_i) {
479✔
2125
        h->min_reply_i = latency;
285✔
2126
    }
96✔
2127

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

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

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

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

2161
    if (!using_sock_dgram4) {
702✔
2162
        struct ip *ip = (struct ip *)reply_buf;
702✔
2163

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

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

2185
    icp = (struct icmp *)(reply_buf + hlen);
702✔
2186

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

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

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

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

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

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

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

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

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

2248
        return -1;
×
2249
    }
2250

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

2254
    return hlen;
420✔
2255
}
138✔
2256

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

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

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

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

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

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

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

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

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

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

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

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

2340
        return 0;
×
2341
    }
2342

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

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

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

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

2373
    if (result <= 0) {
1,761✔
2374
        return 0;
941✔
2375
    }
2376

2377
    update_current_time();
820✔
2378
    if (recv_time == 0)
820✔
2379
        recv_time = current_time_ns;
168✔
2380

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2501
            printf("\n");
107✔
2502
        }
31✔
2503
    }
66✔
2504

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

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

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

2530
        printf("\n");
111✔
2531
    }
37✔
2532

2533
    return 1;
479✔
2534
}
465✔
2535

2536
/************************************************************
2537

2538
  Function: add_name
2539

2540
*************************************************************
2541

2542
  Inputs:  char* name
2543

2544
  Description:
2545

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

2550
************************************************************/
2551

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

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

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

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

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

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

2640
        if (!multif_flag) {
259✔
2641
            break;
259✔
2642
        }
2643
    }
2644

2645
    freeaddrinfo(res0);
259✔
2646
}
82✔
2647

2648
/************************************************************
2649

2650
  Function: add_addr
2651

2652
*************************************************************
2653

2654
  Description:
2655

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

2658
************************************************************/
2659

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

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

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

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

2686
    if (strlen(p->host) > max_hostname_len)
259✔
2687
        max_hostname_len = strlen(p->host);
184✔
2688

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

2695
        for (n = 1; n < trials; n++)
1,123✔
2696
            i[n] = RESP_UNUSED;
864✔
2697

2698
        p->resp_times = i;
259✔
2699
    }
79✔
2700

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

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

2708
    num_hosts++;
259✔
2709
}
259✔
2710

2711
/************************************************************
2712

2713
  Function: crash_and_burn
2714

2715
*************************************************************
2716

2717
  Inputs:  char* message
2718

2719
  Description:
2720

2721
************************************************************/
2722

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

2729
/************************************************************
2730

2731
  Function: errno_crash_and_burn
2732

2733
*************************************************************
2734

2735
  Inputs:  char* message
2736

2737
  Description:
2738

2739
************************************************************/
2740

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

2747
/************************************************************
2748

2749
  Function: print_warning
2750

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

2753
*************************************************************/
2754

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

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

2767
  Function: sprint_tm
2768

2769
*************************************************************
2770

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

2774
************************************************************/
2775

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

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

2805
    return (buf);
699✔
2806
}
2807

2808
/************************************************************
2809

2810
  Function: addr_cmp
2811

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

2829
    return 0;
×
2830
}
68✔
2831

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

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

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

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

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

2861
/************************************************************
2862

2863
  Function: ev_enqueue
2864

2865
  Enqueue an event
2866

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

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

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

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

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

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

2918
/************************************************************
2919

2920
  Function: ev_dequeue
2921

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

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

2933
    return dequeued;
615✔
2934
}
193✔
2935

2936
/************************************************************
2937

2938
  Function: ev_remove
2939

2940
*************************************************************/
2941
void ev_remove(struct event_queue *queue, struct event *event)
1,094✔
2942
{
2943
    if (queue->first == event) {
1,094✔
2944
        queue->first = event->ev_next;
1,085✔
2945
    }
343✔
2946
    if (queue->last == event) {
1,094✔
2947
        queue->last = event->ev_prev;
852✔
2948
    }
266✔
2949
    if (event->ev_prev) {
1,094✔
2950
        event->ev_prev->ev_next = event->ev_next;
9✔
2951
    }
3✔
2952
    if (event->ev_next) {
1,094✔
2953
        event->ev_next->ev_prev = event->ev_prev;
242✔
2954
    }
80✔
2955
    event->ev_prev = NULL;
1,094✔
2956
    event->ev_next = NULL;
1,094✔
2957
}
1,094✔
2958

2959
/************************************************************
2960

2961
  Function: print_human_readable_time from current_time_ns
2962

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

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

2993
/************************************************************
2994

2995
  Function: usage
2996

2997
*************************************************************
2998

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

3001
  Description:
3002

3003
************************************************************/
3004

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