1 /*        $NetBSD: ntpdc_ops.c,v 1.11 2020/05/25 20:47:26 christos Exp $        */
2 
3 /*
4  * ntpdc_ops.c - subroutines which are called to perform operations by
5  *                   ntpdc
6  */
7 
8 #ifdef HAVE_CONFIG_H
9 # include <config.h>
10 #endif
11 
12 #include <stdio.h>
13 #include <stddef.h>
14 
15 #include "ntpdc.h"
16 #include "ntp_net.h"
17 #include "ntp_control.h"
18 #include "ntp_refclock.h"
19 #include "ntp_stdlib.h"
20 
21 #include <ctype.h>
22 #ifdef HAVE_SYS_TIMEX_H
23 # include <sys/timex.h>
24 #endif
25 #if !defined(__bsdi__) && !defined(apollo)
26 #ifdef HAVE_NETINET_IN_H
27 #include <netinet/in.h>
28 #endif
29 #endif
30 
31 #include <arpa/inet.h>
32 
33 /*
34  * utility functions
35  */
36 static    int       checkitems          (size_t, FILE *);
37 static    int       checkitemsize       (size_t, size_t);
38 static    int       check1item          (size_t, FILE *);
39 
40 /*
41  * Declarations for command handlers in here
42  */
43 static    void      peerlist  (struct parse *, FILE *);
44 static    void      peers               (struct parse *, FILE *);
45 static    void      doconfig  (struct parse *pcmd, FILE *fp, int mode, int refc);
46 static    void      dmpeers             (struct parse *, FILE *);
47 static    void      dopeers             (struct parse *, FILE *, int);
48 static    void      printpeer (struct info_peer *, FILE *);
49 static    void      showpeer  (struct parse *, FILE *);
50 static    void      peerstats (struct parse *, FILE *);
51 static    void      loopinfo  (struct parse *, FILE *);
52 static    void      sysinfo             (struct parse *, FILE *);
53 static    void      sysstats  (struct parse *, FILE *);
54 static    void      iostats             (struct parse *, FILE *);
55 static    void      memstats  (struct parse *, FILE *);
56 static    void      timerstats          (struct parse *, FILE *);
57 static    void      addpeer             (struct parse *, FILE *);
58 static    void      addserver (struct parse *, FILE *);
59 static    void      addrefclock         (struct parse *, FILE *);
60 static    void      broadcast (struct parse *, FILE *);
61 static    void      doconfig  (struct parse *, FILE *, int, int);
62 static    void      unconfig  (struct parse *, FILE *);
63 static    void      set                 (struct parse *, FILE *);
64 static    void      sys_clear (struct parse *, FILE *);
65 static    void      doset               (struct parse *, FILE *, int);
66 static    void      reslist             (struct parse *, FILE *);
67 static    void      new_restrict        (struct parse *, FILE *);
68 static    void      unrestrict          (struct parse *, FILE *);
69 static    void      delrestrict         (struct parse *, FILE *);
70 static    void      do_restrict         (struct parse *, FILE *, int);
71 static    void      monlist             (struct parse *, FILE *);
72 static    void      reset               (struct parse *, FILE *);
73 static    void      preset              (struct parse *, FILE *);
74 static    void      readkeys  (struct parse *, FILE *);
75 static    void      trustkey  (struct parse *, FILE *);
76 static    void      untrustkey          (struct parse *, FILE *);
77 static    void      do_trustkey         (struct parse *, FILE *, int);
78 static    void      authinfo  (struct parse *, FILE *);
79 static    void      traps               (struct parse *, FILE *);
80 static    void      addtrap             (struct parse *, FILE *);
81 static    void      clrtrap             (struct parse *, FILE *);
82 static    void      do_addclr_trap      (struct parse *, FILE *, int);
83 static    void      requestkey          (struct parse *, FILE *);
84 static    void      controlkey          (struct parse *, FILE *);
85 static    void      do_changekey        (struct parse *, FILE *, int);
86 static    void      ctlstats  (struct parse *, FILE *);
87 static    void      clockstat (struct parse *, FILE *);
88 static    void      fudge               (struct parse *, FILE *);
89 static    void      clkbug              (struct parse *, FILE *);
90 static    void      kerninfo  (struct parse *, FILE *);
91 static    void      get_if_stats        (struct parse *, FILE *);
92 static    void      do_if_reload        (struct parse *, FILE *);
93 
94 /*
95  * Commands we understand.  Ntpdc imports this.
96  */
97 struct xcmd opcmds[] = {
98           { "listpeers",      peerlist, { OPT|IP_VERSION, NO, NO, NO },
99             { "-4|-6", "", "", "" },
100             "display list of peers the server knows about [IP Version]" },
101           { "peers",          peers,    { OPT|IP_VERSION, NO, NO, NO },
102             { "-4|-6", "", "", "" },
103             "display peer summary information [IP Version]" },
104           { "dmpeers",        dmpeers,  { OPT|IP_VERSION, NO, NO, NO },
105             { "-4|-6", "", "", "" },
106             "display peer summary info the way Dave Mills likes it (IP Version)" },
107           { "showpeer",       showpeer,           { NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD},
108             { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
109             "display detailed information for one or more peers" },
110           { "pstats",         peerstats,          { NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD },
111             { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
112             "display statistical information for one or more peers" },
113           { "loopinfo",       loopinfo, { OPT|NTP_STR, NO, NO, NO },
114             { "oneline|multiline", "", "", "" },
115             "display loop filter information" },
116           { "sysinfo",        sysinfo,  { NO, NO, NO, NO },
117             { "", "", "", "" },
118             "display local server information" },
119           { "sysstats",       sysstats, { NO, NO, NO, NO },
120             { "", "", "", "" },
121             "display local server statistics" },
122           { "memstats",       memstats, { NO, NO, NO, NO },
123             { "", "", "", "" },
124             "display peer memory usage statistics" },
125           { "iostats",        iostats,  { NO, NO, NO, NO },
126             { "", "", "", "" },
127             "display I/O subsystem statistics" },
128           { "timerstats",     timerstats,         { NO, NO, NO, NO },
129             { "", "", "", "" },
130             "display event timer subsystem statistics" },
131           { "addpeer",        addpeer,  { NTP_ADD, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
132             { "addr", "keyid", "version", "minpoll#|prefer|burst|iburst|'minpoll N'|'maxpoll N'|'keyid N'|'version N' ..." },
133             "configure a new peer association" },
134           { "addserver",      addserver,          { NTP_ADD, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
135             { "addr", "keyid", "version", "minpoll#|prefer|burst|iburst|'minpoll N'|'maxpoll N'|'keyid N'|'version N' ..." },
136             "configure a new server" },
137           { "addrefclock",addrefclock,  { NTP_ADD, OPT|NTP_UINT, OPT|NTP_STR, OPT|NTP_STR },
138             { "addr", "mode", "minpoll|prefer", "minpoll|prefer" },
139             "configure a new server" },
140           { "broadcast",      broadcast,          { NTP_ADD, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
141             { "addr", "keyid", "version", "minpoll" },
142             "configure broadcasting time service" },
143           { "unconfig",       unconfig, { NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD },
144             { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
145             "unconfigure existing peer assocations" },
146           { "enable",         set,                { NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
147             { "auth|bclient|monitor|pll|kernel|stats", "...", "...", "..." },
148             "set a system flag (auth, bclient, monitor, pll, kernel, stats)" },
149           { "disable",        sys_clear,          { NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
150             { "auth|bclient|monitor|pll|kernel|stats", "...", "...", "..." },
151             "clear a system flag (auth, bclient, monitor, pll, kernel, stats)" },
152           { "reslist",        reslist,  {OPT|IP_VERSION, NO, NO, NO },
153             { "-4|-6", "", "", "" },
154             "display the server's restrict list" },
155           { "restrict",       new_restrict,       { NTP_ADD, NTP_ADD, NTP_STR, OPT|NTP_STR },
156             { "address", "mask",
157               "ntpport|ignore|noserve|notrust|noquery|nomodify|nopeer|version|kod",
158               "..." },
159             "create restrict entry/add flags to entry" },
160           { "unrestrict", unrestrict,   { NTP_ADD, NTP_ADD, NTP_STR, OPT|NTP_STR },
161             { "address", "mask",
162               "ntpport|ignore|noserve|notrust|noquery|nomodify|nopeer|version|kod",
163               "..." },
164             "remove flags from a restrict entry" },
165           { "delrestrict", delrestrict, { NTP_ADD, NTP_ADD, OPT|NTP_STR, NO },
166             { "address", "mask", "ntpport", "" },
167             "delete a restrict entry" },
168           { "monlist",        monlist,  { OPT|NTP_INT, NO, NO, NO },
169             { "version", "", "", "" },
170             "display data the server's monitor routines have collected" },
171           { "reset",          reset,              { NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
172             { "io|sys|mem|timer|auth|ctl|allpeers", "...", "...", "..." },
173             "reset various subsystem statistics counters" },
174           { "preset",         preset,             { NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD },
175             { "peer_address", "peer2_addr", "peer3_addr", "peer4_addr" },
176             "reset stat counters associated with particular peer(s)" },
177           { "readkeys",       readkeys, { NO, NO, NO, NO },
178             { "", "", "", "" },
179             "request a reread of the keys file and re-init of system keys" },
180           { "trustedkey",     trustkey, { NTP_UINT, OPT|NTP_UINT, OPT|NTP_UINT, OPT|NTP_UINT },
181             { "keyid", "keyid", "keyid", "keyid" },
182             "add one or more key ID's to the trusted list" },
183           { "untrustedkey", untrustkey, { NTP_UINT, OPT|NTP_UINT, OPT|NTP_UINT, OPT|NTP_UINT },
184             { "keyid", "keyid", "keyid", "keyid" },
185             "remove one or more key ID's from the trusted list" },
186           { "authinfo",       authinfo, { NO, NO, NO, NO },
187             { "", "", "", "" },
188             "display the state of the authentication code" },
189           { "traps",          traps,              { NO, NO, NO, NO },
190             { "", "", "", "" },
191             "display the traps set in the server" },
192           { "addtrap",        addtrap,  { NTP_ADD, OPT|NTP_UINT, OPT|NTP_ADD, NO },
193             { "address", "port", "interface", "" },
194             "configure a trap in the server" },
195           { "clrtrap",        clrtrap,  { NTP_ADD, OPT|NTP_UINT, OPT|NTP_ADD, NO },
196             { "address", "port", "interface", "" },
197             "remove a trap (configured or otherwise) from the server" },
198           { "requestkey",     requestkey,         { NTP_UINT, NO, NO, NO },
199             { "keyid", "", "", "" },
200             "change the keyid the server uses to authenticate requests" },
201           { "controlkey",     controlkey,         { NTP_UINT, NO, NO, NO },
202             { "keyid", "", "", "" },
203             "change the keyid the server uses to authenticate control messages" },
204           { "ctlstats",       ctlstats, { NO, NO, NO, NO },
205             { "", "", "", "" },
206             "display packet count statistics from the control module" },
207           { "clockstat",      clockstat,          { NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD },
208             { "address", "address", "address", "address" },
209             "display clock status information" },
210           { "fudge",          fudge,              { NTP_ADD, NTP_STR, NTP_STR, NO },
211             { "address", "time1|time2|val1|val2|flags", "value", "" },
212             "set/change one of a clock's fudge factors" },
213           { "clkbug",         clkbug,             { NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD, OPT|NTP_ADD },
214             { "address", "address", "address", "address" },
215             "display clock debugging information" },
216           { "kerninfo",       kerninfo, { NO, NO, NO, NO },
217             { "", "", "", "" },
218             "display the kernel pll/pps variables" },
219           { "ifstats",        get_if_stats,       { NO, NO, NO, NO },
220             { "", "", "", "" },
221             "list interface statistics" },
222           { "ifreload",       do_if_reload,       { NO, NO, NO, NO },
223             { "", "", "", "" },
224             "reload interface configuration" },
225           { 0,                0,                  { NO, NO, NO, NO },
226             { "", "", "", "" }, "" }
227 };
228 
229 /*
230  * For quick string comparisons
231  */
232 #define   STREQ(a, b)         (*(a) == *(b) && strcmp((a), (b)) == 0)
233 
234 /*
235  * SET_SS_LEN_IF_PRESENT - used by SET_ADDR, SET_ADDRS macros
236  */
237 
238 #ifdef ISC_PLATFORM_HAVESALEN
239 #define SET_SS_LEN_IF_PRESENT(psau)                                   \
240           do {                                                                  \
241                     (psau)->sa.sa_len = SOCKLEN(psau);                \
242           } while (0)
243 #else
244 #define SET_SS_LEN_IF_PRESENT(psau)     do { } while (0)
245 #endif
246 
247 /*
248  * SET_ADDR - setup address for v4/v6 as needed
249  */
250 #define SET_ADDR(address, v6flag, v4addr, v6addr)           \
251 do {                                                                            \
252           ZERO(address);                                                        \
253           if (v6flag) {                                                         \
254                     AF(&(address)) = AF_INET6;                        \
255                     SOCK_ADDR6(&(address)) = (v6addr);                \
256           } else {                                                    \
257                     AF(&(address)) = AF_INET;                         \
258                     NSRCADR(&(address)) = (v4addr);                             \
259           }                                                                     \
260           SET_SS_LEN_IF_PRESENT(&(address));                          \
261 } while (0)
262 
263 
264 /*
265  * SET_ADDRS - setup source and destination addresses for
266  * v4/v6 as needed
267  */
268 #define SET_ADDRS(a1, a2, info, a1prefix, a2prefix)                   \
269 do {                                                                            \
270           ZERO(a1);                                                   \
271           ZERO(a2);                                                   \
272           if ((info)->v6_flag) {                                                \
273                     AF(&(a1)) = AF_INET6;                                       \
274                     AF(&(a2)) = AF_INET6;                                       \
275                     SOCK_ADDR6(&(a1)) = (info)->a1prefix##6;          \
276                     SOCK_ADDR6(&(a2)) = (info)->a2prefix##6;          \
277           } else {                                                    \
278                     AF(&(a1)) = AF_INET;                                        \
279                     AF(&(a2)) = AF_INET;                                        \
280                     NSRCADR(&(a1)) = (info)->a1prefix;                \
281                     NSRCADR(&(a2)) = (info)->a2prefix;                \
282           }                                                                     \
283           SET_SS_LEN_IF_PRESENT(&(a1));                               \
284           SET_SS_LEN_IF_PRESENT(&(a2));                               \
285 } while (0)
286 
287 
288 /*
289  * checkitems - utility to print a message if no items were returned
290  */
291 static int
checkitems(size_t items,FILE * fp)292 checkitems(
293           size_t items,
294           FILE *fp
295           )
296 {
297           if (items == 0) {
298                     (void) fprintf(fp, "No data returned in response to query\n");
299                     return 0;
300           }
301           return 1;
302 }
303 
304 
305 /*
306  * checkitemsize - utility to print a message if the item size is wrong
307  */
308 static int
checkitemsize(size_t itemsize,size_t expected)309 checkitemsize(
310           size_t itemsize,
311           size_t expected
312           )
313 {
314           if (itemsize != expected) {
315                     (void) fprintf(stderr,
316                                      "***Incorrect item size returned by remote host (%lu should be %lu)\n",
317                                      (u_long)itemsize, (u_long)expected);
318                     return 0;
319           }
320           return 1;
321 }
322 
323 
324 /*
325  * check1item - check to make sure we have exactly one item
326  */
327 static int
check1item(size_t items,FILE * fp)328 check1item(
329           size_t items,
330           FILE *fp
331           )
332 {
333           if (items == 0) {
334                     (void) fprintf(fp, "No data returned in response to query\n");
335                     return 0;
336           }
337           if (items > 1) {
338                     (void) fprintf(fp, "Expected one item in response, got %lu\n",
339                                      (u_long)items);
340                     return 0;
341           }
342           return 1;
343 }
344 
345 
346 /*
347  * peerlist - get a short list of peers
348  */
349 /*ARGSUSED*/
350 static void
peerlist(struct parse * pcmd,FILE * fp)351 peerlist(
352           struct parse *pcmd,
353           FILE *fp
354           )
355 {
356           struct info_peer_list *plist;
357           sockaddr_u paddr;
358           size_t items;
359           size_t itemsize;
360           int res;
361 
362 again:
363           res = doquery(impl_ver, REQ_PEER_LIST, 0, 0, 0, (char *)NULL, &items,
364                           &itemsize, (void *)&plist, 0,
365                           sizeof(struct info_peer_list));
366 
367           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
368                     impl_ver = IMPL_XNTPD_OLD;
369                     goto again;
370           }
371 
372           if (res != 0)
373               return;
374 
375           if (!checkitems(items, fp))
376               return;
377 
378           if (!checkitemsize(itemsize, sizeof(struct info_peer_list)) &&
379               !checkitemsize(itemsize, v4sizeof(struct info_peer_list)))
380               return;
381 
382           while (items > 0) {
383                     SET_ADDR(paddr, plist->v6_flag, plist->addr, plist->addr6);
384                     if ((pcmd->nargs == 0) ||
385                         ((pcmd->argval->ival == 6) && (plist->v6_flag != 0)) ||
386                         ((pcmd->argval->ival == 4) && (plist->v6_flag == 0)))
387                     {
388                               const char *strhost = nntohost(&paddr);
389                               const char *straddr = stoa(&paddr);
390                               (void) fprintf(fp, "%-12s %s",
391                                         modetoa(plist->hmode), strhost);
392                               if (strcmp(strhost,straddr))
393                                         (void) fprintf(fp, " (%s)\n", straddr);
394                               else
395                                         (void) fprintf(fp, "\n");
396                     }
397                     plist++;
398                     items--;
399           }
400 }
401 
402 
403 /*
404  * peers - show peer summary
405  */
406 static void
peers(struct parse * pcmd,FILE * fp)407 peers(
408           struct parse *pcmd,
409           FILE *fp
410           )
411 {
412           dopeers(pcmd, fp, 0);
413 }
414 
415 /*
416  * dmpeers - show peer summary, Dave Mills style
417  */
418 static void
dmpeers(struct parse * pcmd,FILE * fp)419 dmpeers(
420           struct parse *pcmd,
421           FILE *fp
422           )
423 {
424           dopeers(pcmd, fp, 1);
425 }
426 
427 
428 /*
429  * peers - show peer summary
430  */
431 /*ARGSUSED*/
432 static void
dopeers(struct parse * pcmd,FILE * fp,int dmstyle)433 dopeers(
434           struct parse *pcmd,
435           FILE *fp,
436           int dmstyle
437           )
438 {
439           struct info_peer_summary *plist;
440           sockaddr_u dstadr;
441           sockaddr_u srcadr;
442           size_t items;
443           size_t itemsize;
444           int ntp_poll;
445           int res;
446           int c;
447           l_fp tempts;
448 
449 again:
450           res = doquery(impl_ver, REQ_PEER_LIST_SUM, 0, 0, 0, (char *)NULL,
451                           &items, &itemsize, (void *)&plist, 0,
452                           sizeof(struct info_peer_summary));
453 
454           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
455                     impl_ver = IMPL_XNTPD_OLD;
456                     goto again;
457           }
458 
459           if (res != 0)
460               return;
461 
462           if (!checkitems(items, fp))
463               return;
464 
465           if (!checkitemsize(itemsize, sizeof(struct info_peer_summary)) &&
466               !checkitemsize(itemsize, v4sizeof(struct info_peer_summary)))
467                     return;
468 
469           (void) fprintf(fp,
470                            "     remote           local      st poll reach  delay   offset    disp\n");
471           (void) fprintf(fp,
472                            "=======================================================================\n");
473           while (items > 0) {
474                     if (!dmstyle) {
475                               if (plist->flags & INFO_FLAG_SYSPEER)
476                                   c = '*';
477                               else if (plist->hmode == MODE_ACTIVE)
478                                   c = '+';
479                               else if (plist->hmode == MODE_PASSIVE)
480                                   c = '-';
481                               else if (plist->hmode == MODE_CLIENT)
482                                   c = '=';
483                               else if (plist->hmode == MODE_BROADCAST)
484                                   c = '^';
485                               else if (plist->hmode == MODE_BCLIENT)
486                                   c = '~';
487                               else
488                                   c = ' ';
489                     } else {
490                               if (plist->flags & INFO_FLAG_SYSPEER)
491                                   c = '*';
492                               else if (plist->flags & INFO_FLAG_SHORTLIST)
493                                   c = '+';
494                               else if (plist->flags & INFO_FLAG_SEL_CANDIDATE)
495                                   c = '.';
496                               else
497                                   c = ' ';
498                     }
499                     NTOHL_FP(&(plist->offset), &tempts);
500                     ntp_poll = 1<<max(min3(plist->ppoll, plist->hpoll, NTP_MAXPOLL),
501                                           NTP_MINPOLL);
502                     SET_ADDRS(dstadr, srcadr, plist, dstadr, srcadr);
503                     if ((pcmd->nargs == 0) ||
504                         ((pcmd->argval->ival == 6) && (plist->v6_flag != 0)) ||
505                         ((pcmd->argval->ival == 4) && (plist->v6_flag == 0)))
506                               (void) fprintf(fp,
507                                   "%c%-15.15s %-15.15s %2u %4d  %3o %7.7s %9.9s %7.7s\n",
508                                   c, nntohost(&srcadr), stoa(&dstadr),
509                                   plist->stratum, ntp_poll, plist->reach,
510                                   fptoa(NTOHS_FP(plist->delay), 5),
511                                   lfptoa(&tempts, 6),
512                                   ufptoa(NTOHS_FP(plist->dispersion), 5));
513                     plist++;
514                     items--;
515           }
516 }
517 
518 /* Convert a refid & stratum (in host order) to a string */
519 static char *
refid_string(u_int32 refid,int stratum)520 refid_string(
521           u_int32 refid,
522           int stratum
523           )
524 {
525           if (stratum <= 1) {
526                     static char junk[5];
527                     junk[4] = 0;
528                     memcpy(junk, &refid, 4);
529                     return junk;
530           }
531 
532           return numtoa(refid);
533 }
534 
535 static void
print_pflag(FILE * fp,u_int32 flags)536 print_pflag(
537           FILE *    fp,
538           u_int32   flags
539           )
540 {
541           static const char none[] = "";
542           static const char comma[] = ",";
543           const char *dlim;
544 
545           if (0 == flags) {
546                     fprintf(fp, " none\n");
547                     return;
548           }
549           dlim = none;
550           if (flags & INFO_FLAG_SYSPEER) {
551                     fprintf(fp, " system_peer");
552                     dlim = comma;
553           }
554           if (flags & INFO_FLAG_CONFIG) {
555                     fprintf(fp, "%s config", dlim);
556                     dlim = comma;
557           }
558           if (flags & INFO_FLAG_REFCLOCK) {
559                     fprintf(fp, "%s refclock", dlim);
560                     dlim = comma;
561           }
562           if (flags & INFO_FLAG_AUTHENABLE) {
563                     fprintf(fp, "%s auth", dlim);
564                     dlim = comma;
565           }
566           if (flags & INFO_FLAG_PREFER) {
567                     fprintf(fp, "%s prefer", dlim);
568                     dlim = comma;
569           }
570           if (flags & INFO_FLAG_IBURST) {
571                     fprintf(fp, "%s iburst", dlim);
572                     dlim = comma;
573           }
574           if (flags & INFO_FLAG_BURST) {
575                     fprintf(fp, "%s burst", dlim);
576                     dlim = comma;
577           }
578           if (flags & INFO_FLAG_SEL_CANDIDATE) {
579                     fprintf(fp, "%s candidate", dlim);
580                     dlim = comma;
581           }
582           if (flags & INFO_FLAG_SHORTLIST) {
583                     fprintf(fp, "%s shortlist", dlim);
584                     dlim = comma;
585           }
586           fprintf(fp, "\n");
587 }
588 /*
589  * printpeer - print detail information for a peer
590  */
591 static void
printpeer(register struct info_peer * pp,FILE * fp)592 printpeer(
593           register struct info_peer *pp,
594           FILE *fp
595           )
596 {
597           register int i;
598           l_fp tempts;
599           sockaddr_u srcadr, dstadr;
600 
601           SET_ADDRS(dstadr, srcadr, pp, dstadr, srcadr);
602 
603           (void) fprintf(fp, "remote %s, local %s\n",
604                            stoa(&srcadr), stoa(&dstadr));
605           (void) fprintf(fp, "hmode %s, pmode %s, stratum %d, precision %d\n",
606                            modetoa(pp->hmode), modetoa(pp->pmode),
607                            pp->stratum, pp->precision);
608 
609           (void) fprintf(fp,
610                            "leap %c%c, refid [%s], rootdistance %s, rootdispersion %s\n",
611                            pp->leap & 0x2 ? '1' : '0',
612                            pp->leap & 0x1 ? '1' : '0',
613                            refid_string(pp->refid,
614                                             (pp->flags & INFO_FLAG_REFCLOCK ? 0 : pp->stratum)),
615                            fptoa(NTOHS_FP(pp->rootdelay), 5),
616                            ufptoa(NTOHS_FP(pp->rootdispersion), 5));
617 
618           (void) fprintf(fp,
619                            "ppoll %d, hpoll %d, keyid %lu, version %d, association %u\n",
620                            pp->ppoll, pp->hpoll, (u_long)pp->keyid, pp->version, ntohs(pp->associd));
621 
622           (void) fprintf(fp,
623                            "reach %03o, unreach %d, flash 0x%04x, ",
624                            pp->reach, pp->unreach, pp->flash2);
625 
626           (void) fprintf(fp, "boffset %s, ttl/mode %d\n",
627                            fptoa(NTOHS_FP(pp->estbdelay), 5), pp->ttl);
628 
629           (void) fprintf(fp, "timer %lds, flags", (long)ntohl(pp->timer));
630           print_pflag(fp, pp->flags);
631 
632           NTOHL_FP(&pp->reftime, &tempts);
633           (void) fprintf(fp, "reference time:      %s\n",
634                            prettydate(&tempts));
635           NTOHL_FP(&pp->org, &tempts);
636           (void) fprintf(fp, "originate timestamp: %s\n",
637                            prettydate(&tempts));
638           NTOHL_FP(&pp->rec, &tempts);
639           (void) fprintf(fp, "receive timestamp:   %s\n",
640                            prettydate(&tempts));
641           NTOHL_FP(&pp->xmt, &tempts);
642           (void) fprintf(fp, "transmit timestamp:  %s\n",
643                            prettydate(&tempts));
644 
645           (void) fprintf(fp, "filter delay: ");
646           for (i = 0; i < NTP_SHIFT; i++) {
647                     (void) fprintf(fp, " %-8.8s",
648                                      fptoa(NTOHS_FP(pp->filtdelay[i]), 5));
649                     if (i == (NTP_SHIFT>>1)-1)
650                         (void) fprintf(fp, "\n              ");
651           }
652           (void) fprintf(fp, "\n");
653 
654           (void) fprintf(fp, "filter offset:");
655           for (i = 0; i < NTP_SHIFT; i++) {
656                     NTOHL_FP(&pp->filtoffset[i], &tempts);
657                     (void) fprintf(fp, " %-8.8s", lfptoa(&tempts, 6));
658                     if (i == (NTP_SHIFT>>1)-1)
659                         (void) fprintf(fp, "\n              ");
660           }
661           (void) fprintf(fp, "\n");
662 
663           (void) fprintf(fp, "filter order: ");
664           for (i = 0; i < NTP_SHIFT; i++) {
665                     (void) fprintf(fp, " %-8d", pp->order[i]);
666                     if (i == (NTP_SHIFT>>1)-1)
667                         (void) fprintf(fp, "\n              ");
668           }
669           (void) fprintf(fp, "\n");
670 
671 
672           NTOHL_FP(&pp->offset, &tempts);
673           (void) fprintf(fp,
674                            "offset %s, delay %s, error bound %s, filter error %s\n",
675                            lfptoa(&tempts, 6), fptoa(NTOHS_FP(pp->delay), 5),
676                            ufptoa(NTOHS_FP(pp->dispersion), 5),
677                            ufptoa(NTOHS_FP(pp->selectdisp), 5));
678 }
679 
680 
681 /*
682  * showpeer - show detailed information for a peer
683  */
684 static void
showpeer(struct parse * pcmd,FILE * fp)685 showpeer(
686           struct parse *pcmd,
687           FILE *fp
688           )
689 {
690           struct info_peer *pp;
691           /* 4 is the maximum number of peers which will fit in a packet */
692           struct info_peer_list *pl, plist[min(MAXARGS, 4)];
693           size_t qitemlim;
694           size_t qitems;
695           size_t items;
696           size_t itemsize;
697           int res;
698           int sendsize;
699 
700 again:
701           if (impl_ver == IMPL_XNTPD)
702                     sendsize = sizeof(struct info_peer_list);
703           else
704                     sendsize = v4sizeof(struct info_peer_list);
705 
706           qitemlim = min(pcmd->nargs, COUNTOF(plist));
707           for (qitems = 0, pl = plist; qitems < qitemlim; qitems++) {
708                     if (IS_IPV4(&pcmd->argval[qitems].netnum)) {
709                               pl->addr = NSRCADR(&pcmd->argval[qitems].netnum);
710                               if (impl_ver == IMPL_XNTPD)
711                                         pl->v6_flag = 0;
712                     } else {
713                               if (impl_ver == IMPL_XNTPD_OLD) {
714                                         fprintf(stderr,
715                                             "***Server doesn't understand IPv6 addresses\n");
716                                         return;
717                               }
718                               pl->addr6 = SOCK_ADDR6(&pcmd->argval[qitems].netnum);
719                               pl->v6_flag = 1;
720                     }
721                     pl->port = (u_short)s_port;
722                     pl->hmode = pl->flags = 0;
723                     pl = (void *)((char *)pl + sendsize);
724           }
725 
726           res = doquery(impl_ver, REQ_PEER_INFO, 0, qitems,
727                           sendsize, (char *)plist, &items,
728                           &itemsize, (void *)&pp, 0, sizeof(struct info_peer));
729 
730           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
731                     impl_ver = IMPL_XNTPD_OLD;
732                     goto again;
733           }
734 
735           if (res != 0)
736                     return;
737 
738           if (!checkitems(items, fp))
739                     return;
740 
741           if (!checkitemsize(itemsize, sizeof(struct info_peer)) &&
742               !checkitemsize(itemsize, v4sizeof(struct info_peer)))
743                     return;
744 
745           while (items-- > 0) {
746                     printpeer(pp, fp);
747                     if (items > 0)
748                               fprintf(fp, "\n");
749                     pp++;
750           }
751 }
752 
753 
754 /*
755  * peerstats - return statistics for a peer
756  */
757 static void
peerstats(struct parse * pcmd,FILE * fp)758 peerstats(
759           struct parse *pcmd,
760           FILE *fp
761           )
762 {
763           struct info_peer_stats *pp;
764           /* 4 is the maximum number of peers which will fit in a packet */
765           struct info_peer_list *pl, plist[min(MAXARGS, 4)];
766           sockaddr_u src, dst;
767           size_t qitemlim;
768           size_t qitems;
769           size_t items;
770           size_t itemsize;
771           int res;
772           size_t sendsize;
773 
774 again:
775           if (impl_ver == IMPL_XNTPD)
776                     sendsize = sizeof(struct info_peer_list);
777           else
778                     sendsize = v4sizeof(struct info_peer_list);
779 
780           ZERO(plist);
781 
782           qitemlim = min(pcmd->nargs, COUNTOF(plist));
783           for (qitems = 0, pl = plist; qitems < qitemlim; qitems++) {
784                     if (IS_IPV4(&pcmd->argval[qitems].netnum)) {
785                               pl->addr = NSRCADR(&pcmd->argval[qitems].netnum);
786                               if (impl_ver == IMPL_XNTPD)
787                                         pl->v6_flag = 0;
788                     } else {
789                               if (impl_ver == IMPL_XNTPD_OLD) {
790                                         fprintf(stderr,
791                                             "***Server doesn't understand IPv6 addresses\n");
792                                         return;
793                               }
794                               pl->addr6 = SOCK_ADDR6(&pcmd->argval[qitems].netnum);
795                               pl->v6_flag = 1;
796                     }
797                     pl->port = (u_short)s_port;
798                     pl->hmode = plist[qitems].flags = 0;
799                     pl = (void *)((char *)pl + sendsize);
800           }
801 
802           res = doquery(impl_ver, REQ_PEER_STATS, 0, qitems,
803                           sendsize, (char *)plist, &items,
804                           &itemsize, (void *)&pp, 0,
805                           sizeof(struct info_peer_stats));
806 
807           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
808                     impl_ver = IMPL_XNTPD_OLD;
809                     goto again;
810           }
811 
812           if (res != 0)
813                     return;
814 
815           if (!checkitems(items, fp))
816               return;
817 
818           if (!checkitemsize(itemsize, sizeof(struct info_peer_stats)) &&
819               !checkitemsize(itemsize, v4sizeof(struct info_peer_stats)))
820               return;
821 
822           while (items-- > 0) {
823                     ZERO_SOCK(&dst);
824                     ZERO_SOCK(&src);
825                     if (pp->v6_flag != 0) {
826                               AF(&dst) = AF_INET6;
827                               AF(&src) = AF_INET6;
828                               SOCK_ADDR6(&dst) = pp->dstadr6;
829                               SOCK_ADDR6(&src) = pp->srcadr6;
830                     } else {
831                               AF(&dst) = AF_INET;
832                               AF(&src) = AF_INET;
833                               NSRCADR(&dst) = pp->dstadr;
834                               NSRCADR(&src) = pp->srcadr;
835                     }
836 #ifdef ISC_PLATFORM_HAVESALEN
837                     src.sa.sa_len = SOCKLEN(&src);
838                     dst.sa.sa_len = SOCKLEN(&dst);
839 #endif
840                     fprintf(fp, "remote host:          %s\n",
841                               nntohost(&src));
842                     fprintf(fp, "local interface:      %s\n",
843                               stoa(&dst));
844                     fprintf(fp, "time last received:   %lus\n",
845                               (u_long)ntohl(pp->timereceived));
846                     fprintf(fp, "time until next send: %lus\n",
847                               (u_long)ntohl(pp->timetosend));
848                     fprintf(fp, "reachability change:  %lus\n",
849                               (u_long)ntohl(pp->timereachable));
850                     fprintf(fp, "packets sent:         %lu\n",
851                               (u_long)ntohl(pp->sent));
852                     fprintf(fp, "packets received:     %lu\n",
853                               (u_long)ntohl(pp->processed));
854                     fprintf(fp, "bad authentication:   %lu\n",
855                               (u_long)ntohl(pp->badauth));
856                     fprintf(fp, "bogus origin:         %lu\n",
857                               (u_long)ntohl(pp->bogusorg));
858                     fprintf(fp, "duplicate:            %lu\n",
859                               (u_long)ntohl(pp->oldpkt));
860                     fprintf(fp, "bad dispersion:       %lu\n",
861                               (u_long)ntohl(pp->seldisp));
862                     fprintf(fp, "bad reference time:   %lu\n",
863                               (u_long)ntohl(pp->selbroken));
864                     fprintf(fp, "candidate order:      %u\n",
865                               pp->candidate);
866                     if (items > 0)
867                               fprintf(fp, "\n");
868                     fprintf(fp, "flags: ");
869                     print_pflag(fp, ntohs(pp->flags));
870                     pp++;
871           }
872 }
873 
874 
875 /*
876  * loopinfo - show loop filter information
877  */
878 static void
loopinfo(struct parse * pcmd,FILE * fp)879 loopinfo(
880           struct parse *pcmd,
881           FILE *fp
882           )
883 {
884           struct info_loop *il;
885           size_t items;
886           size_t itemsize;
887           int oneline = 0;
888           int res;
889           l_fp tempts;
890 
891           if (pcmd->nargs > 0) {
892                     if (STREQ(pcmd->argval[0].string, "oneline"))
893                         oneline = 1;
894                     else if (STREQ(pcmd->argval[0].string, "multiline"))
895                         oneline = 0;
896                     else {
897                               (void) fprintf(stderr, "How many lines?\n");
898                               return;
899                     }
900           }
901 
902 again:
903           res = doquery(impl_ver, REQ_LOOP_INFO, 0, 0, 0, (char *)NULL,
904                           &items, &itemsize, (void *)&il, 0,
905                           sizeof(struct info_loop));
906 
907           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
908                     impl_ver = IMPL_XNTPD_OLD;
909                     goto again;
910           }
911 
912           if (res != 0)
913               return;
914 
915           if (!check1item(items, fp))
916               return;
917 
918           if (!checkitemsize(itemsize, sizeof(struct info_loop)))
919               return;
920 
921           if (oneline) {
922                     l_fp temp2ts;
923 
924                     NTOHL_FP(&il->last_offset, &tempts);
925                     NTOHL_FP(&il->drift_comp, &temp2ts);
926 
927                     (void) fprintf(fp,
928                                      "offset %s, frequency %s, time_const %ld, watchdog %ld\n",
929                                      lfptoa(&tempts, 6),
930                                      lfptoa(&temp2ts, 3),
931                                      (long)(int32)ntohl((u_long)il->compliance),
932                                      (u_long)ntohl((u_long)il->watchdog_timer));
933           } else {
934                     NTOHL_FP(&il->last_offset, &tempts);
935                     (void) fprintf(fp, "offset:               %s s\n",
936                                      lfptoa(&tempts, 6));
937                     NTOHL_FP(&il->drift_comp, &tempts);
938                     (void) fprintf(fp, "frequency:            %s ppm\n",
939                                      lfptoa(&tempts, 3));
940                     (void) fprintf(fp, "poll adjust:          %ld\n",
941                                      (long)(int32)ntohl(il->compliance));
942                     (void) fprintf(fp, "watchdog timer:       %ld s\n",
943                                      (u_long)ntohl(il->watchdog_timer));
944           }
945 }
946 
947 
948 /*
949  * sysinfo - show current system state
950  */
951 /*ARGSUSED*/
952 static void
sysinfo(struct parse * pcmd,FILE * fp)953 sysinfo(
954           struct parse *pcmd,
955           FILE *fp
956           )
957 {
958           struct info_sys *is;
959           sockaddr_u peeraddr;
960           size_t items;
961           size_t itemsize;
962           int res;
963           l_fp tempts;
964 
965 again:
966           res = doquery(impl_ver, REQ_SYS_INFO, 0, 0, 0, (char *)NULL,
967                           &items, &itemsize, (void *)&is, 0,
968                           sizeof(struct info_sys));
969 
970           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
971                     impl_ver = IMPL_XNTPD_OLD;
972                     goto again;
973           }
974 
975           if (res != 0)
976               return;
977 
978           if (!check1item(items, fp))
979               return;
980 
981           if (!checkitemsize(itemsize, sizeof(struct info_sys)) &&
982               !checkitemsize(itemsize, v4sizeof(struct info_sys)))
983               return;
984 
985           SET_ADDR(peeraddr, is->v6_flag, is->peer, is->peer6);
986 
987           (void) fprintf(fp, "system peer:          %s\n", nntohost(&peeraddr));
988           (void) fprintf(fp, "system peer mode:     %s\n", modetoa(is->peer_mode));
989           (void) fprintf(fp, "leap indicator:       %c%c\n",
990                            is->leap & 0x2 ? '1' : '0',
991                            is->leap & 0x1 ? '1' : '0');
992           (void) fprintf(fp, "stratum:              %d\n", (int)is->stratum);
993           (void) fprintf(fp, "precision:            %d\n", (int)is->precision);
994           (void) fprintf(fp, "root distance:        %s s\n",
995                            fptoa(NTOHS_FP(is->rootdelay), 5));
996           (void) fprintf(fp, "root dispersion:      %s s\n",
997                            ufptoa(NTOHS_FP(is->rootdispersion), 5));
998           (void) fprintf(fp, "reference ID:         [%s]\n",
999                            refid_string(is->refid, is->stratum));
1000           NTOHL_FP(&is->reftime, &tempts);
1001           (void) fprintf(fp, "reference time:       %s\n", prettydate(&tempts));
1002 
1003           (void) fprintf(fp, "system flags:         ");
1004           if ((is->flags & (INFO_FLAG_BCLIENT | INFO_FLAG_AUTHENABLE |
1005               INFO_FLAG_NTP | INFO_FLAG_KERNEL| INFO_FLAG_CAL |
1006               INFO_FLAG_PPS_SYNC | INFO_FLAG_MONITOR | INFO_FLAG_FILEGEN)) == 0) {
1007                     (void) fprintf(fp, "none\n");
1008           } else {
1009                     if (is->flags & INFO_FLAG_BCLIENT)
1010                         (void) fprintf(fp, "bclient ");
1011                     if (is->flags & INFO_FLAG_AUTHENTICATE)
1012                         (void) fprintf(fp, "auth ");
1013                     if (is->flags & INFO_FLAG_MONITOR)
1014                         (void) fprintf(fp, "monitor ");
1015                     if (is->flags & INFO_FLAG_NTP)
1016                         (void) fprintf(fp, "ntp ");
1017                     if (is->flags & INFO_FLAG_KERNEL)
1018                         (void) fprintf(fp, "kernel ");
1019                     if (is->flags & INFO_FLAG_FILEGEN)
1020                         (void) fprintf(fp, "stats ");
1021                     if (is->flags & INFO_FLAG_CAL)
1022                         (void) fprintf(fp, "calibrate ");
1023                     if (is->flags & INFO_FLAG_PPS_SYNC)
1024                         (void) fprintf(fp, "pps ");
1025                     (void) fprintf(fp, "\n");
1026           }
1027           (void) fprintf(fp, "jitter:               %s s\n",
1028                            fptoa(ntohl(is->frequency), 6));
1029           (void) fprintf(fp, "stability:            %s ppm\n",
1030                            ufptoa(ntohl(is->stability), 3));
1031           (void) fprintf(fp, "broadcastdelay:       %s s\n",
1032                            fptoa(NTOHS_FP(is->bdelay), 6));
1033           NTOHL_FP(&is->authdelay, &tempts);
1034           (void) fprintf(fp, "authdelay:            %s s\n", lfptoa(&tempts, 6));
1035 }
1036 
1037 
1038 /*
1039  * sysstats - print system statistics
1040  */
1041 /*ARGSUSED*/
1042 static void
sysstats(struct parse * pcmd,FILE * fp)1043 sysstats(
1044           struct parse *pcmd,
1045           FILE *fp
1046           )
1047 {
1048           struct info_sys_stats *ss;
1049           size_t items;
1050           size_t itemsize;
1051           int res;
1052 
1053 again:
1054           res = doquery(impl_ver, REQ_SYS_STATS, 0, 0, 0, (char *)NULL,
1055                           &items, &itemsize, (void *)&ss, 0,
1056                           sizeof(struct info_sys_stats));
1057 
1058           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1059                     impl_ver = IMPL_XNTPD_OLD;
1060                     goto again;
1061           }
1062 
1063           if (res != 0)
1064               return;
1065 
1066           if (!check1item(items, fp))
1067               return;
1068 
1069           if (itemsize != sizeof(struct info_sys_stats) &&
1070               itemsize != sizeof(struct old_info_sys_stats)) {
1071                     /* issue warning according to new structure size */
1072                     checkitemsize(itemsize, sizeof(struct info_sys_stats));
1073                     return;
1074           }
1075           fprintf(fp, "time since restart:     %lu\n",
1076                     (u_long)ntohl(ss->timeup));
1077           fprintf(fp, "time since reset:       %lu\n",
1078                     (u_long)ntohl(ss->timereset));
1079           fprintf(fp, "packets received:       %lu\n",
1080                     (u_long)ntohl(ss->received));
1081           fprintf(fp, "packets processed:      %lu\n",
1082                     (u_long)ntohl(ss->processed));
1083           fprintf(fp, "current version:        %lu\n",
1084                     (u_long)ntohl(ss->newversionpkt));
1085           fprintf(fp, "previous version:       %lu\n",
1086                     (u_long)ntohl(ss->oldversionpkt));
1087           fprintf(fp, "declined:               %lu\n",
1088                     (u_long)ntohl(ss->unknownversion));
1089           fprintf(fp, "access denied:          %lu\n",
1090                     (u_long)ntohl(ss->denied));
1091           fprintf(fp, "bad length or format:   %lu\n",
1092                     (u_long)ntohl(ss->badlength));
1093           fprintf(fp, "bad authentication:     %lu\n",
1094                     (u_long)ntohl(ss->badauth));
1095           if (itemsize != sizeof(struct info_sys_stats))
1096               return;
1097 
1098           fprintf(fp, "rate exceeded:          %lu\n",
1099                  (u_long)ntohl(ss->limitrejected));
1100 }
1101 
1102 
1103 
1104 /*
1105  * iostats - print I/O statistics
1106  */
1107 /*ARGSUSED*/
1108 static void
iostats(struct parse * pcmd,FILE * fp)1109 iostats(
1110           struct parse *pcmd,
1111           FILE *fp
1112           )
1113 {
1114           struct info_io_stats *io;
1115           size_t items;
1116           size_t itemsize;
1117           int res;
1118 
1119 again:
1120           res = doquery(impl_ver, REQ_IO_STATS, 0, 0, 0, NULL, &items,
1121                           &itemsize, (void *)&io, 0, sizeof(*io));
1122 
1123           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1124                     impl_ver = IMPL_XNTPD_OLD;
1125                     goto again;
1126           }
1127 
1128           if (res != 0)
1129                     return;
1130 
1131           if (!check1item(items, fp))
1132                     return;
1133 
1134           if (!checkitemsize(itemsize, sizeof(*io)))
1135                     return;
1136 
1137           fprintf(fp, "time since reset:     %lu\n",
1138                     (u_long)ntohl(io->timereset));
1139           fprintf(fp, "receive buffers:      %u\n",
1140                     (u_int)ntohs(io->totalrecvbufs));
1141           fprintf(fp, "free receive buffers: %u\n",
1142                     (u_int)ntohs(io->freerecvbufs));
1143           fprintf(fp, "used receive buffers: %u\n",
1144                     (u_int)ntohs(io->fullrecvbufs));
1145           fprintf(fp, "low water refills:    %u\n",
1146                     (u_int)ntohs(io->lowwater));
1147           fprintf(fp, "dropped packets:      %lu\n",
1148                     (u_long)ntohl(io->dropped));
1149           fprintf(fp, "ignored packets:      %lu\n",
1150                     (u_long)ntohl(io->ignored));
1151           fprintf(fp, "received packets:     %lu\n",
1152                     (u_long)ntohl(io->received));
1153           fprintf(fp, "packets sent:         %lu\n",
1154                     (u_long)ntohl(io->sent));
1155           fprintf(fp, "packets not sent:     %lu\n",
1156                     (u_long)ntohl(io->notsent));
1157           fprintf(fp, "interrupts handled:   %lu\n",
1158                     (u_long)ntohl(io->interrupts));
1159           fprintf(fp, "received by int:      %lu\n",
1160                     (u_long)ntohl(io->int_received));
1161 }
1162 
1163 
1164 /*
1165  * memstats - print peer memory statistics
1166  */
1167 /*ARGSUSED*/
1168 static void
memstats(struct parse * pcmd,FILE * fp)1169 memstats(
1170           struct parse *pcmd,
1171           FILE *fp
1172           )
1173 {
1174           struct info_mem_stats *mem;
1175           int i;
1176           size_t items;
1177           size_t itemsize;
1178           int res;
1179 
1180 again:
1181           res = doquery(impl_ver, REQ_MEM_STATS, 0, 0, 0, NULL, &items,
1182                           &itemsize, (void *)&mem, 0, sizeof(*mem));
1183 
1184           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1185                     impl_ver = IMPL_XNTPD_OLD;
1186                     goto again;
1187           }
1188 
1189           if (res != 0)
1190                     return;
1191 
1192           if (!check1item(items, fp))
1193                     return;
1194 
1195           if (!checkitemsize(itemsize, sizeof(*mem)))
1196                     return;
1197 
1198           fprintf(fp, "time since reset:     %lu\n",
1199                     (u_long)ntohl(mem->timereset));
1200           fprintf(fp, "total peer memory:    %u\n",
1201                     (u_int)ntohs(mem->totalpeermem));
1202           fprintf(fp, "free peer memory:     %u\n",
1203                     (u_int)ntohs(mem->freepeermem));
1204           fprintf(fp, "calls to findpeer:    %lu\n",
1205                     (u_long)ntohl(mem->findpeer_calls));
1206           fprintf(fp, "new peer allocations: %lu\n",
1207                     (u_long)ntohl(mem->allocations));
1208           fprintf(fp, "peer demobilizations: %lu\n",
1209                     (u_long)ntohl(mem->demobilizations));
1210 
1211           fprintf(fp, "hash table counts:   ");
1212           for (i = 0; i < NTP_HASH_SIZE; i++) {
1213                     fprintf(fp, "%4d", (int)mem->hashcount[i]);
1214                     if ((i % 8) == 7 && i != (NTP_HASH_SIZE-1))
1215                               fprintf(fp, "\n                     ");
1216           }
1217           fprintf(fp, "\n");
1218 }
1219 
1220 
1221 
1222 /*
1223  * timerstats - print timer statistics
1224  */
1225 /*ARGSUSED*/
1226 static void
timerstats(struct parse * pcmd,FILE * fp)1227 timerstats(
1228           struct parse *pcmd,
1229           FILE *fp
1230           )
1231 {
1232           struct info_timer_stats *tim;
1233           size_t items;
1234           size_t itemsize;
1235           int res;
1236 
1237 again:
1238           res = doquery(impl_ver, REQ_TIMER_STATS, 0, 0, 0, NULL, &items,
1239                           &itemsize, (void *)&tim, 0, sizeof(*tim));
1240 
1241           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1242                     impl_ver = IMPL_XNTPD_OLD;
1243                     goto again;
1244           }
1245 
1246           if (res != 0)
1247                     return;
1248 
1249           if (!check1item(items, fp))
1250                     return;
1251 
1252           if (!checkitemsize(itemsize, sizeof(*tim)))
1253                     return;
1254 
1255           fprintf(fp, "time since reset:  %lu\n",
1256                     (u_long)ntohl(tim->timereset));
1257           fprintf(fp, "alarms handled:    %lu\n",
1258                     (u_long)ntohl(tim->alarms));
1259           fprintf(fp, "alarm overruns:    %lu\n",
1260                     (u_long)ntohl(tim->overflows));
1261           fprintf(fp, "calls to transmit: %lu\n",
1262                     (u_long)ntohl(tim->xmtcalls));
1263 }
1264 
1265 
1266 /*
1267  * addpeer - configure an active mode association
1268  */
1269 static void
addpeer(struct parse * pcmd,FILE * fp)1270 addpeer(
1271           struct parse *pcmd,
1272           FILE *fp
1273           )
1274 {
1275           doconfig(pcmd, fp, MODE_ACTIVE, 0);
1276 }
1277 
1278 
1279 /*
1280  * addserver - configure a client mode association
1281  */
1282 static void
addserver(struct parse * pcmd,FILE * fp)1283 addserver(
1284           struct parse *pcmd,
1285           FILE *fp
1286           )
1287 {
1288           doconfig(pcmd, fp, MODE_CLIENT, 0);
1289 }
1290 
1291 /*
1292  * addrefclock - configure a reference clock association
1293  */
1294 static void
addrefclock(struct parse * pcmd,FILE * fp)1295 addrefclock(
1296           struct parse *pcmd,
1297           FILE *fp
1298           )
1299 {
1300           doconfig(pcmd, fp, MODE_CLIENT, 1);
1301 }
1302 
1303 /*
1304  * broadcast - configure a broadcast mode association
1305  */
1306 static void
broadcast(struct parse * pcmd,FILE * fp)1307 broadcast(
1308           struct parse *pcmd,
1309           FILE *fp
1310           )
1311 {
1312           doconfig(pcmd, fp, MODE_BROADCAST, 0);
1313 }
1314 
1315 
1316 /*
1317  * config - configure a new peer association
1318  */
1319 static void
doconfig(struct parse * pcmd,FILE * fp,int mode,int refc)1320 doconfig(
1321           struct parse *pcmd,
1322           FILE *fp,
1323           int mode,
1324           int refc
1325           )
1326 {
1327           struct conf_peer cpeer;
1328           size_t items;
1329           size_t itemsize;
1330           const char *dummy;
1331           u_long keyid;
1332           u_int version;
1333           u_char minpoll;
1334           u_char maxpoll;
1335           u_int flags;
1336           u_char cmode;
1337           int res;
1338           int sendsize;
1339           int numtyp;
1340           long val;
1341 
1342 again:
1343           keyid = 0;
1344           version = 3;
1345           flags = 0;
1346           res = FALSE;
1347           cmode = 0;
1348           minpoll = NTP_MINDPOLL;
1349           maxpoll = NTP_MAXDPOLL;
1350           numtyp = 1;
1351           if (refc)
1352                     numtyp = 5;
1353 
1354           if (impl_ver == IMPL_XNTPD)
1355                     sendsize = sizeof(struct conf_peer);
1356           else
1357                     sendsize = v4sizeof(struct conf_peer);
1358 
1359           items = 1;
1360           while (pcmd->nargs > (size_t)items) {
1361                     if (STREQ(pcmd->argval[items].string, "prefer"))
1362                               flags |= CONF_FLAG_PREFER;
1363                     else if (STREQ(pcmd->argval[items].string, "burst"))
1364                               flags |= CONF_FLAG_BURST;
1365                     else if (STREQ(pcmd->argval[items].string, "iburst"))
1366                               flags |= CONF_FLAG_IBURST;
1367                     else if (!refc && STREQ(pcmd->argval[items].string, "keyid"))
1368                               numtyp = 1;
1369                     else if (!refc && STREQ(pcmd->argval[items].string, "version"))
1370                               numtyp = 2;
1371                     else if (STREQ(pcmd->argval[items].string, "minpoll"))
1372                               numtyp = 3;
1373                     else if (STREQ(pcmd->argval[items].string, "maxpoll"))
1374                               numtyp = 4;
1375                     else {
1376                               if (!atoint(pcmd->argval[items].string, &val))
1377                                         numtyp = 0;
1378                               switch (numtyp) {
1379                               case 1:
1380                                         keyid = val;
1381                                         numtyp = 2;
1382                                         break;
1383 
1384                               case 2:
1385                                         version = (u_int)val;
1386                                         numtyp = 0;
1387                                         break;
1388 
1389                               case 3:
1390                                         minpoll = (u_char)val;
1391                                         numtyp = 0;
1392                                         break;
1393 
1394                               case 4:
1395                                         maxpoll = (u_char)val;
1396                                         numtyp = 0;
1397                                         break;
1398 
1399                               case 5:
1400                                         cmode = (u_char)val;
1401                                         numtyp = 0;
1402                                         break;
1403 
1404                               default:
1405                                         fprintf(fp, "*** '%s' not understood\n",
1406                                                   pcmd->argval[items].string);
1407                                         res = TRUE;
1408                                         numtyp = 0;
1409                               }
1410                               if (val < 0) {
1411                                         fprintf(stderr,
1412                                                   "*** Value '%s' should be unsigned\n",
1413                                                   pcmd->argval[items].string);
1414                                         res = TRUE;
1415                               }
1416                     }
1417                     items++;
1418           }
1419           if (keyid > 0)
1420                     flags |= CONF_FLAG_AUTHENABLE;
1421           if (version > NTP_VERSION || version < NTP_OLDVERSION) {
1422                     fprintf(fp, "***invalid version number: %u\n",
1423                               version);
1424                     res = TRUE;
1425           }
1426           if (minpoll < NTP_MINPOLL || minpoll > NTP_MAXPOLL ||
1427               maxpoll < NTP_MINPOLL || maxpoll > NTP_MAXPOLL ||
1428               minpoll > maxpoll) {
1429                     fprintf(fp, "***min/max-poll must be within %d..%d\n",
1430                               NTP_MINPOLL, NTP_MAXPOLL);
1431                     res = TRUE;
1432           }
1433 
1434           if (res)
1435                     return;
1436 
1437           ZERO(cpeer);
1438 
1439           if (IS_IPV4(&pcmd->argval[0].netnum)) {
1440                     cpeer.peeraddr = NSRCADR(&pcmd->argval[0].netnum);
1441                     if (impl_ver == IMPL_XNTPD)
1442                               cpeer.v6_flag = 0;
1443           } else {
1444                     if (impl_ver == IMPL_XNTPD_OLD) {
1445                               fprintf(stderr,
1446                                   "***Server doesn't understand IPv6 addresses\n");
1447                               return;
1448                     }
1449                     cpeer.peeraddr6 = SOCK_ADDR6(&pcmd->argval[0].netnum);
1450                     cpeer.v6_flag = 1;
1451           }
1452           cpeer.hmode = (u_char) mode;
1453           cpeer.keyid = keyid;
1454           cpeer.version = (u_char) version;
1455           cpeer.minpoll = minpoll;
1456           cpeer.maxpoll = maxpoll;
1457           cpeer.flags = (u_char)flags;
1458           cpeer.ttl = cmode;
1459 
1460           res = doquery(impl_ver, REQ_CONFIG, 1, 1,
1461                           sendsize, (char *)&cpeer, &items,
1462                           &itemsize, &dummy, 0, sizeof(struct conf_peer));
1463 
1464           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1465                     impl_ver = IMPL_XNTPD_OLD;
1466                     goto again;
1467           }
1468 
1469           if (res == INFO_ERR_FMT) {
1470                     (void) fprintf(fp,
1471                         "***Retrying command with old conf_peer size\n");
1472                     res = doquery(impl_ver, REQ_CONFIG, 1, 1,
1473                                     sizeof(struct old_conf_peer), (char *)&cpeer,
1474                                     &items, &itemsize, &dummy, 0,
1475                                     sizeof(struct conf_peer));
1476           }
1477           if (res == 0)
1478               (void) fprintf(fp, "done!\n");
1479           return;
1480 }
1481 
1482 
1483 /*
1484  * unconfig - unconfigure some associations
1485  */
1486 static void
unconfig(struct parse * pcmd,FILE * fp)1487 unconfig(
1488           struct parse *pcmd,
1489           FILE *fp
1490           )
1491 {
1492           /* 8 is the maximum number of peers which will fit in a packet */
1493           struct conf_unpeer *pl, plist[min(MAXARGS, 8)];
1494           size_t qitemlim;
1495           size_t qitems;
1496           size_t items;
1497           size_t itemsize;
1498           const char *dummy;
1499           int res;
1500           size_t sendsize;
1501 
1502 again:
1503           if (impl_ver == IMPL_XNTPD)
1504                     sendsize = sizeof(struct conf_unpeer);
1505           else
1506                     sendsize = v4sizeof(struct conf_unpeer);
1507 
1508           qitemlim = min(pcmd->nargs, COUNTOF(plist));
1509           for (qitems = 0, pl = plist; qitems < qitemlim; qitems++) {
1510                     if (IS_IPV4(&pcmd->argval[0].netnum)) {
1511                               pl->peeraddr = NSRCADR(&pcmd->argval[qitems].netnum);
1512                               if (impl_ver == IMPL_XNTPD)
1513                                         pl->v6_flag = 0;
1514                     } else {
1515                               if (impl_ver == IMPL_XNTPD_OLD) {
1516                                         fprintf(stderr,
1517                                             "***Server doesn't understand IPv6 addresses\n");
1518                                         return;
1519                               }
1520                               pl->peeraddr6 =
1521                                   SOCK_ADDR6(&pcmd->argval[qitems].netnum);
1522                               pl->v6_flag = 1;
1523                     }
1524                     pl = (void *)((char *)pl + sendsize);
1525           }
1526 
1527           res = doquery(impl_ver, REQ_UNCONFIG, 1, qitems,
1528                           sendsize, (char *)plist, &items,
1529                           &itemsize, &dummy, 0, sizeof(struct conf_unpeer));
1530 
1531           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1532                     impl_ver = IMPL_XNTPD_OLD;
1533                     goto again;
1534           }
1535 
1536           if (res == 0)
1537               (void) fprintf(fp, "done!\n");
1538 }
1539 
1540 
1541 /*
1542  * set - set some system flags
1543  */
1544 static void
set(struct parse * pcmd,FILE * fp)1545 set(
1546           struct parse *pcmd,
1547           FILE *fp
1548           )
1549 {
1550           doset(pcmd, fp, REQ_SET_SYS_FLAG);
1551 }
1552 
1553 
1554 /*
1555  * clear - clear some system flags
1556  */
1557 static void
sys_clear(struct parse * pcmd,FILE * fp)1558 sys_clear(
1559           struct parse *pcmd,
1560           FILE *fp
1561           )
1562 {
1563           doset(pcmd, fp, REQ_CLR_SYS_FLAG);
1564 }
1565 
1566 
1567 /*
1568  * doset - set/clear system flags
1569  */
1570 static void
doset(struct parse * pcmd,FILE * fp,int req)1571 doset(
1572           struct parse *pcmd,
1573           FILE *fp,
1574           int req
1575           )
1576 {
1577           struct conf_sys_flags sys;
1578           size_t items;
1579           size_t itemsize;
1580           const char *dummy;
1581           int res;
1582 
1583           sys.flags = 0;
1584           res = 0;
1585           for (items = 0; (size_t)items < pcmd->nargs; items++) {
1586                     if (STREQ(pcmd->argval[items].string, "auth"))
1587                               sys.flags |= SYS_FLAG_AUTH;
1588                     else if (STREQ(pcmd->argval[items].string, "bclient"))
1589                               sys.flags |= SYS_FLAG_BCLIENT;
1590                     else if (STREQ(pcmd->argval[items].string, "calibrate"))
1591                               sys.flags |= SYS_FLAG_CAL;
1592                     else if (STREQ(pcmd->argval[items].string, "kernel"))
1593                               sys.flags |= SYS_FLAG_KERNEL;
1594                     else if (STREQ(pcmd->argval[items].string, "monitor"))
1595                               sys.flags |= SYS_FLAG_MONITOR;
1596                     else if (STREQ(pcmd->argval[items].string, "ntp"))
1597                               sys.flags |= SYS_FLAG_NTP;
1598                     else if (STREQ(pcmd->argval[items].string, "pps"))
1599                               sys.flags |= SYS_FLAG_PPS;
1600                     else if (STREQ(pcmd->argval[items].string, "stats"))
1601                               sys.flags |= SYS_FLAG_FILEGEN;
1602                     else {
1603                               (void) fprintf(fp, "Unknown flag %s\n",
1604                                   pcmd->argval[items].string);
1605                               res = 1;
1606                     }
1607           }
1608 
1609           sys.flags = htonl(sys.flags);
1610           if (res || sys.flags == 0)
1611               return;
1612 
1613 again:
1614           res = doquery(impl_ver, req, 1, 1,
1615                           sizeof(struct conf_sys_flags), (char *)&sys, &items,
1616                           &itemsize, &dummy, 0, sizeof(struct conf_sys_flags));
1617 
1618           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1619                     impl_ver = IMPL_XNTPD_OLD;
1620                     goto again;
1621           }
1622 
1623           if (res == 0)
1624               (void) fprintf(fp, "done!\n");
1625 }
1626 
1627 
1628 /*
1629  * data for printing/interrpreting the restrict flags
1630  */
1631 struct resflags {
1632   const char *str;
1633           int bit;
1634 };
1635 
1636 /* XXX: HMS: we apparently don't report set bits we do not recognize. */
1637 
1638 static struct resflags resflagsV2[] = {
1639           { "ignore",         0x001 },
1640           { "noserve",        0x002 },
1641           { "notrust",        0x004 },
1642           { "noquery",        0x008 },
1643           { "nomodify",       0x010 },
1644           { "nopeer",         0x020 },
1645           { "notrap",         0x040 },
1646           { "lptrap",         0x080 },
1647           { "limited",        0x100 },
1648           { "",               0 }
1649 };
1650 
1651 static struct resflags resflagsV3[] = {
1652           { "ignore",         RES_IGNORE },
1653           { "noserve",        RES_DONTSERVE },
1654           { "notrust",        RES_DONTTRUST },
1655           { "noquery",        RES_NOQUERY },
1656           { "nomodify",       RES_NOMODIFY },
1657           { "nopeer",         RES_NOPEER },
1658           { "notrap",         RES_NOTRAP },
1659           { "lptrap",         RES_LPTRAP },
1660           { "limited",        RES_LIMITED },
1661           { "version",        RES_VERSION },
1662           { "kod",  RES_KOD },
1663           { "flake",          RES_FLAKE },
1664 
1665           { "",               0 }
1666 };
1667 
1668 static struct resflags resmflags[] = {
1669           { "ntpport",        RESM_NTPONLY },
1670           { "interface",      RESM_INTERFACE },
1671           { "source",         RESM_SOURCE },
1672           { "",               0 }
1673 };
1674 
1675 
1676 /*
1677  * reslist - obtain and print the server's restrict list
1678  */
1679 /*ARGSUSED*/
1680 static void
reslist(struct parse * pcmd,FILE * fp)1681 reslist(
1682           struct parse *pcmd,
1683           FILE *fp
1684           )
1685 {
1686           struct info_restrict *rl;
1687           sockaddr_u resaddr;
1688           sockaddr_u maskaddr;
1689           size_t items;
1690           size_t itemsize;
1691           int res;
1692           int skip;
1693           const char *addr;
1694           const char *mask;
1695           struct resflags *rf;
1696           u_int32 count;
1697           u_short rflags;
1698           u_short mflags;
1699           char flagstr[300];
1700           static const char *comma = ", ";
1701 
1702 again:
1703           res = doquery(impl_ver, REQ_GET_RESTRICT, 0, 0, 0, (char *)NULL,
1704                           &items, &itemsize, (void *)&rl, 0,
1705                           sizeof(struct info_restrict));
1706 
1707           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1708                     impl_ver = IMPL_XNTPD_OLD;
1709                     goto again;
1710           }
1711 
1712           if (res != 0)
1713                     return;
1714 
1715           if (!checkitems(items, fp))
1716                     return;
1717 
1718           if (!checkitemsize(itemsize, sizeof(struct info_restrict)) &&
1719               !checkitemsize(itemsize, v4sizeof(struct info_restrict)))
1720                     return;
1721 
1722           fprintf(fp,
1723                     "   address          mask            count        flags\n");
1724           fprintf(fp,
1725                     "=====================================================================\n");
1726 
1727           while (items > 0) {
1728                     SET_ADDRS(resaddr, maskaddr, rl, addr, mask);
1729                     if (rl->v6_flag != 0) {
1730                               addr = nntohost(&resaddr);
1731                     } else {
1732                               if (rl->mask == (u_int32)0xffffffff)
1733                                         addr = nntohost(&resaddr);
1734                               else
1735                                         addr = stoa(&resaddr);
1736                     }
1737                     mask = stoa(&maskaddr);
1738                     skip = 1;
1739                     if ((pcmd->nargs == 0) ||
1740                         ((pcmd->argval->ival == 6) && (rl->v6_flag != 0)) ||
1741                         ((pcmd->argval->ival == 4) && (rl->v6_flag == 0)))
1742                               skip = 0;
1743                     count = ntohl(rl->count);
1744                     rflags = ntohs(rl->rflags);
1745                     mflags = ntohs(rl->mflags);
1746                     flagstr[0] = '\0';
1747 
1748                     res = 1;
1749                     rf = &resmflags[0];
1750                     while (rf->bit != 0) {
1751                               if (mflags & rf->bit) {
1752                                         if (!res)
1753                                                   strlcat(flagstr, comma,
1754                                                             sizeof(flagstr));
1755                                         res = 0;
1756                                         strlcat(flagstr, rf->str,
1757                                                   sizeof(flagstr));
1758                               }
1759                               rf++;
1760                     }
1761 
1762                     rf = (impl_ver == IMPL_XNTPD_OLD)
1763                                ? &resflagsV2[0]
1764                                : &resflagsV3[0];
1765 
1766                     while (rf->bit != 0) {
1767                               if (rflags & rf->bit) {
1768                                         if (!res)
1769                                                   strlcat(flagstr, comma,
1770                                                             sizeof(flagstr));
1771                                         res = 0;
1772                                         strlcat(flagstr, rf->str,
1773                                                   sizeof(flagstr));
1774                               }
1775                               rf++;
1776                     }
1777 
1778                     if (flagstr[0] == '\0')
1779                               strlcpy(flagstr, "none", sizeof(flagstr));
1780 
1781                     if (!skip)
1782                               fprintf(fp, "%-15.15s %-15.15s %9lu  %s\n",
1783                                         addr, mask, (u_long)count, flagstr);
1784                     rl++;
1785                     items--;
1786           }
1787 }
1788 
1789 
1790 
1791 /*
1792  * new_restrict - create/add a set of restrictions
1793  */
1794 static void
new_restrict(struct parse * pcmd,FILE * fp)1795 new_restrict(
1796           struct parse *pcmd,
1797           FILE *fp
1798           )
1799 {
1800           do_restrict(pcmd, fp, REQ_RESADDFLAGS);
1801 }
1802 
1803 
1804 /*
1805  * unrestrict - remove restriction flags from existing entry
1806  */
1807 static void
unrestrict(struct parse * pcmd,FILE * fp)1808 unrestrict(
1809           struct parse *pcmd,
1810           FILE *fp
1811           )
1812 {
1813           do_restrict(pcmd, fp, REQ_RESSUBFLAGS);
1814 }
1815 
1816 
1817 /*
1818  * delrestrict - delete an existing restriction
1819  */
1820 static void
delrestrict(struct parse * pcmd,FILE * fp)1821 delrestrict(
1822           struct parse *pcmd,
1823           FILE *fp
1824           )
1825 {
1826           do_restrict(pcmd, fp, REQ_UNRESTRICT);
1827 }
1828 
1829 
1830 /*
1831  * do_restrict - decode commandline restrictions and make the request
1832  */
1833 static void
do_restrict(struct parse * pcmd,FILE * fp,int req_code)1834 do_restrict(
1835           struct parse *pcmd,
1836           FILE *fp,
1837           int req_code
1838           )
1839 {
1840           struct conf_restrict cres;
1841           size_t items;
1842           size_t itemsize;
1843           const char *dummy;
1844           u_int32 num;
1845           u_long bit;
1846           int i;
1847           size_t res;
1848           int err;
1849           int sendsize;
1850 
1851           /* Initialize cres */
1852           cres.addr = 0;
1853           cres.mask = 0;
1854           cres.flags = 0;
1855           cres.mflags = 0;
1856           cres.v6_flag = 0;
1857 
1858 again:
1859           if (impl_ver == IMPL_XNTPD)
1860                     sendsize = sizeof(struct conf_restrict);
1861           else
1862                     sendsize = v4sizeof(struct conf_restrict);
1863 
1864           if (IS_IPV4(&pcmd->argval[0].netnum)) {
1865                     cres.addr = NSRCADR(&pcmd->argval[0].netnum);
1866                     cres.mask = NSRCADR(&pcmd->argval[1].netnum);
1867                     if (impl_ver == IMPL_XNTPD)
1868                               cres.v6_flag = 0;
1869           } else {
1870                     if (impl_ver == IMPL_XNTPD_OLD) {
1871                               fprintf(stderr,
1872                                         "***Server doesn't understand IPv6 addresses\n");
1873                               return;
1874                     }
1875                     cres.addr6 = SOCK_ADDR6(&pcmd->argval[0].netnum);
1876                     cres.v6_flag = 1;
1877           }
1878           cres.flags = 0;
1879           cres.mflags = 0;
1880           err = FALSE;
1881           for (res = 2; res < pcmd->nargs; res++) {
1882                     if (STREQ(pcmd->argval[res].string, "ntpport")) {
1883                               cres.mflags |= RESM_NTPONLY;
1884                     } else {
1885                               for (i = 0; resflagsV3[i].bit != 0; i++) {
1886                                         if (STREQ(pcmd->argval[res].string,
1887                                                     resflagsV3[i].str))
1888                                                   break;
1889                               }
1890                               if (resflagsV3[i].bit != 0) {
1891                                         cres.flags |= resflagsV3[i].bit;
1892                                         if (req_code == REQ_UNRESTRICT) {
1893                                                   fprintf(fp,
1894                                                             "Flag %s inappropriate\n",
1895                                                             resflagsV3[i].str);
1896                                                   err = TRUE;
1897                                         }
1898                               } else {
1899                                         fprintf(fp, "Unknown flag %s\n",
1900                                                   pcmd->argval[res].string);
1901                                         err = TRUE;
1902                               }
1903                     }
1904           }
1905           cres.flags = htons(cres.flags);
1906           cres.mflags = htons(cres.mflags);
1907 
1908           /*
1909            * Make sure mask for default address is zero.  Otherwise,
1910            * make sure mask bits are contiguous.
1911            */
1912           if (IS_IPV4(&pcmd->argval[0].netnum)) {
1913                     if (cres.addr == 0) {
1914                               cres.mask = 0;
1915                     } else {
1916                               num = ntohl(cres.mask);
1917                               for (bit = 0x80000000; bit != 0; bit >>= 1)
1918                                         if ((num & bit) == 0)
1919                                                   break;
1920                               for ( ; bit != 0; bit >>= 1)
1921                                         if ((num & bit) != 0)
1922                                                   break;
1923                               if (bit != 0) {
1924                                         fprintf(fp, "Invalid mask %s\n",
1925                                                   numtoa(cres.mask));
1926                                         err = TRUE;
1927                               }
1928                     }
1929           } else {
1930                     /* XXX IPv6 sanity checking stuff */
1931           }
1932 
1933           if (err)
1934                     return;
1935 
1936           res = doquery(impl_ver, req_code, 1, 1, sendsize, (char *)&cres,
1937                           &items, &itemsize, &dummy, 0, sizeof(cres));
1938 
1939           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1940                     impl_ver = IMPL_XNTPD_OLD;
1941                     goto again;
1942           }
1943 
1944           if (res == 0)
1945               (void) fprintf(fp, "done!\n");
1946           return;
1947 }
1948 
1949 
1950 /*
1951  * monlist - obtain and print the server's monitor data
1952  */
1953 /*ARGSUSED*/
1954 static void
monlist(struct parse * pcmd,FILE * fp)1955 monlist(
1956           struct parse *pcmd,
1957           FILE *fp
1958           )
1959 {
1960           const char *struct_star;
1961           const struct info_monitor *ml;
1962           const struct info_monitor_1 *m1;
1963           const struct old_info_monitor *oml;
1964           sockaddr_u addr;
1965           sockaddr_u dstadr;
1966           size_t items;
1967           size_t itemsize;
1968           int res;
1969           int version = -1;
1970 
1971           if (pcmd->nargs > 0)
1972                     version = pcmd->argval[0].ival;
1973 
1974 again:
1975           res = doquery(impl_ver,
1976                           (version == 1 || version == -1) ? REQ_MON_GETLIST_1 :
1977                           REQ_MON_GETLIST, 0, 0, 0, NULL,
1978                           &items, &itemsize, &struct_star,
1979                           (version < 0) ? (1 << INFO_ERR_REQ) : 0,
1980                           sizeof(struct info_monitor_1));
1981 
1982           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
1983                     impl_ver = IMPL_XNTPD_OLD;
1984                     goto again;
1985           }
1986 
1987           if (res == INFO_ERR_REQ && version < 0)
1988                     res = doquery(impl_ver, REQ_MON_GETLIST, 0, 0, 0, NULL,
1989                                     &items, &itemsize, &struct_star, 0,
1990                                     sizeof(struct info_monitor));
1991 
1992           if (res != 0)
1993                     return;
1994 
1995           if (!checkitems(items, fp))
1996                     return;
1997 
1998           if (itemsize == sizeof(struct info_monitor_1) ||
1999               itemsize == v4sizeof(struct info_monitor_1)) {
2000 
2001               m1 = (const void*)struct_star;
2002                     fprintf(fp,
2003                               "remote address          port local address      count m ver rstr avgint  lstint\n");
2004                     fprintf(fp,
2005                               "===============================================================================\n");
2006                     while (items > 0) {
2007                               SET_ADDRS(dstadr, addr, m1, daddr, addr);
2008                               if ((pcmd->nargs == 0) ||
2009                                   ((pcmd->argval->ival == 6) && (m1->v6_flag != 0)) ||
2010                                   ((pcmd->argval->ival == 4) && (m1->v6_flag == 0)))
2011                                         fprintf(fp,
2012                                             "%-22.22s %5d %-15s %8lu %1u %1u %6lx %6lu %7lu\n",
2013                                             nntohost(&addr),
2014                                             ntohs(m1->port),
2015                                             stoa(&dstadr),
2016                                             (u_long)ntohl(m1->count),
2017                                             m1->mode,
2018                                             m1->version,
2019                                             (u_long)ntohl(m1->restr),
2020                                             (u_long)ntohl(m1->avg_int),
2021                                             (u_long)ntohl(m1->last_int));
2022                               m1++;
2023                               items--;
2024                     }
2025           } else if (itemsize == sizeof(struct info_monitor) ||
2026               itemsize == v4sizeof(struct info_monitor)) {
2027 
2028                     ml = (const void *)struct_star;
2029                     fprintf(fp,
2030                               "     address               port     count mode ver rstr avgint  lstint\n");
2031                     fprintf(fp,
2032                               "===============================================================================\n");
2033                     while (items > 0) {
2034                               SET_ADDR(dstadr, ml->v6_flag, ml->addr, ml->addr6);
2035                               if ((pcmd->nargs == 0) ||
2036                                   ((pcmd->argval->ival == 6) && (ml->v6_flag != 0)) ||
2037                                   ((pcmd->argval->ival == 4) && (ml->v6_flag == 0)))
2038                                         fprintf(fp,
2039                                             "%-25.25s %5u %9lu %4u %2u %9lx %9lu %9lu\n",
2040                                             nntohost(&dstadr),
2041                                             ntohs(ml->port),
2042                                             (u_long)ntohl(ml->count),
2043                                             ml->mode,
2044                                             ml->version,
2045                                             (u_long)ntohl(ml->restr),
2046                                             (u_long)ntohl(ml->avg_int),
2047                                             (u_long)ntohl(ml->last_int));
2048                               ml++;
2049                               items--;
2050                     }
2051           } else if (itemsize == sizeof(struct old_info_monitor)) {
2052 
2053                     oml = (const void *)struct_star;
2054                     fprintf(fp,
2055                               "     address          port     count  mode version  lasttime firsttime\n");
2056                     fprintf(fp,
2057                               "======================================================================\n");
2058                     while (items > 0) {
2059                               SET_ADDR(dstadr, oml->v6_flag, oml->addr, oml->addr6);
2060                               fprintf(fp, "%-20.20s %5u %9lu %4u   %3u %9lu %9lu\n",
2061                                         nntohost(&dstadr),
2062                                         ntohs(oml->port),
2063                                         (u_long)ntohl(oml->count),
2064                                         oml->mode,
2065                                         oml->version,
2066                                         (u_long)ntohl(oml->lasttime),
2067                                         (u_long)ntohl(oml->firsttime));
2068                               oml++;
2069                               items--;
2070                     }
2071           } else {
2072                     /* issue warning according to new info_monitor size */
2073                     checkitemsize(itemsize, sizeof(struct info_monitor));
2074           }
2075 }
2076 
2077 
2078 /*
2079  * Mapping between command line strings and stat reset flags
2080  */
2081 struct statreset {
2082           const char * const  str;
2083           const int           flag;
2084 } sreset[] = {
2085           { "allpeers",       RESET_FLAG_ALLPEERS },
2086           { "io",             RESET_FLAG_IO },
2087           { "sys",  RESET_FLAG_SYS },
2088           { "mem",  RESET_FLAG_MEM },
2089           { "timer",          RESET_FLAG_TIMER },
2090           { "auth", RESET_FLAG_AUTH },
2091           { "ctl",  RESET_FLAG_CTL },
2092           { "",               0 }
2093 };
2094 
2095 /*
2096  * reset - reset statistic counters
2097  */
2098 static void
reset(struct parse * pcmd,FILE * fp)2099 reset(
2100           struct parse *pcmd,
2101           FILE *fp
2102           )
2103 {
2104           struct reset_flags rflags;
2105           size_t items;
2106           size_t itemsize;
2107           const char *dummy;
2108           int i;
2109           size_t res;
2110           int err;
2111 
2112           err = 0;
2113           rflags.flags = 0;
2114           for (res = 0; res < pcmd->nargs; res++) {
2115                     for (i = 0; sreset[i].flag != 0; i++) {
2116                               if (STREQ(pcmd->argval[res].string, sreset[i].str))
2117                                         break;
2118                     }
2119                     if (sreset[i].flag == 0) {
2120                               fprintf(fp, "Flag %s unknown\n",
2121                                         pcmd->argval[res].string);
2122                               err = 1;
2123                     } else {
2124                               rflags.flags |= sreset[i].flag;
2125                     }
2126           }
2127           rflags.flags = htonl(rflags.flags);
2128 
2129           if (err) {
2130                     (void) fprintf(fp, "Not done due to errors\n");
2131                     return;
2132           }
2133 
2134 again:
2135           res = doquery(impl_ver, REQ_RESET_STATS, 1, 1,
2136                           sizeof(struct reset_flags), (char *)&rflags, &items,
2137                           &itemsize, &dummy, 0, sizeof(struct reset_flags));
2138 
2139           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2140                     impl_ver = IMPL_XNTPD_OLD;
2141                     goto again;
2142           }
2143 
2144           if (res == 0)
2145               (void) fprintf(fp, "done!\n");
2146           return;
2147 }
2148 
2149 
2150 
2151 /*
2152  * preset - reset stat counters for particular peers
2153  */
2154 static void
preset(struct parse * pcmd,FILE * fp)2155 preset(
2156           struct parse *pcmd,
2157           FILE *fp
2158           )
2159 {
2160           /* 8 is the maximum number of peers which will fit in a packet */
2161           struct conf_unpeer *pl, plist[min(MAXARGS, 8)];
2162           size_t qitemlim;
2163           size_t qitems;
2164           size_t items;
2165           size_t itemsize;
2166           const char *dummy;
2167           int res;
2168           size_t sendsize;
2169 
2170 again:
2171           if (impl_ver == IMPL_XNTPD)
2172                     sendsize = sizeof(struct conf_unpeer);
2173           else
2174                     sendsize = v4sizeof(struct conf_unpeer);
2175 
2176           qitemlim = min(pcmd->nargs, COUNTOF(plist));
2177           for (qitems = 0, pl = plist; qitems < qitemlim; qitems++) {
2178                     if (IS_IPV4(&pcmd->argval[qitems].netnum)) {
2179                               pl->peeraddr = NSRCADR(&pcmd->argval[qitems].netnum);
2180                               if (impl_ver == IMPL_XNTPD)
2181                                         pl->v6_flag = 0;
2182                     } else {
2183                               if (impl_ver == IMPL_XNTPD_OLD) {
2184                                         fprintf(stderr,
2185                                             "***Server doesn't understand IPv6 addresses\n");
2186                                         return;
2187                               }
2188                               pl->peeraddr6 =
2189                                   SOCK_ADDR6(&pcmd->argval[qitems].netnum);
2190                               pl->v6_flag = 1;
2191                     }
2192                     pl = (void *)((char *)pl + sendsize);
2193           }
2194 
2195           res = doquery(impl_ver, REQ_RESET_PEER, 1, qitems,
2196                           sendsize, (char *)plist, &items,
2197                           &itemsize, &dummy, 0, sizeof(struct conf_unpeer));
2198 
2199           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2200                     impl_ver = IMPL_XNTPD_OLD;
2201                     goto again;
2202           }
2203 
2204           if (res == 0)
2205               (void) fprintf(fp, "done!\n");
2206 }
2207 
2208 
2209 /*
2210  * readkeys - request the server to reread the keys file
2211  */
2212 /*ARGSUSED*/
2213 static void
readkeys(struct parse * pcmd,FILE * fp)2214 readkeys(
2215           struct parse *pcmd,
2216           FILE *fp
2217           )
2218 {
2219           size_t items;
2220           size_t itemsize;
2221           const char *dummy;
2222           int res;
2223 
2224 again:
2225           res = doquery(impl_ver, REQ_REREAD_KEYS, 1, 0, 0, (char *)0,
2226                           &items, &itemsize, &dummy, 0, sizeof(dummy));
2227 
2228           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2229                     impl_ver = IMPL_XNTPD_OLD;
2230                     goto again;
2231           }
2232 
2233           if (res == 0)
2234               (void) fprintf(fp, "done!\n");
2235           return;
2236 }
2237 
2238 
2239 /*
2240  * trustkey - add some keys to the trusted key list
2241  */
2242 static void
trustkey(struct parse * pcmd,FILE * fp)2243 trustkey(
2244           struct parse *pcmd,
2245           FILE *fp
2246           )
2247 {
2248           do_trustkey(pcmd, fp, REQ_TRUSTKEY);
2249 }
2250 
2251 
2252 /*
2253  * untrustkey - remove some keys from the trusted key list
2254  */
2255 static void
untrustkey(struct parse * pcmd,FILE * fp)2256 untrustkey(
2257           struct parse *pcmd,
2258           FILE *fp
2259           )
2260 {
2261           do_trustkey(pcmd, fp, REQ_UNTRUSTKEY);
2262 }
2263 
2264 
2265 /*
2266  * do_trustkey - do grunge work of adding/deleting keys
2267  */
2268 static void
do_trustkey(struct parse * pcmd,FILE * fp,int req)2269 do_trustkey(
2270           struct parse *pcmd,
2271           FILE *fp,
2272           int req
2273           )
2274 {
2275           u_long keyids[MAXARGS];
2276           size_t i;
2277           size_t items;
2278           size_t itemsize;
2279           const char *dummy;
2280           int ritems;
2281           int res;
2282 
2283           ritems = 0;
2284           for (i = 0; i < pcmd->nargs; i++) {
2285                     keyids[ritems++] = pcmd->argval[i].uval;
2286           }
2287 
2288 again:
2289           res = doquery(impl_ver, req, 1, ritems, sizeof(u_long),
2290                           (char *)keyids, &items, &itemsize, &dummy, 0,
2291                           sizeof(dummy));
2292 
2293           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2294                     impl_ver = IMPL_XNTPD_OLD;
2295                     goto again;
2296           }
2297 
2298           if (res == 0)
2299               (void) fprintf(fp, "done!\n");
2300           return;
2301 }
2302 
2303 
2304 
2305 /*
2306  * authinfo - obtain and print info about authentication
2307  */
2308 /*ARGSUSED*/
2309 static void
authinfo(struct parse * pcmd,FILE * fp)2310 authinfo(
2311           struct parse *pcmd,
2312           FILE *fp
2313           )
2314 {
2315           struct info_auth *ia;
2316           size_t items;
2317           size_t itemsize;
2318           int res;
2319 
2320 again:
2321           res = doquery(impl_ver, REQ_AUTHINFO, 0, 0, 0, NULL, &items,
2322                           &itemsize, (void *)&ia, 0, sizeof(*ia));
2323 
2324           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2325                     impl_ver = IMPL_XNTPD_OLD;
2326                     goto again;
2327           }
2328 
2329           if (res != 0)
2330                     return;
2331 
2332           if (!check1item(items, fp))
2333                     return;
2334 
2335           if (!checkitemsize(itemsize, sizeof(*ia)))
2336                     return;
2337 
2338           fprintf(fp, "time since reset:     %lu\n",
2339                     (u_long)ntohl(ia->timereset));
2340           fprintf(fp, "stored keys:          %lu\n",
2341                     (u_long)ntohl(ia->numkeys));
2342           fprintf(fp, "free keys:            %lu\n",
2343                     (u_long)ntohl(ia->numfreekeys));
2344           fprintf(fp, "key lookups:          %lu\n",
2345                     (u_long)ntohl(ia->keylookups));
2346           fprintf(fp, "keys not found:       %lu\n",
2347                     (u_long)ntohl(ia->keynotfound));
2348           fprintf(fp, "uncached keys:        %lu\n",
2349                     (u_long)ntohl(ia->keyuncached));
2350           fprintf(fp, "encryptions:          %lu\n",
2351                     (u_long)ntohl(ia->encryptions));
2352           fprintf(fp, "decryptions:          %lu\n",
2353                     (u_long)ntohl(ia->decryptions));
2354           fprintf(fp, "expired keys:         %lu\n",
2355                     (u_long)ntohl(ia->expired));
2356 }
2357 
2358 
2359 
2360 /*
2361  * traps - obtain and print a list of traps
2362  */
2363 /*ARGSUSED*/
2364 static void
traps(struct parse * pcmd,FILE * fp)2365 traps(
2366           struct parse *pcmd,
2367           FILE *fp
2368           )
2369 {
2370           size_t i;
2371           struct info_trap *it;
2372           sockaddr_u trap_addr, local_addr;
2373           size_t items;
2374           size_t itemsize;
2375           int res;
2376 
2377 again:
2378           res = doquery(impl_ver, REQ_TRAPS, 0, 0, 0, NULL, &items,
2379                           &itemsize, (void *)&it, 0, sizeof(*it));
2380 
2381           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2382                     impl_ver = IMPL_XNTPD_OLD;
2383                     goto again;
2384           }
2385 
2386           if (res != 0)
2387                     return;
2388 
2389           if (!checkitems(items, fp))
2390                     return;
2391 
2392           if (!checkitemsize(itemsize, sizeof(struct info_trap)) &&
2393               !checkitemsize(itemsize, v4sizeof(struct info_trap)))
2394                     return;
2395 
2396           for (i = 0; i < items; i++ ) {
2397                     SET_ADDRS(trap_addr, local_addr, it, trap_address, local_address);
2398                     fprintf(fp, "%saddress %s, port %d\n",
2399                               (0 == i)
2400                                   ? ""
2401                                   : "\n",
2402                               stoa(&trap_addr), ntohs(it->trap_port));
2403                     fprintf(fp, "interface: %s, ",
2404                               (0 == it->local_address)
2405                                   ? "wildcard"
2406                                   : stoa(&local_addr));
2407                     if (ntohl(it->flags) & TRAP_CONFIGURED)
2408                               fprintf(fp, "configured\n");
2409                     else if (ntohl(it->flags) & TRAP_NONPRIO)
2410                               fprintf(fp, "low priority\n");
2411                     else
2412                               fprintf(fp, "normal priority\n");
2413 
2414                     fprintf(fp, "set for %ld secs, last set %ld secs ago\n",
2415                               (long)ntohl(it->origtime),
2416                               (long)ntohl(it->settime));
2417                     fprintf(fp, "sequence %d, number of resets %ld\n",
2418                               ntohs(it->sequence), (long)ntohl(it->resets));
2419           }
2420 }
2421 
2422 
2423 /*
2424  * addtrap - configure a trap
2425  */
2426 static void
addtrap(struct parse * pcmd,FILE * fp)2427 addtrap(
2428           struct parse *pcmd,
2429           FILE *fp
2430           )
2431 {
2432           do_addclr_trap(pcmd, fp, REQ_ADD_TRAP);
2433 }
2434 
2435 
2436 /*
2437  * clrtrap - clear a trap from the server
2438  */
2439 static void
clrtrap(struct parse * pcmd,FILE * fp)2440 clrtrap(
2441           struct parse *pcmd,
2442           FILE *fp
2443           )
2444 {
2445           do_addclr_trap(pcmd, fp, REQ_CLR_TRAP);
2446 }
2447 
2448 
2449 /*
2450  * do_addclr_trap - do grunge work of adding/deleting traps
2451  */
2452 static void
do_addclr_trap(struct parse * pcmd,FILE * fp,int req)2453 do_addclr_trap(
2454           struct parse *pcmd,
2455           FILE *fp,
2456           int req
2457           )
2458 {
2459           struct conf_trap ctrap;
2460           size_t items;
2461           size_t itemsize;
2462           const char *dummy;
2463           int res;
2464           int sendsize;
2465 
2466 again:
2467           if (impl_ver == IMPL_XNTPD)
2468                     sendsize = sizeof(struct conf_trap);
2469           else
2470                     sendsize = v4sizeof(struct conf_trap);
2471 
2472           if (IS_IPV4(&pcmd->argval[0].netnum)) {
2473                     ctrap.trap_address = NSRCADR(&pcmd->argval[0].netnum);
2474                     if (impl_ver == IMPL_XNTPD)
2475                               ctrap.v6_flag = 0;
2476           } else {
2477                     if (impl_ver == IMPL_XNTPD_OLD) {
2478                               fprintf(stderr,
2479                                   "***Server doesn't understand IPv6 addresses\n");
2480                               return;
2481                     }
2482                     ctrap.trap_address6 = SOCK_ADDR6(&pcmd->argval[0].netnum);
2483                     ctrap.v6_flag = 1;
2484           }
2485           ctrap.local_address = 0;
2486           ctrap.trap_port = htons(TRAPPORT);
2487           ctrap.unused = 0;
2488 
2489           if (pcmd->nargs > 1) {
2490                     ctrap.trap_port     = htons((u_short)pcmd->argval[1].uval);
2491                     if (pcmd->nargs > 2) {
2492                               if (AF(&pcmd->argval[2].netnum) !=
2493                                   AF(&pcmd->argval[0].netnum)) {
2494                                         fprintf(stderr,
2495                                             "***Cannot mix IPv4 and IPv6 addresses\n");
2496                                         return;
2497                               }
2498                               if (IS_IPV4(&pcmd->argval[2].netnum))
2499                                         ctrap.local_address = NSRCADR(&pcmd->argval[2].netnum);
2500                               else
2501                                         ctrap.local_address6 = SOCK_ADDR6(&pcmd->argval[2].netnum);
2502                     }
2503           }
2504 
2505           res = doquery(impl_ver, req, 1, 1, sendsize,
2506                           (char *)&ctrap, &items, &itemsize, &dummy, 0,
2507                           sizeof(struct conf_trap));
2508 
2509           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2510                     impl_ver = IMPL_XNTPD_OLD;
2511                     goto again;
2512           }
2513 
2514           if (res == 0)
2515               (void) fprintf(fp, "done!\n");
2516           return;
2517 }
2518 
2519 
2520 
2521 /*
2522  * requestkey - change the server's request key (a dangerous request)
2523  */
2524 static void
requestkey(struct parse * pcmd,FILE * fp)2525 requestkey(
2526           struct parse *pcmd,
2527           FILE *fp
2528           )
2529 {
2530           do_changekey(pcmd, fp, REQ_REQUEST_KEY);
2531 }
2532 
2533 
2534 /*
2535  * controlkey - change the server's control key
2536  */
2537 static void
controlkey(struct parse * pcmd,FILE * fp)2538 controlkey(
2539           struct parse *pcmd,
2540           FILE *fp
2541           )
2542 {
2543           do_changekey(pcmd, fp, REQ_CONTROL_KEY);
2544 }
2545 
2546 
2547 
2548 /*
2549  * do_changekey - do grunge work of changing keys
2550  */
2551 static void
do_changekey(struct parse * pcmd,FILE * fp,int req)2552 do_changekey(
2553           struct parse *pcmd,
2554           FILE *fp,
2555           int req
2556           )
2557 {
2558           u_long key;
2559           size_t items;
2560           size_t itemsize;
2561           const char *dummy;
2562           int res;
2563 
2564 
2565           key = htonl((u_int32)pcmd->argval[0].uval);
2566 
2567 again:
2568           res = doquery(impl_ver, req, 1, 1, sizeof(u_int32),
2569                           (char *)&key, &items, &itemsize, &dummy, 0,
2570                           sizeof(dummy));
2571 
2572           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2573                     impl_ver = IMPL_XNTPD_OLD;
2574                     goto again;
2575           }
2576 
2577           if (res == 0)
2578               (void) fprintf(fp, "done!\n");
2579           return;
2580 }
2581 
2582 
2583 
2584 /*
2585  * ctlstats - obtain and print info about authentication
2586  */
2587 /*ARGSUSED*/
2588 static void
ctlstats(struct parse * pcmd,FILE * fp)2589 ctlstats(
2590           struct parse *pcmd,
2591           FILE *fp
2592           )
2593 {
2594           struct info_control *ic;
2595           size_t items;
2596           size_t itemsize;
2597           int res;
2598 
2599 again:
2600           res = doquery(impl_ver, REQ_GET_CTLSTATS, 0, 0, 0, NULL, &items,
2601                           &itemsize, (void *)&ic, 0, sizeof(*ic));
2602 
2603           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2604                     impl_ver = IMPL_XNTPD_OLD;
2605                     goto again;
2606           }
2607 
2608           if (res != 0)
2609                     return;
2610 
2611           if (!check1item(items, fp))
2612                     return;
2613 
2614           if (!checkitemsize(itemsize, sizeof(*ic)))
2615                     return;
2616 
2617           fprintf(fp, "time since reset:       %lu\n",
2618                     (u_long)ntohl(ic->ctltimereset));
2619           fprintf(fp, "requests received:      %lu\n",
2620                     (u_long)ntohl(ic->numctlreq));
2621           fprintf(fp, "responses sent:         %lu\n",
2622                     (u_long)ntohl(ic->numctlresponses));
2623           fprintf(fp, "fragments sent:         %lu\n",
2624                     (u_long)ntohl(ic->numctlfrags));
2625           fprintf(fp, "async messages sent:    %lu\n",
2626                     (u_long)ntohl(ic->numasyncmsgs));
2627           fprintf(fp, "error msgs sent:        %lu\n",
2628                     (u_long)ntohl(ic->numctlerrors));
2629           fprintf(fp, "total bad pkts:         %lu\n",
2630                     (u_long)ntohl(ic->numctlbadpkts));
2631           fprintf(fp, "packet too short:       %lu\n",
2632                     (u_long)ntohl(ic->numctltooshort));
2633           fprintf(fp, "response on input:      %lu\n",
2634                     (u_long)ntohl(ic->numctlinputresp));
2635           fprintf(fp, "fragment on input:      %lu\n",
2636                     (u_long)ntohl(ic->numctlinputfrag));
2637           fprintf(fp, "error set on input:     %lu\n",
2638                     (u_long)ntohl(ic->numctlinputerr));
2639           fprintf(fp, "bad offset on input:    %lu\n",
2640                     (u_long)ntohl(ic->numctlbadoffset));
2641           fprintf(fp, "bad version packets:    %lu\n",
2642                     (u_long)ntohl(ic->numctlbadversion));
2643           fprintf(fp, "data in pkt too short:  %lu\n",
2644                     (u_long)ntohl(ic->numctldatatooshort));
2645           fprintf(fp, "unknown op codes:       %lu\n",
2646                     (u_long)ntohl(ic->numctlbadop));
2647 }
2648 
2649 
2650 /*
2651  * clockstat - get and print clock status information
2652  */
2653 static void
clockstat(struct parse * pcmd,FILE * fp)2654 clockstat(
2655           struct parse *pcmd,
2656           FILE *fp
2657           )
2658 {
2659           struct info_clock *cl;
2660           /* 8 is the maximum number of clocks which will fit in a packet */
2661           u_long clist[min(MAXARGS, 8)];
2662           size_t qitemlim;
2663           size_t qitems;
2664           size_t items;
2665           size_t itemsize;
2666           int res;
2667           l_fp ts;
2668           struct clktype *clk;
2669 
2670           qitemlim = min(pcmd->nargs, COUNTOF(clist));
2671           for (qitems = 0; qitems < qitemlim; qitems++)
2672                     clist[qitems] = NSRCADR(&pcmd->argval[qitems].netnum);
2673 
2674 again:
2675           res = doquery(impl_ver, REQ_GET_CLOCKINFO, 0, qitems,
2676                           sizeof(u_int32), (char *)clist, &items,
2677                           &itemsize, (void *)&cl, 0, sizeof(struct info_clock));
2678 
2679           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2680                     impl_ver = IMPL_XNTPD_OLD;
2681                     goto again;
2682           }
2683 
2684           if (res != 0)
2685                     return;
2686 
2687           if (!checkitems(items, fp))
2688                     return;
2689 
2690           if (!checkitemsize(itemsize, sizeof(struct info_clock)))
2691                     return;
2692 
2693           while (items-- > 0) {
2694                     (void) fprintf(fp, "clock address:        %s\n",
2695                                      numtoa(cl->clockadr));
2696                     for (clk = clktypes; clk->code >= 0; clk++)
2697                         if (clk->code == cl->type)
2698                               break;
2699                     if (clk->code >= 0)
2700                         (void) fprintf(fp, "clock type:           %s\n",
2701                                            clk->clocktype);
2702                     else
2703                         (void) fprintf(fp, "clock type:           unknown type (%d)\n",
2704                                            cl->type);
2705                     (void) fprintf(fp, "last event:           %d\n",
2706                                      cl->lastevent);
2707                     (void) fprintf(fp, "current status:       %d\n",
2708                                      cl->currentstatus);
2709                     (void) fprintf(fp, "number of polls:      %lu\n",
2710                                      (u_long)ntohl(cl->polls));
2711                     (void) fprintf(fp, "no response to poll:  %lu\n",
2712                                      (u_long)ntohl(cl->noresponse));
2713                     (void) fprintf(fp, "bad format responses: %lu\n",
2714                                      (u_long)ntohl(cl->badformat));
2715                     (void) fprintf(fp, "bad data responses:   %lu\n",
2716                                      (u_long)ntohl(cl->baddata));
2717                     (void) fprintf(fp, "running time:         %lu\n",
2718                                      (u_long)ntohl(cl->timestarted));
2719                     NTOHL_FP(&cl->fudgetime1, &ts);
2720                     (void) fprintf(fp, "fudge time 1:         %s\n",
2721                                      lfptoa(&ts, 6));
2722                     NTOHL_FP(&cl->fudgetime2, &ts);
2723                     (void) fprintf(fp, "fudge time 2:         %s\n",
2724                                      lfptoa(&ts, 6));
2725                     (void) fprintf(fp, "stratum:              %ld\n",
2726                                      (u_long)ntohl(cl->fudgeval1));
2727                     /* [Bug3527] Backward Incompatible: cl->fudgeval2 is
2728                      * a string, instantiated via memcpy() so there is no
2729                      * endian issue to correct.
2730                      */
2731 #ifdef DISABLE_BUG3527_FIX
2732                     (void) fprintf(fp, "reference ID:         %s\n",
2733                                      refid_string(ntohl(cl->fudgeval2), 0));
2734 #else
2735                     (void) fprintf(fp, "reference ID:         %s\n",
2736                                      refid_string(cl->fudgeval2, 0));
2737 #endif
2738                     (void) fprintf(fp, "fudge flags:          0x%x\n",
2739                                      cl->flags);
2740 
2741                     if (items > 0)
2742                         (void) fprintf(fp, "\n");
2743                     cl++;
2744           }
2745 }
2746 
2747 
2748 /*
2749  * fudge - set clock fudge factors
2750  */
2751 static void
fudge(struct parse * pcmd,FILE * fp)2752 fudge(
2753           struct parse *pcmd,
2754           FILE *fp
2755           )
2756 {
2757           struct conf_fudge fudgedata;
2758           size_t items;
2759           size_t itemsize;
2760           const char *dummy;
2761           l_fp ts;
2762           int res;
2763           long val;
2764           u_long u_val;
2765           int err;
2766 
2767 
2768           err = 0;
2769           ZERO(fudgedata);
2770           fudgedata.clockadr = NSRCADR(&pcmd->argval[0].netnum);
2771 
2772           if (STREQ(pcmd->argval[1].string, "time1")) {
2773                     fudgedata.which = htonl(FUDGE_TIME1);
2774                     if (!atolfp(pcmd->argval[2].string, &ts))
2775                         err = 1;
2776                     else
2777                         NTOHL_FP(&ts, &fudgedata.fudgetime);
2778           } else if (STREQ(pcmd->argval[1].string, "time2")) {
2779                     fudgedata.which = htonl(FUDGE_TIME2);
2780                     if (!atolfp(pcmd->argval[2].string, &ts))
2781                         err = 1;
2782                     else
2783                         NTOHL_FP(&ts, &fudgedata.fudgetime);
2784           } else if (STREQ(pcmd->argval[1].string, "val1")) {
2785                     fudgedata.which = htonl(FUDGE_VAL1);
2786                     if (!atoint(pcmd->argval[2].string, &val))
2787                         err = 1;
2788                     else
2789                         fudgedata.fudgeval_flags = htonl(val);
2790           } else if (STREQ(pcmd->argval[1].string, "val2")) {
2791                     fudgedata.which = htonl(FUDGE_VAL2);
2792                     if (!atoint(pcmd->argval[2].string, &val))
2793                         err = 1;
2794                     else
2795                         fudgedata.fudgeval_flags = htonl((u_int32)val);
2796           } else if (STREQ(pcmd->argval[1].string, "flags")) {
2797                     fudgedata.which = htonl(FUDGE_FLAGS);
2798                     if (!hextoint(pcmd->argval[2].string, &u_val))
2799                         err = 1;
2800                     else
2801                         fudgedata.fudgeval_flags = htonl((u_int32)(u_val & 0xf));
2802           } else {
2803                     (void) fprintf(stderr, "What fudge is %s?\n",
2804                                      pcmd->argval[1].string);
2805                     return;
2806           }
2807 
2808           if (err) {
2809                     (void) fprintf(stderr, "Unknown fudge parameter %s\n",
2810                                      pcmd->argval[2].string);
2811                     return;
2812           }
2813 
2814 again:
2815           res = doquery(impl_ver, REQ_SET_CLKFUDGE, 1, 1,
2816                           sizeof(struct conf_fudge), (char *)&fudgedata, &items,
2817                           &itemsize, &dummy, 0, sizeof(dummy));
2818 
2819           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2820                     impl_ver = IMPL_XNTPD_OLD;
2821                     goto again;
2822           }
2823 
2824           if (res == 0)
2825               (void) fprintf(fp, "done!\n");
2826           return;
2827 }
2828 
2829 /*
2830  * clkbug - get and print clock debugging information
2831  */
2832 static void
clkbug(struct parse * pcmd,FILE * fp)2833 clkbug(
2834           struct parse *pcmd,
2835           FILE *fp
2836           )
2837 {
2838           register int i;
2839           register int n;
2840           register u_int32 s;
2841           struct info_clkbug *cl;
2842           /* 8 is the maximum number of clocks which will fit in a packet */
2843           u_long clist[min(MAXARGS, 8)];
2844           u_int32 ltemp;
2845           size_t qitemlim;
2846           size_t qitems;
2847           size_t items;
2848           size_t itemsize;
2849           int res;
2850           int needsp;
2851           l_fp ts;
2852 
2853           qitemlim = min(pcmd->nargs, COUNTOF(clist));
2854           for (qitems = 0; qitems < qitemlim; qitems++)
2855                     clist[qitems] = NSRCADR(&pcmd->argval[qitems].netnum);
2856 
2857 again:
2858           res = doquery(impl_ver, REQ_GET_CLKBUGINFO, 0, qitems,
2859                           sizeof(u_int32), (char *)clist, &items,
2860                           &itemsize, (void *)&cl, 0, sizeof(struct info_clkbug));
2861 
2862           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2863                     impl_ver = IMPL_XNTPD_OLD;
2864                     goto again;
2865           }
2866 
2867           if (res != 0)
2868                     return;
2869 
2870           if (!checkitems(items, fp))
2871                     return;
2872 
2873           if (!checkitemsize(itemsize, sizeof(struct info_clkbug)))
2874                     return;
2875 
2876           while (items-- > 0) {
2877                     (void) fprintf(fp, "clock address:        %s\n",
2878                                      numtoa(cl->clockadr));
2879                     n = (int)cl->nvalues;
2880                     (void) fprintf(fp, "values: %d", n);
2881                     s = ntohs(cl->svalues);
2882                     if (n > NUMCBUGVALUES)
2883                         n = NUMCBUGVALUES;
2884                     for (i = 0; i < n; i++) {
2885                               ltemp = ntohl(cl->values[i]);
2886                               ltemp &= 0xffffffff;          /* HMS: This does nothing now */
2887                               if ((i & 0x3) == 0)
2888                                   (void) fprintf(fp, "\n");
2889                               if (s & (1 << i))
2890                                   (void) fprintf(fp, "%12ld", (u_long)ltemp);
2891                               else
2892                                   (void) fprintf(fp, "%12lu", (u_long)ltemp);
2893                     }
2894                     (void) fprintf(fp, "\n");
2895 
2896                     n = (int)cl->ntimes;
2897                     (void) fprintf(fp, "times: %d", n);
2898                     s = ntohl(cl->stimes);
2899                     if (n > NUMCBUGTIMES)
2900                         n = NUMCBUGTIMES;
2901                     needsp = 0;
2902                     for (i = 0; i < n; i++) {
2903                               if ((i & 0x1) == 0) {
2904                                   (void) fprintf(fp, "\n");
2905                               } else {
2906                                         for (;needsp > 0; needsp--)
2907                                             putc(' ', fp);
2908                               }
2909                               NTOHL_FP(&cl->times[i], &ts);
2910                               if (s & (1 << i)) {
2911                                         (void) fprintf(fp, "%17s",
2912                                                          lfptoa(&ts, 6));
2913                                         needsp = 22;
2914                               } else {
2915                                         (void) fprintf(fp, "%37s",
2916                                                          uglydate(&ts));
2917                                         needsp = 2;
2918                               }
2919                     }
2920                     (void) fprintf(fp, "\n");
2921                     if (items > 0) {
2922                               cl++;
2923                               (void) fprintf(fp, "\n");
2924                     }
2925           }
2926 }
2927 
2928 
2929 /*
2930  * kerninfo - display the kernel pll/pps variables
2931  */
2932 static void
kerninfo(struct parse * pcmd,FILE * fp)2933 kerninfo(
2934           struct parse *pcmd,
2935           FILE *fp
2936           )
2937 {
2938           struct info_kernel *ik;
2939           size_t items;
2940           size_t itemsize;
2941           int res;
2942           unsigned status;
2943           double tscale_usec = 1e-6, tscale_unano = 1e-6;
2944 
2945 again:
2946           res = doquery(impl_ver, REQ_GET_KERNEL, 0, 0, 0, (char *)NULL,
2947                           &items, &itemsize, (void *)&ik, 0,
2948                           sizeof(struct info_kernel));
2949 
2950           if (res == INFO_ERR_IMPL && impl_ver == IMPL_XNTPD) {
2951                     impl_ver = IMPL_XNTPD_OLD;
2952                     goto again;
2953           }
2954 
2955           if (res != 0)
2956               return;
2957           if (!check1item(items, fp))
2958               return;
2959           if (!checkitemsize(itemsize, sizeof(struct info_kernel)))
2960               return;
2961 
2962           status = ntohs(ik->status) & 0xffff;
2963           /*
2964            * pll variables. We know more than we should about the NANO bit.
2965            */
2966 #ifdef STA_NANO
2967           if (status & STA_NANO)
2968                     tscale_unano = 1e-9;
2969 #endif
2970           (void)fprintf(fp, "pll offset:           %g s\n",
2971               (int32)ntohl(ik->offset) * tscale_unano);
2972           (void)fprintf(fp, "pll frequency:        %s ppm\n",
2973               fptoa((s_fp)ntohl(ik->freq), 3));
2974           (void)fprintf(fp, "maximum error:        %g s\n",
2975               (u_long)ntohl(ik->maxerror) * tscale_usec);
2976           (void)fprintf(fp, "estimated error:      %g s\n",
2977               (u_long)ntohl(ik->esterror) * tscale_usec);
2978           (void)fprintf(fp, "status:               %04x ", status);
2979 #ifdef STA_PLL
2980           if (status & STA_PLL) (void)fprintf(fp, " pll");
2981 #endif
2982 #ifdef STA_PPSFREQ
2983           if (status & STA_PPSFREQ) (void)fprintf(fp, " ppsfreq");
2984 #endif
2985 #ifdef STA_PPSTIME
2986           if (status & STA_PPSTIME) (void)fprintf(fp, " ppstime");
2987 #endif
2988 #ifdef STA_FLL
2989           if (status & STA_FLL) (void)fprintf(fp, " fll");
2990 #endif
2991 #ifdef STA_INS
2992           if (status & STA_INS) (void)fprintf(fp, " ins");
2993 #endif
2994 #ifdef STA_DEL
2995           if (status & STA_DEL) (void)fprintf(fp, " del");
2996 #endif
2997 #ifdef STA_UNSYNC
2998           if (status & STA_UNSYNC) (void)fprintf(fp, " unsync");
2999 #endif
3000 #ifdef STA_FREQHOLD
3001           if (status & STA_FREQHOLD) (void)fprintf(fp, " freqhold");
3002 #endif
3003 #ifdef STA_PPSSIGNAL
3004           if (status & STA_PPSSIGNAL) (void)fprintf(fp, " ppssignal");
3005 #endif
3006 #ifdef STA_PPSJITTER
3007           if (status & STA_PPSJITTER) (void)fprintf(fp, " ppsjitter");
3008 #endif
3009 #ifdef STA_PPSWANDER
3010           if (status & STA_PPSWANDER) (void)fprintf(fp, " ppswander");
3011 #endif
3012 #ifdef STA_PPSERROR
3013           if (status & STA_PPSERROR) (void)fprintf(fp, " ppserror");
3014 #endif
3015 #ifdef STA_CLOCKERR
3016           if (status & STA_CLOCKERR) (void)fprintf(fp, " clockerr");
3017 #endif
3018 #ifdef STA_NANO
3019           if (status & STA_NANO) (void)fprintf(fp, " nano");
3020 #endif
3021 #ifdef STA_MODE
3022           if (status & STA_MODE) (void)fprintf(fp, " mode=fll");
3023 #endif
3024 #ifdef STA_CLK
3025           if (status & STA_CLK) (void)fprintf(fp, " src=B");
3026 #endif
3027           (void)fprintf(fp, "\n");
3028           (void)fprintf(fp, "pll time constant:    %ld\n",
3029               (u_long)ntohl(ik->constant));
3030           (void)fprintf(fp, "precision:            %g s\n",
3031               (u_long)ntohl(ik->precision) * tscale_usec);
3032           (void)fprintf(fp, "frequency tolerance:  %s ppm\n",
3033               fptoa((s_fp)ntohl(ik->tolerance), 0));
3034 
3035           /*
3036            * For backwards compatibility (ugh), we find the pps variables
3037            * only if the shift member is nonzero.
3038            */
3039           if (!ik->shift)
3040               return;
3041 
3042           /*
3043            * pps variables
3044            */
3045           (void)fprintf(fp, "pps frequency:        %s ppm\n",
3046               fptoa((s_fp)ntohl(ik->ppsfreq), 3));
3047           (void)fprintf(fp, "pps stability:        %s ppm\n",
3048               fptoa((s_fp)ntohl(ik->stabil), 3));
3049           (void)fprintf(fp, "pps jitter:           %g s\n",
3050               (u_long)ntohl(ik->jitter) * tscale_unano);
3051           (void)fprintf(fp, "calibration interval: %d s\n",
3052                           1 << ntohs(ik->shift));
3053           (void)fprintf(fp, "calibration cycles:   %ld\n",
3054                           (u_long)ntohl(ik->calcnt));
3055           (void)fprintf(fp, "jitter exceeded:      %ld\n",
3056                           (u_long)ntohl(ik->jitcnt));
3057           (void)fprintf(fp, "stability exceeded:   %ld\n",
3058                           (u_long)ntohl(ik->stbcnt));
3059           (void)fprintf(fp, "calibration errors:   %ld\n",
3060                           (u_long)ntohl(ik->errcnt));
3061 }
3062 
3063 #define IF_LIST_FMT     "%2d %c %48s %c %c %12.12s %03lx %3lu %2lu %5lu %5lu %5lu %2lu %3lu %7lu\n"
3064 #define IF_LIST_FMT_STR "%2s %c %48s %c %c %12.12s %3s %3s %2s %5s %5s %5s %2s %3s %7s\n"
3065 #define IF_LIST_AFMT_STR "     %48s %c\n"
3066 #define IF_LIST_LABELS  "#", 'A', "Address/Mask/Broadcast", 'T', 'E', "IF name", "Flg", "TL", "#M", "recv", "sent", "drop", "S", "PC", "uptime"
3067 #define IF_LIST_LINE    "==================================================================================================================\n"
3068 
3069 static void
iflist(FILE * fp,struct info_if_stats * ifs,size_t items,size_t itemsize,int res)3070 iflist(
3071           FILE *fp,
3072           struct info_if_stats *ifs,
3073           size_t items,
3074           size_t itemsize,
3075           int res
3076           )
3077 {
3078           static const char *actions = "?.+-";
3079           sockaddr_u saddr;
3080 
3081           if (res != 0)
3082               return;
3083 
3084           if (!checkitems(items, fp))
3085               return;
3086 
3087           if (!checkitemsize(itemsize, sizeof(struct info_if_stats)))
3088               return;
3089 
3090           fprintf(fp, IF_LIST_FMT_STR, IF_LIST_LABELS);
3091           fprintf(fp, IF_LIST_LINE);
3092 
3093           while (items > 0) {
3094                     SET_ADDR(saddr, ntohl(ifs->v6_flag),
3095                                ifs->unaddr.addr.s_addr, ifs->unaddr.addr6);
3096                     fprintf(fp, IF_LIST_FMT,
3097                               ntohl(ifs->ifnum),
3098                               actions[(ifs->action >= 1 && ifs->action < 4) ? ifs->action : 0],
3099                               stoa((&saddr)), 'A',
3100                               ifs->ignore_packets ? 'D' : 'E',
3101                               ifs->name,
3102                               (u_long)ntohl(ifs->flags),
3103                               (u_long)ntohl(ifs->last_ttl),
3104                               (u_long)ntohl(ifs->num_mcast),
3105                               (u_long)ntohl(ifs->received),
3106                               (u_long)ntohl(ifs->sent),
3107                               (u_long)ntohl(ifs->notsent),
3108                               (u_long)ntohl(ifs->scopeid),
3109                               (u_long)ntohl(ifs->peercnt),
3110                               (u_long)ntohl(ifs->uptime));
3111 
3112                     SET_ADDR(saddr, ntohl(ifs->v6_flag),
3113                                ifs->unmask.addr.s_addr, ifs->unmask.addr6);
3114                     fprintf(fp, IF_LIST_AFMT_STR, stoa(&saddr), 'M');
3115 
3116                     if (!ntohl(ifs->v6_flag) && ntohl(ifs->flags) & (INT_BCASTOPEN)) {
3117                               SET_ADDR(saddr, ntohl(ifs->v6_flag),
3118                                          ifs->unbcast.addr.s_addr, ifs->unbcast.addr6);
3119                               fprintf(fp, IF_LIST_AFMT_STR, stoa(&saddr), 'B');
3120 
3121                     }
3122 
3123                     ifs++;
3124                     items--;
3125           }
3126 }
3127 
3128 /*ARGSUSED*/
3129 static void
get_if_stats(struct parse * pcmd,FILE * fp)3130 get_if_stats(
3131           struct parse *pcmd,
3132           FILE *fp
3133           )
3134 {
3135           struct info_if_stats *ifs;
3136           size_t items;
3137           size_t itemsize;
3138           int res;
3139 
3140           res = doquery(impl_ver, REQ_IF_STATS, 1, 0, 0, (char *)NULL, &items,
3141                           &itemsize, (void *)&ifs, 0,
3142                           sizeof(struct info_if_stats));
3143           iflist(fp, ifs, items, itemsize, res);
3144 }
3145 
3146 /*ARGSUSED*/
3147 static void
do_if_reload(struct parse * pcmd,FILE * fp)3148 do_if_reload(
3149           struct parse *pcmd,
3150           FILE *fp
3151           )
3152 {
3153           struct info_if_stats *ifs;
3154           size_t items;
3155           size_t itemsize;
3156           int res;
3157 
3158           res = doquery(impl_ver, REQ_IF_RELOAD, 1, 0, 0, (char *)NULL, &items,
3159                           &itemsize, (void *)&ifs, 0,
3160                           sizeof(struct info_if_stats));
3161           iflist(fp, ifs, items, itemsize, res);
3162 }
3163