libntpq.c revision 1.1.1.7 1 /* $NetBSD: libntpq.c,v 1.1.1.7 2016/01/08 21:21:27 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 size_t 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 size_t 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 size_t 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 size_t dsize;
480 u_short rstatus;
481
482 res = doquery(CTL_OP_READVAR, 0, 0, 0, NULL, &rstatus,
483 &dsize, &datap);
484
485 if (res != 0)
486 return 0;
487
488 if (dsize == 0) {
489 if (numhosts > 1)
490 fprintf(stderr, "server=%s ", currenthost);
491 fprintf(stderr, "***No sysvar information returned\n");
492
493 return 0;
494 } else {
495 dsize = min(dsize, maxsize);
496 memcpy(resultbuf, datap, dsize);
497 }
498
499 return dsize;
500 }
501
502
503 /*****************************************************************************
504 * ntpq_get_assoc_allvars
505 *
506 * With this function all association variables for the specified association
507 * ID can be requested from a NTP host. They are stored internally and can be
508 * read by using the ntpq_get_peervar or ntpq_get_clockvar functions.
509 *
510 * Basically this is only a combination of the ntpq_get_assoc_peervars and
511 * ntpq_get_assoc_clockvars functions.
512 *
513 * It returns 1 if both variable-sets (peervars and clockvars) were
514 * received successfully. If one variable-set or both of them weren't
515 * received,
516 *
517 ****************************************************************************
518 * Parameters:
519 * associd int requested associaton ID
520 *
521 * Returns:
522 * int nonzero if at least one variable set could be read
523 * - OR -
524 * 0 (zero) if an error occured and both variable sets
525 * could not be read
526 ****************************************************************************/
527 int ntpq_get_assoc_allvars( associd_t associd )
528 {
529 return ntpq_get_assoc_peervars ( associd ) &
530 ntpq_get_assoc_clockvars( associd );
531 }
532
533
534
535
536 /*****************************************************************************
537 *
538 * ntpq_get_sysvars
539 *
540 * The system variables of a NTP host can be requested by using this function
541 * and afterwards using ntpq_get_sysvar to read the single variable values.
542 *
543 ****************************************************************************
544 * Parameters:
545 * - none -
546 *
547 * Returns:
548 * int nonzero if the variable set could be read
549 * - OR -
550 * 0 (zero) if an error occured and the sysvars
551 * could not be read
552 ****************************************************************************/
553 int
554 ntpq_get_sysvars(void)
555 {
556 sysvarlen = ntpq_read_sysvars(sysvars, sizeof(sysvars));
557 if (sysvarlen <= 0)
558 return 0;
559 else
560 return 1;
561 }
562
563
564 /*****************************************************************************
565 *
566 * ntp_get_peervar
567 *
568 * This function uses the variable-set which was read by using
569 * ntp_get_peervars and searches for a variable specified with varname. If
570 * such a variable exists, it writes its value into
571 * varvalue (maxlen specifies the size of this target buffer).
572 *
573 ****************************************************************************
574 * Parameters:
575 * varname char* requested variable name
576 * varvalue char* the buffer where the value should go into
577 * maxlen int maximum number of bytes that can be copied to
578 * varvalue
579 *
580 * Returns:
581 * int number of bytes copied to varvalue
582 * - OR -
583 * 0 (zero) if an error occured or the variable could
584 * not be found
585 ****************************************************************************/
586 int ntpq_get_peervar( const char *varname, char *varvalue, int maxlen)
587 {
588 return ( ntpq_getvar(peervars,peervarlen,varname,varvalue,maxlen) );
589 }
590
591
592
593 /*****************************************************************************
594 *
595 * ntpq_get_assoc_peervars
596 *
597 * This function requests the peer variables of the specified association
598 * from a NTP host. In order to access the variable values, the function
599 * ntpq_get_peervar must be used.
600 *
601 ****************************************************************************
602 * Parameters:
603 * associd int requested associaton ID
604 *
605 * Returns:
606 * int 1 (one) if the peervars have been read
607 * - OR -
608 * 0 (zero) if an error occured and the variable set
609 * could not be read
610 ****************************************************************************/
611 int
612 ntpq_get_assoc_peervars(
613 associd_t associd
614 )
615 {
616 peervarlen = ntpq_read_assoc_peervars(associd, peervars,
617 sizeof(peervars));
618 if (peervarlen <= 0) {
619 peervar_assoc = 0;
620
621 return 0;
622 }
623 peervar_assoc = associd;
624
625 return 1;
626 }
627
628
629 /*****************************************************************************
630 *
631 * ntp_read_assoc_clockvars
632 *
633 * This function reads the clockvars variable-set of a specified association
634 * from a NTP host and writes it to the result buffer specified, honoring
635 * the maxsize limit.
636 *
637 * It returns the number of bytes written or 0 when the variable-set is
638 * empty or failed to read.
639 *
640 ****************************************************************************
641 * Parameters:
642 * associd int requested associaton ID
643 * resultbuf char* character buffer where the variable set
644 * should be stored
645 * maxsize int the maximum number of bytes that can be
646 * written to resultbuf
647 *
648 * Returns:
649 * int number of chars that have been copied to
650 * resultbuf
651 * - OR -
652 * 0 (zero) if an error occured
653 ****************************************************************************/
654
655 int
656 ntpq_read_assoc_clockvars(
657 associd_t associd,
658 char * resultbuf,
659 int maxsize
660 )
661 {
662 const char *datap;
663 int res;
664 size_t dsize;
665 u_short rstatus;
666
667 res = ntpq_doquerylist(ntpq_varlist, CTL_OP_READCLOCK, associd,
668 0, &rstatus, &dsize, &datap);
669 if (res != 0)
670 return 0;
671
672 if (dsize == 0) {
673 if (numhosts > 1) /* no information returned from server */
674 return 0;
675 } else {
676 if (dsize > maxsize)
677 dsize = maxsize;
678 memcpy(resultbuf, datap, dsize);
679 }
680
681 return dsize;
682 }
683
684
685
686 /*****************************************************************************
687 *
688 * ntpq_get_assoc_clocktype
689 *
690 * This function returns a clocktype value for a given association number
691 * (not ID!):
692 *
693 * NTP_CLOCKTYPE_UNKNOWN Unknown clock type
694 * NTP_CLOCKTYPE_BROADCAST Broadcast server
695 * NTP_CLOCKTYPE_LOCAL Local clock
696 * NTP_CLOCKTYPE_UNICAST Unicast server
697 * NTP_CLOCKTYPE_MULTICAST Multicast server
698 *
699 ****************************************************************************/
700 int
701 ntpq_get_assoc_clocktype(
702 int assoc_index
703 )
704 {
705 associd_t associd;
706 int i;
707 int rc;
708 sockaddr_u dum_store;
709 char dstadr[LENHOSTNAME];
710 char resultbuf[NTPQ_BUFLEN];
711
712 if (assoc_index < 0 || assoc_index >= numassoc)
713 return -1;
714
715 associd = assoc_cache[assoc_index].assid;
716 if (associd == peervar_assoc) {
717 rc = ntpq_get_peervar("dstadr", dstadr, sizeof(dstadr));
718 } else {
719 i = ntpq_read_assoc_peervars(associd, resultbuf,
720 sizeof(resultbuf));
721 if (i <= 0)
722 return -1;
723 rc = ntpq_getvar(resultbuf, i, "dstadr", dstadr,
724 sizeof(dstadr));
725 }
726
727 if (0 != rc && decodenetnum(dstadr, &dum_store))
728 return ntpq_decodeaddrtype(&dum_store);
729
730 return -1;
731 }
732
733
734
735 /*****************************************************************************
736 *
737 * ntpq_get_assoc_clockvars
738 *
739 * With this function the clock variables of the specified association are
740 * requested from a NTP host. This makes only sense for associations with
741 * the type 'l' (Local Clock) and you should check this with
742 * ntpq_get_assoc_clocktype for each association, before you use this function
743 * on it.
744 *
745 ****************************************************************************
746 * Parameters:
747 * associd int requested associaton ID
748 *
749 * Returns:
750 * int 1 (one) if the clockvars have been read
751 * - OR -
752 * 0 (zero) if an error occured and the variable set
753 * could not be read
754 ****************************************************************************/
755 int ntpq_get_assoc_clockvars( associd_t associd )
756 {
757 if (NTP_CLOCKTYPE_LOCAL != ntpq_get_assoc_clocktype(
758 ntpq_get_assoc_number(associd)))
759 return 0;
760 clockvarlen = ntpq_read_assoc_clockvars( associd, clockvars,
761 sizeof(clockvars) );
762 if ( clockvarlen <= 0 ) {
763 clockvar_assoc = 0;
764 return 0;
765 } else {
766 clockvar_assoc = associd;
767 return 1;
768 }
769 }
770
771
772