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