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