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