summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/Makefile.am1
-rw-r--r--plugins/check_ntp_peer.c385
-rw-r--r--plugins/check_ntp_peer.d/config.h67
3 files changed, 281 insertions, 172 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 6c582a15..7a2255df 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -61,6 +61,7 @@ EXTRA_DIST = t \
61 check_mrtgtraf.d \ 61 check_mrtgtraf.d \
62 check_mysql_query.d \ 62 check_mysql_query.d \
63 check_mrtg.d \ 63 check_mrtg.d \
64 check_ntp_peer.d \
64 check_apt.d \ 65 check_apt.d \
65 check_pgsql.d \ 66 check_pgsql.d \
66 check_by_ssh.d \ 67 check_by_ssh.d \
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}