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