summaryrefslogtreecommitdiffstats
path: root/plugins/check_ntp_time.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_ntp_time.c')
-rw-r--r--plugins/check_ntp_time.c857
1 files changed, 489 insertions, 368 deletions
diff --git a/plugins/check_ntp_time.c b/plugins/check_ntp_time.c
index b2e16556..9e0beb9c 100644
--- a/plugins/check_ntp_time.c
+++ b/plugins/check_ntp_time.c
@@ -1,81 +1,83 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_ntp_time plugin 3 * Monitoring check_ntp_time plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2006 Sean Finney <seanius@seanius.net> 6 * Copyright (c) 2006 Sean Finney <seanius@seanius.net>
7* Copyright (c) 2006-2008 Monitoring Plugins Development Team 7 * Copyright (c) 2006-2024 Monitoring Plugins Development Team
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains the check_ntp_time plugin 11 * This file contains the check_ntp_time plugin
12* 12 *
13* This plugin checks the clock offset between the local host and a 13 * This plugin checks the clock offset between the local host and a
14* remote NTP server. It is independent of any commandline programs or 14 * remote NTP server. It is independent of any commandline programs or
15* external libraries. 15 * external libraries.
16* 16 *
17* If you'd rather want to monitor an NTP server, please use 17 * If you'd rather want to monitor an NTP server, please use
18* check_ntp_peer. 18 * check_ntp_peer.
19* 19 *
20* 20 *
21* This program is free software: you can redistribute it and/or modify 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 22 * it under the terms of the GNU General Public License as published by
23* the Free Software Foundation, either version 3 of the License, or 23 * the Free Software Foundation, either version 3 of the License, or
24* (at your option) any later version. 24 * (at your option) any later version.
25* 25 *
26* This program is distributed in the hope that it will be useful, 26 * This program is distributed in the hope that it will be useful,
27* but WITHOUT ANY WARRANTY; without even the implied warranty of 27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29* GNU General Public License for more details. 29 * GNU General Public License for more details.
30* 30 *
31* You should have received a copy of the GNU General Public License 31 * You should have received a copy of the GNU General Public License
32* along with this program. If not, see <http://www.gnu.org/licenses/>. 32 * along with this program. If not, see <http://www.gnu.org/licenses/>.
33* 33 *
34* 34 *
35*****************************************************************************/ 35 *****************************************************************************/
36 36
37const char *progname = "check_ntp_time"; 37#include "output.h"
38const char *copyright = "2006-2008";
39const char *email = "devel@monitoring-plugins.org";
40
41#include "common.h" 38#include "common.h"
42#include "netutils.h" 39#include "netutils.h"
40#include "perfdata.h"
43#include "utils.h" 41#include "utils.h"
42#include "states.h"
43#include "thresholds.h"
44#include "check_ntp_time.d/config.h"
45#include <netinet/in.h>
46#include <sys/socket.h>
44 47
45static char *server_address=NULL; 48static int verbose = 0;
46static char *port="123";
47static int verbose=0;
48static bool quiet = false;
49static char *owarn="60";
50static char *ocrit="120";
51static int time_offset=0;
52 49
53int process_arguments (int, char **); 50const char *progname = "check_ntp_time";
54thresholds *offset_thresholds = NULL; 51const char *copyright = "2006-2024";
55void print_help (void); 52const char *email = "devel@monitoring-plugins.org";
56void print_usage (void); 53
54typedef struct {
55 int errorcode;
56 check_ntp_time_config config;
57} check_ntp_time_config_wrapper;
58static check_ntp_time_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
59
60static void print_help(void);
61void print_usage(void);
57 62
58/* number of times to perform each request to get a good average. */ 63/* number of times to perform each request to get a good average. */
59#ifndef AVG_NUM 64#ifndef AVG_NUM
60#define AVG_NUM 4 65# define AVG_NUM 4
61#endif 66#endif
62 67
63/* max size of control message data */
64#define MAX_CM_SIZE 468
65
66/* this structure holds everything in an ntp request/response as per rfc1305 */ 68/* this structure holds everything in an ntp request/response as per rfc1305 */
67typedef struct { 69typedef struct {
68 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */ 70 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
69 uint8_t stratum; /* clock stratum */ 71 uint8_t stratum; /* clock stratum */
70 int8_t poll; /* polling interval */ 72 int8_t poll; /* polling interval */
71 int8_t precision; /* precision of the local clock */ 73 int8_t precision; /* precision of the local clock */
72 int32_t rtdelay; /* total rt delay, as a fixed point num. see macros */ 74 int32_t rtdelay; /* total rt delay, as a fixed point num. see macros */
73 uint32_t rtdisp; /* like above, but for max err to primary src */ 75 uint32_t rtdisp; /* like above, but for max err to primary src */
74 uint32_t refid; /* ref clock identifier */ 76 uint32_t refid; /* ref clock identifier */
75 uint64_t refts; /* reference timestamp. local time local clock */ 77 uint64_t refts; /* reference timestamp. local time local clock */
76 uint64_t origts; /* time at which request departed client */ 78 uint64_t origts; /* time at which request departed client */
77 uint64_t rxts; /* time at which request arrived at server */ 79 uint64_t rxts; /* time at which request arrived at server */
78 uint64_t txts; /* time at which request departed server */ 80 uint64_t txts; /* time at which request departed server */
79} ntp_message; 81} ntp_message;
80 82
81/* this structure holds data about results from querying offset from a peer */ 83/* this structure holds data about results from querying offset from a peer */
@@ -86,43 +88,55 @@ typedef struct {
86 double rtdelay; /* converted from the ntp_message */ 88 double rtdelay; /* converted from the ntp_message */
87 double rtdisp; /* converted from the ntp_message */ 89 double rtdisp; /* converted from the ntp_message */
88 double offset[AVG_NUM]; /* offsets from each response */ 90 double offset[AVG_NUM]; /* offsets from each response */
89 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */ 91 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
90} ntp_server_results; 92} ntp_server_results;
91 93
92/* bits 1,2 are the leap indicator */ 94/* bits 1,2 are the leap indicator */
93#define LI_MASK 0xc0 95#define LI_MASK 0xc0
94#define LI(x) ((x&LI_MASK)>>6) 96#define LI(x) ((x & LI_MASK) >> 6)
95#define LI_SET(x,y) do{ x |= ((y<<6)&LI_MASK); }while(0) 97#define LI_SET(x, y) \
98 do { \
99 x |= ((y << 6) & LI_MASK); \
100 } while (0)
96/* and these are the values of the leap indicator */ 101/* and these are the values of the leap indicator */
97#define LI_NOWARNING 0x00 102#define LI_NOWARNING 0x00
98#define LI_EXTRASEC 0x01 103#define LI_EXTRASEC 0x01
99#define LI_MISSINGSEC 0x02 104#define LI_MISSINGSEC 0x02
100#define LI_ALARM 0x03 105#define LI_ALARM 0x03
101/* bits 3,4,5 are the ntp version */ 106/* bits 3,4,5 are the ntp version */
102#define VN_MASK 0x38 107#define VN_MASK 0x38
103#define VN(x) ((x&VN_MASK)>>3) 108#define VN(x) ((x & VN_MASK) >> 3)
104#define VN_SET(x,y) do{ x |= ((y<<3)&VN_MASK); }while(0) 109#define VN_SET(x, y) \
110 do { \
111 x |= ((y << 3) & VN_MASK); \
112 } while (0)
105#define VN_RESERVED 0x02 113#define VN_RESERVED 0x02
106/* bits 6,7,8 are the ntp mode */ 114/* bits 6,7,8 are the ntp mode */
107#define MODE_MASK 0x07 115#define MODE_MASK 0x07
108#define MODE(x) (x&MODE_MASK) 116#define MODE(x) (x & MODE_MASK)
109#define MODE_SET(x,y) do{ x |= (y&MODE_MASK); }while(0) 117#define MODE_SET(x, y) \
118 do { \
119 x |= (y & MODE_MASK); \
120 } while (0)
110/* here are some values */ 121/* here are some values */
111#define MODE_CLIENT 0x03 122#define MODE_CLIENT 0x03
112#define MODE_CONTROLMSG 0x06 123#define MODE_CONTROLMSG 0x06
113/* In control message, bits 8-10 are R,E,M bits */ 124/* In control message, bits 8-10 are R,E,M bits */
114#define REM_MASK 0xe0 125#define REM_MASK 0xe0
115#define REM_RESP 0x80 126#define REM_RESP 0x80
116#define REM_ERROR 0x40 127#define REM_ERROR 0x40
117#define REM_MORE 0x20 128#define REM_MORE 0x20
118/* In control message, bits 11 - 15 are opcode */ 129/* In control message, bits 11 - 15 are opcode */
119#define OP_MASK 0x1f 130#define OP_MASK 0x1f
120#define OP_SET(x,y) do{ x |= (y&OP_MASK); }while(0) 131#define OP_SET(x, y) \
132 do { \
133 x |= (y & OP_MASK); \
134 } while (0)
121#define OP_READSTAT 0x01 135#define OP_READSTAT 0x01
122#define OP_READVAR 0x02 136#define OP_READVAR 0x02
123/* In peer status bytes, bits 6,7,8 determine clock selection status */ 137/* In peer status bytes, bits 6,7,8 determine clock selection status */
124#define PEER_SEL(x) ((ntohs(x)>>8)&0x07) 138#define PEER_SEL(x) ((ntohs(x) >> 8) & 0x07)
125#define PEER_INCLUDED 0x04 139#define PEER_INCLUDED 0x04
126#define PEER_SYNCSOURCE 0x06 140#define PEER_SYNCSOURCE 0x06
127 141
128/** 142/**
@@ -136,164 +150,175 @@ typedef struct {
136 150
137/* macros to access the left/right 16 bits of a 32-bit ntp "fixed point" 151/* macros to access the left/right 16 bits of a 32-bit ntp "fixed point"
138 number. note that these can be used as lvalues too */ 152 number. note that these can be used as lvalues too */
139#define L16(x) (((uint16_t*)&x)[0]) 153#define L16(x) (((uint16_t *)&x)[0])
140#define R16(x) (((uint16_t*)&x)[1]) 154#define R16(x) (((uint16_t *)&x)[1])
141/* macros to access the left/right 32 bits of a 64-bit ntp "fixed point" 155/* macros to access the left/right 32 bits of a 64-bit ntp "fixed point"
142 number. these too can be used as lvalues */ 156 number. these too can be used as lvalues */
143#define L32(x) (((uint32_t*)&x)[0]) 157#define L32(x) (((uint32_t *)&x)[0])
144#define R32(x) (((uint32_t*)&x)[1]) 158#define R32(x) (((uint32_t *)&x)[1])
145 159
146/* ntp wants seconds since 1/1/00, epoch is 1/1/70. this is the difference */ 160/* ntp wants seconds since 1/1/00, epoch is 1/1/70. this is the difference */
147#define EPOCHDIFF 0x83aa7e80UL 161#define EPOCHDIFF 0x83aa7e80UL
148 162
149/* extract a 32-bit ntp fixed point number into a double */ 163/* extract a 32-bit ntp fixed point number into a double */
150#define NTP32asDOUBLE(x) (ntohs(L16(x)) + (double)ntohs(R16(x))/65536.0) 164#define NTP32asDOUBLE(x) (ntohs(L16(x)) + ((double)ntohs(R16(x)) / 65536.0))
151 165
152/* likewise for a 64-bit ntp fp number */ 166/* likewise for a 64-bit ntp fp number */
153#define NTP64asDOUBLE(n) (double)(((uint64_t)n)?\ 167#define NTP64asDOUBLE(n) \
154 (ntohl(L32(n))-EPOCHDIFF) + \ 168 (double)(((uint64_t)n) ? (ntohl(L32(n)) - EPOCHDIFF) + \
155 (.00000001*(0.5+(double)(ntohl(R32(n))/42.94967296))):\ 169 (.00000001 * (0.5 + (double)(ntohl(R32(n)) / 42.94967296))) \
156 0) 170 : 0)
157 171
158/* convert a struct timeval to a double */ 172/* convert a struct timeval to a double */
159#define TVasDOUBLE(x) (double)(x.tv_sec+(0.000001*x.tv_usec)) 173static double TVasDOUBLE(struct timeval time) {
174 return ((double)time.tv_sec + (0.000001 * (double)time.tv_usec));
175}
160 176
161/* convert an ntp 64-bit fp number to a struct timeval */ 177/* convert an ntp 64-bit fp number to a struct timeval */
162#define NTP64toTV(n,t) \ 178#define NTP64toTV(n, t) \
163 do{ if(!n) t.tv_sec = t.tv_usec = 0; \ 179 do { \
164 else { \ 180 if (!n) \
165 t.tv_sec=ntohl(L32(n))-EPOCHDIFF; \ 181 t.tv_sec = t.tv_usec = 0; \
166 t.tv_usec=(int)(0.5+(double)(ntohl(R32(n))/4294.967296)); \ 182 else { \
167 } \ 183 t.tv_sec = ntohl(L32(n)) - EPOCHDIFF; \
168 }while(0) 184 t.tv_usec = (int)(0.5 + (double)(ntohl(R32(n)) / 4294.967296)); \
185 } \
186 } while (0)
169 187
170/* convert a struct timeval to an ntp 64-bit fp number */ 188/* convert a struct timeval to an ntp 64-bit fp number */
171#define TVtoNTP64(t,n) \ 189#define TVtoNTP64(t, n) \
172 do{ if(!t.tv_usec && !t.tv_sec) n=0x0UL; \ 190 do { \
173 else { \ 191 if (!t.tv_usec && !t.tv_sec) \
174 L32(n)=htonl(t.tv_sec + EPOCHDIFF); \ 192 n = 0x0UL; \
175 R32(n)=htonl((uint64_t)((4294.967296*t.tv_usec)+.5)); \ 193 else { \
176 } \ 194 L32(n) = htonl(t.tv_sec + EPOCHDIFF); \
177 } while(0) 195 R32(n) = htonl((uint64_t)((4294.967296 * t.tv_usec) + .5)); \
196 } \
197 } while (0)
178 198
179/* NTP control message header is 12 bytes, plus any data in the data 199/* NTP control message header is 12 bytes, plus any data in the data
180 * field, plus null padding to the nearest 32-bit boundary per rfc. 200 * field, plus null padding to the nearest 32-bit boundary per rfc.
181 */ 201 */
182#define SIZEOF_NTPCM(m) (12+ntohs(m.count)+((m.count)?4-(ntohs(m.count)%4):0)) 202#define SIZEOF_NTPCM(m) (12 + ntohs(m.count) + ((m.count) ? 4 - (ntohs(m.count) % 4) : 0))
183 203
184/* finally, a little helper or two for debugging: */ 204/* finally, a little helper or two for debugging: */
185#define DBG(x) do{if(verbose>1){ x; }}while(0); 205#define DBG(x) \
186#define PRINTSOCKADDR(x) \ 206 do { \
187 do{ \ 207 if (verbose > 1) { \
188 printf("%u.%u.%u.%u", (x>>24)&0xff, (x>>16)&0xff, (x>>8)&0xff, x&0xff);\ 208 x; \
189 }while(0); 209 } \
210 } while (0);
211#define PRINTSOCKADDR(x) \
212 do { \
213 printf("%u.%u.%u.%u", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); \
214 } while (0);
190 215
191/* calculate the offset of the local clock */ 216/* calculate the offset of the local clock */
192static inline double calc_offset(const ntp_message *m, const struct timeval *t){ 217static inline double calc_offset(const ntp_message *message, const struct timeval *time_value) {
193 double client_tx, peer_rx, peer_tx, client_rx; 218 double client_tx = NTP64asDOUBLE(message->origts);
194 client_tx = NTP64asDOUBLE(m->origts); 219 double peer_rx = NTP64asDOUBLE(message->rxts);
195 peer_rx = NTP64asDOUBLE(m->rxts); 220 double peer_tx = NTP64asDOUBLE(message->txts);
196 peer_tx = NTP64asDOUBLE(m->txts); 221 double client_rx = TVasDOUBLE((*time_value));
197 client_rx=TVasDOUBLE((*t)); 222 return (((peer_tx - client_rx) + (peer_rx - client_tx)) / 2);
198 return (.5*((peer_tx-client_rx)+(peer_rx-client_tx)));
199} 223}
200 224
201/* print out a ntp packet in human readable/debuggable format */ 225/* print out a ntp packet in human readable/debuggable format */
202void print_ntp_message(const ntp_message *p){ 226void print_ntp_message(const ntp_message *message) {
203 struct timeval ref, orig, rx, tx; 227 struct timeval ref;
228 struct timeval orig;
204 229
205 NTP64toTV(p->refts,ref); 230 NTP64toTV(message->refts, ref);
206 NTP64toTV(p->origts,orig); 231 NTP64toTV(message->origts, orig);
207 NTP64toTV(p->rxts,rx);
208 NTP64toTV(p->txts,tx);
209 232
210 printf("packet contents:\n"); 233 printf("packet contents:\n");
211 printf("\tflags: 0x%.2x\n", p->flags); 234 printf("\tflags: 0x%.2x\n", message->flags);
212 printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags&LI_MASK); 235 printf("\t li=%d (0x%.2x)\n", LI(message->flags), message->flags & LI_MASK);
213 printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags&VN_MASK); 236 printf("\t vn=%d (0x%.2x)\n", VN(message->flags), message->flags & VN_MASK);
214 printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags&MODE_MASK); 237 printf("\t mode=%d (0x%.2x)\n", MODE(message->flags), message->flags & MODE_MASK);
215 printf("\tstratum = %d\n", p->stratum); 238 printf("\tstratum = %d\n", message->stratum);
216 printf("\tpoll = %g\n", pow(2, p->poll)); 239 printf("\tpoll = %g\n", pow(2, message->poll));
217 printf("\tprecision = %g\n", pow(2, p->precision)); 240 printf("\tprecision = %g\n", pow(2, message->precision));
218 printf("\trtdelay = %-.16g\n", NTP32asDOUBLE(p->rtdelay)); 241 printf("\trtdelay = %-.16g\n", NTP32asDOUBLE(message->rtdelay));
219 printf("\trtdisp = %-.16g\n", NTP32asDOUBLE(p->rtdisp)); 242 printf("\trtdisp = %-.16g\n", NTP32asDOUBLE(message->rtdisp));
220 printf("\trefid = %x\n", p->refid); 243 printf("\trefid = %x\n", message->refid);
221 printf("\trefts = %-.16g\n", NTP64asDOUBLE(p->refts)); 244 printf("\trefts = %-.16g\n", NTP64asDOUBLE(message->refts));
222 printf("\torigts = %-.16g\n", NTP64asDOUBLE(p->origts)); 245 printf("\torigts = %-.16g\n", NTP64asDOUBLE(message->origts));
223 printf("\trxts = %-.16g\n", NTP64asDOUBLE(p->rxts)); 246 printf("\trxts = %-.16g\n", NTP64asDOUBLE(message->rxts));
224 printf("\ttxts = %-.16g\n", NTP64asDOUBLE(p->txts)); 247 printf("\ttxts = %-.16g\n", NTP64asDOUBLE(message->txts));
225} 248}
226 249
227void setup_request(ntp_message *p){ 250void setup_request(ntp_message *message) {
228 struct timeval t; 251 memset(message, 0, sizeof(ntp_message));
229 252 LI_SET(message->flags, LI_ALARM);
230 memset(p, 0, sizeof(ntp_message)); 253 VN_SET(message->flags, 4);
231 LI_SET(p->flags, LI_ALARM); 254 MODE_SET(message->flags, MODE_CLIENT);
232 VN_SET(p->flags, 4); 255 message->poll = 4;
233 MODE_SET(p->flags, MODE_CLIENT); 256 message->precision = (int8_t)0xfa;
234 p->poll=4; 257 L16(message->rtdelay) = htons(1);
235 p->precision=(int8_t)0xfa; 258 L16(message->rtdisp) = htons(1);
236 L16(p->rtdelay)=htons(1);
237 L16(p->rtdisp)=htons(1);
238 259
260 struct timeval t;
239 gettimeofday(&t, NULL); 261 gettimeofday(&t, NULL);
240 TVtoNTP64(t,p->txts); 262 TVtoNTP64(t, message->txts);
241} 263}
242 264
243/* select the "best" server from a list of servers, and return its index. 265/* select the "best" server from a list of servers, and return its index.
244 * this is done by filtering servers based on stratum, dispersion, and 266 * this is done by filtering servers based on stratum, dispersion, and
245 * finally round-trip delay. */ 267 * finally round-trip delay. */
246int best_offset_server(const ntp_server_results *slist, int nservers){ 268static int best_offset_server(const ntp_server_results *slist, int nservers) {
247 int cserver=0, best_server=-1; 269 int best_server_index = -1;
248 270
249 /* for each server */ 271 /* for each server */
250 for(cserver=0; cserver<nservers; cserver++){ 272 for (int cserver = 0; cserver < nservers; cserver++) {
251 /* We don't want any servers that fails these tests */ 273 /* We don't want any servers that fails these tests */
252 /* Sort out servers that didn't respond or responede with a 0 stratum; 274 /* Sort out servers that didn't respond or responede with a 0 stratum;
253 * stratum 0 is for reference clocks so no NTP server should ever report 275 * stratum 0 is for reference clocks so no NTP server should ever report
254 * a stratum 0 */ 276 * a stratum 0 */
255 if ( slist[cserver].stratum == 0){ 277 if (slist[cserver].stratum == 0) {
256 if (verbose) printf("discarding peer %d: stratum=%d\n", cserver, slist[cserver].stratum); 278 if (verbose) {
279 printf("discarding peer %d: stratum=%d\n", cserver, slist[cserver].stratum);
280 }
257 continue; 281 continue;
258 } 282 }
259 /* Sort out servers with error flags */ 283 /* Sort out servers with error flags */
260 if ( LI(slist[cserver].flags) == LI_ALARM ){ 284 if (LI(slist[cserver].flags) == LI_ALARM) {
261 if (verbose) printf("discarding peer %d: flags=%d\n", cserver, LI(slist[cserver].flags)); 285 if (verbose) {
286 printf("discarding peer %d: flags=%d\n", cserver, LI(slist[cserver].flags));
287 }
262 continue; 288 continue;
263 } 289 }
264 290
265 /* If we don't have a server yet, use the first one */ 291 /* If we don't have a server yet, use the first one */
266 if (best_server == -1) { 292 if (best_server_index == -1) {
267 best_server = cserver; 293 best_server_index = cserver;
268 DBG(printf("using peer %d as our first candidate\n", best_server)); 294 DBG(printf("using peer %d as our first candidate\n", best_server_index));
269 continue; 295 continue;
270 } 296 }
271 297
272 /* compare the server to the best one we've seen so far */ 298 /* compare the server to the best one we've seen so far */
273 /* does it have an equal or better stratum? */ 299 /* does it have an equal or better stratum? */
274 DBG(printf("comparing peer %d with peer %d\n", cserver, best_server)); 300 DBG(printf("comparing peer %d with peer %d\n", cserver, best_server_index));
275 if(slist[cserver].stratum <= slist[best_server].stratum){ 301 if (slist[cserver].stratum <= slist[best_server_index].stratum) {
276 DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server)); 302 DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server_index));
277 /* does it have an equal or better dispersion? */ 303 /* does it have an equal or better dispersion? */
278 if(slist[cserver].rtdisp <= slist[best_server].rtdisp){ 304 if (slist[cserver].rtdisp <= slist[best_server_index].rtdisp) {
279 DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server)); 305 DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server_index));
280 /* does it have a better rtdelay? */ 306 /* does it have a better rtdelay? */
281 if(slist[cserver].rtdelay < slist[best_server].rtdelay){ 307 if (slist[cserver].rtdelay < slist[best_server_index].rtdelay) {
282 DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server)); 308 DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server_index));
283 best_server = cserver; 309 best_server_index = cserver;
284 DBG(printf("peer %d is now our best candidate\n", best_server)); 310 DBG(printf("peer %d is now our best candidate\n", best_server_index));
285 } 311 }
286 } 312 }
287 } 313 }
288 } 314 }
289 315
290 if(best_server >= 0) { 316 if (best_server_index >= 0) {
291 DBG(printf("best server selected: peer %d\n", best_server)); 317 DBG(printf("best server selected: peer %d\n", best_server_index));
292 return best_server; 318 return best_server_index;
293 } else {
294 DBG(printf("no peers meeting synchronization criteria :(\n"));
295 return -1;
296 } 319 }
320 DBG(printf("no peers meeting synchronization criteria :(\n"));
321 return -1;
297} 322}
298 323
299/* do everything we need to get the total average offset 324/* do everything we need to get the total average offset
@@ -301,178 +326,269 @@ int best_offset_server(const ntp_server_results *slist, int nservers){
301 * we don't waste time sitting around waiting for single packets. 326 * we don't waste time sitting around waiting for single packets.
302 * - we also "manually" handle resolving host names and connecting, because 327 * - we also "manually" handle resolving host names and connecting, because
303 * we have to do it in a way that our lazy macros don't handle currently :( */ 328 * we have to do it in a way that our lazy macros don't handle currently :( */
304double offset_request(const char *host, int *status){ 329typedef struct {
305 int i=0, j=0, ga_result=0, num_hosts=0, *socklist=NULL, respnum=0; 330 mp_state_enum offset_result;
306 int servers_completed=0, one_read=0, servers_readable=0, best_index=-1; 331 double offset;
307 time_t now_time=0, start_ts=0; 332} offset_request_wrapper;
308 ntp_message *req=NULL; 333static offset_request_wrapper offset_request(const char *host, const char *port, int time_offset) {
309 double avg_offset=0.;
310 struct timeval recv_time;
311 struct addrinfo *ai=NULL, *ai_tmp=NULL, hints;
312 struct pollfd *ufds=NULL;
313 ntp_server_results *servers=NULL;
314
315 /* setup hints to only return results from getaddrinfo that we'd like */ 334 /* setup hints to only return results from getaddrinfo that we'd like */
335 struct addrinfo hints;
316 memset(&hints, 0, sizeof(struct addrinfo)); 336 memset(&hints, 0, sizeof(struct addrinfo));
317 hints.ai_family = address_family; 337 hints.ai_family = address_family;
318 hints.ai_protocol = IPPROTO_UDP; 338 hints.ai_protocol = IPPROTO_UDP;
319 hints.ai_socktype = SOCK_DGRAM; 339 hints.ai_socktype = SOCK_DGRAM;
320 340
321 /* fill in ai with the list of hosts resolved by the host name */ 341 bool is_socket;
322 ga_result = getaddrinfo(host, port, &hints, &ai); 342 struct addrinfo *addresses = NULL;
323 if(ga_result!=0){ 343 size_t num_hosts = 0;
324 die(STATE_UNKNOWN, "error getting address for %s: %s\n", 344 if (host[0] == '/') {
325 host, gai_strerror(ga_result)); 345 num_hosts = 1;
346 is_socket = true;
347 } else {
348 is_socket = false;
349
350 /* fill in ai with the list of hosts resolved by the host name */
351 int ga_result = getaddrinfo(host, port, &hints, &addresses);
352 if (ga_result != 0) {
353 die(STATE_UNKNOWN, "error getting address for %s: %s\n", host, gai_strerror(ga_result));
354 }
355
356 /* count the number of returned hosts, and allocate stuff accordingly */
357 for (struct addrinfo *ai_tmp = addresses; ai_tmp != NULL; ai_tmp = ai_tmp->ai_next) {
358 num_hosts++;
359 }
360 }
361
362 ntp_message *req = (ntp_message *)malloc(sizeof(ntp_message) * num_hosts);
363
364 if (req == NULL) {
365 die(STATE_UNKNOWN, "can not allocate ntp message array");
326 } 366 }
367 int *socklist = (int *)malloc(sizeof(int) * num_hosts);
327 368
328 /* count the number of returned hosts, and allocate stuff accordingly */ 369 if (socklist == NULL) {
329 for(ai_tmp=ai; ai_tmp!=NULL; ai_tmp=ai_tmp->ai_next){ num_hosts++; } 370 die(STATE_UNKNOWN, "can not allocate socket array");
330 req=(ntp_message*)malloc(sizeof(ntp_message)*num_hosts); 371 }
331 if(req==NULL) die(STATE_UNKNOWN, "can not allocate ntp message array"); 372
332 socklist=(int*)malloc(sizeof(int)*num_hosts); 373 struct pollfd *ufds = (struct pollfd *)malloc(sizeof(struct pollfd) * num_hosts);
333 if(socklist==NULL) die(STATE_UNKNOWN, "can not allocate socket array"); 374 if (ufds == NULL) {
334 ufds=(struct pollfd*)malloc(sizeof(struct pollfd)*num_hosts); 375 die(STATE_UNKNOWN, "can not allocate socket array");
335 if(ufds==NULL) die(STATE_UNKNOWN, "can not allocate socket array"); 376 }
336 servers=(ntp_server_results*)malloc(sizeof(ntp_server_results)*num_hosts); 377
337 if(servers==NULL) die(STATE_UNKNOWN, "can not allocate server array"); 378 ntp_server_results *servers =
338 memset(servers, 0, sizeof(ntp_server_results)*num_hosts); 379 (ntp_server_results *)malloc(sizeof(ntp_server_results) * num_hosts);
339 DBG(printf("Found %d peers to check\n", num_hosts)); 380 if (servers == NULL) {
381 die(STATE_UNKNOWN, "can not allocate server array");
382 }
383 memset(servers, 0, sizeof(ntp_server_results) * num_hosts);
384 DBG(printf("Found %zu peers to check\n", num_hosts));
340 385
341 /* setup each socket for writing, and the corresponding struct pollfd */ 386 /* setup each socket for writing, and the corresponding struct pollfd */
342 ai_tmp=ai; 387 if (is_socket) {
343 for(i=0;ai_tmp;i++){ 388 socklist[0] = socket(AF_UNIX, SOCK_STREAM, 0);
344 socklist[i]=socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP); 389 if (socklist[0] == -1) {
345 if(socklist[i] == -1) { 390 DBG(printf("can't create socket: %s\n", strerror(errno)));
346 perror(NULL); 391 die(STATE_UNKNOWN, "can not create new socket\n");
347 die(STATE_UNKNOWN, "can not create new socket");
348 } 392 }
349 if(connect(socklist[i], ai_tmp->ai_addr, ai_tmp->ai_addrlen)){ 393
394 struct sockaddr_un unix_socket = {
395 .sun_family = AF_UNIX,
396 };
397
398 strncpy(unix_socket.sun_path, host, strlen(host));
399
400 if (connect(socklist[0], &unix_socket, sizeof(unix_socket))) {
350 /* don't die here, because it is enough if there is one server 401 /* don't die here, because it is enough if there is one server
351 answering in time. This also would break for dual ipv4/6 stacked 402 answering in time. This also would break for dual ipv4/6 stacked
352 ntp servers when the client only supports on of them. 403 ntp servers when the client only supports on of them.
353 */ 404 */
354 DBG(printf("can't create socket connection on peer %i: %s\n", i, strerror(errno))); 405 DBG(printf("can't create socket connection on peer %i: %s\n", 0, strerror(errno)));
355 } else { 406 } else {
356 ufds[i].fd=socklist[i]; 407 ufds[0].fd = socklist[0];
357 ufds[i].events=POLLIN; 408 ufds[0].events = POLLIN;
358 ufds[i].revents=0; 409 ufds[0].revents = 0;
410 }
411 } else {
412 struct addrinfo *ai_tmp = addresses;
413 for (int i = 0; ai_tmp; i++) {
414 socklist[i] = socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP);
415 if (socklist[i] == -1) {
416 perror(NULL);
417 die(STATE_UNKNOWN, "can not create new socket");
418 }
419 if (connect(socklist[i], ai_tmp->ai_addr, ai_tmp->ai_addrlen)) {
420 /* don't die here, because it is enough if there is one server
421 answering in time. This also would break for dual ipv4/6 stacked
422 ntp servers when the client only supports on of them.
423 */
424 DBG(printf("can't create socket connection on peer %i: %s\n", i, strerror(errno)));
425 } else {
426 ufds[i].fd = socklist[i];
427 ufds[i].events = POLLIN;
428 ufds[i].revents = 0;
429 }
430 ai_tmp = ai_tmp->ai_next;
359 } 431 }
360 ai_tmp = ai_tmp->ai_next;
361 } 432 }
362 433
363 /* now do AVG_NUM checks to each host. We stop before timeout/2 seconds 434 /* now do AVG_NUM checks to each host. We stop before timeout/2 seconds
364 * have passed in order to ensure post-processing and jitter time. */ 435 * have passed in order to ensure post-processing and jitter time. */
365 now_time=start_ts=time(NULL); 436 time_t start_ts = 0;
366 while(servers_completed<num_hosts && now_time-start_ts <= socket_timeout/2){ 437 time_t now_time = 0;
438 now_time = start_ts = time(NULL);
439 size_t servers_completed = 0;
440 bool one_read = false;
441 while (servers_completed < num_hosts && now_time - start_ts <= socket_timeout / 2) {
367 /* loop through each server and find each one which hasn't 442 /* loop through each server and find each one which hasn't
368 * been touched in the past second or so and is still lacking 443 * been touched in the past second or so and is still lacking
369 * some responses. For each of these servers, send a new request, 444 * some responses. For each of these servers, send a new request,
370 * and update the "waiting" timestamp with the current time. */ 445 * and update the "waiting" timestamp with the current time. */
371 now_time=time(NULL); 446 now_time = time(NULL);
372 447
373 for(i=0; i<num_hosts; i++){ 448 for (size_t i = 0; i < num_hosts; i++) {
374 if(servers[i].waiting<now_time && servers[i].num_responses<AVG_NUM){ 449 if (servers[i].waiting < now_time && servers[i].num_responses < AVG_NUM) {
375 if(verbose && servers[i].waiting != 0) printf("re-"); 450 if (verbose && servers[i].waiting != 0) {
376 if(verbose) printf("sending request to peer %d\n", i); 451 printf("re-");
452 }
453 if (verbose) {
454 printf("sending request to peer %zu\n", i);
455 }
377 setup_request(&req[i]); 456 setup_request(&req[i]);
378 write(socklist[i], &req[i], sizeof(ntp_message)); 457 write(socklist[i], &req[i], sizeof(ntp_message));
379 servers[i].waiting=now_time; 458 servers[i].waiting = now_time;
380 break; 459 break;
381 } 460 }
382 } 461 }
383 462
384 /* quickly poll for any sockets with pending data */ 463 /* quickly poll for any sockets with pending data */
385 servers_readable=poll(ufds, num_hosts, 100); 464 int servers_readable = poll(ufds, num_hosts, 100);
386 if(servers_readable==-1){ 465 if (servers_readable == -1) {
387 perror("polling ntp sockets"); 466 perror("polling ntp sockets");
388 die(STATE_UNKNOWN, "communication errors"); 467 die(STATE_UNKNOWN, "communication errors");
389 } 468 }
390 469
391 /* read from any sockets with pending data */ 470 /* read from any sockets with pending data */
392 for(i=0; servers_readable && i<num_hosts; i++){ 471 for (size_t i = 0; servers_readable && i < num_hosts; i++) {
393 if(ufds[i].revents&POLLIN && servers[i].num_responses < AVG_NUM){ 472 if (ufds[i].revents & POLLIN && servers[i].num_responses < AVG_NUM) {
394 if(verbose) { 473 if (verbose) {
395 printf("response from peer %d: ", i); 474 printf("response from peer %zu: ", i);
396 } 475 }
397 476
398 read(ufds[i].fd, &req[i], sizeof(ntp_message)); 477 read(ufds[i].fd, &req[i], sizeof(ntp_message));
478
479 struct timeval recv_time;
399 gettimeofday(&recv_time, NULL); 480 gettimeofday(&recv_time, NULL);
400 DBG(print_ntp_message(&req[i])); 481 DBG(print_ntp_message(&req[i]));
401 respnum=servers[i].num_responses++; 482 int respnum = servers[i].num_responses++;
402 servers[i].offset[respnum]=calc_offset(&req[i], &recv_time)+time_offset; 483 servers[i].offset[respnum] = calc_offset(&req[i], &recv_time) + time_offset;
403 if(verbose) { 484 if (verbose) {
404 printf("offset %.10g\n", servers[i].offset[respnum]); 485 printf("offset %.10g\n", servers[i].offset[respnum]);
405 } 486 }
406 servers[i].stratum=req[i].stratum; 487 servers[i].stratum = req[i].stratum;
407 servers[i].rtdisp=NTP32asDOUBLE(req[i].rtdisp); 488 servers[i].rtdisp = NTP32asDOUBLE(req[i].rtdisp);
408 servers[i].rtdelay=NTP32asDOUBLE(req[i].rtdelay); 489 servers[i].rtdelay = NTP32asDOUBLE(req[i].rtdelay);
409 servers[i].waiting=0; 490 servers[i].waiting = 0;
410 servers[i].flags=req[i].flags; 491 servers[i].flags = req[i].flags;
411 servers_readable--; 492 servers_readable--;
412 one_read = 1; 493 one_read = true;
413 if(servers[i].num_responses==AVG_NUM) servers_completed++; 494 if (servers[i].num_responses == AVG_NUM) {
495 servers_completed++;
496 }
414 } 497 }
415 } 498 }
416 /* lather, rinse, repeat. */ 499 /* lather, rinse, repeat. */
417 } 500 }
418 501
419 if (one_read == 0) { 502 if (!one_read) {
420 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n"); 503 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
421 } 504 }
422 505
506 offset_request_wrapper result = {
507 .offset = 0,
508 .offset_result = STATE_UNKNOWN,
509 };
510
423 /* now, pick the best server from the list */ 511 /* now, pick the best server from the list */
424 best_index=best_offset_server(servers, num_hosts); 512 double avg_offset = 0.;
425 if(best_index < 0){ 513 int best_index = best_offset_server(servers, num_hosts);
426 *status=STATE_UNKNOWN; 514 if (best_index < 0) {
515 result.offset_result = STATE_UNKNOWN;
427 } else { 516 } else {
517 result.offset_result = STATE_OK;
428 /* finally, calculate the average offset */ 518 /* finally, calculate the average offset */
429 for(i=0; i<servers[best_index].num_responses;i++){ 519 for (int i = 0; i < servers[best_index].num_responses; i++) {
430 avg_offset+=servers[best_index].offset[i]; 520 avg_offset += servers[best_index].offset[i];
431 } 521 }
432 avg_offset/=servers[best_index].num_responses; 522 avg_offset /= servers[best_index].num_responses;
433 } 523 }
434 524
435 /* cleanup */ 525 /* cleanup */
436 for(j=0; j<num_hosts; j++){ close(socklist[j]); } 526 for (size_t j = 0; j < num_hosts; j++) {
527 close(socklist[j]);
528 }
437 free(socklist); 529 free(socklist);
438 free(ufds); 530 free(ufds);
439 free(servers); 531 free(servers);
440 free(req); 532 free(req);
441 freeaddrinfo(ai); 533 freeaddrinfo(addresses);
534
535 if (verbose) {
536 printf("overall average offset: %.10g\n", avg_offset);
537 }
442 538
443 if(verbose) printf("overall average offset: %.10g\n", avg_offset); 539 result.offset = avg_offset;
444 return avg_offset; 540 return result;
445} 541}
446 542
447int process_arguments(int argc, char **argv){ 543static check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
448 int c; 544
449 int option=0; 545 enum {
450 static struct option longopts[] = { 546 output_format_index = CHAR_MAX + 1,
451 {"version", no_argument, 0, 'V'},
452 {"help", no_argument, 0, 'h'},
453 {"verbose", no_argument, 0, 'v'},
454 {"use-ipv4", no_argument, 0, '4'},
455 {"use-ipv6", no_argument, 0, '6'},
456 {"quiet", no_argument, 0, 'q'},
457 {"time-offset", optional_argument, 0, 'o'},
458 {"warning", required_argument, 0, 'w'},
459 {"critical", required_argument, 0, 'c'},
460 {"timeout", required_argument, 0, 't'},
461 {"hostname", required_argument, 0, 'H'},
462 {"port", required_argument, 0, 'p'},
463 {0, 0, 0, 0}
464 }; 547 };
465 548
549 static struct option longopts[] = {{"version", no_argument, 0, 'V'},
550 {"help", no_argument, 0, 'h'},
551 {"verbose", no_argument, 0, 'v'},
552 {"use-ipv4", no_argument, 0, '4'},
553 {"use-ipv6", no_argument, 0, '6'},
554 {"quiet", no_argument, 0, 'q'},
555 {"time-offset", required_argument, 0, 'o'},
556 {"warning", required_argument, 0, 'w'},
557 {"critical", required_argument, 0, 'c'},
558 {"timeout", required_argument, 0, 't'},
559 {"hostname", required_argument, 0, 'H'},
560 {"port", required_argument, 0, 'p'},
561 {"output-format", required_argument, 0, output_format_index},
562 {0, 0, 0, 0}};
563
564 if (argc < 2) {
565 usage("\n");
566 }
466 567
467 if (argc < 2) 568 check_ntp_time_config_wrapper result = {
468 usage ("\n"); 569 .errorcode = OK,
570 .config = check_ntp_time_config_init(),
571 };
469 572
470 while (1) { 573 while (true) {
471 c = getopt_long (argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option); 574 int option = 0;
472 if (c == -1 || c == EOF || c == 1) 575 int option_char = getopt_long(argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option);
576 if (option_char == -1 || option_char == EOF || option_char == 1) {
473 break; 577 break;
578 }
579
580 switch (option_char) {
581 case output_format_index: {
582 parsed_output_format parser = mp_parse_output_format(optarg);
583 if (!parser.parsing_success) {
584 printf("Invalid output format: %s\n", optarg);
585 exit(STATE_UNKNOWN);
586 }
474 587
475 switch (c) { 588 result.config.output_format_is_set = true;
589 result.config.output_format = parser.output_format;
590 break;
591 }
476 case 'h': 592 case 'h':
477 print_help(); 593 print_help();
478 exit(STATE_UNKNOWN); 594 exit(STATE_UNKNOWN);
@@ -485,28 +601,41 @@ int process_arguments(int argc, char **argv){
485 verbose++; 601 verbose++;
486 break; 602 break;
487 case 'q': 603 case 'q':
488 quiet = true; 604 result.config.quiet = true;
489 break;
490 case 'w':
491 owarn = optarg;
492 break;
493 case 'c':
494 ocrit = optarg;
495 break; 605 break;
606 case 'w': {
607 mp_range_parsed tmp = mp_parse_range_string(optarg);
608 if (tmp.error != MP_PARSING_SUCCES) {
609 die(STATE_UNKNOWN, "failed to parse warning threshold");
610 }
611
612 result.config.offset_thresholds =
613 mp_thresholds_set_warn(result.config.offset_thresholds, tmp.range);
614 } break;
615 case 'c': {
616 mp_range_parsed tmp = mp_parse_range_string(optarg);
617 if (tmp.error != MP_PARSING_SUCCES) {
618 die(STATE_UNKNOWN, "failed to parse crit threshold");
619 }
620
621 result.config.offset_thresholds =
622 mp_thresholds_set_crit(result.config.offset_thresholds, tmp.range);
623 } break;
496 case 'H': 624 case 'H':
497 if(!is_host(optarg)) 625 if (!is_host(optarg) && (optarg[0] != '/')) {
498 usage2(_("Invalid hostname/address"), optarg); 626 usage2(_("Invalid hostname/address"), optarg);
499 server_address = strdup(optarg); 627 }
628 result.config.server_address = strdup(optarg);
500 break; 629 break;
501 case 'p': 630 case 'p':
502 port = strdup(optarg); 631 result.config.port = strdup(optarg);
503 break; 632 break;
504 case 't': 633 case 't':
505 socket_timeout=atoi(optarg); 634 socket_timeout = atoi(optarg);
506 break; 635 break;
507 case 'o': 636 case 'o':
508 time_offset=atoi(optarg); 637 result.config.time_offset = atoi(optarg);
509 break; 638 break;
510 case '4': 639 case '4':
511 address_family = AF_INET; 640 address_family = AF_INET;
512 break; 641 break;
@@ -514,114 +643,108 @@ int process_arguments(int argc, char **argv){
514#ifdef USE_IPV6 643#ifdef USE_IPV6
515 address_family = AF_INET6; 644 address_family = AF_INET6;
516#else 645#else
517 usage4 (_("IPv6 support not available")); 646 usage4(_("IPv6 support not available"));
518#endif 647#endif
519 break; 648 break;
520 case '?': 649 case '?':
521 /* print short usage statement if args not parsable */ 650 /* print short usage statement if args not parsable */
522 usage5 (); 651 usage5();
523 break; 652 break;
524 } 653 }
525 } 654 }
526 655
527 if(server_address == NULL){ 656 if (result.config.server_address == NULL) {
528 usage4(_("Hostname was not supplied")); 657 usage4(_("Hostname was not supplied"));
529 } 658 }
530 659
531 return 0; 660 return result;
532}
533
534char *perfd_offset (double offset) {
535 return fperfdata ("offset", offset, "s",
536 true, offset_thresholds->warning->end,
537 true, offset_thresholds->critical->end,
538 false, 0, false, 0);
539} 661}
540 662
541int main(int argc, char *argv[]){ 663int main(int argc, char *argv[]) {
542 int result, offset_result; 664 setlocale(LC_ALL, "");
543 double offset=0; 665 bindtextdomain(PACKAGE, LOCALEDIR);
544 char *result_line, *perfdata_line; 666 textdomain(PACKAGE);
545 667
546 setlocale (LC_ALL, ""); 668 /* Parse extra opts if any */
547 bindtextdomain (PACKAGE, LOCALEDIR); 669 argv = np_extra_opts(&argc, argv, progname);
548 textdomain (PACKAGE);
549 670
550 result = offset_result = STATE_OK; 671 check_ntp_time_config_wrapper tmp_config = process_arguments(argc, argv);
551 672
552 /* Parse extra opts if any */ 673 if (tmp_config.errorcode == ERROR) {
553 argv=np_extra_opts (&argc, argv, progname); 674 usage4(_("Could not parse arguments"));
675 }
554 676
555 if (process_arguments (argc, argv) == ERROR) 677 const check_ntp_time_config config = tmp_config.config;
556 usage4 (_("Could not parse arguments"));
557 678
558 set_thresholds(&offset_thresholds, owarn, ocrit); 679 if (config.output_format_is_set) {
680 mp_set_format(config.output_format);
681 }
559 682
560 /* initialize alarm signal handling */ 683 /* initialize alarm signal handling */
561 signal (SIGALRM, socket_timeout_alarm_handler); 684 signal(SIGALRM, socket_timeout_alarm_handler);
562 685
563 /* set socket timeout */ 686 /* set socket timeout */
564 alarm (socket_timeout); 687 alarm(socket_timeout);
565 688
566 offset = offset_request(server_address, &offset_result); 689 mp_check overall = mp_check_init();
567 if (offset_result == STATE_UNKNOWN) {
568 result = ( (!quiet) ? STATE_UNKNOWN : STATE_CRITICAL);
569 } else {
570 result = get_status(fabs(offset), offset_thresholds);
571 }
572 690
573 switch (result) { 691 mp_subcheck sc_offset = mp_subcheck_init();
574 case STATE_CRITICAL : 692 offset_request_wrapper offset_result =
575 xasprintf(&result_line, _("NTP CRITICAL:")); 693 offset_request(config.server_address, config.port, config.time_offset);
576 break; 694
577 case STATE_WARNING : 695 if (offset_result.offset_result == STATE_UNKNOWN) {
578 xasprintf(&result_line, _("NTP WARNING:")); 696 sc_offset =
579 break; 697 mp_set_subcheck_state(sc_offset, (!config.quiet) ? STATE_UNKNOWN : STATE_CRITICAL);
580 case STATE_OK : 698 xasprintf(&sc_offset.output, "Offset unknown");
581 xasprintf(&result_line, _("NTP OK:")); 699 mp_add_subcheck_to_check(&overall, sc_offset);
582 break; 700 mp_exit(overall);
583 default :
584 xasprintf(&result_line, _("NTP UNKNOWN:"));
585 break;
586 }
587 if(offset_result == STATE_UNKNOWN){
588 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown"));
589 xasprintf(&perfdata_line, "");
590 } else {
591 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset);
592 xasprintf(&perfdata_line, "%s", perfd_offset(offset));
593 } 701 }
594 printf("%s|%s\n", result_line, perfdata_line);
595 702
596 if(server_address!=NULL) free(server_address); 703 xasprintf(&sc_offset.output, "Offset: %.6fs", offset_result.offset);
597 return result; 704
705 mp_perfdata pd_offset = perfdata_init();
706 pd_offset = mp_set_pd_value(pd_offset, fabs(offset_result.offset));
707 pd_offset.label = "offset";
708 pd_offset.uom = "s";
709 pd_offset = mp_pd_set_thresholds(pd_offset, config.offset_thresholds);
710
711 sc_offset = mp_set_subcheck_state(sc_offset, mp_get_pd_status(pd_offset));
712
713 mp_add_perfdata_to_subcheck(&sc_offset, pd_offset);
714 mp_add_subcheck_to_check(&overall, sc_offset);
715
716 if (config.server_address != NULL) {
717 free(config.server_address);
718 }
719 mp_exit(overall);
598} 720}
599 721
600void print_help(void){ 722void print_help(void) {
601 print_revision(progname, NP_VERSION); 723 print_revision(progname, NP_VERSION);
602 724
603 printf ("Copyright (c) 2006 Sean Finney\n"); 725 printf("Copyright (c) 2006 Sean Finney\n");
604 printf (COPYRIGHT, copyright, email); 726 printf(COPYRIGHT, copyright, email);
605 727
606 printf ("%s\n", _("This plugin checks the clock offset with the ntp server")); 728 printf("%s\n", _("This plugin checks the clock offset with the ntp server"));
607 729
608 printf ("\n\n"); 730 printf("\n\n");
609 731
610 print_usage(); 732 print_usage();
611 printf (UT_HELP_VRSN); 733 printf(UT_HELP_VRSN);
612 printf (UT_EXTRA_OPTS); 734 printf(UT_EXTRA_OPTS);
613 printf (UT_IPv46); 735 printf(UT_IPv46);
614 printf (UT_HOST_PORT, 'p', "123"); 736 printf(UT_HOST_PORT, 'p', "123");
615 printf (" %s\n", "-q, --quiet"); 737 printf(" %s\n", "-q, --quiet");
616 printf (" %s\n", _("Returns UNKNOWN instead of CRITICAL if offset cannot be found")); 738 printf(" %s\n", _("Returns UNKNOWN instead of CRITICAL if offset cannot be found"));
617 printf (" %s\n", "-w, --warning=THRESHOLD"); 739 printf(" %s\n", "-w, --warning=THRESHOLD");
618 printf (" %s\n", _("Offset to result in warning status (seconds)")); 740 printf(" %s\n", _("Offset to result in warning status (seconds)"));
619 printf (" %s\n", "-c, --critical=THRESHOLD"); 741 printf(" %s\n", "-c, --critical=THRESHOLD");
620 printf (" %s\n", _("Offset to result in critical status (seconds)")); 742 printf(" %s\n", _("Offset to result in critical status (seconds)"));
621 printf (" %s\n", "-o, --time_offset=INTEGER"); 743 printf(" %s\n", "-o, --time-offset=INTEGER");
622 printf (" %s\n", _("Expected offset of the ntp server relative to local server (seconds)")); 744 printf(" %s\n", _("Expected offset of the ntp server relative to local server (seconds)"));
623 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 745 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
624 printf (UT_VERBOSE); 746 printf(UT_VERBOSE);
747 printf(UT_OUTPUT_FORMAT);
625 748
626 printf("\n"); 749 printf("\n");
627 printf("%s\n", _("This plugin checks the clock offset between the local host and a")); 750 printf("%s\n", _("This plugin checks the clock offset between the local host and a"));
@@ -641,13 +764,11 @@ void print_help(void){
641 printf("%s\n", _("Examples:")); 764 printf("%s\n", _("Examples:"));
642 printf(" %s\n", ("./check_ntp_time -H ntpserv -w 0.5 -c 1")); 765 printf(" %s\n", ("./check_ntp_time -H ntpserv -w 0.5 -c 1"));
643 766
644 printf (UT_SUPPORT); 767 printf(UT_SUPPORT);
645} 768}
646 769
647void 770void print_usage(void) {
648print_usage(void) 771 printf("%s\n", _("Usage:"));
649{ 772 printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [-v verbose] [-o <time offset>]\n",
650 printf ("%s\n", _("Usage:")); 773 progname);
651 printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [-v verbose] [-o <time offset>]\n", progname);
652} 774}
653