Back to index

nagios-plugins  1.4.16
Classes | Defines | Functions | Variables
check_ntp_peer.c File Reference
#include "common.h"
#include "netutils.h"
#include "utils.h"

Go to the source code of this file.


struct  ntp_control_message
struct  ntp_assoc_status_pair


#define MAX_CM_SIZE   468
#define LI_MASK   0xc0
#define LI(x)   ((x&LI_MASK)>>6)
#define LI_SET(x, y)   do{ x |= ((y<<6)&LI_MASK); }while(0)
#define LI_NOWARNING   0x00
#define LI_EXTRASEC   0x01
#define LI_MISSINGSEC   0x02
#define LI_ALARM   0x03
#define VN_MASK   0x38
#define VN(x)   ((x&VN_MASK)>>3)
#define VN_SET(x, y)   do{ x |= ((y<<3)&VN_MASK); }while(0)
#define VN_RESERVED   0x02
#define MODE_MASK   0x07
#define MODE(x)   (x&MODE_MASK)
#define MODE_SET(x, y)   do{ x |= (y&MODE_MASK); }while(0)
#define MODE_CLIENT   0x03
#define MODE_CONTROLMSG   0x06
#define REM_MASK   0xe0
#define REM_RESP   0x80
#define REM_ERROR   0x40
#define REM_MORE   0x20
#define OP_MASK   0x1f
#define OP_SET(x, y)   do{ x |= (y&OP_MASK); }while(0)
#define OP_READSTAT   0x01
#define OP_READVAR   0x02
#define PEER_SEL(x)   ((ntohs(x)>>8)&0x07)
#define PEER_TRUECHIMER   0x02
#define PEER_INCLUDED   0x04
#define PEER_SYNCSOURCE   0x06
#define SIZEOF_NTPCM(m)   (12+ntohs(m.count)+((ntohs(m.count)%4)?4-(ntohs(m.count)%4):0))
#define DBG(x)   do{if(verbose>1){ x; }}while(0);


int process_arguments (int, char **)
void print_help (void)
void print_usage (void)
void print_ntp_control_message (const ntp_control_message *p)
void setup_control_request (ntp_control_message *p, uint8_t opcode, uint16_t seq)
int ntp_request (const char *host, double *offset, int *offset_result, double *jitter, int *stratum, int *num_truechimers)
char * perfd_offset (double offset)
char * perfd_jitter (double jitter)
char * perfd_stratum (int stratum)
char * perfd_truechimers (int num_truechimers)
int main (int argc, char *argv[])


const char * progname = "check_ntp_peer"
const char * copyright = "2006-2008"
const char * email = ""
static char * server_address = NULL
static int port = 123
static int verbose = 0
static int quiet = 0
static short do_offset = 0
static char * owarn = "60"
static char * ocrit = "120"
static short do_stratum = 0
static char * swarn = "-1:16"
static char * scrit = "-1:16"
static short do_jitter = 0
static char * jwarn = "-1:5000"
static char * jcrit = "-1:10000"
static short do_truechimers = 0
static char * twarn = "0:"
static char * tcrit = "0:"
static int syncsource_found = 0
static int li_alarm = 0
thresholdsoffset_thresholds = NULL
thresholdsjitter_thresholds = NULL
thresholdsstratum_thresholds = NULL
thresholdstruechimer_thresholds = NULL

Class Documentation

struct ntp_control_message

Definition at line 89 of file check_ntp.c.

Class Members
uint16_t assoc
uint16_t count
char data
uint8_t flags
uint16_t offset
uint8_t op
uint16_t seq
uint16_t status
struct ntp_assoc_status_pair

Definition at line 102 of file check_ntp.c.

Class Members
uint16_t assoc
uint16_t status

Define Documentation

#define DBG (   x)    do{if(verbose>1){ x; }}while(0);

Definition at line 138 of file check_ntp_peer.c.

#define LI (   x)    ((x&LI_MASK)>>6)

Definition at line 97 of file check_ntp_peer.c.

#define LI_ALARM   0x03

Definition at line 103 of file check_ntp_peer.c.

#define LI_EXTRASEC   0x01

Definition at line 101 of file check_ntp_peer.c.

#define LI_MASK   0xc0

