summaryrefslogtreecommitdiffstats
path: root/plugins-root/check_icmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins-root/check_icmp.c')
-rw-r--r--plugins-root/check_icmp.c1287
1 files changed, 659 insertions, 628 deletions
diff --git a/plugins-root/check_icmp.c b/plugins-root/check_icmp.c
index 061e7d82..87dac21d 100644
--- a/plugins-root/check_icmp.c
+++ b/plugins-root/check_icmp.c
@@ -67,6 +67,10 @@ const char *email = "devel@monitoring-plugins.org";
67#include <math.h> 67#include <math.h>
68#include <netdb.h> 68#include <netdb.h>
69 69
70#include "../lib/states.h"
71#include "./check_icmp.d/config.h"
72#include "./check_icmp.d/check_icmp_helpers.h"
73
70/** sometimes undefined system macros (quite a few, actually) **/ 74/** sometimes undefined system macros (quite a few, actually) **/
71#ifndef MAXTTL 75#ifndef MAXTTL
72# define MAXTTL 255 76# define MAXTTL 255
@@ -97,56 +101,8 @@ const char *email = "devel@monitoring-plugins.org";
97# define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 101# define ICMP_UNREACH_PRECEDENCE_CUTOFF 15
98#endif 102#endif
99 103
100typedef unsigned short range_t; /* type for get_range() -- unimplemented */
101
102typedef struct rta_host {
103 unsigned short id; /* id in **table, and icmp pkts */
104 char *name; /* arg used for adding this host */
105 char *msg; /* icmp error message, if any */
106 struct sockaddr_storage saddr_in; /* the address of this host */
107 struct sockaddr_storage error_addr; /* stores address of error replies */
108 unsigned long long time_waited; /* total time waited, in usecs */
109 unsigned int icmp_sent, icmp_recv, icmp_lost; /* counters */
110 unsigned char icmp_type, icmp_code; /* type and code from errors */
111 unsigned short flags; /* control/status flags */
112 double rta; /* measured RTA */
113 int rta_status; // check result for RTA checks
114 double rtmax; /* max rtt */
115 double rtmin; /* min rtt */
116 double jitter; /* measured jitter */
117 int jitter_status; // check result for Jitter checks
118 double jitter_max; /* jitter rtt maximum */
119 double jitter_min; /* jitter rtt minimum */
120 double EffectiveLatency;
121 double mos; /* Mean opnion score */
122 int mos_status; // check result for MOS checks
123 double score; /* score */
124 int score_status; // check result for score checks
125 u_int last_tdiff;
126 u_int last_icmp_seq; /* Last ICMP_SEQ to check out of order pkts */
127 unsigned char pl; /* measured packet loss */
128 int pl_status; // check result for packet loss checks
129 struct rta_host *next; /* linked list */
130 int order_status; // check result for packet order checks
131} rta_host;
132
133#define FLAG_LOST_CAUSE 0x01 /* decidedly dead target. */ 104#define FLAG_LOST_CAUSE 0x01 /* decidedly dead target. */
134 105
135/* threshold structure. all values are maximum allowed, exclusive */
136typedef struct threshold {
137 unsigned char pl; /* max allowed packet loss in percent */
138 unsigned int rta; /* roundtrip time average, microseconds */
139 double jitter; /* jitter time average, microseconds */
140 double mos; /* MOS */
141 double score; /* Score */
142} threshold;
143
144/* the data structure */
145typedef struct icmp_ping_data {
146 struct timeval stime; /* timestamp (saved in protocol struct as well) */
147 unsigned short ping_id;
148} icmp_ping_data;
149
150typedef union ip_hdr { 106typedef union ip_hdr {
151 struct ip ip; 107 struct ip ip;
152 struct ip6_hdr ip6; 108 struct ip6_hdr ip6;
@@ -159,24 +115,6 @@ typedef union icmp_packet {
159 u_short *cksum_in; 115 u_short *cksum_in;
160} icmp_packet; 116} icmp_packet;
161 117
162/* the different modes of this program are as follows:
163 * MODE_RTA: send all packets no matter what (mimic check_icmp and check_ping)
164 * MODE_HOSTCHECK: Return immediately upon any sign of life
165 * In addition, sends packets to ALL addresses assigned
166 * to this host (as returned by gethostbyname() or
167 * gethostbyaddr() and expects one host only to be checked at
168 * a time. Therefore, any packet response what so ever will
169 * count as a sign of life, even when received outside
170 * crit.rta limit. Do not misspell any additional IP's.
171 * MODE_ALL: Requires packets from ALL requested IP to return OK (default).
172 * MODE_ICMP: implement something similar to check_icmp (MODE_RTA without
173 * tcp and udp args does this)
174 */
175#define MODE_RTA 0
176#define MODE_HOSTCHECK 1
177#define MODE_ALL 2
178#define MODE_ICMP 3
179
180enum enum_threshold_mode { 118enum enum_threshold_mode {
181 const_rta_mode, 119 const_rta_mode,
182 const_packet_loss_mode, 120 const_packet_loss_mode,
@@ -187,78 +125,325 @@ enum enum_threshold_mode {
187 125
188typedef enum enum_threshold_mode threshold_mode; 126typedef enum enum_threshold_mode threshold_mode;
189 127
190/* the different ping types we can do
191 * TODO: investigate ARP ping as well */
192#define HAVE_ICMP 1
193#define HAVE_UDP 2
194#define HAVE_TCP 4
195#define HAVE_ARP 8
196
197#define MIN_PING_DATA_SIZE sizeof(struct icmp_ping_data)
198#define MAX_IP_PKT_SIZE 65536 /* (theoretical) max IP packet size */
199#define IP_HDR_SIZE 20
200#define MAX_PING_DATA (MAX_IP_PKT_SIZE - IP_HDR_SIZE - ICMP_MINLEN)
201#define DEFAULT_PING_DATA_SIZE (MIN_PING_DATA_SIZE + 44)
202
203/* various target states */
204#define TSTATE_INACTIVE 0x01 /* don't ping this host anymore */
205#define TSTATE_WAITING 0x02 /* unanswered packets on the wire */
206#define TSTATE_ALIVE 0x04 /* target is alive (has answered something) */
207#define TSTATE_UNREACH 0x08
208
209/** prototypes **/ 128/** prototypes **/
210void print_help(void); 129void print_help();
211void print_usage(void); 130void print_usage(void);
212static u_int get_timevar(const char * /*str*/); 131
213static u_int get_timevaldiff(struct timeval * /*early*/, struct timeval * /*later*/); 132/* Time related */
133static unsigned int get_timevar(const char * /*str*/);
134static time_t get_timevaldiff(struct timeval * /*early*/, struct timeval * /*later*/,
135 struct timeval *prog_start);
136
214static in_addr_t get_ip_address(const char * /*ifname*/); 137static in_addr_t get_ip_address(const char * /*ifname*/);
215static int wait_for_reply(int /*sock*/, u_int /*t*/); 138static void set_source_ip(char * /*arg*/, const int icmp_sock);
216static int recvfrom_wto(int /*sock*/, void * /*buf*/, unsigned int /*len*/, struct sockaddr * /*saddr*/, u_int * /*timo*/, 139
217 struct timeval * /*tv*/); 140/* Receiving data */
218static int send_icmp_ping(int /*sock*/, struct rta_host * /*host*/); 141static int wait_for_reply(int /*sock*/, unsigned int /*t*/, bool order_mode, bool mos_mode,
142 bool rta_mode, bool pl_mode, bool jitter_mode, bool score_mode,
143 int min_hosts_alive, unsigned short icmp_pkt_size,
144 unsigned int *pkt_interval, unsigned int *target_interval, threshold warn,
145 threshold crit, pid_t pid, int mode,
146 unsigned long long max_completion_time, struct timeval *prog_start,
147 struct rta_host **table, const unsigned short packets,
148 const int icmp_sock, const unsigned short number_of_targets,
149 check_icmp_state *program_state);
150
151static int recvfrom_wto(int /*sock*/, void * /*buf*/, unsigned int /*len*/,
152 struct sockaddr * /*saddr*/, unsigned int * /*timo*/,
153 struct timeval * /*tv*/, struct timeval *prog_start);
154static int handle_random_icmp(unsigned char * /*packet*/, struct sockaddr_storage * /*addr*/,
155 unsigned int *pkt_interval, unsigned int *target_interval, pid_t pid,
156 struct rta_host **table, unsigned short packets,
157 const unsigned short number_of_targets,
158 check_icmp_state *program_state);
159
160/* Sending data */
161static int send_icmp_ping(int /*sock*/, struct rta_host * /*host*/, unsigned short icmp_pkt_size,
162 pid_t pid, check_icmp_state *program_state);
163
164/* Threshold related */
219static int get_threshold(char *str, threshold *th); 165static int get_threshold(char *str, threshold *th);
220static bool get_threshold2(char *str, size_t length, threshold * /*warn*/, threshold * /*crit*/, threshold_mode mode); 166static bool get_threshold2(char *str, size_t length, threshold * /*warn*/, threshold * /*crit*/,
167 threshold_mode mode);
221static bool parse_threshold2_helper(char *s, size_t length, threshold *thr, threshold_mode mode); 168static bool parse_threshold2_helper(char *s, size_t length, threshold *thr, threshold_mode mode);
222static void run_checks(void); 169
223static void set_source_ip(char * /*arg*/); 170/* main test function */
224static int add_target(char * /*arg*/); 171static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mode,
172 bool jitter_mode, bool score_mode, int min_hosts_alive,
173 unsigned short icmp_pkt_size, unsigned int *pkt_interval,
174 unsigned int *target_interval, threshold warn, threshold crit, pid_t pid,
175 int mode, unsigned int max_completion_time, const struct timeval *prog_start,
176 struct rta_host **table, const unsigned short packets, const int icmp_sock,
177 const unsigned short number_of_targets, check_icmp_state *program_state);
178
179/* Target aquisition */
180static int add_target(char * /*arg*/, int mode);
225static int add_target_ip(char * /*arg*/, struct sockaddr_storage * /*in*/); 181static int add_target_ip(char * /*arg*/, struct sockaddr_storage * /*in*/);
226static int handle_random_icmp(unsigned char * /*packet*/, struct sockaddr_storage * /*addr*/); 182
227static void parse_address(struct sockaddr_storage * /*addr*/, char * /*address*/, int /*size*/); 183static void parse_address(struct sockaddr_storage * /*addr*/, char * /*address*/, int /*size*/);
184
228static unsigned short icmp_checksum(uint16_t * /*p*/, size_t /*n*/); 185static unsigned short icmp_checksum(uint16_t * /*p*/, size_t /*n*/);
229static void finish(int /*sig*/); 186
187/* End of run function */
188static void finish(int /*sig*/, bool order_mode, bool mos_mode, bool rta_mode, bool pl_mode,
189 bool jitter_mode, bool score_mode, int min_hosts_alive, threshold warn,
190 threshold crit, const int icmp_sock, const unsigned short number_of_targets,
191 check_icmp_state *program_state);
192
193/* Error exit */
230static void crash(const char * /*fmt*/, ...); 194static void crash(const char * /*fmt*/, ...);
231 195
232/** global variables **/ 196/** global variables **/
233static struct rta_host **table, *cursor, *list; 197static struct rta_host *cursor = NULL;
234 198static struct rta_host *host_list = NULL;
235static threshold crit = {.pl = 80, .rta = 500000, .jitter = 0.0, .mos = 0.0, .score = 0.0}; 199
236static threshold warn = {.pl = 40, .rta = 200000, .jitter = 0.0, .mos = 0.0, .score = 0.0}; 200static int debug = 0;
237 201
238static int mode, protocols, sockets, debug = 0, timeout = 10; 202/** the working code **/
239static unsigned short icmp_data_size = DEFAULT_PING_DATA_SIZE; 203
240static unsigned short icmp_pkt_size = DEFAULT_PING_DATA_SIZE + ICMP_MINLEN; 204static inline unsigned short targets_alive(unsigned short targets, unsigned short targets_down) {
241 205 return targets - targets_down;
242static unsigned int icmp_sent = 0, icmp_recv = 0, icmp_lost = 0, ttl = 0; 206}
243#define icmp_pkts_en_route (icmp_sent - (icmp_recv + icmp_lost)) 207static inline unsigned int icmp_pkts_en_route(unsigned int icmp_sent, unsigned int icmp_recv,
244static unsigned short targets_down = 0, targets = 0, packets = 0; 208 unsigned int icmp_lost) {
245#define targets_alive (targets - targets_down) 209 return icmp_sent - (icmp_recv + icmp_lost);
246static unsigned int retry_interval, pkt_interval, target_interval; 210}
247static int icmp_sock, tcp_sock, udp_sock, status = STATE_OK; 211
248static pid_t pid; 212// Create configuration from cli parameters
249static struct timezone tz; 213typedef struct {
250static struct timeval prog_start; 214 int errorcode;
251static unsigned long long max_completion_time = 0; 215 check_icmp_config config;
252static unsigned int warn_down = 1, crit_down = 1; /* host down threshold values */ 216} check_icmp_config_wrapper;
253static int min_hosts_alive = -1; 217check_icmp_config_wrapper process_arguments(int argc, char **argv);
254static float pkt_backoff_factor = 1.5; 218
255static float target_backoff_factor = 1.5; 219check_icmp_config_wrapper process_arguments(int argc, char **argv) {
256static bool rta_mode = false; 220 /* get calling name the old-fashioned way for portability instead
257static bool pl_mode = false; 221 * of relying on the glibc-ism __progname */
258static bool jitter_mode = false; 222 char *ptr = strrchr(argv[0], '/');
259static bool score_mode = false; 223 if (ptr) {
260static bool mos_mode = false; 224 progname = &ptr[1];
261static bool order_mode = false; 225 } else {
226 progname = argv[0];
227 }
228
229 check_icmp_config_wrapper result = {
230 .errorcode = OK,
231 .config = check_icmp_config_init(),
232 };
233
234 /* use the pid to mark packets as ours */
235 /* Some systems have 32-bit pid_t so mask off only 16 bits */
236 result.config.pid = getpid() & 0xffff;
237
238 if (!strcmp(progname, "check_icmp") || !strcmp(progname, "check_ping")) {
239 result.config.mode = MODE_ICMP;
240 } else if (!strcmp(progname, "check_host")) {
241 result.config.mode = MODE_HOSTCHECK;
242 result.config.pkt_interval = 1000000;
243 result.config.packets = 5;
244 result.config.crit.rta = result.config.warn.rta = 1000000;
245 result.config.crit.pl = result.config.warn.pl = 100;
246 } else if (!strcmp(progname, "check_rta_multi")) {
247 result.config.mode = MODE_ALL;
248 result.config.target_interval = 0;
249 result.config.pkt_interval = 50000;
250 result.config.packets = 5;
251 }
252 /* support "--help" and "--version" */
253 if (argc == 2) {
254 if (!strcmp(argv[1], "--help")) {
255 strcpy(argv[1], "-h");
256 }
257 if (!strcmp(argv[1], "--version")) {
258 strcpy(argv[1], "-V");
259 }
260 }
261
262 /* Parse protocol arguments first */
263 char *opts_str = "vhVw:c:n:p:t:H:s:i:b:I:l:m:P:R:J:S:M:O64";
264 for (int i = 1; i < argc; i++) {
265 long int arg;
266 while ((arg = getopt(argc, argv, opts_str)) != EOF) {
267 switch (arg) {
268 case '4':
269 if (address_family != -1) {
270 crash("Multiple protocol versions not supported");
271 }
272 address_family = AF_INET;
273 break;
274 case '6':
275#ifdef USE_IPV6
276 if (address_family != -1) {
277 crash("Multiple protocol versions not supported");
278 }
279 address_family = AF_INET6;
280#else
281 usage(_("IPv6 support not available\n"));
282#endif
283 break;
284 }
285 }
286 }
287
288 /* Reset argument scanning */
289 optind = 1;
290
291 bool err;
292 /* parse the arguments */
293 for (int i = 1; i < argc; i++) {
294 long int arg;
295 while ((arg = getopt(argc, argv, opts_str)) != EOF) {
296 switch (arg) {
297 case 'v':
298 debug++;
299 break;
300 case 'b': {
301 long size = strtol(optarg, NULL, 0);
302 if ((unsigned long)size >= (sizeof(struct icmp) + sizeof(struct icmp_ping_data)) &&
303 size < MAX_PING_DATA) {
304 result.config.icmp_data_size = size;
305 result.config.icmp_pkt_size = size + ICMP_MINLEN;
306 } else {
307 usage_va("ICMP data length must be between: %lu and %lu",
308 sizeof(struct icmp) + sizeof(struct icmp_ping_data),
309 MAX_PING_DATA - 1);
310 }
311 } break;
312 case 'i':
313 result.config.pkt_interval = get_timevar(optarg);
314 break;
315 case 'I':
316 result.config.target_interval = get_timevar(optarg);
317 break;
318 case 'w':
319 get_threshold(optarg, &result.config.warn);
320 break;
321 case 'c':
322 get_threshold(optarg, &result.config.crit);
323 break;
324 case 'n':
325 case 'p':
326 result.config.packets = strtoul(optarg, NULL, 0);
327 if (result.config.packets > 20) {
328 errno = 0;
329 crash("packets is > 20 (%d)", result.config.packets);
330 }
331 break;
332 case 't':
333 result.config.timeout = strtoul(optarg, NULL, 0);
334 // TODO die here and complain about wrong input
335 // instead of:
336 if (!result.config.timeout) {
337 result.config.timeout = 10;
338 }
339 break;
340 case 'H': {
341 int add_result = add_target(optarg, result.config.mode);
342 if (add_result == 0) {
343 result.config.number_of_targets++;
344 }
345 } break;
346 case 'l':
347 result.config.ttl = strtoul(optarg, NULL, 0);
348 break;
349 case 'm':
350 result.config.min_hosts_alive = (int)strtoul(optarg, NULL, 0);
351 break;
352 case 's': /* specify source IP address */
353 result.config.source_ip = optarg;
354 break;
355 case 'V': /* version */
356 print_revision(progname, NP_VERSION);
357 exit(STATE_UNKNOWN);
358 case 'h': /* help */
359 print_help();
360 exit(STATE_UNKNOWN);
361 break;
362 case 'R': /* RTA mode */
363 err = get_threshold2(optarg, strlen(optarg), &result.config.warn,
364 &result.config.crit, const_rta_mode);
365 if (!err) {
366 crash("Failed to parse RTA threshold");
367 }
368
369 result.config.rta_mode = true;
370 break;
371 case 'P': /* packet loss mode */
372 err = get_threshold2(optarg, strlen(optarg), &result.config.warn,
373 &result.config.crit, const_packet_loss_mode);
374 if (!err) {
375 crash("Failed to parse packet loss threshold");
376 }
377
378 result.config.pl_mode = true;
379 break;
380 case 'J': /* jitter mode */
381 err = get_threshold2(optarg, strlen(optarg), &result.config.warn,
382 &result.config.crit, const_jitter_mode);
383 if (!err) {
384 crash("Failed to parse jitter threshold");
385 }
386
387 result.config.jitter_mode = true;
388 break;
389 case 'M': /* MOS mode */
390 err = get_threshold2(optarg, strlen(optarg), &result.config.warn,
391 &result.config.crit, const_mos_mode);
392 if (!err) {
393 crash("Failed to parse MOS threshold");
394 }
395
396 result.config.mos_mode = true;
397 break;
398 case 'S': /* score mode */
399 err = get_threshold2(optarg, strlen(optarg), &result.config.warn,
400 &result.config.crit, const_score_mode);
401 if (!err) {
402 crash("Failed to parse score threshold");
403 }
404
405 result.config.score_mode = true;
406 break;
407 case 'O': /* out of order mode */
408 result.config.order_mode = true;
409 break;
410 }
411 }
412 }
413
414 argv = &argv[optind];
415 while (*argv) {
416 add_target(*argv, result.config.mode);
417 argv++;
418 }
419
420 if (!result.config.number_of_targets) {
421 errno = 0;
422 crash("No hosts to check");
423 }
424
425 /* stupid users should be able to give whatever thresholds they want
426 * (nothing will break if they do), but some anal plugin maintainer
427 * will probably add some printf() thing here later, so it might be
428 * best to at least show them where to do it. ;) */
429 if (result.config.warn.pl > result.config.crit.pl) {
430 result.config.warn.pl = result.config.crit.pl;
431 }
432 if (result.config.warn.rta > result.config.crit.rta) {
433 result.config.warn.rta = result.config.crit.rta;
434 }
435 if (result.config.warn.jitter > result.config.crit.jitter) {
436 result.config.crit.jitter = result.config.warn.jitter;
437 }
438 if (result.config.warn.mos < result.config.crit.mos) {
439 result.config.warn.mos = result.config.crit.mos;
440 }
441 if (result.config.warn.score < result.config.crit.score) {
442 result.config.warn.score = result.config.crit.score;
443 }
444
445 return result;
446}
262 447
263/** code start **/ 448/** code start **/
264static void crash(const char *fmt, ...) { 449static void crash(const char *fmt, ...) {
@@ -382,7 +567,11 @@ static const char *get_icmp_error_msg(unsigned char icmp_type, unsigned char icm
382 return msg; 567 return msg;
383} 568}
384 569
385static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *addr) { 570static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *addr,
571 unsigned int *pkt_interval, unsigned int *target_interval,
572 const pid_t pid, struct rta_host **table, unsigned short packets,
573 const unsigned short number_of_targets,
574 check_icmp_state *program_state) {
386 struct icmp p; 575 struct icmp p;
387 memcpy(&p, packet, sizeof(p)); 576 memcpy(&p, packet, sizeof(p));
388 if (p.icmp_type == ICMP_ECHO && ntohs(p.icmp_id) == pid) { 577 if (p.icmp_type == ICMP_ECHO && ntohs(p.icmp_id) == pid) {
@@ -404,7 +593,8 @@ static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *ad
404 * TIMXCEED actually sends a proper icmp response we will have passed 593 * TIMXCEED actually sends a proper icmp response we will have passed
405 * too many hops to have a hope of reaching it later, in which case it 594 * too many hops to have a hope of reaching it later, in which case it
406 * indicates overconfidence in the network, poor routing or both. */ 595 * indicates overconfidence in the network, poor routing or both. */
407 if (p.icmp_type != ICMP_UNREACH && p.icmp_type != ICMP_TIMXCEED && p.icmp_type != ICMP_SOURCEQUENCH && p.icmp_type != ICMP_PARAMPROB) { 596 if (p.icmp_type != ICMP_UNREACH && p.icmp_type != ICMP_TIMXCEED &&
597 p.icmp_type != ICMP_SOURCEQUENCH && p.icmp_type != ICMP_PARAMPROB) {
408 return 0; 598 return 0;
409 } 599 }
410 600
@@ -412,7 +602,8 @@ static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *ad
412 * to RFC 792). If it isn't, just ignore it */ 602 * to RFC 792). If it isn't, just ignore it */
413 struct icmp sent_icmp; 603 struct icmp sent_icmp;
414 memcpy(&sent_icmp, packet + 28, sizeof(sent_icmp)); 604 memcpy(&sent_icmp, packet + 28, sizeof(sent_icmp));
415 if (sent_icmp.icmp_type != ICMP_ECHO || ntohs(sent_icmp.icmp_id) != pid || ntohs(sent_icmp.icmp_seq) >= targets * packets) { 605 if (sent_icmp.icmp_type != ICMP_ECHO || ntohs(sent_icmp.icmp_id) != pid ||
606 ntohs(sent_icmp.icmp_seq) >= number_of_targets * packets) {
416 if (debug) { 607 if (debug) {
417 printf("Packet is no response to a packet we sent\n"); 608 printf("Packet is no response to a packet we sent\n");
418 } 609 }
@@ -424,10 +615,11 @@ static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *ad
424 if (debug) { 615 if (debug) {
425 char address[INET6_ADDRSTRLEN]; 616 char address[INET6_ADDRSTRLEN];
426 parse_address(addr, address, sizeof(address)); 617 parse_address(addr, address, sizeof(address));
427 printf("Received \"%s\" from %s for ICMP ECHO sent to %s.\n", get_icmp_error_msg(p.icmp_type, p.icmp_code), address, host->name); 618 printf("Received \"%s\" from %s for ICMP ECHO sent to %s.\n",
619 get_icmp_error_msg(p.icmp_type, p.icmp_code), address, host->name);
428 } 620 }
429 621
430 icmp_lost++; 622 program_state->icmp_lost++;
431 host->icmp_lost++; 623 host->icmp_lost++;
432 /* don't spend time on lost hosts any more */ 624 /* don't spend time on lost hosts any more */
433 if (host->flags & FLAG_LOST_CAUSE) { 625 if (host->flags & FLAG_LOST_CAUSE) {
@@ -437,10 +629,10 @@ static int handle_random_icmp(unsigned char *packet, struct sockaddr_storage *ad
437 /* source quench means we're sending too fast, so increase the 629 /* source quench means we're sending too fast, so increase the
438 * interval and mark this packet lost */ 630 * interval and mark this packet lost */
439 if (p.icmp_type == ICMP_SOURCEQUENCH) { 631 if (p.icmp_type == ICMP_SOURCEQUENCH) {
440 pkt_interval *= pkt_backoff_factor; 632 *pkt_interval *= PACKET_BACKOFF_FACTOR;
441 target_interval *= target_backoff_factor; 633 *target_interval *= TARGET_BACKOFF_FACTOR;
442 } else { 634 } else {
443 targets_down++; 635 program_state->targets_down++;
444 host->flags |= FLAG_LOST_CAUSE; 636 host->flags |= FLAG_LOST_CAUSE;
445 } 637 }
446 host->icmp_type = p.icmp_type; 638 host->icmp_type = p.icmp_type;
@@ -466,240 +658,23 @@ int main(int argc, char **argv) {
466 bindtextdomain(PACKAGE, LOCALEDIR); 658 bindtextdomain(PACKAGE, LOCALEDIR);
467 textdomain(PACKAGE); 659 textdomain(PACKAGE);
468 660
469 /* we only need to be setsuid when we get the sockets, so do
470 * that before pointer magic (esp. on network data) */
471 int icmp_sockerrno;
472 int udp_sockerrno;
473 int tcp_sockerrno;
474 icmp_sockerrno = udp_sockerrno = tcp_sockerrno = sockets = 0;
475
476 address_family = -1; 661 address_family = -1;
477 int icmp_proto = IPPROTO_ICMP; 662 int icmp_proto = IPPROTO_ICMP;
478 663
479 /* get calling name the old-fashioned way for portability instead
480 * of relying on the glibc-ism __progname */
481 char *ptr = strrchr(argv[0], '/');
482 if (ptr) {
483 progname = &ptr[1];
484 } else {
485 progname = argv[0];
486 }
487
488 /* now set defaults. Use progname to set them initially (allows for
489 * superfast check_host program when target host is up */
490 cursor = list = NULL;
491 table = NULL;
492
493 mode = MODE_RTA;
494 /* Default critical thresholds */
495 crit.rta = 500000;
496 crit.pl = 80;
497 crit.jitter = 50;
498 crit.mos = 3;
499 crit.score = 70;
500 /* Default warning thresholds */
501 warn.rta = 200000;
502 warn.pl = 40;
503 warn.jitter = 40;
504 warn.mos = 3.5;
505 warn.score = 80;
506
507 protocols = HAVE_ICMP | HAVE_UDP | HAVE_TCP;
508 pkt_interval = 80000; /* 80 msec packet interval by default */
509 packets = 5;
510
511 if (!strcmp(progname, "check_icmp") || !strcmp(progname, "check_ping")) {
512 mode = MODE_ICMP;
513 protocols = HAVE_ICMP;
514 } else if (!strcmp(progname, "check_host")) {
515 mode = MODE_HOSTCHECK;
516 pkt_interval = 1000000;
517 packets = 5;
518 crit.rta = warn.rta = 1000000;
519 crit.pl = warn.pl = 100;
520 } else if (!strcmp(progname, "check_rta_multi")) {
521 mode = MODE_ALL;
522 target_interval = 0;
523 pkt_interval = 50000;
524 packets = 5;
525 }
526
527 /* support "--help" and "--version" */
528 if (argc == 2) {
529 if (!strcmp(argv[1], "--help")) {
530 strcpy(argv[1], "-h");
531 }
532 if (!strcmp(argv[1], "--version")) {
533 strcpy(argv[1], "-V");
534 }
535 }
536
537 /* Parse protocol arguments first */
538 char *opts_str = "vhVw:c:n:p:t:H:s:i:b:I:l:m:P:R:J:S:M:O64";
539 for (int i = 1; i < argc; i++) {
540 long int arg;
541 while ((arg = getopt(argc, argv, opts_str)) != EOF) {
542 switch (arg) {
543 case '4':
544 if (address_family != -1) {
545 crash("Multiple protocol versions not supported");
546 }
547 address_family = AF_INET;
548 break;
549 case '6':
550#ifdef USE_IPV6
551 if (address_family != -1) {
552 crash("Multiple protocol versions not supported");
553 }
554 address_family = AF_INET6;
555#else
556 usage(_("IPv6 support not available\n"));
557#endif
558 break;
559 }
560 }
561 }
562
563 /* Reset argument scanning */
564 optind = 1;
565
566 unsigned long size;
567 bool err;
568 /* parse the arguments */
569 char *source_ip = NULL;
570 for (int i = 1; i < argc; i++) {
571 long int arg;
572 while ((arg = getopt(argc, argv, opts_str)) != EOF) {
573 switch (arg) {
574 case 'v':
575 debug++;
576 break;
577 case 'b':
578 size = strtol(optarg, NULL, 0);
579 if (size >= (sizeof(struct icmp) + sizeof(struct icmp_ping_data)) && size < MAX_PING_DATA) {
580 icmp_data_size = size;
581 icmp_pkt_size = size + ICMP_MINLEN;
582 } else {
583 usage_va("ICMP data length must be between: %lu and %lu", sizeof(struct icmp) + sizeof(struct icmp_ping_data),
584 MAX_PING_DATA - 1);
585 }
586 break;
587 case 'i':
588 pkt_interval = get_timevar(optarg);
589 break;
590 case 'I':
591 target_interval = get_timevar(optarg);
592 break;
593 case 'w':
594 get_threshold(optarg, &warn);
595 break;
596 case 'c':
597 get_threshold(optarg, &crit);
598 break;
599 case 'n':
600 case 'p':
601 packets = strtoul(optarg, NULL, 0);
602 break;
603 case 't':
604 timeout = strtoul(optarg, NULL, 0);
605 if (!timeout) {
606 timeout = 10;
607 }
608 break;
609 case 'H':
610 add_target(optarg);
611 break;
612 case 'l':
613 ttl = (int)strtoul(optarg, NULL, 0);
614 break;
615 case 'm':
616 min_hosts_alive = (int)strtoul(optarg, NULL, 0);
617 break;
618 case 'd': /* implement later, for cluster checks */
619 warn_down = (unsigned char)strtoul(optarg, &ptr, 0);
620 if (ptr) {
621 crit_down = (unsigned char)strtoul(ptr + 1, NULL, 0);
622 }
623 break;
624 case 's': /* specify source IP address */
625 source_ip = optarg;
626 break;
627 case 'V': /* version */
628 print_revision(progname, NP_VERSION);
629 exit(STATE_UNKNOWN);
630 case 'h': /* help */
631 print_help();
632 exit(STATE_UNKNOWN);
633 break;
634 case 'R': /* RTA mode */
635 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_rta_mode);
636 if (!err) {
637 crash("Failed to parse RTA threshold");
638 }
639
640 rta_mode = true;
641 break;
642 case 'P': /* packet loss mode */
643 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_packet_loss_mode);
644 if (!err) {
645 crash("Failed to parse packet loss threshold");
646 }
647
648 pl_mode = true;
649 break;
650 case 'J': /* jitter mode */
651 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_jitter_mode);
652 if (!err) {
653 crash("Failed to parse jitter threshold");
654 }
655
656 jitter_mode = true;
657 break;
658 case 'M': /* MOS mode */
659 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_mos_mode);
660 if (!err) {
661 crash("Failed to parse MOS threshold");
662 }
663
664 mos_mode = true;
665 break;
666 case 'S': /* score mode */
667 err = get_threshold2(optarg, strlen(optarg), &warn, &crit, const_score_mode);
668 if (!err) {
669 crash("Failed to parse score threshold");
670 }
671
672 score_mode = true;
673 break;
674 case 'O': /* out of order mode */
675 order_mode = true;
676 break;
677 }
678 }
679 }
680
681 /* POSIXLY_CORRECT might break things, so unset it (the portable way) */ 664 /* POSIXLY_CORRECT might break things, so unset it (the portable way) */
682 environ = NULL; 665 environ = NULL;
683 666
684 /* use the pid to mark packets as ours */
685 /* Some systems have 32-bit pid_t so mask off only 16 bits */
686 pid = getpid() & 0xffff;
687 /* printf("pid = %u\n", pid); */
688
689 /* Parse extra opts if any */ 667 /* Parse extra opts if any */
690 argv = np_extra_opts(&argc, argv, progname); 668 argv = np_extra_opts(&argc, argv, progname);
691 669
692 argv = &argv[optind]; 670 check_icmp_config_wrapper tmp_config = process_arguments(argc, argv);
693 while (*argv) {
694 add_target(*argv);
695 argv++;
696 }
697 671
698 if (!targets) { 672 if (tmp_config.errorcode != OK) {
699 errno = 0; 673 crash("failed to parse config");
700 crash("No hosts to check");
701 } 674 }
702 675
676 const check_icmp_config config = tmp_config.config;
677
703 // add_target might change address_family 678 // add_target might change address_family
704 switch (address_family) { 679 switch (address_family) {
705 case AF_INET: 680 case AF_INET:
@@ -711,14 +686,14 @@ int main(int argc, char **argv) {
711 default: 686 default:
712 crash("Address family not supported"); 687 crash("Address family not supported");
713 } 688 }
714 if ((icmp_sock = socket(address_family, SOCK_RAW, icmp_proto)) != -1) { 689
715 sockets |= HAVE_ICMP; 690 int icmp_sock = socket(address_family, SOCK_RAW, icmp_proto);
716 } else { 691 if (icmp_sock == -1) {
717 icmp_sockerrno = errno; 692 crash("Failed to obtain ICMP socket");
718 } 693 }
719 694
720 if (source_ip) { 695 if (config.source_ip) {
721 set_source_ip(source_ip); 696 set_source_ip(config.source_ip, icmp_sock);
722 } 697 }
723 698
724#ifdef SO_TIMESTAMP 699#ifdef SO_TIMESTAMP
@@ -736,184 +711,179 @@ int main(int argc, char **argv) {
736 return 1; 711 return 1;
737 } 712 }
738 713
739 if (!sockets) {
740 if (icmp_sock == -1) {
741 errno = icmp_sockerrno;
742 crash("Failed to obtain ICMP socket");
743 return -1;
744 }
745 /* if(udp_sock == -1) { */
746 /* errno = icmp_sockerrno; */
747 /* crash("Failed to obtain UDP socket"); */
748 /* return -1; */
749 /* } */
750 /* if(tcp_sock == -1) { */
751 /* errno = icmp_sockerrno; */
752 /* crash("Failed to obtain TCP socker"); */
753 /* return -1; */
754 /* } */
755 }
756 if (!ttl) {
757 ttl = 64;
758 }
759
760 if (icmp_sock) { 714 if (icmp_sock) {
761 int result = setsockopt(icmp_sock, SOL_IP, IP_TTL, &ttl, sizeof(ttl)); 715 int result = setsockopt(icmp_sock, SOL_IP, IP_TTL, &config.ttl, sizeof(config.ttl));
762 if (debug) { 716 if (debug) {
763 if (result == -1) { 717 if (result == -1) {
764 printf("setsockopt failed\n"); 718 printf("setsockopt failed\n");
765 } else { 719 } else {
766 printf("ttl set to %u\n", ttl); 720 printf("ttl set to %lu\n", config.ttl);
767 } 721 }
768 } 722 }
769 } 723 }
770 724
771 /* stupid users should be able to give whatever thresholds they want
772 * (nothing will break if they do), but some anal plugin maintainer
773 * will probably add some printf() thing here later, so it might be
774 * best to at least show them where to do it. ;) */
775 if (warn.pl > crit.pl) {
776 warn.pl = crit.pl;
777 }
778 if (warn.rta > crit.rta) {
779 warn.rta = crit.rta;
780 }
781 if (warn_down > crit_down) {
782 crit_down = warn_down;
783 }
784 if (warn.jitter > crit.jitter) {
785 crit.jitter = warn.jitter;
786 }
787 if (warn.mos < crit.mos) {
788 warn.mos = crit.mos;
789 }
790 if (warn.score < crit.score) {
791 warn.score = crit.score;
792 }
793
794#ifdef HAVE_SIGACTION 725#ifdef HAVE_SIGACTION
795 struct sigaction sig_action; 726 struct sigaction sig_action;
796 sig_action.sa_sigaction = NULL; 727 sig_action.sa_sigaction = NULL;
797 sig_action.sa_handler = finish; 728 sig_action.sa_handler = finish;
798 sigfillset(&sig_action.sa_mask); 729 sigfillset(&sig_action.sa_mask);
799 sig_action.sa_flags = SA_NODEFER | SA_RESTART; 730 sig_action.sa_flags = SA_NODEFER | SA_RESTART;
731
800 sigaction(SIGINT, &sig_action, NULL); 732 sigaction(SIGINT, &sig_action, NULL);
801 sigaction(SIGHUP, &sig_action, NULL); 733 sigaction(SIGHUP, &sig_action, NULL);
802 sigaction(SIGTERM, &sig_action, NULL); 734 sigaction(SIGTERM, &sig_action, NULL);
803 sigaction(SIGALRM, &sig_action, NULL); 735 sigaction(SIGALRM, &sig_action, NULL);
804#else /* HAVE_SIGACTION */ 736#else /* HAVE_SIGACTION */
805 signal(SIGINT, finish); 737 // signal(SIGINT, finish);
806 signal(SIGHUP, finish); 738 // signal(SIGHUP, finish);
807 signal(SIGTERM, finish); 739 // signal(SIGTERM, finish);
808 signal(SIGALRM, finish); 740 // signal(SIGALRM, finish);
809#endif /* HAVE_SIGACTION */ 741#endif /* HAVE_SIGACTION */
810 if (debug) { 742 if (debug) {
811 printf("Setting alarm timeout to %u seconds\n", timeout); 743 printf("Setting alarm timeout to %u seconds\n", config.timeout);
812 } 744 }
813 alarm(timeout); 745 alarm(config.timeout);
814 746
815 /* make sure we don't wait any longer than necessary */ 747 /* make sure we don't wait any longer than necessary */
816 gettimeofday(&prog_start, &tz); 748 struct timezone time_zone_dummy;
817 max_completion_time = ((targets * packets * pkt_interval) + (targets * target_interval)) + (targets * packets * crit.rta) + crit.rta; 749 struct timeval prog_start;
750 gettimeofday(&prog_start, &time_zone_dummy);
751
752 unsigned int max_completion_time =
753 ((config.number_of_targets * config.packets * config.pkt_interval) +
754 (config.number_of_targets * config.target_interval)) +
755 (config.number_of_targets * config.packets * config.crit.rta) + config.crit.rta;
818 756
819 if (debug) { 757 if (debug) {
820 printf("packets: %u, targets: %u\n" 758 printf("packets: %u, targets: %u\n"
821 "target_interval: %0.3f, pkt_interval %0.3f\n" 759 "target_interval: %0.3f, pkt_interval %0.3f\n"
822 "crit.rta: %0.3f\n" 760 "crit.rta: %0.3f\n"
823 "max_completion_time: %0.3f\n", 761 "max_completion_time: %0.3f\n",
824 packets, targets, (float)target_interval / 1000, (float)pkt_interval / 1000, (float)crit.rta / 1000, 762 config.packets, config.number_of_targets, (float)config.target_interval / 1000,
763 (float)config.pkt_interval / 1000, (float)config.crit.rta / 1000,
825 (float)max_completion_time / 1000); 764 (float)max_completion_time / 1000);
826 } 765 }
827 766
828 if (debug) { 767 if (debug) {
829 if (max_completion_time > (u_int)timeout * 1000000) { 768 if (max_completion_time > (unsigned int)config.timeout * 1000000) {
830 printf("max_completion_time: %llu timeout: %u\n", max_completion_time, timeout); 769 printf("max_completion_time: %u timeout: %u\n", max_completion_time, config.timeout);
831 printf("Timeout must be at least %llu\n", max_completion_time / 1000000 + 1); 770 printf("Timeout must be at least %u\n", (max_completion_time / 1000000) + 1);
832 } 771 }
833 } 772 }
834 773
835 if (debug) { 774 if (debug) {
836 printf("crit = {%u, %u%%}, warn = {%u, %u%%}\n", crit.rta, crit.pl, warn.rta, warn.pl); 775 printf("crit = {%u, %u%%}, warn = {%u, %u%%}\n", config.crit.rta, config.crit.pl,
837 printf("pkt_interval: %u target_interval: %u retry_interval: %u\n", pkt_interval, target_interval, retry_interval); 776 config.warn.rta, config.warn.pl);
838 printf("icmp_pkt_size: %u timeout: %u\n", icmp_pkt_size, timeout); 777 printf("pkt_interval: %u target_interval: %u\n", config.pkt_interval,
778 config.target_interval);
779 printf("icmp_pkt_size: %u timeout: %u\n", config.icmp_pkt_size, config.timeout);
839 } 780 }
840 781
841 if (packets > 20) { 782 if (config.min_hosts_alive < -1) {
842 errno = 0; 783 errno = 0;
843 crash("packets is > 20 (%d)", packets); 784 crash("minimum alive hosts is negative (%i)", config.min_hosts_alive);
844 } 785 }
845 786
846 if (min_hosts_alive < -1) { 787 struct rta_host *host = host_list;
847 errno = 0; 788 struct rta_host **table = malloc(sizeof(struct rta_host *) * config.number_of_targets);
848 crash("minimum alive hosts is negative (%i)", min_hosts_alive);
849 }
850
851 struct rta_host *host = list;
852 table = malloc(sizeof(struct rta_host *) * targets);
853 if (!table) { 789 if (!table) {
854 crash("main(): malloc failed for host table"); 790 crash("main(): malloc failed for host table");
855 } 791 }
856 792
857 int i = 0; 793 unsigned short i = 0;
858 while (host) { 794 while (host) {
859 host->id = i * packets; 795 host->id = i * config.packets;
860 table[i] = host; 796 table[i] = host;
861 host = host->next; 797 host = host->next;
862 i++; 798 i++;
863 } 799 }
864 800
865 run_checks(); 801 unsigned int pkt_interval = config.pkt_interval;
802 unsigned int target_interval = config.target_interval;
803
804 check_icmp_state program_state = check_icmp_state_init();
805
806 run_checks(config.order_mode, config.mos_mode, config.rta_mode, config.pl_mode,
807 config.jitter_mode, config.score_mode, config.min_hosts_alive, config.icmp_data_size,
808 &pkt_interval, &target_interval, config.warn, config.crit, config.pid, config.mode,
809 max_completion_time, &prog_start, table, config.packets, icmp_sock,
810 config.number_of_targets, &program_state);
866 811
867 errno = 0; 812 errno = 0;
868 finish(0); 813 finish(0, config.order_mode, config.mos_mode, config.rta_mode, config.pl_mode,
814 config.jitter_mode, config.score_mode, config.min_hosts_alive, config.warn, config.crit,
815 icmp_sock, config.number_of_targets, &program_state);
869 816
870 return (0); 817 return (0);
871} 818}
872 819
873static void run_checks(void) { 820static void run_checks(bool order_mode, bool mos_mode, bool rta_mode, bool pl_mode,
821 bool jitter_mode, bool score_mode, int min_hosts_alive,
822 unsigned short icmp_pkt_size, unsigned int *pkt_interval,
823 unsigned int *target_interval, threshold warn, threshold crit,
824 const pid_t pid, const int mode, const unsigned int max_completion_time,
825 const struct timeval *prog_start, struct rta_host **table,
826 const unsigned short packets, const int icmp_sock,
827 const unsigned short number_of_targets, check_icmp_state *program_state) {
874 /* this loop might actually violate the pkt_interval or target_interval 828 /* this loop might actually violate the pkt_interval or target_interval
875 * settings, but only if there aren't any packets on the wire which 829 * settings, but only if there aren't any packets on the wire which
876 * indicates that the target can handle an increased packet rate */ 830 * indicates that the target can handle an increased packet rate */
877 for (u_int i = 0; i < packets; i++) { 831 for (unsigned int packet_index = 0; packet_index < packets; packet_index++) {
878 for (u_int t = 0; t < targets; t++) { 832 for (unsigned int target_index = 0; target_index < number_of_targets; target_index++) {
879 /* don't send useless packets */ 833 /* don't send useless packets */
880 if (!targets_alive) { 834 if (!targets_alive(number_of_targets, program_state->targets_down)) {
881 finish(0); 835 finish(0, order_mode, mos_mode, rta_mode, pl_mode, jitter_mode, score_mode,
836 min_hosts_alive, warn, crit, icmp_sock, number_of_targets, program_state);
882 } 837 }
883 if (table[t]->flags & FLAG_LOST_CAUSE) { 838 if (table[target_index]->flags & FLAG_LOST_CAUSE) {
884 if (debug) { 839 if (debug) {
885 printf("%s is a lost cause. not sending any more\n", table[t]->name); 840 printf("%s is a lost cause. not sending any more\n", table[target_index]->name);
886 } 841 }
887 continue; 842 continue;
888 } 843 }
889 844
890 /* we're still in the game, so send next packet */ 845 /* we're still in the game, so send next packet */
891 (void)send_icmp_ping(icmp_sock, table[t]); 846 (void)send_icmp_ping(icmp_sock, table[target_index], icmp_pkt_size, pid, program_state);
892 wait_for_reply(icmp_sock, target_interval); 847
848 wait_for_reply(icmp_sock, *target_interval, order_mode, mos_mode, rta_mode, pl_mode,
849 jitter_mode, score_mode, min_hosts_alive, icmp_pkt_size, pkt_interval,
850 target_interval, warn, crit, pid, mode, max_completion_time, prog_start,
851 table, packets, icmp_sock, number_of_targets, program_state);
893 } 852 }
894 wait_for_reply(icmp_sock, pkt_interval * targets); 853 wait_for_reply(icmp_sock, *pkt_interval * number_of_targets, order_mode, mos_mode, rta_mode,
854 pl_mode, jitter_mode, score_mode, min_hosts_alive, icmp_pkt_size,
855 pkt_interval, target_interval, warn, crit, pid, mode, max_completion_time,
856 prog_start, table, packets, icmp_sock, number_of_targets, program_state);
895 } 857 }
896 858
897 if (icmp_pkts_en_route && targets_alive) { 859 if (icmp_pkts_en_route(program_state->icmp_sent, program_state->icmp_recv,
898 u_int time_passed = get_timevaldiff(NULL, NULL); 860 program_state->icmp_lost) &&
899 u_int final_wait = max_completion_time - time_passed; 861 targets_alive(number_of_targets, program_state->targets_down)) {
862 unsigned int time_passed = get_timevaldiff(NULL, NULL, prog_start);
863 unsigned int final_wait = max_completion_time - time_passed;
900 864
901 if (debug) { 865 if (debug) {
902 printf("time_passed: %u final_wait: %u max_completion_time: %llu\n", time_passed, final_wait, max_completion_time); 866 printf("time_passed: %u final_wait: %u max_completion_time: %u\n", time_passed,
867 final_wait, max_completion_time);
903 } 868 }
904 if (time_passed > max_completion_time) { 869 if (time_passed > max_completion_time) {
905 if (debug) { 870 if (debug) {
906 printf("Time passed. Finishing up\n"); 871 printf("Time passed. Finishing up\n");
907 } 872 }
908 finish(0); 873 finish(0, order_mode, mos_mode, rta_mode, pl_mode, jitter_mode, score_mode,
874 min_hosts_alive, warn, crit, icmp_sock, number_of_targets, program_state);
909 } 875 }
910 876
911 /* catch the packets that might come in within the timeframe, but 877 /* catch the packets that might come in within the timeframe, but
912 * haven't yet */ 878 * haven't yet */
913 if (debug) { 879 if (debug) {
914 printf("Waiting for %u micro-seconds (%0.3f msecs)\n", final_wait, (float)final_wait / 1000); 880 printf("Waiting for %u micro-seconds (%0.3f msecs)\n", final_wait,
881 (float)final_wait / 1000);
915 } 882 }
916 wait_for_reply(icmp_sock, final_wait); 883 wait_for_reply(icmp_sock, final_wait, order_mode, mos_mode, rta_mode, pl_mode, jitter_mode,
884 score_mode, min_hosts_alive, icmp_pkt_size, pkt_interval, target_interval,
885 warn, crit, pid, mode, max_completion_time, prog_start, table, packets,
886 icmp_sock, number_of_targets, program_state);
917 } 887 }
918} 888}
919 889
@@ -927,7 +897,15 @@ static void run_checks(void) {
927 * both: 897 * both:
928 * icmp echo reply : the rest 898 * icmp echo reply : the rest
929 */ 899 */
930static int wait_for_reply(int sock, u_int t) { 900static int wait_for_reply(int sock, const unsigned int time_interval, bool order_mode,
901 bool mos_mode, bool rta_mode, bool pl_mode, bool jitter_mode,
902 bool score_mode, int min_hosts_alive, unsigned short icmp_pkt_size,
903 unsigned int *pkt_interval, unsigned int *target_interval, threshold warn,
904 threshold crit, const pid_t pid, const int mode,
905 const unsigned long long max_completion_time, struct timeval *prog_start,
906 struct rta_host **table, const unsigned short packets,
907 const int icmp_sock, const unsigned short number_of_targets,
908 check_icmp_state *program_state) {
931 union icmp_packet packet; 909 union icmp_packet packet;
932 if (!(packet.buf = malloc(icmp_pkt_size))) { 910 if (!(packet.buf = malloc(icmp_pkt_size))) {
933 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", icmp_pkt_size); 911 crash("send_icmp_ping(): failed to malloc %d bytes for send buffer", icmp_pkt_size);
@@ -937,30 +915,39 @@ static int wait_for_reply(int sock, u_int t) {
937 memset(packet.buf, 0, icmp_pkt_size); 915 memset(packet.buf, 0, icmp_pkt_size);
938 916
939 /* if we can't listen or don't have anything to listen to, just return */ 917 /* if we can't listen or don't have anything to listen to, just return */
940 if (!t || !icmp_pkts_en_route) { 918 if (!time_interval || !icmp_pkts_en_route(program_state->icmp_sent, program_state->icmp_recv,
919 program_state->icmp_lost)) {
941 free(packet.buf); 920 free(packet.buf);
942 return 0; 921 return 0;
943 } 922 }
944 923
945 struct timeval wait_start; 924 struct timeval wait_start;
946 gettimeofday(&wait_start, &tz); 925 struct timezone time_zone_dummy;
926 gettimeofday(&wait_start, &time_zone_dummy);
947 927
948 u_int i = t;
949 struct sockaddr_storage resp_addr; 928 struct sockaddr_storage resp_addr;
950 u_int per_pkt_wait = t / icmp_pkts_en_route; 929 unsigned int per_pkt_wait =
930 time_interval / icmp_pkts_en_route(program_state->icmp_sent, program_state->icmp_recv,
931 program_state->icmp_lost);
951 static unsigned char buf[65536]; 932 static unsigned char buf[65536];
952 union ip_hdr *ip; 933 union ip_hdr *ip;
953 struct timeval now; 934 struct timeval now;
954 while (icmp_pkts_en_route && get_timevaldiff(&wait_start, NULL) < i) { 935 while (icmp_pkts_en_route(program_state->icmp_sent, program_state->icmp_recv,
955 t = per_pkt_wait; 936 program_state->icmp_lost) &&
937 get_timevaldiff(&wait_start, NULL, prog_start) < time_interval) {
938 unsigned int loop_time_interval = per_pkt_wait;
956 939
957 /* wrap up if all targets are declared dead */ 940 /* wrap up if all targets are declared dead */
958 if (!targets_alive || get_timevaldiff(&prog_start, NULL) >= max_completion_time || (mode == MODE_HOSTCHECK && targets_down)) { 941 if (!targets_alive(number_of_targets, program_state->targets_down) ||
959 finish(0); 942 get_timevaldiff(prog_start, NULL, prog_start) >= max_completion_time ||
943 (mode == MODE_HOSTCHECK && program_state->targets_down)) {
944 finish(0, order_mode, mos_mode, rta_mode, pl_mode, jitter_mode, score_mode,
945 min_hosts_alive, warn, crit, icmp_sock, number_of_targets, program_state);
960 } 946 }
961 947
962 /* reap responses until we hit a timeout */ 948 /* reap responses until we hit a timeout */
963 int n = recvfrom_wto(sock, buf, sizeof(buf), (struct sockaddr *)&resp_addr, &t, &now); 949 int n = recvfrom_wto(sock, buf, sizeof(buf), (struct sockaddr *)&resp_addr,
950 &loop_time_interval, &now, prog_start);
964 if (!n) { 951 if (!n) {
965 if (debug > 1) { 952 if (debug > 1) {
966 printf("recvfrom_wto() timed out during a %u usecs wait\n", per_pkt_wait); 953 printf("recvfrom_wto() timed out during a %u usecs wait\n", per_pkt_wait);
@@ -982,7 +969,9 @@ static int wait_for_reply(int sock, u_int t) {
982 if (debug > 1) { 969 if (debug > 1) {
983 char address[INET6_ADDRSTRLEN]; 970 char address[INET6_ADDRSTRLEN];
984 parse_address(&resp_addr, address, sizeof(address)); 971 parse_address(&resp_addr, address, sizeof(address));
985 printf("received %u bytes from %s\n", address_family == AF_INET6 ? ntohs(ip->ip6.ip6_plen) : ntohs(ip->ip.ip_len), address); 972 printf("received %u bytes from %s\n",
973 address_family == AF_INET6 ? ntohs(ip->ip6.ip6_plen) : ntohs(ip->ip.ip_len),
974 address);
986 } 975 }
987 } 976 }
988 977
@@ -999,7 +988,8 @@ static int wait_for_reply(int sock, u_int t) {
999 if (n < (hlen + ICMP_MINLEN)) { 988 if (n < (hlen + ICMP_MINLEN)) {
1000 char address[INET6_ADDRSTRLEN]; 989 char address[INET6_ADDRSTRLEN];
1001 parse_address(&resp_addr, address, sizeof(address)); 990 parse_address(&resp_addr, address, sizeof(address));
1002 crash("received packet too short for ICMP (%d bytes, expected %d) from %s\n", n, hlen + icmp_pkt_size, address); 991 crash("received packet too short for ICMP (%d bytes, expected %d) from %s\n", n,
992 hlen + icmp_pkt_size, address);
1003 } 993 }
1004 /* else if(debug) { */ 994 /* else if(debug) { */
1005 /* printf("ip header size: %u, packet size: %u (expected %u, %u)\n", */ 995 /* printf("ip header size: %u, packet size: %u (expected %u, %u)\n", */
@@ -1013,14 +1003,19 @@ static int wait_for_reply(int sock, u_int t) {
1013 /* address_family == AF_INET6 ? sizeof(struct icmp6_hdr) 1003 /* address_family == AF_INET6 ? sizeof(struct icmp6_hdr)
1014 : sizeof(struct icmp));*/ 1004 : sizeof(struct icmp));*/
1015 1005
1016 if ((address_family == PF_INET && (ntohs(packet.icp->icmp_id) != pid || packet.icp->icmp_type != ICMP_ECHOREPLY || 1006 if ((address_family == PF_INET &&
1017 ntohs(packet.icp->icmp_seq) >= targets * packets)) || 1007 (ntohs(packet.icp->icmp_id) != pid || packet.icp->icmp_type != ICMP_ECHOREPLY ||
1018 (address_family == PF_INET6 && (ntohs(packet.icp6->icmp6_id) != pid || packet.icp6->icmp6_type != ICMP6_ECHO_REPLY || 1008 ntohs(packet.icp->icmp_seq) >= number_of_targets * packets)) ||
1019 ntohs(packet.icp6->icmp6_seq) >= targets * packets))) { 1009 (address_family == PF_INET6 &&
1010 (ntohs(packet.icp6->icmp6_id) != pid || packet.icp6->icmp6_type != ICMP6_ECHO_REPLY ||
1011 ntohs(packet.icp6->icmp6_seq) >= number_of_targets * packets))) {
1020 if (debug > 2) { 1012 if (debug > 2) {
1021 printf("not a proper ICMP_ECHOREPLY\n"); 1013 printf("not a proper ICMP_ECHOREPLY\n");
1022 } 1014 }
1023 handle_random_icmp(buf + hlen, &resp_addr); 1015
1016 handle_random_icmp(buf + hlen, &resp_addr, pkt_interval, target_interval, pid, table,
1017 packets, number_of_targets, program_state);
1018
1024 continue; 1019 continue;
1025 } 1020 }
1026 1021
@@ -1030,20 +1025,22 @@ static int wait_for_reply(int sock, u_int t) {
1030 if (address_family == PF_INET) { 1025 if (address_family == PF_INET) {
1031 memcpy(&data, packet.icp->icmp_data, sizeof(data)); 1026 memcpy(&data, packet.icp->icmp_data, sizeof(data));
1032 if (debug > 2) { 1027 if (debug > 2) {
1033 printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n", sizeof(data), ntohs(packet.icp->icmp_id), 1028 printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n", sizeof(data),
1034 ntohs(packet.icp->icmp_seq), packet.icp->icmp_cksum); 1029 ntohs(packet.icp->icmp_id), ntohs(packet.icp->icmp_seq),
1030 packet.icp->icmp_cksum);
1035 } 1031 }
1036 host = table[ntohs(packet.icp->icmp_seq) / packets]; 1032 host = table[ntohs(packet.icp->icmp_seq) / packets];
1037 } else { 1033 } else {
1038 memcpy(&data, &packet.icp6->icmp6_dataun.icmp6_un_data8[4], sizeof(data)); 1034 memcpy(&data, &packet.icp6->icmp6_dataun.icmp6_un_data8[4], sizeof(data));
1039 if (debug > 2) { 1035 if (debug > 2) {
1040 printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n", sizeof(data), ntohs(packet.icp6->icmp6_id), 1036 printf("ICMP echo-reply of len %lu, id %u, seq %u, cksum 0x%X\n", sizeof(data),
1041 ntohs(packet.icp6->icmp6_seq), packet.icp6->icmp6_cksum); 1037 ntohs(packet.icp6->icmp6_id), ntohs(packet.icp6->icmp6_seq),
1038 packet.icp6->icmp6_cksum);
1042 } 1039 }
1043 host = table[ntohs(packet.icp6->icmp6_seq) / packets]; 1040 host = table[ntohs(packet.icp6->icmp6_seq) / packets];
1044 } 1041 }
1045 1042
1046 u_int tdiff = get_timevaldiff(&data.stime, &now); 1043 unsigned int tdiff = get_timevaldiff(&data.stime, &now, prog_start);
1047 1044
1048 if (host->last_tdiff > 0) { 1045 if (host->last_tdiff > 0) {
1049 /* Calculate jitter */ 1046 /* Calculate jitter */
@@ -1081,7 +1078,7 @@ static int wait_for_reply(int sock, u_int t) {
1081 1078
1082 host->time_waited += tdiff; 1079 host->time_waited += tdiff;
1083 host->icmp_recv++; 1080 host->icmp_recv++;
1084 icmp_recv++; 1081 program_state->icmp_recv++;
1085 1082
1086 if (tdiff > (unsigned int)host->rtmax) { 1083 if (tdiff > (unsigned int)host->rtmax) {
1087 host->rtmax = tdiff; 1084 host->rtmax = tdiff;
@@ -1097,13 +1094,14 @@ static int wait_for_reply(int sock, u_int t) {
1097 1094
1098 switch (address_family) { 1095 switch (address_family) {
1099 case AF_INET: { 1096 case AF_INET: {
1100 printf("%0.3f ms rtt from %s, outgoing ttl: %u, incoming ttl: %u, max: %0.3f, min: %0.3f\n", (float)tdiff / 1000, address, 1097 printf("%0.3f ms rtt from %s, incoming ttl: %u, max: %0.3f, min: %0.3f\n",
1101 ttl, ip->ip.ip_ttl, (float)host->rtmax / 1000, (float)host->rtmin / 1000); 1098 (float)tdiff / 1000, address, ip->ip.ip_ttl, (float)host->rtmax / 1000,
1099 (float)host->rtmin / 1000);
1102 break; 1100 break;
1103 }; 1101 };
1104 case AF_INET6: { 1102 case AF_INET6: {
1105 printf("%0.3f ms rtt from %s, outgoing ttl: %u, max: %0.3f, min: %0.3f\n", (float)tdiff / 1000, address, ttl, 1103 printf("%0.3f ms rtt from %s, max: %0.3f, min: %0.3f\n", (float)tdiff / 1000,
1106 (float)host->rtmax / 1000, (float)host->rtmin / 1000); 1104 address, (float)host->rtmax / 1000, (float)host->rtmin / 1000);
1107 }; 1105 };
1108 } 1106 }
1109 } 1107 }
@@ -1112,7 +1110,8 @@ static int wait_for_reply(int sock, u_int t) {
1112 if (mode == MODE_HOSTCHECK) { 1110 if (mode == MODE_HOSTCHECK) {
1113 printf("OK - %s responds to ICMP. Packet %u, rta %0.3fms|" 1111 printf("OK - %s responds to ICMP. Packet %u, rta %0.3fms|"
1114 "pkt=%u;;;0;%u rta=%0.3f;%0.3f;%0.3f;;\n", 1112 "pkt=%u;;;0;%u rta=%0.3f;%0.3f;%0.3f;;\n",
1115 host->name, icmp_recv, (float)tdiff / 1000, icmp_recv, packets, (float)tdiff / 1000, (float)warn.rta / 1000, 1113 host->name, program_state->icmp_recv, (float)tdiff / 1000,
1114 program_state->icmp_recv, packets, (float)tdiff / 1000, (float)warn.rta / 1000,
1116 (float)crit.rta / 1000); 1115 (float)crit.rta / 1000);
1117 exit(STATE_OK); 1116 exit(STATE_OK);
1118 } 1117 }
@@ -1123,7 +1122,8 @@ static int wait_for_reply(int sock, u_int t) {
1123} 1122}
1124 1123
1125/* the ping functions */ 1124/* the ping functions */
1126static int send_icmp_ping(int sock, struct rta_host *host) { 1125static int send_icmp_ping(const int sock, struct rta_host *host, const unsigned short icmp_pkt_size,
1126 const pid_t pid, check_icmp_state *program_state) {
1127 if (sock == -1) { 1127 if (sock == -1) {
1128 errno = 0; 1128 errno = 0;
1129 crash("Attempt to send on bogus socket"); 1129 crash("Attempt to send on bogus socket");
@@ -1141,6 +1141,7 @@ static int send_icmp_ping(int sock, struct rta_host *host) {
1141 memset(buf, 0, icmp_pkt_size); 1141 memset(buf, 0, icmp_pkt_size);
1142 1142
1143 struct timeval tv; 1143 struct timeval tv;
1144 struct timezone tz;
1144 if ((gettimeofday(&tv, &tz)) == -1) { 1145 if ((gettimeofday(&tv, &tz)) == -1) {
1145 free(buf); 1146 free(buf);
1146 return -1; 1147 return -1;
@@ -1166,8 +1167,9 @@ static int send_icmp_ping(int sock, struct rta_host *host) {
1166 icp->icmp_cksum = icmp_checksum((uint16_t *)buf, (size_t)icmp_pkt_size); 1167 icp->icmp_cksum = icmp_checksum((uint16_t *)buf, (size_t)icmp_pkt_size);
1167 1168
1168 if (debug > 2) { 1169 if (debug > 2) {
1169 printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n", sizeof(data), ntohs(icp->icmp_id), 1170 printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n",
1170 ntohs(icp->icmp_seq), icp->icmp_cksum, host->name); 1171 sizeof(data), ntohs(icp->icmp_id), ntohs(icp->icmp_seq), icp->icmp_cksum,
1172 host->name);
1171 } 1173 }
1172 } else { 1174 } else {
1173 struct icmp6_hdr *icp6 = (struct icmp6_hdr *)buf; 1175 struct icmp6_hdr *icp6 = (struct icmp6_hdr *)buf;
@@ -1183,8 +1185,9 @@ static int send_icmp_ping(int sock, struct rta_host *host) {
1183 // let checksum be calculated automatically 1185 // let checksum be calculated automatically
1184 1186
1185 if (debug > 2) { 1187 if (debug > 2) {
1186 printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n", sizeof(data), ntohs(icp6->icmp6_id), 1188 printf("Sending ICMP echo-request of len %lu, id %u, seq %u, cksum 0x%X to host %s\n",
1187 ntohs(icp6->icmp6_seq), icp6->icmp6_cksum, host->name); 1189 sizeof(data), ntohs(icp6->icmp6_id), ntohs(icp6->icmp6_seq), icp6->icmp6_cksum,
1190 host->name);
1188 } 1191 }
1189 } 1192 }
1190 1193
@@ -1222,13 +1225,14 @@ static int send_icmp_ping(int sock, struct rta_host *host) {
1222 return -1; 1225 return -1;
1223 } 1226 }
1224 1227
1225 icmp_sent++; 1228 program_state->icmp_sent++;
1226 host->icmp_sent++; 1229 host->icmp_sent++;
1227 1230
1228 return 0; 1231 return 0;
1229} 1232}
1230 1233
1231static int recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *saddr, u_int *timo, struct timeval *tv) { 1234static int recvfrom_wto(const int sock, void *buf, const unsigned int len, struct sockaddr *saddr,
1235 unsigned int *timeout, struct timeval *tv, struct timeval *prog_start) {
1232#ifdef HAVE_MSGHDR_MSG_CONTROL 1236#ifdef HAVE_MSGHDR_MSG_CONTROL
1233 char ans_data[4096]; 1237 char ans_data[4096];
1234#endif // HAVE_MSGHDR_MSG_CONTROL 1238#endif // HAVE_MSGHDR_MSG_CONTROL
@@ -1236,16 +1240,16 @@ static int recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *
1236 struct cmsghdr *chdr; 1240 struct cmsghdr *chdr;
1237#endif 1241#endif
1238 1242
1239 if (!*timo) { 1243 if (!*timeout) {
1240 if (debug) { 1244 if (debug) {
1241 printf("*timo is not\n"); 1245 printf("*timeout is not\n");
1242 } 1246 }
1243 return 0; 1247 return 0;
1244 } 1248 }
1245 1249
1246 struct timeval to; 1250 struct timeval to;
1247 to.tv_sec = *timo / 1000000; 1251 to.tv_sec = *timeout / 1000000;
1248 to.tv_usec = (*timo - (to.tv_sec * 1000000)); 1252 to.tv_usec = (*timeout - (to.tv_sec * 1000000));
1249 1253
1250 fd_set rd; 1254 fd_set rd;
1251 fd_set wr; 1255 fd_set wr;
@@ -1255,54 +1259,68 @@ static int recvfrom_wto(int sock, void *buf, unsigned int len, struct sockaddr *
1255 errno = 0; 1259 errno = 0;
1256 1260
1257 struct timeval then; 1261 struct timeval then;
1258 gettimeofday(&then, &tz); 1262 struct timezone time_zone_dummy;
1263 gettimeofday(&then, &time_zone_dummy);
1264
1259 int n = select(sock + 1, &rd, &wr, NULL, &to); 1265 int n = select(sock + 1, &rd, &wr, NULL, &to);
1260 if (n < 0) { 1266 if (n < 0) {
1261 crash("select() in recvfrom_wto"); 1267 crash("select() in recvfrom_wto");
1262 } 1268 }
1269
1263 struct timeval now; 1270 struct timeval now;
1264 gettimeofday(&now, &tz); 1271 gettimeofday(&now, &time_zone_dummy);
1265 *timo = get_timevaldiff(&then, &now); 1272 *timeout = get_timevaldiff(&then, &now, prog_start);
1266 1273
1267 if (!n) { 1274 if (!n) {
1268 return 0; /* timeout */ 1275 return 0; /* timeout */
1269 } 1276 }
1270 1277
1271 u_int slen = sizeof(struct sockaddr_storage); 1278 unsigned int slen = sizeof(struct sockaddr_storage);
1272 1279
1273 struct iovec iov; 1280 struct iovec iov = {
1274 memset(&iov, 0, sizeof(iov)); 1281 .iov_base = buf,
1275 iov.iov_base = buf; 1282 .iov_len = len,
1276 iov.iov_len = len; 1283 };
1277 1284
1278 struct msghdr hdr; 1285 struct msghdr hdr = {
1279 memset(&hdr, 0, sizeof(hdr)); 1286 .msg_name = saddr,
1280 hdr.msg_name = saddr; 1287 .msg_namelen = slen,
1281 hdr.msg_namelen = slen; 1288 .msg_iov = &iov,
1282 hdr.msg_iov = &iov; 1289 .msg_iovlen = 1,
1283 hdr.msg_iovlen = 1;
1284#ifdef HAVE_MSGHDR_MSG_CONTROL 1290#ifdef HAVE_MSGHDR_MSG_CONTROL
1285 hdr.msg_control = ans_data; 1291 .msg_control = ans_data,
1286 hdr.msg_controllen = sizeof(ans_data); 1292 .msg_controllen = sizeof(ans_data),
1287#endif 1293#endif
1294 };
1295
1296 ssize_t ret = recvmsg(sock, &hdr, 0);
1288 1297
1289 int ret = recvmsg(sock, &hdr, 0);
1290#ifdef SO_TIMESTAMP 1298#ifdef SO_TIMESTAMP
1291 for (chdr = CMSG_FIRSTHDR(&hdr); chdr; chdr = CMSG_NXTHDR(&hdr, chdr)) { 1299 for (chdr = CMSG_FIRSTHDR(&hdr); chdr; chdr = CMSG_NXTHDR(&hdr, chdr)) {
1292 if (chdr->cmsg_level == SOL_SOCKET && chdr->cmsg_type == SO_TIMESTAMP && chdr->cmsg_len >= CMSG_LEN(sizeof(struct timeval))) { 1300 if (chdr->cmsg_level == SOL_SOCKET && chdr->cmsg_type == SO_TIMESTAMP &&
1301 chdr->cmsg_len >= CMSG_LEN(sizeof(struct timeval))) {
1293 memcpy(tv, CMSG_DATA(chdr), sizeof(*tv)); 1302 memcpy(tv, CMSG_DATA(chdr), sizeof(*tv));
1294 break; 1303 break;
1295 } 1304 }
1296 } 1305 }
1297 1306
1298 if (!chdr) 1307 if (!chdr) {
1308 gettimeofday(tv, &time_zone_dummy);
1309 }
1310#else
1311 gettimeofday(tv, &time_zone_dummy);
1299#endif // SO_TIMESTAMP 1312#endif // SO_TIMESTAMP
1300 gettimeofday(tv, &tz); 1313
1301 return (ret); 1314 return (ret);
1302} 1315}
1303 1316
1304static void finish(int sig) { 1317static void finish(int sig, bool order_mode, bool mos_mode, bool rta_mode, bool pl_mode,
1318 bool jitter_mode, bool score_mode, int min_hosts_alive, threshold warn,
1319 threshold crit, const int icmp_sock, const unsigned short number_of_targets,
1320 check_icmp_state *program_state) {
1321 // Deactivate alarm
1305 alarm(0); 1322 alarm(0);
1323
1306 if (debug > 1) { 1324 if (debug > 1) {
1307 printf("finish(%d) called\n", sig); 1325 printf("finish(%d) called\n", sig);
1308 } 1326 }
@@ -1310,57 +1328,56 @@ static void finish(int sig) {
1310 if (icmp_sock != -1) { 1328 if (icmp_sock != -1) {
1311 close(icmp_sock); 1329 close(icmp_sock);
1312 } 1330 }
1313 if (udp_sock != -1) {
1314 close(udp_sock);
1315 }
1316 if (tcp_sock != -1) {
1317 close(tcp_sock);
1318 }
1319 1331
1320 if (debug) { 1332 if (debug) {
1321 printf("icmp_sent: %u icmp_recv: %u icmp_lost: %u\n", icmp_sent, icmp_recv, icmp_lost); 1333 printf("icmp_sent: %u icmp_recv: %u icmp_lost: %u\n", program_state->icmp_sent,
1322 printf("targets: %u targets_alive: %u\n", targets, targets_alive); 1334 program_state->icmp_recv, program_state->icmp_lost);
1335 printf("targets: %u targets_alive: %u\n", number_of_targets,
1336 targets_alive(number_of_targets, program_state->targets_down));
1323 } 1337 }
1324 1338
1325 /* iterate thrice to calculate values, give output, and print perfparse */ 1339 /* iterate thrice to calculate values, give output, and print perfparse */
1326 status = STATE_OK; 1340 mp_state_enum status = STATE_OK;
1327 struct rta_host *host = list; 1341 struct rta_host *host = host_list;
1328 1342
1329 u_int i = 0; 1343 unsigned int target_counter = 0;
1330 const char *status_string[] = {"OK", "WARNING", "CRITICAL", "UNKNOWN", "DEPENDENT"}; 1344 const char *status_string[] = {"OK", "WARNING", "CRITICAL", "UNKNOWN", "DEPENDENT"};
1331 int hosts_ok = 0; 1345 int hosts_ok = 0;
1332 int hosts_warn = 0; 1346 int hosts_warn = 0;
1333 while (host) { 1347 while (host) {
1334 int this_status = STATE_OK; 1348 mp_state_enum this_status = STATE_OK;
1335 1349
1336 unsigned char pl; 1350 unsigned char packet_loss;
1337 double rta; 1351 double rta;
1338 if (!host->icmp_recv) { 1352 if (!host->icmp_recv) {
1339 /* rta 0 is ofcourse not entirely correct, but will still show up 1353 /* rta 0 is ofcourse not entirely correct, but will still show up
1340 * conspicuously as missing entries in perfparse and cacti */ 1354 * conspicuously as missing entries in perfparse and cacti */
1341 pl = 100; 1355 packet_loss = 100;
1342 rta = 0; 1356 rta = 0;
1343 status = STATE_CRITICAL; 1357 status = STATE_CRITICAL;
1344 /* up the down counter if not already counted */ 1358 /* up the down counter if not already counted */
1345 if (!(host->flags & FLAG_LOST_CAUSE) && targets_alive) { 1359 if (!(host->flags & FLAG_LOST_CAUSE) &&
1346 targets_down++; 1360 targets_alive(number_of_targets, program_state->targets_down)) {
1361 program_state->targets_down++;
1347 } 1362 }
1348 } else { 1363 } else {
1349 pl = ((host->icmp_sent - host->icmp_recv) * 100) / host->icmp_sent; 1364 packet_loss = ((host->icmp_sent - host->icmp_recv) * 100) / host->icmp_sent;
1350 rta = (double)host->time_waited / host->icmp_recv; 1365 rta = (double)host->time_waited / host->icmp_recv;
1351 } 1366 }
1352 1367
1353 if (host->icmp_recv > 1) { 1368 if (host->icmp_recv > 1) {
1354 /* 1369 /*
1355 * This algorithm is probably pretty much blindly copied from 1370 * This algorithm is probably pretty much blindly copied from
1356 * locations like this one: https://www.slac.stanford.edu/comp/net/wan-mon/tutorial.html#mos 1371 * locations like this one:
1357 * It calculates a MOS value (range of 1 to 5, where 1 is bad and 5 really good). 1372 * https://www.slac.stanford.edu/comp/net/wan-mon/tutorial.html#mos It calculates a MOS
1358 * According to some quick research MOS originates from the Audio/Video transport network area. 1373 * value (range of 1 to 5, where 1 is bad and 5 really good). According to some quick
1359 * Whether it can and should be computed from ICMP data, I can not say. 1374 * research MOS originates from the Audio/Video transport network area. Whether it can
1375 * and should be computed from ICMP data, I can not say.
1360 * 1376 *
1361 * Anyway the basic idea is to map a value "R" with a range of 0-100 to the MOS value 1377 * Anyway the basic idea is to map a value "R" with a range of 0-100 to the MOS value
1362 * 1378 *
1363 * MOS stands likely for Mean Opinion Score ( https://en.wikipedia.org/wiki/Mean_Opinion_Score ) 1379 * MOS stands likely for Mean Opinion Score (
1380 * https://en.wikipedia.org/wiki/Mean_Opinion_Score )
1364 * 1381 *
1365 * More links: 1382 * More links:
1366 * - https://confluence.slac.stanford.edu/display/IEPM/MOS 1383 * - https://confluence.slac.stanford.edu/display/IEPM/MOS
@@ -1383,7 +1400,7 @@ static void finish(int sig) {
1383 1400
1384 // Now, let us deduct 2.5 R values per percentage of packet loss (i.e. a 1401 // Now, let us deduct 2.5 R values per percentage of packet loss (i.e. a
1385 // loss of 5% will be entered as 5). 1402 // loss of 5% will be entered as 5).
1386 R = R - (pl * 2.5); 1403 R = R - (packet_loss * 2.5);
1387 1404
1388 if (R < 0) { 1405 if (R < 0) {
1389 R = 0; 1406 R = 0;
@@ -1398,7 +1415,7 @@ static void finish(int sig) {
1398 host->mos = 0; 1415 host->mos = 0;
1399 } 1416 }
1400 1417
1401 host->pl = pl; 1418 host->pl = packet_loss;
1402 host->rta = rta; 1419 host->rta = rta;
1403 1420
1404 /* if no new mode selected, use old schema */ 1421 /* if no new mode selected, use old schema */
@@ -1421,11 +1438,11 @@ static void finish(int sig) {
1421 } 1438 }
1422 1439
1423 if (pl_mode) { 1440 if (pl_mode) {
1424 if (pl >= crit.pl) { 1441 if (packet_loss >= crit.pl) {
1425 this_status = STATE_CRITICAL; 1442 this_status = STATE_CRITICAL;
1426 status = STATE_CRITICAL; 1443 status = STATE_CRITICAL;
1427 host->pl_status = STATE_CRITICAL; 1444 host->pl_status = STATE_CRITICAL;
1428 } else if (status != STATE_CRITICAL && (pl >= warn.pl)) { 1445 } else if (status != STATE_CRITICAL && (packet_loss >= warn.pl)) {
1429 this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status); 1446 this_status = (this_status <= STATE_WARNING ? STATE_WARNING : this_status);
1430 status = STATE_WARNING; 1447 status = STATE_WARNING;
1431 host->pl_status = STATE_WARNING; 1448 host->pl_status = STATE_WARNING;
@@ -1478,7 +1495,7 @@ static void finish(int sig) {
1478 } 1495 }
1479 1496
1480 /* this is inevitable */ 1497 /* this is inevitable */
1481 if (!targets_alive) { 1498 if (!targets_alive(number_of_targets, program_state->targets_down)) {
1482 status = STATE_CRITICAL; 1499 status = STATE_CRITICAL;
1483 } 1500 }
1484 if (min_hosts_alive > -1) { 1501 if (min_hosts_alive > -1) {
@@ -1490,21 +1507,21 @@ static void finish(int sig) {
1490 } 1507 }
1491 printf("%s - ", status_string[status]); 1508 printf("%s - ", status_string[status]);
1492 1509
1493 host = list; 1510 host = host_list;
1494 while (host) { 1511 while (host) {
1495 if (debug) { 1512 if (debug) {
1496 puts(""); 1513 puts("");
1497 } 1514 }
1498 1515
1499 if (i) { 1516 if (target_counter) {
1500 if (i < targets) { 1517 if (target_counter < number_of_targets) {
1501 printf(" :: "); 1518 printf(" :: ");
1502 } else { 1519 } else {
1503 printf("\n"); 1520 printf("\n");
1504 } 1521 }
1505 } 1522 }
1506 1523
1507 i++; 1524 target_counter++;
1508 1525
1509 if (!host->icmp_recv) { 1526 if (!host->icmp_recv) {
1510 status = STATE_CRITICAL; 1527 status = STATE_CRITICAL;
@@ -1514,7 +1531,8 @@ static void finish(int sig) {
1514 if (host->flags & FLAG_LOST_CAUSE) { 1531 if (host->flags & FLAG_LOST_CAUSE) {
1515 char address[INET6_ADDRSTRLEN]; 1532 char address[INET6_ADDRSTRLEN];
1516 parse_address(&host->error_addr, address, sizeof(address)); 1533 parse_address(&host->error_addr, address, sizeof(address));
1517 printf("%s: %s @ %s. rta nan, lost %d%%", host->name, get_icmp_error_msg(host->icmp_type, host->icmp_code), address, 100); 1534 printf("%s: %s @ %s. rta nan, lost %d%%", host->name,
1535 get_icmp_error_msg(host->icmp_type, host->icmp_code), address, 100);
1518 } else { /* not marked as lost cause, so we have no flags for it */ 1536 } else { /* not marked as lost cause, so we have no flags for it */
1519 printf("%s: rta nan, lost 100%%", host->name); 1537 printf("%s: rta nan, lost 100%%", host->name);
1520 } 1538 }
@@ -1525,9 +1543,11 @@ static void finish(int sig) {
1525 if (status == STATE_OK) { 1543 if (status == STATE_OK) {
1526 printf(" rta %0.3fms", host->rta / 1000); 1544 printf(" rta %0.3fms", host->rta / 1000);
1527 } else if (status == STATE_WARNING && host->rta_status == status) { 1545 } else if (status == STATE_WARNING && host->rta_status == status) {
1528 printf(" rta %0.3fms > %0.3fms", (float)host->rta / 1000, (float)warn.rta / 1000); 1546 printf(" rta %0.3fms > %0.3fms", (float)host->rta / 1000,
1547 (float)warn.rta / 1000);
1529 } else if (status == STATE_CRITICAL && host->rta_status == status) { 1548 } else if (status == STATE_CRITICAL && host->rta_status == status) {
1530 printf(" rta %0.3fms > %0.3fms", (float)host->rta / 1000, (float)crit.rta / 1000); 1549 printf(" rta %0.3fms > %0.3fms", (float)host->rta / 1000,
1550 (float)crit.rta / 1000);
1531 } 1551 }
1532 } 1552 }
1533 1553
@@ -1591,8 +1611,8 @@ static void finish(int sig) {
1591 if (!(!rta_mode && !pl_mode && !jitter_mode && !score_mode && !mos_mode && order_mode)) { 1611 if (!(!rta_mode && !pl_mode && !jitter_mode && !score_mode && !mos_mode && order_mode)) {
1592 printf("|"); 1612 printf("|");
1593 } 1613 }
1594 i = 0; 1614 target_counter = 0;
1595 host = list; 1615 host = host_list;
1596 while (host) { 1616 while (host) {
1597 if (debug) { 1617 if (debug) {
1598 puts(""); 1618 puts("");
@@ -1600,45 +1620,56 @@ static void finish(int sig) {
1600 1620
1601 if (rta_mode) { 1621 if (rta_mode) {
1602 if (host->pl < 100) { 1622 if (host->pl < 100) {
1603 printf("%srta=%0.3fms;%0.3f;%0.3f;0; %srtmax=%0.3fms;;;; %srtmin=%0.3fms;;;; ", (targets > 1) ? host->name : "", 1623 printf("%srta=%0.3fms;%0.3f;%0.3f;0; %srtmax=%0.3fms;;;; %srtmin=%0.3fms;;;; ",
1604 host->rta / 1000, (float)warn.rta / 1000, (float)crit.rta / 1000, (targets > 1) ? host->name : "", 1624 (number_of_targets > 1) ? host->name : "", host->rta / 1000,
1605 (float)host->rtmax / 1000, (targets > 1) ? host->name : "", 1625 (float)warn.rta / 1000, (float)crit.rta / 1000,
1626 (number_of_targets > 1) ? host->name : "", (float)host->rtmax / 1000,
1627 (number_of_targets > 1) ? host->name : "",
1606 (host->rtmin < INFINITY) ? (float)host->rtmin / 1000 : (float)0); 1628 (host->rtmin < INFINITY) ? (float)host->rtmin / 1000 : (float)0);
1607 } else { 1629 } else {
1608 printf("%srta=U;;;; %srtmax=U;;;; %srtmin=U;;;; ", (targets > 1) ? host->name : "", (targets > 1) ? host->name : "", 1630 printf("%srta=U;;;; %srtmax=U;;;; %srtmin=U;;;; ",
1609 (targets > 1) ? host->name : ""); 1631 (number_of_targets > 1) ? host->name : "",
1632 (number_of_targets > 1) ? host->name : "",
1633 (number_of_targets > 1) ? host->name : "");
1610 } 1634 }
1611 } 1635 }
1612 1636
1613 if (pl_mode) { 1637 if (pl_mode) {
1614 printf("%spl=%u%%;%u;%u;0;100 ", (targets > 1) ? host->name : "", host->pl, warn.pl, crit.pl); 1638 printf("%spl=%u%%;%u;%u;0;100 ", (number_of_targets > 1) ? host->name : "", host->pl,
1639 warn.pl, crit.pl);
1615 } 1640 }
1616 1641
1617 if (jitter_mode) { 1642 if (jitter_mode) {
1618 if (host->pl < 100) { 1643 if (host->pl < 100) {
1619 printf("%sjitter_avg=%0.3fms;%0.3f;%0.3f;0; %sjitter_max=%0.3fms;;;; %sjitter_min=%0.3fms;;;; ", 1644 printf("%sjitter_avg=%0.3fms;%0.3f;%0.3f;0; %sjitter_max=%0.3fms;;;; "
1620 (targets > 1) ? host->name : "", (float)host->jitter, (float)warn.jitter, (float)crit.jitter, 1645 "%sjitter_min=%0.3fms;;;; ",
1621 (targets > 1) ? host->name : "", (float)host->jitter_max / 1000, (targets > 1) ? host->name : "", 1646 (number_of_targets > 1) ? host->name : "", (float)host->jitter,
1622 (float)host->jitter_min / 1000); 1647 (float)warn.jitter, (float)crit.jitter,
1648 (number_of_targets > 1) ? host->name : "", (float)host->jitter_max / 1000,
1649 (number_of_targets > 1) ? host->name : "", (float)host->jitter_min / 1000);
1623 } else { 1650 } else {
1624 printf("%sjitter_avg=U;;;; %sjitter_max=U;;;; %sjitter_min=U;;;; ", (targets > 1) ? host->name : "", 1651 printf("%sjitter_avg=U;;;; %sjitter_max=U;;;; %sjitter_min=U;;;; ",
1625 (targets > 1) ? host->name : "", (targets > 1) ? host->name : ""); 1652 (number_of_targets > 1) ? host->name : "",
1653 (number_of_targets > 1) ? host->name : "",
1654 (number_of_targets > 1) ? host->name : "");
1626 } 1655 }
1627 } 1656 }
1628 1657
1629 if (mos_mode) { 1658 if (mos_mode) {
1630 if (host->pl < 100) { 1659 if (host->pl < 100) {
1631 printf("%smos=%0.1f;%0.1f;%0.1f;0;5 ", (targets > 1) ? host->name : "", (float)host->mos, (float)warn.mos, (float)crit.mos); 1660 printf("%smos=%0.1f;%0.1f;%0.1f;0;5 ", (number_of_targets > 1) ? host->name : "",
1661 (float)host->mos, (float)warn.mos, (float)crit.mos);
1632 } else { 1662 } else {
1633 printf("%smos=U;;;; ", (targets > 1) ? host->name : ""); 1663 printf("%smos=U;;;; ", (number_of_targets > 1) ? host->name : "");
1634 } 1664 }
1635 } 1665 }
1636 1666
1637 if (score_mode) { 1667 if (score_mode) {
1638 if (host->pl < 100) { 1668 if (host->pl < 100) {
1639 printf("%sscore=%u;%u;%u;0;100 ", (targets > 1) ? host->name : "", (int)host->score, (int)warn.score, (int)crit.score); 1669 printf("%sscore=%u;%u;%u;0;100 ", (number_of_targets > 1) ? host->name : "",
1670 (int)host->score, (int)warn.score, (int)crit.score);
1640 } else { 1671 } else {
1641 printf("%sscore=U;;;; ", (targets > 1) ? host->name : ""); 1672 printf("%sscore=U;;;; ", (number_of_targets > 1) ? host->name : "");
1642 } 1673 }
1643 } 1674 }
1644 1675
@@ -1656,46 +1687,53 @@ static void finish(int sig) {
1656 /* finish with an empty line */ 1687 /* finish with an empty line */
1657 puts(""); 1688 puts("");
1658 if (debug) { 1689 if (debug) {
1659 printf("targets: %u, targets_alive: %u, hosts_ok: %u, hosts_warn: %u, min_hosts_alive: %i\n", targets, targets_alive, hosts_ok, 1690 printf(
1660 hosts_warn, min_hosts_alive); 1691 "targets: %u, targets_alive: %u, hosts_ok: %u, hosts_warn: %u, min_hosts_alive: %i\n",
1692 number_of_targets, targets_alive(number_of_targets, program_state->targets_down),
1693 hosts_ok, hosts_warn, min_hosts_alive);
1661 } 1694 }
1662 1695
1663 exit(status); 1696 exit(status);
1664} 1697}
1665 1698
1666static u_int get_timevaldiff(struct timeval *early, struct timeval *later) { 1699static time_t get_timevaldiff(struct timeval *earlier, struct timeval *later,
1700 struct timeval *prog_start) {
1667 struct timeval now; 1701 struct timeval now;
1668 1702
1669 if (!later) { 1703 if (!later) {
1670 gettimeofday(&now, &tz); 1704 struct timezone time_zone_dummy;
1705 gettimeofday(&now, &time_zone_dummy);
1671 later = &now; 1706 later = &now;
1672 } 1707 }
1673 if (!early) { 1708 if (!earlier) {
1674 early = &prog_start; 1709 earlier = prog_start;
1675 } 1710 }
1676 1711
1677 /* if early > later we return 0 so as to indicate a timeout */ 1712 /* if early > later we return 0 so as to indicate a timeout */
1678 if (early->tv_sec > later->tv_sec || (early->tv_sec == later->tv_sec && early->tv_usec > later->tv_usec)) { 1713 if (earlier->tv_sec > later->tv_sec ||
1714 (earlier->tv_sec == later->tv_sec && earlier->tv_usec > later->tv_usec)) {
1679 return 0; 1715 return 0;
1680 } 1716 }
1681 u_int ret = (later->tv_sec - early->tv_sec) * 1000000; 1717
1682 ret += later->tv_usec - early->tv_usec; 1718 time_t ret = (later->tv_sec - earlier->tv_sec) * 1000000;
1719 ret += later->tv_usec - earlier->tv_usec;
1683 1720
1684 return ret; 1721 return ret;
1685} 1722}
1686 1723
1687static int add_target_ip(char *arg, struct sockaddr_storage *in) { 1724static int add_target_ip(char *arg, struct sockaddr_storage *address) {
1688 struct sockaddr_in *sin; 1725 struct sockaddr_in *sin;
1689 struct sockaddr_in6 *sin6; 1726 struct sockaddr_in6 *sin6;
1690 if (address_family == AF_INET) { 1727 if (address_family == AF_INET) {
1691 sin = (struct sockaddr_in *)in; 1728 sin = (struct sockaddr_in *)address;
1692 } else { 1729 } else {
1693 sin6 = (struct sockaddr_in6 *)in; 1730 sin6 = (struct sockaddr_in6 *)address;
1694 } 1731 }
1695 1732
1696 /* disregard obviously stupid addresses 1733 /* disregard obviously stupid addresses
1697 * (I didn't find an ipv6 equivalent to INADDR_NONE) */ 1734 * (I didn't find an ipv6 equivalent to INADDR_NONE) */
1698 if (((address_family == AF_INET && (sin->sin_addr.s_addr == INADDR_NONE || sin->sin_addr.s_addr == INADDR_ANY))) || 1735 if (((address_family == AF_INET &&
1736 (sin->sin_addr.s_addr == INADDR_NONE || sin->sin_addr.s_addr == INADDR_ANY))) ||
1699 (address_family == AF_INET6 && (sin6->sin6_addr.s6_addr == in6addr_any.s6_addr))) { 1737 (address_family == AF_INET6 && (sin6->sin6_addr.s6_addr == in6addr_any.s6_addr))) {
1700 return -1; 1738 return -1;
1701 } 1739 }
@@ -1703,13 +1741,14 @@ static int add_target_ip(char *arg, struct sockaddr_storage *in) {
1703 /* no point in adding two identical IP's, so don't. ;) */ 1741 /* no point in adding two identical IP's, so don't. ;) */
1704 struct sockaddr_in *host_sin; 1742 struct sockaddr_in *host_sin;
1705 struct sockaddr_in6 *host_sin6; 1743 struct sockaddr_in6 *host_sin6;
1706 struct rta_host *host = list; 1744 struct rta_host *host = host_list;
1707 while (host) { 1745 while (host) {
1708 host_sin = (struct sockaddr_in *)&host->saddr_in; 1746 host_sin = (struct sockaddr_in *)&host->saddr_in;
1709 host_sin6 = (struct sockaddr_in6 *)&host->saddr_in; 1747 host_sin6 = (struct sockaddr_in6 *)&host->saddr_in;
1710 1748
1711 if ((address_family == AF_INET && host_sin->sin_addr.s_addr == sin->sin_addr.s_addr) || 1749 if ((address_family == AF_INET && host_sin->sin_addr.s_addr == sin->sin_addr.s_addr) ||
1712 (address_family == AF_INET6 && host_sin6->sin6_addr.s6_addr == sin6->sin6_addr.s6_addr)) { 1750 (address_family == AF_INET6 &&
1751 host_sin6->sin6_addr.s6_addr == sin6->sin6_addr.s6_addr)) {
1713 if (debug) { 1752 if (debug) {
1714 printf("Identical IP already exists. Not adding %s\n", arg); 1753 printf("Identical IP already exists. Not adding %s\n", arg);
1715 } 1754 }
@@ -1722,10 +1761,11 @@ static int add_target_ip(char *arg, struct sockaddr_storage *in) {
1722 host = (struct rta_host *)malloc(sizeof(struct rta_host)); 1761 host = (struct rta_host *)malloc(sizeof(struct rta_host));
1723 if (!host) { 1762 if (!host) {
1724 char straddr[INET6_ADDRSTRLEN]; 1763 char straddr[INET6_ADDRSTRLEN];
1725 parse_address((struct sockaddr_storage *)&in, straddr, sizeof(straddr)); 1764 parse_address((struct sockaddr_storage *)&address, straddr, sizeof(straddr));
1726 crash("add_target_ip(%s, %s): malloc(%lu) failed", arg, straddr, sizeof(struct rta_host)); 1765 crash("add_target_ip(%s, %s): malloc(%lu) failed", arg, straddr, sizeof(struct rta_host));
1727 } 1766 }
1728 memset(host, 0, sizeof(struct rta_host)); 1767
1768 *host = ping_target_init();
1729 1769
1730 /* set the values. use calling name for output */ 1770 /* set the values. use calling name for output */
1731 host->name = strdup(arg); 1771 host->name = strdup(arg);
@@ -1738,39 +1778,23 @@ static int add_target_ip(char *arg, struct sockaddr_storage *in) {
1738 } else { 1778 } else {
1739 host_sin6 = (struct sockaddr_in6 *)&host->saddr_in; 1779 host_sin6 = (struct sockaddr_in6 *)&host->saddr_in;
1740 host_sin6->sin6_family = AF_INET6; 1780 host_sin6->sin6_family = AF_INET6;
1741 memcpy(host_sin6->sin6_addr.s6_addr, sin6->sin6_addr.s6_addr, sizeof host_sin6->sin6_addr.s6_addr); 1781 memcpy(host_sin6->sin6_addr.s6_addr, sin6->sin6_addr.s6_addr,
1742 } 1782 sizeof host_sin6->sin6_addr.s6_addr);
1743 1783 }
1744 /* fill out the sockaddr_in struct */ 1784
1745 host->rtmin = INFINITY; 1785 if (!host_list) {
1746 host->rtmax = 0; 1786 host_list = cursor = host;
1747 host->jitter = 0;
1748 host->jitter_max = 0;
1749 host->jitter_min = INFINITY;
1750 host->last_tdiff = 0;
1751 host->order_status = STATE_OK;
1752 host->last_icmp_seq = 0;
1753 host->rta_status = 0;
1754 host->pl_status = 0;
1755 host->jitter_status = 0;
1756 host->mos_status = 0;
1757 host->score_status = 0;
1758 host->pl_status = 0;
1759
1760 if (!list) {
1761 list = cursor = host;
1762 } else { 1787 } else {
1763 cursor->next = host; 1788 cursor->next = host;
1764 } 1789 }
1765 1790
1766 cursor = host; 1791 cursor = host;
1767 targets++;
1768 1792
1769 return 0; 1793 return 0;
1770} 1794}
1771 1795
1772/* wrapper for add_target_ip */ 1796/* wrapper for add_target_ip */
1773static int add_target(char *arg) { 1797static int add_target(char *arg, const int mode) {
1774 struct sockaddr_storage ip; 1798 struct sockaddr_storage ip;
1775 struct sockaddr_in *sin; 1799 struct sockaddr_in *sin;
1776 struct sockaddr_in6 *sin6; 1800 struct sockaddr_in6 *sin6;
@@ -1850,7 +1874,7 @@ static int add_target(char *arg) {
1850 return 0; 1874 return 0;
1851} 1875}
1852 1876
1853static void set_source_ip(char *arg) { 1877static void set_source_ip(char *arg, const int icmp_sock) {
1854 struct sockaddr_in src; 1878 struct sockaddr_in src;
1855 1879
1856 memset(&src, 0, sizeof(src)); 1880 memset(&src, 0, sizeof(src));
@@ -1894,7 +1918,7 @@ static in_addr_t get_ip_address(const char *ifname) {
1894 * s = seconds 1918 * s = seconds
1895 * return value is in microseconds 1919 * return value is in microseconds
1896 */ 1920 */
1897static u_int get_timevar(const char *str) { 1921static unsigned int get_timevar(const char *str) {
1898 if (!str) { 1922 if (!str) {
1899 return 0; 1923 return 0;
1900 } 1924 }
@@ -1920,7 +1944,7 @@ static u_int get_timevar(const char *str) {
1920 printf("evaluating %s, u: %c, p: %c\n", str, u, p); 1944 printf("evaluating %s, u: %c, p: %c\n", str, u, p);
1921 } 1945 }
1922 1946
1923 u_int factor = 1000; /* default to milliseconds */ 1947 unsigned int factor = 1000; /* default to milliseconds */
1924 if (u == 'u') { 1948 if (u == 'u') {
1925 factor = 1; /* microseconds */ 1949 factor = 1; /* microseconds */
1926 } else if (u == 'm') { 1950 } else if (u == 'm') {
@@ -1933,7 +1957,7 @@ static u_int get_timevar(const char *str) {
1933 } 1957 }
1934 1958
1935 char *ptr; 1959 char *ptr;
1936 u_int i; 1960 unsigned int i;
1937 i = strtoul(str, &ptr, 0); 1961 i = strtoul(str, &ptr, 0);
1938 if (!ptr || *ptr != '.' || strlen(ptr) < 2 || factor == 1) { 1962 if (!ptr || *ptr != '.' || strlen(ptr) < 2 || factor == 1) {
1939 return i * factor; 1963 return i * factor;
@@ -1945,7 +1969,7 @@ static u_int get_timevar(const char *str) {
1945 } 1969 }
1946 1970
1947 /* integer and decimal, respectively */ 1971 /* integer and decimal, respectively */
1948 u_int d = strtoul(ptr + 1, NULL, 0); 1972 unsigned int d = strtoul(ptr + 1, NULL, 0);
1949 1973
1950 /* d is decimal, so get rid of excess digits */ 1974 /* d is decimal, so get rid of excess digits */
1951 while (d >= factor) { 1975 while (d >= factor) {
@@ -2000,9 +2024,11 @@ static int get_threshold(char *str, threshold *th) {
2000 * @param[in] length strlen(str) 2024 * @param[in] length strlen(str)
2001 * @param[out] warn Pointer to the warn threshold struct to which the values should be assigned 2025 * @param[out] warn Pointer to the warn threshold struct to which the values should be assigned
2002 * @param[out] crit Pointer to the crit threshold struct to which the values should be assigned 2026 * @param[out] crit Pointer to the crit threshold struct to which the values should be assigned
2003 * @param[in] mode Determines whether this a threshold for rta, packet_loss, jitter, mos or score (exclusively) 2027 * @param[in] mode Determines whether this a threshold for rta, packet_loss, jitter, mos or score
2028 * (exclusively)
2004 */ 2029 */
2005static bool get_threshold2(char *str, size_t length, threshold *warn, threshold *crit, threshold_mode mode) { 2030static bool get_threshold2(char *str, size_t length, threshold *warn, threshold *crit,
2031 threshold_mode mode) {
2006 if (!str || !length || !warn || !crit) { 2032 if (!str || !length || !warn || !crit) {
2007 return false; 2033 return false;
2008 } 2034 }
@@ -2108,13 +2134,14 @@ void print_help(void) {
2108 printf(" %s\n", _("Use IPv4 (default) or IPv6 to communicate with the targets")); 2134 printf(" %s\n", _("Use IPv4 (default) or IPv6 to communicate with the targets"));
2109 printf(" %s\n", "-w"); 2135 printf(" %s\n", "-w");
2110 printf(" %s", _("warning threshold (currently ")); 2136 printf(" %s", _("warning threshold (currently "));
2111 printf("%0.3fms,%u%%)\n", (float)warn.rta / 1000, warn.pl); 2137 printf("%0.3fms,%u%%)\n", (float)DEFAULT_WARN_RTA / 1000, DEFAULT_WARN_PL);
2112 printf(" %s\n", "-c"); 2138 printf(" %s\n", "-c");
2113 printf(" %s", _("critical threshold (currently ")); 2139 printf(" %s", _("critical threshold (currently "));
2114 printf("%0.3fms,%u%%)\n", (float)crit.rta / 1000, crit.pl); 2140 printf("%0.3fms,%u%%)\n", (float)DEFAULT_CRIT_RTA / 1000, DEFAULT_CRIT_PL);
2115 2141
2116 printf(" %s\n", "-R"); 2142 printf(" %s\n", "-R");
2117 printf(" %s\n", _("RTA, round trip average, mode warning,critical, ex. 100ms,200ms unit in ms")); 2143 printf(" %s\n",
2144 _("RTA, round trip average, mode warning,critical, ex. 100ms,200ms unit in ms"));
2118 printf(" %s\n", "-P"); 2145 printf(" %s\n", "-P");
2119 printf(" %s\n", _("packet loss mode, ex. 40%,50% , unit in %")); 2146 printf(" %s\n", _("packet loss mode, ex. 40%,50% , unit in %"));
2120 printf(" %s\n", "-J"); 2147 printf(" %s\n", "-J");
@@ -2131,28 +2158,29 @@ void print_help(void) {
2131 printf(" %s\n", _("specify a source IP address or device name")); 2158 printf(" %s\n", _("specify a source IP address or device name"));
2132 printf(" %s\n", "-n"); 2159 printf(" %s\n", "-n");
2133 printf(" %s", _("number of packets to send (currently ")); 2160 printf(" %s", _("number of packets to send (currently "));
2134 printf("%u)\n", packets); 2161 printf("%u)\n", DEFAULT_NUMBER_OF_PACKETS);
2135 printf(" %s\n", "-p"); 2162 printf(" %s\n", "-p");
2136 printf(" %s", _("number of packets to send (currently ")); 2163 printf(" %s", _("number of packets to send (currently "));
2137 printf("%u)\n", packets); 2164 printf("%u)\n", DEFAULT_NUMBER_OF_PACKETS);
2138 printf(" %s\n", "-i"); 2165 printf(" %s\n", "-i");
2139 printf(" %s", _("max packet interval (currently ")); 2166 printf(" %s", _("max packet interval (currently "));
2140 printf("%0.3fms)\n", (float)pkt_interval / 1000); 2167 printf("%0.3fms)\n", (float)DEFAULT_PKT_INTERVAL / 1000);
2141 printf(" %s\n", "-I"); 2168 printf(" %s\n", "-I");
2142 printf(" %s", _("max target interval (currently ")); 2169 printf(" %s", _("max target interval (currently "));
2143 printf("%0.3fms)\n", (float)target_interval / 1000); 2170 printf("%0.3fms)\n", (float)DEFAULT_TARGET_INTERVAL / 1000);
2144 printf(" %s\n", "-m"); 2171 printf(" %s\n", "-m");
2145 printf(" %s", _("number of alive hosts required for success")); 2172 printf(" %s", _("number of alive hosts required for success"));
2146 printf("\n"); 2173 printf("\n");
2147 printf(" %s\n", "-l"); 2174 printf(" %s\n", "-l");
2148 printf(" %s", _("TTL on outgoing packets (currently ")); 2175 printf(" %s", _("TTL on outgoing packets (currently "));
2149 printf("%u)\n", ttl); 2176 printf("%u)\n", DEFAULT_TTL);
2150 printf(" %s\n", "-t"); 2177 printf(" %s\n", "-t");
2151 printf(" %s", _("timeout value (seconds, currently ")); 2178 printf(" %s", _("timeout value (seconds, currently "));
2152 printf("%u)\n", timeout); 2179 printf("%u)\n", DEFAULT_TIMEOUT);
2153 printf(" %s\n", "-b"); 2180 printf(" %s\n", "-b");
2154 printf(" %s\n", _("Number of icmp data bytes to send")); 2181 printf(" %s\n", _("Number of icmp data bytes to send"));
2155 printf(" %s %u + %d)\n", _("Packet size will be data bytes + icmp header (currently"), icmp_data_size, ICMP_MINLEN); 2182 printf(" %s %lu + %d)\n", _("Packet size will be data bytes + icmp header (currently"),
2183 DEFAULT_PING_DATA_SIZE, ICMP_MINLEN);
2156 printf(" %s\n", "-v"); 2184 printf(" %s\n", "-v");
2157 printf(" %s\n", _("verbose")); 2185 printf(" %s\n", _("verbose"));
2158 printf("\n"); 2186 printf("\n");
@@ -2162,12 +2190,15 @@ void print_help(void) {
2162 printf("\n"); 2190 printf("\n");
2163 printf(" %s\n", _("Threshold format for -w and -c is 200.25,60% for 200.25 msec RTA and 60%")); 2191 printf(" %s\n", _("Threshold format for -w and -c is 200.25,60% for 200.25 msec RTA and 60%"));
2164 printf(" %s\n", _("packet loss. The default values should work well for most users.")); 2192 printf(" %s\n", _("packet loss. The default values should work well for most users."));
2165 printf(" %s\n", _("You can specify different RTA factors using the standardized abbreviations")); 2193 printf(" %s\n",
2166 printf(" %s\n", _("us (microseconds), ms (milliseconds, default) or just plain s for seconds.")); 2194 _("You can specify different RTA factors using the standardized abbreviations"));
2195 printf(" %s\n",
2196 _("us (microseconds), ms (milliseconds, default) or just plain s for seconds."));
2167 /* -d not yet implemented */ 2197 /* -d not yet implemented */
2168 /* printf ("%s\n", _("Threshold format for -d is warn,crit. 12,14 means WARNING if >= 12 hops")); 2198 /* printf ("%s\n", _("Threshold format for -d is warn,crit. 12,14 means WARNING if >= 12
2169 printf ("%s\n", _("are spent and CRITICAL if >= 14 hops are spent.")); 2199 hops")); printf ("%s\n", _("are spent and CRITICAL if >= 14 hops are spent.")); printf
2170 printf ("%s\n\n", _("NOTE: Some systems decrease TTL when forming ICMP_ECHOREPLY, others do not."));*/ 2200 ("%s\n\n", _("NOTE: Some systems decrease TTL when forming ICMP_ECHOREPLY, others do
2201 not."));*/
2171 printf("\n"); 2202 printf("\n");
2172 printf(" %s\n", _("The -v switch can be specified several times for increased verbosity.")); 2203 printf(" %s\n", _("The -v switch can be specified several times for increased verbosity."));
2173 /* printf ("%s\n", _("Long options are currently unsupported.")); 2204 /* printf ("%s\n", _("Long options are currently unsupported."));