xref: /freebsd/contrib/bsnmp/snmp_ntp/snmp_ntp.c (revision 8e9b3e707151d136ec95e7f1d37556e39c1e228c)
1  /*
2   * Copyright (c) 2005,2018
3   *	Hartmut Brandt.
4   *	All rights reserved.
5   *
6   * Author: Harti Brandt <harti@freebsd.org>
7   *
8   * Redistribution of this software and documentation and use in source and
9   * binary forms, with or without modification, are permitted provided that
10   * the following conditions are met:
11   *
12   * 1. Redistributions of source code or documentation must retain the above
13   *    copyright notice, this list of conditions and the following disclaimer.
14   * 2. Redistributions in binary form must reproduce the above copyright
15   *    notice, this list of conditions and the following disclaimer in the
16   *    documentation and/or other materials provided with the distribution.
17   *
18   * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
19   * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
22   * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
23   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
25   * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29   *
30   * $Begemot: bsnmp/snmp_ntp/snmp_ntp.c,v 1.9 2005/10/06 07:15:01 brandt_h Exp $
31   *
32   * NTP interface for SNMPd.
33   */
34  
35  #include <sys/queue.h>
36  #include <sys/time.h>
37  #include <sys/types.h>
38  #include <sys/select.h>
39  #include <sys/socket.h>
40  #include <ctype.h>
41  #include <errno.h>
42  #include <netdb.h>
43  #ifdef HAVE_STDINT_H
44  #include <stdint.h>
45  #elif defined(HAVE_INTTYPES_H)
46  #include <inttypes.h>
47  #endif
48  #include <stdio.h>
49  #include <stdlib.h>
50  #include <string.h>
51  #include <syslog.h>
52  #include <unistd.h>
53  
54  #include "support.h"
55  #include "snmpmod.h"
56  
57  #define	SNMPTREE_TYPES
58  #include "ntp_tree.h"
59  #include "ntp_oid.h"
60  
61  #define	NTPC_MAX	576
62  #define	NTPC_VERSION	3
63  #define	NTPC_MODE	6
64  #define	NTPC_DMAX	468
65  
66  #define	NTPC_BIT_RESP	0x80
67  #define	NTPC_BIT_ERROR	0x40
68  #define	NTPC_BIT_MORE	0x20
69  
70  #define	NTPC_OPMASK	0x1f
71  #define	NTPC_OP_READSTAT	1
72  #define	NTPC_OP_READVAR		2
73  
74  /* our module handle */
75  static struct lmodule *module;
76  
77  /* debug flag */
78  static uint32_t ntp_debug;
79  #define DBG_DUMP_PKTS	0x01
80  #define	DBG_DUMP_VARS	0x02
81  
82  /* OIDs */
83  static const struct asn_oid oid_ntpMIB = OIDX_ntpMIB;
84  
85  /* the Object Resource registration index */
86  static u_int reg_index;
87  
88  /* last time we've fetch the system variables */
89  static uint64_t sysinfo_tick;
90  
91  /* cached system variables */
92  static int32_t	sys_leap;
93  static int	sysb_leap;
94  static int32_t	sys_stratum;
95  static int	sysb_stratum;
96  static int32_t	sys_precision;
97  static int	sysb_precision;
98  static char	*sys_rootdelay;
99  static char	*sys_rootdispersion;
100  static char	*sys_refid;
101  static char	sys_reftime[8];
102  static int	sysb_reftime;
103  static int32_t	sys_poll;
104  static int	sysb_poll;
105  static uint32_t	sys_peer;
106  static int	sysb_peer;
107  static u_char	sys_clock[8];
108  static int	sysb_clock;
109  static char	*sys_system;
110  static char	*sys_processor;
111  static int	sysb_jitter;
112  static double	sys_jitter;
113  static int	sysb_stability;
114  static double	sys_stability;
115  
116  /* last time we've fetch the peer list */
117  static uint64_t peers_tick;
118  
119  /* request sequence number generator */
120  static uint16_t	seqno;
121  
122  /* NTPD socket */
123  static int ntpd_sock;
124  static void *ntpd_fd;
125  
126  struct peer {
127  	/* required entries for macros */
128  	uint32_t	index;
129  	TAILQ_ENTRY(peer) link;
130  
131  	int32_t		config;		/* config bit */
132  	u_char		srcadr[4];	/* PeerAddress */
133  	uint32_t	srcport;	/* PeerPort */
134  	u_char		dstadr[4];	/* HostAddress */
135  	uint32_t	dstport;	/* HostPort */
136  	int32_t		leap;		/* Leap */
137  	int32_t		hmode;		/* Mode */
138  	int32_t		stratum;	/* Stratum */
139  	int32_t		ppoll;		/* PeerPoll */
140  	int32_t		hpoll;		/* HostPoll */
141  	int32_t		precision;	/* Precision */
142  	char		*rootdelay;	/* RootDelay */
143  	char		*rootdispersion;/* RootDispersion */
144  	char		*refid;		/* RefId */
145  	u_char		reftime[8];	/* RefTime */
146  	u_char		orgtime[8];	/* OrgTime */
147  	u_char		rcvtime[8];	/* ReceiveTime */
148  	u_char		xmttime[8];	/* TransmitTime */
149  	u_int32_t	reach;		/* Reach */
150  	int32_t		timer;		/* Timer */
151  	char		*offset;	/* Offset */
152  	char		*delay;		/* Delay */
153  	char		*dispersion;	/* Dispersion */
154  	int32_t		filt_entries;
155  };
156  TAILQ_HEAD(peer_list, peer);
157  
158  /* list of peers */
159  static struct peer_list peers = TAILQ_HEAD_INITIALIZER(peers);
160  
161  struct filt {
162  	/* required fields */
163  	struct asn_oid	index;
164  	TAILQ_ENTRY(filt) link;
165  
166  	char		*offset;
167  	char		*delay;
168  	char		*dispersion;
169  };
170  TAILQ_HEAD(filt_list, filt);
171  
172  /* list of filters */
173  static struct filt_list filts = TAILQ_HEAD_INITIALIZER(filts);
174  
175  /* configuration */
176  static u_char *ntp_host;
177  static u_char *ntp_port;
178  static uint32_t ntp_timeout;
179  
180  static void ntpd_input(int, void *);
181  static int open_socket(void);
182  
183  /* the initialization function */
184  static int
ntp_init(struct lmodule * mod,int argc,char * argv[]__unused)185  ntp_init(struct lmodule *mod, int argc, char *argv[] __unused)
186  {
187  
188  	module = mod;
189  
190  	if (argc != 0) {
191  		syslog(LOG_ERR, "bad number of arguments for %s", __func__);
192  		return (EINVAL);
193  	}
194  
195  	ntp_host = strdup("localhost");
196  	ntp_port = strdup("ntp");
197  	ntp_timeout = 50;		/* 0.5sec */
198  
199  	return (0);
200  }
201  
202  /*
203   * Module is started
204   */
205  static void
ntp_start(void)206  ntp_start(void)
207  {
208  
209  	if (open_socket() != -1) {
210  		ntpd_fd = fd_select(ntpd_sock, ntpd_input, NULL, module);
211  		if (ntpd_fd == NULL) {
212  			syslog(LOG_ERR, "fd_select failed on ntpd socket: %m");
213  			return;
214  		}
215  	}
216  	reg_index = or_register(&oid_ntpMIB, "The MIB for NTP.", module);
217  }
218  
219  /*
220   * Called, when the module is to be unloaded after it was successfully loaded
221   */
222  static int
ntp_fini(void)223  ntp_fini(void)
224  {
225  
226  	or_unregister(reg_index);
227  	fd_deselect(ntpd_fd);
228  
229  	return (0);
230  }
231  
232  const struct snmp_module config = {
233  	.comment =	"This module implements the NTP MIB",
234  	.init =		ntp_init,
235  	.start =	ntp_start,
236  	.fini =		ntp_fini,
237  	.tree =		ntp_ctree,
238  	.tree_size =	ntp_CTREE_SIZE,
239  };
240  
241  /*
242   * Open the NTPD socket
243   */
244  static int
open_socket(void)245  open_socket(void)
246  {
247  	struct addrinfo hints, *res, *res0;
248  	int	error;
249  	const char *cause;
250  
251  	memset(&hints, 0, sizeof(hints));
252  	hints.ai_family = AF_INET;
253  	hints.ai_socktype = SOCK_DGRAM;
254  
255  	error = getaddrinfo(ntp_host, ntp_port, &hints, &res0);
256  	if (error) {
257  		syslog(LOG_ERR, "%s(%s): %s", ntp_host, ntp_port,
258  		    gai_strerror(error));
259  		return (-1);
260  	}
261  
262  	ntpd_sock = -1;
263  	cause = "no address";
264  	errno = EADDRNOTAVAIL;
265  	for (res = res0; res != NULL; res = res->ai_next) {
266  		ntpd_sock = socket(res->ai_family, res->ai_socktype,
267  		    res->ai_protocol);
268  		if (ntpd_sock == -1) {
269  			cause = "socket";
270  			continue;
271  		}
272  		if (connect(ntpd_sock, res->ai_addr, res->ai_addrlen) == -1) {
273  			cause = "connect";
274  			(void)close(ntpd_sock);
275  			ntpd_sock = -1;
276  			continue;
277  		}
278  		break;
279  	}
280  	if (ntpd_sock == -1) {
281  		syslog(LOG_ERR, "%s: %m", cause);
282  		return (-1);
283  	}
284  	freeaddrinfo(res0);
285  	return (0);
286  }
287  
288  /*
289   * Dump a packet
290   */
291  static void
dump_packet(const u_char * pkt,size_t ret)292  dump_packet(const u_char *pkt, size_t ret)
293  {
294  	char buf[8 * 3 + 1];
295  	size_t i, j;
296  
297  	for (i = 0; i < ret; i += 8) {
298  		buf[0] = '\0';
299  		for (j = 0; i + j < (size_t)ret && j < 8; j++)
300  			sprintf(buf + strlen(buf), " %02x", pkt[i + j]);
301  		syslog(LOG_INFO, "%04zu:%s", i, buf);
302  	}
303  }
304  
305  /*
306   * Execute an NTP request.
307   */
308  static int
ntpd_request(u_int op,u_int associd,const char * vars)309  ntpd_request(u_int op, u_int associd, const char *vars)
310  {
311  	u_char	*rpkt;
312  	u_char	*ptr;
313  	size_t	vlen;
314  	ssize_t	ret;
315  
316  	if ((rpkt = malloc(NTPC_MAX)) == NULL) {
317  		syslog(LOG_ERR, "%m");
318  		return (-1);
319  	}
320  	memset(rpkt, 0, NTPC_MAX);
321  
322  	ptr = rpkt;
323  	*ptr++ = (NTPC_VERSION << 3) | NTPC_MODE;
324  	*ptr++ = op;
325  
326  	if (++seqno == 0)
327  		seqno++;
328  	*ptr++ = seqno >> 8;
329  	*ptr++ = seqno;
330  
331  	/* skip status */
332  	ptr += 2;
333  
334  	*ptr++ = associd >> 8;
335  	*ptr++ = associd;
336  
337  	/* skip offset */
338  	ptr += 2;
339  
340  	if (vars != NULL) {
341  		vlen = strlen(vars);
342  		if (vlen > NTPC_DMAX) {
343  			syslog(LOG_ERR, "NTP request too long (%zu)", vlen);
344  			free(rpkt);
345  			return (-1);
346  		}
347  		*ptr++ = vlen >> 8;
348  		*ptr++ = vlen;
349  
350  		memcpy(ptr, vars, vlen);
351  		ptr += vlen;
352  	} else
353  		/* skip data length (is already zero) */
354  		ptr += 2;
355  
356  	while ((ptr - rpkt) % 4 != 0)
357  		*ptr++ = 0;
358  
359  	if (ntp_debug & DBG_DUMP_PKTS) {
360  		syslog(LOG_INFO, "sending %zd bytes", ptr - rpkt);
361  		dump_packet(rpkt, ptr - rpkt);
362  	}
363  
364  	ret = send(ntpd_sock, rpkt, ptr - rpkt, 0);
365  	if (ret == -1) {
366  		syslog(LOG_ERR, "cannot send to ntpd: %m");
367  		free(rpkt);
368  		return (-1);
369  	}
370  	return (0);
371  }
372  
373  /*
374   * Callback if packet arrived from NTPD
375   */
376  static int
ntpd_read(uint16_t * op,uint16_t * associd,u_char ** data,size_t * datalen)377  ntpd_read(uint16_t *op, uint16_t *associd, u_char **data, size_t *datalen)
378  {
379  	u_char	pkt[NTPC_MAX + 1];
380  	u_char	*ptr, *nptr;
381  	u_int	n;
382  	ssize_t	ret;
383  	size_t	z;
384  	u_int	offset;		/* current offset */
385  	int	more;		/* more flag */
386  	int	sel;
387  	struct timeval inc, end, rem;
388  	fd_set	iset;
389  
390  	*datalen = 0;
391  	*data = NULL;
392  	offset = 0;
393  
394  	inc.tv_sec = ntp_timeout / 100;
395  	inc.tv_usec = (ntp_timeout % 100) * 1000;
396  
397  	(void)gettimeofday(&end, NULL);
398  	timeradd(&end, &inc, &end);
399  
400    next:
401  	/* compute remaining time */
402  	(void)gettimeofday(&rem, NULL);
403  	if (timercmp(&rem, &end, >=)) {
404  		/* do a poll */
405  		rem.tv_sec = 0;
406  		rem.tv_usec = 0;
407  	} else {
408  		timersub(&end, &rem, &rem);
409  	}
410  
411  	/* select */
412  	FD_ZERO(&iset);
413  	FD_SET(ntpd_sock, &iset);
414  	sel = select(ntpd_sock + 1, &iset, NULL, NULL, &rem);
415  	if (sel == -1) {
416  		if (errno == EINTR)
417  			goto next;
418  		syslog(LOG_ERR, "select ntpd_sock: %m");
419  		free(*data);
420  		return (-1);
421  	}
422  	if (sel == 0) {
423  		syslog(LOG_ERR, "timeout on NTP connection");
424  		free(*data);
425  		return (-1);
426  	}
427  
428  	/* now read it */
429  	ret = recv(ntpd_sock, pkt, sizeof(pkt), 0);
430  	if (ret == -1) {
431  		syslog(LOG_ERR, "error reading from ntpd: %m");
432  		free(*data);
433  		return (-1);
434  	}
435  
436  	if (ntp_debug & DBG_DUMP_PKTS) {
437  		syslog(LOG_INFO, "got %zd bytes", ret);
438  		dump_packet(pkt, (size_t)ret);
439  	}
440  
441  	ptr = pkt;
442  	if ((*ptr & 0x3f) != ((NTPC_VERSION << 3) | NTPC_MODE)) {
443  		syslog(LOG_ERR, "unexpected packet version 0x%x", *ptr);
444  		free(*data);
445  		return (-1);
446  	}
447  	ptr++;
448  
449  	if (!(*ptr & NTPC_BIT_RESP)) {
450  		syslog(LOG_ERR, "not a response packet");
451  		return (-1);
452  	}
453  	if (*ptr & NTPC_BIT_ERROR) {
454  		z = *datalen - 12;
455  		if (z > NTPC_DMAX)
456  			z = NTPC_DMAX;
457  		syslog(LOG_ERR, "error response: %.*s", (int)z, pkt + 12);
458  		free(*data);
459  		return (-1);
460  	}
461  	more = (*ptr & NTPC_BIT_MORE);
462  
463  	*op = *ptr++ & NTPC_OPMASK;
464  
465  	/* seqno */
466  	n = *ptr++ << 8;
467  	n |= *ptr++;
468  
469  	if (n != seqno) {
470  		syslog(LOG_ERR, "expecting seqno %u, got %u", seqno, n);
471  		free(*data);
472  		return (-1);
473  	}
474  
475  	/* status */
476  	n = *ptr++ << 8;
477  	n |= *ptr++;
478  
479  	/* associd */
480  	*associd = *ptr++ << 8;
481  	*associd |= *ptr++;
482  
483  	/* offset */
484  	n = *ptr++ << 8;
485  	n |= *ptr++;
486  
487  	if (n != offset) {
488  		syslog(LOG_ERR, "offset: expecting %u, got %u", offset, n);
489  		free(*data);
490  		return (-1);
491  	}
492  
493  	/* count */
494  	n = *ptr++ << 8;
495  	n |= *ptr++;
496  
497  	if ((size_t)ret < 12 + n) {
498  		syslog(LOG_ERR, "packet too short");
499  		return (-1);
500  	}
501  
502  	nptr = realloc(*data, *datalen + n);
503  	if (nptr == NULL) {
504  		syslog(LOG_ERR, "cannot allocate memory: %m");
505  		free(*data);
506  		return (-1);
507  	}
508  	*data = nptr;
509  
510  	memcpy(*data + offset, ptr, n);
511  	*datalen += n;
512  
513  	if (!more)
514  		return (0);
515  
516  	offset += n;
517  	goto next;
518  }
519  
520  /*
521   * Send a request and wait for the response
522   */
523  static int
ntpd_dialog(u_int op,u_int associd,const char * vars,u_char ** data,size_t * datalen)524  ntpd_dialog(u_int op, u_int associd, const char *vars, u_char **data,
525      size_t *datalen)
526  {
527  	uint16_t rassocid;
528  	uint16_t rop;
529  
530  	if (ntpd_request(op, associd, vars) == -1)
531  		return (-1);
532  	if (ntpd_read(&rop, &rassocid, data, datalen) == -1)
533  		return (-1);
534  
535  	if (rop != op) {
536  		syslog(LOG_ERR, "bad response op 0x%x", rop);
537  		free(data);
538  		return (-1);
539  	}
540  
541  	if (associd != rassocid) {
542  		syslog(LOG_ERR, "response for wrong associd");
543  		free(data);
544  		return (-1);
545  	}
546  	return (0);
547  }
548  
549  /*
550   * Callback if packet arrived from NTPD
551   */
552  static void
ntpd_input(int fd __unused,void * arg __unused)553  ntpd_input(int fd __unused, void *arg __unused)
554  {
555  	uint16_t associd;
556  	uint16_t op;
557  	u_char	*data;
558  	size_t	datalen;
559  
560  	if (ntpd_read(&op, &associd, &data, &datalen) == -1)
561  		return;
562  
563  	free(data);
564  }
565  
566  /*
567   * Find the value of a variable
568   */
569  static int
ntpd_parse(u_char ** data,size_t * datalen,char ** namep,char ** valp)570  ntpd_parse(u_char **data, size_t *datalen, char **namep, char **valp)
571  {
572  	u_char *ptr = *data;
573  	u_char *end = ptr + *datalen;
574  	char *ptr1;
575  	char endc;
576  
577  	/* skip leading spaces */
578  	while (ptr < end && isspace((int)*ptr))
579  		ptr++;
580  
581  	if (ptr == end)
582  		return (0);
583  
584  	*namep = ptr;
585  
586  	/* skip to space or '=' or ','*/
587  	while (ptr < end && !isspace((int)*ptr) && *ptr != '=' && *ptr != ',')
588  		ptr++;
589  	endc = *ptr;
590  	*ptr++ = '\0';
591  
592  	/* skip space */
593  	while (ptr < end && isspace((int)*ptr))
594  		ptr++;
595  
596  	if (ptr == end || endc == ',') {
597  		/* no value */
598  		*valp = NULL;
599  		*datalen -= ptr - *data;
600  		*data = ptr;
601  		return (1);
602  	}
603  
604  	if (*ptr == '"') {
605  		/* quoted */
606  		ptr++;
607  		*valp = ptr;
608  		while (ptr < end && *ptr != '"')
609  			ptr++;
610  		if (ptr == end)
611  			return (0);
612  
613  		*ptr++ = '\0';
614  
615  		/* find comma */
616  		while (ptr < end && isspace((int)*ptr) && *ptr == ',')
617  			ptr++;
618  	} else {
619  		*valp = ptr;
620  
621  		/* skip to end of value */
622  		while (ptr < end && *ptr != ',')
623  			ptr++;
624  
625  		/* remove trailing blanks */
626  		for (ptr1 = ptr; ptr1 > *valp; ptr1--)
627  			if (!isspace((int)ptr1[-1]))
628  				break;
629  		*ptr1 = '\0';
630  
631  		if (ptr < end)
632  			ptr++;
633  	}
634  
635  	*datalen -= ptr - *data;
636  	*data = ptr;
637  
638  	return (1);
639  }
640  
641  /*
642   * Parse an int32 value
643   */
644  static int
val_parse_int32(const char * val,int32_t * p,int32_t min,int32_t max,int base)645  val_parse_int32(const char *val, int32_t *p, int32_t min, int32_t max, int base)
646  {
647  	long n;
648  	char *end;
649  
650  	errno = 0;
651  	n = strtol(val, &end, base);
652  	if (errno != 0 || *end != '\0')
653  		return (0);
654  	if (n < min || n > max)
655  		return (0);
656  	*p = (int32_t)n;
657  	return (1);
658  }
659  
660  /*
661   * Parse an uint32 value
662   */
663  static int
val_parse_uint32(const char * val,uint32_t * p,uint32_t min,uint32_t max,int base)664  val_parse_uint32(const char *val, uint32_t *p, uint32_t min, uint32_t max,
665      int base)
666  {
667  	u_long n;
668  	char *end;
669  
670  	errno = 0;
671  	n = strtoul(val, &end, base);
672  	if (errno != 0 || *end != '\0')
673  		return (0);
674  	if (n < min || n > max)
675  		return (0);
676  	*p = (uint32_t)n;
677  	return (1);
678  }
679  
680  /*
681   * Parse a double
682   */
683  static int
val_parse_double(const char * val,double * p)684  val_parse_double(const char *val, double *p)
685  {
686  	char *end;
687  
688  	errno = 0;
689  	*p = strtod(val, &end);
690  	if (errno != 0 || *end != '\0')
691  		return (0);
692  	return (1);
693  }
694  
695  static int
val_parse_ts(const char * val,char * buf)696  val_parse_ts(const char *val, char *buf)
697  {
698  	int r, n;
699  	u_int i, f;
700  
701  	if (strlen(val) > 2 && val[0] == '0' && val[1] == 'x') {
702  		/* hex format */
703  		r = sscanf(val + 2, "%x.%x%n", &i, &f, &n);
704  		if (r != 2 || (size_t)n != strlen(val + 2))
705  			return (0);
706  	} else {
707  		/* probably decimal */
708  		r = sscanf(val, "%d.%d%n", &i, &f, &n);
709  		if (r != 2 || (size_t)n != strlen(val))
710  			return (0);
711  	}
712  	buf[0] = i >> 24;
713  	buf[1] = i >> 16;
714  	buf[2] = i >>  8;
715  	buf[3] = i >>  0;
716  	buf[4] = f >> 24;
717  	buf[5] = f >> 16;
718  	buf[6] = f >>  8;
719  	buf[7] = f >>  0;
720  	return (1);
721  }
722  
723  /*
724   * Parse an IP address. This resolves non-numeric names.
725   */
726  static int
val_parse_ip(const char * val,u_char ip[4])727  val_parse_ip(const char *val, u_char ip[4])
728  {
729  	int r, n, error;
730  	struct addrinfo hints, *res0;
731  	struct sockaddr_in *sin_local;
732  
733  	r = sscanf(val, "%hhd.%hhd.%hhd.%hhd%n",
734  	    &ip[0], &ip[1], &ip[2], &ip[3], &n);
735  	if (n == 4 && (size_t)n == strlen(val))
736  		return (0);
737  
738  	memset(ip, 0, 4);
739  
740  	memset(&hints, 0, sizeof(hints));
741  	hints.ai_family = AF_INET;
742  	hints.ai_socktype = SOCK_DGRAM;
743  
744  	error = getaddrinfo(val, NULL, &hints, &res0);
745  	if (error) {
746  		syslog(LOG_ERR, "%s: %s", val, gai_strerror(error));
747  		return (-1);
748  	}
749  	if (res0 == NULL) {
750  		syslog(LOG_ERR, "%s: no address", val);
751  		return (-1);
752  	}
753  
754  	sin_local = (struct sockaddr_in *)(void *)res0->ai_addr;
755  	ip[3] = sin_local->sin_addr.s_addr >> 24;
756  	ip[2] = sin_local->sin_addr.s_addr >> 16;
757  	ip[1] = sin_local->sin_addr.s_addr >>  8;
758  	ip[0] = sin_local->sin_addr.s_addr >>  0;
759  
760  	freeaddrinfo(res0);
761  	return (0);
762  }
763  
764  /*
765   * Fetch system info
766   */
767  static int
fetch_sysinfo(void)768  fetch_sysinfo(void)
769  {
770  	u_char *data;
771  	u_char *ptr;
772  	size_t datalen;
773  	char *name;
774  	char *val;
775  
776  	if (ntpd_dialog(NTPC_OP_READVAR, 0,
777  	    "leap,stratum,precision,rootdelay,rootdispersion,refid,reftime,"
778  	    "poll,peer,clock,system,processor,jitter,stability",
779  	    &data, &datalen))
780  		return (-1);
781  
782  	/* clear info */
783  	sysb_leap = 0;
784  	sysb_stratum = 0;
785  	sysb_precision = 0;
786  	free(sys_rootdelay);
787  	sys_rootdelay = NULL;
788  	free(sys_rootdispersion);
789  	sys_rootdispersion = NULL;
790  	free(sys_refid);
791  	sys_refid = NULL;
792  	sysb_reftime = 0;
793  	sysb_poll = 0;
794  	sysb_peer = 0;
795  	sysb_clock = 0;
796  	free(sys_system);
797  	sys_system = NULL;
798  	free(sys_processor);
799  	sys_processor = NULL;
800  	sysb_jitter = 0;
801  	sysb_stability = 0;
802  
803  	ptr = data;
804  	while (ntpd_parse(&ptr, &datalen, &name, &val)) {
805  		if (ntp_debug & DBG_DUMP_VARS)
806  			syslog(LOG_DEBUG, "%s: '%s'='%s'", __func__, name, val);
807  		if (strcmp(name, "leap") == 0 ||
808  		    strcmp(name, "sys.leap") == 0) {
809  			sysb_leap = val_parse_int32(val, &sys_leap,
810  			    0, 3, 2);
811  
812  		} else if (strcmp(name, "stratum") == 0 ||
813  		    strcmp(name, "sys.stratum") == 0) {
814  			sysb_stratum = val_parse_int32(val, &sys_stratum,
815  			    0, 255, 0);
816  
817  		} else if (strcmp(name, "precision") == 0 ||
818  		    strcmp(name, "sys.precision") == 0) {
819  			sysb_precision = val_parse_int32(val, &sys_precision,
820  			    INT32_MIN, INT32_MAX, 0);
821  
822  		} else if (strcmp(name, "rootdelay") == 0 ||
823  		    strcmp(name, "sys.rootdelay") == 0) {
824  			sys_rootdelay = strdup(val);
825  
826  		} else if (strcmp(name, "rootdispersion") == 0 ||
827  		    strcmp(name, "sys.rootdispersion") == 0) {
828  			sys_rootdispersion = strdup(val);
829  
830  		} else if (strcmp(name, "refid") == 0 ||
831  		    strcmp(name, "sys.refid") == 0) {
832  			sys_refid = strdup(val);
833  
834  		} else if (strcmp(name, "reftime") == 0 ||
835  		    strcmp(name, "sys.reftime") == 0) {
836  			sysb_reftime = val_parse_ts(val, sys_reftime);
837  
838  		} else if (strcmp(name, "poll") == 0 ||
839  		    strcmp(name, "sys.poll") == 0) {
840  			sysb_poll = val_parse_int32(val, &sys_poll,
841  			    INT32_MIN, INT32_MAX, 0);
842  
843  		} else if (strcmp(name, "peer") == 0 ||
844  		    strcmp(name, "sys.peer") == 0) {
845  			sysb_peer = val_parse_uint32(val, &sys_peer,
846  			    0, UINT32_MAX, 0);
847  
848  		} else if (strcmp(name, "clock") == 0 ||
849  		    strcmp(name, "sys.clock") == 0) {
850  			sysb_clock = val_parse_ts(val, sys_clock);
851  
852  		} else if (strcmp(name, "system") == 0 ||
853  		    strcmp(name, "sys.system") == 0) {
854  			sys_system = strdup(val);
855  
856  		} else if (strcmp(name, "processor") == 0 ||
857  		    strcmp(name, "sys.processor") == 0) {
858  			sys_processor = strdup(val);
859  
860  		} else if (strcmp(name, "jitter") == 0 ||
861  		    strcmp(name, "sys.jitter") == 0) {
862  			sysb_jitter = val_parse_double(val, &sys_jitter);
863  
864  		} else if (strcmp(name, "stability") == 0 ||
865  		    strcmp(name, "sys.stability") == 0) {
866  			sysb_stability = val_parse_double(val, &sys_stability);
867  		}
868  	}
869  
870  	free(data);
871  	return (0);
872  }
873  
874  static int
parse_filt(char * val,uint16_t associd,int which)875  parse_filt(char *val, uint16_t associd, int which)
876  {
877  	char *w;
878  	int cnt;
879  	struct filt *f;
880  
881  	cnt = 0;
882  	for (w = strtok(val, " \t"); w != NULL; w = strtok(NULL, " \t")) {
883  		TAILQ_FOREACH(f, &filts, link)
884  			if (f->index.subs[0] == associd &&
885  			    f->index.subs[1] == (asn_subid_t)(cnt + 1))
886  				break;
887  		if (f == NULL) {
888  			f = malloc(sizeof(*f));
889  			memset(f, 0, sizeof(*f));
890  			f->index.len = 2;
891  			f->index.subs[0] = associd;
892  			f->index.subs[1] = cnt + 1;
893  
894  			INSERT_OBJECT_OID(f, &filts);
895  		}
896  
897  		switch (which) {
898  
899  		  case 0:
900  			f->offset = strdup(w);
901  			break;
902  
903  		  case 1:
904  			f->delay = strdup(w);
905  			break;
906  
907  		  case 2:
908  			f->dispersion = strdup(w);
909  			break;
910  
911  		  default:
912  			abort();
913  		}
914  		cnt++;
915  	}
916  	return (cnt);
917  }
918  
919  /*
920   * Fetch the complete peer list
921   */
922  static int
fetch_peers(void)923  fetch_peers(void)
924  {
925  	u_char *data, *pdata, *ptr;
926  	size_t datalen, pdatalen;
927  	int i;
928  	struct peer *p;
929  	struct filt *f;
930  	uint16_t associd;
931  	char *name, *val;
932  
933  	/* free the old list */
934  	while ((p = TAILQ_FIRST(&peers)) != NULL) {
935  		TAILQ_REMOVE(&peers, p, link);
936  		free(p->rootdelay);
937  		free(p->rootdispersion);
938  		free(p->refid);
939  		free(p->offset);
940  		free(p->delay);
941  		free(p->dispersion);
942  		free(p);
943  	}
944  	while ((f = TAILQ_FIRST(&filts)) != NULL) {
945  		TAILQ_REMOVE(&filts, f, link);
946  		free(f->offset);
947  		free(f->delay);
948  		free(f->dispersion);
949  		free(f);
950  	}
951  
952  	/* fetch the list of associations */
953  	if (ntpd_dialog(NTPC_OP_READSTAT, 0, NULL, &data, &datalen))
954  		return (-1);
955  
956  	for (i = 0; i < (int)(datalen / 4); i++) {
957  		associd  = data[4 * i + 0] << 8;
958  		associd |= data[4 * i + 1] << 0;
959  
960  		/* ask for the association variables */
961  		if (ntpd_dialog(NTPC_OP_READVAR, associd,
962  		    "config,srcadr,srcport,dstadr,dstport,leap,hmode,stratum,"
963  		    "hpoll,ppoll,precision,rootdelay,rootdispersion,refid,"
964  		    "reftime,org,rec,xmt,reach,timer,offset,delay,dispersion,"
965  		    "filtdelay,filtoffset,filtdisp",
966  		    &pdata, &pdatalen)) {
967  			free(data);
968  			return (-1);
969  		}
970  
971  		/* now save and parse the data */
972  		p = malloc(sizeof(*p));
973  		if (p == NULL) {
974  			free(data);
975  			syslog(LOG_ERR, "%m");
976  			return (-1);
977  		}
978  		memset(p, 0, sizeof(*p));
979  		p->index = associd;
980  		INSERT_OBJECT_INT(p, &peers);
981  
982  		ptr = pdata;
983  		while (ntpd_parse(&ptr, &pdatalen, &name, &val)) {
984  			if (ntp_debug & DBG_DUMP_VARS)
985  				syslog(LOG_DEBUG, "%s: '%s'='%s'",
986  				    __func__, name, val);
987  			if (strcmp(name, "config") == 0 ||
988  			    strcmp(name, "peer.config") == 0) {
989  				val_parse_int32(val, &p->config, 0, 1, 0);
990  
991  			} else if (strcmp(name, "srcadr") == 0 ||
992  			    strcmp(name, "peer.srcadr") == 0) {
993  				val_parse_ip(val, p->srcadr);
994  
995  			} else if (strcmp(name, "srcport") == 0 ||
996  			    strcmp(name, "peer.srcport") == 0) {
997  				val_parse_uint32(val, &p->srcport,
998  				    1, 65535, 0);
999  
1000  			} else if (strcmp(name, "dstadr") == 0 ||
1001  			    strcmp(name, "peer.dstadr") == 0) {
1002  				val_parse_ip(val, p->dstadr);
1003  
1004  			} else if (strcmp(name, "dstport") == 0 ||
1005  			    strcmp(name, "peer.dstport") == 0) {
1006  				val_parse_uint32(val, &p->dstport,
1007  				    1, 65535, 0);
1008  
1009  			} else if (strcmp(name, "leap") == 0 ||
1010  			    strcmp(name, "peer.leap") == 0) {
1011  				val_parse_int32(val, &p->leap, 0, 3, 2);
1012  
1013  			} else if (strcmp(name, "hmode") == 0 ||
1014  			    strcmp(name, "peer.hmode") == 0) {
1015  				val_parse_int32(val, &p->hmode, 0, 7, 0);
1016  
1017  			} else if (strcmp(name, "stratum") == 0 ||
1018  			    strcmp(name, "peer.stratum") == 0) {
1019  				val_parse_int32(val, &p->stratum, 0, 255, 0);
1020  
1021  			} else if (strcmp(name, "ppoll") == 0 ||
1022  			    strcmp(name, "peer.ppoll") == 0) {
1023  				val_parse_int32(val, &p->ppoll,
1024  				    INT32_MIN, INT32_MAX, 0);
1025  
1026  			} else if (strcmp(name, "hpoll") == 0 ||
1027  			    strcmp(name, "peer.hpoll") == 0) {
1028  				val_parse_int32(val, &p->hpoll,
1029  				    INT32_MIN, INT32_MAX, 0);
1030  
1031  			} else if (strcmp(name, "precision") == 0 ||
1032  			    strcmp(name, "peer.precision") == 0) {
1033  				val_parse_int32(val, &p->hpoll,
1034  				    INT32_MIN, INT32_MAX, 0);
1035  
1036  			} else if (strcmp(name, "rootdelay") == 0 ||
1037  			    strcmp(name, "peer.rootdelay") == 0) {
1038  				p->rootdelay = strdup(val);
1039  
1040  			} else if (strcmp(name, "rootdispersion") == 0 ||
1041  			    strcmp(name, "peer.rootdispersion") == 0) {
1042  				p->rootdispersion = strdup(val);
1043  
1044  			} else if (strcmp(name, "refid") == 0 ||
1045  			    strcmp(name, "peer.refid") == 0) {
1046  				p->refid = strdup(val);
1047  
1048  			} else if (strcmp(name, "reftime") == 0 ||
1049  			    strcmp(name, "sys.reftime") == 0) {
1050  				val_parse_ts(val, p->reftime);
1051  
1052  			} else if (strcmp(name, "org") == 0 ||
1053  			    strcmp(name, "sys.org") == 0) {
1054  				val_parse_ts(val, p->orgtime);
1055  
1056  			} else if (strcmp(name, "rec") == 0 ||
1057  			    strcmp(name, "sys.rec") == 0) {
1058  				val_parse_ts(val, p->rcvtime);
1059  
1060  			} else if (strcmp(name, "xmt") == 0 ||
1061  			    strcmp(name, "sys.xmt") == 0) {
1062  				val_parse_ts(val, p->xmttime);
1063  
1064  			} else if (strcmp(name, "reach") == 0 ||
1065  			    strcmp(name, "peer.reach") == 0) {
1066  				val_parse_uint32(val, &p->reach,
1067  				    0, 65535, 0);
1068  
1069  			} else if (strcmp(name, "timer") == 0 ||
1070  			    strcmp(name, "peer.timer") == 0) {
1071  				val_parse_int32(val, &p->timer,
1072  				    INT32_MIN, INT32_MAX, 0);
1073  
1074  			} else if (strcmp(name, "offset") == 0 ||
1075  			    strcmp(name, "peer.offset") == 0) {
1076  				p->offset = strdup(val);
1077  
1078  			} else if (strcmp(name, "delay") == 0 ||
1079  			    strcmp(name, "peer.delay") == 0) {
1080  				p->delay = strdup(val);
1081  
1082  			} else if (strcmp(name, "dispersion") == 0 ||
1083  			    strcmp(name, "peer.dispersion") == 0) {
1084  				p->dispersion = strdup(val);
1085  
1086  			} else if (strcmp(name, "filtdelay") == 0 ||
1087  			    strcmp(name, "peer.filtdelay") == 0) {
1088  				p->filt_entries = parse_filt(val, associd, 0);
1089  
1090  			} else if (strcmp(name, "filtoffset") == 0 ||
1091  			    strcmp(name, "peer.filtoffset") == 0) {
1092  				p->filt_entries = parse_filt(val, associd, 1);
1093  
1094  			} else if (strcmp(name, "filtdisp") == 0 ||
1095  			    strcmp(name, "peer.filtdisp") == 0) {
1096  				p->filt_entries = parse_filt(val, associd, 2);
1097  			}
1098  		}
1099  		free(pdata);
1100  	}
1101  
1102  	free(data);
1103  	return (0);
1104  }
1105  
1106  /*
1107   * System variables - read-only scalars only.
1108   */
1109  int
op_ntpSystem(struct snmp_context * ctx __unused,struct snmp_value * value,u_int sub,u_int iidx __unused,enum snmp_op op)1110  op_ntpSystem(struct snmp_context *ctx __unused, struct snmp_value *value,
1111      u_int sub, u_int iidx __unused, enum snmp_op op)
1112  {
1113  	asn_subid_t which = value->var.subs[sub - 1];
1114  
1115  	switch (op) {
1116  
1117  	  case SNMP_OP_GETNEXT:
1118  		abort();
1119  
1120  	  case SNMP_OP_GET:
1121  		if (this_tick > sysinfo_tick) {
1122  			if (fetch_sysinfo() == -1)
1123  				return (SNMP_ERR_GENERR);
1124  			sysinfo_tick = this_tick;
1125  		}
1126  
1127  		switch (which) {
1128  
1129  		  case LEAF_ntpSysLeap:
1130  			if (!sysb_leap)
1131  				return (SNMP_ERR_NOSUCHNAME);
1132  			value->v.integer = sys_leap;
1133  			break;
1134  
1135  		  case LEAF_ntpSysStratum:
1136  			if (!sysb_stratum)
1137  				return (SNMP_ERR_NOSUCHNAME);
1138  			value->v.integer = sys_stratum;
1139  			break;
1140  
1141  		  case LEAF_ntpSysPrecision:
1142  			if (!sysb_precision)
1143  				return (SNMP_ERR_NOSUCHNAME);
1144  			value->v.integer = sys_precision;
1145  			break;
1146  
1147  		  case LEAF_ntpSysRootDelay:
1148  			if (sys_rootdelay == NULL)
1149  				return (SNMP_ERR_NOSUCHNAME);
1150  			return (string_get(value, sys_rootdelay, -1));
1151  
1152  		  case LEAF_ntpSysRootDispersion:
1153  			if (sys_rootdispersion == NULL)
1154  				return (SNMP_ERR_NOSUCHNAME);
1155  			return (string_get(value, sys_rootdispersion, -1));
1156  
1157  		  case LEAF_ntpSysRefId:
1158  			if (sys_refid == NULL)
1159  				return (SNMP_ERR_NOSUCHNAME);
1160  			return (string_get(value, sys_refid, -1));
1161  
1162  		  case LEAF_ntpSysRefTime:
1163  			if (sysb_reftime == 0)
1164  				return (SNMP_ERR_NOSUCHNAME);
1165  			return (string_get(value, sys_reftime, 8));
1166  
1167  		  case LEAF_ntpSysPoll:
1168  			if (sysb_poll == 0)
1169  				return (SNMP_ERR_NOSUCHNAME);
1170  			value->v.integer = sys_poll;
1171  			break;
1172  
1173  		  case LEAF_ntpSysPeer:
1174  			if (sysb_peer == 0)
1175  				return (SNMP_ERR_NOSUCHNAME);
1176  			value->v.uint32 = sys_peer;
1177  			break;
1178  
1179  		  case LEAF_ntpSysClock:
1180  			if (sysb_clock == 0)
1181  				return (SNMP_ERR_NOSUCHNAME);
1182  			return (string_get(value, sys_clock, 8));
1183  
1184  		  case LEAF_ntpSysSystem:
1185  			if (sys_system == NULL)
1186  				return (SNMP_ERR_NOSUCHNAME);
1187  			return (string_get(value, sys_system, -1));
1188  
1189  		  case LEAF_ntpSysProcessor:
1190  			if (sys_processor == NULL)
1191  				return (SNMP_ERR_NOSUCHNAME);
1192  			return (string_get(value, sys_processor, -1));
1193  
1194  		  default:
1195  			abort();
1196  		}
1197  		return (SNMP_ERR_NOERROR);
1198  
1199  	  case SNMP_OP_SET:
1200  		return (SNMP_ERR_NOT_WRITEABLE);
1201  
1202  	  case SNMP_OP_COMMIT:
1203  	  case SNMP_OP_ROLLBACK:
1204  		abort();
1205  	}
1206  	abort();
1207  }
1208  
1209  int
op_ntpPeersVarTable(struct snmp_context * ctx __unused,struct snmp_value * value,u_int sub,u_int iidx,enum snmp_op op)1210  op_ntpPeersVarTable(struct snmp_context *ctx __unused, struct snmp_value *value,
1211      u_int sub, u_int iidx, enum snmp_op op)
1212  {
1213  	asn_subid_t which = value->var.subs[sub - 1];
1214  	uint32_t peer;
1215  	struct peer *t;
1216  
1217  	if (this_tick > peers_tick) {
1218  		if (fetch_peers() == -1)
1219  			return (SNMP_ERR_GENERR);
1220  		peers_tick = this_tick;
1221  	}
1222  
1223  	switch (op) {
1224  
1225  	  case SNMP_OP_GETNEXT:
1226  		t = NEXT_OBJECT_INT(&peers, &value->var, sub);
1227  		if (t == NULL)
1228  			return (SNMP_ERR_NOSUCHNAME);
1229  		value->var.len = sub + 1;
1230  		value->var.subs[sub] = t->index;
1231  		break;
1232  
1233  	  case SNMP_OP_GET:
1234  		t = FIND_OBJECT_INT(&peers, &value->var, sub);
1235  		if (t == NULL)
1236  			return (SNMP_ERR_NOSUCHNAME);
1237  		break;
1238  
1239  	  case SNMP_OP_SET:
1240  		if (index_decode(&value->var, sub, iidx, &peer))
1241  			return (SNMP_ERR_NO_CREATION);
1242  		t = FIND_OBJECT_INT(&peers, &value->var, sub);
1243  		if (t != NULL)
1244  			return (SNMP_ERR_NOT_WRITEABLE);
1245  		return (SNMP_ERR_NO_CREATION);
1246  
1247  	  case SNMP_OP_COMMIT:
1248  	  case SNMP_OP_ROLLBACK:
1249  	  default:
1250  		abort();
1251  	}
1252  
1253  	/*
1254  	 * Come here for GET and COMMIT
1255  	 */
1256  	switch (which) {
1257  
1258  	  case LEAF_ntpPeersConfigured:
1259  		value->v.integer = t->config;
1260  		break;
1261  
1262  	  case LEAF_ntpPeersPeerAddress:
1263  		return (ip_get(value, t->srcadr));
1264  
1265  	  case LEAF_ntpPeersPeerPort:
1266  		value->v.uint32 = t->srcport;
1267  		break;
1268  
1269  	  case LEAF_ntpPeersHostAddress:
1270  		return (ip_get(value, t->dstadr));
1271  
1272  	  case LEAF_ntpPeersHostPort:
1273  		value->v.uint32 = t->dstport;
1274  		break;
1275  
1276  	  case LEAF_ntpPeersLeap:
1277  		value->v.integer = t->leap;
1278  		break;
1279  
1280  	  case LEAF_ntpPeersMode:
1281  		value->v.integer = t->hmode;
1282  		break;
1283  
1284  	  case LEAF_ntpPeersStratum:
1285  		value->v.integer = t->stratum;
1286  		break;
1287  
1288  	  case LEAF_ntpPeersPeerPoll:
1289  		value->v.integer = t->ppoll;
1290  		break;
1291  
1292  	  case LEAF_ntpPeersHostPoll:
1293  		value->v.integer = t->hpoll;
1294  		break;
1295  
1296  	  case LEAF_ntpPeersPrecision:
1297  		value->v.integer = t->precision;
1298  		break;
1299  
1300  	  case LEAF_ntpPeersRootDelay:
1301  		return (string_get(value, t->rootdelay, -1));
1302  
1303  	  case LEAF_ntpPeersRootDispersion:
1304  		return (string_get(value, t->rootdispersion, -1));
1305  
1306  	  case LEAF_ntpPeersRefId:
1307  		return (string_get(value, t->refid, -1));
1308  
1309  	  case LEAF_ntpPeersRefTime:
1310  		return (string_get(value, t->reftime, 8));
1311  
1312  	  case LEAF_ntpPeersOrgTime:
1313  		return (string_get(value, t->orgtime, 8));
1314  
1315  	  case LEAF_ntpPeersReceiveTime:
1316  		return (string_get(value, t->rcvtime, 8));
1317  
1318  	  case LEAF_ntpPeersTransmitTime:
1319  		return (string_get(value, t->xmttime, 8));
1320  
1321  	  case LEAF_ntpPeersReach:
1322  		value->v.uint32 = t->reach;
1323  		break;
1324  
1325  	  case LEAF_ntpPeersTimer:
1326  		value->v.uint32 = t->timer;
1327  		break;
1328  
1329  	  case LEAF_ntpPeersOffset:
1330  		return (string_get(value, t->offset, -1));
1331  
1332  	  case LEAF_ntpPeersDelay:
1333  		return (string_get(value, t->delay, -1));
1334  
1335  	  case LEAF_ntpPeersDispersion:
1336  		return (string_get(value, t->dispersion, -1));
1337  
1338  	  default:
1339  		abort();
1340  	}
1341  	return (SNMP_ERR_NOERROR);
1342  }
1343  
1344  
1345  int
op_ntpFilterPeersVarTable(struct snmp_context * ctx __unused,struct snmp_value * value,u_int sub,u_int iidx,enum snmp_op op)1346  op_ntpFilterPeersVarTable(struct snmp_context *ctx __unused,
1347      struct snmp_value *value, u_int sub, u_int iidx, enum snmp_op op)
1348  {
1349  	asn_subid_t which = value->var.subs[sub - 1];
1350  	uint32_t peer;
1351  	struct peer *t;
1352  
1353  	if (this_tick > peers_tick) {
1354  		if (fetch_peers() == -1)
1355  			return (SNMP_ERR_GENERR);
1356  		peers_tick = this_tick;
1357  	}
1358  
1359  	switch (op) {
1360  
1361  	  case SNMP_OP_GETNEXT:
1362  		t = NEXT_OBJECT_INT(&peers, &value->var, sub);
1363  		if (t == NULL)
1364  			return (SNMP_ERR_NOSUCHNAME);
1365  		value->var.len = sub + 1;
1366  		value->var.subs[sub] = t->index;
1367  		break;
1368  
1369  	  case SNMP_OP_GET:
1370  		t = FIND_OBJECT_INT(&peers, &value->var, sub);
1371  		if (t == NULL)
1372  			return (SNMP_ERR_NOSUCHNAME);
1373  		break;
1374  
1375  	  case SNMP_OP_SET:
1376  		if (index_decode(&value->var, sub, iidx, &peer))
1377  			return (SNMP_ERR_NO_CREATION);
1378  		t = FIND_OBJECT_INT(&peers, &value->var, sub);
1379  		if (t != NULL)
1380  			return (SNMP_ERR_NOT_WRITEABLE);
1381  		return (SNMP_ERR_NO_CREATION);
1382  
1383  	  case SNMP_OP_COMMIT:
1384  	  case SNMP_OP_ROLLBACK:
1385  	  default:
1386  		abort();
1387  	}
1388  
1389  	/*
1390  	 * Come here for GET and COMMIT
1391  	 */
1392  	switch (which) {
1393  
1394  	  case LEAF_ntpFilterValidEntries:
1395  		value->v.integer = t->filt_entries;
1396  		break;
1397  
1398  	  default:
1399  		abort();
1400  	}
1401  	return (SNMP_ERR_NOERROR);
1402  }
1403  
1404  int
op_ntpFilterRegisterTable(struct snmp_context * ctx __unused,struct snmp_value * value __unused,u_int sub __unused,u_int iidx __unused,enum snmp_op op __unused)1405  op_ntpFilterRegisterTable(struct snmp_context *ctx __unused, struct snmp_value *value __unused,
1406      u_int sub __unused, u_int iidx __unused, enum snmp_op op __unused)
1407  {
1408  	asn_subid_t which = value->var.subs[sub - 1];
1409  	uint32_t peer;
1410  	uint32_t filt;
1411  	struct filt *t;
1412  
1413  	if (this_tick > peers_tick) {
1414  		if (fetch_peers() == -1)
1415  			return (SNMP_ERR_GENERR);
1416  		peers_tick = this_tick;
1417  	}
1418  
1419  	switch (op) {
1420  
1421  	  case SNMP_OP_GETNEXT:
1422  		t = NEXT_OBJECT_OID(&filts, &value->var, sub);
1423  		if (t == NULL)
1424  			return (SNMP_ERR_NOSUCHNAME);
1425  		index_append(&value->var, sub, &t->index);
1426  		break;
1427  
1428  	  case SNMP_OP_GET:
1429  		t = FIND_OBJECT_OID(&filts, &value->var, sub);
1430  		if (t == NULL)
1431  			return (SNMP_ERR_NOSUCHNAME);
1432  		break;
1433  
1434  	  case SNMP_OP_SET:
1435  		if (index_decode(&value->var, sub, iidx, &peer, &filt))
1436  			return (SNMP_ERR_NO_CREATION);
1437  		t = FIND_OBJECT_OID(&filts, &value->var, sub);
1438  		if (t != NULL)
1439  			return (SNMP_ERR_NOT_WRITEABLE);
1440  		return (SNMP_ERR_NO_CREATION);
1441  
1442  	  case SNMP_OP_COMMIT:
1443  	  case SNMP_OP_ROLLBACK:
1444  	  default:
1445  		abort();
1446  	}
1447  
1448  	/*
1449  	 * Come here for GET and COMMIT
1450  	 */
1451  	switch (which) {
1452  
1453  	  case LEAF_ntpFilterPeersOffset:
1454  		return (string_get(value, t->offset, -1));
1455  
1456  	  case LEAF_ntpFilterPeersDelay:
1457  		return (string_get(value, t->delay, -1));
1458  
1459  	  case LEAF_ntpFilterPeersDispersion:
1460  		return (string_get(value, t->dispersion, -1));
1461  
1462  	  default:
1463  		abort();
1464  	}
1465  	return (SNMP_ERR_NOERROR);
1466  }
1467  
1468  /*
1469   * System variables - read-only scalars only.
1470   */
1471  int
op_begemot_ntp(struct snmp_context * ctx __unused,struct snmp_value * value,u_int sub,u_int iidx __unused,enum snmp_op op)1472  op_begemot_ntp(struct snmp_context *ctx __unused, struct snmp_value *value,
1473      u_int sub, u_int iidx __unused, enum snmp_op op)
1474  {
1475  	asn_subid_t which = value->var.subs[sub - 1];
1476  	int ret;
1477  
1478  	switch (op) {
1479  
1480  	  case SNMP_OP_GETNEXT:
1481  		abort();
1482  
1483  	  case SNMP_OP_GET:
1484  		switch (which) {
1485  
1486  		  case LEAF_begemotNtpHost:
1487  			return (string_get(value, ntp_host, -1));
1488  
1489  		  case LEAF_begemotNtpPort:
1490  			return (string_get(value, ntp_port, -1));
1491  
1492  		  case LEAF_begemotNtpTimeout:
1493  			value->v.uint32 = ntp_timeout;
1494  			return (SNMP_ERR_NOERROR);
1495  
1496  		  case LEAF_begemotNtpDebug:
1497  			value->v.uint32 = ntp_debug;
1498  			return (SNMP_ERR_NOERROR);
1499  
1500  		  case LEAF_begemotNtpJitter:
1501  			if (this_tick > sysinfo_tick) {
1502  				if (fetch_sysinfo() == -1)
1503  					return (SNMP_ERR_GENERR);
1504  				sysinfo_tick = this_tick;
1505  			}
1506  			if (!sysb_jitter)
1507  				return (SNMP_ERR_NOSUCHNAME);
1508  			value->v.counter64 = sys_jitter / 1000 * (1ULL << 32);
1509  			return (SNMP_ERR_NOERROR);
1510  
1511  		  case LEAF_begemotNtpStability:
1512  			if (this_tick > sysinfo_tick) {
1513  				if (fetch_sysinfo() == -1)
1514  					return (SNMP_ERR_GENERR);
1515  				sysinfo_tick = this_tick;
1516  			}
1517  			if (!sysb_stability)
1518  				return (SNMP_ERR_NOSUCHNAME);
1519  			value->v.counter64 = sys_stability * (1ULL << 32);
1520  			return (SNMP_ERR_NOERROR);
1521  		}
1522  		abort();
1523  
1524  	  case SNMP_OP_SET:
1525  		switch (which) {
1526  
1527  		  case LEAF_begemotNtpHost:
1528  			/* only at initialization */
1529  			if (community != COMM_INITIALIZE)
1530  				return (SNMP_ERR_NOT_WRITEABLE);
1531  
1532  			if ((ret = string_save(value, ctx, -1, &ntp_host))
1533  			    != SNMP_ERR_NOERROR)
1534  				return (ret);
1535  			return (SNMP_ERR_NOERROR);
1536  
1537  		  case LEAF_begemotNtpPort:
1538  			/* only at initialization */
1539  			if (community != COMM_INITIALIZE)
1540  				return (SNMP_ERR_NOT_WRITEABLE);
1541  
1542  			if ((ret = string_save(value, ctx, -1, &ntp_port))
1543  			    != SNMP_ERR_NOERROR)
1544  				return (ret);
1545  			return (SNMP_ERR_NOERROR);
1546  
1547  		  case LEAF_begemotNtpTimeout:
1548  			ctx->scratch->int1 = ntp_timeout;
1549  			if (value->v.uint32 < 1)
1550  				return (SNMP_ERR_WRONG_VALUE);
1551  			ntp_timeout = value->v.integer;
1552  			return (SNMP_ERR_NOERROR);
1553  
1554  		  case LEAF_begemotNtpDebug:
1555  			ctx->scratch->int1 = ntp_debug;
1556  			ntp_debug = value->v.integer;
1557  			return (SNMP_ERR_NOERROR);
1558  		}
1559  		abort();
1560  
1561  	  case SNMP_OP_ROLLBACK:
1562  		switch (which) {
1563  
1564  		  case LEAF_begemotNtpHost:
1565  			string_rollback(ctx, &ntp_host);
1566  			return (SNMP_ERR_NOERROR);
1567  
1568  		  case LEAF_begemotNtpPort:
1569  			string_rollback(ctx, &ntp_port);
1570  			return (SNMP_ERR_NOERROR);
1571  
1572  		  case LEAF_begemotNtpTimeout:
1573  			ntp_timeout = ctx->scratch->int1;
1574  			return (SNMP_ERR_NOERROR);
1575  
1576  		  case LEAF_begemotNtpDebug:
1577  			ntp_debug = ctx->scratch->int1;
1578  			return (SNMP_ERR_NOERROR);
1579  		}
1580  		abort();
1581  
1582  	  case SNMP_OP_COMMIT:
1583  		switch (which) {
1584  
1585  		  case LEAF_begemotNtpHost:
1586  			string_commit(ctx);
1587  			return (SNMP_ERR_NOERROR);
1588  
1589  		  case LEAF_begemotNtpPort:
1590  			string_commit(ctx);
1591  			return (SNMP_ERR_NOERROR);
1592  
1593  		  case LEAF_begemotNtpTimeout:
1594  		  case LEAF_begemotNtpDebug:
1595  			return (SNMP_ERR_NOERROR);
1596  		}
1597  		abort();
1598  	}
1599  	abort();
1600  }
1601