summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/utils_tcp.h1
-rw-r--r--plugins/Makefile.am7
-rw-r--r--plugins/check_ntp_peer.c385
-rw-r--r--plugins/check_ntp_peer.d/config.h67
-rw-r--r--plugins/check_ping.c529
-rw-r--r--plugins/check_ping.d/config.h46
-rw-r--r--plugins/check_radius.c541
-rw-r--r--plugins/check_radius.d/config.h42
-rw-r--r--plugins/check_tcp.c777
-rw-r--r--plugins/check_tcp.d/config.h84
-rw-r--r--plugins/check_time.c191
-rw-r--r--plugins/check_time.d/config.h42
-rw-r--r--plugins/check_ups.c274
-rw-r--r--plugins/check_ups.d/config.h55
-rw-r--r--plugins/negate.c96
-rw-r--r--plugins/negate.d/config.h24
-rw-r--r--plugins/t/check_ftp.t2
-rw-r--r--plugins/t/check_jabber.t4
-rw-r--r--plugins/t/check_tcp.t12
-rw-r--r--plugins/t/check_udp.t4
20 files changed, 1895 insertions, 1288 deletions
diff --git a/lib/utils_tcp.h b/lib/utils_tcp.h
index d5999e9b..a7d83c59 100644
--- a/lib/utils_tcp.h
+++ b/lib/utils_tcp.h
@@ -11,6 +11,7 @@
11 * server. 11 * server.
12 */ 12 */
13enum np_match_result { 13enum np_match_result {
14 NP_MATCH_NONE,
14 NP_MATCH_FAILURE, 15 NP_MATCH_FAILURE,
15 NP_MATCH_SUCCESS, 16 NP_MATCH_SUCCESS,
16 NP_MATCH_RETRY 17 NP_MATCH_RETRY
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 3269b9fb..30ca63d1 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -49,12 +49,16 @@ np_test_scripts = tests/test_check_swap.t
49EXTRA_DIST = t \ 49EXTRA_DIST = t \
50 tests \ 50 tests \
51 $(np_test_scripts) \ 51 $(np_test_scripts) \
52 negate.d \
52 check_swap.d \ 53 check_swap.d \
53 check_ldap.d \ 54 check_ldap.d \
54 check_hpjd.d \ 55 check_hpjd.d \
55 check_game.d \ 56 check_game.d \
57 check_radius.d \
58 check_time.d \
56 check_nagios.d \ 59 check_nagios.d \
57 check_dbi.d \ 60 check_dbi.d \
61 check_tcp.d \
58 check_real.d \ 62 check_real.d \
59 check_ssh.d \ 63 check_ssh.d \
60 check_nt.d \ 64 check_nt.d \
@@ -62,14 +66,17 @@ EXTRA_DIST = t \
62 check_mrtgtraf.d \ 66 check_mrtgtraf.d \
63 check_mysql_query.d \ 67 check_mysql_query.d \
64 check_mrtg.d \ 68 check_mrtg.d \
69 check_ntp_peer.d \
65 check_apt.d \ 70 check_apt.d \
66 check_pgsql.d \ 71 check_pgsql.d \
72 check_ping.d \
67 check_by_ssh.d \ 73 check_by_ssh.d \
68 check_smtp.d \ 74 check_smtp.d \
69 check_mysql.d \ 75 check_mysql.d \
70 check_ntp_time.d \ 76 check_ntp_time.d \
71 check_dig.d \ 77 check_dig.d \
72 check_cluster.d \ 78 check_cluster.d \
79 check_ups.d \
73 check_fping.d 80 check_fping.d
74 81
75PLUGINHDRS = common.h 82PLUGINHDRS = common.h
diff --git a/plugins/check_ntp_peer.c b/plugins/check_ntp_peer.c
index f99e5032..6e76bf23 100644
--- a/plugins/check_ntp_peer.c
+++ b/plugins/check_ntp_peer.c
@@ -35,6 +35,7 @@
35 * 35 *
36 *****************************************************************************/ 36 *****************************************************************************/
37 37
38#include "thresholds.h"
38const char *progname = "check_ntp_peer"; 39const char *progname = "check_ntp_peer";
39const char *copyright = "2006-2024"; 40const char *copyright = "2006-2024";
40const char *email = "devel@monitoring-plugins.org"; 41const char *email = "devel@monitoring-plugins.org";
@@ -42,30 +43,18 @@ const char *email = "devel@monitoring-plugins.org";
42#include "common.h" 43#include "common.h"
43#include "netutils.h" 44#include "netutils.h"
44#include "utils.h" 45#include "utils.h"
46#include "../lib/states.h"
47#include "check_ntp_peer.d/config.h"
45 48
46static char *server_address = NULL;
47static int port = 123;
48static int verbose = 0; 49static int verbose = 0;
49static bool quiet = false;
50static char *owarn = "60";
51static char *ocrit = "120";
52static bool do_stratum = false;
53static char *swarn = "-1:16";
54static char *scrit = "-1:16";
55static bool do_jitter = false;
56static char *jwarn = "-1:5000";
57static char *jcrit = "-1:10000";
58static bool do_truechimers = false;
59static char *twarn = "0:";
60static char *tcrit = "0:";
61static bool syncsource_found = false; 50static bool syncsource_found = false;
62static bool li_alarm = false; 51static bool li_alarm = false;
63 52
64static int process_arguments(int /*argc*/, char ** /*argv*/); 53typedef struct {
65static thresholds *offset_thresholds = NULL; 54 int errorcode;
66static thresholds *jitter_thresholds = NULL; 55 check_ntp_peer_config config;
67static thresholds *stratum_thresholds = NULL; 56} check_ntp_peer_config_wrapper;
68static thresholds *truechimer_thresholds = NULL; 57static check_ntp_peer_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
69static void print_help(void); 58static void print_help(void);
70void print_usage(void); 59void print_usage(void);
71 60
@@ -157,25 +146,25 @@ typedef struct {
157 printf("%u.%u.%u.%u", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); \ 146 printf("%u.%u.%u.%u", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); \
158 } while (0); 147 } while (0);
159 148
160void print_ntp_control_message(const ntp_control_message *p) { 149void print_ntp_control_message(const ntp_control_message *message) {
161 printf("control packet contents:\n"); 150 printf("control packet contents:\n");
162 printf("\tflags: 0x%.2x , 0x%.2x\n", p->flags, p->op); 151 printf("\tflags: 0x%.2x , 0x%.2x\n", message->flags, message->op);
163 printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags & LI_MASK); 152 printf("\t li=%d (0x%.2x)\n", LI(message->flags), message->flags & LI_MASK);
164 printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags & VN_MASK); 153 printf("\t vn=%d (0x%.2x)\n", VN(message->flags), message->flags & VN_MASK);
165 printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags & MODE_MASK); 154 printf("\t mode=%d (0x%.2x)\n", MODE(message->flags), message->flags & MODE_MASK);
166 printf("\t response=%d (0x%.2x)\n", (p->op & REM_RESP) > 0, p->op & REM_RESP); 155 printf("\t response=%d (0x%.2x)\n", (message->op & REM_RESP) > 0, message->op & REM_RESP);
167 printf("\t more=%d (0x%.2x)\n", (p->op & REM_MORE) > 0, p->op & REM_MORE); 156 printf("\t more=%d (0x%.2x)\n", (message->op & REM_MORE) > 0, message->op & REM_MORE);
168 printf("\t error=%d (0x%.2x)\n", (p->op & REM_ERROR) > 0, p->op & REM_ERROR); 157 printf("\t error=%d (0x%.2x)\n", (message->op & REM_ERROR) > 0, message->op & REM_ERROR);
169 printf("\t op=%d (0x%.2x)\n", p->op & OP_MASK, p->op & OP_MASK); 158 printf("\t op=%d (0x%.2x)\n", message->op & OP_MASK, message->op & OP_MASK);
170 printf("\tsequence: %d (0x%.2x)\n", ntohs(p->seq), ntohs(p->seq)); 159 printf("\tsequence: %d (0x%.2x)\n", ntohs(message->seq), ntohs(message->seq));
171 printf("\tstatus: %d (0x%.2x)\n", ntohs(p->status), ntohs(p->status)); 160 printf("\tstatus: %d (0x%.2x)\n", ntohs(message->status), ntohs(message->status));
172 printf("\tassoc: %d (0x%.2x)\n", ntohs(p->assoc), ntohs(p->assoc)); 161 printf("\tassoc: %d (0x%.2x)\n", ntohs(message->assoc), ntohs(message->assoc));
173 printf("\toffset: %d (0x%.2x)\n", ntohs(p->offset), ntohs(p->offset)); 162 printf("\toffset: %d (0x%.2x)\n", ntohs(message->offset), ntohs(message->offset));
174 printf("\tcount: %d (0x%.2x)\n", ntohs(p->count), ntohs(p->count)); 163 printf("\tcount: %d (0x%.2x)\n", ntohs(message->count), ntohs(message->count));
175 164
176 int numpeers = ntohs(p->count) / (sizeof(ntp_assoc_status_pair)); 165 int numpeers = ntohs(message->count) / (sizeof(ntp_assoc_status_pair));
177 if (p->op & REM_RESP && p->op & OP_READSTAT) { 166 if (message->op & REM_RESP && message->op & OP_READSTAT) {
178 const ntp_assoc_status_pair *peer = (ntp_assoc_status_pair *)p->data; 167 const ntp_assoc_status_pair *peer = (ntp_assoc_status_pair *)message->data;
179 for (int i = 0; i < numpeers; i++) { 168 for (int i = 0; i < numpeers; i++) {
180 printf("\tpeer id %.2x status %.2x", ntohs(peer[i].assoc), ntohs(peer[i].status)); 169 printf("\tpeer id %.2x status %.2x", ntohs(peer[i].assoc), ntohs(peer[i].status));
181 if (PEER_SEL(peer[i].status) >= PEER_SYNCSOURCE) { 170 if (PEER_SEL(peer[i].status) >= PEER_SYNCSOURCE) {
@@ -190,13 +179,13 @@ void print_ntp_control_message(const ntp_control_message *p) {
190 } 179 }
191} 180}
192 181
193void setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq) { 182void setup_control_request(ntp_control_message *message, uint8_t opcode, uint16_t seq) {
194 memset(p, 0, sizeof(ntp_control_message)); 183 memset(message, 0, sizeof(ntp_control_message));
195 LI_SET(p->flags, LI_NOWARNING); 184 LI_SET(message->flags, LI_NOWARNING);
196 VN_SET(p->flags, VN_RESERVED); 185 VN_SET(message->flags, VN_RESERVED);
197 MODE_SET(p->flags, MODE_CONTROLMSG); 186 MODE_SET(message->flags, MODE_CONTROLMSG);
198 OP_SET(p->op, opcode); 187 OP_SET(message->op, opcode);
199 p->seq = htons(seq); 188 message->seq = htons(seq);
200 /* Remaining fields are zero for requests */ 189 /* Remaining fields are zero for requests */
201} 190}
202 191
@@ -211,10 +200,23 @@ void setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq)
211 * status is pretty much useless as syncsource_found is a global variable 200 * status is pretty much useless as syncsource_found is a global variable
212 * used later in main to check is the server was synchronized. It works 201 * used later in main to check is the server was synchronized. It works
213 * so I left it alone */ 202 * so I left it alone */
214int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum, int *num_truechimers) { 203typedef struct {
215 *offset_result = STATE_UNKNOWN; 204 mp_state_enum state;
216 *jitter = *stratum = -1; 205 mp_state_enum offset_result;
217 *num_truechimers = 0; 206 double offset;
207 double jitter;
208 long stratum;
209 int num_truechimers;
210} ntp_request_result;
211ntp_request_result ntp_request(const check_ntp_peer_config config) {
212
213 ntp_request_result result = {
214 .state = STATE_OK,
215 .offset_result = STATE_UNKNOWN,
216 .jitter = -1,
217 .stratum = -1,
218 .num_truechimers = 0,
219 };
218 220
219 /* Long-winded explanation: 221 /* Long-winded explanation:
220 * Getting the sync peer offset, jitter and stratum requires a number of 222 * Getting the sync peer offset, jitter and stratum requires a number of
@@ -237,10 +239,10 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
237 void *tmp; 239 void *tmp;
238 ntp_assoc_status_pair *peers = NULL; 240 ntp_assoc_status_pair *peers = NULL;
239 int peer_offset = 0; 241 int peer_offset = 0;
240 int peers_size = 0; 242 size_t peers_size = 0;
241 int npeers = 0; 243 size_t npeers = 0;
242 int conn = -1; 244 int conn = -1;
243 my_udp_connect(server_address, port, &conn); 245 my_udp_connect(config.server_address, config.port, &conn);
244 246
245 /* keep sending requests until the server stops setting the 247 /* keep sending requests until the server stops setting the
246 * REM_MORE bit, though usually this is only 1 packet. */ 248 * REM_MORE bit, though usually this is only 1 packet. */
@@ -255,24 +257,28 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
255 /* Attempt to read the largest size packet possible */ 257 /* Attempt to read the largest size packet possible */
256 req.count = htons(MAX_CM_SIZE); 258 req.count = htons(MAX_CM_SIZE);
257 DBG(printf("receiving READSTAT response")) 259 DBG(printf("receiving READSTAT response"))
258 if (read(conn, &req, SIZEOF_NTPCM(req)) == -1) 260 if (read(conn, &req, SIZEOF_NTPCM(req)) == -1) {
259 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n"); 261 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
262 }
260 DBG(print_ntp_control_message(&req)); 263 DBG(print_ntp_control_message(&req));
261 /* discard obviously invalid packets */ 264 /* discard obviously invalid packets */
262 if (ntohs(req.count) > MAX_CM_SIZE) 265 if (ntohs(req.count) > MAX_CM_SIZE) {
263 die(STATE_CRITICAL, "NTP CRITICAL: Invalid packet received from NTP server\n"); 266 die(STATE_CRITICAL, "NTP CRITICAL: Invalid packet received from NTP server\n");
267 }
264 } while (!(req.op & OP_READSTAT && ntohs(req.seq) == 1)); 268 } while (!(req.op & OP_READSTAT && ntohs(req.seq) == 1));
265 269
266 if (LI(req.flags) == LI_ALARM) 270 if (LI(req.flags) == LI_ALARM) {
267 li_alarm = true; 271 li_alarm = true;
272 }
268 /* Each peer identifier is 4 bytes in the data section, which 273 /* Each peer identifier is 4 bytes in the data section, which
269 * we represent as a ntp_assoc_status_pair datatype. 274 * we represent as a ntp_assoc_status_pair datatype.
270 */ 275 */
271 peers_size += ntohs(req.count); 276 peers_size += ntohs(req.count);
272 if ((tmp = realloc(peers, peers_size)) == NULL) 277 if ((tmp = realloc(peers, peers_size)) == NULL) {
273 free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n"); 278 free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n");
279 }
274 peers = tmp; 280 peers = tmp;
275 memcpy((void *)((ptrdiff_t)peers + peer_offset), (void *)req.data, ntohs(req.count)); 281 memcpy((peers + peer_offset), (void *)req.data, ntohs(req.count));
276 npeers = peers_size / sizeof(ntp_assoc_status_pair); 282 npeers = peers_size / sizeof(ntp_assoc_status_pair);
277 peer_offset += ntohs(req.count); 283 peer_offset += ntohs(req.count);
278 } while (req.op & REM_MORE); 284 } while (req.op & REM_MORE);
@@ -280,9 +286,9 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
280 /* first, let's find out if we have a sync source, or if there are 286 /* first, let's find out if we have a sync source, or if there are
281 * at least some candidates. In the latter case we'll issue 287 * at least some candidates. In the latter case we'll issue
282 * a warning but go ahead with the check on them. */ 288 * a warning but go ahead with the check on them. */
283 for (int i = 0; i < npeers; i++) { 289 for (size_t i = 0; i < npeers; i++) {
284 if (PEER_SEL(peers[i].status) >= PEER_TRUECHIMER) { 290 if (PEER_SEL(peers[i].status) >= PEER_TRUECHIMER) {
285 (*num_truechimers)++; 291 result.num_truechimers++;
286 if (PEER_SEL(peers[i].status) >= PEER_INCLUDED) { 292 if (PEER_SEL(peers[i].status) >= PEER_INCLUDED) {
287 num_candidates++; 293 num_candidates++;
288 if (PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE) { 294 if (PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE) {
@@ -293,31 +299,35 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
293 } 299 }
294 } 300 }
295 301
296 if (verbose) 302 if (verbose) {
297 printf("%d candidate peers available\n", num_candidates); 303 printf("%d candidate peers available\n", num_candidates);
298 if (verbose && syncsource_found) 304 }
305 if (verbose && syncsource_found) {
299 printf("synchronization source found\n"); 306 printf("synchronization source found\n");
307 }
300 308
301 int status = STATE_OK;
302 if (!syncsource_found) { 309 if (!syncsource_found) {
303 status = STATE_WARNING; 310 result.state = STATE_WARNING;
304 if (verbose) 311 if (verbose) {
305 printf("warning: no synchronization source found\n"); 312 printf("warning: no synchronization source found\n");
313 }
306 } 314 }
307 if (li_alarm) { 315 if (li_alarm) {
308 status = STATE_WARNING; 316 result.state = STATE_WARNING;
309 if (verbose) 317 if (verbose) {
310 printf("warning: LI_ALARM bit is set\n"); 318 printf("warning: LI_ALARM bit is set\n");
319 }
311 } 320 }
312 321
313 const char *getvar = "stratum,offset,jitter"; 322 const char *getvar = "stratum,offset,jitter";
314 char *data; 323 char *data;
315 for (int i = 0; i < npeers; i++) { 324 for (size_t i = 0; i < npeers; i++) {
316 /* Only query this server if it is the current sync source */ 325 /* Only query this server if it is the current sync source */
317 /* If there's no sync.peer, query all candidates and use the best one */ 326 /* If there's no sync.peer, query all candidates and use the best one */
318 if (PEER_SEL(peers[i].status) >= min_peer_sel) { 327 if (PEER_SEL(peers[i].status) >= min_peer_sel) {
319 if (verbose) 328 if (verbose) {
320 printf("Getting offset, jitter and stratum for peer %.2x\n", ntohs(peers[i].assoc)); 329 printf("Getting offset, jitter and stratum for peer %.2x\n", ntohs(peers[i].assoc));
330 }
321 xasprintf(&data, ""); 331 xasprintf(&data, "");
322 do { 332 do {
323 setup_control_request(&req, OP_READVAR, 2); 333 setup_control_request(&req, OP_READVAR, 2);
@@ -342,60 +352,68 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
342 DBG(print_ntp_control_message(&req)); 352 DBG(print_ntp_control_message(&req));
343 } while (!(req.op & OP_READVAR && ntohs(req.seq) == 2)); 353 } while (!(req.op & OP_READVAR && ntohs(req.seq) == 2));
344 354
345 if (!(req.op & REM_ERROR)) 355 if (!(req.op & REM_ERROR)) {
346 xasprintf(&data, "%s%s", data, req.data); 356 xasprintf(&data, "%s%s", data, req.data);
357 }
347 } while (req.op & REM_MORE); 358 } while (req.op & REM_MORE);
348 359
349 if (req.op & REM_ERROR) { 360 if (req.op & REM_ERROR) {
350 if (strstr(getvar, "jitter")) { 361 if (strstr(getvar, "jitter")) {
351 if (verbose) 362 if (verbose) {
352 printf("The command failed. This is usually caused by servers refusing the 'jitter'\nvariable. Restarting with " 363 printf("The command failed. This is usually caused by servers refusing the 'jitter'\nvariable. Restarting with "
353 "'dispersion'...\n"); 364 "'dispersion'...\n");
365 }
354 getvar = "stratum,offset,dispersion"; 366 getvar = "stratum,offset,dispersion";
355 i--; 367 i--;
356 continue; 368 continue;
357 } 369 }
358 if (strlen(getvar)) { 370 if (strlen(getvar)) {
359 if (verbose) 371 if (verbose) {
360 printf("Server didn't like dispersion either; will retrieve everything\n"); 372 printf("Server didn't like dispersion either; will retrieve everything\n");
373 }
361 getvar = ""; 374 getvar = "";
362 i--; 375 i--;
363 continue; 376 continue;
364 } 377 }
365 } 378 }
366 379
367 if (verbose > 1) 380 if (verbose > 1) {
368 printf("Server responded: >>>%s<<<\n", data); 381 printf("Server responded: >>>%s<<<\n", data);
382 }
369 383
370 double tmp_offset = 0; 384 double tmp_offset = 0;
371 char *value; 385 char *value;
372 char *nptr; 386 char *nptr;
373 /* get the offset */ 387 /* get the offset */
374 if (verbose) 388 if (verbose) {
375 printf("parsing offset from peer %.2x: ", ntohs(peers[i].assoc)); 389 printf("parsing offset from peer %.2x: ", ntohs(peers[i].assoc));
390 }
376 391
377 value = np_extract_ntpvar(data, "offset"); 392 value = np_extract_ntpvar(data, "offset");
378 nptr = NULL; 393 nptr = NULL;
379 /* Convert the value if we have one */ 394 /* Convert the value if we have one */
380 if (value != NULL) 395 if (value != NULL) {
381 tmp_offset = strtod(value, &nptr) / 1000; 396 tmp_offset = strtod(value, &nptr) / 1000;
397 }
382 /* If value is null or no conversion was performed */ 398 /* If value is null or no conversion was performed */
383 if (value == NULL || value == nptr) { 399 if (value == NULL || value == nptr) {
384 if (verbose) 400 if (verbose) {
385 printf("error: unable to read server offset response.\n"); 401 printf("error: unable to read server offset response.\n");
402 }
386 } else { 403 } else {
387 if (verbose) 404 if (verbose) {
388 printf("%.10g\n", tmp_offset); 405 printf("%.10g\n", tmp_offset);
389 if (*offset_result == STATE_UNKNOWN || fabs(tmp_offset) < fabs(*offset)) { 406 }
390 *offset = tmp_offset; 407 if (result.offset_result == STATE_UNKNOWN || fabs(tmp_offset) < fabs(result.offset)) {
391 *offset_result = STATE_OK; 408 result.offset = tmp_offset;
409 result.offset_result = STATE_OK;
392 } else { 410 } else {
393 /* Skip this one; move to the next */ 411 /* Skip this one; move to the next */
394 continue; 412 continue;
395 } 413 }
396 } 414 }
397 415
398 if (do_jitter) { 416 if (config.do_jitter) {
399 /* get the jitter */ 417 /* get the jitter */
400 if (verbose) { 418 if (verbose) {
401 printf("parsing %s from peer %.2x: ", strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter", 419 printf("parsing %s from peer %.2x: ", strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter",
@@ -404,19 +422,21 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
404 value = np_extract_ntpvar(data, strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter"); 422 value = np_extract_ntpvar(data, strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter");
405 nptr = NULL; 423 nptr = NULL;
406 /* Convert the value if we have one */ 424 /* Convert the value if we have one */
407 if (value != NULL) 425 if (value != NULL) {
408 *jitter = strtod(value, &nptr); 426 result.jitter = strtod(value, &nptr);
427 }
409 /* If value is null or no conversion was performed */ 428 /* If value is null or no conversion was performed */
410 if (value == NULL || value == nptr) { 429 if (value == NULL || value == nptr) {
411 if (verbose) 430 if (verbose) {
412 printf("error: unable to read server jitter/dispersion response.\n"); 431 printf("error: unable to read server jitter/dispersion response.\n");
413 *jitter = -1; 432 }
433 result.jitter = -1;
414 } else if (verbose) { 434 } else if (verbose) {
415 printf("%.10g\n", *jitter); 435 printf("%.10g\n", result.jitter);
416 } 436 }
417 } 437 }
418 438
419 if (do_stratum) { 439 if (config.do_stratum) {
420 /* get the stratum */ 440 /* get the stratum */
421 if (verbose) { 441 if (verbose) {
422 printf("parsing stratum from peer %.2x: ", ntohs(peers[i].assoc)); 442 printf("parsing stratum from peer %.2x: ", ntohs(peers[i].assoc));
@@ -424,28 +444,32 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
424 value = np_extract_ntpvar(data, "stratum"); 444 value = np_extract_ntpvar(data, "stratum");
425 nptr = NULL; 445 nptr = NULL;
426 /* Convert the value if we have one */ 446 /* Convert the value if we have one */
427 if (value != NULL) 447 if (value != NULL) {
428 *stratum = strtol(value, &nptr, 10); 448 result.stratum = strtol(value, &nptr, 10);
449 }
429 if (value == NULL || value == nptr) { 450 if (value == NULL || value == nptr) {
430 if (verbose) 451 if (verbose) {
431 printf("error: unable to read server stratum response.\n"); 452 printf("error: unable to read server stratum response.\n");
432 *stratum = -1; 453 }
454 result.stratum = -1;
433 } else { 455 } else {
434 if (verbose) 456 if (verbose) {
435 printf("%i\n", *stratum); 457 printf("%li\n", result.stratum);
458 }
436 } 459 }
437 } 460 }
438 } /* if (PEER_SEL(peers[i].status) >= min_peer_sel) */ 461 } /* if (PEER_SEL(peers[i].status) >= min_peer_sel) */
439 } /* for (i = 0; i < npeers; i++) */ 462 } /* for (i = 0; i < npeers; i++) */
440 463
441 close(conn); 464 close(conn);
442 if (peers != NULL) 465 if (peers != NULL) {
443 free(peers); 466 free(peers);
467 }
444 468
445 return status; 469 return result;
446} 470}
447 471
448int process_arguments(int argc, char **argv) { 472check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) {
449 static struct option longopts[] = { 473 static struct option longopts[] = {
450 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {"verbose", no_argument, 0, 'v'}, 474 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {"verbose", no_argument, 0, 'v'},
451 {"use-ipv4", no_argument, 0, '4'}, {"use-ipv6", no_argument, 0, '6'}, {"quiet", no_argument, 0, 'q'}, 475 {"use-ipv4", no_argument, 0, '4'}, {"use-ipv6", no_argument, 0, '6'}, {"quiet", no_argument, 0, 'q'},
@@ -454,14 +478,21 @@ int process_arguments(int argc, char **argv) {
454 {"twarn", required_argument, 0, 'm'}, {"tcrit", required_argument, 0, 'n'}, {"timeout", required_argument, 0, 't'}, 478 {"twarn", required_argument, 0, 'm'}, {"tcrit", required_argument, 0, 'n'}, {"timeout", required_argument, 0, 't'},
455 {"hostname", required_argument, 0, 'H'}, {"port", required_argument, 0, 'p'}, {0, 0, 0, 0}}; 479 {"hostname", required_argument, 0, 'H'}, {"port", required_argument, 0, 'p'}, {0, 0, 0, 0}};
456 480
457 if (argc < 2) 481 if (argc < 2) {
458 usage("\n"); 482 usage("\n");
483 }
484
485 check_ntp_peer_config_wrapper result = {
486 .errorcode = OK,
487 .config = check_ntp_peer_config_init(),
488 };
459 489
460 while (true) { 490 while (true) {
461 int option = 0; 491 int option = 0;
462 int option_char = getopt_long(argc, argv, "Vhv46qw:c:W:C:j:k:m:n:t:H:p:", longopts, &option); 492 int option_char = getopt_long(argc, argv, "Vhv46qw:c:W:C:j:k:m:n:t:H:p:", longopts, &option);
463 if (option_char == -1 || option_char == EOF || option_char == 1) 493 if (option_char == -1 || option_char == EOF || option_char == 1) {
464 break; 494 break;
495 }
465 496
466 switch (option_char) { 497 switch (option_char) {
467 case 'h': 498 case 'h':
@@ -476,45 +507,46 @@ int process_arguments(int argc, char **argv) {
476 verbose++; 507 verbose++;
477 break; 508 break;
478 case 'q': 509 case 'q':
479 quiet = true; 510 result.config.quiet = true;
480 break; 511 break;
481 case 'w': 512 case 'w':
482 owarn = optarg; 513 result.config.owarn = optarg;
483 break; 514 break;
484 case 'c': 515 case 'c':
485 ocrit = optarg; 516 result.config.ocrit = optarg;
486 break; 517 break;
487 case 'W': 518 case 'W':
488 do_stratum = true; 519 result.config.do_stratum = true;
489 swarn = optarg; 520 result.config.swarn = optarg;
490 break; 521 break;
491 case 'C': 522 case 'C':
492 do_stratum = true; 523 result.config.do_stratum = true;
493 scrit = optarg; 524 result.config.scrit = optarg;
494 break; 525 break;
495 case 'j': 526 case 'j':
496 do_jitter = true; 527 result.config.do_jitter = true;
497 jwarn = optarg; 528 result.config.jwarn = optarg;
498 break; 529 break;
499 case 'k': 530 case 'k':
500 do_jitter = true; 531 result.config.do_jitter = true;
501 jcrit = optarg; 532 result.config.jcrit = optarg;
502 break; 533 break;
503 case 'm': 534 case 'm':
504 do_truechimers = true; 535 result.config.do_truechimers = true;
505 twarn = optarg; 536 result.config.twarn = optarg;
506 break; 537 break;
507 case 'n': 538 case 'n':
508 do_truechimers = true; 539 result.config.do_truechimers = true;
509 tcrit = optarg; 540 result.config.tcrit = optarg;
510 break; 541 break;
511 case 'H': 542 case 'H':
512 if (!is_host(optarg)) 543 if (!is_host(optarg)) {
513 usage2(_("Invalid hostname/address"), optarg); 544 usage2(_("Invalid hostname/address"), optarg);
514 server_address = strdup(optarg); 545 }
546 result.config.server_address = strdup(optarg);
515 break; 547 break;
516 case 'p': 548 case 'p':
517 port = atoi(optarg); 549 result.config.port = atoi(optarg);
518 break; 550 break;
519 case 't': 551 case 't':
520 socket_timeout = atoi(optarg); 552 socket_timeout = atoi(optarg);
@@ -536,29 +568,34 @@ int process_arguments(int argc, char **argv) {
536 } 568 }
537 } 569 }
538 570
539 if (server_address == NULL) { 571 if (result.config.server_address == NULL) {
540 usage4(_("Hostname was not supplied")); 572 usage4(_("Hostname was not supplied"));
541 } 573 }
542 574
543 return 0; 575 set_thresholds(&result.config.offset_thresholds, result.config.owarn, result.config.ocrit);
576 set_thresholds(&result.config.jitter_thresholds, result.config.jwarn, result.config.jcrit);
577 set_thresholds(&result.config.stratum_thresholds, result.config.swarn, result.config.scrit);
578 set_thresholds(&result.config.truechimer_thresholds, result.config.twarn, result.config.tcrit);
579
580 return result;
544} 581}
545 582
546char *perfd_offset(double offset) { 583char *perfd_offset(double offset, thresholds *offset_thresholds) {
547 return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true, offset_thresholds->critical->end, false, 0, false, 584 return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true, offset_thresholds->critical->end, false, 0, false,
548 0); 585 0);
549} 586}
550 587
551char *perfd_jitter(double jitter) { 588char *perfd_jitter(double jitter, bool do_jitter, thresholds *jitter_thresholds) {
552 return fperfdata("jitter", jitter, "", do_jitter, jitter_thresholds->warning->end, do_jitter, jitter_thresholds->critical->end, true, 0, 589 return fperfdata("jitter", jitter, "", do_jitter, jitter_thresholds->warning->end, do_jitter, jitter_thresholds->critical->end, true, 0,
553 false, 0); 590 false, 0);
554} 591}
555 592
556char *perfd_stratum(int stratum) { 593char *perfd_stratum(int stratum, bool do_stratum, thresholds *stratum_thresholds) {
557 return perfdata("stratum", stratum, "", do_stratum, (int)stratum_thresholds->warning->end, do_stratum, 594 return perfdata("stratum", stratum, "", do_stratum, (int)stratum_thresholds->warning->end, do_stratum,
558 (int)stratum_thresholds->critical->end, true, 0, true, 16); 595 (int)stratum_thresholds->critical->end, true, 0, true, 16);
559} 596}
560 597
561char *perfd_truechimers(int num_truechimers) { 598char *perfd_truechimers(int num_truechimers, const bool do_truechimers, thresholds *truechimer_thresholds) {
562 return perfdata("truechimers", num_truechimers, "", do_truechimers, (int)truechimer_thresholds->warning->end, do_truechimers, 599 return perfdata("truechimers", num_truechimers, "", do_truechimers, (int)truechimer_thresholds->warning->end, do_truechimers,
563 (int)truechimer_thresholds->critical->end, true, 0, false, 0); 600 (int)truechimer_thresholds->critical->end, true, 0, false, 0);
564} 601}
@@ -571,13 +608,13 @@ int main(int argc, char *argv[]) {
571 /* Parse extra opts if any */ 608 /* Parse extra opts if any */
572 argv = np_extra_opts(&argc, argv, progname); 609 argv = np_extra_opts(&argc, argv, progname);
573 610
574 if (process_arguments(argc, argv) == ERROR) 611 check_ntp_peer_config_wrapper tmp_config = process_arguments(argc, argv);
612
613 if (tmp_config.errorcode == ERROR) {
575 usage4(_("Could not parse arguments")); 614 usage4(_("Could not parse arguments"));
615 }
576 616
577 set_thresholds(&offset_thresholds, owarn, ocrit); 617 const check_ntp_peer_config config = tmp_config.config;
578 set_thresholds(&jitter_thresholds, jwarn, jcrit);
579 set_thresholds(&stratum_thresholds, swarn, scrit);
580 set_thresholds(&truechimer_thresholds, twarn, tcrit);
581 618
582 /* initialize alarm signal handling */ 619 /* initialize alarm signal handling */
583 signal(SIGALRM, socket_timeout_alarm_handler); 620 signal(SIGALRM, socket_timeout_alarm_handler);
@@ -585,44 +622,40 @@ int main(int argc, char *argv[]) {
585 /* set socket timeout */ 622 /* set socket timeout */
586 alarm(socket_timeout); 623 alarm(socket_timeout);
587 624
588 int offset_result;
589 int stratum;
590 int num_truechimers;
591 double offset = 0;
592 double jitter = 0;
593 /* This returns either OK or WARNING (See comment preceding ntp_request) */ 625 /* This returns either OK or WARNING (See comment preceding ntp_request) */
594 int result = ntp_request(&offset, &offset_result, &jitter, &stratum, &num_truechimers); 626 ntp_request_result ntp_res = ntp_request(config);
627 mp_state_enum result = STATE_UNKNOWN;
595 628
596 if (offset_result == STATE_UNKNOWN) { 629 if (ntp_res.offset_result == STATE_UNKNOWN) {
597 /* if there's no sync peer (this overrides ntp_request output): */ 630 /* if there's no sync peer (this overrides ntp_request output): */
598 result = (quiet ? STATE_UNKNOWN : STATE_CRITICAL); 631 result = (config.quiet ? STATE_UNKNOWN : STATE_CRITICAL);
599 } else { 632 } else {
600 /* Be quiet if there's no candidates either */ 633 /* Be quiet if there's no candidates either */
601 if (quiet && result == STATE_WARNING) 634 if (config.quiet && result == STATE_WARNING) {
602 result = STATE_UNKNOWN; 635 result = STATE_UNKNOWN;
603 result = max_state_alt(result, get_status(fabs(offset), offset_thresholds)); 636 }
637 result = max_state_alt(result, get_status(fabs(ntp_res.offset), config.offset_thresholds));
604 } 638 }
605 639
606 int oresult = result; 640 mp_state_enum oresult = result;
607 641 mp_state_enum tresult = STATE_UNKNOWN;
608 int tresult = STATE_UNKNOWN;
609 642
610 if (do_truechimers) { 643 if (config.do_truechimers) {
611 tresult = get_status(num_truechimers, truechimer_thresholds); 644 tresult = get_status(ntp_res.num_truechimers, config.truechimer_thresholds);
612 result = max_state_alt(result, tresult); 645 result = max_state_alt(result, tresult);
613 } 646 }
614 647
615 int sresult = STATE_UNKNOWN; 648 mp_state_enum sresult = STATE_UNKNOWN;
616 649
617 if (do_stratum) { 650 if (config.do_stratum) {
618 sresult = get_status(stratum, stratum_thresholds); 651 sresult = get_status((double)ntp_res.stratum, config.stratum_thresholds);
619 result = max_state_alt(result, sresult); 652 result = max_state_alt(result, sresult);
620 } 653 }
621 654
622 int jresult = STATE_UNKNOWN; 655 mp_state_enum jresult = STATE_UNKNOWN;
623 656
624 if (do_jitter) { 657 if (config.do_jitter) {
625 jresult = get_status(jitter, jitter_thresholds); 658 jresult = get_status(ntp_res.jitter, config.jitter_thresholds);
626 result = max_state_alt(result, jresult); 659 result = max_state_alt(result, jresult);
627 } 660 }
628 661
@@ -641,59 +674,67 @@ int main(int argc, char *argv[]) {
641 xasprintf(&result_line, _("NTP UNKNOWN:")); 674 xasprintf(&result_line, _("NTP UNKNOWN:"));
642 break; 675 break;
643 } 676 }
644 if (!syncsource_found) 677
678 if (!syncsource_found) {
645 xasprintf(&result_line, "%s %s,", result_line, _("Server not synchronized")); 679 xasprintf(&result_line, "%s %s,", result_line, _("Server not synchronized"));
646 else if (li_alarm) 680 } else if (li_alarm) {
647 xasprintf(&result_line, "%s %s,", result_line, _("Server has the LI_ALARM bit set")); 681 xasprintf(&result_line, "%s %s,", result_line, _("Server has the LI_ALARM bit set"));
682 }
648 683
649 char *perfdata_line; 684 char *perfdata_line;
650 if (offset_result == STATE_UNKNOWN) { 685 if (ntp_res.offset_result == STATE_UNKNOWN) {
651 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown")); 686 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown"));
652 xasprintf(&perfdata_line, ""); 687 xasprintf(&perfdata_line, "");
653 } else if (oresult == STATE_WARNING) { 688 } else if (oresult == STATE_WARNING) {
654 xasprintf(&result_line, "%s %s %.10g secs (WARNING)", result_line, _("Offset"), offset); 689 xasprintf(&result_line, "%s %s %.10g secs (WARNING)", result_line, _("Offset"), ntp_res.offset);
655 } else if (oresult == STATE_CRITICAL) { 690 } else if (oresult == STATE_CRITICAL) {
656 xasprintf(&result_line, "%s %s %.10g secs (CRITICAL)", result_line, _("Offset"), offset); 691 xasprintf(&result_line, "%s %s %.10g secs (CRITICAL)", result_line, _("Offset"), ntp_res.offset);
657 } else { 692 } else {
658 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset); 693 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), ntp_res.offset);
659 } 694 }
660 xasprintf(&perfdata_line, "%s", perfd_offset(offset)); 695 xasprintf(&perfdata_line, "%s", perfd_offset(ntp_res.offset, config.offset_thresholds));
661 696
662 if (do_jitter) { 697 if (config.do_jitter) {
663 if (jresult == STATE_WARNING) { 698 if (jresult == STATE_WARNING) {
664 xasprintf(&result_line, "%s, jitter=%f (WARNING)", result_line, jitter); 699 xasprintf(&result_line, "%s, jitter=%f (WARNING)", result_line, ntp_res.jitter);
665 } else if (jresult == STATE_CRITICAL) { 700 } else if (jresult == STATE_CRITICAL) {
666 xasprintf(&result_line, "%s, jitter=%f (CRITICAL)", result_line, jitter); 701 xasprintf(&result_line, "%s, jitter=%f (CRITICAL)", result_line, ntp_res.jitter);
667 } else { 702 } else {
668 xasprintf(&result_line, "%s, jitter=%f", result_line, jitter); 703 xasprintf(&result_line, "%s, jitter=%f", result_line, ntp_res.jitter);
669 } 704 }
670 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_jitter(jitter)); 705 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_jitter(ntp_res.jitter, config.do_jitter, config.jitter_thresholds));
671 } 706 }
672 if (do_stratum) { 707
708 if (config.do_stratum) {
673 if (sresult == STATE_WARNING) { 709 if (sresult == STATE_WARNING) {
674 xasprintf(&result_line, "%s, stratum=%i (WARNING)", result_line, stratum); 710 xasprintf(&result_line, "%s, stratum=%l (WARNING)", result_line, ntp_res.stratum);
675 } else if (sresult == STATE_CRITICAL) { 711 } else if (sresult == STATE_CRITICAL) {
676 xasprintf(&result_line, "%s, stratum=%i (CRITICAL)", result_line, stratum); 712 xasprintf(&result_line, "%s, stratum=%l (CRITICAL)", result_line, ntp_res.stratum);
677 } else { 713 } else {
678 xasprintf(&result_line, "%s, stratum=%i", result_line, stratum); 714 xasprintf(&result_line, "%s, stratum=%l", result_line, ntp_res.stratum);
679 } 715 }
680 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_stratum(stratum)); 716 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_stratum(ntp_res.stratum, config.do_stratum, config.stratum_thresholds));
681 } 717 }
682 if (do_truechimers) { 718
719 if (config.do_truechimers) {
683 if (tresult == STATE_WARNING) { 720 if (tresult == STATE_WARNING) {
684 xasprintf(&result_line, "%s, truechimers=%i (WARNING)", result_line, num_truechimers); 721 xasprintf(&result_line, "%s, truechimers=%i (WARNING)", result_line, ntp_res.num_truechimers);
685 } else if (tresult == STATE_CRITICAL) { 722 } else if (tresult == STATE_CRITICAL) {
686 xasprintf(&result_line, "%s, truechimers=%i (CRITICAL)", result_line, num_truechimers); 723 xasprintf(&result_line, "%s, truechimers=%i (CRITICAL)", result_line, ntp_res.num_truechimers);
687 } else { 724 } else {
688 xasprintf(&result_line, "%s, truechimers=%i", result_line, num_truechimers); 725 xasprintf(&result_line, "%s, truechimers=%i", result_line, ntp_res.num_truechimers);
689 } 726 }
690 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_truechimers(num_truechimers)); 727 xasprintf(&perfdata_line, "%s %s", perfdata_line,
728 perfd_truechimers(ntp_res.num_truechimers, config.do_truechimers, config.truechimer_thresholds));
691 } 729 }
730
692 printf("%s|%s\n", result_line, perfdata_line); 731 printf("%s|%s\n", result_line, perfdata_line);
693 732
694 if (server_address != NULL) 733 if (config.server_address != NULL) {
695 free(server_address); 734 free(config.server_address);
696 return result; 735 }
736
737 exit(result);
697} 738}
698 739
699void print_help(void) { 740void print_help(void) {
diff --git a/plugins/check_ntp_peer.d/config.h b/plugins/check_ntp_peer.d/config.h
new file mode 100644
index 00000000..00e6b05d
--- /dev/null
+++ b/plugins/check_ntp_peer.d/config.h
@@ -0,0 +1,67 @@
1#pragma once
2
3#include "../../config.h"
4#include "thresholds.h"
5#include <stddef.h>
6
7enum {
8 DEFAULT_NTP_PORT = 123,
9};
10
11typedef struct {
12 char *server_address;
13 int port;
14
15 bool quiet;
16
17 // truechimer stuff
18 bool do_truechimers;
19 char *twarn;
20 char *tcrit;
21 thresholds *truechimer_thresholds;
22
23 char *owarn;
24 char *ocrit;
25 thresholds *offset_thresholds;
26
27 // stratum stuff
28 bool do_stratum;
29 char *swarn;
30 char *scrit;
31 thresholds *stratum_thresholds;
32
33 // jitter stuff
34 bool do_jitter;
35 char *jwarn;
36 char *jcrit;
37 thresholds *jitter_thresholds;
38
39} check_ntp_peer_config;
40
41check_ntp_peer_config check_ntp_peer_config_init() {
42 check_ntp_peer_config tmp = {
43 .server_address = NULL,
44 .port = DEFAULT_NTP_PORT,
45
46 .quiet = false,
47 .do_truechimers = false,
48 .twarn = "0:",
49 .tcrit = "0:",
50 .truechimer_thresholds = NULL,
51
52 .owarn = "60",
53 .ocrit = "120",
54 .offset_thresholds = NULL,
55
56 .do_stratum = false,
57 .swarn = "-1:16",
58 .scrit = "-1:16",
59 .stratum_thresholds = NULL,
60
61 .do_jitter = false,
62 .jwarn = "-1:5000",
63 .jcrit = "-1:10000",
64 .jitter_thresholds = NULL,
65 };
66 return tmp;
67}
diff --git a/plugins/check_ping.c b/plugins/check_ping.c
index 4aafaf41..940b9475 100644
--- a/plugins/check_ping.c
+++ b/plugins/check_ping.c
@@ -36,61 +36,52 @@ const char *email = "devel@monitoring-plugins.org";
36#include "netutils.h" 36#include "netutils.h"
37#include "popen.h" 37#include "popen.h"
38#include "utils.h" 38#include "utils.h"
39#include "check_ping.d/config.h"
40#include "../lib/states.h"
39 41
40#include <signal.h> 42#include <signal.h>
41 43
42#define WARN_DUPLICATES "DUPLICATES FOUND! " 44#define WARN_DUPLICATES "DUPLICATES FOUND! "
43#define UNKNOWN_TRIP_TIME -1.0 /* -1 seconds */
44 45
45enum { 46typedef struct {
46 UNKNOWN_PACKET_LOSS = 200, /* 200% */ 47 int errorcode;
47 DEFAULT_MAX_PACKETS = 5 /* default no. of ICMP ECHO packets */ 48 check_ping_config config;
48}; 49} check_ping_config_wrapper;
50static check_ping_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
51static check_ping_config_wrapper validate_arguments(check_ping_config_wrapper /*config_wrapper*/);
49 52
50static int process_arguments(int /*argc*/, char ** /*argv*/); 53static int get_threshold(char * /*arg*/, double * /*trta*/, int * /*tpl*/);
51static int get_threshold(char * /*arg*/, float * /*trta*/, int * /*tpl*/); 54
52static int validate_arguments(void); 55typedef struct {
53static int run_ping(const char *cmd, const char *addr); 56 mp_state_enum state;
54static int error_scan(char buf[MAX_INPUT_BUFFER], const char *addr); 57 double round_trip_average;
58 int packet_loss;
59} ping_result;
60static ping_result run_ping(const char *cmd, const char *addr, double /*crta*/);
61
62static mp_state_enum error_scan(char buf[MAX_INPUT_BUFFER], const char *addr);
55static void print_help(void); 63static void print_help(void);
56void print_usage(void); 64void print_usage(void);
57 65
58static bool display_html = false;
59static int wpl = UNKNOWN_PACKET_LOSS;
60static int cpl = UNKNOWN_PACKET_LOSS;
61static float wrta = UNKNOWN_TRIP_TIME;
62static float crta = UNKNOWN_TRIP_TIME;
63static char **addresses = NULL;
64static int n_addresses = 0;
65static int max_addr = 1;
66static int max_packets = -1;
67static int verbose = 0; 66static int verbose = 0;
68 67
69static float rta = UNKNOWN_TRIP_TIME;
70static int pl = UNKNOWN_PACKET_LOSS;
71
72static char *warn_text; 68static char *warn_text;
73 69
74int main(int argc, char **argv) { 70int main(int argc, char **argv) {
75 char *cmd = NULL;
76 char *rawcmd = NULL;
77 int result = STATE_UNKNOWN;
78 int this_result = STATE_UNKNOWN;
79 int i;
80
81 setlocale(LC_ALL, ""); 71 setlocale(LC_ALL, "");
82 setlocale(LC_NUMERIC, "C"); 72 setlocale(LC_NUMERIC, "C");
83 bindtextdomain(PACKAGE, LOCALEDIR); 73 bindtextdomain(PACKAGE, LOCALEDIR);
84 textdomain(PACKAGE); 74 textdomain(PACKAGE);
85 75
86 addresses = malloc(sizeof(char *) * max_addr);
87 addresses[0] = NULL;
88
89 /* Parse extra opts if any */ 76 /* Parse extra opts if any */
90 argv = np_extra_opts(&argc, argv, progname); 77 argv = np_extra_opts(&argc, argv, progname);
91 78
92 if (process_arguments(argc, argv) == ERROR) 79 check_ping_config_wrapper tmp_config = process_arguments(argc, argv);
80 if (tmp_config.errorcode == ERROR) {
93 usage4(_("Could not parse arguments")); 81 usage4(_("Could not parse arguments"));
82 }
83
84 const check_ping_config config = tmp_config.config;
94 85
95 /* Set signal handling and alarm */ 86 /* Set signal handling and alarm */
96 if (signal(SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) { 87 if (signal(SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
@@ -105,71 +96,86 @@ int main(int argc, char **argv) {
105 alarm(timeout_interval); 96 alarm(timeout_interval);
106#endif 97#endif
107 98
108 for (i = 0; i < n_addresses; i++) { 99 int result = STATE_UNKNOWN;
109 100 char *rawcmd = NULL;
101 for (size_t i = 0; i < config.n_addresses; i++) {
110#ifdef PING6_COMMAND 102#ifdef PING6_COMMAND
111 if (address_family != AF_INET && is_inet6_addr(addresses[i])) 103 if (address_family != AF_INET && is_inet6_addr(config.addresses[i])) {
112 rawcmd = strdup(PING6_COMMAND); 104 rawcmd = strdup(PING6_COMMAND);
113 else 105 } else {
114 rawcmd = strdup(PING_COMMAND); 106 rawcmd = strdup(PING_COMMAND);
107 }
115#else 108#else
116 rawcmd = strdup(PING_COMMAND); 109 rawcmd = strdup(PING_COMMAND);
117#endif 110#endif
118 111
119 /* does the host address of number of packets argument come first? */ 112 char *cmd = NULL;
113
114 /* does the host address of number of packets argument come first? */
120#ifdef PING_PACKETS_FIRST 115#ifdef PING_PACKETS_FIRST
121# ifdef PING_HAS_TIMEOUT 116# ifdef PING_HAS_TIMEOUT
122 xasprintf(&cmd, rawcmd, timeout_interval, max_packets, addresses[i]); 117 xasprintf(&cmd, rawcmd, timeout_interval, config.max_packets, config.addresses[i]);
123# else 118# else
124 xasprintf(&cmd, rawcmd, max_packets, addresses[i]); 119 xasprintf(&cmd, rawcmd, config.max_packets, addresses[i]);
125# endif 120# endif
126#else 121#else
127 xasprintf(&cmd, rawcmd, addresses[i], max_packets); 122 xasprintf(&cmd, rawcmd, addresses[i], config.max_packets);
128#endif 123#endif
129 124
130 if (verbose >= 2) 125 if (verbose >= 2) {
131 printf("CMD: %s\n", cmd); 126 printf("CMD: %s\n", cmd);
127 }
132 128
133 /* run the command */ 129 /* run the command */
134 this_result = run_ping(cmd, addresses[i]);
135 130
136 if (pl == UNKNOWN_PACKET_LOSS || rta < 0.0) { 131 ping_result pinged = run_ping(cmd, config.addresses[i], config.crta);
132
133 if (pinged.packet_loss == UNKNOWN_PACKET_LOSS || pinged.round_trip_average < 0.0) {
137 printf("%s\n", cmd); 134 printf("%s\n", cmd);
138 die(STATE_UNKNOWN, _("CRITICAL - Could not interpret output from ping command\n")); 135 die(STATE_UNKNOWN, _("CRITICAL - Could not interpret output from ping command\n"));
139 } 136 }
140 137
141 if (pl >= cpl || rta >= crta || rta < 0) 138 if (pinged.packet_loss >= config.cpl || pinged.round_trip_average >= config.crta || pinged.round_trip_average < 0) {
142 this_result = STATE_CRITICAL; 139 pinged.state = STATE_CRITICAL;
143 else if (pl >= wpl || rta >= wrta) 140 } else if (pinged.packet_loss >= config.wpl || pinged.round_trip_average >= config.wrta) {
144 this_result = STATE_WARNING; 141 pinged.state = STATE_WARNING;
145 else if (pl >= 0 && rta >= 0) 142 } else if (pinged.packet_loss >= 0 && pinged.round_trip_average >= 0) {
146 this_result = max_state(STATE_OK, this_result); 143 pinged.state = max_state(STATE_OK, pinged.state);
147 144 }
148 if (n_addresses > 1 && this_result != STATE_UNKNOWN) 145
149 die(STATE_OK, "%s is alive\n", addresses[i]); 146 if (config.n_addresses > 1 && pinged.state != STATE_UNKNOWN) {
150 147 die(STATE_OK, "%s is alive\n", config.addresses[i]);
151 if (display_html == true) 148 }
152 printf("<A HREF='%s/traceroute.cgi?%s'>", CGIURL, addresses[i]); 149
153 if (pl == 100) 150 if (config.display_html) {
154 printf(_("PING %s - %sPacket loss = %d%%"), state_text(this_result), warn_text, pl); 151 printf("<A HREF='%s/traceroute.cgi?%s'>", CGIURL, config.addresses[i]);
155 else 152 }
156 printf(_("PING %s - %sPacket loss = %d%%, RTA = %2.2f ms"), state_text(this_result), warn_text, pl, rta); 153 if (pinged.packet_loss == 100) {
157 if (display_html == true) 154 printf(_("PING %s - %sPacket loss = %d%%"), state_text(pinged.state), warn_text, pinged.packet_loss);
155 } else {
156 printf(_("PING %s - %sPacket loss = %d%%, RTA = %2.2f ms"), state_text(pinged.state), warn_text, pinged.packet_loss,
157 pinged.round_trip_average);
158 }
159 if (config.display_html) {
158 printf("</A>"); 160 printf("</A>");
161 }
159 162
160 /* Print performance data */ 163 /* Print performance data */
161 if (pl != 100) { 164 if (pinged.packet_loss != 100) {
162 printf("|%s", 165 printf("|%s", fperfdata("rta", pinged.round_trip_average, "ms", (bool)(config.wrta > 0), config.wrta, (bool)(config.crta > 0),
163 fperfdata("rta", (double)rta, "ms", wrta > 0 ? true : false, wrta, crta > 0 ? true : false, crta, true, 0, false, 0)); 166 config.crta, true, 0, false, 0));
164 } else { 167 } else {
165 printf("| rta=U;%f;%f;;", wrta, crta); 168 printf("| rta=U;%f;%f;;", config.wrta, config.crta);
166 } 169 }
167 printf(" %s\n", perfdata("pl", (long)pl, "%", wpl > 0 ? true : false, wpl, cpl > 0 ? true : false, cpl, true, 0, false, 0));
168 170
169 if (verbose >= 2) 171 printf(" %s\n", perfdata("pl", (long)pinged.packet_loss, "%", (bool)(config.wpl > 0), config.wpl, (bool)(config.cpl > 0),
170 printf("%f:%d%% %f:%d%%\n", wrta, wpl, crta, cpl); 172 config.cpl, true, 0, false, 0));
173
174 if (verbose >= 2) {
175 printf("%f:%d%% %f:%d%%\n", config.wrta, config.wpl, config.crta, config.cpl);
176 }
171 177
172 result = max_state(result, this_result); 178 result = max_state(result, pinged.state);
173 free(rawcmd); 179 free(rawcmd);
174 free(cmd); 180 free(cmd);
175 } 181 }
@@ -178,11 +184,7 @@ int main(int argc, char **argv) {
178} 184}
179 185
180/* process command-line arguments */ 186/* process command-line arguments */
181int process_arguments(int argc, char **argv) { 187check_ping_config_wrapper process_arguments(int argc, char **argv) {
182 int c = 1;
183 char *ptr;
184
185 int option = 0;
186 static struct option longopts[] = {STD_LONG_OPTS, 188 static struct option longopts[] = {STD_LONG_OPTS,
187 {"packets", required_argument, 0, 'p'}, 189 {"packets", required_argument, 0, 'p'},
188 {"nohtml", no_argument, 0, 'n'}, 190 {"nohtml", no_argument, 0, 'n'},
@@ -191,23 +193,35 @@ int process_arguments(int argc, char **argv) {
191 {"use-ipv6", no_argument, 0, '6'}, 193 {"use-ipv6", no_argument, 0, '6'},
192 {0, 0, 0, 0}}; 194 {0, 0, 0, 0}};
193 195
194 if (argc < 2) 196 check_ping_config_wrapper result = {
195 return ERROR; 197 .errorcode = OK,
198 .config = check_ping_config_init(),
199 };
200
201 if (argc < 2) {
202 result.errorcode = ERROR;
203 return result;
204 }
196 205
197 for (c = 1; c < argc; c++) { 206 for (int index = 1; index < argc; index++) {
198 if (strcmp("-to", argv[c]) == 0) 207 if (strcmp("-to", argv[index]) == 0) {
199 strcpy(argv[c], "-t"); 208 strcpy(argv[index], "-t");
200 if (strcmp("-nohtml", argv[c]) == 0) 209 }
201 strcpy(argv[c], "-n"); 210 if (strcmp("-nohtml", argv[index]) == 0) {
211 strcpy(argv[index], "-n");
212 }
202 } 213 }
203 214
204 while (1) { 215 int option = 0;
205 c = getopt_long(argc, argv, "VvhnL46t:c:w:H:p:", longopts, &option); 216 size_t max_addr = MAX_ADDR_START;
217 while (true) {
218 int option_index = getopt_long(argc, argv, "VvhnL46t:c:w:H:p:", longopts, &option);
206 219
207 if (c == -1 || c == EOF) 220 if (option_index == -1 || option_index == EOF) {
208 break; 221 break;
222 }
209 223
210 switch (c) { 224 switch (option_index) {
211 case '?': /* usage */ 225 case '?': /* usage */
212 usage5(); 226 usage5();
213 case 'h': /* help */ 227 case 'h': /* help */
@@ -234,17 +248,18 @@ int process_arguments(int argc, char **argv) {
234 usage(_("IPv6 support not available\n")); 248 usage(_("IPv6 support not available\n"));
235#endif 249#endif
236 break; 250 break;
237 case 'H': /* hostname */ 251 case 'H': /* hostname */ {
238 ptr = optarg; 252 char *ptr = optarg;
239 while (1) { 253 while (true) {
240 n_addresses++; 254 result.config.n_addresses++;
241 if (n_addresses > max_addr) { 255 if (result.config.n_addresses > max_addr) {
242 max_addr *= 2; 256 max_addr *= 2;
243 addresses = realloc(addresses, sizeof(char *) * max_addr); 257 result.config.addresses = realloc(result.config.addresses, sizeof(char *) * max_addr);
244 if (addresses == NULL) 258 if (result.config.addresses == NULL) {
245 die(STATE_UNKNOWN, _("Could not realloc() addresses\n")); 259 die(STATE_UNKNOWN, _("Could not realloc() addresses\n"));
260 }
246 } 261 }
247 addresses[n_addresses - 1] = ptr; 262 result.config.addresses[result.config.n_addresses - 1] = ptr;
248 if ((ptr = index(ptr, ','))) { 263 if ((ptr = index(ptr, ','))) {
249 strcpy(ptr, ""); 264 strcpy(ptr, "");
250 ptr += sizeof(char); 265 ptr += sizeof(char);
@@ -252,203 +267,248 @@ int process_arguments(int argc, char **argv) {
252 break; 267 break;
253 } 268 }
254 } 269 }
255 break; 270 } break;
256 case 'p': /* number of packets to send */ 271 case 'p': /* number of packets to send */
257 if (is_intnonneg(optarg)) 272 if (is_intnonneg(optarg)) {
258 max_packets = atoi(optarg); 273 result.config.max_packets = atoi(optarg);
259 else 274 } else {
260 usage2(_("<max_packets> (%s) must be a non-negative number\n"), optarg); 275 usage2(_("<max_packets> (%s) must be a non-negative number\n"), optarg);
276 }
261 break; 277 break;
262 case 'n': /* no HTML */ 278 case 'n': /* no HTML */
263 display_html = false; 279 result.config.display_html = false;
264 break; 280 break;
265 case 'L': /* show HTML */ 281 case 'L': /* show HTML */
266 display_html = true; 282 result.config.display_html = true;
267 break; 283 break;
268 case 'c': 284 case 'c':
269 get_threshold(optarg, &crta, &cpl); 285 get_threshold(optarg, &result.config.crta, &result.config.cpl);
270 break; 286 break;
271 case 'w': 287 case 'w':
272 get_threshold(optarg, &wrta, &wpl); 288 get_threshold(optarg, &result.config.wrta, &result.config.wpl);
273 break; 289 break;
274 } 290 }
275 } 291 }
276 292
277 c = optind; 293 int arg_counter = optind;
278 if (c == argc) 294 if (arg_counter == argc) {
279 return validate_arguments(); 295 return validate_arguments(result);
296 }
280 297
281 if (addresses[0] == NULL) { 298 if (result.config.addresses[0] == NULL) {
282 if (!is_host(argv[c])) { 299 if (!is_host(argv[arg_counter])) {
283 usage2(_("Invalid hostname/address"), argv[c]); 300 usage2(_("Invalid hostname/address"), argv[arg_counter]);
284 } else { 301 } else {
285 addresses[0] = argv[c++]; 302 result.config.addresses[0] = argv[arg_counter++];
286 n_addresses++; 303 result.config.n_addresses++;
287 if (c == argc) 304 if (arg_counter == argc) {
288 return validate_arguments(); 305 return validate_arguments(result);
306 }
289 } 307 }
290 } 308 }
291 309
292 if (wpl == UNKNOWN_PACKET_LOSS) { 310 if (result.config.wpl == UNKNOWN_PACKET_LOSS) {
293 if (!is_intpercent(argv[c])) { 311 if (!is_intpercent(argv[arg_counter])) {
294 printf(_("<wpl> (%s) must be an integer percentage\n"), argv[c]); 312 printf(_("<wpl> (%s) must be an integer percentage\n"), argv[arg_counter]);
295 return ERROR; 313 result.errorcode = ERROR;
296 } else { 314 return result;
297 wpl = atoi(argv[c++]); 315 }
298 if (c == argc) 316 result.config.wpl = atoi(argv[arg_counter++]);
299 return validate_arguments(); 317 if (arg_counter == argc) {
318 return validate_arguments(result);
300 } 319 }
301 } 320 }
302 321
303 if (cpl == UNKNOWN_PACKET_LOSS) { 322 if (result.config.cpl == UNKNOWN_PACKET_LOSS) {
304 if (!is_intpercent(argv[c])) { 323 if (!is_intpercent(argv[arg_counter])) {
305 printf(_("<cpl> (%s) must be an integer percentage\n"), argv[c]); 324 printf(_("<cpl> (%s) must be an integer percentage\n"), argv[arg_counter]);
306 return ERROR; 325 result.errorcode = ERROR;
307 } else { 326 return result;
308 cpl = atoi(argv[c++]); 327 }
309 if (c == argc) 328 result.config.cpl = atoi(argv[arg_counter++]);
310 return validate_arguments(); 329 if (arg_counter == argc) {
330 return validate_arguments(result);
311 } 331 }
312 } 332 }
313 333
314 if (wrta < 0.0) { 334 if (result.config.wrta < 0.0) {
315 if (is_negative(argv[c])) { 335 if (is_negative(argv[arg_counter])) {
316 printf(_("<wrta> (%s) must be a non-negative number\n"), argv[c]); 336 printf(_("<wrta> (%s) must be a non-negative number\n"), argv[arg_counter]);
317 return ERROR; 337 result.errorcode = ERROR;
318 } else { 338 return result;
319 wrta = atof(argv[c++]); 339 }
320 if (c == argc) 340 result.config.wrta = atof(argv[arg_counter++]);
321 return validate_arguments(); 341 if (arg_counter == argc) {
342 return validate_arguments(result);
322 } 343 }
323 } 344 }
324 345
325 if (crta < 0.0) { 346 if (result.config.crta < 0.0) {
326 if (is_negative(argv[c])) { 347 if (is_negative(argv[arg_counter])) {
327 printf(_("<crta> (%s) must be a non-negative number\n"), argv[c]); 348 printf(_("<crta> (%s) must be a non-negative number\n"), argv[arg_counter]);
328 return ERROR; 349 result.errorcode = ERROR;
329 } else { 350 return result;
330 crta = atof(argv[c++]); 351 }
331 if (c == argc) 352 result.config.crta = atof(argv[arg_counter++]);
332 return validate_arguments(); 353 if (arg_counter == argc) {
354 return validate_arguments(result);
333 } 355 }
334 } 356 }
335 357
336 if (max_packets == -1) { 358 if (result.config.max_packets == -1) {
337 if (is_intnonneg(argv[c])) { 359 if (is_intnonneg(argv[arg_counter])) {
338 max_packets = atoi(argv[c++]); 360 result.config.max_packets = atoi(argv[arg_counter++]);
339 } else { 361 } else {
340 printf(_("<max_packets> (%s) must be a non-negative number\n"), argv[c]); 362 printf(_("<max_packets> (%s) must be a non-negative number\n"), argv[arg_counter]);
341 return ERROR; 363 result.errorcode = ERROR;
364 return result;
342 } 365 }
343 } 366 }
344 367
345 return validate_arguments(); 368 return validate_arguments(result);
346} 369}
347 370
348int get_threshold(char *arg, float *trta, int *tpl) { 371int get_threshold(char *arg, double *trta, int *tpl) {
349 if (is_intnonneg(arg) && sscanf(arg, "%f", trta) == 1) 372 if (is_intnonneg(arg) && sscanf(arg, "%lf", trta) == 1) {
350 return OK; 373 return OK;
351 else if (strpbrk(arg, ",:") && strstr(arg, "%") && sscanf(arg, "%f%*[:,]%d%%", trta, tpl) == 2) 374 }
375
376 if (strpbrk(arg, ",:") && strstr(arg, "%") && sscanf(arg, "%lf%*[:,]%d%%", trta, tpl) == 2) {
352 return OK; 377 return OK;
353 else if (strstr(arg, "%") && sscanf(arg, "%d%%", tpl) == 1) 378 }
379
380 if (strstr(arg, "%") && sscanf(arg, "%d%%", tpl) == 1) {
354 return OK; 381 return OK;
382 }
355 383
356 usage2(_("%s: Warning threshold must be integer or percentage!\n\n"), arg); 384 usage2(_("%s: Warning threshold must be integer or percentage!\n\n"), arg);
357 return STATE_UNKNOWN; 385 return STATE_UNKNOWN;
358} 386}
359 387
360int validate_arguments() { 388check_ping_config_wrapper validate_arguments(check_ping_config_wrapper config_wrapper) {
361 float max_seconds; 389 if (config_wrapper.config.wrta < 0.0) {
362 int i;
363
364 if (wrta < 0.0) {
365 printf(_("<wrta> was not set\n")); 390 printf(_("<wrta> was not set\n"));
366 return ERROR; 391 config_wrapper.errorcode = ERROR;
367 } else if (crta < 0.0) { 392 return config_wrapper;
393 }
394
395 if (config_wrapper.config.crta < 0.0) {
368 printf(_("<crta> was not set\n")); 396 printf(_("<crta> was not set\n"));
369 return ERROR; 397 config_wrapper.errorcode = ERROR;
370 } else if (wpl == UNKNOWN_PACKET_LOSS) { 398 return config_wrapper;
399 }
400
401 if (config_wrapper.config.wpl == UNKNOWN_PACKET_LOSS) {
371 printf(_("<wpl> was not set\n")); 402 printf(_("<wpl> was not set\n"));
372 return ERROR; 403 config_wrapper.errorcode = ERROR;
373 } else if (cpl == UNKNOWN_PACKET_LOSS) { 404 return config_wrapper;
405 }
406
407 if (config_wrapper.config.cpl == UNKNOWN_PACKET_LOSS) {
374 printf(_("<cpl> was not set\n")); 408 printf(_("<cpl> was not set\n"));
375 return ERROR; 409 config_wrapper.errorcode = ERROR;
376 } else if (wrta > crta) { 410 return config_wrapper;
377 printf(_("<wrta> (%f) cannot be larger than <crta> (%f)\n"), wrta, crta); 411 }
378 return ERROR; 412
379 } else if (wpl > cpl) { 413 if (config_wrapper.config.wrta > config_wrapper.config.crta) {
380 printf(_("<wpl> (%d) cannot be larger than <cpl> (%d)\n"), wpl, cpl); 414 printf(_("<wrta> (%f) cannot be larger than <crta> (%f)\n"), config_wrapper.config.wrta, config_wrapper.config.crta);
381 return ERROR; 415 config_wrapper.errorcode = ERROR;
416 return config_wrapper;
382 } 417 }
383 418
384 if (max_packets == -1) 419 if (config_wrapper.config.wpl > config_wrapper.config.cpl) {
385 max_packets = DEFAULT_MAX_PACKETS; 420 printf(_("<wpl> (%d) cannot be larger than <cpl> (%d)\n"), config_wrapper.config.wpl, config_wrapper.config.cpl);
421 config_wrapper.errorcode = ERROR;
422 return config_wrapper;
423 }
386 424
387 max_seconds = crta / 1000.0 * max_packets + max_packets; 425 if (config_wrapper.config.max_packets == -1) {
388 if (max_seconds > timeout_interval) 426 config_wrapper.config.max_packets = DEFAULT_MAX_PACKETS;
389 timeout_interval = (int)max_seconds; 427 }
390 428
391 for (i = 0; i < n_addresses; i++) { 429 double max_seconds = (config_wrapper.config.crta / 1000.0 * config_wrapper.config.max_packets) + config_wrapper.config.max_packets;
392 if (!is_host(addresses[i])) 430 if (max_seconds > timeout_interval) {
393 usage2(_("Invalid hostname/address"), addresses[i]); 431 timeout_interval = (unsigned int)max_seconds;
432 }
433
434 for (size_t i = 0; i < config_wrapper.config.n_addresses; i++) {
435 if (!is_host(config_wrapper.config.addresses[i])) {
436 usage2(_("Invalid hostname/address"), config_wrapper.config.addresses[i]);
437 }
394 } 438 }
395 439
396 if (n_addresses == 0) { 440 if (config_wrapper.config.n_addresses == 0) {
397 usage(_("You must specify a server address or host name")); 441 usage(_("You must specify a server address or host name"));
398 } 442 }
399 443
400 return OK; 444 return config_wrapper;
401} 445}
402 446
403int run_ping(const char *cmd, const char *addr) { 447ping_result run_ping(const char *cmd, const char *addr, double crta) {
404 char buf[MAX_INPUT_BUFFER]; 448 if ((child_process = spopen(cmd)) == NULL) {
405 int result = STATE_UNKNOWN;
406 int match;
407
408 if ((child_process = spopen(cmd)) == NULL)
409 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd); 449 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd);
450 }
410 451
411 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r"); 452 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
412 if (child_stderr == NULL) 453 if (child_stderr == NULL) {
413 printf(_("Cannot open stderr for %s\n"), cmd); 454 printf(_("Cannot open stderr for %s\n"), cmd);
455 }
414 456
415 while (fgets(buf, MAX_INPUT_BUFFER - 1, child_process)) { 457 char buf[MAX_INPUT_BUFFER];
458 ping_result result = {
459 .state = STATE_UNKNOWN,
460 .packet_loss = UNKNOWN_PACKET_LOSS,
461 .round_trip_average = UNKNOWN_TRIP_TIME,
462 };
416 463
417 if (verbose >= 3) 464 while (fgets(buf, MAX_INPUT_BUFFER - 1, child_process)) {
465 if (verbose >= 3) {
418 printf("Output: %s", buf); 466 printf("Output: %s", buf);
467 }
419 468
420 result = max_state(result, error_scan(buf, addr)); 469 result.state = max_state(result.state, error_scan(buf, addr));
421 470
422 /* get the percent loss statistics */ 471 /* get the percent loss statistics */
423 match = 0; 472 int match = 0;
424 if ((sscanf(buf, "%*d packets transmitted, %*d packets received, +%*d errors, %d%% packet loss%n", &pl, &match) && match) || 473 if ((sscanf(buf, "%*d packets transmitted, %*d packets received, +%*d errors, %d%% packet loss%n", &result.packet_loss, &match) ==
425 (sscanf(buf, "%*d packets transmitted, %*d packets received, +%*d duplicates, %d%% packet loss%n", &pl, &match) && match) || 474 1 &&
426 (sscanf(buf, "%*d packets transmitted, %*d received, +%*d duplicates, %d%% packet loss%n", &pl, &match) && match) || 475 match) ||
427 (sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% packet loss%n", &pl, &match) && match) || 476 (sscanf(buf, "%*d packets transmitted, %*d packets received, +%*d duplicates, %d%% packet loss%n", &result.packet_loss,
428 (sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% loss, time%n", &pl, &match) && match) || 477 &match) == 1 &&
429 (sscanf(buf, "%*d packets transmitted, %*d received, %d%% loss, time%n", &pl, &match) && match) || 478 match) ||
430 (sscanf(buf, "%*d packets transmitted, %*d received, %d%% packet loss, time%n", &pl, &match) && match) || 479 (sscanf(buf, "%*d packets transmitted, %*d received, +%*d duplicates, %d%% packet loss%n", &result.packet_loss, &match) == 1 &&
431 (sscanf(buf, "%*d packets transmitted, %*d received, +%*d errors, %d%% packet loss%n", &pl, &match) && match) || 480 match) ||
432 (sscanf(buf, "%*d packets transmitted %*d received, +%*d errors, %d%% packet loss%n", &pl, &match) && match) || 481 (sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% packet loss%n", &result.packet_loss, &match) == 1 && match) ||
433 (sscanf(buf, "%*[^(](%d%% %*[^)])%n", &pl, &match) && match)) 482 (sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% loss, time%n", &result.packet_loss, &match) == 1 && match) ||
483 (sscanf(buf, "%*d packets transmitted, %*d received, %d%% loss, time%n", &result.packet_loss, &match) == 1 && match) ||
484 (sscanf(buf, "%*d packets transmitted, %*d received, %d%% packet loss, time%n", &result.packet_loss, &match) == 1 && match) ==
485 1 ||
486 (sscanf(buf, "%*d packets transmitted, %*d received, +%*d errors, %d%% packet loss%n", &result.packet_loss, &match) == 1 &&
487 match) ||
488 (sscanf(buf, "%*d packets transmitted %*d received, +%*d errors, %d%% packet loss%n", &result.packet_loss, &match) == 1 &&
489 match) ||
490 (sscanf(buf, "%*[^(](%d%% %*[^)])%n", &result.packet_loss, &match) == 1 && match)) {
434 continue; 491 continue;
492 }
435 493
436 /* get the round trip average */ 494 /* get the round trip average */
437 else if ((sscanf(buf, "round-trip min/avg/max = %*f/%f/%*f%n", &rta, &match) && match) || 495 if ((sscanf(buf, "round-trip min/avg/max = %*f/%lf/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
438 (sscanf(buf, "round-trip min/avg/max/mdev = %*f/%f/%*f/%*f%n", &rta, &match) && match) || 496 (sscanf(buf, "round-trip min/avg/max/mdev = %*f/%lf/%*f/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
439 (sscanf(buf, "round-trip min/avg/max/sdev = %*f/%f/%*f/%*f%n", &rta, &match) && match) || 497 (sscanf(buf, "round-trip min/avg/max/sdev = %*f/%lf/%*f/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
440 (sscanf(buf, "round-trip min/avg/max/stddev = %*f/%f/%*f/%*f%n", &rta, &match) && match) || 498 (sscanf(buf, "round-trip min/avg/max/stddev = %*f/%lf/%*f/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
441 (sscanf(buf, "round-trip min/avg/max/std-dev = %*f/%f/%*f/%*f%n", &rta, &match) && match) || 499 (sscanf(buf, "round-trip min/avg/max/std-dev = %*f/%lf/%*f/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
442 (sscanf(buf, "round-trip (ms) min/avg/max = %*f/%f/%*f%n", &rta, &match) && match) || 500 (sscanf(buf, "round-trip (ms) min/avg/max = %*f/%lf/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
443 (sscanf(buf, "round-trip (ms) min/avg/max/stddev = %*f/%f/%*f/%*f%n", &rta, &match) && match) || 501 (sscanf(buf, "round-trip (ms) min/avg/max/stddev = %*f/%lf/%*f/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
444 (sscanf(buf, "rtt min/avg/max/mdev = %*f/%f/%*f/%*f ms%n", &rta, &match) && match) || 502 (sscanf(buf, "rtt min/avg/max/mdev = %*f/%lf/%*f/%*f ms%n", &result.round_trip_average, &match) == 1 && match) ||
445 (sscanf(buf, "%*[^=] = %*fms, %*[^=] = %*fms, %*[^=] = %fms%n", &rta, &match) && match)) 503 (sscanf(buf, "%*[^=] = %*fms, %*[^=] = %*fms, %*[^=] = %lfms%n", &result.round_trip_average, &match) == 1 && match)) {
446 continue; 504 continue;
505 }
447 } 506 }
448 507
449 /* this is needed because there is no rta if all packets are lost */ 508 /* this is needed because there is no rta if all packets are lost */
450 if (pl == 100) 509 if (result.packet_loss == 100) {
451 rta = crta; 510 result.round_trip_average = crta;
511 }
452 512
453 /* check stderr, setting at least WARNING if there is output here */ 513 /* check stderr, setting at least WARNING if there is output here */
454 /* Add warning into warn_text */ 514 /* Add warning into warn_text */
@@ -459,8 +519,8 @@ int run_ping(const char *cmd, const char *addr) {
459 if (verbose >= 3) { 519 if (verbose >= 3) {
460 printf("Got stderr: %s", buf); 520 printf("Got stderr: %s", buf);
461 } 521 }
462 if ((result = error_scan(buf, addr)) == STATE_OK) { 522 if ((result.state = error_scan(buf, addr)) == STATE_OK) {
463 result = STATE_WARNING; 523 result.state = STATE_WARNING;
464 if (warn_text == NULL) { 524 if (warn_text == NULL) {
465 warn_text = strdup(_("System call sent warnings to stderr ")); 525 warn_text = strdup(_("System call sent warnings to stderr "));
466 } else { 526 } else {
@@ -474,43 +534,46 @@ int run_ping(const char *cmd, const char *addr) {
474 534
475 spclose(child_process); 535 spclose(child_process);
476 536
477 if (warn_text == NULL) 537 if (warn_text == NULL) {
478 warn_text = strdup(""); 538 warn_text = strdup("");
539 }
479 540
480 return result; 541 return result;
481} 542}
482 543
483int error_scan(char buf[MAX_INPUT_BUFFER], const char *addr) { 544mp_state_enum error_scan(char buf[MAX_INPUT_BUFFER], const char *addr) {
484 if (strstr(buf, "Network is unreachable") || strstr(buf, "Destination Net Unreachable") || strstr(buf, "No route")) 545 if (strstr(buf, "Network is unreachable") || strstr(buf, "Destination Net Unreachable") || strstr(buf, "No route")) {
485 die(STATE_CRITICAL, _("CRITICAL - Network Unreachable (%s)\n"), addr); 546 die(STATE_CRITICAL, _("CRITICAL - Network Unreachable (%s)\n"), addr);
486 else if (strstr(buf, "Destination Host Unreachable") || strstr(buf, "Address unreachable")) 547 } else if (strstr(buf, "Destination Host Unreachable") || strstr(buf, "Address unreachable")) {
487 die(STATE_CRITICAL, _("CRITICAL - Host Unreachable (%s)\n"), addr); 548 die(STATE_CRITICAL, _("CRITICAL - Host Unreachable (%s)\n"), addr);
488 else if (strstr(buf, "Destination Port Unreachable") || strstr(buf, "Port unreachable")) 549 } else if (strstr(buf, "Destination Port Unreachable") || strstr(buf, "Port unreachable")) {
489 die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Port Unreachable (%s)\n"), addr); 550 die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Port Unreachable (%s)\n"), addr);
490 else if (strstr(buf, "Destination Protocol Unreachable")) 551 } else if (strstr(buf, "Destination Protocol Unreachable")) {
491 die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Protocol Unreachable (%s)\n"), addr); 552 die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Protocol Unreachable (%s)\n"), addr);
492 else if (strstr(buf, "Destination Net Prohibited")) 553 } else if (strstr(buf, "Destination Net Prohibited")) {
493 die(STATE_CRITICAL, _("CRITICAL - Network Prohibited (%s)\n"), addr); 554 die(STATE_CRITICAL, _("CRITICAL - Network Prohibited (%s)\n"), addr);
494 else if (strstr(buf, "Destination Host Prohibited")) 555 } else if (strstr(buf, "Destination Host Prohibited")) {
495 die(STATE_CRITICAL, _("CRITICAL - Host Prohibited (%s)\n"), addr); 556 die(STATE_CRITICAL, _("CRITICAL - Host Prohibited (%s)\n"), addr);
496 else if (strstr(buf, "Packet filtered") || strstr(buf, "Administratively prohibited")) 557 } else if (strstr(buf, "Packet filtered") || strstr(buf, "Administratively prohibited")) {
497 die(STATE_CRITICAL, _("CRITICAL - Packet Filtered (%s)\n"), addr); 558 die(STATE_CRITICAL, _("CRITICAL - Packet Filtered (%s)\n"), addr);
498 else if (strstr(buf, "unknown host")) 559 } else if (strstr(buf, "unknown host")) {
499 die(STATE_CRITICAL, _("CRITICAL - Host not found (%s)\n"), addr); 560 die(STATE_CRITICAL, _("CRITICAL - Host not found (%s)\n"), addr);
500 else if (strstr(buf, "Time to live exceeded") || strstr(buf, "Time exceeded")) 561 } else if (strstr(buf, "Time to live exceeded") || strstr(buf, "Time exceeded")) {
501 die(STATE_CRITICAL, _("CRITICAL - Time to live exceeded (%s)\n"), addr); 562 die(STATE_CRITICAL, _("CRITICAL - Time to live exceeded (%s)\n"), addr);
502 else if (strstr(buf, "Destination unreachable: ")) 563 } else if (strstr(buf, "Destination unreachable: ")) {
503 die(STATE_CRITICAL, _("CRITICAL - Destination Unreachable (%s)\n"), addr); 564 die(STATE_CRITICAL, _("CRITICAL - Destination Unreachable (%s)\n"), addr);
565 }
504 566
505 if (strstr(buf, "(DUP!)") || strstr(buf, "DUPLICATES FOUND")) { 567 if (strstr(buf, "(DUP!)") || strstr(buf, "DUPLICATES FOUND")) {
506 if (warn_text == NULL) 568 if (warn_text == NULL) {
507 warn_text = strdup(_(WARN_DUPLICATES)); 569 warn_text = strdup(_(WARN_DUPLICATES));
508 else if (!strstr(warn_text, _(WARN_DUPLICATES)) && xasprintf(&warn_text, "%s %s", warn_text, _(WARN_DUPLICATES)) == -1) 570 } else if (!strstr(warn_text, _(WARN_DUPLICATES)) && xasprintf(&warn_text, "%s %s", warn_text, _(WARN_DUPLICATES)) == -1) {
509 die(STATE_UNKNOWN, _("Unable to realloc warn_text\n")); 571 die(STATE_UNKNOWN, _("Unable to realloc warn_text\n"));
510 return (STATE_WARNING); 572 }
573 return STATE_WARNING;
511 } 574 }
512 575
513 return (STATE_OK); 576 return STATE_OK;
514} 577}
515 578
516void print_help(void) { 579void print_help(void) {
@@ -551,9 +614,7 @@ void print_help(void) {
551 614
552 printf("\n"); 615 printf("\n");
553 printf("%s\n", _("This plugin uses the ping command to probe the specified host for packet loss")); 616 printf("%s\n", _("This plugin uses the ping command to probe the specified host for packet loss"));
554 printf("%s\n", _("(percentage) and round trip average (milliseconds). It can produce HTML output")); 617 printf("%s\n", _("(percentage) and round trip average (milliseconds). It can produce HTML output."));
555 printf("%s\n", _("linking to a traceroute CGI contributed by Ian Cass. The CGI can be found in"));
556 printf("%s\n", _("the contrib area of the downloads section at http://www.nagios.org/"));
557 618
558 printf(UT_SUPPORT); 619 printf(UT_SUPPORT);
559} 620}
diff --git a/plugins/check_ping.d/config.h b/plugins/check_ping.d/config.h
new file mode 100644
index 00000000..eb2735a7
--- /dev/null
+++ b/plugins/check_ping.d/config.h
@@ -0,0 +1,46 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5#include <stdlib.h>
6
7enum {
8 UNKNOWN_PACKET_LOSS = 200, /* 200% */
9 DEFAULT_MAX_PACKETS = 5 /* default no. of ICMP ECHO packets */
10};
11
12#define UNKNOWN_TRIP_TIME -1.0 /* -1 seconds */
13
14#define MAX_ADDR_START 1
15
16typedef struct {
17 bool display_html;
18 int max_packets;
19
20 char **addresses;
21 size_t n_addresses;
22
23 int wpl;
24 int cpl;
25 double wrta;
26 double crta;
27} check_ping_config;
28
29check_ping_config check_ping_config_init() {
30 check_ping_config tmp = {
31 .display_html = false,
32 .max_packets = -1,
33
34 .addresses = NULL,
35 .n_addresses = 0,
36
37 .wpl = UNKNOWN_PACKET_LOSS,
38 .cpl = UNKNOWN_PACKET_LOSS,
39 .wrta = UNKNOWN_TRIP_TIME,
40 .crta = UNKNOWN_TRIP_TIME,
41 };
42
43 tmp.addresses = calloc(MAX_ADDR_START, sizeof(char *));
44 tmp.addresses[0] = NULL;
45 return tmp;
46}
diff --git a/plugins/check_radius.c b/plugins/check_radius.c
index d9ff8fa7..cc846709 100644
--- a/plugins/check_radius.c
+++ b/plugins/check_radius.c
@@ -1,32 +1,32 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_radius plugin 3 * Monitoring check_radius plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2024 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_radius plugin 10 * This file contains the check_radius plugin
11* 11 *
12* Tests to see if a radius server is accepting connections. 12 * Tests to see if a radius server is accepting connections.
13* 13 *
14* 14 *
15* This program is free software: you can redistribute it and/or modify 15 * This program is free software: you can redistribute it and/or modify
16* it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
17* the Free Software Foundation, either version 3 of the License, or 17 * the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18 * (at your option) any later version.
19* 19 *
20* This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23 * GNU General Public License for more details.
24* 24 *
25* You should have received a copy of the GNU General Public License 25 * You should have received a copy of the GNU General Public License
26* along with this program. If not, see <http://www.gnu.org/licenses/>. 26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27 *
28* 28 *
29*****************************************************************************/ 29 *****************************************************************************/
30 30
31const char *progname = "check_radius"; 31const char *progname = "check_radius";
32const char *copyright = "2000-2024"; 32const char *copyright = "2000-2024";
@@ -35,64 +35,57 @@ const char *email = "devel@monitoring-plugins.org";
35#include "common.h" 35#include "common.h"
36#include "utils.h" 36#include "utils.h"
37#include "netutils.h" 37#include "netutils.h"
38#include "states.h"
39#include "check_radius.d/config.h"
38 40
39#if defined(HAVE_LIBRADCLI) 41#if defined(HAVE_LIBRADCLI)
40#include <radcli/radcli.h> 42# include <radcli/radcli.h>
41#elif defined(HAVE_LIBFREERADIUS_CLIENT) 43#elif defined(HAVE_LIBFREERADIUS_CLIENT)
42#include <freeradius-client.h> 44# include <freeradius-client.h>
43#elif defined(HAVE_LIBRADIUSCLIENT_NG) 45#elif defined(HAVE_LIBRADIUSCLIENT_NG)
44#include <radiusclient-ng.h> 46# include <radiusclient-ng.h>
45#else 47#else
46#include <radiusclient.h> 48# include <radiusclient.h>
47#endif 49#endif
48 50
49static int process_arguments (int /*argc*/, char ** /*argv*/); 51typedef struct {
50static void print_help (void); 52 int errorcode;
51void print_usage (void); 53 check_radius_config config;
54} check_radius_config_wrapper;
55static check_radius_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
56static void print_help(void);
57void print_usage(void);
52 58
53#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI) 59#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
54#define my_rc_conf_str(a) rc_conf_str(rch,a) 60# define my_rc_conf_str(a) rc_conf_str(rch, a)
55#if defined(HAVE_LIBRADCLI) 61# if defined(HAVE_LIBRADCLI)
56#define my_rc_send_server(a,b) rc_send_server(rch,a,b,AUTH) 62# define my_rc_send_server(a, b) rc_send_server(rch, a, b, AUTH)
57#else 63# else
58#define my_rc_send_server(a,b) rc_send_server(rch,a,b) 64# define my_rc_send_server(a, b) rc_send_server(rch, a, b)
59#endif 65# endif
60#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADCLI) 66# if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADCLI)
61#define my_rc_buildreq(a,b,c,d,e,f) rc_buildreq(rch,a,b,c,d,(a)->secret,e,f) 67# define my_rc_buildreq(a, b, c, d, e, f) rc_buildreq(rch, a, b, c, d, (a)->secret, e, f)
62#else 68# else
63#define my_rc_buildreq(a,b,c,d,e,f) rc_buildreq(rch,a,b,c,d,e,f) 69# define my_rc_buildreq(a, b, c, d, e, f) rc_buildreq(rch, a, b, c, d, e, f)
64#endif 70# endif
65#define my_rc_avpair_add(a,b,c,d) rc_avpair_add(rch,a,b,c,-1,d) 71# define my_rc_avpair_add(a, b, c, d) rc_avpair_add(rch, a, b, c, -1, d)
66#define my_rc_read_dictionary(a) rc_read_dictionary(rch, a) 72# define my_rc_read_dictionary(a) rc_read_dictionary(rch, a)
67#else 73#else
68#define my_rc_conf_str(a) rc_conf_str(a) 74# define my_rc_conf_str(a) rc_conf_str(a)
69#define my_rc_send_server(a,b) rc_send_server(a, b) 75# define my_rc_send_server(a, b) rc_send_server(a, b)
70#define my_rc_buildreq(a,b,c,d,e,f) rc_buildreq(a,b,c,d,e,f) 76# define my_rc_buildreq(a, b, c, d, e, f) rc_buildreq(a, b, c, d, e, f)
71#define my_rc_avpair_add(a,b,c,d) rc_avpair_add(a, b, c, d) 77# define my_rc_avpair_add(a, b, c, d) rc_avpair_add(a, b, c, d)
72#define my_rc_read_dictionary(a) rc_read_dictionary(a) 78# define my_rc_read_dictionary(a) rc_read_dictionary(a)
73#endif 79#endif
74 80
75/* REJECT_RC is only defined in some version of radiusclient. It has 81/* REJECT_RC is only defined in some version of radiusclient. It has
76 * been reported from radiusclient-ng 0.5.6 on FreeBSD 7.2-RELEASE */ 82 * been reported from radiusclient-ng 0.5.6 on FreeBSD 7.2-RELEASE */
77#ifndef REJECT_RC 83#ifndef REJECT_RC
78#define REJECT_RC BADRESP_RC 84# define REJECT_RC BADRESP_RC
79#endif 85#endif
80 86
81static int my_rc_read_config(char * /*a*/); 87static int my_rc_read_config(char * /*a*/, rc_handle ** /*rch*/);
82
83#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
84static rc_handle *rch = NULL;
85#endif
86 88
87static char *server = NULL;
88static char *username = NULL;
89static char *password = NULL;
90static char *nasid = NULL;
91static char *nasipaddress = NULL;
92static char *expect = NULL;
93static char *config_file = NULL;
94static unsigned short port = PW_AUTH_UDP_PORT;
95static int retries = 1;
96static bool verbose = false; 89static bool verbose = false;
97 90
98/****************************************************************************** 91/******************************************************************************
@@ -148,149 +141,167 @@ Please note that all tags must be lowercase to use the DocBook XML DTD.
148-@@ 141-@@
149******************************************************************************/ 142******************************************************************************/
150 143
144int main(int argc, char **argv) {
145 setlocale(LC_ALL, "");
146 bindtextdomain(PACKAGE, LOCALEDIR);
147 textdomain(PACKAGE);
151 148
149 /* Parse extra opts if any */
150 argv = np_extra_opts(&argc, argv, progname);
151
152 check_radius_config_wrapper tmp_config = process_arguments(argc, argv);
153
154 if (tmp_config.errorcode == ERROR) {
155 usage4(_("Could not parse arguments"));
156 }
157
158 check_radius_config config = tmp_config.config;
159
160#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
161 rc_handle *rch = NULL;
162#endif
163
164 char *str = strdup("dictionary");
165 if ((config.config_file && my_rc_read_config(config.config_file, &rch)) || my_rc_read_dictionary(my_rc_conf_str(str))) {
166 die(STATE_UNKNOWN, _("Config file error\n"));
167 }
168
169 uint32_t service = PW_AUTHENTICATE_ONLY;
170
171 SEND_DATA data;
172 memset(&data, 0, sizeof(data));
173 if (!(my_rc_avpair_add(&data.send_pairs, PW_SERVICE_TYPE, &service, 0) &&
174 my_rc_avpair_add(&data.send_pairs, PW_USER_NAME, config.username, 0) &&
175 my_rc_avpair_add(&data.send_pairs, PW_USER_PASSWORD, config.password, 0))) {
176 die(STATE_UNKNOWN, _("Out of Memory?\n"));
177 }
178
179 if (config.nas_id != NULL) {
180 if (!(my_rc_avpair_add(&data.send_pairs, PW_NAS_IDENTIFIER, config.nas_id, 0))) {
181 die(STATE_UNKNOWN, _("Invalid NAS-Identifier\n"));
182 }
183 }
152 184
153int
154main (int argc, char **argv)
155{
156 struct sockaddr_storage ss;
157 char name[HOST_NAME_MAX]; 185 char name[HOST_NAME_MAX];
186 if (config.nas_ip_address == NULL) {
187 if (gethostname(name, sizeof(name)) != 0) {
188 die(STATE_UNKNOWN, _("gethostname() failed!\n"));
189 }
190 config.nas_ip_address = name;
191 }
192
193 struct sockaddr_storage radius_server_socket;
194 if (!dns_lookup(config.nas_ip_address, &radius_server_socket, AF_UNSPEC)) {
195 die(STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
196 }
197
198 uint32_t client_id = ntohl(((struct sockaddr_in *)&radius_server_socket)->sin_addr.s_addr);
199 if (my_rc_avpair_add(&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0) == NULL) {
200 die(STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
201 }
202
203 my_rc_buildreq(&data, PW_ACCESS_REQUEST, config.server, config.port, (int)timeout_interval, config.retries);
204
158#ifdef RC_BUFFER_LEN 205#ifdef RC_BUFFER_LEN
159 char msg[RC_BUFFER_LEN]; 206 char msg[RC_BUFFER_LEN];
160#else 207#else
161 char msg[BUFFER_LEN]; 208 char msg[BUFFER_LEN];
162#endif 209#endif
163 SEND_DATA data;
164 int result = STATE_UNKNOWN;
165 uint32_t client_id, service;
166 char *str;
167
168 setlocale (LC_ALL, "");
169 bindtextdomain (PACKAGE, LOCALEDIR);
170 textdomain (PACKAGE);
171 210
172 /* Parse extra opts if any */ 211 int result = my_rc_send_server(&data, msg);
173 argv=np_extra_opts (&argc, argv, progname); 212 rc_avpair_free(data.send_pairs);
213 if (data.receive_pairs) {
214 rc_avpair_free(data.receive_pairs);
215 }
174 216
175 if (process_arguments (argc, argv) == ERROR) 217 if (result == TIMEOUT_RC) {
176 usage4 (_("Could not parse arguments")); 218 printf("Timeout\n");
219 exit(STATE_CRITICAL);
220 }
177 221
178 str = strdup ("dictionary"); 222 if (result == ERROR_RC) {
179 if ((config_file && my_rc_read_config (config_file)) || 223 printf(_("Auth Error\n"));
180 my_rc_read_dictionary (my_rc_conf_str (str))) 224 exit(STATE_CRITICAL);
181 die (STATE_UNKNOWN, _("Config file error\n")); 225 }
182 226
183 service = PW_AUTHENTICATE_ONLY; 227 if (result == REJECT_RC) {
228 printf(_("Auth Failed\n"));
229 exit(STATE_WARNING);
230 }
184 231
185 memset (&data, 0, sizeof(data)); 232 if (result == BADRESP_RC) {
186 if (!(my_rc_avpair_add (&data.send_pairs, PW_SERVICE_TYPE, &service, 0) && 233 printf(_("Bad Response\n"));
187 my_rc_avpair_add (&data.send_pairs, PW_USER_NAME, username, 0) && 234 exit(STATE_WARNING);
188 my_rc_avpair_add (&data.send_pairs, PW_USER_PASSWORD, password, 0) 235 }
189 ))
190 die (STATE_UNKNOWN, _("Out of Memory?\n"));
191 236
192 if (nasid != NULL) { 237 if (config.expect && !strstr(msg, config.expect)) {
193 if (!(my_rc_avpair_add (&data.send_pairs, PW_NAS_IDENTIFIER, nasid, 0))) 238 printf("%s\n", msg);
194 die (STATE_UNKNOWN, _("Invalid NAS-Identifier\n")); 239 exit(STATE_WARNING);
195 } 240 }
196 241
197 if (nasipaddress == NULL) { 242 if (result == OK_RC) {
198 if (gethostname (name, sizeof(name)) != 0) 243 printf(_("Auth OK\n"));
199 die (STATE_UNKNOWN, _("gethostname() failed!\n")); 244 exit(STATE_OK);
200 nasipaddress = name;
201 } 245 }
202 if (!dns_lookup (nasipaddress, &ss, AF_INET)) /* TODO: Support IPv6. */ 246
203 die (STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
204 client_id = ntohl (((struct sockaddr_in *)&ss)->sin_addr.s_addr);
205 if (my_rc_avpair_add (&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0) == NULL)
206 die (STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
207
208 my_rc_buildreq (&data, PW_ACCESS_REQUEST, server, port, (int)timeout_interval,
209 retries);
210
211 result = my_rc_send_server (&data, msg);
212 rc_avpair_free (data.send_pairs);
213 if (data.receive_pairs)
214 rc_avpair_free (data.receive_pairs);
215
216 if (result == TIMEOUT_RC)
217 die (STATE_CRITICAL, _("Timeout\n"));
218 if (result == ERROR_RC)
219 die (STATE_CRITICAL, _("Auth Error\n"));
220 if (result == REJECT_RC)
221 die (STATE_WARNING, _("Auth Failed\n"));
222 if (result == BADRESP_RC)
223 die (STATE_WARNING, _("Bad Response\n"));
224 if (expect && !strstr (msg, expect))
225 die (STATE_WARNING, "%s\n", msg);
226 if (result == OK_RC)
227 die (STATE_OK, _("Auth OK\n"));
228 (void)snprintf(msg, sizeof(msg), _("Unexpected result code %d"), result); 247 (void)snprintf(msg, sizeof(msg), _("Unexpected result code %d"), result);
229 die (STATE_UNKNOWN, "%s\n", msg); 248 printf("%s\n", msg);
249 exit(STATE_UNKNOWN);
230} 250}
231 251
232
233
234/* process command-line arguments */ 252/* process command-line arguments */
235int 253check_radius_config_wrapper process_arguments(int argc, char **argv) {
236process_arguments (int argc, char **argv) 254 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, {"port", required_argument, 0, 'P'},
237{ 255 {"username", required_argument, 0, 'u'}, {"password", required_argument, 0, 'p'},
238 int c; 256 {"nas-id", required_argument, 0, 'n'}, {"nas-ip-address", required_argument, 0, 'N'},
239 257 {"filename", required_argument, 0, 'F'}, {"expect", required_argument, 0, 'e'},
240 int option = 0; 258 {"retries", required_argument, 0, 'r'}, {"timeout", required_argument, 0, 't'},
241 static struct option longopts[] = { 259 {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'},
242 {"hostname", required_argument, 0, 'H'}, 260 {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
243 {"port", required_argument, 0, 'P'}, 261
244 {"username", required_argument, 0, 'u'}, 262 check_radius_config_wrapper result = {
245 {"password", required_argument, 0, 'p'}, 263 .errorcode = OK,
246 {"nas-id", required_argument, 0, 'n'}, 264 .config = check_radius_config_init(),
247 {"nas-ip-address", required_argument, 0, 'N'},
248 {"filename", required_argument, 0, 'F'},
249 {"expect", required_argument, 0, 'e'},
250 {"retries", required_argument, 0, 'r'},
251 {"timeout", required_argument, 0, 't'},
252 {"verbose", no_argument, 0, 'v'},
253 {"version", no_argument, 0, 'V'},
254 {"help", no_argument, 0, 'h'},
255 {0, 0, 0, 0}
256 }; 265 };
257 266
258 while (1) { 267 while (true) {
259 c = getopt_long (argc, argv, "+hVvH:P:F:u:p:n:N:t:r:e:", longopts, 268 int option = 0;
260 &option); 269 int option_index = getopt_long(argc, argv, "+hVvH:P:F:u:p:n:N:t:r:e:", longopts, &option);
261 270
262 if (c == -1 || c == EOF || c == 1) 271 if (option_index == -1 || option_index == EOF || option_index == 1) {
263 break; 272 break;
273 }
264 274
265 switch (c) { 275 switch (option_index) {
266 case '?': /* print short usage statement if args not parsable */ 276 case '?': /* print short usage statement if args not parsable */
267 usage5 (); 277 usage5();
268 case 'h': /* help */ 278 case 'h': /* help */
269 print_help (); 279 print_help();
270 exit (STATE_UNKNOWN); 280 exit(STATE_UNKNOWN);
271 case 'V': /* version */ 281 case 'V': /* version */
272 print_revision (progname, NP_VERSION); 282 print_revision(progname, NP_VERSION);
273 exit (STATE_UNKNOWN); 283 exit(STATE_UNKNOWN);
274 case 'v': /* verbose mode */ 284 case 'v': /* verbose mode */
275 verbose = true; 285 verbose = true;
276 break; 286 break;
277 case 'H': /* hostname */ 287 case 'H': /* hostname */
278 if (!is_host (optarg)) { 288 if (!is_host(optarg)) {
279 usage2 (_("Invalid hostname/address"), optarg); 289 usage2(_("Invalid hostname/address"), optarg);
280 } 290 }
281 server = optarg; 291 result.config.server = optarg;
282 break; 292 break;
283 case 'P': /* port */ 293 case 'P': /* port */
284 if (is_intnonneg (optarg)) 294 if (is_intnonneg(optarg)) {
285 port = (unsigned short)atoi (optarg); 295 result.config.port = (unsigned short)atoi(optarg);
286 else 296 } else {
287 usage4 (_("Port must be a positive integer")); 297 usage4(_("Port must be a positive integer"));
298 }
288 break; 299 break;
289 case 'u': /* username */ 300 case 'u': /* username */
290 username = optarg; 301 result.config.username = optarg;
291 break; 302 break;
292 case 'p': /* password */ 303 case 'p': /* password */
293 password = strdup(optarg); 304 result.config.password = strdup(optarg);
294 305
295 /* Delete the password from process list */ 306 /* Delete the password from process list */
296 while (*optarg != '\0') { 307 while (*optarg != '\0') {
@@ -298,119 +309,115 @@ process_arguments (int argc, char **argv)
298 optarg++; 309 optarg++;
299 } 310 }
300 break; 311 break;
301 case 'n': /* nas id */ 312 case 'n': /* nas id */
302 nasid = optarg; 313 result.config.nas_id = optarg;
303 break; 314 break;
304 case 'N': /* nas ip address */ 315 case 'N': /* nas ip address */
305 nasipaddress = optarg; 316 result.config.nas_ip_address = optarg;
306 break; 317 break;
307 case 'F': /* configuration file */ 318 case 'F': /* configuration file */
308 config_file = optarg; 319 result.config.config_file = optarg;
309 break; 320 break;
310 case 'e': /* expect */ 321 case 'e': /* expect */
311 expect = optarg; 322 result.config.expect = optarg;
312 break; 323 break;
313 case 'r': /* retries */ 324 case 'r': /* retries */
314 if (is_intpos (optarg)) 325 if (is_intpos(optarg)) {
315 retries = atoi (optarg); 326 result.config.retries = atoi(optarg);
316 else 327 } else {
317 usage4 (_("Number of retries must be a positive integer")); 328 usage4(_("Number of retries must be a positive integer"));
329 }
318 break; 330 break;
319 case 't': /* timeout */ 331 case 't': /* timeout */
320 if (is_intpos (optarg)) 332 if (is_intpos(optarg)) {
321 timeout_interval = (unsigned)atoi (optarg); 333 timeout_interval = (unsigned)atoi(optarg);
322 else 334 } else {
323 usage2 (_("Timeout interval must be a positive integer"), optarg); 335 usage2(_("Timeout interval must be a positive integer"), optarg);
336 }
324 break; 337 break;
325 } 338 }
326 } 339 }
327 340
328 if (server == NULL) 341 if (result.config.server == NULL) {
329 usage4 (_("Hostname was not supplied")); 342 usage4(_("Hostname was not supplied"));
330 if (username == NULL) 343 }
331 usage4 (_("User not specified")); 344 if (result.config.username == NULL) {
332 if (password == NULL) 345 usage4(_("User not specified"));
333 usage4 (_("Password not specified")); 346 }
334 if (config_file == NULL) 347 if (result.config.password == NULL) {
335 usage4 (_("Configuration file not specified")); 348 usage4(_("Password not specified"));
349 }
350 if (result.config.config_file == NULL) {
351 usage4(_("Configuration file not specified"));
352 }
336 353
337 return OK; 354 return result;
338} 355}
339 356
340 357void print_help(void) {
341
342void
343print_help (void)
344{
345 char *myport; 358 char *myport;
346 xasprintf (&myport, "%d", PW_AUTH_UDP_PORT); 359 xasprintf(&myport, "%d", PW_AUTH_UDP_PORT);
347 360
348 print_revision (progname, NP_VERSION); 361 print_revision(progname, NP_VERSION);
349 362
350 printf ("Copyright (c) 1999 Robert August Vincent II\n"); 363 printf("Copyright (c) 1999 Robert August Vincent II\n");
351 printf (COPYRIGHT, copyright, email); 364 printf(COPYRIGHT, copyright, email);
352 365
353 printf("%s\n", _("Tests to see if a RADIUS server is accepting connections.")); 366 printf("%s\n", _("Tests to see if a RADIUS server is accepting connections."));
354 367
355 printf ("\n\n"); 368 printf("\n\n");
356 369
357 print_usage (); 370 print_usage();
358 371
359 printf (UT_HELP_VRSN); 372 printf(UT_HELP_VRSN);
360 printf (UT_EXTRA_OPTS); 373 printf(UT_EXTRA_OPTS);
361 374
362 printf (UT_HOST_PORT, 'P', myport); 375 printf(UT_HOST_PORT, 'P', myport);
363 376
364 printf (" %s\n", "-u, --username=STRING"); 377 printf(" %s\n", "-u, --username=STRING");
365 printf (" %s\n", _("The user to authenticate")); 378 printf(" %s\n", _("The user to authenticate"));
366 printf (" %s\n", "-p, --password=STRING"); 379 printf(" %s\n", "-p, --password=STRING");
367 printf (" %s\n", _("Password for authentication (SECURITY RISK)")); 380 printf(" %s\n", _("Password for authentication (SECURITY RISK)"));
368 printf (" %s\n", "-n, --nas-id=STRING"); 381 printf(" %s\n", "-n, --nas-id=STRING");
369 printf (" %s\n", _("NAS identifier")); 382 printf(" %s\n", _("NAS identifier"));
370 printf (" %s\n", "-N, --nas-ip-address=STRING"); 383 printf(" %s\n", "-N, --nas-ip-address=STRING");
371 printf (" %s\n", _("NAS IP Address")); 384 printf(" %s\n", _("NAS IP Address"));
372 printf (" %s\n", "-F, --filename=STRING"); 385 printf(" %s\n", "-F, --filename=STRING");
373 printf (" %s\n", _("Configuration file")); 386 printf(" %s\n", _("Configuration file"));
374 printf (" %s\n", "-e, --expect=STRING"); 387 printf(" %s\n", "-e, --expect=STRING");
375 printf (" %s\n", _("Response string to expect from the server")); 388 printf(" %s\n", _("Response string to expect from the server"));
376 printf (" %s\n", "-r, --retries=INTEGER"); 389 printf(" %s\n", "-r, --retries=INTEGER");
377 printf (" %s\n", _("Number of times to retry a failed connection")); 390 printf(" %s\n", _("Number of times to retry a failed connection"));
378 391
379 printf (UT_CONN_TIMEOUT, timeout_interval); 392 printf(UT_CONN_TIMEOUT, timeout_interval);
380 393
381 printf ("\n"); 394 printf("\n");
382 printf ("%s\n", _("This plugin tests a RADIUS server to see if it is accepting connections.")); 395 printf("%s\n", _("This plugin tests a RADIUS server to see if it is accepting connections."));
383 printf ("%s\n", _("The server to test must be specified in the invocation, as well as a user")); 396 printf("%s\n", _("The server to test must be specified in the invocation, as well as a user"));
384 printf ("%s\n", _("name and password. A configuration file must be present. The format of")); 397 printf("%s\n", _("name and password. A configuration file must be present. The format of"));
385 printf ("%s\n", _("the configuration file is described in the radiusclient library sources.")); 398 printf("%s\n", _("the configuration file is described in the radiusclient library sources."));
386 printf ("%s\n", _("The password option presents a substantial security issue because the")); 399 printf("%s\n", _("The password option presents a substantial security issue because the"));
387 printf ("%s\n", _("password can possibly be determined by careful watching of the command line")); 400 printf("%s\n", _("password can possibly be determined by careful watching of the command line"));
388 printf ("%s\n", _("in a process listing. This risk is exacerbated because the plugin will")); 401 printf("%s\n", _("in a process listing. This risk is exacerbated because the plugin will"));
389 printf ("%s\n", _("typically be executed at regular predictable intervals. Please be sure that")); 402 printf("%s\n", _("typically be executed at regular predictable intervals. Please be sure that"));
390 printf ("%s\n", _("the password used does not allow access to sensitive system resources.")); 403 printf("%s\n", _("the password used does not allow access to sensitive system resources."));
391 404
392 printf (UT_SUPPORT); 405 printf(UT_SUPPORT);
393} 406}
394 407
395 408void print_usage(void) {
396 409 printf("%s\n", _("Usage:"));
397void 410 printf("%s -H host -F config_file -u username -p password\n\
398print_usage (void)
399{
400 printf ("%s\n", _("Usage:"));
401 printf ("%s -H host -F config_file -u username -p password\n\
402 [-P port] [-t timeout] [-r retries] [-e expect]\n\ 411 [-P port] [-t timeout] [-r retries] [-e expect]\n\
403 [-n nas-id] [-N nas-ip-addr]\n", progname); 412 [-n nas-id] [-N nas-ip-addr]\n",
413 progname);
404} 414}
405 415
406 416int my_rc_read_config(char *config_file_name, rc_handle **rch) {
407
408int my_rc_read_config(char * a)
409{
410#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI) 417#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
411 rch = rc_read_config(a); 418 *rch = rc_read_config(config_file_name);
412 return (rch == NULL) ? 1 : 0; 419 return (rch == NULL) ? 1 : 0;
413#else 420#else
414 return rc_read_config(a); 421 return rc_read_config(config_file_name);
415#endif 422#endif
416} 423}
diff --git a/plugins/check_radius.d/config.h b/plugins/check_radius.d/config.h
new file mode 100644
index 00000000..b27d31e7
--- /dev/null
+++ b/plugins/check_radius.d/config.h
@@ -0,0 +1,42 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5#if defined(HAVE_LIBRADCLI)
6# include <radcli/radcli.h>
7#elif defined(HAVE_LIBFREERADIUS_CLIENT)
8# include <freeradius-client.h>
9#elif defined(HAVE_LIBRADIUSCLIENT_NG)
10# include <radiusclient-ng.h>
11#else
12# include <radiusclient.h>
13#endif
14
15typedef struct {
16 char *server;
17 char *username;
18 char *password;
19 char *config_file;
20 char *nas_id;
21 char *nas_ip_address;
22 int retries;
23 unsigned short port;
24
25 char *expect;
26} check_radius_config;
27
28check_radius_config check_radius_config_init() {
29 check_radius_config tmp = {
30 .server = NULL,
31 .username = NULL,
32 .password = NULL,
33 .config_file = NULL,
34 .nas_id = NULL,
35 .nas_ip_address = NULL,
36 .retries = 1,
37 .port = PW_AUTH_UDP_PORT,
38
39 .expect = NULL,
40 };
41 return tmp;
42}
diff --git a/plugins/check_tcp.c b/plugins/check_tcp.c
index 49ad096c..22dcc74e 100644
--- a/plugins/check_tcp.c
+++ b/plugins/check_tcp.c
@@ -3,7 +3,7 @@
3 * Monitoring check_tcp plugin 3 * Monitoring check_tcp plugin
4 * 4 *
5 * License: GPL 5 * License: GPL
6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2025 Monitoring Plugins Development Team
7 * 7 *
8 * Description: 8 * Description:
9 * 9 *
@@ -29,74 +29,63 @@
29 29
30/* progname "check_tcp" changes depending on symlink called */ 30/* progname "check_tcp" changes depending on symlink called */
31char *progname; 31char *progname;
32const char *copyright = "1999-2024"; 32const char *copyright = "1999-2025";
33const char *email = "devel@monitoring-plugins.org"; 33const char *email = "devel@monitoring-plugins.org";
34 34
35#include "common.h" 35#include "./common.h"
36#include "netutils.h" 36#include "./netutils.h"
37#include "utils.h" 37#include "./utils.h"
38#include "utils_tcp.h" 38#include "./check_tcp.d/config.h"
39#include "output.h"
40#include "states.h"
39 41
42#include <sys/types.h>
40#include <ctype.h> 43#include <ctype.h>
41#include <sys/select.h> 44#include <sys/select.h>
42 45
46ssize_t my_recv(int socket_descriptor, char *buf, size_t len, bool use_tls) {
43#ifdef HAVE_SSL 47#ifdef HAVE_SSL
44static bool check_cert = false; 48 if (use_tls) {
45static int days_till_exp_warn, days_till_exp_crit; 49 return np_net_ssl_read(buf, (int)len);
46# define my_recv(buf, len) ((flags & FLAG_SSL) ? np_net_ssl_read(buf, len) : read(sd, buf, len)) 50 }
47# define my_send(buf, len) ((flags & FLAG_SSL) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
48#else
49# define my_recv(buf, len) read(sd, buf, len)
50# define my_send(buf, len) send(sd, buf, len, 0)
51#endif 51#endif
52 return read(socket_descriptor, buf, len);
53}
52 54
53/* int my_recv(char *, size_t); */ 55ssize_t my_send(int socket_descriptor, char *buf, size_t len, bool use_tls) {
54static int process_arguments(int /*argc*/, char ** /*argv*/); 56#ifdef HAVE_SSL
55static void print_help(void); 57 if (use_tls) {
58 return np_net_ssl_write(buf, (int)len);
59 }
60#endif
61 return write(socket_descriptor, buf, len);
62}
63
64typedef struct {
65 int errorcode;
66 check_tcp_config config;
67} check_tcp_config_wrapper;
68static check_tcp_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/, check_tcp_config /*config*/);
69void print_help(const char *service);
56void print_usage(void); 70void print_usage(void);
57 71
58#define EXPECT server_expect[0] 72int verbosity = 0;
59static char *SERVICE = "TCP";
60static char *SEND = NULL;
61static char *QUIT = NULL;
62static int PROTOCOL = IPPROTO_TCP; /* most common is default */
63static int PORT = 0;
64static int READ_TIMEOUT = 2;
65
66static int server_port = 0;
67static char *server_address = NULL;
68static bool host_specified = false;
69static char *server_send = NULL;
70static char *server_quit = NULL;
71static char **server_expect;
72static size_t server_expect_count = 0;
73static ssize_t maxbytes = 0;
74static char **warn_codes = NULL;
75static size_t warn_codes_count = 0;
76static char **crit_codes = NULL;
77static size_t crit_codes_count = 0;
78static unsigned int delay = 0;
79static double warning_time = 0;
80static double critical_time = 0;
81static double elapsed_time = 0;
82static long microsec;
83static int sd = 0;
84#define MAXBUF 1024
85static char buffer[MAXBUF];
86static int expect_mismatch_state = STATE_WARNING;
87static int match_flags = NP_MATCH_EXACT;
88 73
89#ifdef HAVE_SSL 74static const int READ_TIMEOUT = 2;
90static char *sni = NULL;
91static bool sni_specified = false;
92#endif
93 75
94#define FLAG_SSL 0x01 76const int MAXBUF = 1024;
95#define FLAG_VERBOSE 0x02 77
96#define FLAG_TIME_WARN 0x04 78const int DEFAULT_FTP_PORT = 21;
97#define FLAG_TIME_CRIT 0x08 79const int DEFAULT_POP_PORT = 110;
98#define FLAG_HIDE_OUTPUT 0x10 80const int DEFAULT_SPOP_PORT = 995;
99static size_t flags; 81const int DEFAULT_SMTP_PORT = 25;
82const int DEFAULT_SSMTP_PORT = 465;
83const int DEFAULT_IMAP_PORT = 143;
84const int DEFAULT_SIMAP_PORT = 993;
85const int DEFAULT_XMPP_C2S_PORT = 5222;
86const int DEFAULT_NNTP_PORT = 119;
87const int DEFAULT_NNTPS_PORT = 563;
88const int DEFAULT_CLAMD_PORT = 3310;
100 89
101int main(int argc, char **argv) { 90int main(int argc, char **argv) {
102 setlocale(LC_ALL, ""); 91 setlocale(LC_ALL, "");
@@ -105,277 +94,377 @@ int main(int argc, char **argv) {
105 94
106 /* determine program- and service-name quickly */ 95 /* determine program- and service-name quickly */
107 progname = strrchr(argv[0], '/'); 96 progname = strrchr(argv[0], '/');
108 if (progname != NULL) 97 if (progname != NULL) {
109 progname++; 98 progname++;
110 else 99 } else {
111 progname = argv[0]; 100 progname = argv[0];
101 }
102
103 // Initialize config here with values from above,
104 // might be changed by on disk config or cli commands
105 check_tcp_config config = check_tcp_config_init();
112 106
113 size_t prog_name_len = strlen(progname); 107 size_t prog_name_len = strlen(progname);
114 if (prog_name_len > 6 && !memcmp(progname, "check_", 6)) { 108 const size_t prefix_length = strlen("check_");
115 SERVICE = strdup(progname + 6); 109
116 for (size_t i = 0; i < prog_name_len - 6; i++) 110 if (prog_name_len <= prefix_length) {
117 SERVICE[i] = toupper(SERVICE[i]); 111 die(STATE_UNKNOWN, _("Weird progname"));
112 }
113
114 if (!memcmp(progname, "check_", prefix_length)) {
115 config.service = strdup(progname + prefix_length);
116 if (config.service == NULL) {
117 die(STATE_UNKNOWN, _("Allocation failed"));
118 }
119
120 for (size_t i = 0; i < prog_name_len - prefix_length; i++) {
121 config.service[i] = toupper(config.service[i]);
122 }
118 } 123 }
119 124
120 /* set up a reasonable buffer at first (will be realloc()'ed if 125 /* set up a reasonable buffer at first (will be realloc()'ed if
121 * user specifies other options) */ 126 * user specifies other options) */
122 server_expect = calloc(2, sizeof(char *)); 127 config.server_expect = calloc(2, sizeof(char *));
128
129 if (config.server_expect == NULL) {
130 die(STATE_UNKNOWN, _("Allocation failed"));
131 }
123 132
124 /* determine defaults for this service's protocol */ 133 /* determine defaults for this service's protocol */
125 if (!strncmp(SERVICE, "UDP", 3)) { 134 if (!strncmp(config.service, "UDP", strlen("UDP"))) {
126 PROTOCOL = IPPROTO_UDP; 135 config.protocol = IPPROTO_UDP;
127 } else if (!strncmp(SERVICE, "FTP", 3)) { 136 } else if (!strncmp(config.service, "FTP", strlen("FTP"))) {
128 EXPECT = "220"; 137 config.server_expect[0] = "220";
129 QUIT = "QUIT\r\n"; 138 config.quit = "QUIT\r\n";
130 PORT = 21; 139 config.server_port = DEFAULT_FTP_PORT;
131 } else if (!strncmp(SERVICE, "POP", 3) || !strncmp(SERVICE, "POP3", 4)) { 140 } else if (!strncmp(config.service, "POP", strlen("POP")) || !strncmp(config.service, "POP3", strlen("POP3"))) {
132 EXPECT = "+OK"; 141 config.server_expect[0] = "+OK";
133 QUIT = "QUIT\r\n"; 142 config.quit = "QUIT\r\n";
134 PORT = 110; 143 config.server_port = DEFAULT_POP_PORT;
135 } else if (!strncmp(SERVICE, "SMTP", 4)) { 144 } else if (!strncmp(config.service, "SMTP", strlen("SMTP"))) {
136 EXPECT = "220"; 145 config.server_expect[0] = "220";
137 QUIT = "QUIT\r\n"; 146 config.quit = "QUIT\r\n";
138 PORT = 25; 147 config.server_port = DEFAULT_SMTP_PORT;
139 } else if (!strncmp(SERVICE, "IMAP", 4)) { 148 } else if (!strncmp(config.service, "IMAP", strlen("IMAP"))) {
140 EXPECT = "* OK"; 149 config.server_expect[0] = "* OK";
141 QUIT = "a1 LOGOUT\r\n"; 150 config.quit = "a1 LOGOUT\r\n";
142 PORT = 143; 151 config.server_port = DEFAULT_IMAP_PORT;
143 } 152 }
144#ifdef HAVE_SSL 153#ifdef HAVE_SSL
145 else if (!strncmp(SERVICE, "SIMAP", 5)) { 154 else if (!strncmp(config.service, "SIMAP", strlen("SIMAP"))) {
146 EXPECT = "* OK"; 155 config.server_expect[0] = "* OK";
147 QUIT = "a1 LOGOUT\r\n"; 156 config.quit = "a1 LOGOUT\r\n";
148 flags |= FLAG_SSL; 157 config.use_tls = true;
149 PORT = 993; 158 config.server_port = DEFAULT_SIMAP_PORT;
150 } else if (!strncmp(SERVICE, "SPOP", 4)) { 159 } else if (!strncmp(config.service, "SPOP", strlen("SPOP"))) {
151 EXPECT = "+OK"; 160 config.server_expect[0] = "+OK";
152 QUIT = "QUIT\r\n"; 161 config.quit = "QUIT\r\n";
153 flags |= FLAG_SSL; 162 config.use_tls = true;
154 PORT = 995; 163 config.server_port = DEFAULT_SPOP_PORT;
155 } else if (!strncmp(SERVICE, "SSMTP", 5)) { 164 } else if (!strncmp(config.service, "SSMTP", strlen("SSMTP"))) {
156 EXPECT = "220"; 165 config.server_expect[0] = "220";
157 QUIT = "QUIT\r\n"; 166 config.quit = "QUIT\r\n";
158 flags |= FLAG_SSL; 167 config.use_tls = true;
159 PORT = 465; 168 config.server_port = DEFAULT_SSMTP_PORT;
160 } else if (!strncmp(SERVICE, "JABBER", 6)) { 169 } else if (!strncmp(config.service, "JABBER", strlen("JABBER"))) {
161 SEND = "<stream:stream to=\'host\' xmlns=\'jabber:client\' xmlns:stream=\'http://etherx.jabber.org/streams\'>\n"; 170 config.send = "<stream:stream to=\'host\' xmlns=\'jabber:client\' xmlns:stream=\'http://etherx.jabber.org/streams\'>\n";
162 EXPECT = "<?xml version=\'1.0\'"; 171 config.server_expect[0] = "<?xml version=\'1.0\'";
163 QUIT = "</stream:stream>\n"; 172 config.quit = "</stream:stream>\n";
164 flags |= FLAG_HIDE_OUTPUT; 173 config.hide_output = true;
165 PORT = 5222; 174 config.server_port = DEFAULT_XMPP_C2S_PORT;
166 } else if (!strncmp(SERVICE, "NNTPS", 5)) { 175 } else if (!strncmp(config.service, "NNTPS", strlen("NNTPS"))) {
167 server_expect_count = 2; 176 config.server_expect_count = 2;
168 server_expect[0] = "200"; 177 config.server_expect[0] = "200";
169 server_expect[1] = "201"; 178 config.server_expect[1] = "201";
170 QUIT = "QUIT\r\n"; 179 config.quit = "QUIT\r\n";
171 flags |= FLAG_SSL; 180 config.use_tls = true;
172 PORT = 563; 181 config.server_port = DEFAULT_NNTPS_PORT;
173 } 182 }
174#endif 183#endif
175 else if (!strncmp(SERVICE, "NNTP", 4)) { 184 else if (!strncmp(config.service, "NNTP", strlen("NNTP"))) {
176 server_expect_count = 2; 185 config.server_expect_count = 2;
177 server_expect = malloc(sizeof(char *) * server_expect_count); 186 char **tmp = realloc(config.server_expect, config.server_expect_count * sizeof(char *));
178 server_expect[0] = strdup("200"); 187 if (tmp == NULL) {
179 server_expect[1] = strdup("201"); 188 free(config.server_expect);
180 QUIT = "QUIT\r\n"; 189 die(STATE_UNKNOWN, _("Allocation failed"));
181 PORT = 119; 190 }
182 } else if (!strncmp(SERVICE, "CLAMD", 5)) { 191 config.server_expect = tmp;
183 SEND = "PING"; 192
184 EXPECT = "PONG"; 193 config.server_expect[0] = strdup("200");
185 QUIT = NULL; 194 config.server_expect[1] = strdup("201");
186 PORT = 3310; 195 config.quit = "QUIT\r\n";
196 config.server_port = DEFAULT_NNTP_PORT;
197 } else if (!strncmp(config.service, "CLAMD", strlen("CLAMD"))) {
198 config.send = "PING";
199 config.server_expect[0] = "PONG";
200 config.quit = NULL;
201 config.server_port = DEFAULT_CLAMD_PORT;
187 } 202 }
188 /* fallthrough check, so it's supposed to use reverse matching */ 203 /* fallthrough check, so it's supposed to use reverse matching */
189 else if (strcmp(SERVICE, "TCP")) 204 else if (strcmp(config.service, "TCP")) {
190 usage(_("CRITICAL - Generic check_tcp called with unknown service\n")); 205 usage(_("CRITICAL - Generic check_tcp called with unknown service\n"));
191 206 }
192 server_address = "127.0.0.1";
193 server_port = PORT;
194 server_send = SEND;
195 server_quit = QUIT;
196 char *status = NULL;
197 207
198 /* Parse extra opts if any */ 208 /* Parse extra opts if any */
199 argv = np_extra_opts(&argc, argv, progname); 209 argv = np_extra_opts(&argc, argv, progname);
200 210
201 if (process_arguments(argc, argv) == ERROR) 211 check_tcp_config_wrapper paw = process_arguments(argc, argv, config);
212 if (paw.errorcode == ERROR) {
202 usage4(_("Could not parse arguments")); 213 usage4(_("Could not parse arguments"));
214 }
203 215
204 if (flags & FLAG_VERBOSE) { 216 config = paw.config;
205 printf("Using service %s\n", SERVICE); 217
206 printf("Port: %d\n", server_port); 218 if (verbosity > 0) {
207 printf("flags: 0x%x\n", (int)flags); 219 printf("Using service %s\n", config.service);
220 printf("Port: %d\n", config.server_port);
208 } 221 }
209 222
210 if (EXPECT && !server_expect_count) 223 if ((config.server_expect_count == 0) && config.server_expect[0]) {
211 server_expect_count++; 224 config.server_expect_count++;
225 }
212 226
213 if (PROTOCOL == IPPROTO_UDP && !(server_expect_count && server_send)) { 227 if (config.protocol == IPPROTO_UDP && !(config.server_expect_count && config.send)) {
214 usage(_("With UDP checks, a send/expect string must be specified.")); 228 usage(_("With UDP checks, a send/expect string must be specified."));
215 } 229 }
216 230
231 // Initialize check stuff before setting timers
232 mp_check overall = mp_check_init();
233 if (config.output_format_set) {
234 mp_set_format(config.output_format);
235 }
236
217 /* set up the timer */ 237 /* set up the timer */
218 signal(SIGALRM, socket_timeout_alarm_handler); 238 signal(SIGALRM, socket_timeout_alarm_handler);
219 alarm(socket_timeout); 239 alarm(socket_timeout);
220 240
221 /* try to connect to the host at the given port number */ 241 /* try to connect to the host at the given port number */
222 struct timeval tv; 242 struct timeval start_time;
223 gettimeofday(&tv, NULL); 243 gettimeofday(&start_time, NULL);
224 244
225 int result = STATE_UNKNOWN; 245 int socket_descriptor = 0;
226 result = np_net_connect(server_address, server_port, &sd, PROTOCOL); 246 mp_subcheck inital_connect_result = mp_subcheck_init();
227 if (result == STATE_CRITICAL) 247
228 return econn_refuse_state; 248 // Try initial connection
249 if (np_net_connect(config.server_address, config.server_port, &socket_descriptor, config.protocol) == STATE_CRITICAL) {
250 // Early exit here, we got connection refused
251 inital_connect_result = mp_set_subcheck_state(inital_connect_result, config.econn_refuse_state);
252 xasprintf(&inital_connect_result.output, "Connection to %s on port %i was REFUSED", config.server_address, config.server_port);
253 mp_add_subcheck_to_check(&overall, inital_connect_result);
254 mp_exit(overall);
255 } else {
256 inital_connect_result = mp_set_subcheck_state(inital_connect_result, STATE_OK);
257 xasprintf(&inital_connect_result.output, "Connection to %s on port %i was a SUCCESS", config.server_address, config.server_port);
258 mp_add_subcheck_to_check(&overall, inital_connect_result);
259 }
229 260
230#ifdef HAVE_SSL 261#ifdef HAVE_SSL
231 if (flags & FLAG_SSL) { 262 if (config.use_tls) {
232 result = np_net_ssl_init_with_hostname(sd, (sni_specified ? sni : NULL)); 263 mp_subcheck tls_connection_result = mp_subcheck_init();
233 if (result == STATE_OK && check_cert) { 264 mp_state_enum result = np_net_ssl_init_with_hostname(socket_descriptor, (config.sni_specified ? config.sni : NULL));
234 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit); 265 tls_connection_result = mp_set_subcheck_default_state(tls_connection_result, result);
266
267 if (result == STATE_OK) {
268 xasprintf(&tls_connection_result.output, "TLS connection succeeded");
269
270 if (config.check_cert) {
271 result = np_net_ssl_check_cert(config.days_till_exp_warn, config.days_till_exp_crit);
272
273 mp_subcheck tls_certificate_lifetime_result = mp_subcheck_init();
274 tls_certificate_lifetime_result = mp_set_subcheck_state(tls_certificate_lifetime_result, result);
275
276 if (result == STATE_OK) {
277 xasprintf(&tls_certificate_lifetime_result.output, "Certificate lifetime is within thresholds");
278 } else if (result == STATE_WARNING) {
279 xasprintf(&tls_certificate_lifetime_result.output, "Certificate lifetime is violating warning threshold (%i)",
280 config.days_till_exp_warn);
281 } else if (result == STATE_CRITICAL) {
282 xasprintf(&tls_certificate_lifetime_result.output, "Certificate lifetime is violating critical threshold (%i)",
283 config.days_till_exp_crit);
284 } else {
285 xasprintf(&tls_certificate_lifetime_result.output, "Certificate lifetime is somehow unknown");
286 }
287
288 mp_add_subcheck_to_subcheck(&tls_connection_result, tls_certificate_lifetime_result);
289 }
290
291 mp_add_subcheck_to_check(&overall, tls_connection_result);
292 } else {
293 xasprintf(&tls_connection_result.output, "TLS connection failed");
294 mp_add_subcheck_to_check(&overall, tls_connection_result);
295
296 if (socket_descriptor) {
297 close(socket_descriptor);
298 }
299 np_net_ssl_cleanup();
300
301 mp_exit(overall);
235 } 302 }
236 } 303 }
237 if (result != STATE_OK) {
238 if (sd)
239 close(sd);
240 np_net_ssl_cleanup();
241 return result;
242 }
243#endif /* HAVE_SSL */ 304#endif /* HAVE_SSL */
244 305
245 if (server_send != NULL) { /* Something to send? */ 306 if (config.send != NULL) { /* Something to send? */
246 my_send(server_send, strlen(server_send)); 307 my_send(socket_descriptor, config.send, strlen(config.send), config.use_tls);
247 } 308 }
248 309
249 if (delay > 0) { 310 if (config.delay > 0) {
250 tv.tv_sec += delay; 311 start_time.tv_sec += config.delay;
251 sleep(delay); 312 sleep(config.delay);
252 } 313 }
253 314
254 if (flags & FLAG_VERBOSE) { 315 if (verbosity > 0) {
255 if (server_send) { 316 if (config.send) {
256 printf("Send string: %s\n", server_send); 317 printf("Send string: %s\n", config.send);
318 }
319 if (config.quit) {
320 printf("Quit string: %s\n", config.quit);
257 } 321 }
258 if (server_quit) { 322 printf("server_expect_count: %d\n", (int)config.server_expect_count);
259 printf("Quit string: %s\n", server_quit); 323 for (size_t i = 0; i < config.server_expect_count; i++) {
324 printf("\t%zd: %s\n", i, config.server_expect[i]);
260 } 325 }
261 printf("server_expect_count: %d\n", (int)server_expect_count);
262 for (size_t i = 0; i < server_expect_count; i++)
263 printf("\t%zd: %s\n", i, server_expect[i]);
264 } 326 }
265 327
266 /* if(len) later on, we know we have a non-NULL response */ 328 /* if(len) later on, we know we have a non-NULL response */
267 ssize_t len = 0; 329 ssize_t len = 0;
330 char *received_buffer = NULL;
331 enum np_match_result match = NP_MATCH_NONE;
332 mp_subcheck expected_data_result = mp_subcheck_init();
268 333
269 int match = -1; 334 if (config.server_expect_count) {
270 struct timeval timeout;
271 fd_set rfds;
272 FD_ZERO(&rfds);
273 if (server_expect_count) {
274 ssize_t received = 0; 335 ssize_t received = 0;
336 char buffer[MAXBUF];
275 337
276 /* watch for the expect string */ 338 /* watch for the expect string */
277 while ((received = my_recv(buffer, sizeof(buffer))) > 0) { 339 while ((received = my_recv(socket_descriptor, buffer, sizeof(buffer), config.use_tls)) > 0) {
278 status = realloc(status, len + received + 1); 340 received_buffer = realloc(received_buffer, len + received + 1);
279 memcpy(&status[len], buffer, received); 341
342 if (received_buffer == NULL) {
343 die(STATE_UNKNOWN, _("Allocation failed"));
344 }
345
346 memcpy(&received_buffer[len], buffer, received);
280 len += received; 347 len += received;
281 status[len] = '\0'; 348 received_buffer[len] = '\0';
282 349
283 /* stop reading if user-forced */ 350 /* stop reading if user-forced */
284 if (maxbytes && len >= maxbytes) 351 if (config.maxbytes && len >= config.maxbytes) {
285 break; 352 break;
353 }
286 354
287 if ((match = np_expect_match(status, server_expect, server_expect_count, match_flags)) != NP_MATCH_RETRY) 355 if ((match = np_expect_match(received_buffer, config.server_expect, config.server_expect_count, config.match_flags)) !=
356 NP_MATCH_RETRY) {
288 break; 357 break;
358 }
359
360 fd_set rfds;
361 FD_ZERO(&rfds);
362 FD_SET(socket_descriptor, &rfds);
289 363
290 /* some protocols wait for further input, so make sure we don't wait forever */ 364 /* some protocols wait for further input, so make sure we don't wait forever */
291 FD_SET(sd, &rfds); 365 struct timeval timeout;
292 timeout.tv_sec = READ_TIMEOUT; 366 timeout.tv_sec = READ_TIMEOUT;
293 timeout.tv_usec = 0; 367 timeout.tv_usec = 0;
294 if (select(sd + 1, &rfds, NULL, NULL, &timeout) <= 0) 368
369 if (select(socket_descriptor + 1, &rfds, NULL, NULL, &timeout) <= 0) {
295 break; 370 break;
371 }
296 } 372 }
297 373
298 if (match == NP_MATCH_RETRY) 374 if (match == NP_MATCH_RETRY) {
299 match = NP_MATCH_FAILURE; 375 match = NP_MATCH_FAILURE;
376 }
300 377
301 /* no data when expected, so return critical */ 378 /* no data when expected, so return critical */
302 if (len == 0) 379 if (len == 0) {
303 die(STATE_CRITICAL, _("No data received from host\n")); 380 xasprintf(&expected_data_result.output, "Received no data when some was expected");
381 expected_data_result = mp_set_subcheck_state(expected_data_result, STATE_CRITICAL);
382 mp_add_subcheck_to_check(&overall, expected_data_result);
383 mp_exit(overall);
384 }
304 385
305 /* print raw output if we're debugging */ 386 /* print raw output if we're debugging */
306 if (flags & FLAG_VERBOSE) 387 if (verbosity > 0) {
307 printf("received %d bytes from host\n#-raw-recv-------#\n%s\n#-raw-recv-------#\n", (int)len + 1, status); 388 printf("received %d bytes from host\n#-raw-recv-------#\n%s\n#-raw-recv-------#\n", (int)len + 1, received_buffer);
389 }
308 /* strip whitespace from end of output */ 390 /* strip whitespace from end of output */
309 while (--len > 0 && isspace(status[len])) 391 while (--len > 0 && isspace(received_buffer[len])) {
310 status[len] = '\0'; 392 received_buffer[len] = '\0';
393 }
311 } 394 }
312 395
313 if (server_quit != NULL) { 396 if (config.quit != NULL) {
314 my_send(server_quit, strlen(server_quit)); 397 my_send(socket_descriptor, config.quit, strlen(config.quit), config.use_tls);
398 }
399
400 if (socket_descriptor) {
401 close(socket_descriptor);
315 } 402 }
316 if (sd)
317 close(sd);
318#ifdef HAVE_SSL 403#ifdef HAVE_SSL
319 np_net_ssl_cleanup(); 404 np_net_ssl_cleanup();
320#endif 405#endif
321 406
322 microsec = deltime(tv); 407 long microsec = deltime(start_time);
323 elapsed_time = (double)microsec / 1.0e6; 408 double elapsed_time = (double)microsec / 1.0e6;
324 409
325 if (flags & FLAG_TIME_CRIT && elapsed_time > critical_time) 410 mp_subcheck elapsed_time_result = mp_subcheck_init();
326 result = STATE_CRITICAL;
327 else if (flags & FLAG_TIME_WARN && elapsed_time > warning_time)
328 result = STATE_WARNING;
329 411
330 /* did we get the response we hoped? */ 412 mp_perfdata time_pd = perfdata_init();
331 if (match == NP_MATCH_FAILURE && result != STATE_CRITICAL) 413 time_pd = mp_set_pd_value(time_pd, elapsed_time);
332 result = expect_mismatch_state; 414 time_pd.label = "time";
415 time_pd.uom = "s";
333 416
334 /* reset the alarm */ 417 if (config.critical_time_set && elapsed_time > config.critical_time) {
335 alarm(0); 418 xasprintf(&elapsed_time_result.output, "Connection time %fs exceeded critical threshold (%f)", elapsed_time, config.critical_time);
419
420 elapsed_time_result = mp_set_subcheck_state(elapsed_time_result, STATE_CRITICAL);
421 time_pd.crit_present = true;
422 mp_range crit_val = mp_range_init();
423
424 crit_val.end = mp_create_pd_value(config.critical_time);
425 crit_val.end_infinity = false;
336 426
337 /* this is a bit stupid, because we don't want to print the 427 time_pd.crit = crit_val;
338 * response time (which can look ok to the user) if we didn't get 428 } else if (config.warning_time_set && elapsed_time > config.warning_time) {
339 * the response we were looking for. if-else */ 429 xasprintf(&elapsed_time_result.output, "Connection time %fs exceeded warning threshold (%f)", elapsed_time, config.critical_time);
340 printf("%s %s - ", SERVICE, state_text(result)); 430
341 431 elapsed_time_result = mp_set_subcheck_state(elapsed_time_result, STATE_WARNING);
342 if (match == NP_MATCH_FAILURE && len && !(flags & FLAG_HIDE_OUTPUT)) 432 time_pd.warn_present = true;
343 printf("Unexpected response from host/socket: %s", status); 433 mp_range warn_val = mp_range_init();
344 else { 434 warn_val.end = mp_create_pd_value(config.critical_time);
345 if (match == NP_MATCH_FAILURE) 435 warn_val.end_infinity = false;
346 printf("Unexpected response from host/socket on "); 436
347 else 437 time_pd.warn = warn_val;
348 printf("%.3f second response time on ", elapsed_time); 438 } else {
349 if (server_address[0] != '/') { 439 elapsed_time_result = mp_set_subcheck_state(elapsed_time_result, STATE_OK);
350 if (host_specified) 440 xasprintf(&elapsed_time_result.output, "Connection time %fs is within thresholds", elapsed_time);
351 printf("%s port %d", server_address, server_port);
352 else
353 printf("port %d", server_port);
354 } else
355 printf("socket %s", server_address);
356 } 441 }
357 442
358 if (match != NP_MATCH_FAILURE && !(flags & FLAG_HIDE_OUTPUT) && len) 443 mp_add_perfdata_to_subcheck(&elapsed_time_result, time_pd);
359 printf(" [%s]", status); 444 mp_add_subcheck_to_check(&overall, elapsed_time_result);
360 445
361 /* perf-data doesn't apply when server doesn't talk properly, 446 /* did we get the response we hoped? */
362 * so print all zeroes on warn and crit. Use fperfdata since 447 if (match == NP_MATCH_FAILURE) {
363 * localisation settings can make different outputs */ 448 expected_data_result = mp_set_subcheck_state(expected_data_result, config.expect_mismatch_state);
364 if (match == NP_MATCH_FAILURE) 449 xasprintf(&expected_data_result.output, "Answer failed to match expectation");
365 printf("|%s", fperfdata("time", elapsed_time, "s", (flags & FLAG_TIME_WARN ? true : false), 0, 450 mp_add_subcheck_to_check(&overall, expected_data_result);
366 (flags & FLAG_TIME_CRIT ? true : false), 0, true, 0, true, socket_timeout)); 451 } else if (match == NP_MATCH_SUCCESS) {
367 else 452 expected_data_result = mp_set_subcheck_state(expected_data_result, STATE_OK);
368 printf("|%s", fperfdata("time", elapsed_time, "s", (flags & FLAG_TIME_WARN ? true : false), warning_time, 453 xasprintf(&expected_data_result.output, "The answer of the server matched the expectation");
369 (flags & FLAG_TIME_CRIT ? true : false), critical_time, true, 0, true, socket_timeout)); 454 mp_add_subcheck_to_check(&overall, expected_data_result);
455 }
370 456
371 putchar('\n'); 457 /* reset the alarm */
372 return result; 458 alarm(0);
459
460 mp_exit(overall);
373} 461}
374 462
375/* process command-line arguments */ 463/* process command-line arguments */
376static int process_arguments(int argc, char **argv) { 464static check_tcp_config_wrapper process_arguments(int argc, char **argv, check_tcp_config config) {
377 enum { 465 enum {
378 SNI_OPTION = CHAR_MAX + 1 466 SNI_OPTION = CHAR_MAX + 1,
467 output_format_index,
379 }; 468 };
380 469
381 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, 470 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
@@ -404,54 +493,58 @@ static int process_arguments(int argc, char **argv) {
404 {"ssl", no_argument, 0, 'S'}, 493 {"ssl", no_argument, 0, 'S'},
405 {"sni", required_argument, 0, SNI_OPTION}, 494 {"sni", required_argument, 0, SNI_OPTION},
406 {"certificate", required_argument, 0, 'D'}, 495 {"certificate", required_argument, 0, 'D'},
496 {"output-format", required_argument, 0, output_format_index},
407 {0, 0, 0, 0}}; 497 {0, 0, 0, 0}};
408 498
409 if (argc < 2) 499 if (argc < 2) {
410 usage4(_("No arguments found")); 500 usage4(_("No arguments found"));
501 }
411 502
412 /* backwards compatibility */ 503 /* backwards compatibility */
413 for (int i = 1; i < argc; i++) { 504 for (int i = 1; i < argc; i++) {
414 if (strcmp("-to", argv[i]) == 0) 505 if (strcmp("-to", argv[i]) == 0) {
415 strcpy(argv[i], "-t"); 506 strcpy(argv[i], "-t");
416 else if (strcmp("-wt", argv[i]) == 0) 507 } else if (strcmp("-wt", argv[i]) == 0) {
417 strcpy(argv[i], "-w"); 508 strcpy(argv[i], "-w");
418 else if (strcmp("-ct", argv[i]) == 0) 509 } else if (strcmp("-ct", argv[i]) == 0) {
419 strcpy(argv[i], "-c"); 510 strcpy(argv[i], "-c");
511 }
420 } 512 }
421 513
422 if (!is_option(argv[1])) { 514 if (!is_option(argv[1])) {
423 server_address = argv[1]; 515 config.server_address = argv[1];
424 argv[1] = argv[0]; 516 argv[1] = argv[0];
425 argv = &argv[1]; 517 argv = &argv[1];
426 argc--; 518 argc--;
427 } 519 }
428 520
429 int option_char;
430 bool escape = false; 521 bool escape = false;
522
431 while (true) { 523 while (true) {
432 int option = 0; 524 int option = 0;
433 option_char = getopt_long(argc, argv, "+hVv46EAH:s:e:q:m:c:w:t:p:C:W:d:Sr:jD:M:", longopts, &option); 525 int option_index = getopt_long(argc, argv, "+hVv46EAH:s:e:q:m:c:w:t:p:C:W:d:Sr:jD:M:", longopts, &option);
434 526
435 if (option_char == -1 || option_char == EOF || option_char == 1) 527 if (option_index == -1 || option_index == EOF || option_index == 1) {
436 break; 528 break;
529 }
437 530
438 switch (option_char) { 531 switch (option_index) {
439 case '?': /* print short usage statement if args not parsable */ 532 case '?': /* print short usage statement if args not parsable */
440 usage5(); 533 usage5();
441 case 'h': /* help */ 534 case 'h': /* help */
442 print_help(); 535 print_help(config.service);
443 exit(STATE_UNKNOWN); 536 exit(STATE_UNKNOWN);
444 case 'V': /* version */ 537 case 'V': /* version */
445 print_revision(progname, NP_VERSION); 538 print_revision(progname, NP_VERSION);
446 exit(STATE_UNKNOWN); 539 exit(STATE_UNKNOWN);
447 case 'v': /* verbose mode */ 540 case 'v': /* verbose mode */
448 flags |= FLAG_VERBOSE; 541 verbosity++;
449 match_flags |= NP_MATCH_VERBOSE; 542 config.match_flags |= NP_MATCH_VERBOSE;
450 break; 543 break;
451 case '4': 544 case '4': // Apparently unused TODO
452 address_family = AF_INET; 545 address_family = AF_INET;
453 break; 546 break;
454 case '6': 547 case '6': // Apparently unused TODO
455#ifdef USE_IPV6 548#ifdef USE_IPV6
456 address_family = AF_INET6; 549 address_family = AF_INET6;
457#else 550#else
@@ -459,163 +552,190 @@ static int process_arguments(int argc, char **argv) {
459#endif 552#endif
460 break; 553 break;
461 case 'H': /* hostname */ 554 case 'H': /* hostname */
462 host_specified = true; 555 config.host_specified = true;
463 server_address = optarg; 556 config.server_address = optarg;
464 break; 557 break;
465 case 'c': /* critical */ 558 case 'c': /* critical */
466 critical_time = strtod(optarg, NULL); 559 config.critical_time = strtod(optarg, NULL);
467 flags |= FLAG_TIME_CRIT; 560 config.critical_time_set = true;
468 break; 561 break;
469 case 'j': /* hide output */ 562 case 'j': /* hide output */
470 flags |= FLAG_HIDE_OUTPUT; 563 config.hide_output = true;
471 break; 564 break;
472 case 'w': /* warning */ 565 case 'w': /* warning */
473 warning_time = strtod(optarg, NULL); 566 config.warning_time = strtod(optarg, NULL);
474 flags |= FLAG_TIME_WARN; 567 config.warning_time_set = true;
475 break;
476 case 'C':
477 crit_codes = realloc(crit_codes, ++crit_codes_count);
478 crit_codes[crit_codes_count - 1] = optarg;
479 break;
480 case 'W':
481 warn_codes = realloc(warn_codes, ++warn_codes_count);
482 warn_codes[warn_codes_count - 1] = optarg;
483 break; 568 break;
484 case 't': /* timeout */ 569 case 't': /* timeout */
485 if (!is_intpos(optarg)) 570 if (!is_intpos(optarg)) {
486 usage4(_("Timeout interval must be a positive integer")); 571 usage4(_("Timeout interval must be a positive integer"));
487 else 572 } else {
488 socket_timeout = atoi(optarg); 573 socket_timeout = atoi(optarg);
574 }
489 break; 575 break;
490 case 'p': /* port */ 576 case 'p': /* port */
491 if (!is_intpos(optarg)) 577 if (!is_intpos(optarg)) {
492 usage4(_("Port must be a positive integer")); 578 usage4(_("Port must be a positive integer"));
493 else 579 } else {
494 server_port = atoi(optarg); 580 config.server_port = atoi(optarg);
581 }
495 break; 582 break;
496 case 'E': 583 case 'E':
497 escape = true; 584 escape = true;
498 break; 585 break;
499 case 's': 586 case 's':
500 if (escape) 587 if (escape) {
501 server_send = np_escaped_string(optarg); 588 config.send = np_escaped_string(optarg);
502 else 589 } else {
503 xasprintf(&server_send, "%s", optarg); 590 xasprintf(&config.send, "%s", optarg);
591 }
504 break; 592 break;
505 case 'e': /* expect string (may be repeated) */ 593 case 'e': /* expect string (may be repeated) */
506 match_flags &= ~NP_MATCH_EXACT; 594 config.match_flags &= ~NP_MATCH_EXACT;
507 if (server_expect_count == 0) 595 if (config.server_expect_count == 0) {
508 server_expect = malloc(sizeof(char *) * (++server_expect_count)); 596 config.server_expect = malloc(sizeof(char *) * (++config.server_expect_count));
509 else 597 } else {
510 server_expect = realloc(server_expect, sizeof(char *) * (++server_expect_count)); 598 config.server_expect = realloc(config.server_expect, sizeof(char *) * (++config.server_expect_count));
511 server_expect[server_expect_count - 1] = optarg; 599 }
600
601 if (config.server_expect == NULL) {
602 die(STATE_UNKNOWN, _("Allocation failed"));
603 }
604 config.server_expect[config.server_expect_count - 1] = optarg;
512 break; 605 break;
513 case 'm': 606 case 'm':
514 if (!is_intpos(optarg)) 607 if (!is_intpos(optarg)) {
515 usage4(_("Maxbytes must be a positive integer")); 608 usage4(_("Maxbytes must be a positive integer"));
516 else 609 } else {
517 maxbytes = strtol(optarg, NULL, 0); 610 config.maxbytes = strtol(optarg, NULL, 0);
611 }
518 break; 612 break;
519 case 'q': 613 case 'q':
520 if (escape) 614 if (escape) {
521 server_quit = np_escaped_string(optarg); 615 config.quit = np_escaped_string(optarg);
522 else 616 } else {
523 xasprintf(&server_quit, "%s\r\n", optarg); 617 xasprintf(&config.quit, "%s\r\n", optarg);
618 }
524 break; 619 break;
525 case 'r': 620 case 'r':
526 if (!strncmp(optarg, "ok", 2)) 621 if (!strncmp(optarg, "ok", 2)) {
527 econn_refuse_state = STATE_OK; 622 config.econn_refuse_state = STATE_OK;
528 else if (!strncmp(optarg, "warn", 4)) 623 } else if (!strncmp(optarg, "warn", 4)) {
529 econn_refuse_state = STATE_WARNING; 624 config.econn_refuse_state = STATE_WARNING;
530 else if (!strncmp(optarg, "crit", 4)) 625 } else if (!strncmp(optarg, "crit", 4)) {
531 econn_refuse_state = STATE_CRITICAL; 626 config.econn_refuse_state = STATE_CRITICAL;
532 else 627 } else {
533 usage4(_("Refuse must be one of ok, warn, crit")); 628 usage4(_("Refuse must be one of ok, warn, crit"));
629 }
534 break; 630 break;
535 case 'M': 631 case 'M':
536 if (!strncmp(optarg, "ok", 2)) 632 if (!strncmp(optarg, "ok", 2)) {
537 expect_mismatch_state = STATE_OK; 633 config.expect_mismatch_state = STATE_OK;
538 else if (!strncmp(optarg, "warn", 4)) 634 } else if (!strncmp(optarg, "warn", 4)) {
539 expect_mismatch_state = STATE_WARNING; 635 config.expect_mismatch_state = STATE_WARNING;
540 else if (!strncmp(optarg, "crit", 4)) 636 } else if (!strncmp(optarg, "crit", 4)) {
541 expect_mismatch_state = STATE_CRITICAL; 637 config.expect_mismatch_state = STATE_CRITICAL;
542 else 638 } else {
543 usage4(_("Mismatch must be one of ok, warn, crit")); 639 usage4(_("Mismatch must be one of ok, warn, crit"));
640 }
544 break; 641 break;
545 case 'd': 642 case 'd':
546 if (is_intpos(optarg)) 643 if (is_intpos(optarg)) {
547 delay = atoi(optarg); 644 config.delay = atoi(optarg);
548 else 645 } else {
549 usage4(_("Delay must be a positive integer")); 646 usage4(_("Delay must be a positive integer"));
647 }
550 break; 648 break;
551 case 'D': { /* Check SSL cert validity - days 'til certificate expiration */ 649 case 'D': /* Check SSL cert validity - days 'til certificate expiration */
552#ifdef HAVE_SSL 650#ifdef HAVE_SSL
553# ifdef USE_OPENSSL /* XXX */ 651# ifdef USE_OPENSSL /* XXX */
652 {
554 char *temp; 653 char *temp;
555 if ((temp = strchr(optarg, ',')) != NULL) { 654 if ((temp = strchr(optarg, ',')) != NULL) {
556 *temp = '\0'; 655 *temp = '\0';
557 if (!is_intnonneg(optarg)) 656 if (!is_intnonneg(optarg)) {
558 usage2(_("Invalid certificate expiration period"), optarg); 657 usage2(_("Invalid certificate expiration period"), optarg);
559 days_till_exp_warn = atoi(optarg); 658 }
659 config.days_till_exp_warn = atoi(optarg);
560 *temp = ','; 660 *temp = ',';
561 temp++; 661 temp++;
562 if (!is_intnonneg(temp)) 662 if (!is_intnonneg(temp)) {
563 usage2(_("Invalid certificate expiration period"), temp); 663 usage2(_("Invalid certificate expiration period"), temp);
564 days_till_exp_crit = atoi(temp); 664 }
665 config.days_till_exp_crit = atoi(temp);
565 } else { 666 } else {
566 days_till_exp_crit = 0; 667 config.days_till_exp_crit = 0;
567 if (!is_intnonneg(optarg)) 668 if (!is_intnonneg(optarg)) {
568 usage2(_("Invalid certificate expiration period"), optarg); 669 usage2(_("Invalid certificate expiration period"), optarg);
569 days_till_exp_warn = atoi(optarg); 670 }
671 config.days_till_exp_warn = atoi(optarg);
570 } 672 }
571 check_cert = true; 673 config.check_cert = true;
572 flags |= FLAG_SSL; 674 config.use_tls = true;
573 } break; 675 } break;
574# endif /* USE_OPENSSL */ 676# endif /* USE_OPENSSL */
575#endif 677#endif
576 /* fallthrough if we don't have ssl */ 678 /* fallthrough if we don't have ssl */
577 case 'S': 679 case 'S':
578#ifdef HAVE_SSL 680#ifdef HAVE_SSL
579 flags |= FLAG_SSL; 681 config.use_tls = true;
580#else 682#else
581 die(STATE_UNKNOWN, _("Invalid option - SSL is not available")); 683 die(STATE_UNKNOWN, _("Invalid option - SSL is not available"));
582#endif 684#endif
583 break; 685 break;
584 case SNI_OPTION: 686 case SNI_OPTION:
585#ifdef HAVE_SSL 687#ifdef HAVE_SSL
586 flags |= FLAG_SSL; 688 config.use_tls = true;
587 sni_specified = true; 689 config.sni_specified = true;
588 sni = optarg; 690 config.sni = optarg;
589#else 691#else
590 die(STATE_UNKNOWN, _("Invalid option - SSL is not available")); 692 die(STATE_UNKNOWN, _("Invalid option - SSL is not available"));
591#endif 693#endif
592 break; 694 break;
593 case 'A': 695 case 'A':
594 match_flags |= NP_MATCH_ALL; 696 config.match_flags |= NP_MATCH_ALL;
697 break;
698 case output_format_index: {
699 parsed_output_format parser = mp_parse_output_format(optarg);
700 if (!parser.parsing_success) {
701 // TODO List all available formats here, maybe add anothoer usage function
702 printf("Invalid output format: %s\n", optarg);
703 exit(STATE_UNKNOWN);
704 }
705
706 config.output_format_set = true;
707 config.output_format = parser.output_format;
595 break; 708 break;
596 } 709 }
710 }
597 } 711 }
598 712
599 option_char = optind; 713 int index = optind;
600 if (!host_specified && option_char < argc) 714 if (!config.host_specified && index < argc) {
601 server_address = strdup(argv[option_char++]); 715 config.server_address = strdup(argv[index++]);
716 }
602 717
603 if (server_address == NULL) 718 if (config.server_address == NULL) {
604 usage4(_("You must provide a server address")); 719 usage4(_("You must provide a server address"));
605 else if (server_address[0] != '/' && !is_host(server_address)) 720 } else if (config.server_address[0] != '/' && !is_host(config.server_address)) {
606 die(STATE_CRITICAL, "%s %s - %s: %s\n", SERVICE, state_text(STATE_CRITICAL), _("Invalid hostname, address or socket"), 721 die(STATE_CRITICAL, "%s %s - %s: %s\n", config.service, state_text(STATE_CRITICAL), _("Invalid hostname, address or socket"),
607 server_address); 722 config.server_address);
723 }
608 724
609 return OK; 725 check_tcp_config_wrapper result = {
726 .config = config,
727 .errorcode = OK,
728 };
729 return result;
610} 730}
611 731
612void print_help(void) { 732void print_help(const char *service) {
613 print_revision(progname, NP_VERSION); 733 print_revision(progname, NP_VERSION);
614 734
615 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 735 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
616 printf(COPYRIGHT, copyright, email); 736 printf(COPYRIGHT, copyright, email);
617 737
618 printf(_("This plugin tests %s connections with the specified host (or unix socket).\n\n"), SERVICE); 738 printf(_("This plugin tests %s connections with the specified host (or unix socket).\n\n"), service);
619 739
620 print_usage(); 740 print_usage();
621 741
@@ -662,6 +782,7 @@ void print_help(void) {
662 782
663 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 783 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
664 784
785 printf(UT_OUTPUT_FORMAT);
665 printf(UT_VERBOSE); 786 printf(UT_VERBOSE);
666 787
667 printf(UT_SUPPORT); 788 printf(UT_SUPPORT);
diff --git a/plugins/check_tcp.d/config.h b/plugins/check_tcp.d/config.h
new file mode 100644
index 00000000..dc25d79e
--- /dev/null
+++ b/plugins/check_tcp.d/config.h
@@ -0,0 +1,84 @@
1#pragma once
2
3#include "../../lib/utils_tcp.h"
4#include "output.h"
5#include "states.h"
6#include <netinet/in.h>
7
8typedef struct {
9 char *server_address;
10 bool host_specified;
11 int server_port; // TODO can this be a uint16?
12
13 int protocol; /* most common is default */
14 char *service;
15 char *send;
16 char *quit;
17 char **server_expect;
18 size_t server_expect_count;
19 bool use_tls;
20#ifdef HAVE_SSL
21 char *sni;
22 bool sni_specified;
23 bool check_cert;
24 int days_till_exp_warn;
25 int days_till_exp_crit;
26#endif // HAVE_SSL
27 int match_flags;
28 mp_state_enum expect_mismatch_state;
29 unsigned int delay;
30
31 bool warning_time_set;
32 double warning_time;
33 bool critical_time_set;
34 double critical_time;
35
36 mp_state_enum econn_refuse_state;
37
38 ssize_t maxbytes;
39
40 bool hide_output;
41
42 bool output_format_set;
43 mp_output_format output_format;
44} check_tcp_config;
45
46check_tcp_config check_tcp_config_init() {
47 check_tcp_config result = {
48 .server_address = "127.0.0.1",
49 .host_specified = false,
50 .server_port = 0,
51
52 .protocol = IPPROTO_TCP,
53 .service = "TCP",
54 .send = NULL,
55 .quit = NULL,
56 .server_expect = NULL,
57 .server_expect_count = 0,
58 .use_tls = false,
59#ifdef HAVE_SSL
60 .sni = NULL,
61 .sni_specified = false,
62 .check_cert = false,
63 .days_till_exp_warn = 0,
64 .days_till_exp_crit = 0,
65#endif // HAVE_SSL
66 .match_flags = NP_MATCH_EXACT,
67 .expect_mismatch_state = STATE_WARNING,
68 .delay = 0,
69
70 .warning_time_set = false,
71 .warning_time = 0,
72 .critical_time_set = false,
73 .critical_time = 0,
74
75 .econn_refuse_state = STATE_CRITICAL,
76
77 .maxbytes = 0,
78
79 .hide_output = false,
80
81 .output_format_set = false,
82 };
83 return result;
84}
diff --git a/plugins/check_time.c b/plugins/check_time.c
index d1f50683..debf59f3 100644
--- a/plugins/check_time.c
+++ b/plugins/check_time.c
@@ -28,6 +28,7 @@
28 * 28 *
29 *****************************************************************************/ 29 *****************************************************************************/
30 30
31#include "states.h"
31const char *progname = "check_time"; 32const char *progname = "check_time";
32const char *copyright = "1999-2024"; 33const char *copyright = "1999-2024";
33const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
@@ -35,28 +36,15 @@ const char *email = "devel@monitoring-plugins.org";
35#include "common.h" 36#include "common.h"
36#include "netutils.h" 37#include "netutils.h"
37#include "utils.h" 38#include "utils.h"
38 39#include "check_time.d/config.h"
39enum {
40 TIME_PORT = 37
41};
42 40
43#define UNIX_EPOCH 2208988800UL 41#define UNIX_EPOCH 2208988800UL
44 42
45static uint32_t raw_server_time; 43typedef struct {
46static unsigned long server_time, diff_time; 44 int errorcode;
47static int warning_time = 0; 45 check_time_config config;
48static bool check_warning_time = false; 46} check_time_config_wrapper;
49static int critical_time = 0; 47static check_time_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
50static bool check_critical_time = false;
51static unsigned long warning_diff = 0;
52static bool check_warning_diff = false;
53static unsigned long critical_diff = 0;
54static bool check_critical_diff = false;
55static int server_port = TIME_PORT;
56static char *server_address = NULL;
57static bool use_udp = false;
58
59static int process_arguments(int, char **);
60static void print_help(void); 48static void print_help(void);
61void print_usage(void); 49void print_usage(void);
62 50
@@ -68,8 +56,12 @@ int main(int argc, char **argv) {
68 /* Parse extra opts if any */ 56 /* Parse extra opts if any */
69 argv = np_extra_opts(&argc, argv, progname); 57 argv = np_extra_opts(&argc, argv, progname);
70 58
71 if (process_arguments(argc, argv) == ERROR) 59 check_time_config_wrapper tmp_config = process_arguments(argc, argv);
60 if (tmp_config.errorcode == ERROR) {
72 usage4(_("Could not parse arguments")); 61 usage4(_("Could not parse arguments"));
62 }
63
64 const check_time_config config = tmp_config.config;
73 65
74 /* initialize alarm signal handling */ 66 /* initialize alarm signal handling */
75 signal(SIGALRM, socket_timeout_alarm_handler); 67 signal(SIGALRM, socket_timeout_alarm_handler);
@@ -79,37 +71,40 @@ int main(int argc, char **argv) {
79 time(&start_time); 71 time(&start_time);
80 72
81 int socket; 73 int socket;
82 int result = STATE_UNKNOWN; 74 mp_state_enum result = STATE_UNKNOWN;
83 /* try to connect to the host at the given port number */ 75 /* try to connect to the host at the given port number */
84 if (use_udp) { 76 if (config.use_udp) {
85 result = my_udp_connect(server_address, server_port, &socket); 77 result = my_udp_connect(config.server_address, config.server_port, &socket);
86 } else { 78 } else {
87 result = my_tcp_connect(server_address, server_port, &socket); 79 result = my_tcp_connect(config.server_address, config.server_port, &socket);
88 } 80 }
89 81
90 if (result != STATE_OK) { 82 if (result != STATE_OK) {
91 if (check_critical_time) 83 if (config.check_critical_time) {
92 result = STATE_CRITICAL; 84 result = STATE_CRITICAL;
93 else if (check_warning_time) 85 } else if (config.check_warning_time) {
94 result = STATE_WARNING; 86 result = STATE_WARNING;
95 else 87 } else {
96 result = STATE_UNKNOWN; 88 result = STATE_UNKNOWN;
97 die(result, _("TIME UNKNOWN - could not connect to server %s, port %d\n"), server_address, server_port); 89 }
90 die(result, _("TIME UNKNOWN - could not connect to server %s, port %d\n"), config.server_address, config.server_port);
98 } 91 }
99 92
100 if (use_udp) { 93 if (config.use_udp) {
101 if (send(socket, "", 0, 0) < 0) { 94 if (send(socket, "", 0, 0) < 0) {
102 if (check_critical_time) 95 if (config.check_critical_time) {
103 result = STATE_CRITICAL; 96 result = STATE_CRITICAL;
104 else if (check_warning_time) 97 } else if (config.check_warning_time) {
105 result = STATE_WARNING; 98 result = STATE_WARNING;
106 else 99 } else {
107 result = STATE_UNKNOWN; 100 result = STATE_UNKNOWN;
108 die(result, _("TIME UNKNOWN - could not send UDP request to server %s, port %d\n"), server_address, server_port); 101 }
102 die(result, _("TIME UNKNOWN - could not send UDP request to server %s, port %d\n"), config.server_address, config.server_port);
109 } 103 }
110 } 104 }
111 105
112 /* watch for the connection string */ 106 /* watch for the connection string */
107 uint32_t raw_server_time;
113 result = recv(socket, (void *)&raw_server_time, sizeof(raw_server_time), 0); 108 result = recv(socket, (void *)&raw_server_time, sizeof(raw_server_time), 0);
114 109
115 /* close the connection */ 110 /* close the connection */
@@ -121,48 +116,56 @@ int main(int argc, char **argv) {
121 116
122 /* return a WARNING status if we couldn't read any data */ 117 /* return a WARNING status if we couldn't read any data */
123 if (result <= 0) { 118 if (result <= 0) {
124 if (check_critical_time) 119 if (config.check_critical_time) {
125 result = STATE_CRITICAL; 120 result = STATE_CRITICAL;
126 else if (check_warning_time) 121 } else if (config.check_warning_time) {
127 result = STATE_WARNING; 122 result = STATE_WARNING;
128 else 123 } else {
129 result = STATE_UNKNOWN; 124 result = STATE_UNKNOWN;
130 die(result, _("TIME UNKNOWN - no data received from server %s, port %d\n"), server_address, server_port); 125 }
126 die(result, _("TIME UNKNOWN - no data received from server %s, port %d\n"), config.server_address, config.server_port);
131 } 127 }
132 128
133 result = STATE_OK; 129 result = STATE_OK;
134 130
135 time_t conntime = (end_time - start_time); 131 time_t conntime = (end_time - start_time);
136 if (check_critical_time && conntime > critical_time) 132 if (config.check_critical_time && conntime > config.critical_time) {
137 result = STATE_CRITICAL; 133 result = STATE_CRITICAL;
138 else if (check_warning_time && conntime > warning_time) 134 } else if (config.check_warning_time && conntime > config.warning_time) {
139 result = STATE_WARNING; 135 result = STATE_WARNING;
136 }
140 137
141 if (result != STATE_OK) 138 if (result != STATE_OK) {
142 die(result, _("TIME %s - %d second response time|%s\n"), state_text(result), (int)conntime, 139 die(result, _("TIME %s - %d second response time|%s\n"), state_text(result), (int)conntime,
143 perfdata("time", (long)conntime, "s", check_warning_time, (long)warning_time, check_critical_time, (long)critical_time, true, 0, 140 perfdata("time", (long)conntime, "s", config.check_warning_time, (long)config.warning_time, config.check_critical_time,
144 false, 0)); 141 (long)config.critical_time, true, 0, false, 0));
142 }
145 143
144 unsigned long server_time;
145 unsigned long diff_time;
146 server_time = ntohl(raw_server_time) - UNIX_EPOCH; 146 server_time = ntohl(raw_server_time) - UNIX_EPOCH;
147 if (server_time > (unsigned long)end_time) 147 if (server_time > (unsigned long)end_time) {
148 diff_time = server_time - (unsigned long)end_time; 148 diff_time = server_time - (unsigned long)end_time;
149 else 149 } else {
150 diff_time = (unsigned long)end_time - server_time; 150 diff_time = (unsigned long)end_time - server_time;
151 }
151 152
152 if (check_critical_diff && diff_time > critical_diff) 153 if (config.check_critical_diff && diff_time > config.critical_diff) {
153 result = STATE_CRITICAL; 154 result = STATE_CRITICAL;
154 else if (check_warning_diff && diff_time > warning_diff) 155 } else if (config.check_warning_diff && diff_time > config.warning_diff) {
155 result = STATE_WARNING; 156 result = STATE_WARNING;
157 }
156 158
157 printf(_("TIME %s - %lu second time difference|%s %s\n"), state_text(result), diff_time, 159 printf(_("TIME %s - %lu second time difference|%s %s\n"), state_text(result), diff_time,
158 perfdata("time", (long)conntime, "s", check_warning_time, (long)warning_time, check_critical_time, (long)critical_time, true, 0, 160 perfdata("time", (long)conntime, "s", config.check_warning_time, (long)config.warning_time, config.check_critical_time,
159 false, 0), 161 (long)config.critical_time, true, 0, false, 0),
160 perfdata("offset", diff_time, "s", check_warning_diff, warning_diff, check_critical_diff, critical_diff, true, 0, false, 0)); 162 perfdata("offset", diff_time, "s", config.check_warning_diff, config.warning_diff, config.check_critical_diff,
163 config.critical_diff, true, 0, false, 0));
161 return result; 164 return result;
162} 165}
163 166
164/* process command-line arguments */ 167/* process command-line arguments */
165int process_arguments(int argc, char **argv) { 168check_time_config_wrapper process_arguments(int argc, char **argv) {
166 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, 169 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
167 {"warning-variance", required_argument, 0, 'w'}, 170 {"warning-variance", required_argument, 0, 'w'},
168 {"critical-variance", required_argument, 0, 'c'}, 171 {"critical-variance", required_argument, 0, 'c'},
@@ -175,29 +178,37 @@ int process_arguments(int argc, char **argv) {
175 {"help", no_argument, 0, 'h'}, 178 {"help", no_argument, 0, 'h'},
176 {0, 0, 0, 0}}; 179 {0, 0, 0, 0}};
177 180
178 if (argc < 2) 181 if (argc < 2) {
179 usage("\n"); 182 usage("\n");
183 }
180 184
181 for (int i = 1; i < argc; i++) { 185 for (int i = 1; i < argc; i++) {
182 if (strcmp("-to", argv[i]) == 0) 186 if (strcmp("-to", argv[i]) == 0) {
183 strcpy(argv[i], "-t"); 187 strcpy(argv[i], "-t");
184 else if (strcmp("-wd", argv[i]) == 0) 188 } else if (strcmp("-wd", argv[i]) == 0) {
185 strcpy(argv[i], "-w"); 189 strcpy(argv[i], "-w");
186 else if (strcmp("-cd", argv[i]) == 0) 190 } else if (strcmp("-cd", argv[i]) == 0) {
187 strcpy(argv[i], "-c"); 191 strcpy(argv[i], "-c");
188 else if (strcmp("-wt", argv[i]) == 0) 192 } else if (strcmp("-wt", argv[i]) == 0) {
189 strcpy(argv[i], "-W"); 193 strcpy(argv[i], "-W");
190 else if (strcmp("-ct", argv[i]) == 0) 194 } else if (strcmp("-ct", argv[i]) == 0) {
191 strcpy(argv[i], "-C"); 195 strcpy(argv[i], "-C");
196 }
192 } 197 }
193 198
199 check_time_config_wrapper result = {
200 .errorcode = OK,
201 .config = check_time_config_init(),
202 };
203
194 int option_char; 204 int option_char;
195 while (true) { 205 while (true) {
196 int option = 0; 206 int option = 0;
197 option_char = getopt_long(argc, argv, "hVH:w:c:W:C:p:t:u", longopts, &option); 207 option_char = getopt_long(argc, argv, "hVH:w:c:W:C:p:t:u", longopts, &option);
198 208
199 if (option_char == -1 || option_char == EOF) 209 if (option_char == -1 || option_char == EOF) {
200 break; 210 break;
211 }
201 212
202 switch (option_char) { 213 switch (option_char) {
203 case '?': /* print short usage statement if args not parsable */ 214 case '?': /* print short usage statement if args not parsable */
@@ -209,18 +220,19 @@ int process_arguments(int argc, char **argv) {
209 print_revision(progname, NP_VERSION); 220 print_revision(progname, NP_VERSION);
210 exit(STATE_UNKNOWN); 221 exit(STATE_UNKNOWN);
211 case 'H': /* hostname */ 222 case 'H': /* hostname */
212 if (!is_host(optarg)) 223 if (!is_host(optarg)) {
213 usage2(_("Invalid hostname/address"), optarg); 224 usage2(_("Invalid hostname/address"), optarg);
214 server_address = optarg; 225 }
226 result.config.server_address = optarg;
215 break; 227 break;
216 case 'w': /* warning-variance */ 228 case 'w': /* warning-variance */
217 if (is_intnonneg(optarg)) { 229 if (is_intnonneg(optarg)) {
218 warning_diff = strtoul(optarg, NULL, 10); 230 result.config.warning_diff = strtoul(optarg, NULL, 10);
219 check_warning_diff = true; 231 result.config.check_warning_diff = true;
220 } else if (strspn(optarg, "0123456789:,") > 0) { 232 } else if (strspn(optarg, "0123456789:,") > 0) {
221 if (sscanf(optarg, "%lu%*[:,]%d", &warning_diff, &warning_time) == 2) { 233 if (sscanf(optarg, "%lu%*[:,]%d", &result.config.warning_diff, &result.config.warning_time) == 2) {
222 check_warning_diff = true; 234 result.config.check_warning_diff = true;
223 check_warning_time = true; 235 result.config.check_warning_time = true;
224 } else { 236 } else {
225 usage4(_("Warning thresholds must be a positive integer")); 237 usage4(_("Warning thresholds must be a positive integer"));
226 } 238 }
@@ -230,12 +242,12 @@ int process_arguments(int argc, char **argv) {
230 break; 242 break;
231 case 'c': /* critical-variance */ 243 case 'c': /* critical-variance */
232 if (is_intnonneg(optarg)) { 244 if (is_intnonneg(optarg)) {
233 critical_diff = strtoul(optarg, NULL, 10); 245 result.config.critical_diff = strtoul(optarg, NULL, 10);
234 check_critical_diff = true; 246 result.config.check_critical_diff = true;
235 } else if (strspn(optarg, "0123456789:,") > 0) { 247 } else if (strspn(optarg, "0123456789:,") > 0) {
236 if (sscanf(optarg, "%lu%*[:,]%d", &critical_diff, &critical_time) == 2) { 248 if (sscanf(optarg, "%lu%*[:,]%d", &result.config.critical_diff, &result.config.critical_time) == 2) {
237 check_critical_diff = true; 249 result.config.check_critical_diff = true;
238 check_critical_time = true; 250 result.config.check_critical_time = true;
239 } else { 251 } else {
240 usage4(_("Critical thresholds must be a positive integer")); 252 usage4(_("Critical thresholds must be a positive integer"));
241 } 253 }
@@ -244,48 +256,53 @@ int process_arguments(int argc, char **argv) {
244 } 256 }
245 break; 257 break;
246 case 'W': /* warning-connect */ 258 case 'W': /* warning-connect */
247 if (!is_intnonneg(optarg)) 259 if (!is_intnonneg(optarg)) {
248 usage4(_("Warning threshold must be a positive integer")); 260 usage4(_("Warning threshold must be a positive integer"));
249 else 261 } else {
250 warning_time = atoi(optarg); 262 result.config.warning_time = atoi(optarg);
251 check_warning_time = true; 263 }
264 result.config.check_warning_time = true;
252 break; 265 break;
253 case 'C': /* critical-connect */ 266 case 'C': /* critical-connect */
254 if (!is_intnonneg(optarg)) 267 if (!is_intnonneg(optarg)) {
255 usage4(_("Critical threshold must be a positive integer")); 268 usage4(_("Critical threshold must be a positive integer"));
256 else 269 } else {
257 critical_time = atoi(optarg); 270 result.config.critical_time = atoi(optarg);
258 check_critical_time = true; 271 }
272 result.config.check_critical_time = true;
259 break; 273 break;
260 case 'p': /* port */ 274 case 'p': /* port */
261 if (!is_intnonneg(optarg)) 275 if (!is_intnonneg(optarg)) {
262 usage4(_("Port must be a positive integer")); 276 usage4(_("Port must be a positive integer"));
263 else 277 } else {
264 server_port = atoi(optarg); 278 result.config.server_port = atoi(optarg);
279 }
265 break; 280 break;
266 case 't': /* timeout */ 281 case 't': /* timeout */
267 if (!is_intnonneg(optarg)) 282 if (!is_intnonneg(optarg)) {
268 usage2(_("Timeout interval must be a positive integer"), optarg); 283 usage2(_("Timeout interval must be a positive integer"), optarg);
269 else 284 } else {
270 socket_timeout = atoi(optarg); 285 socket_timeout = atoi(optarg);
286 }
271 break; 287 break;
272 case 'u': /* udp */ 288 case 'u': /* udp */
273 use_udp = true; 289 result.config.use_udp = true;
274 } 290 }
275 } 291 }
276 292
277 option_char = optind; 293 option_char = optind;
278 if (server_address == NULL) { 294 if (result.config.server_address == NULL) {
279 if (argc > option_char) { 295 if (argc > option_char) {
280 if (!is_host(argv[option_char])) 296 if (!is_host(argv[option_char])) {
281 usage2(_("Invalid hostname/address"), optarg); 297 usage2(_("Invalid hostname/address"), optarg);
282 server_address = argv[option_char]; 298 }
299 result.config.server_address = argv[option_char];
283 } else { 300 } else {
284 usage4(_("Hostname was not supplied")); 301 usage4(_("Hostname was not supplied"));
285 } 302 }
286 } 303 }
287 304
288 return OK; 305 return result;
289} 306}
290 307
291void print_help(void) { 308void print_help(void) {
diff --git a/plugins/check_time.d/config.h b/plugins/check_time.d/config.h
new file mode 100644
index 00000000..09bd7c45
--- /dev/null
+++ b/plugins/check_time.d/config.h
@@ -0,0 +1,42 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6enum {
7 TIME_PORT = 37
8};
9
10typedef struct {
11 char *server_address;
12 int server_port;
13 bool use_udp;
14
15 int warning_time;
16 bool check_warning_time;
17 int critical_time;
18 bool check_critical_time;
19 unsigned long warning_diff;
20 bool check_warning_diff;
21 unsigned long critical_diff;
22 bool check_critical_diff;
23} check_time_config;
24
25check_time_config check_time_config_init() {
26 check_time_config tmp = {
27 .server_address = NULL,
28 .server_port = TIME_PORT,
29 .use_udp = false,
30
31 .warning_time = 0,
32 .check_warning_time = false,
33 .critical_time = 0,
34 .check_critical_time = false,
35
36 .warning_diff = 0,
37 .check_warning_diff = false,
38 .critical_diff = 0,
39 .check_critical_diff = false,
40 };
41 return tmp;
42}
diff --git a/plugins/check_ups.c b/plugins/check_ups.c
index 526a29df..ecc0760f 100644
--- a/plugins/check_ups.c
+++ b/plugins/check_ups.c
@@ -39,69 +39,29 @@ const char *email = "devel@monitoring-plugins.org";
39#include "common.h" 39#include "common.h"
40#include "netutils.h" 40#include "netutils.h"
41#include "utils.h" 41#include "utils.h"
42 42#include "check_ups.d/config.h"
43enum { 43#include "states.h"
44 PORT = 3493
45};
46
47#define UPS_NONE 0 /* no supported options */
48#define UPS_UTILITY 1 /* supports utility line */
49#define UPS_BATTPCT 2 /* supports percent battery remaining */
50#define UPS_STATUS 4 /* supports UPS status */
51#define UPS_TEMP 8 /* supports UPS temperature */
52#define UPS_LOADPCT 16 /* supports load percent */
53#define UPS_REALPOWER 32 /* supports real power */
54
55#define UPSSTATUS_NONE 0
56#define UPSSTATUS_OFF 1
57#define UPSSTATUS_OL 2
58#define UPSSTATUS_OB 4
59#define UPSSTATUS_LB 8
60#define UPSSTATUS_CAL 16
61#define UPSSTATUS_RB 32 /*Replace Battery */
62#define UPSSTATUS_BYPASS 64
63#define UPSSTATUS_OVER 128
64#define UPSSTATUS_TRIM 256
65#define UPSSTATUS_BOOST 512
66#define UPSSTATUS_CHRG 1024
67#define UPSSTATUS_DISCHRG 2048
68#define UPSSTATUS_UNKNOWN 4096
69#define UPSSTATUS_ALARM 8192
70 44
71enum { 45enum {
72 NOSUCHVAR = ERROR - 1 46 NOSUCHVAR = ERROR - 1
73}; 47};
74 48
75typedef struct ups_config {
76 unsigned int server_port;
77 char *server_address;
78 char *ups_name;
79 double warning_value;
80 double critical_value;
81 bool check_warn;
82 bool check_crit;
83 int check_variable;
84 int status;
85 bool temp_output_c;
86} ups_config;
87
88ups_config ups_config_init(void) {
89 ups_config tmp = {0};
90 tmp.server_port = PORT;
91 tmp.server_address = NULL;
92 tmp.ups_name = NULL;
93 tmp.check_variable = UPS_NONE;
94 tmp.status = UPSSTATUS_NONE;
95
96 return tmp;
97}
98
99// Forward declarations 49// Forward declarations
100static int determine_status(ups_config * /*config*/, int *supported_options); 50typedef struct {
101static int get_ups_variable(const char * /*varname*/, char * /*buf*/, ups_config config); 51 int errorcode;
52 int ups_status;
53 int supported_options;
54} determine_status_result;
55static determine_status_result determine_status(check_ups_config /*config*/);
56static int get_ups_variable(const char * /*varname*/, char * /*buf*/, check_ups_config config);
57
58typedef struct {
59 int errorcode;
60 check_ups_config config;
61} check_ups_config_wrapper;
62static check_ups_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
63static check_ups_config_wrapper validate_arguments(check_ups_config_wrapper /*config_wrapper*/);
102 64
103static int process_arguments(int /*argc*/, char ** /*argv*/, ups_config * /*config*/);
104static int validate_arguments(ups_config /*config*/);
105static void print_help(void); 65static void print_help(void);
106void print_usage(void); 66void print_usage(void);
107 67
@@ -109,28 +69,16 @@ int main(int argc, char **argv) {
109 setlocale(LC_ALL, ""); 69 setlocale(LC_ALL, "");
110 bindtextdomain(PACKAGE, LOCALEDIR); 70 bindtextdomain(PACKAGE, LOCALEDIR);
111 textdomain(PACKAGE); 71 textdomain(PACKAGE);
112
113 char *ups_status;
114 ups_status = strdup("N/A");
115
116 char *data;
117 data = strdup("");
118
119 char *message;
120 message = strdup("");
121
122 // Exit result
123 int result = STATE_UNKNOWN;
124
125 /* Parse extra opts if any */ 72 /* Parse extra opts if any */
126 argv = np_extra_opts(&argc, argv, progname); 73 argv = np_extra_opts(&argc, argv, progname);
127 74
128 // Config from commandline 75 check_ups_config_wrapper tmp_config = process_arguments(argc, argv);
129 ups_config config = ups_config_init();
130 76
131 if (process_arguments(argc, argv, &config) == ERROR) { 77 if (tmp_config.errorcode == ERROR) {
132 usage4(_("Could not parse arguments")); 78 usage4(_("Could not parse arguments"));
133 } 79 }
80 // Config from commandline
81 check_ups_config config = tmp_config.config;
134 82
135 /* initialize alarm signal handling */ 83 /* initialize alarm signal handling */
136 signal(SIGALRM, socket_timeout_alarm_handler); 84 signal(SIGALRM, socket_timeout_alarm_handler);
@@ -138,71 +86,75 @@ int main(int argc, char **argv) {
138 /* set socket timeout */ 86 /* set socket timeout */
139 alarm(socket_timeout); 87 alarm(socket_timeout);
140 88
141 int supported_options = UPS_NONE;
142
143 /* get the ups status if possible */ 89 /* get the ups status if possible */
144 if (determine_status(&config, &supported_options) != OK) { 90 determine_status_result query_result = determine_status(config);
91 if (query_result.errorcode != OK) {
145 return STATE_CRITICAL; 92 return STATE_CRITICAL;
146 } 93 }
147 94
148 if (supported_options & UPS_STATUS) { 95 int ups_status_flags = query_result.ups_status;
96 int supported_options = query_result.supported_options;
149 97
150 ups_status = strdup(""); 98 // Exit result
99 mp_state_enum result = STATE_UNKNOWN;
100 char *message = NULL;
151 101
102 if (supported_options & UPS_STATUS) {
103 char *ups_status = strdup("");
152 result = STATE_OK; 104 result = STATE_OK;
153 105
154 if (config.status & UPSSTATUS_OFF) { 106 if (ups_status_flags & UPSSTATUS_OFF) {
155 xasprintf(&ups_status, "Off"); 107 xasprintf(&ups_status, "Off");
156 result = STATE_CRITICAL; 108 result = STATE_CRITICAL;
157 } else if ((config.status & (UPSSTATUS_OB | UPSSTATUS_LB)) == (UPSSTATUS_OB | UPSSTATUS_LB)) { 109 } else if ((ups_status_flags & (UPSSTATUS_OB | UPSSTATUS_LB)) == (UPSSTATUS_OB | UPSSTATUS_LB)) {
158 xasprintf(&ups_status, _("On Battery, Low Battery")); 110 xasprintf(&ups_status, _("On Battery, Low Battery"));
159 result = STATE_CRITICAL; 111 result = STATE_CRITICAL;
160 } else { 112 } else {
161 if (config.status & UPSSTATUS_OL) { 113 if (ups_status_flags & UPSSTATUS_OL) {
162 xasprintf(&ups_status, "%s%s", ups_status, _("Online")); 114 xasprintf(&ups_status, "%s%s", ups_status, _("Online"));
163 } 115 }
164 if (config.status & UPSSTATUS_OB) { 116 if (ups_status_flags & UPSSTATUS_OB) {
165 xasprintf(&ups_status, "%s%s", ups_status, _("On Battery")); 117 xasprintf(&ups_status, "%s%s", ups_status, _("On Battery"));
166 result = max_state(result, STATE_WARNING); 118 result = max_state(result, STATE_WARNING);
167 } 119 }
168 if (config.status & UPSSTATUS_LB) { 120 if (ups_status_flags & UPSSTATUS_LB) {
169 xasprintf(&ups_status, "%s%s", ups_status, _(", Low Battery")); 121 xasprintf(&ups_status, "%s%s", ups_status, _(", Low Battery"));
170 result = max_state(result, STATE_WARNING); 122 result = max_state(result, STATE_WARNING);
171 } 123 }
172 if (config.status & UPSSTATUS_CAL) { 124 if (ups_status_flags & UPSSTATUS_CAL) {
173 xasprintf(&ups_status, "%s%s", ups_status, _(", Calibrating")); 125 xasprintf(&ups_status, "%s%s", ups_status, _(", Calibrating"));
174 } 126 }
175 if (config.status & UPSSTATUS_RB) { 127 if (ups_status_flags & UPSSTATUS_RB) {
176 xasprintf(&ups_status, "%s%s", ups_status, _(", Replace Battery")); 128 xasprintf(&ups_status, "%s%s", ups_status, _(", Replace Battery"));
177 result = max_state(result, STATE_WARNING); 129 result = max_state(result, STATE_WARNING);
178 } 130 }
179 if (config.status & UPSSTATUS_BYPASS) { 131 if (ups_status_flags & UPSSTATUS_BYPASS) {
180 xasprintf(&ups_status, "%s%s", ups_status, _(", On Bypass")); 132 xasprintf(&ups_status, "%s%s", ups_status, _(", On Bypass"));
181 // Bypassing the battery is likely a bad thing 133 // Bypassing the battery is likely a bad thing
182 result = STATE_CRITICAL; 134 result = STATE_CRITICAL;
183 } 135 }
184 if (config.status & UPSSTATUS_OVER) { 136 if (ups_status_flags & UPSSTATUS_OVER) {
185 xasprintf(&ups_status, "%s%s", ups_status, _(", Overload")); 137 xasprintf(&ups_status, "%s%s", ups_status, _(", Overload"));
186 result = max_state(result, STATE_WARNING); 138 result = max_state(result, STATE_WARNING);
187 } 139 }
188 if (config.status & UPSSTATUS_TRIM) { 140 if (ups_status_flags & UPSSTATUS_TRIM) {
189 xasprintf(&ups_status, "%s%s", ups_status, _(", Trimming")); 141 xasprintf(&ups_status, "%s%s", ups_status, _(", Trimming"));
190 } 142 }
191 if (config.status & UPSSTATUS_BOOST) { 143 if (ups_status_flags & UPSSTATUS_BOOST) {
192 xasprintf(&ups_status, "%s%s", ups_status, _(", Boosting")); 144 xasprintf(&ups_status, "%s%s", ups_status, _(", Boosting"));
193 } 145 }
194 if (config.status & UPSSTATUS_CHRG) { 146 if (ups_status_flags & UPSSTATUS_CHRG) {
195 xasprintf(&ups_status, "%s%s", ups_status, _(", Charging")); 147 xasprintf(&ups_status, "%s%s", ups_status, _(", Charging"));
196 } 148 }
197 if (config.status & UPSSTATUS_DISCHRG) { 149 if (ups_status_flags & UPSSTATUS_DISCHRG) {
198 xasprintf(&ups_status, "%s%s", ups_status, _(", Discharging")); 150 xasprintf(&ups_status, "%s%s", ups_status, _(", Discharging"));
199 result = max_state(result, STATE_WARNING); 151 result = max_state(result, STATE_WARNING);
200 } 152 }
201 if (config.status & UPSSTATUS_ALARM) { 153 if (ups_status_flags & UPSSTATUS_ALARM) {
202 xasprintf(&ups_status, "%s%s", ups_status, _(", ALARM")); 154 xasprintf(&ups_status, "%s%s", ups_status, _(", ALARM"));
203 result = STATE_CRITICAL; 155 result = STATE_CRITICAL;
204 } 156 }
205 if (config.status & UPSSTATUS_UNKNOWN) { 157 if (ups_status_flags & UPSSTATUS_UNKNOWN) {
206 xasprintf(&ups_status, "%s%s", ups_status, _(", Unknown")); 158 xasprintf(&ups_status, "%s%s", ups_status, _(", Unknown"));
207 } 159 }
208 } 160 }
@@ -211,7 +163,7 @@ int main(int argc, char **argv) {
211 163
212 int res; 164 int res;
213 char temp_buffer[MAX_INPUT_BUFFER]; 165 char temp_buffer[MAX_INPUT_BUFFER];
214 166 char *performance_data = strdup("");
215 /* get the ups utility voltage if possible */ 167 /* get the ups utility voltage if possible */
216 res = get_ups_variable("input.voltage", temp_buffer, config); 168 res = get_ups_variable("input.voltage", temp_buffer, config);
217 if (res == NOSUCHVAR) { 169 if (res == NOSUCHVAR) {
@@ -239,11 +191,12 @@ int main(int argc, char **argv) {
239 } else if (config.check_warn && ups_utility_deviation >= config.warning_value) { 191 } else if (config.check_warn && ups_utility_deviation >= config.warning_value) {
240 result = max_state(result, STATE_WARNING); 192 result = max_state(result, STATE_WARNING);
241 } 193 }
242 xasprintf(&data, "%s", 194 xasprintf(&performance_data, "%s",
243 perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", config.check_warn, (long)(1000 * config.warning_value), 195 perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", config.check_warn, (long)(1000 * config.warning_value),
244 config.check_crit, (long)(1000 * config.critical_value), true, 0, false, 0)); 196 config.check_crit, (long)(1000 * config.critical_value), true, 0, false, 0));
245 } else { 197 } else {
246 xasprintf(&data, "%s", perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", false, 0, false, 0, true, 0, false, 0)); 198 xasprintf(&performance_data, "%s",
199 perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", false, 0, false, 0, true, 0, false, 0));
247 } 200 }
248 } 201 }
249 202
@@ -266,11 +219,12 @@ int main(int argc, char **argv) {
266 } else if (config.check_warn && ups_battery_percent <= config.warning_value) { 219 } else if (config.check_warn && ups_battery_percent <= config.warning_value) {
267 result = max_state(result, STATE_WARNING); 220 result = max_state(result, STATE_WARNING);
268 } 221 }
269 xasprintf(&data, "%s %s", data, 222 xasprintf(&performance_data, "%s %s", performance_data,
270 perfdata("battery", (long)ups_battery_percent, "%", config.check_warn, (long)(config.warning_value), 223 perfdata("battery", (long)ups_battery_percent, "%", config.check_warn, (long)(config.warning_value),
271 config.check_crit, (long)(config.critical_value), true, 0, true, 100)); 224 config.check_crit, (long)(config.critical_value), true, 0, true, 100));
272 } else { 225 } else {
273 xasprintf(&data, "%s %s", data, perfdata("battery", (long)ups_battery_percent, "%", false, 0, false, 0, true, 0, true, 100)); 226 xasprintf(&performance_data, "%s %s", performance_data,
227 perfdata("battery", (long)ups_battery_percent, "%", false, 0, false, 0, true, 0, true, 100));
274 } 228 }
275 } 229 }
276 230
@@ -293,11 +247,12 @@ int main(int argc, char **argv) {
293 } else if (config.check_warn && ups_load_percent >= config.warning_value) { 247 } else if (config.check_warn && ups_load_percent >= config.warning_value) {
294 result = max_state(result, STATE_WARNING); 248 result = max_state(result, STATE_WARNING);
295 } 249 }
296 xasprintf(&data, "%s %s", data, 250 xasprintf(&performance_data, "%s %s", performance_data,
297 perfdata("load", (long)ups_load_percent, "%", config.check_warn, (long)(config.warning_value), config.check_crit, 251 perfdata("load", (long)ups_load_percent, "%", config.check_warn, (long)(config.warning_value), config.check_crit,
298 (long)(config.critical_value), true, 0, true, 100)); 252 (long)(config.critical_value), true, 0, true, 100));
299 } else { 253 } else {
300 xasprintf(&data, "%s %s", data, perfdata("load", (long)ups_load_percent, "%", false, 0, false, 0, true, 0, true, 100)); 254 xasprintf(&performance_data, "%s %s", performance_data,
255 perfdata("load", (long)ups_load_percent, "%", false, 0, false, 0, true, 0, true, 100));
301 } 256 }
302 } 257 }
303 258
@@ -329,11 +284,12 @@ int main(int argc, char **argv) {
329 } else if (config.check_warn && ups_temperature >= config.warning_value) { 284 } else if (config.check_warn && ups_temperature >= config.warning_value) {
330 result = max_state(result, STATE_WARNING); 285 result = max_state(result, STATE_WARNING);
331 } 286 }
332 xasprintf(&data, "%s %s", data, 287 xasprintf(&performance_data, "%s %s", performance_data,
333 perfdata("temp", (long)ups_temperature, tunits, config.check_warn, (long)(config.warning_value), config.check_crit, 288 perfdata("temp", (long)ups_temperature, tunits, config.check_warn, (long)(config.warning_value), config.check_crit,
334 (long)(config.critical_value), true, 0, false, 0)); 289 (long)(config.critical_value), true, 0, false, 0));
335 } else { 290 } else {
336 xasprintf(&data, "%s %s", data, perfdata("temp", (long)ups_temperature, tunits, false, 0, false, 0, true, 0, false, 0)); 291 xasprintf(&performance_data, "%s %s", performance_data,
292 perfdata("temp", (long)ups_temperature, tunits, false, 0, false, 0, true, 0, false, 0));
337 } 293 }
338 } 294 }
339 295
@@ -355,11 +311,12 @@ int main(int argc, char **argv) {
355 } else if (config.check_warn && ups_realpower >= config.warning_value) { 311 } else if (config.check_warn && ups_realpower >= config.warning_value) {
356 result = max_state(result, STATE_WARNING); 312 result = max_state(result, STATE_WARNING);
357 } 313 }
358 xasprintf(&data, "%s %s", data, 314 xasprintf(&performance_data, "%s %s", performance_data,
359 perfdata("realpower", (long)ups_realpower, "W", config.check_warn, (long)(config.warning_value), config.check_crit, 315 perfdata("realpower", (long)ups_realpower, "W", config.check_warn, (long)(config.warning_value), config.check_crit,
360 (long)(config.critical_value), true, 0, false, 0)); 316 (long)(config.critical_value), true, 0, false, 0));
361 } else { 317 } else {
362 xasprintf(&data, "%s %s", data, perfdata("realpower", (long)ups_realpower, "W", false, 0, false, 0, true, 0, false, 0)); 318 xasprintf(&performance_data, "%s %s", performance_data,
319 perfdata("realpower", (long)ups_realpower, "W", false, 0, false, 0, true, 0, false, 0));
363 } 320 }
364 } 321 }
365 322
@@ -373,66 +330,73 @@ int main(int argc, char **argv) {
373 /* reset timeout */ 330 /* reset timeout */
374 alarm(0); 331 alarm(0);
375 332
376 printf("UPS %s - %s|%s\n", state_text(result), message, data); 333 printf("UPS %s - %s|%s\n", state_text(result), message, performance_data);
377 return result; 334 exit(result);
378} 335}
379 336
380/* determines what options are supported by the UPS */ 337/* determines what options are supported by the UPS */
381int determine_status(ups_config *config, int *supported_options) { 338determine_status_result determine_status(const check_ups_config config) {
382 char recv_buffer[MAX_INPUT_BUFFER];
383 339
384 int res = get_ups_variable("ups.status", recv_buffer, *config); 340 determine_status_result result = {
341 .errorcode = OK,
342 .ups_status = UPSSTATUS_NONE,
343 .supported_options = 0,
344 };
345
346 char recv_buffer[MAX_INPUT_BUFFER];
347 int res = get_ups_variable("ups.status", recv_buffer, config);
385 if (res == NOSUCHVAR) { 348 if (res == NOSUCHVAR) {
386 return OK; 349 return result;
387 } 350 }
388 351
389 if (res != STATE_OK) { 352 if (res != STATE_OK) {
390 printf("%s\n", _("Invalid response received from host")); 353 printf("%s\n", _("Invalid response received from host"));
391 return ERROR; 354 result.errorcode = ERROR;
355 return result;
392 } 356 }
393 357
394 *supported_options |= UPS_STATUS; 358 result.supported_options |= UPS_STATUS;
395 359
396 char temp_buffer[MAX_INPUT_BUFFER]; 360 char temp_buffer[MAX_INPUT_BUFFER];
397 361
398 strcpy(temp_buffer, recv_buffer); 362 strcpy(temp_buffer, recv_buffer);
399 for (char *ptr = (char *)strtok(temp_buffer, " "); ptr != NULL; ptr = (char *)strtok(NULL, " ")) { 363 for (char *ptr = strtok(temp_buffer, " "); ptr != NULL; ptr = strtok(NULL, " ")) {
400 if (!strcmp(ptr, "OFF")) { 364 if (!strcmp(ptr, "OFF")) {
401 config->status |= UPSSTATUS_OFF; 365 result.ups_status |= UPSSTATUS_OFF;
402 } else if (!strcmp(ptr, "OL")) { 366 } else if (!strcmp(ptr, "OL")) {
403 config->status |= UPSSTATUS_OL; 367 result.ups_status |= UPSSTATUS_OL;
404 } else if (!strcmp(ptr, "OB")) { 368 } else if (!strcmp(ptr, "OB")) {
405 config->status |= UPSSTATUS_OB; 369 result.ups_status |= UPSSTATUS_OB;
406 } else if (!strcmp(ptr, "LB")) { 370 } else if (!strcmp(ptr, "LB")) {
407 config->status |= UPSSTATUS_LB; 371 result.ups_status |= UPSSTATUS_LB;
408 } else if (!strcmp(ptr, "CAL")) { 372 } else if (!strcmp(ptr, "CAL")) {
409 config->status |= UPSSTATUS_CAL; 373 result.ups_status |= UPSSTATUS_CAL;
410 } else if (!strcmp(ptr, "RB")) { 374 } else if (!strcmp(ptr, "RB")) {
411 config->status |= UPSSTATUS_RB; 375 result.ups_status |= UPSSTATUS_RB;
412 } else if (!strcmp(ptr, "BYPASS")) { 376 } else if (!strcmp(ptr, "BYPASS")) {
413 config->status |= UPSSTATUS_BYPASS; 377 result.ups_status |= UPSSTATUS_BYPASS;
414 } else if (!strcmp(ptr, "OVER")) { 378 } else if (!strcmp(ptr, "OVER")) {
415 config->status |= UPSSTATUS_OVER; 379 result.ups_status |= UPSSTATUS_OVER;
416 } else if (!strcmp(ptr, "TRIM")) { 380 } else if (!strcmp(ptr, "TRIM")) {
417 config->status |= UPSSTATUS_TRIM; 381 result.ups_status |= UPSSTATUS_TRIM;
418 } else if (!strcmp(ptr, "BOOST")) { 382 } else if (!strcmp(ptr, "BOOST")) {
419 config->status |= UPSSTATUS_BOOST; 383 result.ups_status |= UPSSTATUS_BOOST;
420 } else if (!strcmp(ptr, "CHRG")) { 384 } else if (!strcmp(ptr, "CHRG")) {
421 config->status |= UPSSTATUS_CHRG; 385 result.ups_status |= UPSSTATUS_CHRG;
422 } else if (!strcmp(ptr, "DISCHRG")) { 386 } else if (!strcmp(ptr, "DISCHRG")) {
423 config->status |= UPSSTATUS_DISCHRG; 387 result.ups_status |= UPSSTATUS_DISCHRG;
424 } else if (!strcmp(ptr, "ALARM")) { 388 } else if (!strcmp(ptr, "ALARM")) {
425 config->status |= UPSSTATUS_ALARM; 389 result.ups_status |= UPSSTATUS_ALARM;
426 } else { 390 } else {
427 config->status |= UPSSTATUS_UNKNOWN; 391 result.ups_status |= UPSSTATUS_UNKNOWN;
428 } 392 }
429 } 393 }
430 394
431 return OK; 395 return result;
432} 396}
433 397
434/* gets a variable value for a specific UPS */ 398/* gets a variable value for a specific UPS */
435int get_ups_variable(const char *varname, char *buf, const ups_config config) { 399int get_ups_variable(const char *varname, char *buf, const check_ups_config config) {
436 char send_buffer[MAX_INPUT_BUFFER]; 400 char send_buffer[MAX_INPUT_BUFFER];
437 401
438 /* create the command string to send to the UPS daemon */ 402 /* create the command string to send to the UPS daemon */
@@ -500,7 +464,7 @@ int get_ups_variable(const char *varname, char *buf, const ups_config config) {
500 [-wv warn_value] [-cv crit_value] [-to to_sec] */ 464 [-wv warn_value] [-cv crit_value] [-to to_sec] */
501 465
502/* process command-line arguments */ 466/* process command-line arguments */
503int process_arguments(int argc, char **argv, ups_config *config) { 467check_ups_config_wrapper process_arguments(int argc, char **argv) {
504 468
505 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, 469 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
506 {"ups", required_argument, 0, 'u'}, 470 {"ups", required_argument, 0, 'u'},
@@ -514,8 +478,14 @@ int process_arguments(int argc, char **argv, ups_config *config) {
514 {"help", no_argument, 0, 'h'}, 478 {"help", no_argument, 0, 'h'},
515 {0, 0, 0, 0}}; 479 {0, 0, 0, 0}};
516 480
481 check_ups_config_wrapper result = {
482 .errorcode = OK,
483 .config = check_ups_config_init(),
484 };
485
517 if (argc < 2) { 486 if (argc < 2) {
518 return ERROR; 487 result.errorcode = ERROR;
488 return result;
519 } 489 }
520 490
521 int c; 491 int c;
@@ -542,52 +512,52 @@ int process_arguments(int argc, char **argv, ups_config *config) {
542 usage5(); 512 usage5();
543 case 'H': /* hostname */ 513 case 'H': /* hostname */
544 if (is_host(optarg)) { 514 if (is_host(optarg)) {
545 config->server_address = optarg; 515 result.config.server_address = optarg;
546 } else { 516 } else {
547 usage2(_("Invalid hostname/address"), optarg); 517 usage2(_("Invalid hostname/address"), optarg);
548 } 518 }
549 break; 519 break;
550 case 'T': /* FIXME: to be improved (ie "-T C" for Celsius or "-T F" for 520 case 'T': /* FIXME: to be improved (ie "-T C" for Celsius or "-T F" for
551 Fahrenheit) */ 521 Fahrenheit) */
552 config->temp_output_c = true; 522 result.config.temp_output_c = true;
553 break; 523 break;
554 case 'u': /* ups name */ 524 case 'u': /* ups name */
555 config->ups_name = optarg; 525 result.config.ups_name = optarg;
556 break; 526 break;
557 case 'p': /* port */ 527 case 'p': /* port */
558 if (is_intpos(optarg)) { 528 if (is_intpos(optarg)) {
559 config->server_port = atoi(optarg); 529 result.config.server_port = atoi(optarg);
560 } else { 530 } else {
561 usage2(_("Port must be a positive integer"), optarg); 531 usage2(_("Port must be a positive integer"), optarg);
562 } 532 }
563 break; 533 break;
564 case 'c': /* critical time threshold */ 534 case 'c': /* critical time threshold */
565 if (is_intnonneg(optarg)) { 535 if (is_intnonneg(optarg)) {
566 config->critical_value = atoi(optarg); 536 result.config.critical_value = atoi(optarg);
567 config->check_crit = true; 537 result.config.check_crit = true;
568 } else { 538 } else {
569 usage2(_("Critical time must be a positive integer"), optarg); 539 usage2(_("Critical time must be a positive integer"), optarg);
570 } 540 }
571 break; 541 break;
572 case 'w': /* warning time threshold */ 542 case 'w': /* warning time threshold */
573 if (is_intnonneg(optarg)) { 543 if (is_intnonneg(optarg)) {
574 config->warning_value = atoi(optarg); 544 result.config.warning_value = atoi(optarg);
575 config->check_warn = true; 545 result.config.check_warn = true;
576 } else { 546 } else {
577 usage2(_("Warning time must be a positive integer"), optarg); 547 usage2(_("Warning time must be a positive integer"), optarg);
578 } 548 }
579 break; 549 break;
580 case 'v': /* variable */ 550 case 'v': /* variable */
581 if (!strcmp(optarg, "LINE")) { 551 if (!strcmp(optarg, "LINE")) {
582 config->check_variable = UPS_UTILITY; 552 result.config.check_variable = UPS_UTILITY;
583 } else if (!strcmp(optarg, "TEMP")) { 553 } else if (!strcmp(optarg, "TEMP")) {
584 config->check_variable = UPS_TEMP; 554 result.config.check_variable = UPS_TEMP;
585 } else if (!strcmp(optarg, "BATTPCT")) { 555 } else if (!strcmp(optarg, "BATTPCT")) {
586 config->check_variable = UPS_BATTPCT; 556 result.config.check_variable = UPS_BATTPCT;
587 } else if (!strcmp(optarg, "LOADPCT")) { 557 } else if (!strcmp(optarg, "LOADPCT")) {
588 config->check_variable = UPS_LOADPCT; 558 result.config.check_variable = UPS_LOADPCT;
589 } else if (!strcmp(optarg, "REALPOWER")) { 559 } else if (!strcmp(optarg, "REALPOWER")) {
590 config->check_variable = UPS_REALPOWER; 560 result.config.check_variable = UPS_REALPOWER;
591 } else { 561 } else {
592 usage2(_("Unrecognized UPS variable"), optarg); 562 usage2(_("Unrecognized UPS variable"), optarg);
593 } 563 }
@@ -608,27 +578,27 @@ int process_arguments(int argc, char **argv, ups_config *config) {
608 } 578 }
609 } 579 }
610 580
611 if (config->server_address == NULL && argc > optind) { 581 if (result.config.server_address == NULL && argc > optind) {
612 if (is_host(argv[optind])) { 582 if (is_host(argv[optind])) {
613 config->server_address = argv[optind++]; 583 result.config.server_address = argv[optind++];
614 } else { 584 } else {
615 usage2(_("Invalid hostname/address"), optarg); 585 usage2(_("Invalid hostname/address"), optarg);
616 } 586 }
617 } 587 }
618 588
619 if (config->server_address == NULL) { 589 if (result.config.server_address == NULL) {
620 config->server_address = strdup("127.0.0.1"); 590 result.config.server_address = strdup("127.0.0.1");
621 } 591 }
622 592
623 return validate_arguments(*config); 593 return validate_arguments(result);
624} 594}
625 595
626int validate_arguments(ups_config config) { 596check_ups_config_wrapper validate_arguments(check_ups_config_wrapper config_wrapper) {
627 if (!config.ups_name) { 597 if (config_wrapper.config.ups_name) {
628 printf("%s\n", _("Error : no UPS indicated")); 598 printf("%s\n", _("Error : no UPS indicated"));
629 return ERROR; 599 config_wrapper.errorcode = ERROR;
630 } 600 }
631 return OK; 601 return config_wrapper;
632} 602}
633 603
634void print_help(void) { 604void print_help(void) {
diff --git a/plugins/check_ups.d/config.h b/plugins/check_ups.d/config.h
new file mode 100644
index 00000000..353104f2
--- /dev/null
+++ b/plugins/check_ups.d/config.h
@@ -0,0 +1,55 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6#define UPS_NONE 0 /* no supported options */
7#define UPS_UTILITY 1 /* supports utility line */
8#define UPS_BATTPCT 2 /* supports percent battery remaining */
9#define UPS_STATUS 4 /* supports UPS status */
10#define UPS_TEMP 8 /* supports UPS temperature */
11#define UPS_LOADPCT 16 /* supports load percent */
12#define UPS_REALPOWER 32 /* supports real power */
13
14#define UPSSTATUS_NONE 0
15#define UPSSTATUS_OFF 1
16#define UPSSTATUS_OL 2
17#define UPSSTATUS_OB 4
18#define UPSSTATUS_LB 8
19#define UPSSTATUS_CAL 16
20#define UPSSTATUS_RB 32 /*Replace Battery */
21#define UPSSTATUS_BYPASS 64
22#define UPSSTATUS_OVER 128
23#define UPSSTATUS_TRIM 256
24#define UPSSTATUS_BOOST 512
25#define UPSSTATUS_CHRG 1024
26#define UPSSTATUS_DISCHRG 2048
27#define UPSSTATUS_UNKNOWN 4096
28#define UPSSTATUS_ALARM 8192
29
30enum {
31 PORT = 3493
32};
33
34typedef struct ups_config {
35 unsigned int server_port;
36 char *server_address;
37 char *ups_name;
38 double warning_value;
39 double critical_value;
40 bool check_warn;
41 bool check_crit;
42 int check_variable;
43 bool temp_output_c;
44} check_ups_config;
45
46check_ups_config check_ups_config_init(void) {
47 check_ups_config tmp = {0};
48 tmp.server_port = PORT;
49 tmp.server_address = NULL;
50 tmp.ups_name = NULL;
51 tmp.check_variable = UPS_NONE;
52
53 return tmp;
54}
55
diff --git a/plugins/negate.c b/plugins/negate.c
index 750c0bfb..0520d298 100644
--- a/plugins/negate.c
+++ b/plugins/negate.c
@@ -38,21 +38,18 @@ const char *email = "devel@monitoring-plugins.org";
38#include "common.h" 38#include "common.h"
39#include "utils.h" 39#include "utils.h"
40#include "utils_cmd.h" 40#include "utils_cmd.h"
41#include "negate.d/config.h"
42#include "../lib/states.h"
41 43
42#include <ctype.h> 44typedef struct {
45 int errorcode;
46 negate_config config;
47} negate_config_wrapper;
48static negate_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
49static negate_config_wrapper validate_arguments(negate_config_wrapper /*config_wrapper*/);
43 50
44static const char **process_arguments(int /*argc*/, char ** /*argv*/);
45static void validate_arguments(char ** /*command_line*/);
46static void print_help(void); 51static void print_help(void);
47void print_usage(void); 52void print_usage(void);
48static bool subst_text = false;
49
50static int state[4] = {
51 STATE_OK,
52 STATE_WARNING,
53 STATE_CRITICAL,
54 STATE_UNKNOWN,
55};
56 53
57int main(int argc, char **argv) { 54int main(int argc, char **argv) {
58 setlocale(LC_ALL, ""); 55 setlocale(LC_ALL, "");
@@ -61,15 +58,24 @@ int main(int argc, char **argv) {
61 58
62 timeout_interval = DEFAULT_TIMEOUT; 59 timeout_interval = DEFAULT_TIMEOUT;
63 60
64 char **command_line = (char **)process_arguments(argc, argv); 61 negate_config_wrapper tmp_config = process_arguments(argc, argv);
62
63 if (tmp_config.errorcode == ERROR) {
64 die(STATE_UNKNOWN, _("negate: Failed to parse input"));
65 }
66
67 negate_config config = tmp_config.config;
68
69 char **command_line = config.command_line;
65 70
66 /* Set signal handling and alarm */ 71 /* Set signal handling and alarm */
67 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) 72 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
68 die(STATE_UNKNOWN, _("Cannot catch SIGALRM")); 73 die(STATE_UNKNOWN, _("Cannot catch SIGALRM"));
74 }
69 75
70 (void)alarm((unsigned)timeout_interval); 76 (void)alarm(timeout_interval);
71 77
72 int result = STATE_UNKNOWN; 78 mp_state_enum result = STATE_UNKNOWN;
73 output chld_out; 79 output chld_out;
74 output chld_err; 80 output chld_err;
75 81
@@ -86,46 +92,52 @@ int main(int argc, char **argv) {
86 } 92 }
87 93
88 /* Return UNKNOWN or worse if no output is returned */ 94 /* Return UNKNOWN or worse if no output is returned */
89 if (chld_out.lines == 0) 95 if (chld_out.lines == 0) {
90 die(max_state_alt(result, STATE_UNKNOWN), _("No data returned from command\n")); 96 die(max_state_alt(result, STATE_UNKNOWN), _("No data returned from command\n"));
97 }
91 98
92 char *sub; 99 char *sub;
93 for (size_t i = 0; i < chld_out.lines; i++) { 100 for (size_t i = 0; i < chld_out.lines; i++) {
94 if (subst_text && result >= 0 && result <= 4 && result != state[result]) { 101 if (config.subst_text && result >= 0 && result <= 4 && result != config.state[result]) {
95 /* Loop over each match found */ 102 /* Loop over each match found */
96 while ((sub = strstr(chld_out.line[i], state_text(result)))) { 103 while ((sub = strstr(chld_out.line[i], state_text(result)))) {
97 /* Terminate the first part and skip over the string we'll substitute */ 104 /* Terminate the first part and skip over the string we'll substitute */
98 *sub = '\0'; 105 *sub = '\0';
99 sub += strlen(state_text(result)); 106 sub += strlen(state_text(result));
100 /* then put everything back together */ 107 /* then put everything back together */
101 xasprintf(&chld_out.line[i], "%s%s%s", chld_out.line[i], state_text(state[result]), sub); 108 xasprintf(&chld_out.line[i], "%s%s%s", chld_out.line[i], state_text(config.state[result]), sub);
102 } 109 }
103 } 110 }
104 printf("%s\n", chld_out.line[i]); 111 printf("%s\n", chld_out.line[i]);
105 } 112 }
106 113
107 if (result >= 0 && result <= 4) { 114 if (result >= 0 && result <= 4) {
108 exit(state[result]); 115 exit(config.state[result]);
109 } else { 116 } else {
110 exit(result); 117 exit(result);
111 } 118 }
112} 119}
113 120
114/* process command-line arguments */ 121/* process command-line arguments */
115static const char **process_arguments(int argc, char **argv) { 122static negate_config_wrapper process_arguments(int argc, char **argv) {
116 static struct option longopts[] = {{"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, 123 static struct option longopts[] = {{"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'},
117 {"timeout", required_argument, 0, 't'}, {"timeout-result", required_argument, 0, 'T'}, 124 {"timeout", required_argument, 0, 't'}, {"timeout-result", required_argument, 0, 'T'},
118 {"ok", required_argument, 0, 'o'}, {"warning", required_argument, 0, 'w'}, 125 {"ok", required_argument, 0, 'o'}, {"warning", required_argument, 0, 'w'},
119 {"critical", required_argument, 0, 'c'}, {"unknown", required_argument, 0, 'u'}, 126 {"critical", required_argument, 0, 'c'}, {"unknown", required_argument, 0, 'u'},
120 {"substitute", no_argument, 0, 's'}, {0, 0, 0, 0}}; 127 {"substitute", no_argument, 0, 's'}, {0, 0, 0, 0}};
121 128
129 negate_config_wrapper result = {
130 .errorcode = OK,
131 .config = negate_config_init(),
132 };
122 bool permute = true; 133 bool permute = true;
123 while (true) { 134 while (true) {
124 int option = 0; 135 int option = 0;
125 int option_char = getopt_long(argc, argv, "+hVt:T:o:w:c:u:s", longopts, &option); 136 int option_char = getopt_long(argc, argv, "+hVt:T:o:w:c:u:s", longopts, &option);
126 137
127 if (option_char == -1 || option_char == EOF) 138 if (option_char == -1 || option_char == EOF) {
128 break; 139 break;
140 }
129 141
130 switch (option_char) { 142 switch (option_char) {
131 case '?': /* help */ 143 case '?': /* help */
@@ -139,58 +151,68 @@ static const char **process_arguments(int argc, char **argv) {
139 print_revision(progname, NP_VERSION); 151 print_revision(progname, NP_VERSION);
140 exit(STATE_UNKNOWN); 152 exit(STATE_UNKNOWN);
141 case 't': /* timeout period */ 153 case 't': /* timeout period */
142 if (!is_integer(optarg)) 154 if (!is_integer(optarg)) {
143 usage2(_("Timeout interval must be a positive integer"), optarg); 155 usage2(_("Timeout interval must be a positive integer"), optarg);
144 else 156 } else {
145 timeout_interval = atoi(optarg); 157 timeout_interval = atoi(optarg);
158 }
146 break; 159 break;
147 case 'T': /* Result to return on timeouts */ 160 case 'T': /* Result to return on timeouts */
148 if ((timeout_state = mp_translate_state(optarg)) == ERROR) 161 if ((timeout_state = mp_translate_state(optarg)) == ERROR) {
149 usage4(_("Timeout result must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 162 usage4(_("Timeout result must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
163 }
150 break; 164 break;
151 case 'o': /* replacement for OK */ 165 case 'o': /* replacement for OK */
152 if ((state[STATE_OK] = mp_translate_state(optarg)) == ERROR) 166 if ((result.config.state[STATE_OK] = mp_translate_state(optarg)) == ERROR) {
153 usage4(_("Ok must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 167 usage4(_("Ok must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
168 }
154 permute = false; 169 permute = false;
155 break; 170 break;
156 171
157 case 'w': /* replacement for WARNING */ 172 case 'w': /* replacement for WARNING */
158 if ((state[STATE_WARNING] = mp_translate_state(optarg)) == ERROR) 173 if ((result.config.state[STATE_WARNING] = mp_translate_state(optarg)) == ERROR) {
159 usage4(_("Warning must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 174 usage4(_("Warning must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
175 }
160 permute = false; 176 permute = false;
161 break; 177 break;
162 case 'c': /* replacement for CRITICAL */ 178 case 'c': /* replacement for CRITICAL */
163 if ((state[STATE_CRITICAL] = mp_translate_state(optarg)) == ERROR) 179 if ((result.config.state[STATE_CRITICAL] = mp_translate_state(optarg)) == ERROR) {
164 usage4(_("Critical must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 180 usage4(_("Critical must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
181 }
165 permute = false; 182 permute = false;
166 break; 183 break;
167 case 'u': /* replacement for UNKNOWN */ 184 case 'u': /* replacement for UNKNOWN */
168 if ((state[STATE_UNKNOWN] = mp_translate_state(optarg)) == ERROR) 185 if ((result.config.state[STATE_UNKNOWN] = mp_translate_state(optarg)) == ERROR) {
169 usage4(_("Unknown must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 186 usage4(_("Unknown must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
187 }
170 permute = false; 188 permute = false;
171 break; 189 break;
172 case 's': /* Substitute status text */ 190 case 's': /* Substitute status text */
173 subst_text = true; 191 result.config.subst_text = true;
174 break; 192 break;
175 } 193 }
176 } 194 }
177 195
178 validate_arguments(&argv[optind]);
179
180 if (permute) { /* No [owcu] switch specified, default to this */ 196 if (permute) { /* No [owcu] switch specified, default to this */
181 state[STATE_OK] = STATE_CRITICAL; 197 result.config.state[STATE_OK] = STATE_CRITICAL;
182 state[STATE_CRITICAL] = STATE_OK; 198 result.config.state[STATE_CRITICAL] = STATE_OK;
183 } 199 }
184 200
185 return (const char **)&argv[optind]; 201 result.config.command_line = &argv[optind];
202
203 return validate_arguments(result);
186} 204}
187 205
188void validate_arguments(char **command_line) { 206negate_config_wrapper validate_arguments(negate_config_wrapper config_wrapper) {
189 if (command_line[0] == NULL) 207 if (config_wrapper.config.command_line[0] == NULL) {
190 usage4(_("Could not parse arguments")); 208 usage4(_("Could not parse arguments"));
209 }
191 210
192 if (strncmp(command_line[0], "/", 1) != 0 && strncmp(command_line[0], "./", 2) != 0) 211 if (strncmp(config_wrapper.config.command_line[0], "/", 1) != 0 && strncmp(config_wrapper.config.command_line[0], "./", 2) != 0) {
193 usage4(_("Require path to command")); 212 usage4(_("Require path to command"));
213 }
214
215 return config_wrapper;
194} 216}
195 217
196void print_help(void) { 218void print_help(void) {
diff --git a/plugins/negate.d/config.h b/plugins/negate.d/config.h
new file mode 100644
index 00000000..0cf30cd4
--- /dev/null
+++ b/plugins/negate.d/config.h
@@ -0,0 +1,24 @@
1#pragma once
2
3#include "states.h"
4
5typedef struct {
6 mp_state_enum state[4];
7 bool subst_text;
8 char **command_line;
9} negate_config;
10
11negate_config negate_config_init() {
12 negate_config tmp = {
13 .state =
14 {
15 STATE_OK,
16 STATE_WARNING,
17 STATE_CRITICAL,
18 STATE_UNKNOWN,
19 },
20 .subst_text = false,
21 .command_line = NULL,
22 };
23 return tmp;
24}
diff --git a/plugins/t/check_ftp.t b/plugins/t/check_ftp.t
index 93a7d7c3..a2f79dca 100644
--- a/plugins/t/check_ftp.t
+++ b/plugins/t/check_ftp.t
@@ -15,7 +15,7 @@ my $host_tcp_ftp = getTestParameter("NP_HOST_TCP_FTP", "A host providing t
15my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1"); 15my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
16my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost"); 16my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
17 17
18my $successOutput = '/FTP OK -\s+[0-9]?\.?[0-9]+ second response time/'; 18my $successOutput = '/Connection time\s+[0-9]?\.?[0-9]+/';
19 19
20my $t; 20my $t;
21 21
diff --git a/plugins/t/check_jabber.t b/plugins/t/check_jabber.t
index 08cadcbd..dc46f4c3 100644
--- a/plugins/t/check_jabber.t
+++ b/plugins/t/check_jabber.t
@@ -15,11 +15,11 @@ my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname
15my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost"); 15my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
16 16
17 17
18my $jabberOK = '/JABBER OK\s-\s\d+\.\d+\ssecond response time on '.$host_tcp_jabber.' port 5222/'; 18my $jabberOK = '/Connection to '.$host_tcp_jabber.' on port 5222/';
19 19
20my $jabberUnresponsive = '/Socket timeout after\s\d+\sseconds/'; 20my $jabberUnresponsive = '/Socket timeout after\s\d+\sseconds/';
21 21
22my $jabberInvalid = '/JABBER CRITICAL - Invalid hostname, address or socket:\s.+/'; 22my $jabberInvalid = '/Invalid hostname, address or socket:\s.+/';
23 23
24my $r; 24my $r;
25 25
diff --git a/plugins/t/check_tcp.t b/plugins/t/check_tcp.t
index cb4de53d..5c8fd0be 100644
--- a/plugins/t/check_tcp.t
+++ b/plugins/t/check_tcp.t
@@ -21,19 +21,19 @@ my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname
21my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost"); 21my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
22my $internet_access = getTestParameter("NP_INTERNET_ACCESS", "Is this system directly connected to the internet?", "yes"); 22my $internet_access = getTestParameter("NP_INTERNET_ACCESS", "Is this system directly connected to the internet?", "yes");
23 23
24my $successOutput = '/^TCP OK\s-\s+[0-9]?\.?[0-9]+ second response time on port [0-9]+/'; 24my $successOutput = '/Connection time\s+[0-9]?\.?[0-9]+s is within thresholds+/';
25 25
26my $failedExpect = '/^TCP WARNING\s-\sUnexpected response from host/socket on port [0-9]+/'; 26my $failedExpect = '/Answer failed to match/';
27 27
28my $t; 28my $t;
29 29
30$tests = $tests - 4 if $internet_access eq "no"; 30$tests = $tests - 4 if $internet_access eq "no";
31plan tests => $tests; 31plan tests => $tests;
32 32
33$t += checkCmd( "./check_tcp $host_tcp_http -p 80 -wt 300 -ct 600", 0, $successOutput ); 33$t += checkCmd( "./check_tcp $host_tcp_http -p 80 -w 300 -c 600", 0, $successOutput );
34$t += checkCmd( "./check_tcp $host_tcp_http -p 81 -wt 0 -ct 0 -to 1", 2 ); # use invalid port for this test 34$t += checkCmd( "./check_tcp $host_tcp_http -p 81 -w 0 -c 0 -t 1", 2 ); # use invalid port for this test
35$t += checkCmd( "./check_tcp $host_nonresponsive -p 80 -wt 0 -ct 0 -to 1", 2 ); 35$t += checkCmd( "./check_tcp $host_nonresponsive -p 80 -w 0 -c 0 -t 1", 2 );
36$t += checkCmd( "./check_tcp $hostname_invalid -p 80 -wt 0 -ct 0 -to 1", 2 ); 36$t += checkCmd( "./check_tcp $hostname_invalid -p 80 -w 0 -c 0 -t 1", 2 );
37if($internet_access ne "no") { 37if($internet_access ne "no") {
38 $t += checkCmd( "./check_tcp -S -D 1 -H $host_tls_http -p 443", 0 ); 38 $t += checkCmd( "./check_tcp -S -D 1 -H $host_tls_http -p 443", 0 );
39 $t += checkCmd( "./check_tcp -S -D 9000,1 -H $host_tls_http -p 443", 1 ); 39 $t += checkCmd( "./check_tcp -S -D 9000,1 -H $host_tls_http -p 443", 1 );
diff --git a/plugins/t/check_udp.t b/plugins/t/check_udp.t
index 6c47d095..5cb9e6dc 100644
--- a/plugins/t/check_udp.t
+++ b/plugins/t/check_udp.t
@@ -28,7 +28,7 @@ like ( $res->output, '/With UDP checks, a send/expect string must be specified.
28 28
29$res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s foo -e bar" ); 29$res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s foo -e bar" );
30cmp_ok( $res->return_code, '==', 2, "Errors correctly because no udp service running" ); 30cmp_ok( $res->return_code, '==', 2, "Errors correctly because no udp service running" );
31like ( $res->output, '/No data received from host/', "Output OK"); 31like ( $res->output, '/Received no data /', "Output OK");
32 32
33my $nc; 33my $nc;
34if(system("which nc.traditional >/dev/null 2>&1") == 0) { 34if(system("which nc.traditional >/dev/null 2>&1") == 0) {
@@ -48,7 +48,7 @@ SKIP: {
48 sleep 1; 48 sleep 1;
49 $res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s '' -e barbar -4" ); 49 $res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s '' -e barbar -4" );
50 cmp_ok( $res->return_code, '==', 0, "Got barbar response back" ); 50 cmp_ok( $res->return_code, '==', 0, "Got barbar response back" );
51 like ( $res->output, '/\[barbar\]/', "Output OK"); 51 like ( $res->output, '/answer of the server matched/', "Output OK");
52 close NC; 52 close NC;
53 53
54 # Start up a udp server listening on port 3333, quit after 3 seconds 54 # Start up a udp server listening on port 3333, quit after 3 seconds