Definition at line 96 of file check_ntp_peer.c.

#define LI_MISSINGSEC   0x02

Definition at line 102 of file check_ntp_peer.c.

#define LI_NOWARNING   0x00

Definition at line 100 of file check_ntp_peer.c.

#define LI_SET (   x,
)    do{ x |= ((y<<6)&LI_MASK); }while(0)

Definition at line 98 of file check_ntp_peer.c.

#define MAX_CM_SIZE   468

Definition at line 74 of file check_ntp_peer.c.

#define MODE (   x)    (x&MODE_MASK)

Definition at line 111 of file check_ntp_peer.c.

#define MODE_CLIENT   0x03

Definition at line 114 of file check_ntp_peer.c.

#define MODE_CONTROLMSG   0x06

Definition at line 115 of file check_ntp_peer.c.

#define MODE_MASK   0x07

Definition at line 110 of file check_ntp_peer.c.

#define MODE_SET (   x,
)    do{ x |= (y&MODE_MASK); }while(0)

Definition at line 112 of file check_ntp_peer.c.

#define OP_MASK   0x1f

Definition at line 122 of file check_ntp_peer.c.

#define OP_READSTAT   0x01

Definition at line 124 of file check_ntp_peer.c.

#define OP_READVAR   0x02

Definition at line 125 of file check_ntp_peer.c.

#define OP_SET (   x,
)    do{ x |= (y&OP_MASK); }while(0)

Definition at line 123 of file check_ntp_peer.c.

#define PEER_INCLUDED   0x04

Definition at line 129 of file check_ntp_peer.c.

#define PEER_SEL (   x)    ((ntohs(x)>>8)&0x07)

Definition at line 127 of file check_ntp_peer.c.

#define PEER_SYNCSOURCE   0x06

Definition at line 130 of file check_ntp_peer.c.

#define PEER_TRUECHIMER   0x02

Definition at line 128 of file check_ntp_peer.c.

#define PRINTSOCKADDR (   x)
do{ \
              printf("%u.%u.%u.%u", (x>>24)&0xff, (x>>16)&0xff, (x>>8)&0xff, x&0xff);\

Definition at line 139 of file check_ntp_peer.c.

#define REM_ERROR   0x40

Definition at line 119 of file check_ntp_peer.c.

#define REM_MASK   0xe0

Definition at line 117 of file check_ntp_peer.c.

#define REM_MORE   0x20

Definition at line 120 of file check_ntp_peer.c.

#define REM_RESP   0x80

Definition at line 118 of file check_ntp_peer.c.

#define SIZEOF_NTPCM (   m)    (12+ntohs(m.count)+((ntohs(m.count)%4)?4-(ntohs(m.count)%4):0))

Definition at line 135 of file check_ntp_peer.c.

#define VN (   x)    ((x&VN_MASK)>>3)

Definition at line 106 of file check_ntp_peer.c.

#define VN_MASK   0x38

Definition at line 105 of file check_ntp_peer.c.

#define VN_RESERVED   0x02

Definition at line 108 of file check_ntp_peer.c.

#define VN_SET (   x,
)    do{ x |= ((y<<3)&VN_MASK); }while(0)

Definition at line 107 of file check_ntp_peer.c.

Function Documentation

