Back to index

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

Go to the source code of this file.


struct  ntp_message
struct  ntp_server_results


#define AVG_NUM   4
#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_INCLUDED   0x04
#define PEER_SYNCSOURCE   0x06
#define L16(x)   (((uint16_t*)&x)[0])
 a note about the 32-bit "fixed point" numbers:
#define R16(x)   (((uint16_t*)&x)[1])
#define L32(x)   (((uint32_t*)&x)[0])
#define R32(x)   (((uint32_t*)&x)[1])
#define EPOCHDIFF   0x83aa7e80UL
#define NTP32asDOUBLE(x)   (ntohs(L16(x)) + (double)ntohs(R16(x))/65536.0)
#define NTP64asDOUBLE(n)
#define TVasDOUBLE(x)   (double)(x.tv_sec+(0.000001*x.tv_usec))
#define NTP64toTV(n, t)
#define TVtoNTP64(t, n)
#define SIZEOF_NTPCM(m)   (12+ntohs(m.count)+((m.count)?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)
static double calc_offset (const ntp_message *m, const struct timeval *t)
void print_ntp_message (const ntp_message *p)
void setup_request (ntp_message *p)
int best_offset_server (const ntp_server_results *slist, int nservers)
double offset_request (const char *host, int *status)
char * perfd_offset (double offset)
int main (int argc, char *argv[])


const char * progname = "check_ntp_time"
const char * copyright = "2006-2008"
const char * email = ""
static char * server_address = NULL
static char * port = "123"
static int verbose = 0
static int quiet = 0
static char * owarn = "60"
static char * ocrit = "120"
thresholdsoffset_thresholds = NULL

Class Documentation

struct ntp_message

Definition at line 63 of file check_ntp.c.

Class Members
uint8_t flags
uint64_t origts
int8_t poll
int8_t precision
uint32_t refid
uint64_t refts
int32_t rtdelay
uint32_t rtdisp
uint64_t rxts
uint8_t stratum
uint64_t txts
struct ntp_server_results

Definition at line 78 of file check_ntp.c.

Class Members
uint8_t flags
int num_responses
double offset
double rtdelay
double rtdisp
uint8_t stratum
time_t waiting

Define Documentation

#define AVG_NUM   4

Definition at line 58 of file check_ntp_time.c.

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

Definition at line 182 of file check_ntp_time.c.

#define EPOCHDIFF   0x83aa7e80UL

Definition at line 144 of file check_ntp_time.c.

#define L16 (   x)    (((uint16_t*)&x)[0])

a note about the 32-bit "fixed point" numbers:

they are divided into halves, each being a 16-bit int in network byte order:

  • the first 16 bits are an int on the left side of a decimal point.
  • the second 16 bits represent a fraction n/(2^16) likewise for the 64-bit "fixed point" numbers with everything doubled :)

Definition at line 136 of file check_ntp_time.c.

#define L32 (   x)    (((uint32_t*)&x)[0])

Definition at line 140 of file check_ntp_time.c.

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

Definition at line 91 of file check_ntp_time.c.

#define LI_ALARM   0x03

Definition at line 97 of file check_ntp_time.c.

#define LI_EXTRASEC   0x01

Definition at line 95 of file check_ntp_time.c.

#define LI_MASK   0xc0

Definition at line 90 of file check_ntp_time.c.

#define LI_MISSINGSEC   0x02

Definition at line 96 of file check_ntp_time.c.

#define LI_NOWARNING   0x00

Definition at line 94 of file check_ntp_time.c.

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

Definition at line 92 of file check_ntp_time.c.

#define MAX_CM_SIZE   468

Definition at line 61 of file check_ntp_time.c.

#define MODE (   x)    (x&MODE_MASK)

Definition at line 105 of file check_ntp_time.c.

#define MODE_CLIENT   0x03

Definition at line 108 of file check_ntp_time.c.

#define MODE_CONTROLMSG   0x06

Definition at line 109 of file check_ntp_time.c.

#define MODE_MASK   0x07

Definition at line 104 of file check_ntp_time.c.

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

Definition at line 106 of file check_ntp_time.c.

#define NTP32asDOUBLE (   x)    (ntohs(L16(x)) + (double)ntohs(R16(x))/65536.0)

