Home | History | Annotate | Line # | Download | only in ntpq
libntpq.c revision 1.3
      1 /*	$NetBSD: libntpq.c,v 1.3 2015/07/10 14:20:33 christos Exp $	*/
      2 
      3 /*****************************************************************************
      4  *
      5  *  libntpq.c
      6  *
      7  *  This is the wrapper library for ntpq, the NTP query utility.
      8  *  This library reuses the sourcecode from ntpq and exports a number
      9  *  of useful functions in a library that can be linked against applications
     10  *  that need to query the status of a running ntpd. The whole
     11  *  communcation is based on mode 6 packets.
     12  *
     13  ****************************************************************************/
     14 #define LIBNTPQ_C
     15 #define NO_MAIN_ALLOWED 1
     16 /* #define BUILD_AS_LIB		Already provided by the Makefile */
     17 
     18 #include "ntpq.c"
     19 #include "libntpq.h"
     20 
     21 /* Function Prototypes */
     22 
     23 
     24 const char *Version = "libntpq 0.3beta";
     25 
     26 /* global variables used for holding snapshots of data */
     27 char peervars[NTPQ_BUFLEN];
     28 int peervarlen = 0;
     29 associd_t peervar_assoc = 0;
     30 char clockvars[NTPQ_BUFLEN];
     31 int clockvarlen = 0;
     32 int clockvar_assoc = 0;
     33 char sysvars[NTPQ_BUFLEN];
     34 int sysvarlen = 0;
     35 char *ntpq_resultbuffer[NTPQ_BUFLEN];
     36 unsigned short ntpq_associations[MAXASSOC];
     37 struct ntpq_varlist ntpq_varlist[MAXLIST];
     38 
     39 /*****************************************************************************
     40  *
     41  *  ntpq_stripquotes
     42  *
     43  *  Parses a given character buffer srcbuf and removes all quoted
     44  *  characters. The resulting string is copied to the specified
     45  *  resultbuf character buffer.  E.g. \" will be translated into "
     46  *
     47  ****************************************************************************
     48  * Parameters:
     49  *	resultbuf	char*	The resulting string without quoted
     50  *				characters
     51  *	srcbuf		char*	The buffer holding the original string
     52  *	datalen		int	The number of bytes stored in srcbuf
     53  *	maxlen		int	Max. number of bytes for resultbuf
     54  *
     55  * Returns:
     56  *	int		number of chars that have been copied to
     57  *			resultbuf
     58  ****************************************************************************/
     59 
     60 int ntpq_stripquotes ( char *resultbuf, char *srcbuf, int datalen, int maxlen )
     61 {
     62 	char* tmpbuf = srcbuf;
     63 
     64 	while ( *tmpbuf != 0 )
     65 	{
     66 		if ( *tmpbuf == '\"' )
     67 		{
     68 			tmpbuf++;
     69 			continue;
     70 		}
     71 
     72 		if ( *tmpbuf == '\\' )
     73 		{
     74 			tmpbuf++;
     75 			switch ( *tmpbuf )
     76 			{
     77 				/* ignore if end of string */
     78 				case 0:
     79 					continue;
     80 				/* skip and do not copy */
     81 				case '\"': /* quotes */
     82 				case 'n': /*newline*/
     83 				case 'r': /*carriage return*/
     84 				case 'g': /*bell*/
     85 				case 't': /*tab*/
     86 					tmpbuf++;
     87 					continue;
     88 			}
     89 		}
     90 
     91 		*resultbuf++ = *tmpbuf++;
     92 
     93 	}
     94 
     95 	*resultbuf = 0;
     96 	return strlen(resultbuf);
     97 }
     98 
     99 
    100 /*****************************************************************************
    101  *
    102  *  ntpq_getvar
    103  *
    104  *  This function parses a given buffer for a variable/value pair and
    105  *  copies the value of the requested variable into the specified
    106  *  varvalue buffer.
    107  *
    108  *  It returns the number of bytes copied or zero for an empty result
    109  *  (=no matching variable found or empty value)
    110  *
    111  ****************************************************************************
    112  * Parameters:
    113  *	resultbuf	char*	The resulting string without quoted
    114  *				characters
    115  *	datalen		size_t	The number of bytes stored in
    116  *							resultbuf
    117  *	varname		char*	Name of the required variable
    118  *	varvalue	char*	Where the value of the variable should
    119  *							be stored
    120  *	maxlen		size_t	Max. number of bytes for varvalue
    121  *
    122  * Returns:
    123  *	size_t		number of chars that have been copied to
    124  *			varvalue
    125  ****************************************************************************/
    126 
    127 size_t
    128 ntpq_getvar(
    129 	const char *	resultbuf,
    130 	size_t		datalen,
    131 	const char *	varname,
    132 	char *		varvalue,
    133 	size_t		maxlen)
    134 {
    135 	char *	name;
    136 	char *	value;
    137 	int	idatalen;
    138 
    139 	value = NULL;
    140 	idatalen = (int)datalen;
    141 
    142 	while (nextvar(&idatalen, &resultbuf, &name, &value)) {
    143 		if (strcmp(varname, name) == 0) {
    144 			ntpq_stripquotes(varvalue, value, strlen(value), maxlen);
    145 
    146 			return strlen(varvalue);
    147 		}
    148 	}
    149 
    150 	return 0;
    151 }
    152 
    153 
    154 /*****************************************************************************
    155  *
    156  *  ntpq_queryhost
    157  *
    158  *  Sends a mode 6 query packet to the current open host (see
    159  *  ntpq_openhost) and stores the requested variable set in the specified
    160  *  character buffer.
    161  *  It returns the number of bytes read or zero for an empty result
    162  *  (=no answer or empty value)
    163  *
    164  ****************************************************************************
    165  * Parameters:
    166  *      VARSET		u_short	Which variable set should be
    167  *				read (PEERVARS or CLOCKVARS)
    168  *	association	int	The association ID that should be read
    169  *				0 represents the ntpd instance itself
    170  *	resultbuf	char*	The resulting string without quoted
    171  *				characters
    172  *	maxlen		int	Max. number of bytes for varvalue
    173  *
    174  * Returns:
    175  *	int		number of bytes that have been copied to
    176  *			resultbuf
    177  *  			- OR -
    178  *			0 (zero) if no reply has been received or
    179  *			another failure occured
    180  ****************************************************************************/
    181 
    182 int ntpq_queryhost(unsigned short VARSET, unsigned short association, char *resultbuf, int maxlen)
    183 {
    184 	const char *datap;
    185 	int res;
    186 	int dsize;
    187 	u_short rstatus;
    188 
    189 	if ( numhosts > 0 )
    190 		res = doquery(VARSET,association,0,0, (char *)0, &rstatus, &dsize, &datap);
    191 	else
    192 		return 0;
    193 
    194 	if ( ( res != 0) || ( dsize == 0 ) ) /* no data */
    195 		return 0;
    196 
    197 	if ( dsize > maxlen)
    198 		dsize = maxlen;
    199 
    200 
    201 	/* fill result resultbuf */
    202 	memcpy(resultbuf, datap, dsize);
    203 
    204 	return dsize;
    205 }
    206 
    207 
    208 
    209 /*****************************************************************************
    210  *
    211  *  ntpq_openhost
    212  *
    213  *  Sets up a connection to the ntpd instance of a specified host. Note:
    214  *  There is no real "connection" established because NTP solely works
    215  *  based on UDP.
    216  *
    217  ****************************************************************************
    218  * Parameters:
    219  *	hostname	char*	Hostname/IP of the host running ntpd
    220  *	fam		int	Address Family (AF_INET, AF_INET6, or 0)
    221  *
    222  * Returns:
    223  *	int		1 if the host connection could be set up, i.e.
    224  *			name resolution was succesful and/or IP address
    225  *			has been validated
    226  *  			- OR -
    227  *			0 (zero) if a failure occured
    228  ****************************************************************************/
    229 
    230 int
    231 ntpq_openhost(
    232 	char *hostname,
    233 	int fam
    234 	)
    235 {
    236 	if ( openhost(hostname, fam) )
    237 	{
    238 		numhosts = 1;
    239 	} else {
    240 		numhosts = 0;
    241 	}
    242 
    243 	return numhosts;
    244 
    245 }
    246 
    247 
    248 /*****************************************************************************
    249  *
    250  *  ntpq_closehost
    251  *
    252  *  Cleans up a connection by closing the used socket. Should be called
    253  *  when no further queries are required for the currently used host.
    254  *
    255  ****************************************************************************
    256  * Parameters:
    257  *	- none -
    258  *
    259  * Returns:
    260  *	int		0 (zero) if no host has been opened before
    261  *			- OR -
    262  *			the resultcode from the closesocket function call
    263  ****************************************************************************/
    264 
    265 int ntpq_closehost(void)
    266 {
    267 	if ( numhosts )
    268 	 return closesocket(sockfd);
    269 
    270 	return 0;
    271 }
    272 
    273 
    274 /*****************************************************************************
    275  *
    276  *  ntpq_read_associations
    277  *
    278  *  This function queries the ntp host for its associations and returns the
    279  *  number of associations found.
    280  *
    281  *  It takes an u_short array as its first parameter, this array holds the
    282  *  IDs of the associations,
    283  *  the function will not write more entries than specified with the
    284  *  max_entries parameter.
    285  *
    286  *  However, if more than max_entries associations were found, the return
    287  *  value of this function will reflect the real number, even if not all
    288  *  associations have been stored in the array.
    289  *
    290  ****************************************************************************
    291  * Parameters:
    292  *	resultbuf	u_short*Array that should hold the list of
    293  *				association IDs
    294  *	maxentries	int	maximum number of association IDs that can
    295  *				be stored in resultbuf
    296  *
    297  * Returns:
    298  *	int		number of association IDs stored in resultbuf
    299  *  			- OR -
    300  *			0 (zero) if a failure occured or no association has
    301  *			been returned.
    302  ****************************************************************************/
    303 
    304  int  ntpq_read_associations ( u_short resultbuf[], int max_entries )
    305 {
    306     int i = 0;
    307 
    308     if (ntpq_dogetassoc()) {
    309 
    310         if(numassoc < max_entries)
    311           max_entries = numassoc;
    312 
    313         for (i=0;i<max_entries;i++)
    314             resultbuf[i] = assoc_cache[i].assid;
    315 
    316         return numassoc;
    317     }
    318 
    319     return 0;
    320 }
    321 
    322 
    323 
    324 
    325 /*****************************************************************************
    326  *
    327  *  ntpq_get_assocs
    328  *
    329  *  This function reads the associations of a previously selected (with
    330  *  ntpq_openhost) NTP host into its own (global) array and returns the
    331  *  number of associations found.
    332  *
    333  *  The obtained association IDs can be read by using the ntpq_get_assoc_id
    334  *  function.
    335  *
    336  ****************************************************************************
    337  * Parameters:
    338  *	- none -
    339  *
    340  * Returns:
    341  *	int		number of association IDs stored in resultbuf
    342  *  			- OR -
    343  *			0 (zero) if a failure occured or no association has
    344  *			been returned.
    345  ****************************************************************************/
    346 
    347  int  ntpq_get_assocs ( void )
    348 {
    349     return ntpq_read_associations( ntpq_associations, MAXASSOC );
    350 }
    351 
    352 
    353 /*****************************************************************************
    354  *
    355  *  ntpq_get_assoc_number
    356  *
    357  *  This function returns for a given Association ID the association number
    358  *  in the internal association array, which is filled by the ntpq_get_assocs
    359  *  function.
    360  *
    361  ****************************************************************************
    362  * Parameters:
    363  *	associd		int	requested associaton ID
    364  *
    365  * Returns:
    366  *	int		the number of the association array element that is
    367  *			representing the given association ID
    368  *  			- OR -
    369  *			-1 if a failure occured or no matching association
    370  * 			ID has been found
    371  ****************************************************************************/
    372 
    373 int ntpq_get_assoc_number ( associd_t associd )
    374 {
    375 	int i;
    376 
    377 	for (i=0;i<numassoc;i++) {
    378 		if (assoc_cache[i].assid == associd)
    379 			return i;
    380 	}
    381 
    382 	return -1;
    383 
    384 }
    385 
    386 
    387 /*****************************************************************************
    388  *
    389  *  ntpq_read_assoc_peervars
    390  *
    391  *  This function reads the peervars variable-set of a specified association
    392  *  from a NTP host and writes it to the result buffer specified, honoring
    393  *  the maxsize limit.
    394  *
    395  *  It returns the number of bytes written or 0 when the variable-set is
    396  *  empty or failed to read.
    397  *
    398  ****************************************************************************
    399  * Parameters:
    400  *	associd		int	requested associaton ID
    401  *	resultbuf	char*	character buffer where the variable set
    402  *				should be stored
    403  *	maxsize		int	the maximum number of bytes that can be
    404  *				written to resultbuf
    405  *
    406  * Returns:
    407  *	int		number of chars that have been copied to
    408  *			resultbuf
    409  *			- OR -
    410  *			0 (zero) if an error occured
    411  ****************************************************************************/
    412 
    413 int
    414 ntpq_read_assoc_peervars(
    415 	associd_t	associd,
    416 	char *		resultbuf,
    417 	int		maxsize
    418 	)
    419 {
    420 	const char *	datap;
    421 	int		res;
    422 	int		dsize;
    423 	u_short		rstatus;
    424 
    425 	res = doquery(CTL_OP_READVAR, associd, 0, 0, NULL, &rstatus,
    426 		      &dsize, &datap);
    427 	if (res != 0)
    428 		return 0;
    429 	if (dsize <= 0) {
    430 		if (numhosts > 1)
    431 			fprintf(stderr, "server=%s ", currenthost);
    432 		fprintf(stderr,
    433 			"***No information returned for association %d\n",
    434 			associd);
    435 
    436 		return 0;
    437 	}
    438 	if (dsize > maxsize)
    439 		dsize = maxsize;
    440 	memcpy(resultbuf, datap, dsize);
    441 
    442 	return dsize;
    443 }
    444 
    445 
    446 
    447 
    448 /*****************************************************************************
    449  *
    450  *  ntpq_read_sysvars
    451  *
    452  *  This function reads the sysvars variable-set from a NTP host and writes it
    453  *  to the result buffer specified, honoring the maxsize limit.
    454  *
    455  *  It returns the number of bytes written or 0 when the variable-set is empty
    456  *  or could not be read.
    457  *
    458  ****************************************************************************
    459  * Parameters:
    460  *	resultbuf	char*	character buffer where the variable set
    461  *				should be stored
    462  *	maxsize		int	the maximum number of bytes that can be
    463  *				written to resultbuf
    464  *
    465  * Returns:
    466  *	int		number of chars that have been copied to
    467  *			resultbuf
    468  *			- OR -
    469  *			0 (zero) if an error occured
    470  ****************************************************************************/
    471 size_t
    472 ntpq_read_sysvars(
    473 	char *	resultbuf,
    474 	size_t	maxsize
    475 	)
    476 {
    477 	const char *	datap;
    478 	int		res;
    479 	int		i_dsize;
    480 	size_t		dsize;
    481 	u_short		rstatus;
    482 
    483 	res = doquery(CTL_OP_READVAR, 0, 0, 0, NULL, &rstatus,
    484 		      &i_dsize, &datap);
    485 
    486 	if (res != 0)
    487 		return 0;
    488 
    489 	if (i_dsize == 0) {
    490 		if (numhosts > 1)
    491 			fprintf(stderr, "server=%s ", currenthost);
    492 		fprintf(stderr, "***No sysvar information returned\n");
    493 
    494 		return 0;
    495 	} else {
    496 		dsize = max(0, i_dsize);
    497 		dsize = min(dsize, maxsize);
    498 		memcpy(resultbuf, datap, dsize);
    499 	}
    500 
    501 	return dsize;
    502 }
    503 
    504 
    505 /*****************************************************************************
    506  *  ntpq_get_assoc_allvars
    507  *
    508  *  With this function all association variables for the specified association
    509  *  ID can be requested from a NTP host. They are stored internally and can be
    510  *  read by using the ntpq_get_peervar or ntpq_get_clockvar functions.
    511  *
    512  *  Basically this is only a combination of the ntpq_get_assoc_peervars and
    513  *  ntpq_get_assoc_clockvars functions.
    514  *
    515  *  It returns 1 if both variable-sets (peervars and clockvars) were
    516  *  received successfully. If one variable-set or both of them weren't
    517  *  received,
    518  *
    519  ****************************************************************************
    520  * Parameters:
    521  *	associd		int	requested associaton ID
    522  *
    523  * Returns:
    524  *	int		nonzero if at least one variable set could be read
    525  * 			- OR -
    526  *			0 (zero) if an error occured and both variable sets
    527  *			could not be read
    528  ****************************************************************************/
    529  int  ntpq_get_assoc_allvars( associd_t associd  )
    530 {
    531 	return ntpq_get_assoc_peervars ( associd ) &
    532 	       ntpq_get_assoc_clockvars( associd );
    533 }
    534 
    535 
    536 
    537 
    538 /*****************************************************************************
    539  *
    540  *  ntpq_get_sysvars
    541  *
    542  *  The system variables of a NTP host can be requested by using this function
    543  *  and afterwards using ntpq_get_sysvar to read the single variable values.
    544  *
    545  ****************************************************************************
    546  * Parameters:
    547  *	- none -
    548  *
    549  * Returns:
    550  *	int		nonzero if the variable set could be read
    551  * 			- OR -
    552  *			0 (zero) if an error occured and the sysvars
    553  *			could not be read
    554  ****************************************************************************/
    555 int
    556 ntpq_get_sysvars(void)
    557 {
    558 	sysvarlen = ntpq_read_sysvars(sysvars, sizeof(sysvars));
    559 	if (sysvarlen <= 0)
    560 		return 0;
    561 	else
    562 		return 1;
    563 }
    564 
    565 
    566 /*****************************************************************************
    567  *
    568  *  ntp_get_peervar
    569  *
    570  *  This function uses the variable-set which was read by using
    571  *  ntp_get_peervars and searches for a variable specified with varname. If
    572  *  such a variable exists, it writes its value into
    573  *  varvalue (maxlen specifies the size of this target buffer).
    574  *
    575  ****************************************************************************
    576  * Parameters:
    577  *	varname		char*	requested variable name
    578  *	varvalue	char*	the buffer where the value should go into
    579  *	maxlen		int	maximum number of bytes that can be copied to
    580  *				varvalue
    581  *
    582  * Returns:
    583  *	int		number of bytes copied to varvalue
    584  * 			- OR -
    585  *			0 (zero) if an error occured or the variable could
    586  *			not be found
    587  ****************************************************************************/
    588 int ntpq_get_peervar( const char *varname, char *varvalue, int maxlen)
    589 {
    590     return ( ntpq_getvar(peervars,peervarlen,varname,varvalue,maxlen) );
    591 }
    592 
    593 
    594 
    595 /*****************************************************************************
    596  *
    597  *  ntpq_get_assoc_peervars
    598  *
    599  *  This function requests the peer variables of the specified association
    600  *  from a NTP host. In order to access the variable values, the function
    601  *  ntpq_get_peervar must be used.
    602  *
    603  ****************************************************************************
    604  * Parameters:
    605  *	associd		int	requested associaton ID
    606  *
    607  * Returns:
    608  *	int		1 (one) if the peervars have been read
    609  * 			- OR -
    610  *			0 (zero) if an error occured and the variable set
    611  *			could not be read
    612  ****************************************************************************/
    613 int
    614 ntpq_get_assoc_peervars(
    615 	associd_t associd
    616 	)
    617 {
    618 	peervarlen = ntpq_read_assoc_peervars(associd, peervars,
    619 					      sizeof(peervars));
    620 	if (peervarlen <= 0) {
    621 		peervar_assoc = 0;
    622 
    623 		return 0;
    624 	}
    625 	peervar_assoc = associd;
    626 
    627 	return 1;
    628 }
    629 
    630 
    631 /*****************************************************************************
    632  *
    633  *  ntp_read_assoc_clockvars
    634  *
    635  *  This function reads the clockvars variable-set of a specified association
    636  *  from a NTP host and writes it to the result buffer specified, honoring
    637  *  the maxsize limit.
    638  *
    639  *  It returns the number of bytes written or 0 when the variable-set is
    640  *  empty or failed to read.
    641  *
    642  ****************************************************************************
    643  * Parameters:
    644  *	associd		int	requested associaton ID
    645  *	resultbuf	char*	character buffer where the variable set
    646  *				should be stored
    647  *	maxsize		int	the maximum number of bytes that can be
    648  *				written to resultbuf
    649  *
    650  * Returns:
    651  *	int		number of chars that have been copied to
    652  *			resultbuf
    653  *			- OR -
    654  *			0 (zero) if an error occured
    655  ****************************************************************************/
    656 
    657 int
    658 ntpq_read_assoc_clockvars(
    659 	associd_t	associd,
    660 	char *		resultbuf,
    661 	int		maxsize
    662 	)
    663 {
    664 	const char *datap;
    665 	int res;
    666 	int dsize;
    667 	u_short rstatus;
    668 
    669 	res = ntpq_doquerylist(ntpq_varlist, CTL_OP_READCLOCK, associd,
    670 			       0, &rstatus, &dsize, &datap);
    671 	if (res != 0)
    672 		return 0;
    673 
    674 	if (dsize == 0) {
    675 		if (numhosts > 1) /* no information returned from server */
    676 			return 0;
    677 	} else {
    678 		if (dsize > maxsize)
    679 			dsize = maxsize;
    680 		memcpy(resultbuf, datap, dsize);
    681 	}
    682 
    683 	return dsize;
    684 }
    685 
    686 
    687 
    688 /*****************************************************************************
    689  *
    690  *  ntpq_get_assoc_clocktype
    691  *
    692  *  This function returns a clocktype value for a given association number
    693  *  (not ID!):
    694  *
    695  *  NTP_CLOCKTYPE_UNKNOWN   Unknown clock type
    696  *  NTP_CLOCKTYPE_BROADCAST Broadcast server
    697  *  NTP_CLOCKTYPE_LOCAL     Local clock
    698  *  NTP_CLOCKTYPE_UNICAST   Unicast server
    699  *  NTP_CLOCKTYPE_MULTICAST Multicast server
    700  *
    701  ****************************************************************************/
    702 int
    703 ntpq_get_assoc_clocktype(
    704 	int assoc_index
    705 	)
    706 {
    707 	associd_t	associd;
    708 	int		i;
    709 	int		rc;
    710 	sockaddr_u	dum_store;
    711 	char		dstadr[LENHOSTNAME];
    712 	char		resultbuf[NTPQ_BUFLEN];
    713 
    714 	if (assoc_index < 0 || assoc_index >= numassoc)
    715 		return -1;
    716 
    717 	associd = assoc_cache[assoc_index].assid;
    718 	if (associd == peervar_assoc) {
    719 		rc = ntpq_get_peervar("dstadr", dstadr, sizeof(dstadr));
    720 	} else {
    721 		i = ntpq_read_assoc_peervars(associd, resultbuf,
    722 					     sizeof(resultbuf));
    723 		if (i <= 0)
    724 			return -1;
    725 		rc = ntpq_getvar(resultbuf, i, "dstadr", dstadr,
    726 				 sizeof(dstadr));
    727 	}
    728 
    729 	if (0 != rc && decodenetnum(dstadr, &dum_store))
    730 		return ntpq_decodeaddrtype(&dum_store);
    731 
    732 	return -1;
    733 }
    734 
    735 
    736 
    737 /*****************************************************************************
    738  *
    739  *  ntpq_get_assoc_clockvars
    740  *
    741  *  With this function the clock variables of the specified association are
    742  *  requested from a NTP host. This makes only sense for associations with
    743  *  the type 'l' (Local Clock) and you should check this with
    744  *  ntpq_get_assoc_clocktype for each association, before you use this function
    745  *  on it.
    746  *
    747  ****************************************************************************
    748  * Parameters:
    749  *	associd		int	requested associaton ID
    750  *
    751  * Returns:
    752  *	int		1 (one) if the clockvars have been read
    753  * 			- OR -
    754  *			0 (zero) if an error occured and the variable set
    755  *			could not be read
    756  ****************************************************************************/
    757 int  ntpq_get_assoc_clockvars( associd_t associd )
    758 {
    759 	if (NTP_CLOCKTYPE_LOCAL != ntpq_get_assoc_clocktype(
    760 	    ntpq_get_assoc_number(associd)))
    761 		return 0;
    762 	clockvarlen = ntpq_read_assoc_clockvars( associd, clockvars,
    763 						 sizeof(clockvars) );
    764 	if ( clockvarlen <= 0 ) {
    765 		clockvar_assoc = 0;
    766 		return 0;
    767 	} else {
    768 		clockvar_assoc = associd;
    769 		return 1;
    770 	}
    771 }
    772 
    773 
    774