int main ( int  argc,
char *  argv[] 

Definition at line 556 of file check_ntp_peer.c.

       int result, offset_result, stratum, num_truechimers;
       double offset=0, jitter=0;
       char *result_line, *perfdata_line;

       setlocale (LC_ALL, "");
       bindtextdomain (PACKAGE, LOCALEDIR);
       textdomain (PACKAGE);

       /* Parse extra opts if any */
       argv=np_extra_opts (&argc, argv, progname);

       if (process_arguments (argc, argv) == ERROR)
              usage4 (_("Could not parse arguments"));

       set_thresholds(&offset_thresholds, owarn, ocrit);
       set_thresholds(&jitter_thresholds, jwarn, jcrit);
       set_thresholds(&stratum_thresholds, swarn, scrit);
       set_thresholds(&truechimer_thresholds, twarn, tcrit);

       /* initialize alarm signal handling */
       signal (SIGALRM, socket_timeout_alarm_handler);

       /* set socket timeout */
       alarm (socket_timeout);

       /* This returns either OK or WARNING (See comment preceeding ntp_request) */
       result = ntp_request(server_address, &offset, &offset_result, &jitter, &stratum, &num_truechimers);

       if(offset_result == STATE_UNKNOWN) {
              /* if there's no sync peer (this overrides ntp_request output): */
              result = (quiet == 1 ? STATE_UNKNOWN : STATE_CRITICAL);
       } else {
              /* Be quiet if there's no candidates either */
              if (quiet == 1 && result == STATE_WARNING)
                     result = STATE_UNKNOWN;
              result = max_state_alt(result, get_status(fabs(offset), offset_thresholds));

              result = max_state_alt(result, get_status(num_truechimers, truechimer_thresholds));

              result = max_state_alt(result, get_status(stratum, stratum_thresholds));

              result = max_state_alt(result, get_status(jitter, jitter_thresholds));

       switch (result) {
              case STATE_CRITICAL :
                     asprintf(&result_line, _("NTP CRITICAL:"));
              case STATE_WARNING :
                     asprintf(&result_line, _("NTP WARNING:"));
              case STATE_OK :
                     asprintf(&result_line, _("NTP OK:"));
              default :
                     asprintf(&result_line, _("NTP UNKNOWN:"));
              asprintf(&result_line, "%s %s,", result_line, _("Server not synchronized"));
       else if(li_alarm)
              asprintf(&result_line, "%s %s,", result_line, _("Server has the LI_ALARM bit set"));

       if(offset_result == STATE_UNKNOWN){
              asprintf(&result_line, "%s %s", result_line, _("Offset unknown"));
              asprintf(&perfdata_line, "");
       } else {
              asprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset);
              asprintf(&perfdata_line, "%s", perfd_offset(offset));
       if (do_jitter) {
              asprintf(&result_line, "%s, jitter=%f", result_line, jitter);
              asprintf(&perfdata_line, "%s %s", perfdata_line, perfd_jitter(jitter));
       if (do_stratum) {
              asprintf(&result_line, "%s, stratum=%i", result_line, stratum);
              asprintf(&perfdata_line, "%s %s", perfdata_line, perfd_stratum(stratum));
       if (do_truechimers) {
              asprintf(&result_line, "%s, truechimers=%i", result_line, num_truechimers);
              asprintf(&perfdata_line, "%s %s", perfdata_line, perfd_truechimers(num_truechimers));
       printf("%s|%s\n", result_line, perfdata_line);

       if(server_address!=NULL) free(server_address);
       return result;

Here is the call graph for this function:

int ntp_request ( const char *  host,
double *  offset,
int *  offset_result,
double *  jitter,
int *  stratum,
int *  num_truechimers 

Definition at line 202 of file check_ntp_peer.c.

       int conn=-1, i, npeers=0, num_candidates=0;
       double tmp_offset = 0;
       int min_peer_sel=PEER_INCLUDED;
       int peers_size=0, peer_offset=0;
       int status;
       ntp_assoc_status_pair *peers=NULL;
       ntp_control_message req;
       const char *getvar = "stratum,offset,jitter";
       char *data, *value, *nptr;
       void *tmp;

       status = STATE_OK;
       *offset_result = STATE_UNKNOWN;
       *jitter = *stratum = -1;
       *num_truechimers = 0;

       /* Long-winded explanation:
        * Getting the sync peer offset, jitter and stratum requires a number of
        * steps:
        * 1) Send a READSTAT request.
        * 2) Interpret the READSTAT reply
        *  a) The data section contains a list of peer identifiers (16 bits)
        *     and associated status words (16 bits)
        *  b) We want the value of 0x06 in the SEL (peer selection) value,
        *     which means "current synchronizatin source".  If that's missing,
        *     we take anything better than 0x04 (see the rfc for details) but
        *     set a minimum of warning.
        * 3) Send a READVAR request for information on each peer identified
        *    in 2b greater than the minimum selection value.
        * 4) Extract the offset, jitter and stratum value from the data[]
        *    (it's ASCII)
       my_udp_connect(server_address, port, &conn);

       /* keep sending requests until the server stops setting the
        * REM_MORE bit, though usually this is only 1 packet. */
              setup_control_request(&req, OP_READSTAT, 1);
              DBG(printf("sending READSTAT request"));
              write(conn, &req, SIZEOF_NTPCM(req));
              /* Attempt to read the largest size packet possible */
              DBG(printf("recieving READSTAT response"))
              if(read(conn, &req, SIZEOF_NTPCM(req)) == -1)
                     die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
              /* discard obviously invalid packets */
              if (ntohs(req.count) > MAX_CM_SIZE)
                     die(STATE_CRITICAL, "NTP CRITICAL: Invalid packet received from NTP server\n");
              if (LI(req.flags) == LI_ALARM) li_alarm = 1;
              /* Each peer identifier is 4 bytes in the data section, which
               * we represent as a ntp_assoc_status_pair datatype.
              if((tmp=realloc(peers, peers_size)) == NULL)
                     free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n");
              memcpy((void*)((ptrdiff_t)peers+peer_offset), (void*), ntohs(req.count));
       } while(req.op&REM_MORE);

       /* first, let's find out if we have a sync source, or if there are
        * at least some candidates. In the latter case we'll issue
        * a warning but go ahead with the check on them. */
       for (i = 0; i < npeers; i++){
              if(PEER_SEL(peers[i].status) >= PEER_TRUECHIMER){
                     if(PEER_SEL(peers[i].status) >= PEER_INCLUDED){
                            if(PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE){
       if(verbose) printf("%d candidate peers available\n", num_candidates);
       if(verbose && syncsource_found) printf("synchronization source found\n");
       if(! syncsource_found){
              status = STATE_WARNING;
              if(verbose) printf("warning: no synchronization source found\n");
              status = STATE_WARNING;
              if(verbose) printf("warning: LI_ALARM bit is set\n");

       for (i = 0; i < npeers; i++){
              /* Only query this server if it is the current sync source */
              /* If there's no sync.peer, query all candidates and use the best one */
              if (PEER_SEL(peers[i].status) >= min_peer_sel){
                     if(verbose) printf("Getting offset, jitter and stratum for peer %.2x\n", ntohs(peers[i].assoc));
                     asprintf(&data, "");
                            setup_control_request(&req, OP_READVAR, 2);
                            req.assoc = peers[i].assoc;
                            /* Putting the wanted variable names in the request
                             * cause the server to provide _only_ the requested values.
                             * thus reducing net traffic, guaranteeing us only a single
                             * datagram in reply, and making intepretation much simpler
                            /* Older servers doesn't know what jitter is, so if we get an
                             * error on the first pass we redo it with "dispersion" */
                            strncpy(, getvar, MAX_CM_SIZE-1);
                            req.count = htons(strlen(getvar));
                            DBG(printf("sending READVAR request...\n"));
                            write(conn, &req, SIZEOF_NTPCM(req));

                            req.count = htons(MAX_CM_SIZE);
                            DBG(printf("receiving READVAR response...\n"));
                            read(conn, &req, SIZEOF_NTPCM(req));

                                   asprintf(&data, "%s%s", data,;
                     } while(req.op&REM_MORE);

                     if(req.op&REM_ERROR) {
                            if(strstr(getvar, "jitter")) {
                                   if(verbose) printf("The command failed. This is usually caused by servers refusing the 'jitter'\nvariable. Restarting with 'dispersion'...\n");
                                   getvar = "stratum,offset,dispersion";
                            } else if(strlen(getvar)) {
                                   if(verbose) printf("Server didn't like dispersion either; will retrieve everything\n");
                                   getvar = "";

                     if(verbose > 1)
                            printf("Server responded: >>>%s<<<\n", data);

                     /* get the offset */
                            printf("parsing offset from peer %.2x: ", ntohs(peers[i].assoc));

                     value = np_extract_ntpvar(data, "offset");
                     /* Convert the value if we have one */
                     if(value != NULL)
                            tmp_offset = strtod(value, &nptr) / 1000;
                     /* If value is null or no conversion was performed */
                     if(value == NULL || value==nptr) {
                            if(verbose) printf("error: unable to read server offset response.\n");
                     } else {
                            if(verbose) printf("%.10g\n", tmp_offset);
                            if(*offset_result == STATE_UNKNOWN || fabs(tmp_offset) < fabs(*offset)) {
                                   *offset = tmp_offset;
                                   *offset_result = STATE_OK;
                            } else {
                                   /* Skip this one; move to the next */

                     if(do_jitter) {
                            /* get the jitter */
                            if(verbose) {
                                   printf("parsing %s from peer %.2x: ", strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter", ntohs(peers[i].assoc));
                            value = np_extract_ntpvar(data, strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter");
                            /* Convert the value if we have one */
                            if(value != NULL)
                                   *jitter = strtod(value, &nptr);
                            /* If value is null or no conversion was performed */
                            if(value == NULL || value==nptr) {
                                   if(verbose) printf("error: unable to read server jitter/dispersion response.\n");
                                   *jitter = -1;
                            } else if(verbose) {
                                   printf("%.10g\n", *jitter);

                     if(do_stratum) {
                            /* get the stratum */
                            if(verbose) {
                                   printf("parsing stratum from peer %.2x: ", ntohs(peers[i].assoc));
                            value = np_extract_ntpvar(data, "stratum");
                            /* Convert the value if we have one */
                            if(value != NULL)
                                   *stratum = strtol(value, &nptr, 10);
                            if(value == NULL || value==nptr) {
                                   if(verbose) printf("error: unable to read server stratum response.\n");
                                   *stratum = -1;
                            } else {
                                   if(verbose) printf("%i\n", *stratum);
              } /* if (PEER_SEL(peers[i].status) >= min_peer_sel) */
       } /* for (i = 0; i < npeers; i++) */

       if(peers!=NULL) free(peers);

       return status;

Here is the call graph for this function:

Here is the caller graph for this function:

char* perfd_jitter ( double  jitter)

Definition at line 532 of file check_ntp_peer.c.

       return fperfdata ("jitter", jitter, "",
              do_jitter, jitter_thresholds->warning->end,
              do_jitter, jitter_thresholds->critical->end,
              TRUE, 0, FALSE, 0);

Here is the call graph for this function:

char* perfd_offset ( double  offset)

Definition at line 524 of file check_ntp_peer.c.

       return fperfdata ("offset", offset, "s",
              TRUE, offset_thresholds->warning->end,
              TRUE, offset_thresholds->critical->end,
              FALSE, 0, FALSE, 0);

Here is the call graph for this function:

char* perfd_stratum ( int  stratum)

Definition at line 540 of file check_ntp_peer.c.

       return perfdata ("stratum", stratum, "",
              do_stratum, (int)stratum_thresholds->warning->end,
              do_stratum, (int)stratum_thresholds->critical->end,
              TRUE, 0, TRUE, 16);

Here is the call graph for this function:

Here is the caller graph for this function:

char* perfd_truechimers ( int  num_truechimers)

Definition at line 548 of file check_ntp_peer.c.

       return perfdata ("truechimers", num_truechimers, "",
              do_truechimers, (int)truechimer_thresholds->warning->end,
              do_truechimers, (int)truechimer_thresholds->critical->end,
              TRUE, 0, FALSE, 0);

Here is the call graph for this function:

Here is the caller graph for this function:

void print_help ( void  )

Definition at line 144 of file check_ntp_peer.c.

       int i=0, numpeers=0;
       const ntp_assoc_status_pair *peer=NULL;

       printf("control packet contents:\n");
       printf("\tflags: 0x%.2x , 0x%.2x\n", p->flags, p->op);
       printf("\t  li=%d (0x%.2x)\n", LI(p->flags), p->flags&LI_MASK);
       printf("\t  vn=%d (0x%.2x)\n", VN(p->flags), p->flags&VN_MASK);
       printf("\t  mode=%d (0x%.2x)\n", MODE(p->flags), p->flags&MODE_MASK);
       printf("\t  response=%d (0x%.2x)\n", (p->op&REM_RESP)>0, p->op&REM_RESP);
       printf("\t  more=%d (0x%.2x)\n", (p->op&REM_MORE)>0, p->op&REM_MORE);
       printf("\t  error=%d (0x%.2x)\n", (p->op&REM_ERROR)>0, p->op&REM_ERROR);
       printf("\t  op=%d (0x%.2x)\n", p->op&OP_MASK, p->op&OP_MASK);
       printf("\tsequence: %d (0x%.2x)\n", ntohs(p->seq), ntohs(p->seq));
       printf("\tstatus: %d (0x%.2x)\n", ntohs(p->status), ntohs(p->status));
       printf("\tassoc: %d (0x%.2x)\n", ntohs(p->assoc), ntohs(p->assoc));
       printf("\toffset: %d (0x%.2x)\n", ntohs(p->offset), ntohs(p->offset));
       printf("\tcount: %d (0x%.2x)\n", ntohs(p->count), ntohs(p->count));
       if(p->op&REM_RESP && p->op&OP_READSTAT){
                     printf("\tpeer id %.2x status %.2x",
                            ntohs(peer[i].assoc), ntohs(peer[i].status));
                     if(PEER_SEL(peer[i].status) >= PEER_SYNCSOURCE){
                            printf(" <-- current sync source");
                     } else if(PEER_SEL(peer[i].status) >= PEER_INCLUDED){
                            printf(" <-- current sync candidate");
                     } else if(PEER_SEL(peer[i].status) >= PEER_TRUECHIMER){
                            printf(" <-- outlyer, but truechimer");
void print_usage ( void  )

Definition at line 389 of file check_cpqarray.c.

  printf("cpqarrayd [options]\n");
  printf("   -h         prints this text\n");
  printf("   -d         enables debugging\n");
int process_arguments ( int  argc,
char **  argv 
void setup_control_request ( ntp_control_message p,
uint8_t  opcode,
uint16_t  seq 

Definition at line 181 of file check_ntp_peer.c.

       memset(p, 0, sizeof(ntp_control_message));
       LI_SET(p->flags, LI_NOWARNING);
       VN_SET(p->flags, VN_RESERVED);
       MODE_SET(p->flags, MODE_CONTROLMSG);
       OP_SET(p->op, opcode);
       p->seq = htons(seq);
       /* Remaining fields are zero for requests */

Variable Documentation

const char* copyright = "2006-2008"

Definition at line 39 of file check_ntp_peer.c.

short do_jitter = 0 [static]

Definition at line 56 of file check_ntp_peer.c.

short do_offset = 0 [static]

Definition at line 50 of file check_ntp_peer.c.

short do_stratum = 0 [static]

Definition at line 53 of file check_ntp_peer.c.

short do_truechimers = 0 [static]

Definition at line 59 of file check_ntp_peer.c.

const char* email = ""

Definition at line 40 of file check_ntp_peer.c.

char* jcrit = "-1:10000" [static]

Definition at line 58 of file check_ntp_peer.c.

Definition at line 67 of file check_ntp_peer.c.

char* jwarn = "-1:5000" [static]

Definition at line 57 of file check_ntp_peer.c.

int li_alarm = 0 [static]

Definition at line 63 of file check_ntp_peer.c.

char* ocrit = "120" [static]

Definition at line 52 of file check_ntp_peer.c.

Definition at line 66 of file check_ntp_peer.c.

char* owarn = "60" [static]

Definition at line 51 of file check_ntp_peer.c.

int port = 123 [static]

Definition at line 47 of file check_ntp_peer.c.

const char* progname = "check_ntp_peer"

Definition at line 38 of file check_ntp_peer.c.

int quiet = 0 [static]

Definition at line 49 of file check_ntp_peer.c.

char* scrit = "-1:16" [static]

Definition at line 55 of file check_ntp_peer.c.

char* server_address = NULL [static]

Definition at line 46 of file check_ntp_peer.c.

Definition at line 68 of file check_ntp_peer.c.

char* swarn = "-1:16" [static]

Definition at line 54 of file check_ntp_peer.c.

int syncsource_found = 0 [static]

Definition at line 62 of file check_ntp_peer.c.

char* tcrit = "0:" [static]

Definition at line 61 of file check_ntp_peer.c.

Definition at line 69 of file check_ntp_peer.c.

char* twarn = "0:" [static]

Definition at line 60 of file check_ntp_peer.c.

int verbose = 0 [static]

Definition at line 48 of file check_ntp_peer.c.