Definition at line 147 of file check_ntp_time.c.

#define NTP64asDOUBLE (   n)
                         (ntohl(L32(n))-EPOCHDIFF) + \

Definition at line 150 of file check_ntp_time.c.

#define NTP64toTV (   n,
do{ if(!n) t.tv_sec = t.tv_usec = 0; \
           else { \
                     t.tv_sec=ntohl(L32(n))-EPOCHDIFF; \
                     t.tv_usec=(int)(0.5+(double)(ntohl(R32(n))/4294.967296)); \
              } \

Definition at line 159 of file check_ntp_time.c.

#define OP_MASK   0x1f

Definition at line 116 of file check_ntp_time.c.

#define OP_READSTAT   0x01

Definition at line 118 of file check_ntp_time.c.

#define OP_READVAR   0x02

Definition at line 119 of file check_ntp_time.c.

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

Definition at line 117 of file check_ntp_time.c.

#define PEER_INCLUDED   0x04

Definition at line 122 of file check_ntp_time.c.

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

Definition at line 121 of file check_ntp_time.c.

#define PEER_SYNCSOURCE   0x06

Definition at line 123 of file check_ntp_time.c.

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

Definition at line 183 of file check_ntp_time.c.

#define R16 (   x)    (((uint16_t*)&x)[1])

Definition at line 137 of file check_ntp_time.c.

#define R32 (   x)    (((uint32_t*)&x)[1])

Definition at line 141 of file check_ntp_time.c.

#define REM_ERROR   0x40

Definition at line 113 of file check_ntp_time.c.

#define REM_MASK   0xe0

Definition at line 111 of file check_ntp_time.c.

#define REM_MORE   0x20

Definition at line 114 of file check_ntp_time.c.

#define REM_RESP   0x80

Definition at line 112 of file check_ntp_time.c.

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

Definition at line 179 of file check_ntp_time.c.

#define TVasDOUBLE (   x)    (double)(x.tv_sec+(0.000001*x.tv_usec))

Definition at line 156 of file check_ntp_time.c.

#define TVtoNTP64 (   t,
do{ if(!t.tv_usec && !t.tv_sec) n=0x0UL; \
              else { \
                     L32(n)=htonl(t.tv_sec + EPOCHDIFF); \
                     R32(n)=htonl((uint64_t)((4294.967296*t.tv_usec)+.5)); \
              } \
       } while(0)

Definition at line 168 of file check_ntp_time.c.

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

Definition at line 100 of file check_ntp_time.c.

#define VN_MASK   0x38

Definition at line 99 of file check_ntp_time.c.

#define VN_RESERVED   0x02

Definition at line 102 of file check_ntp_time.c.

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

Definition at line 101 of file check_ntp_time.c.

Function Documentation

int best_offset_server ( const ntp_server_results slist,
int  nservers 

Definition at line 243 of file check_ntp_time.c.

       int i=0, cserver=0, best_server=-1;

       /* for each server */
       for(cserver=0; cserver<nservers; cserver++){
              /* We don't want any servers that fails these tests */
              /* Sort out servers that didn't respond or responede with a 0 stratum;
               * stratum 0 is for reference clocks so no NTP server should ever report
               * a stratum 0 */
              if ( slist[cserver].stratum == 0){
                     if (verbose) printf("discarding peer %d: stratum=%d\n", cserver, slist[cserver].stratum);
              /* Sort out servers with error flags */
              if ( LI(slist[cserver].flags) == LI_ALARM ){
                     if (verbose) printf("discarding peer %d: flags=%d\n", cserver, LI(slist[cserver].flags));

              /* If we don't have a server yet, use the first one */
              if (best_server == -1) {
                     best_server = cserver;
                     DBG(printf("using peer %d as our first candidate\n", best_server));

              /* compare the server to the best one we've seen so far */
              /* does it have an equal or better stratum? */
              DBG(printf("comparing peer %d with peer %d\n", cserver, best_server));
              if(slist[cserver].stratum <= slist[best_server].stratum){
                     DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server));
                     /* does it have an equal or better dispersion? */
                     if(slist[cserver].rtdisp <= slist[best_server].rtdisp){
                            DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server));
                            /* does it have a better rtdelay? */
                            if(slist[cserver].rtdelay < slist[best_server].rtdelay){
                                   DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server));
                                   best_server = cserver;
                                   DBG(printf("peer %d is now our best candidate\n", best_server));

       if(best_server >= 0) {
              DBG(printf("best server selected: peer %d\n", best_server));
              return best_server;
       } else {
              DBG(printf("no peers meeting synchronization criteria :(\n"));
              return -1;
static double calc_offset ( const ntp_message m,
const struct timeval t 
) [inline, static]

Definition at line 189 of file check_ntp_time.c.

       double client_tx, peer_rx, peer_tx, client_rx;
       client_tx = NTP64asDOUBLE(m->origts);
       peer_rx = NTP64asDOUBLE(m->rxts);
       peer_tx = NTP64asDOUBLE(m->txts);
       return (.5*((peer_tx-client_rx)+(peer_rx-client_tx)));

Here is the caller graph for this function:

int main ( int  argc,
char *  argv[] 

Definition at line 533 of file check_ntp_time.c.

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

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

       result = offset_result = STATE_OK;

       /* 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);

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

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

       offset = offset_request(server_address, &offset_result);
       if (offset_result == STATE_UNKNOWN) {
              result = (quiet == 1 ? STATE_UNKNOWN : STATE_CRITICAL);
       } else {
              result = get_status(fabs(offset), offset_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:"));
       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));
       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:

double offset_request ( const char *  host,
int *  status 

Definition at line 301 of file check_ntp_time.c.

       int i=0, j=0, ga_result=0, num_hosts=0, *socklist=NULL, respnum=0;
       int servers_completed=0, one_written=0, one_read=0, servers_readable=0, best_index=-1;
       time_t now_time=0, start_ts=0;
       ntp_message *req=NULL;
       double avg_offset=0.;
       struct timeval recv_time;
       struct addrinfo *ai=NULL, *ai_tmp=NULL, hints;
       struct pollfd *ufds=NULL;
       ntp_server_results *servers=NULL;

       /* setup hints to only return results from getaddrinfo that we'd like */
       memset(&hints, 0, sizeof(struct addrinfo));
       hints.ai_family = address_family;
       hints.ai_protocol = IPPROTO_UDP;
       hints.ai_socktype = SOCK_DGRAM;

       /* fill in ai with the list of hosts resolved by the host name */
       ga_result = getaddrinfo(host, port, &hints, &ai);
              die(STATE_UNKNOWN, "error getting address for %s: %s\n",
                  host, gai_strerror(ga_result));

       /* count the number of returned hosts, and allocate stuff accordingly */
       for(ai_tmp=ai; ai_tmp!=NULL; ai_tmp=ai_tmp->ai_next){ num_hosts++; }
       if(req==NULL) die(STATE_UNKNOWN, "can not allocate ntp message array");
       if(socklist==NULL) die(STATE_UNKNOWN, "can not allocate socket array");
       ufds=(struct pollfd*)malloc(sizeof(struct pollfd)*num_hosts);
       if(ufds==NULL) die(STATE_UNKNOWN, "can not allocate socket array");
       if(servers==NULL) die(STATE_UNKNOWN, "can not allocate server array");
       memset(servers, 0, sizeof(ntp_server_results)*num_hosts);
       DBG(printf("Found %d peers to check\n", num_hosts));

       /* setup each socket for writing, and the corresponding struct pollfd */
              socklist[i]=socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP);
              if(socklist[i] == -1) {
                     die(STATE_UNKNOWN, "can not create new socket");
              if(connect(socklist[i], ai_tmp->ai_addr, ai_tmp->ai_addrlen)){
                     die(STATE_UNKNOWN, "can't create socket connection");
              } else {
              ai_tmp = ai_tmp->ai_next;

       /* now do AVG_NUM checks to each host. We stop before timeout/2 seconds
        * have passed in order to ensure post-processing and jitter time. */
       while(servers_completed<num_hosts && now_time-start_ts <= socket_timeout/2){
              /* loop through each server and find each one which hasn't
               * been touched in the past second or so and is still lacking
               * some responses. For each of these servers, send a new request,
               * and update the "waiting" timestamp with the current time. */

              for(i=0; i<num_hosts; i++){
                     if(servers[i].waiting<now_time && servers[i].num_responses<AVG_NUM){
                            if(verbose && servers[i].waiting != 0) printf("re-");
                            if(verbose) printf("sending request to peer %d\n", i);
                            write(socklist[i], &req[i], sizeof(ntp_message));

              /* quickly poll for any sockets with pending data */
              servers_readable=poll(ufds, num_hosts, 100);
                     perror("polling ntp sockets");
                     die(STATE_UNKNOWN, "communication errors");

              /* read from any sockets with pending data */
              for(i=0; servers_readable && i<num_hosts; i++){
                     if(ufds[i].revents&POLLIN && servers[i].num_responses < AVG_NUM){
                            if(verbose) {
                                   printf("response from peer %d: ", i);

                            read(ufds[i].fd, &req[i], sizeof(ntp_message));
                            gettimeofday(&recv_time, NULL);
                            servers[i].offset[respnum]=calc_offset(&req[i], &recv_time);
                            if(verbose) {
                                   printf("offset %.10g\n", servers[i].offset[respnum]);
                            one_read = 1;
                            if(servers[i].num_responses==AVG_NUM) servers_completed++;
              /* lather, rinse, repeat. */

       if (one_read == 0) {
              die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");

       /* now, pick the best server from the list */
       best_index=best_offset_server(servers, num_hosts);
       if(best_index < 0){
       } else {
              /* finally, calculate the average offset */
              for(i=0; i<servers[best_index].num_responses;i++){

       /* cleanup */
       for(j=0; j<num_hosts; j++){ close(socklist[j]); }

       if(verbose) printf("overall average offset: %.10g\n", avg_offset);
       return avg_offset;

Here is the call graph for this function:

char* perfd_offset ( double  offset)

Definition at line 525 of file check_ntp_time.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:

void print_help ( void  )

Definition at line 199 of file check_ntp_time.c.

       struct timeval ref, orig, rx, tx;


       printf("packet contents:\n");
       printf("\tflags: 0x%.2x\n", p->flags);
       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("\tstratum = %d\n", p->stratum);
       printf("\tpoll = %g\n", pow(2, p->poll));
       printf("\tprecision = %g\n", pow(2, p->precision));
       printf("\trtdelay = %-.16g\n", NTP32asDOUBLE(p->rtdelay));
       printf("\trtdisp = %-.16g\n", NTP32asDOUBLE(p->rtdisp));
       printf("\trefid = %x\n", p->refid);
       printf("\trefts = %-.16g\n", NTP64asDOUBLE(p->refts));
       printf("\torigts = %-.16g\n", NTP64asDOUBLE(p->origts));
       printf("\trxts = %-.16g\n", NTP64asDOUBLE(p->rxts));
       printf("\ttxts = %-.16g\n", NTP64asDOUBLE(p->txts));
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_request ( ntp_message p)

Definition at line 224 of file check_ntp_time.c.

       struct timeval t;

       memset(p, 0, sizeof(ntp_message));
       LI_SET(p->flags, LI_ALARM);
       VN_SET(p->flags, 4);
       MODE_SET(p->flags, MODE_CLIENT);

       gettimeofday(&t, NULL);

Here is the call graph for this function:

Variable Documentation

const char* copyright = "2006-2008"

Definition at line 38 of file check_ntp_time.c.

const char* email = ""

Definition at line 39 of file check_ntp_time.c.

char* ocrit = "120" [static]

Definition at line 50 of file check_ntp_time.c.

Definition at line 53 of file check_ntp_time.c.

char* owarn = "60" [static]

Definition at line 49 of file check_ntp_time.c.

char* port = "123" [static]

Definition at line 46 of file check_ntp_time.c.

const char* progname = "check_ntp_time"

Definition at line 37 of file check_ntp_time.c.

int quiet = 0 [static]

Definition at line 48 of file check_ntp_time.c.

char* server_address = NULL [static]

Definition at line 45 of file check_ntp_time.c.

int verbose = 0 [static]

Definition at line 47 of file check_ntp_time.c.