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