diff options
Diffstat (limited to 'plugins/check_ntp_peer.c')
-rw-r--r-- | plugins/check_ntp_peer.c | 618 |
1 files changed, 618 insertions, 0 deletions
diff --git a/plugins/check_ntp_peer.c b/plugins/check_ntp_peer.c new file mode 100644 index 00000000..840fe0ac --- /dev/null +++ b/plugins/check_ntp_peer.c | |||
@@ -0,0 +1,618 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Nagios check_ntp_peer plugin | ||
4 | * | ||
5 | * License: GPL | ||
6 | * Copyright (c) 2006 sean finney <seanius@seanius.net> | ||
7 | * Copyright (c) 2007 nagios-plugins team | ||
8 | * | ||
9 | * Last Modified: $Date$ | ||
10 | * | ||
11 | * Description: | ||
12 | * | ||
13 | * This file contains the check_ntp_peer plugin | ||
14 | * | ||
15 | * This plugin to check ntp servers independant of any commandline | ||
16 | * programs or external libraries. | ||
17 | * | ||
18 | * | ||
19 | * License Information: | ||
20 | * | ||
21 | * This program is free software; you can redistribute it and/or modify | ||
22 | * it under the terms of the GNU General Public License as published by | ||
23 | * the Free Software Foundation; either version 2 of the License, or | ||
24 | * (at your option) any later version. | ||
25 | * | ||
26 | * This program is distributed in the hope that it will be useful, | ||
27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
29 | * GNU General Public License for more details. | ||
30 | * | ||
31 | * You should have received a copy of the GNU General Public License | ||
32 | * along with this program; if not, write to the Free Software | ||
33 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
34 | |||
35 | $Id$ | ||
36 | |||
37 | *****************************************************************************/ | ||
38 | |||
39 | const char *progname = "check_ntp_peer"; | ||
40 | const char *revision = "$Revision$"; | ||
41 | const char *copyright = "2007"; | ||
42 | const char *email = "nagiosplug-devel@lists.sourceforge.net"; | ||
43 | |||
44 | #include "common.h" | ||
45 | #include "netutils.h" | ||
46 | #include "utils.h" | ||
47 | |||
48 | static char *server_address=NULL; | ||
49 | static int verbose=0; | ||
50 | static short do_offset=0; | ||
51 | static char *owarn="60"; | ||
52 | static char *ocrit="120"; | ||
53 | static short do_stratum=0; | ||
54 | static char *swarn="16"; | ||
55 | static char *scrit="16"; | ||
56 | static short do_jitter=0; | ||
57 | static char *jwarn="5000"; | ||
58 | static char *jcrit="10000"; | ||
59 | static int syncsource_found=0; | ||
60 | |||
61 | int process_arguments (int, char **); | ||
62 | thresholds *offset_thresholds = NULL; | ||
63 | thresholds *jitter_thresholds = NULL; | ||
64 | thresholds *stratum_thresholds = NULL; | ||
65 | void print_help (void); | ||
66 | void print_usage (void); | ||
67 | |||
68 | /* max size of control message data */ | ||
69 | #define MAX_CM_SIZE 468 | ||
70 | |||
71 | /* this structure holds everything in an ntp control message as per rfc1305 */ | ||
72 | typedef struct { | ||
73 | uint8_t flags; /* byte with leapindicator,vers,mode. see macros */ | ||
74 | uint8_t op; /* R,E,M bits and Opcode */ | ||
75 | uint16_t seq; /* Packet sequence */ | ||
76 | uint16_t status; /* Clock status */ | ||
77 | uint16_t assoc; /* Association */ | ||
78 | uint16_t offset; /* Similar to TCP sequence # */ | ||
79 | uint16_t count; /* # bytes of data */ | ||
80 | char data[MAX_CM_SIZE]; /* ASCII data of the request */ | ||
81 | /* NB: not necessarily NULL terminated! */ | ||
82 | } ntp_control_message; | ||
83 | |||
84 | /* this is an association/status-word pair found in control packet reponses */ | ||
85 | typedef struct { | ||
86 | uint16_t assoc; | ||
87 | uint16_t status; | ||
88 | } ntp_assoc_status_pair; | ||
89 | |||
90 | /* bits 1,2 are the leap indicator */ | ||
91 | #define LI_MASK 0xc0 | ||
92 | #define LI(x) ((x&LI_MASK)>>6) | ||
93 | #define LI_SET(x,y) do{ x |= ((y<<6)&LI_MASK); }while(0) | ||
94 | /* and these are the values of the leap indicator */ | ||
95 | #define LI_NOWARNING 0x00 | ||
96 | #define LI_EXTRASEC 0x01 | ||
97 | #define LI_MISSINGSEC 0x02 | ||
98 | #define LI_ALARM 0x03 | ||
99 | /* bits 3,4,5 are the ntp version */ | ||
100 | #define VN_MASK 0x38 | ||
101 | #define VN(x) ((x&VN_MASK)>>3) | ||
102 | #define VN_SET(x,y) do{ x |= ((y<<3)&VN_MASK); }while(0) | ||
103 | #define VN_RESERVED 0x02 | ||
104 | /* bits 6,7,8 are the ntp mode */ | ||
105 | #define MODE_MASK 0x07 | ||
106 | #define MODE(x) (x&MODE_MASK) | ||
107 | #define MODE_SET(x,y) do{ x |= (y&MODE_MASK); }while(0) | ||
108 | /* here are some values */ | ||
109 | #define MODE_CLIENT 0x03 | ||
110 | #define MODE_CONTROLMSG 0x06 | ||
111 | /* In control message, bits 8-10 are R,E,M bits */ | ||
112 | #define REM_MASK 0xe0 | ||
113 | #define REM_RESP 0x80 | ||
114 | #define REM_ERROR 0x40 | ||
115 | #define REM_MORE 0x20 | ||
116 | /* In control message, bits 11 - 15 are opcode */ | ||
117 | #define OP_MASK 0x1f | ||
118 | #define OP_SET(x,y) do{ x |= (y&OP_MASK); }while(0) | ||
119 | #define OP_READSTAT 0x01 | ||
120 | #define OP_READVAR 0x02 | ||
121 | /* In peer status bytes, bits 6,7,8 determine clock selection status */ | ||
122 | #define PEER_SEL(x) ((ntohs(x)>>8)&0x07) | ||
123 | #define PEER_INCLUDED 0x04 | ||
124 | #define PEER_SYNCSOURCE 0x06 | ||
125 | |||
126 | /* NTP control message header is 12 bytes, plus any data in the data | ||
127 | * field, plus null padding to the nearest 32-bit boundary per rfc. | ||
128 | */ | ||
129 | #define SIZEOF_NTPCM(m) (12+ntohs(m.count)+((m.count)?4-(ntohs(m.count)%4):0)) | ||
130 | |||
131 | /* finally, a little helper or two for debugging: */ | ||
132 | #define DBG(x) do{if(verbose>1){ x; }}while(0); | ||
133 | #define PRINTSOCKADDR(x) \ | ||
134 | do{ \ | ||
135 | printf("%u.%u.%u.%u", (x>>24)&0xff, (x>>16)&0xff, (x>>8)&0xff, x&0xff);\ | ||
136 | }while(0); | ||
137 | |||
138 | void print_ntp_control_message(const ntp_control_message *p){ | ||
139 | int i=0, numpeers=0; | ||
140 | const ntp_assoc_status_pair *peer=NULL; | ||
141 | |||
142 | printf("control packet contents:\n"); | ||
143 | printf("\tflags: 0x%.2x , 0x%.2x\n", p->flags, p->op); | ||
144 | printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags&LI_MASK); | ||
145 | printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags&VN_MASK); | ||
146 | printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags&MODE_MASK); | ||
147 | printf("\t response=%d (0x%.2x)\n", (p->op&REM_RESP)>0, p->op&REM_RESP); | ||
148 | printf("\t more=%d (0x%.2x)\n", (p->op&REM_MORE)>0, p->op&REM_MORE); | ||
149 | printf("\t error=%d (0x%.2x)\n", (p->op&REM_ERROR)>0, p->op&REM_ERROR); | ||
150 | printf("\t op=%d (0x%.2x)\n", p->op&OP_MASK, p->op&OP_MASK); | ||
151 | printf("\tsequence: %d (0x%.2x)\n", ntohs(p->seq), ntohs(p->seq)); | ||
152 | printf("\tstatus: %d (0x%.2x)\n", ntohs(p->status), ntohs(p->status)); | ||
153 | printf("\tassoc: %d (0x%.2x)\n", ntohs(p->assoc), ntohs(p->assoc)); | ||
154 | printf("\toffset: %d (0x%.2x)\n", ntohs(p->offset), ntohs(p->offset)); | ||
155 | printf("\tcount: %d (0x%.2x)\n", ntohs(p->count), ntohs(p->count)); | ||
156 | numpeers=ntohs(p->count)/(sizeof(ntp_assoc_status_pair)); | ||
157 | if(p->op&REM_RESP && p->op&OP_READSTAT){ | ||
158 | peer=(ntp_assoc_status_pair*)p->data; | ||
159 | for(i=0;i<numpeers;i++){ | ||
160 | printf("\tpeer id %.2x status %.2x", | ||
161 | ntohs(peer[i].assoc), ntohs(peer[i].status)); | ||
162 | if (PEER_SEL(peer[i].status) >= PEER_INCLUDED){ | ||
163 | if(PEER_SEL(peer[i].status) >= PEER_SYNCSOURCE){ | ||
164 | printf(" <-- current sync source"); | ||
165 | } else { | ||
166 | printf(" <-- current sync candidate"); | ||
167 | } | ||
168 | } | ||
169 | printf("\n"); | ||
170 | } | ||
171 | } | ||
172 | } | ||
173 | |||
174 | char *extract_value(const char *varlist, const char *name){ | ||
175 | char *tmpvarlist=NULL, *tmpkey=NULL, *value=NULL; | ||
176 | int last=0; | ||
177 | |||
178 | tmpvarlist = strdup(varlist); | ||
179 | tmpkey = strtok(tmpvarlist, "="); | ||
180 | |||
181 | do { | ||
182 | if(strstr(tmpkey, name) != NULL) { | ||
183 | value = strtok(NULL, ","); | ||
184 | last = 1; | ||
185 | } | ||
186 | } while (last == 0 && (tmpkey = strtok(NULL, "="))); | ||
187 | |||
188 | return value; | ||
189 | } | ||
190 | |||
191 | void | ||
192 | setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq){ | ||
193 | memset(p, 0, sizeof(ntp_control_message)); | ||
194 | LI_SET(p->flags, LI_NOWARNING); | ||
195 | VN_SET(p->flags, VN_RESERVED); | ||
196 | MODE_SET(p->flags, MODE_CONTROLMSG); | ||
197 | OP_SET(p->op, opcode); | ||
198 | p->seq = htons(seq); | ||
199 | /* Remaining fields are zero for requests */ | ||
200 | } | ||
201 | |||
202 | /* XXX handle responses with the error bit set */ | ||
203 | int ntp_request(const char *host, double *offset, int *offset_result, double *jitter, int *stratum){ | ||
204 | int conn=-1, i, npeers=0, num_candidates=0; | ||
205 | int min_peer_sel=PEER_INCLUDED; | ||
206 | int peers_size=0, peer_offset=0; | ||
207 | int status; | ||
208 | ntp_assoc_status_pair *peers=NULL; | ||
209 | ntp_control_message req; | ||
210 | const char *getvar = "stratum,offset,jitter"; | ||
211 | char *value=NULL, *nptr=NULL; | ||
212 | void *tmp; | ||
213 | |||
214 | status = STATE_OK; | ||
215 | *offset_result = STATE_UNKNOWN; | ||
216 | *jitter = *stratum = -1; | ||
217 | |||
218 | /* Long-winded explanation: | ||
219 | * Getting the sync peer offset, jitter and stratum requires a number of | ||
220 | * steps: | ||
221 | * 1) Send a READSTAT request. | ||
222 | * 2) Interpret the READSTAT reply | ||
223 | * a) The data section contains a list of peer identifiers (16 bits) | ||
224 | * and associated status words (16 bits) | ||
225 | * b) We want the value of 0x06 in the SEL (peer selection) value, | ||
226 | * which means "current synchronizatin source". If that's missing, | ||
227 | * we take anything better than 0x04 (see the rfc for details) but | ||
228 | * set a minimum of warning. | ||
229 | * 3) Send a READVAR request for information on each peer identified | ||
230 | * in 2b greater than the minimum selection value. | ||
231 | * 4) Extract the offset, jitter and stratum value from the data[] | ||
232 | * (it's ASCII) | ||
233 | */ | ||
234 | my_udp_connect(server_address, 123, &conn); | ||
235 | |||
236 | /* keep sending requests until the server stops setting the | ||
237 | * REM_MORE bit, though usually this is only 1 packet. */ | ||
238 | do{ | ||
239 | setup_control_request(&req, OP_READSTAT, 1); | ||
240 | DBG(printf("sending READSTAT request")); | ||
241 | write(conn, &req, SIZEOF_NTPCM(req)); | ||
242 | DBG(print_ntp_control_message(&req)); | ||
243 | /* Attempt to read the largest size packet possible */ | ||
244 | req.count=htons(MAX_CM_SIZE); | ||
245 | DBG(printf("recieving READSTAT response")) | ||
246 | read(conn, &req, SIZEOF_NTPCM(req)); | ||
247 | DBG(print_ntp_control_message(&req)); | ||
248 | /* Each peer identifier is 4 bytes in the data section, which | ||
249 | * we represent as a ntp_assoc_status_pair datatype. | ||
250 | */ | ||
251 | peers_size+=ntohs(req.count); | ||
252 | if((tmp=realloc(peers, peers_size)) == NULL) | ||
253 | free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n"); | ||
254 | peers=tmp; | ||
255 | memcpy((void*)((ptrdiff_t)peers+peer_offset), (void*)req.data, ntohs(req.count)); | ||
256 | npeers=peers_size/sizeof(ntp_assoc_status_pair); | ||
257 | peer_offset+=ntohs(req.count); | ||
258 | } while(req.op&REM_MORE); | ||
259 | |||
260 | /* first, let's find out if we have a sync source, or if there are | ||
261 | * at least some candidates. in the case of the latter we'll issue | ||
262 | * a warning but go ahead with the check on them. */ | ||
263 | for (i = 0; i < npeers; i++){ | ||
264 | if (PEER_SEL(peers[i].status) >= PEER_INCLUDED){ | ||
265 | num_candidates++; | ||
266 | if(PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE){ | ||
267 | syncsource_found=1; | ||
268 | min_peer_sel=PEER_SYNCSOURCE; | ||
269 | } | ||
270 | } | ||
271 | } | ||
272 | if(verbose) printf("%d candiate peers available\n", num_candidates); | ||
273 | if(verbose && syncsource_found) printf("synchronization source found\n"); | ||
274 | if(! syncsource_found){ | ||
275 | status = STATE_WARNING; | ||
276 | if(verbose) printf("warning: no synchronization source found\n"); | ||
277 | } | ||
278 | |||
279 | |||
280 | for (i = 0; i < npeers; i++){ | ||
281 | /* Only query this server if it is the current sync source */ | ||
282 | if (PEER_SEL(peers[i].status) >= min_peer_sel){ | ||
283 | if(verbose) printf("Getting offset, jitter and stratum for peer %.2x\n", ntohs(peers[i].assoc)); | ||
284 | setup_control_request(&req, OP_READVAR, 2); | ||
285 | req.assoc = peers[i].assoc; | ||
286 | /* Putting the wanted variable names in the request | ||
287 | * cause the server to provide _only_ the requested values. | ||
288 | * thus reducing net traffic, guaranteeing us only a single | ||
289 | * datagram in reply, and making intepretation much simpler | ||
290 | */ | ||
291 | /* Older servers doesn't know what jitter is, so if we get an | ||
292 | * error on the first pass we redo it with "dispersion" */ | ||
293 | strncpy(req.data, getvar, MAX_CM_SIZE-1); | ||
294 | req.count = htons(strlen(getvar)); | ||
295 | DBG(printf("sending READVAR request...\n")); | ||
296 | write(conn, &req, SIZEOF_NTPCM(req)); | ||
297 | DBG(print_ntp_control_message(&req)); | ||
298 | |||
299 | req.count = htons(MAX_CM_SIZE); | ||
300 | DBG(printf("recieving READVAR response...\n")); | ||
301 | read(conn, &req, SIZEOF_NTPCM(req)); | ||
302 | DBG(print_ntp_control_message(&req)); | ||
303 | |||
304 | if(req.op&REM_ERROR && strstr(getvar, "jitter")) { | ||
305 | if(verbose) printf("The 'jitter' command failed (old ntp server?)\nRestarting with 'dispersion'...\n"); | ||
306 | getvar = "stratum,offset,dispersion"; | ||
307 | i--; | ||
308 | continue; | ||
309 | } | ||
310 | |||
311 | if(verbose > 1) | ||
312 | printf("Server responded: >>>%s<<<\n", req.data); | ||
313 | |||
314 | /* get the offset */ | ||
315 | if(verbose) | ||
316 | printf("parsing offset from peer %.2x: ", ntohs(peers[i].assoc)); | ||
317 | |||
318 | value = extract_value(req.data, "offset"); | ||
319 | /* Convert the value if we have one */ | ||
320 | if(value != NULL) | ||
321 | *offset = strtod(value, &nptr) / 1000; | ||
322 | /* If value is null or no conversion was performed */ | ||
323 | if(value == NULL || value==nptr) { | ||
324 | printf("warning: unable to read server offset response.\n"); | ||
325 | status = max_state_alt(status, STATE_CRITICAL); | ||
326 | } else { | ||
327 | *offset_result = STATE_OK; | ||
328 | if(verbose) printf("%g\n", *offset); | ||
329 | } | ||
330 | |||
331 | if(do_jitter) { | ||
332 | /* first reset the pointers */ | ||
333 | value = NULL, nptr=NULL; | ||
334 | /* get the jitter */ | ||
335 | if(verbose) { | ||
336 | printf("parsing jitter from peer %.2x: ", ntohs(peers[i].assoc)); | ||
337 | } | ||
338 | value = extract_value(req.data, strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter"); | ||
339 | /* Convert the value if we have one */ | ||
340 | if(value != NULL) | ||
341 | *jitter = strtod(value, &nptr); | ||
342 | /* If value is null or no conversion was performed */ | ||
343 | if(value == NULL || value==nptr){ | ||
344 | printf("warning: unable to read server jitter response.\n"); | ||
345 | status = max_state_alt(status, STATE_UNKNOWN); | ||
346 | } else { | ||
347 | if(verbose) printf("%g\n", *jitter); | ||
348 | } | ||
349 | } | ||
350 | |||
351 | if(do_stratum) { | ||
352 | value = NULL; | ||
353 | /* get the stratum */ | ||
354 | if(verbose) { | ||
355 | printf("parsing stratum from peer %.2x: ", ntohs(peers[i].assoc)); | ||
356 | } | ||
357 | value = extract_value(req.data, "stratum"); | ||
358 | if(value == NULL){ | ||
359 | printf("warning: unable to read server stratum response.\n"); | ||
360 | status = max_state_alt(status, STATE_UNKNOWN); | ||
361 | } else { | ||
362 | *stratum = atoi(value); | ||
363 | if(verbose) printf("%i\n", *stratum); | ||
364 | } | ||
365 | } | ||
366 | } /* if (PEER_SEL(peers[i].status) >= min_peer_sel) */ | ||
367 | } /* for (i = 0; i < npeers; i++) */ | ||
368 | |||
369 | close(conn); | ||
370 | if(peers!=NULL) free(peers); | ||
371 | |||
372 | return status; | ||
373 | } | ||
374 | |||
375 | int process_arguments(int argc, char **argv){ | ||
376 | int c; | ||
377 | int option=0; | ||
378 | static struct option longopts[] = { | ||
379 | {"version", no_argument, 0, 'V'}, | ||
380 | {"help", no_argument, 0, 'h'}, | ||
381 | {"verbose", no_argument, 0, 'v'}, | ||
382 | {"use-ipv4", no_argument, 0, '4'}, | ||
383 | {"use-ipv6", no_argument, 0, '6'}, | ||
384 | {"warning", required_argument, 0, 'w'}, | ||
385 | {"critical", required_argument, 0, 'c'}, | ||
386 | {"swarn", required_argument, 0, 'W'}, | ||
387 | {"scrit", required_argument, 0, 'C'}, | ||
388 | {"jwarn", required_argument, 0, 'j'}, | ||
389 | {"jcrit", required_argument, 0, 'k'}, | ||
390 | {"timeout", required_argument, 0, 't'}, | ||
391 | {"hostname", required_argument, 0, 'H'}, | ||
392 | {0, 0, 0, 0} | ||
393 | }; | ||
394 | |||
395 | |||
396 | if (argc < 2) | ||
397 | usage ("\n"); | ||
398 | |||
399 | while (1) { | ||
400 | c = getopt_long (argc, argv, "Vhv46w:c:W:C:j:k:t:H:", longopts, &option); | ||
401 | if (c == -1 || c == EOF || c == 1) | ||
402 | break; | ||
403 | |||
404 | switch (c) { | ||
405 | case 'h': | ||
406 | print_help(); | ||
407 | exit(STATE_OK); | ||
408 | break; | ||
409 | case 'V': | ||
410 | print_revision(progname, revision); | ||
411 | exit(STATE_OK); | ||
412 | break; | ||
413 | case 'v': | ||
414 | verbose++; | ||
415 | break; | ||
416 | case 'w': | ||
417 | do_offset=1; | ||
418 | owarn = optarg; | ||
419 | break; | ||
420 | case 'c': | ||
421 | do_offset=1; | ||
422 | ocrit = optarg; | ||
423 | break; | ||
424 | case 'W': | ||
425 | do_stratum=1; | ||
426 | swarn = optarg; | ||
427 | break; | ||
428 | case 'C': | ||
429 | do_stratum=1; | ||
430 | scrit = optarg; | ||
431 | break; | ||
432 | case 'j': | ||
433 | do_jitter=1; | ||
434 | jwarn = optarg; | ||
435 | break; | ||
436 | case 'k': | ||
437 | do_jitter=1; | ||
438 | jcrit = optarg; | ||
439 | break; | ||
440 | case 'H': | ||
441 | if(is_host(optarg) == FALSE) | ||
442 | usage2(_("Invalid hostname/address"), optarg); | ||
443 | server_address = strdup(optarg); | ||
444 | break; | ||
445 | case 't': | ||
446 | socket_timeout=atoi(optarg); | ||
447 | break; | ||
448 | case '4': | ||
449 | address_family = AF_INET; | ||
450 | break; | ||
451 | case '6': | ||
452 | #ifdef USE_IPV6 | ||
453 | address_family = AF_INET6; | ||
454 | #else | ||
455 | usage4 (_("IPv6 support not available")); | ||
456 | #endif | ||
457 | break; | ||
458 | case '?': | ||
459 | /* print short usage statement if args not parsable */ | ||
460 | usage5 (); | ||
461 | break; | ||
462 | } | ||
463 | } | ||
464 | |||
465 | if(server_address == NULL){ | ||
466 | usage4(_("Hostname was not supplied")); | ||
467 | } | ||
468 | |||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | char *perfd_offset (double offset) | ||
473 | { | ||
474 | return fperfdata ("offset", offset, "s", | ||
475 | TRUE, offset_thresholds->warning->end, | ||
476 | TRUE, offset_thresholds->critical->end, | ||
477 | FALSE, 0, FALSE, 0); | ||
478 | } | ||
479 | |||
480 | char *perfd_jitter (double jitter) | ||
481 | { | ||
482 | return fperfdata ("jitter", jitter, "s", | ||
483 | do_jitter, jitter_thresholds->warning->end, | ||
484 | do_jitter, jitter_thresholds->critical->end, | ||
485 | TRUE, 0, FALSE, 0); | ||
486 | } | ||
487 | |||
488 | char *perfd_stratum (int stratum) | ||
489 | { | ||
490 | return perfdata ("stratum", stratum, "", | ||
491 | do_stratum, (int)stratum_thresholds->warning->end, | ||
492 | do_stratum, (int)stratum_thresholds->critical->end, | ||
493 | TRUE, 0, TRUE, 16); | ||
494 | } | ||
495 | |||
496 | int main(int argc, char *argv[]){ | ||
497 | int result, offset_result, stratum; | ||
498 | double offset=0, jitter=0; | ||
499 | char *result_line, *perfdata_line; | ||
500 | |||
501 | result = offset_result = STATE_OK; | ||
502 | |||
503 | if (process_arguments (argc, argv) == ERROR) | ||
504 | usage4 (_("Could not parse arguments")); | ||
505 | |||
506 | set_thresholds(&offset_thresholds, owarn, ocrit); | ||
507 | set_thresholds(&jitter_thresholds, jwarn, jcrit); | ||
508 | set_thresholds(&stratum_thresholds, swarn, scrit); | ||
509 | |||
510 | /* initialize alarm signal handling */ | ||
511 | signal (SIGALRM, socket_timeout_alarm_handler); | ||
512 | |||
513 | /* set socket timeout */ | ||
514 | alarm (socket_timeout); | ||
515 | |||
516 | result = ntp_request(server_address, &offset, &offset_result, &jitter, &stratum); | ||
517 | result = max_state_alt(result, get_status(fabs(offset), offset_thresholds)); | ||
518 | |||
519 | if(do_stratum) | ||
520 | result = max_state_alt(result, get_status(stratum, stratum_thresholds)); | ||
521 | |||
522 | if(do_jitter) | ||
523 | result = max_state_alt(result, get_status(jitter, jitter_thresholds)); | ||
524 | |||
525 | switch (result) { | ||
526 | case STATE_CRITICAL : | ||
527 | asprintf(&result_line, "NTP CRITICAL:"); | ||
528 | break; | ||
529 | case STATE_WARNING : | ||
530 | asprintf(&result_line, "NTP WARNING:"); | ||
531 | break; | ||
532 | case STATE_OK : | ||
533 | asprintf(&result_line, "NTP OK:"); | ||
534 | break; | ||
535 | default : | ||
536 | asprintf(&result_line, "NTP UNKNOWN:"); | ||
537 | break; | ||
538 | } | ||
539 | if(!syncsource_found) | ||
540 | asprintf(&result_line, "%s %s, ", result_line, _("Server not synchronized")); | ||
541 | |||
542 | if(offset_result == STATE_UNKNOWN){ | ||
543 | asprintf(&result_line, "%s %s", result_line, _("Offset unknown")); | ||
544 | asprintf(&perfdata_line, ""); | ||
545 | } else { | ||
546 | asprintf(&result_line, "%s Offset %.10g secs", result_line, offset); | ||
547 | asprintf(&perfdata_line, "%s", perfd_offset(offset)); | ||
548 | } | ||
549 | if (do_jitter) { | ||
550 | asprintf(&result_line, "%s, jitter=%f", result_line, jitter); | ||
551 | asprintf(&perfdata_line, "%s %s", perfdata_line, perfd_jitter(jitter)); | ||
552 | } | ||
553 | if (do_stratum) { | ||
554 | asprintf(&result_line, "%s, stratum=%i", result_line, stratum); | ||
555 | asprintf(&perfdata_line, "%s %s", perfdata_line, perfd_stratum(stratum)); | ||
556 | } | ||
557 | printf("%s|%s\n", result_line, perfdata_line); | ||
558 | |||
559 | if(server_address!=NULL) free(server_address); | ||
560 | return result; | ||
561 | } | ||
562 | |||
563 | |||
564 | |||
565 | void print_help(void){ | ||
566 | print_revision(progname, revision); | ||
567 | |||
568 | printf ("Copyright (c) 2006 Sean Finney\n"); | ||
569 | printf (COPYRIGHT, copyright, email); | ||
570 | |||
571 | printf ("%s\n", _("This plugin checks the selected ntp server")); | ||
572 | |||
573 | printf ("\n\n"); | ||
574 | |||
575 | print_usage(); | ||
576 | printf (_(UT_HELP_VRSN)); | ||
577 | printf (_(UT_HOST_PORT), 'p', "123"); | ||
578 | printf (" %s\n", "-w, --warning=THRESHOLD"); | ||
579 | printf (" %s\n", _("Offset to result in warning status (seconds)")); | ||
580 | printf (" %s\n", "-c, --critical=THRESHOLD"); | ||
581 | printf (" %s\n", _("Offset to result in critical status (seconds)")); | ||
582 | printf (" %s\n", "-W, --warning=THRESHOLD"); | ||
583 | printf (" %s\n", _("Warning threshold for stratum")); | ||
584 | printf (" %s\n", "-W, --critical=THRESHOLD"); | ||
585 | printf (" %s\n", _("Critical threshold for stratum")); | ||
586 | printf (" %s\n", "-j, --warning=THRESHOLD"); | ||
587 | printf (" %s\n", _("Warning threshold for jitter")); | ||
588 | printf (" %s\n", "-k, --critical=THRESHOLD"); | ||
589 | printf (" %s\n", _("Critical threshold for jitter")); | ||
590 | printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT); | ||
591 | printf (_(UT_VERBOSE)); | ||
592 | |||
593 | printf("\n"); | ||
594 | printf("%s\n", _("Notes:")); | ||
595 | printf(" %s\n", _("See:")); | ||
596 | printf(" %s\n", ("http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT")); | ||
597 | printf(" %s\n", _("for THRESHOLD format and examples.")); | ||
598 | |||
599 | printf("\n"); | ||
600 | printf("%s\n", _("Examples:")); | ||
601 | printf(" %s\n", _("Normal offset check:")); | ||
602 | printf(" %s\n", ("./check_ntp_peer -H ntpserv -w 0.5 -c 1")); | ||
603 | printf(" %s\n", _("Check jitter too, avoiding critical notifications if jitter isn't available")); | ||
604 | printf(" %s\n", _("(See Notes above for more details on thresholds formats):")); | ||
605 | printf(" %s\n", ("./check_ntp_peer -H ntpserv -w 0.5 -c 1 -j -1:100 -k -1:200")); | ||
606 | printf(" %s\n", _("Check only stratum:")); | ||
607 | printf(" %s\n", ("./check_ntp_peer -H ntpserv -W 4 -C 6")); | ||
608 | |||
609 | printf (_(UT_SUPPORT)); | ||
610 | } | ||
611 | |||
612 | void | ||
613 | print_usage(void) | ||
614 | { | ||
615 | printf (_("Usage:")); | ||
616 | printf(" %s -H <host> [-w <warn>] [-c <crit>] [-W <warn>] [-C <crit>]\n", progname); | ||
617 | printf(" [-j <warn>] [-k <crit>] [-v verbose]\n"); | ||
618 | } | ||