1145557Sharti/* 2145557Sharti * Copyright (c) 2005 3145557Sharti * Hartmut Brandt. 4145557Sharti * All rights reserved. 5145557Sharti * 6145557Sharti * Author: Harti Brandt <harti@freebsd.org> 7145557Sharti * 8145557Sharti * Redistribution of this software and documentation and use in source and 9145557Sharti * binary forms, with or without modification, are permitted provided that 10145557Sharti * the following conditions are met: 11145557Sharti * 12145557Sharti * 1. Redistributions of source code or documentation must retain the above 13145557Sharti * copyright notice, this list of conditions and the following disclaimer. 14145557Sharti * 2. Redistributions in binary form must reproduce the above copyright 15145557Sharti * notice, this list of conditions and the following disclaimer in the 16145557Sharti * documentation and/or other materials provided with the distribution. 17145557Sharti * 18145557Sharti * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS 19145557Sharti * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 20145557Sharti * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21145557Sharti * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22145557Sharti * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23145557Sharti * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24145557Sharti * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 25145557Sharti * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26145557Sharti * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27145557Sharti * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 28145557Sharti * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29145557Sharti * 30156066Sharti * $Begemot: bsnmp/snmp_ntp/snmp_ntp.c,v 1.9 2005/10/06 07:15:01 brandt_h Exp $ 31145557Sharti * 32145557Sharti * NTP interface for SNMPd. 33145557Sharti */ 34145557Sharti 35145557Sharti#include <sys/queue.h> 36145557Sharti#include <sys/time.h> 37145557Sharti#include <sys/types.h> 38145557Sharti#include <sys/select.h> 39145557Sharti#include <sys/socket.h> 40145557Sharti#include <ctype.h> 41145557Sharti#include <errno.h> 42145557Sharti#include <netdb.h> 43150920Sharti#ifdef HAVE_STDINT_H 44145557Sharti#include <stdint.h> 45150920Sharti#elif defined(HAVE_INTTYPES_H) 46150920Sharti#include <inttypes.h> 47150920Sharti#endif 48145557Sharti#include <stdio.h> 49145557Sharti#include <stdlib.h> 50145557Sharti#include <string.h> 51145557Sharti#include <syslog.h> 52145557Sharti#include <unistd.h> 53145557Sharti 54156066Sharti#include "support.h" 55145557Sharti#include "snmpmod.h" 56145557Sharti#include "ntp_tree.h" 57145557Sharti#include "ntp_oid.h" 58145557Sharti 59145557Sharti#define NTPC_MAX 576 60145557Sharti#define NTPC_VERSION 3 61145557Sharti#define NTPC_MODE 6 62145557Sharti#define NTPC_DMAX 468 63145557Sharti 64145557Sharti#define NTPC_BIT_RESP 0x80 65145557Sharti#define NTPC_BIT_ERROR 0x40 66145557Sharti#define NTPC_BIT_MORE 0x20 67145557Sharti 68145557Sharti#define NTPC_OPMASK 0x1f 69145557Sharti#define NTPC_OP_READSTAT 1 70145557Sharti#define NTPC_OP_READVAR 2 71145557Sharti 72145557Sharti/* our module handle */ 73145557Shartistatic struct lmodule *module; 74145557Sharti 75145557Sharti/* debug flag */ 76145557Shartistatic uint32_t ntp_debug; 77145557Sharti#define DBG_DUMP_PKTS 0x01 78145557Sharti#define DBG_DUMP_VARS 0x02 79145557Sharti 80145557Sharti/* OIDs */ 81145557Shartistatic const struct asn_oid oid_ntpMIB = OIDX_ntpMIB; 82145557Sharti 83145557Sharti/* the Object Resource registration index */ 84145557Shartistatic u_int reg_index; 85145557Sharti 86145557Sharti/* last time we've fetch the system variables */ 87146525Shartistatic uint64_t sysinfo_tick; 88145557Sharti 89145557Sharti/* cached system variables */ 90145557Shartistatic int32_t sys_leap; 91145557Shartistatic int sysb_leap; 92145557Shartistatic int32_t sys_stratum; 93145557Shartistatic int sysb_stratum; 94145557Shartistatic int32_t sys_precision; 95145557Shartistatic int sysb_precision; 96145557Shartistatic char *sys_rootdelay; 97145557Shartistatic char *sys_rootdispersion; 98145557Shartistatic char *sys_refid; 99145557Shartistatic char sys_reftime[8]; 100145557Shartistatic int sysb_reftime; 101145557Shartistatic int32_t sys_poll; 102145557Shartistatic int sysb_poll; 103145557Shartistatic uint32_t sys_peer; 104145557Shartistatic int sysb_peer; 105145557Shartistatic u_char sys_clock[8]; 106145557Shartistatic int sysb_clock; 107145557Shartistatic char *sys_system; 108145557Shartistatic char *sys_processor; 109145557Shartistatic int sysb_jitter; 110145557Shartistatic double sys_jitter; 111145557Shartistatic int sysb_stability; 112145557Shartistatic double sys_stability; 113145557Sharti 114145557Sharti/* last time we've fetch the peer list */ 115146525Shartistatic uint64_t peers_tick; 116145557Sharti 117145557Sharti/* request sequence number generator */ 118145557Shartistatic uint16_t seqno; 119145557Sharti 120145557Sharti/* NTPD socket */ 121145557Shartistatic int ntpd_sock; 122145557Shartistatic void *ntpd_fd; 123145557Sharti 124145557Shartistruct peer { 125145557Sharti /* required entries for macros */ 126145557Sharti uint32_t index; 127145557Sharti TAILQ_ENTRY(peer) link; 128145557Sharti 129145557Sharti int32_t config; /* config bit */ 130145557Sharti u_char srcadr[4]; /* PeerAddress */ 131145557Sharti uint32_t srcport; /* PeerPort */ 132145557Sharti u_char dstadr[4]; /* HostAddress */ 133145557Sharti uint32_t dstport; /* HostPort */ 134145557Sharti int32_t leap; /* Leap */ 135145557Sharti int32_t hmode; /* Mode */ 136145557Sharti int32_t stratum; /* Stratum */ 137145557Sharti int32_t ppoll; /* PeerPoll */ 138145557Sharti int32_t hpoll; /* HostPoll */ 139145557Sharti int32_t precision; /* Precision */ 140145557Sharti char *rootdelay; /* RootDelay */ 141145557Sharti char *rootdispersion;/* RootDispersion */ 142145557Sharti char *refid; /* RefId */ 143145557Sharti u_char reftime[8]; /* RefTime */ 144145557Sharti u_char orgtime[8]; /* OrgTime */ 145145557Sharti u_char rcvtime[8]; /* ReceiveTime */ 146145557Sharti u_char xmttime[8]; /* TransmitTime */ 147145557Sharti u_int32_t reach; /* Reach */ 148145557Sharti int32_t timer; /* Timer */ 149145557Sharti char *offset; /* Offset */ 150145557Sharti char *delay; /* Delay */ 151145557Sharti char *dispersion; /* Dispersion */ 152145557Sharti int32_t filt_entries; 153145557Sharti}; 154145557ShartiTAILQ_HEAD(peer_list, peer); 155145557Sharti 156145557Sharti/* list of peers */ 157145557Shartistatic struct peer_list peers = TAILQ_HEAD_INITIALIZER(peers); 158145557Sharti 159145557Shartistruct filt { 160145557Sharti /* required fields */ 161145557Sharti struct asn_oid index; 162145557Sharti TAILQ_ENTRY(filt) link; 163145557Sharti 164145557Sharti char *offset; 165145557Sharti char *delay; 166145557Sharti char *dispersion; 167145557Sharti}; 168145557ShartiTAILQ_HEAD(filt_list, filt); 169145557Sharti 170145557Sharti/* list of filters */ 171145557Shartistatic struct filt_list filts = TAILQ_HEAD_INITIALIZER(filts); 172145557Sharti 173145557Sharti/* configuration */ 174145557Shartistatic u_char *ntp_host; 175145557Shartistatic u_char *ntp_port; 176145557Shartistatic uint32_t ntp_timeout; 177145557Sharti 178145557Shartistatic void ntpd_input(int, void *); 179145557Shartistatic int open_socket(void); 180145557Sharti 181150920Sharti/* the initialization function */ 182145557Shartistatic int 183145557Shartintp_init(struct lmodule *mod, int argc, char *argv[] __unused) 184145557Sharti{ 185145557Sharti 186145557Sharti module = mod; 187145557Sharti 188145557Sharti if (argc != 0) { 189145557Sharti syslog(LOG_ERR, "bad number of arguments for %s", __func__); 190145557Sharti return (EINVAL); 191145557Sharti } 192145557Sharti 193145557Sharti ntp_host = strdup("localhost"); 194145557Sharti ntp_port = strdup("ntp"); 195145557Sharti ntp_timeout = 50; /* 0.5sec */ 196145557Sharti 197145557Sharti return (0); 198145557Sharti} 199145557Sharti 200145557Sharti/* 201145557Sharti * Module is started 202145557Sharti */ 203145557Shartistatic void 204145557Shartintp_start(void) 205145557Sharti{ 206145557Sharti 207145557Sharti if (open_socket() != -1) { 208145557Sharti ntpd_fd = fd_select(ntpd_sock, ntpd_input, NULL, module); 209145557Sharti if (ntpd_fd == NULL) { 210145557Sharti syslog(LOG_ERR, "fd_select failed on ntpd socket: %m"); 211145557Sharti return; 212145557Sharti } 213145557Sharti } 214145557Sharti reg_index = or_register(&oid_ntpMIB, "The MIB for NTP.", module); 215145557Sharti} 216145557Sharti 217145557Sharti/* 218145557Sharti * Called, when the module is to be unloaded after it was successfully loaded 219145557Sharti */ 220145557Shartistatic int 221145557Shartintp_fini(void) 222145557Sharti{ 223145557Sharti 224145557Sharti or_unregister(reg_index); 225145557Sharti fd_deselect(ntpd_fd); 226145557Sharti 227145557Sharti return (0); 228145557Sharti} 229145557Sharti 230145557Sharticonst struct snmp_module config = { 231145557Sharti .comment = "This module implements the NTP MIB", 232145557Sharti .init = ntp_init, 233145557Sharti .start = ntp_start, 234145557Sharti .fini = ntp_fini, 235145557Sharti .tree = ntp_ctree, 236145557Sharti .tree_size = ntp_CTREE_SIZE, 237145557Sharti}; 238145557Sharti 239145557Sharti/* 240145557Sharti * Open the NTPD socket 241145557Sharti */ 242145557Shartistatic int 243145557Shartiopen_socket(void) 244145557Sharti{ 245145557Sharti struct addrinfo hints, *res, *res0; 246145557Sharti int error; 247145557Sharti const char *cause; 248145557Sharti 249145557Sharti memset(&hints, 0, sizeof(hints)); 250145557Sharti hints.ai_family = AF_INET; 251145557Sharti hints.ai_socktype = SOCK_DGRAM; 252145557Sharti 253145557Sharti error = getaddrinfo(ntp_host, ntp_port, &hints, &res0); 254145557Sharti if (error) { 255145557Sharti syslog(LOG_ERR, "%s(%s): %s", ntp_host, ntp_port, 256145557Sharti gai_strerror(error)); 257145557Sharti return (-1); 258145557Sharti } 259145557Sharti 260145557Sharti ntpd_sock = -1; 261145557Sharti cause = "no address"; 262145557Sharti errno = EADDRNOTAVAIL; 263145557Sharti for (res = res0; res != NULL; res = res->ai_next) { 264145557Sharti ntpd_sock = socket(res->ai_family, res->ai_socktype, 265145557Sharti res->ai_protocol); 266145557Sharti if (ntpd_sock == -1) { 267145557Sharti cause = "socket"; 268145557Sharti continue; 269145557Sharti } 270145557Sharti if (connect(ntpd_sock, res->ai_addr, res->ai_addrlen) == -1) { 271145557Sharti cause = "connect"; 272145557Sharti (void)close(ntpd_sock); 273145557Sharti ntpd_sock = -1; 274145557Sharti continue; 275145557Sharti } 276145557Sharti break; 277145557Sharti } 278145557Sharti if (ntpd_sock == -1) { 279145557Sharti syslog(LOG_ERR, "%s: %m", cause); 280145557Sharti return (-1); 281145557Sharti } 282145557Sharti freeaddrinfo(res0); 283145557Sharti return (0); 284145557Sharti} 285145557Sharti 286145557Sharti/* 287145557Sharti * Dump a packet 288145557Sharti */ 289145557Shartistatic void 290145557Shartidump_packet(const u_char *pkt, size_t ret) 291145557Sharti{ 292145557Sharti char buf[8 * 3 + 1]; 293145557Sharti size_t i, j; 294145557Sharti 295145557Sharti for (i = 0; i < ret; i += 8) { 296145557Sharti buf[0] = '\0'; 297145557Sharti for (j = 0; i + j < (size_t)ret && j < 8; j++) 298145557Sharti sprintf(buf + strlen(buf), " %02x", pkt[i + j]); 299145557Sharti syslog(LOG_INFO, "%04zu:%s", i, buf); 300145557Sharti } 301145557Sharti} 302145557Sharti 303145557Sharti/* 304145557Sharti * Execute an NTP request. 305145557Sharti */ 306145557Shartistatic int 307145557Shartintpd_request(u_int op, u_int associd, const char *vars) 308145557Sharti{ 309145557Sharti u_char *rpkt; 310145557Sharti u_char *ptr; 311145557Sharti size_t vlen; 312145557Sharti ssize_t ret; 313145557Sharti 314145557Sharti if ((rpkt = malloc(NTPC_MAX)) == NULL) { 315145557Sharti syslog(LOG_ERR, "%m"); 316145557Sharti return (-1); 317145557Sharti } 318145557Sharti memset(rpkt, 0, NTPC_MAX); 319145557Sharti 320145557Sharti ptr = rpkt; 321145557Sharti *ptr++ = (NTPC_VERSION << 3) | NTPC_MODE; 322145557Sharti *ptr++ = op; 323145557Sharti 324145557Sharti if (++seqno == 0) 325145557Sharti seqno++; 326145557Sharti *ptr++ = seqno >> 8; 327145557Sharti *ptr++ = seqno; 328145557Sharti 329145557Sharti /* skip status */ 330145557Sharti ptr += 2; 331145557Sharti 332145557Sharti *ptr++ = associd >> 8; 333145557Sharti *ptr++ = associd; 334145557Sharti 335145557Sharti /* skip offset */ 336145557Sharti ptr += 2; 337145557Sharti 338145557Sharti if (vars != NULL) { 339145557Sharti vlen = strlen(vars); 340145557Sharti if (vlen > NTPC_DMAX) { 341145557Sharti syslog(LOG_ERR, "NTP request too long (%zu)", vlen); 342145557Sharti free(rpkt); 343145557Sharti return (-1); 344145557Sharti } 345145557Sharti *ptr++ = vlen >> 8; 346145557Sharti *ptr++ = vlen; 347145557Sharti 348145557Sharti memcpy(ptr, vars, vlen); 349145557Sharti ptr += vlen; 350145557Sharti } else 351145557Sharti /* skip data length (is already zero) */ 352145557Sharti ptr += 2; 353145557Sharti 354145557Sharti while ((ptr - rpkt) % 4 != 0) 355145557Sharti *ptr++ = 0; 356145557Sharti 357145557Sharti if (ntp_debug & DBG_DUMP_PKTS) { 358145557Sharti syslog(LOG_INFO, "sending %zd bytes", ptr - rpkt); 359145557Sharti dump_packet(rpkt, ptr - rpkt); 360145557Sharti } 361145557Sharti 362145557Sharti ret = send(ntpd_sock, rpkt, ptr - rpkt, 0); 363145557Sharti if (ret == -1) { 364145557Sharti syslog(LOG_ERR, "cannot send to ntpd: %m"); 365145557Sharti free(rpkt); 366145557Sharti return (-1); 367145557Sharti } 368150920Sharti return (0); 369145557Sharti} 370145557Sharti 371145557Sharti/* 372145557Sharti * Callback if packet arrived from NTPD 373145557Sharti */ 374145557Shartistatic int 375145557Shartintpd_read(uint16_t *op, uint16_t *associd, u_char **data, size_t *datalen) 376145557Sharti{ 377145557Sharti u_char pkt[NTPC_MAX + 1]; 378145557Sharti u_char *ptr, *nptr; 379145557Sharti u_int n; 380145557Sharti ssize_t ret; 381145557Sharti size_t z; 382145557Sharti u_int offset; /* current offset */ 383145557Sharti int more; /* more flag */ 384145557Sharti int sel; 385145557Sharti struct timeval inc, end, rem; 386145557Sharti fd_set iset; 387145557Sharti 388145557Sharti *datalen = 0; 389145557Sharti *data = NULL; 390145557Sharti offset = 0; 391145557Sharti 392145557Sharti inc.tv_sec = ntp_timeout / 100; 393145557Sharti inc.tv_usec = (ntp_timeout % 100) * 1000; 394145557Sharti 395145557Sharti (void)gettimeofday(&end, NULL); 396145557Sharti timeradd(&end, &inc, &end); 397145557Sharti 398145557Sharti next: 399145557Sharti /* compute remaining time */ 400145557Sharti (void)gettimeofday(&rem, NULL); 401145557Sharti if (timercmp(&rem, &end, >=)) { 402145557Sharti /* do a poll */ 403145557Sharti rem.tv_sec = 0; 404145557Sharti rem.tv_usec = 0; 405145557Sharti } else { 406145557Sharti timersub(&end, &rem, &rem); 407145557Sharti } 408145557Sharti 409145557Sharti /* select */ 410145557Sharti FD_ZERO(&iset); 411145557Sharti FD_SET(ntpd_sock, &iset); 412145557Sharti sel = select(ntpd_sock + 1, &iset, NULL, NULL, &rem); 413145557Sharti if (sel == -1) { 414145557Sharti if (errno == EINTR) 415145557Sharti goto next; 416145557Sharti syslog(LOG_ERR, "select ntpd_sock: %m"); 417145557Sharti free(*data); 418145557Sharti return (-1); 419145557Sharti } 420145557Sharti if (sel == 0) { 421145557Sharti syslog(LOG_ERR, "timeout on NTP connection"); 422145557Sharti free(*data); 423145557Sharti return (-1); 424145557Sharti } 425145557Sharti 426145557Sharti /* now read it */ 427145557Sharti ret = recv(ntpd_sock, pkt, sizeof(pkt), 0); 428145557Sharti if (ret == -1) { 429145557Sharti syslog(LOG_ERR, "error reading from ntpd: %m"); 430145557Sharti free(*data); 431145557Sharti return (-1); 432145557Sharti } 433145557Sharti 434145557Sharti if (ntp_debug & DBG_DUMP_PKTS) { 435145557Sharti syslog(LOG_INFO, "got %zd bytes", ret); 436145557Sharti dump_packet(pkt, (size_t)ret); 437145557Sharti } 438145557Sharti 439145557Sharti ptr = pkt; 440150920Sharti if ((*ptr & 0x3f) != ((NTPC_VERSION << 3) | NTPC_MODE)) { 441145557Sharti syslog(LOG_ERR, "unexpected packet version 0x%x", *ptr); 442145557Sharti free(*data); 443145557Sharti return (-1); 444145557Sharti } 445145557Sharti ptr++; 446145557Sharti 447145557Sharti if (!(*ptr & NTPC_BIT_RESP)) { 448145557Sharti syslog(LOG_ERR, "not a response packet"); 449145557Sharti return (-1); 450145557Sharti } 451145557Sharti if (*ptr & NTPC_BIT_ERROR) { 452145557Sharti z = *datalen - 12; 453145557Sharti if (z > NTPC_DMAX) 454145557Sharti z = NTPC_DMAX; 455145557Sharti syslog(LOG_ERR, "error response: %.*s", (int)z, pkt + 12); 456145557Sharti free(*data); 457145557Sharti return (-1); 458145557Sharti } 459145557Sharti more = (*ptr & NTPC_BIT_MORE); 460145557Sharti 461145557Sharti *op = *ptr++ & NTPC_OPMASK; 462145557Sharti 463145557Sharti /* seqno */ 464145557Sharti n = *ptr++ << 8; 465145557Sharti n |= *ptr++; 466145557Sharti 467145557Sharti if (n != seqno) { 468145557Sharti syslog(LOG_ERR, "expecting seqno %u, got %u", seqno, n); 469145557Sharti free(*data); 470145557Sharti return (-1); 471145557Sharti } 472145557Sharti 473145557Sharti /* status */ 474145557Sharti n = *ptr++ << 8; 475145557Sharti n |= *ptr++; 476145557Sharti 477145557Sharti /* associd */ 478145557Sharti *associd = *ptr++ << 8; 479145557Sharti *associd |= *ptr++; 480145557Sharti 481145557Sharti /* offset */ 482145557Sharti n = *ptr++ << 8; 483145557Sharti n |= *ptr++; 484145557Sharti 485145557Sharti if (n != offset) { 486145557Sharti syslog(LOG_ERR, "offset: expecting %u, got %u", offset, n); 487145557Sharti free(*data); 488145557Sharti return (-1); 489145557Sharti } 490145557Sharti 491145557Sharti /* count */ 492145557Sharti n = *ptr++ << 8; 493145557Sharti n |= *ptr++; 494145557Sharti 495145557Sharti if ((size_t)ret < 12 + n) { 496145557Sharti syslog(LOG_ERR, "packet too short"); 497145557Sharti return (-1); 498145557Sharti } 499145557Sharti 500145557Sharti nptr = realloc(*data, *datalen + n); 501145557Sharti if (nptr == NULL) { 502145557Sharti syslog(LOG_ERR, "cannot allocate memory: %m"); 503145557Sharti free(*data); 504145557Sharti return (-1); 505145557Sharti } 506145557Sharti *data = nptr; 507145557Sharti 508145557Sharti memcpy(*data + offset, ptr, n); 509145557Sharti *datalen += n; 510145557Sharti 511145557Sharti if (!more) 512145557Sharti return (0); 513145557Sharti 514145557Sharti offset += n; 515145557Sharti goto next; 516145557Sharti} 517145557Sharti 518145557Sharti/* 519145557Sharti * Send a request and wait for the response 520145557Sharti */ 521145557Shartistatic int 522145557Shartintpd_dialog(u_int op, u_int associd, const char *vars, u_char **data, 523145557Sharti size_t *datalen) 524145557Sharti{ 525145557Sharti uint16_t rassocid; 526145557Sharti uint16_t rop; 527145557Sharti 528145557Sharti if (ntpd_request(op, associd, vars) == -1) 529145557Sharti return (-1); 530145557Sharti if (ntpd_read(&rop, &rassocid, data, datalen) == -1) 531145557Sharti return (-1); 532145557Sharti 533145557Sharti if (rop != op) { 534145557Sharti syslog(LOG_ERR, "bad response op 0x%x", rop); 535145557Sharti free(data); 536145557Sharti return (-1); 537145557Sharti } 538145557Sharti 539145557Sharti if (associd != rassocid) { 540145557Sharti syslog(LOG_ERR, "response for wrong associd"); 541145557Sharti free(data); 542145557Sharti return (-1); 543145557Sharti } 544145557Sharti return (0); 545145557Sharti} 546145557Sharti 547145557Sharti/* 548145557Sharti * Callback if packet arrived from NTPD 549145557Sharti */ 550145557Shartistatic void 551145557Shartintpd_input(int fd __unused, void *arg __unused) 552145557Sharti{ 553145557Sharti uint16_t associd; 554145557Sharti uint16_t op; 555145557Sharti u_char *data; 556145557Sharti size_t datalen; 557145557Sharti 558145557Sharti if (ntpd_read(&op, &associd, &data, &datalen) == -1) 559145557Sharti return; 560145557Sharti 561145557Sharti free(data); 562145557Sharti} 563145557Sharti 564145557Sharti/* 565145557Sharti * Find the value of a variable 566145557Sharti */ 567145557Shartistatic int 568145557Shartintpd_parse(u_char **data, size_t *datalen, char **namep, char **valp) 569145557Sharti{ 570145557Sharti u_char *ptr = *data; 571145557Sharti u_char *end = ptr + *datalen; 572145557Sharti char *ptr1; 573145557Sharti char endc; 574145557Sharti 575145557Sharti /* skip leading spaces */ 576145557Sharti while (ptr < end && isspace((int)*ptr)) 577145557Sharti ptr++; 578145557Sharti 579145557Sharti if (ptr == end) 580145557Sharti return (0); 581145557Sharti 582145557Sharti *namep = ptr; 583145557Sharti 584145557Sharti /* skip to space or '=' or ','*/ 585145557Sharti while (ptr < end && !isspace((int)*ptr) && *ptr != '=' && *ptr != ',') 586145557Sharti ptr++; 587145557Sharti endc = *ptr; 588145557Sharti *ptr++ = '\0'; 589145557Sharti 590145557Sharti /* skip space */ 591145557Sharti while (ptr < end && isspace((int)*ptr)) 592145557Sharti ptr++; 593145557Sharti 594145557Sharti if (ptr == end || endc == ',') { 595145557Sharti /* no value */ 596145557Sharti *valp = NULL; 597145557Sharti *datalen -= ptr - *data; 598145557Sharti *data = ptr; 599145557Sharti return (1); 600145557Sharti } 601145557Sharti 602145557Sharti if (*ptr == '"') { 603145557Sharti /* quoted */ 604145557Sharti ptr++; 605145557Sharti *valp = ptr; 606145557Sharti while (ptr < end && *ptr != '"') 607145557Sharti ptr++; 608145557Sharti if (ptr == end) 609145557Sharti return (0); 610145557Sharti 611145557Sharti *ptr++ = '\0'; 612145557Sharti 613145557Sharti /* find comma */ 614145557Sharti while (ptr < end && isspace((int)*ptr) && *ptr == ',') 615145557Sharti ptr++; 616145557Sharti } else { 617145557Sharti *valp = ptr; 618145557Sharti 619145557Sharti /* skip to end of value */ 620145557Sharti while (ptr < end && *ptr != ',') 621145557Sharti ptr++; 622145557Sharti 623145557Sharti /* remove trailing blanks */ 624145557Sharti for (ptr1 = ptr; ptr1 > *valp; ptr1--) 625145557Sharti if (!isspace((int)ptr1[-1])) 626145557Sharti break; 627145557Sharti *ptr1 = '\0'; 628145557Sharti 629145557Sharti if (ptr < end) 630145557Sharti ptr++; 631145557Sharti } 632145557Sharti 633145557Sharti *datalen -= ptr - *data; 634145557Sharti *data = ptr; 635145557Sharti 636145557Sharti return (1); 637145557Sharti} 638145557Sharti 639145557Sharti/* 640145557Sharti * Parse an int32 value 641145557Sharti */ 642145557Shartistatic int 643145557Shartival_parse_int32(const char *val, int32_t *p, int32_t min, int32_t max, int base) 644145557Sharti{ 645145557Sharti long n; 646145557Sharti char *end; 647145557Sharti 648145557Sharti errno = 0; 649145557Sharti n = strtol(val, &end, base); 650145557Sharti if (errno != 0 || *end != '\0') 651145557Sharti return (0); 652145557Sharti if (n < min || n > max) 653145557Sharti return (0); 654145557Sharti *p = (int32_t)n; 655145557Sharti return (1); 656145557Sharti} 657145557Sharti 658145557Sharti/* 659145557Sharti * Parse an uint32 value 660145557Sharti */ 661145557Shartistatic int 662145557Shartival_parse_uint32(const char *val, uint32_t *p, uint32_t min, uint32_t max, 663145557Sharti int base) 664145557Sharti{ 665145557Sharti u_long n; 666145557Sharti char *end; 667145557Sharti 668145557Sharti errno = 0; 669145557Sharti n = strtoul(val, &end, base); 670145557Sharti if (errno != 0 || *end != '\0') 671145557Sharti return (0); 672145557Sharti if (n < min || n > max) 673145557Sharti return (0); 674145557Sharti *p = (uint32_t)n; 675145557Sharti return (1); 676145557Sharti} 677145557Sharti 678145557Sharti/* 679145557Sharti * Parse a double 680145557Sharti */ 681145557Shartistatic int 682145557Shartival_parse_double(const char *val, double *p) 683145557Sharti{ 684145557Sharti char *end; 685145557Sharti 686145557Sharti errno = 0; 687145557Sharti *p = strtod(val, &end); 688145557Sharti if (errno != 0 || *end != '\0') 689145557Sharti return (0); 690145557Sharti return (1); 691145557Sharti} 692145557Sharti 693145557Shartistatic int 694145557Shartival_parse_ts(const char *val, char *buf) 695145557Sharti{ 696145557Sharti int r, n; 697145557Sharti u_int i, f; 698145557Sharti 699145557Sharti if (strlen(val) > 2 && val[0] == '0' && val[1] == 'x') { 700145557Sharti /* hex format */ 701145557Sharti r = sscanf(val + 2, "%x.%x%n", &i, &f, &n); 702145557Sharti if (r != 2 || (size_t)n != strlen(val + 2)) 703145557Sharti return (0); 704145557Sharti } else { 705145557Sharti /* probably decimal */ 706145557Sharti r = sscanf(val, "%d.%d%n", &i, &f, &n); 707145557Sharti if (r != 2 || (size_t)n != strlen(val)) 708145557Sharti return (0); 709145557Sharti } 710145557Sharti buf[0] = i >> 24; 711145557Sharti buf[1] = i >> 16; 712145557Sharti buf[2] = i >> 8; 713145557Sharti buf[3] = i >> 0; 714145557Sharti buf[4] = f >> 24; 715145557Sharti buf[5] = f >> 16; 716145557Sharti buf[6] = f >> 8; 717145557Sharti buf[7] = f >> 0; 718145557Sharti return (1); 719145557Sharti} 720145557Sharti 721145557Sharti/* 722145557Sharti * Parse an IP address. This resolves non-numeric names. 723145557Sharti */ 724145557Shartistatic int 725145557Shartival_parse_ip(const char *val, u_char ip[4]) 726145557Sharti{ 727145557Sharti int r, n, error; 728145557Sharti struct addrinfo hints, *res0; 729150920Sharti struct sockaddr_in *sin_local; 730145557Sharti 731145557Sharti r = sscanf(val, "%hhd.%hhd.%hhd.%hhd%n", 732145557Sharti &ip[0], &ip[1], &ip[2], &ip[3], &n); 733145557Sharti if (n == 4 && (size_t)n == strlen(val)) 734145557Sharti return (0); 735145557Sharti 736145557Sharti memset(ip, 0, 4); 737145557Sharti 738145557Sharti memset(&hints, 0, sizeof(hints)); 739145557Sharti hints.ai_family = AF_INET; 740145557Sharti hints.ai_socktype = SOCK_DGRAM; 741145557Sharti 742145557Sharti error = getaddrinfo(val, NULL, &hints, &res0); 743145557Sharti if (error) { 744145557Sharti syslog(LOG_ERR, "%s: %s", val, gai_strerror(error)); 745145557Sharti return (-1); 746145557Sharti } 747145557Sharti if (res0 == NULL) { 748145557Sharti syslog(LOG_ERR, "%s: no address", val); 749145557Sharti return (-1); 750145557Sharti } 751145557Sharti 752150920Sharti sin_local = (struct sockaddr_in *)(void *)res0->ai_addr; 753150920Sharti ip[3] = sin_local->sin_addr.s_addr >> 24; 754150920Sharti ip[2] = sin_local->sin_addr.s_addr >> 16; 755150920Sharti ip[1] = sin_local->sin_addr.s_addr >> 8; 756150920Sharti ip[0] = sin_local->sin_addr.s_addr >> 0; 757145557Sharti 758145557Sharti freeaddrinfo(res0); 759145557Sharti return (0); 760145557Sharti} 761145557Sharti 762145557Sharti/* 763145557Sharti * Fetch system info 764145557Sharti */ 765145557Shartistatic int 766145557Shartifetch_sysinfo(void) 767145557Sharti{ 768145557Sharti u_char *data; 769145557Sharti u_char *ptr; 770145557Sharti size_t datalen; 771145557Sharti char *name; 772145557Sharti char *val; 773145557Sharti 774145557Sharti if (ntpd_dialog(NTPC_OP_READVAR, 0, 775145557Sharti "leap,stratum,precision,rootdelay,rootdispersion,refid,reftime," 776145557Sharti "poll,peer,clock,system,processor,jitter,stability", 777145557Sharti &data, &datalen)) 778145557Sharti return (-1); 779145557Sharti 780145557Sharti /* clear info */ 781145557Sharti sysb_leap = 0; 782145557Sharti sysb_stratum = 0; 783145557Sharti sysb_precision = 0; 784145557Sharti free(sys_rootdelay); 785145557Sharti sys_rootdelay = NULL; 786145557Sharti free(sys_rootdispersion); 787145557Sharti sys_rootdispersion = NULL; 788145557Sharti free(sys_refid); 789145557Sharti sys_refid = NULL; 790145557Sharti sysb_reftime = 0; 791145557Sharti sysb_poll = 0; 792145557Sharti sysb_peer = 0; 793145557Sharti sysb_clock = 0; 794145557Sharti free(sys_system); 795145557Sharti sys_system = NULL; 796145557Sharti free(sys_processor); 797145557Sharti sys_processor = NULL; 798145557Sharti sysb_jitter = 0; 799145557Sharti sysb_stability = 0; 800145557Sharti 801145557Sharti ptr = data; 802145557Sharti while (ntpd_parse(&ptr, &datalen, &name, &val)) { 803145557Sharti if (ntp_debug & DBG_DUMP_VARS) 804145557Sharti syslog(LOG_DEBUG, "%s: '%s'='%s'", __func__, name, val); 805145557Sharti if (strcmp(name, "leap") == 0 || 806145557Sharti strcmp(name, "sys.leap") == 0) { 807145557Sharti sysb_leap = val_parse_int32(val, &sys_leap, 808145557Sharti 0, 3, 2); 809145557Sharti 810145557Sharti } else if (strcmp(name, "stratum") == 0 || 811145557Sharti strcmp(name, "sys.stratum") == 0) { 812145557Sharti sysb_stratum = val_parse_int32(val, &sys_stratum, 813145557Sharti 0, 255, 0); 814145557Sharti 815145557Sharti } else if (strcmp(name, "precision") == 0 || 816145557Sharti strcmp(name, "sys.precision") == 0) { 817145557Sharti sysb_precision = val_parse_int32(val, &sys_precision, 818145557Sharti INT32_MIN, INT32_MAX, 0); 819145557Sharti 820145557Sharti } else if (strcmp(name, "rootdelay") == 0 || 821145557Sharti strcmp(name, "sys.rootdelay") == 0) { 822145557Sharti sys_rootdelay = strdup(val); 823145557Sharti 824145557Sharti } else if (strcmp(name, "rootdispersion") == 0 || 825145557Sharti strcmp(name, "sys.rootdispersion") == 0) { 826145557Sharti sys_rootdispersion = strdup(val); 827145557Sharti 828145557Sharti } else if (strcmp(name, "refid") == 0 || 829145557Sharti strcmp(name, "sys.refid") == 0) { 830145557Sharti sys_refid = strdup(val); 831145557Sharti 832145557Sharti } else if (strcmp(name, "reftime") == 0 || 833145557Sharti strcmp(name, "sys.reftime") == 0) { 834145557Sharti sysb_reftime = val_parse_ts(val, sys_reftime); 835145557Sharti 836145557Sharti } else if (strcmp(name, "poll") == 0 || 837145557Sharti strcmp(name, "sys.poll") == 0) { 838145557Sharti sysb_poll = val_parse_int32(val, &sys_poll, 839145557Sharti INT32_MIN, INT32_MAX, 0); 840145557Sharti 841145557Sharti } else if (strcmp(name, "peer") == 0 || 842145557Sharti strcmp(name, "sys.peer") == 0) { 843145557Sharti sysb_peer = val_parse_uint32(val, &sys_peer, 844145557Sharti 0, UINT32_MAX, 0); 845145557Sharti 846145557Sharti } else if (strcmp(name, "clock") == 0 || 847145557Sharti strcmp(name, "sys.clock") == 0) { 848145557Sharti sysb_clock = val_parse_ts(val, sys_clock); 849145557Sharti 850145557Sharti } else if (strcmp(name, "system") == 0 || 851145557Sharti strcmp(name, "sys.system") == 0) { 852145557Sharti sys_system = strdup(val); 853145557Sharti 854145557Sharti } else if (strcmp(name, "processor") == 0 || 855145557Sharti strcmp(name, "sys.processor") == 0) { 856145557Sharti sys_processor = strdup(val); 857145557Sharti 858145557Sharti } else if (strcmp(name, "jitter") == 0 || 859145557Sharti strcmp(name, "sys.jitter") == 0) { 860145557Sharti sysb_jitter = val_parse_double(val, &sys_jitter); 861145557Sharti 862145557Sharti } else if (strcmp(name, "stability") == 0 || 863145557Sharti strcmp(name, "sys.stability") == 0) { 864145557Sharti sysb_stability = val_parse_double(val, &sys_stability); 865145557Sharti } 866145557Sharti } 867145557Sharti 868145557Sharti free(data); 869145557Sharti return (0); 870145557Sharti} 871145557Sharti 872145557Shartistatic int 873145557Shartiparse_filt(char *val, uint16_t associd, int which) 874145557Sharti{ 875145557Sharti char *w; 876145557Sharti int cnt; 877145557Sharti struct filt *f; 878145557Sharti 879145557Sharti cnt = 0; 880145557Sharti for (w = strtok(val, " \t"); w != NULL; w = strtok(NULL, " \t")) { 881145557Sharti TAILQ_FOREACH(f, &filts, link) 882145557Sharti if (f->index.subs[0] == associd && 883145557Sharti f->index.subs[1] == (asn_subid_t)(cnt + 1)) 884145557Sharti break; 885145557Sharti if (f == NULL) { 886145557Sharti f = malloc(sizeof(*f)); 887145557Sharti memset(f, 0, sizeof(*f)); 888145557Sharti f->index.len = 2; 889145557Sharti f->index.subs[0] = associd; 890145557Sharti f->index.subs[1] = cnt + 1; 891145557Sharti 892145557Sharti INSERT_OBJECT_OID(f, &filts); 893145557Sharti } 894145557Sharti 895145557Sharti switch (which) { 896145557Sharti 897145557Sharti case 0: 898145557Sharti f->offset = strdup(w); 899145557Sharti break; 900145557Sharti 901145557Sharti case 1: 902145557Sharti f->delay = strdup(w); 903145557Sharti break; 904145557Sharti 905145557Sharti case 2: 906145557Sharti f->dispersion = strdup(w); 907145557Sharti break; 908145557Sharti 909145557Sharti default: 910145557Sharti abort(); 911145557Sharti } 912145557Sharti cnt++; 913145557Sharti } 914145557Sharti return (cnt); 915145557Sharti} 916145557Sharti 917145557Sharti/* 918145557Sharti * Fetch the complete peer list 919145557Sharti */ 920145557Shartistatic int 921145557Shartifetch_peers(void) 922145557Sharti{ 923145557Sharti u_char *data, *pdata, *ptr; 924145557Sharti size_t datalen, pdatalen; 925145557Sharti int i; 926145557Sharti struct peer *p; 927145557Sharti struct filt *f; 928145557Sharti uint16_t associd; 929145557Sharti char *name, *val; 930145557Sharti 931145557Sharti /* free the old list */ 932145557Sharti while ((p = TAILQ_FIRST(&peers)) != NULL) { 933145557Sharti TAILQ_REMOVE(&peers, p, link); 934145557Sharti free(p->rootdelay); 935145557Sharti free(p->rootdispersion); 936145557Sharti free(p->refid); 937145557Sharti free(p->offset); 938145557Sharti free(p->delay); 939145557Sharti free(p->dispersion); 940145557Sharti free(p); 941145557Sharti } 942145557Sharti while ((f = TAILQ_FIRST(&filts)) != NULL) { 943145557Sharti TAILQ_REMOVE(&filts, f, link); 944145557Sharti free(f->offset); 945145557Sharti free(f->delay); 946145557Sharti free(f->dispersion); 947145557Sharti free(f); 948145557Sharti } 949145557Sharti 950145557Sharti /* fetch the list of associations */ 951145557Sharti if (ntpd_dialog(NTPC_OP_READSTAT, 0, NULL, &data, &datalen)) 952145557Sharti return (-1); 953145557Sharti 954145557Sharti for (i = 0; i < (int)(datalen / 4); i++) { 955145557Sharti associd = data[4 * i + 0] << 8; 956145557Sharti associd |= data[4 * i + 1] << 0; 957145557Sharti 958145557Sharti /* ask for the association variables */ 959145557Sharti if (ntpd_dialog(NTPC_OP_READVAR, associd, 960145557Sharti "config,srcadr,srcport,dstadr,dstport,leap,hmode,stratum," 961145557Sharti "hpoll,ppoll,precision,rootdelay,rootdispersion,refid," 962145557Sharti "reftime,org,rec,xmt,reach,timer,offset,delay,dispersion," 963145557Sharti "filtdelay,filtoffset,filtdisp", 964145557Sharti &pdata, &pdatalen)) { 965145557Sharti free(data); 966145557Sharti return (-1); 967145557Sharti } 968145557Sharti 969145557Sharti /* now save and parse the data */ 970145557Sharti p = malloc(sizeof(*p)); 971145557Sharti if (p == NULL) { 972145557Sharti free(data); 973145557Sharti syslog(LOG_ERR, "%m"); 974145557Sharti return (-1); 975145557Sharti } 976145557Sharti memset(p, 0, sizeof(*p)); 977145557Sharti p->index = associd; 978145557Sharti INSERT_OBJECT_INT(p, &peers); 979145557Sharti 980145557Sharti ptr = pdata; 981145557Sharti while (ntpd_parse(&ptr, &pdatalen, &name, &val)) { 982145557Sharti if (ntp_debug & DBG_DUMP_VARS) 983145557Sharti syslog(LOG_DEBUG, "%s: '%s'='%s'", 984145557Sharti __func__, name, val); 985145557Sharti if (strcmp(name, "config") == 0 || 986145557Sharti strcmp(name, "peer.config") == 0) { 987145557Sharti val_parse_int32(val, &p->config, 0, 1, 0); 988145557Sharti 989145557Sharti } else if (strcmp(name, "srcadr") == 0 || 990145557Sharti strcmp(name, "peer.srcadr") == 0) { 991145557Sharti val_parse_ip(val, p->srcadr); 992145557Sharti 993145557Sharti } else if (strcmp(name, "srcport") == 0 || 994145557Sharti strcmp(name, "peer.srcport") == 0) { 995145557Sharti val_parse_uint32(val, &p->srcport, 996145557Sharti 1, 65535, 0); 997145557Sharti 998145557Sharti } else if (strcmp(name, "dstadr") == 0 || 999145557Sharti strcmp(name, "peer.dstadr") == 0) { 1000145557Sharti val_parse_ip(val, p->dstadr); 1001145557Sharti 1002145557Sharti } else if (strcmp(name, "dstport") == 0 || 1003145557Sharti strcmp(name, "peer.dstport") == 0) { 1004145557Sharti val_parse_uint32(val, &p->dstport, 1005145557Sharti 1, 65535, 0); 1006145557Sharti 1007145557Sharti } else if (strcmp(name, "leap") == 0 || 1008145557Sharti strcmp(name, "peer.leap") == 0) { 1009145557Sharti val_parse_int32(val, &p->leap, 0, 3, 2); 1010145557Sharti 1011145557Sharti } else if (strcmp(name, "hmode") == 0 || 1012145557Sharti strcmp(name, "peer.hmode") == 0) { 1013145557Sharti val_parse_int32(val, &p->hmode, 0, 7, 0); 1014145557Sharti 1015145557Sharti } else if (strcmp(name, "stratum") == 0 || 1016145557Sharti strcmp(name, "peer.stratum") == 0) { 1017145557Sharti val_parse_int32(val, &p->stratum, 0, 255, 0); 1018145557Sharti 1019145557Sharti } else if (strcmp(name, "ppoll") == 0 || 1020145557Sharti strcmp(name, "peer.ppoll") == 0) { 1021145557Sharti val_parse_int32(val, &p->ppoll, 1022145557Sharti INT32_MIN, INT32_MAX, 0); 1023145557Sharti 1024145557Sharti } else if (strcmp(name, "hpoll") == 0 || 1025145557Sharti strcmp(name, "peer.hpoll") == 0) { 1026145557Sharti val_parse_int32(val, &p->hpoll, 1027145557Sharti INT32_MIN, INT32_MAX, 0); 1028145557Sharti 1029145557Sharti } else if (strcmp(name, "precision") == 0 || 1030145557Sharti strcmp(name, "peer.precision") == 0) { 1031145557Sharti val_parse_int32(val, &p->hpoll, 1032145557Sharti INT32_MIN, INT32_MAX, 0); 1033145557Sharti 1034145557Sharti } else if (strcmp(name, "rootdelay") == 0 || 1035145557Sharti strcmp(name, "peer.rootdelay") == 0) { 1036145557Sharti p->rootdelay = strdup(val); 1037145557Sharti 1038145557Sharti } else if (strcmp(name, "rootdispersion") == 0 || 1039145557Sharti strcmp(name, "peer.rootdispersion") == 0) { 1040145557Sharti p->rootdispersion = strdup(val); 1041145557Sharti 1042145557Sharti } else if (strcmp(name, "refid") == 0 || 1043145557Sharti strcmp(name, "peer.refid") == 0) { 1044145557Sharti p->refid = strdup(val); 1045145557Sharti 1046145557Sharti } else if (strcmp(name, "reftime") == 0 || 1047145557Sharti strcmp(name, "sys.reftime") == 0) { 1048145557Sharti val_parse_ts(val, p->reftime); 1049145557Sharti 1050145557Sharti } else if (strcmp(name, "org") == 0 || 1051145557Sharti strcmp(name, "sys.org") == 0) { 1052145557Sharti val_parse_ts(val, p->orgtime); 1053145557Sharti 1054145557Sharti } else if (strcmp(name, "rec") == 0 || 1055145557Sharti strcmp(name, "sys.rec") == 0) { 1056145557Sharti val_parse_ts(val, p->rcvtime); 1057145557Sharti 1058145557Sharti } else if (strcmp(name, "xmt") == 0 || 1059145557Sharti strcmp(name, "sys.xmt") == 0) { 1060145557Sharti val_parse_ts(val, p->xmttime); 1061145557Sharti 1062145557Sharti } else if (strcmp(name, "reach") == 0 || 1063145557Sharti strcmp(name, "peer.reach") == 0) { 1064145557Sharti val_parse_uint32(val, &p->reach, 1065145557Sharti 0, 65535, 0); 1066145557Sharti 1067145557Sharti } else if (strcmp(name, "timer") == 0 || 1068145557Sharti strcmp(name, "peer.timer") == 0) { 1069145557Sharti val_parse_int32(val, &p->timer, 1070145557Sharti INT32_MIN, INT32_MAX, 0); 1071145557Sharti 1072145557Sharti } else if (strcmp(name, "offset") == 0 || 1073145557Sharti strcmp(name, "peer.offset") == 0) { 1074145557Sharti p->offset = strdup(val); 1075145557Sharti 1076145557Sharti } else if (strcmp(name, "delay") == 0 || 1077145557Sharti strcmp(name, "peer.delay") == 0) { 1078145557Sharti p->delay = strdup(val); 1079145557Sharti 1080145557Sharti } else if (strcmp(name, "dispersion") == 0 || 1081145557Sharti strcmp(name, "peer.dispersion") == 0) { 1082145557Sharti p->dispersion = strdup(val); 1083145557Sharti 1084145557Sharti } else if (strcmp(name, "filtdelay") == 0 || 1085145557Sharti strcmp(name, "peer.filtdelay") == 0) { 1086145557Sharti p->filt_entries = parse_filt(val, associd, 0); 1087145557Sharti 1088145557Sharti } else if (strcmp(name, "filtoffset") == 0 || 1089145557Sharti strcmp(name, "peer.filtoffset") == 0) { 1090145557Sharti p->filt_entries = parse_filt(val, associd, 1); 1091145557Sharti 1092145557Sharti } else if (strcmp(name, "filtdisp") == 0 || 1093145557Sharti strcmp(name, "peer.filtdisp") == 0) { 1094145557Sharti p->filt_entries = parse_filt(val, associd, 2); 1095145557Sharti } 1096145557Sharti } 1097145557Sharti free(pdata); 1098145557Sharti } 1099145557Sharti 1100145557Sharti free(data); 1101145557Sharti return (0); 1102145557Sharti} 1103145557Sharti 1104145557Sharti/* 1105145557Sharti * System variables - read-only scalars only. 1106145557Sharti */ 1107145557Shartiint 1108145557Shartiop_ntpSystem(struct snmp_context *ctx __unused, struct snmp_value *value, 1109145557Sharti u_int sub, u_int iidx __unused, enum snmp_op op) 1110145557Sharti{ 1111145557Sharti asn_subid_t which = value->var.subs[sub - 1]; 1112145557Sharti 1113145557Sharti switch (op) { 1114145557Sharti 1115145557Sharti case SNMP_OP_GETNEXT: 1116145557Sharti abort(); 1117145557Sharti 1118145557Sharti case SNMP_OP_GET: 1119145557Sharti if (this_tick > sysinfo_tick) { 1120145557Sharti if (fetch_sysinfo() == -1) 1121145557Sharti return (SNMP_ERR_GENERR); 1122145557Sharti sysinfo_tick = this_tick; 1123145557Sharti } 1124145557Sharti 1125145557Sharti switch (which) { 1126145557Sharti 1127145557Sharti case LEAF_ntpSysLeap: 1128145557Sharti if (!sysb_leap) 1129145557Sharti return (SNMP_ERR_NOSUCHNAME); 1130145557Sharti value->v.integer = sys_leap; 1131145557Sharti break; 1132145557Sharti 1133145557Sharti case LEAF_ntpSysStratum: 1134145557Sharti if (!sysb_stratum) 1135145557Sharti return (SNMP_ERR_NOSUCHNAME); 1136145557Sharti value->v.integer = sys_stratum; 1137145557Sharti break; 1138145557Sharti 1139145557Sharti case LEAF_ntpSysPrecision: 1140145557Sharti if (!sysb_precision) 1141145557Sharti return (SNMP_ERR_NOSUCHNAME); 1142145557Sharti value->v.integer = sys_precision; 1143145557Sharti break; 1144145557Sharti 1145145557Sharti case LEAF_ntpSysRootDelay: 1146145557Sharti if (sys_rootdelay == NULL) 1147145557Sharti return (SNMP_ERR_NOSUCHNAME); 1148145557Sharti return (string_get(value, sys_rootdelay, -1)); 1149145557Sharti 1150145557Sharti case LEAF_ntpSysRootDispersion: 1151145557Sharti if (sys_rootdispersion == NULL) 1152145557Sharti return (SNMP_ERR_NOSUCHNAME); 1153145557Sharti return (string_get(value, sys_rootdispersion, -1)); 1154145557Sharti 1155145557Sharti case LEAF_ntpSysRefId: 1156145557Sharti if (sys_refid == NULL) 1157145557Sharti return (SNMP_ERR_NOSUCHNAME); 1158145557Sharti return (string_get(value, sys_refid, -1)); 1159145557Sharti 1160145557Sharti case LEAF_ntpSysRefTime: 1161145557Sharti if (sysb_reftime == 0) 1162145557Sharti return (SNMP_ERR_NOSUCHNAME); 1163145557Sharti return (string_get(value, sys_reftime, 8)); 1164145557Sharti 1165145557Sharti case LEAF_ntpSysPoll: 1166145557Sharti if (sysb_poll == 0) 1167145557Sharti return (SNMP_ERR_NOSUCHNAME); 1168145557Sharti value->v.integer = sys_poll; 1169145557Sharti break; 1170145557Sharti 1171145557Sharti case LEAF_ntpSysPeer: 1172145557Sharti if (sysb_peer == 0) 1173145557Sharti return (SNMP_ERR_NOSUCHNAME); 1174145557Sharti value->v.uint32 = sys_peer; 1175145557Sharti break; 1176145557Sharti 1177145557Sharti case LEAF_ntpSysClock: 1178145557Sharti if (sysb_clock == 0) 1179145557Sharti return (SNMP_ERR_NOSUCHNAME); 1180145557Sharti return (string_get(value, sys_clock, 8)); 1181145557Sharti 1182145557Sharti case LEAF_ntpSysSystem: 1183145557Sharti if (sys_system == NULL) 1184145557Sharti return (SNMP_ERR_NOSUCHNAME); 1185145557Sharti return (string_get(value, sys_system, -1)); 1186145557Sharti 1187145557Sharti case LEAF_ntpSysProcessor: 1188145557Sharti if (sys_processor == NULL) 1189145557Sharti return (SNMP_ERR_NOSUCHNAME); 1190145557Sharti return (string_get(value, sys_processor, -1)); 1191145557Sharti 1192145557Sharti default: 1193145557Sharti abort(); 1194145557Sharti } 1195145557Sharti return (SNMP_ERR_NOERROR); 1196145557Sharti 1197145557Sharti case SNMP_OP_SET: 1198145557Sharti return (SNMP_ERR_NOT_WRITEABLE); 1199145557Sharti 1200145557Sharti case SNMP_OP_COMMIT: 1201145557Sharti case SNMP_OP_ROLLBACK: 1202145557Sharti abort(); 1203145557Sharti } 1204145557Sharti abort(); 1205145557Sharti} 1206145557Sharti 1207145557Shartiint 1208145557Shartiop_ntpPeersVarTable(struct snmp_context *ctx __unused, struct snmp_value *value, 1209145557Sharti u_int sub, u_int iidx, enum snmp_op op) 1210145557Sharti{ 1211145557Sharti asn_subid_t which = value->var.subs[sub - 1]; 1212145557Sharti uint32_t peer; 1213145557Sharti struct peer *t; 1214145557Sharti 1215145557Sharti if (this_tick > peers_tick) { 1216145557Sharti if (fetch_peers() == -1) 1217145557Sharti return (SNMP_ERR_GENERR); 1218145557Sharti peers_tick = this_tick; 1219145557Sharti } 1220145557Sharti 1221145557Sharti switch (op) { 1222145557Sharti 1223145557Sharti case SNMP_OP_GETNEXT: 1224145557Sharti t = NEXT_OBJECT_INT(&peers, &value->var, sub); 1225145557Sharti if (t == NULL) 1226145557Sharti return (SNMP_ERR_NOSUCHNAME); 1227145557Sharti value->var.len = sub + 1; 1228145557Sharti value->var.subs[sub] = t->index; 1229145557Sharti break; 1230145557Sharti 1231145557Sharti case SNMP_OP_GET: 1232145557Sharti t = FIND_OBJECT_INT(&peers, &value->var, sub); 1233145557Sharti if (t == NULL) 1234145557Sharti return (SNMP_ERR_NOSUCHNAME); 1235145557Sharti break; 1236145557Sharti 1237145557Sharti case SNMP_OP_SET: 1238145557Sharti if (index_decode(&value->var, sub, iidx, &peer)) 1239145557Sharti return (SNMP_ERR_NO_CREATION); 1240145557Sharti t = FIND_OBJECT_INT(&peers, &value->var, sub); 1241145557Sharti if (t != NULL) 1242145557Sharti return (SNMP_ERR_NOT_WRITEABLE); 1243145557Sharti return (SNMP_ERR_NO_CREATION); 1244145557Sharti 1245145557Sharti case SNMP_OP_COMMIT: 1246145557Sharti case SNMP_OP_ROLLBACK: 1247145557Sharti default: 1248145557Sharti abort(); 1249145557Sharti } 1250145557Sharti 1251145557Sharti /* 1252145557Sharti * Come here for GET and COMMIT 1253145557Sharti */ 1254145557Sharti switch (which) { 1255145557Sharti 1256145557Sharti case LEAF_ntpPeersConfigured: 1257145557Sharti value->v.integer = t->config; 1258145557Sharti break; 1259145557Sharti 1260145557Sharti case LEAF_ntpPeersPeerAddress: 1261145557Sharti return (ip_get(value, t->srcadr)); 1262145557Sharti 1263145557Sharti case LEAF_ntpPeersPeerPort: 1264145557Sharti value->v.uint32 = t->srcport; 1265145557Sharti break; 1266145557Sharti 1267145557Sharti case LEAF_ntpPeersHostAddress: 1268145557Sharti return (ip_get(value, t->dstadr)); 1269145557Sharti 1270145557Sharti case LEAF_ntpPeersHostPort: 1271145557Sharti value->v.uint32 = t->dstport; 1272145557Sharti break; 1273145557Sharti 1274145557Sharti case LEAF_ntpPeersLeap: 1275145557Sharti value->v.integer = t->leap; 1276145557Sharti break; 1277145557Sharti 1278145557Sharti case LEAF_ntpPeersMode: 1279145557Sharti value->v.integer = t->hmode; 1280145557Sharti break; 1281145557Sharti 1282145557Sharti case LEAF_ntpPeersStratum: 1283145557Sharti value->v.integer = t->stratum; 1284145557Sharti break; 1285145557Sharti 1286145557Sharti case LEAF_ntpPeersPeerPoll: 1287145557Sharti value->v.integer = t->ppoll; 1288145557Sharti break; 1289145557Sharti 1290145557Sharti case LEAF_ntpPeersHostPoll: 1291145557Sharti value->v.integer = t->hpoll; 1292145557Sharti break; 1293145557Sharti 1294145557Sharti case LEAF_ntpPeersPrecision: 1295145557Sharti value->v.integer = t->precision; 1296145557Sharti break; 1297145557Sharti 1298145557Sharti case LEAF_ntpPeersRootDelay: 1299145557Sharti return (string_get(value, t->rootdelay, -1)); 1300145557Sharti 1301145557Sharti case LEAF_ntpPeersRootDispersion: 1302145557Sharti return (string_get(value, t->rootdispersion, -1)); 1303145557Sharti 1304145557Sharti case LEAF_ntpPeersRefId: 1305145557Sharti return (string_get(value, t->refid, -1)); 1306145557Sharti 1307145557Sharti case LEAF_ntpPeersRefTime: 1308145557Sharti return (string_get(value, t->reftime, 8)); 1309145557Sharti 1310145557Sharti case LEAF_ntpPeersOrgTime: 1311145557Sharti return (string_get(value, t->orgtime, 8)); 1312145557Sharti 1313145557Sharti case LEAF_ntpPeersReceiveTime: 1314145557Sharti return (string_get(value, t->rcvtime, 8)); 1315145557Sharti 1316145557Sharti case LEAF_ntpPeersTransmitTime: 1317145557Sharti return (string_get(value, t->xmttime, 8)); 1318145557Sharti 1319145557Sharti case LEAF_ntpPeersReach: 1320145557Sharti value->v.uint32 = t->reach; 1321145557Sharti break; 1322145557Sharti 1323145557Sharti case LEAF_ntpPeersTimer: 1324145557Sharti value->v.uint32 = t->timer; 1325145557Sharti break; 1326145557Sharti 1327145557Sharti case LEAF_ntpPeersOffset: 1328145557Sharti return (string_get(value, t->offset, -1)); 1329145557Sharti 1330145557Sharti case LEAF_ntpPeersDelay: 1331145557Sharti return (string_get(value, t->delay, -1)); 1332145557Sharti 1333145557Sharti case LEAF_ntpPeersDispersion: 1334145557Sharti return (string_get(value, t->dispersion, -1)); 1335145557Sharti 1336145557Sharti default: 1337145557Sharti abort(); 1338145557Sharti } 1339145557Sharti return (SNMP_ERR_NOERROR); 1340145557Sharti} 1341145557Sharti 1342145557Sharti 1343145557Shartiint 1344145557Shartiop_ntpFilterPeersVarTable(struct snmp_context *ctx __unused, 1345145557Sharti struct snmp_value *value, u_int sub, u_int iidx, enum snmp_op op) 1346145557Sharti{ 1347145557Sharti asn_subid_t which = value->var.subs[sub - 1]; 1348145557Sharti uint32_t peer; 1349145557Sharti struct peer *t; 1350145557Sharti 1351145557Sharti if (this_tick > peers_tick) { 1352145557Sharti if (fetch_peers() == -1) 1353145557Sharti return (SNMP_ERR_GENERR); 1354145557Sharti peers_tick = this_tick; 1355145557Sharti } 1356145557Sharti 1357145557Sharti switch (op) { 1358145557Sharti 1359145557Sharti case SNMP_OP_GETNEXT: 1360145557Sharti t = NEXT_OBJECT_INT(&peers, &value->var, sub); 1361145557Sharti if (t == NULL) 1362145557Sharti return (SNMP_ERR_NOSUCHNAME); 1363145557Sharti value->var.len = sub + 1; 1364145557Sharti value->var.subs[sub] = t->index; 1365145557Sharti break; 1366145557Sharti 1367145557Sharti case SNMP_OP_GET: 1368145557Sharti t = FIND_OBJECT_INT(&peers, &value->var, sub); 1369145557Sharti if (t == NULL) 1370145557Sharti return (SNMP_ERR_NOSUCHNAME); 1371145557Sharti break; 1372145557Sharti 1373145557Sharti case SNMP_OP_SET: 1374145557Sharti if (index_decode(&value->var, sub, iidx, &peer)) 1375145557Sharti return (SNMP_ERR_NO_CREATION); 1376145557Sharti t = FIND_OBJECT_INT(&peers, &value->var, sub); 1377145557Sharti if (t != NULL) 1378145557Sharti return (SNMP_ERR_NOT_WRITEABLE); 1379145557Sharti return (SNMP_ERR_NO_CREATION); 1380145557Sharti 1381145557Sharti case SNMP_OP_COMMIT: 1382145557Sharti case SNMP_OP_ROLLBACK: 1383145557Sharti default: 1384145557Sharti abort(); 1385145557Sharti } 1386145557Sharti 1387145557Sharti /* 1388145557Sharti * Come here for GET and COMMIT 1389145557Sharti */ 1390145557Sharti switch (which) { 1391145557Sharti 1392145557Sharti case LEAF_ntpFilterValidEntries: 1393145557Sharti value->v.integer = t->filt_entries; 1394145557Sharti break; 1395145557Sharti 1396145557Sharti default: 1397145557Sharti abort(); 1398145557Sharti } 1399145557Sharti return (SNMP_ERR_NOERROR); 1400145557Sharti} 1401145557Sharti 1402145557Shartiint 1403145557Shartiop_ntpFilterRegisterTable(struct snmp_context *ctx __unused, struct snmp_value *value __unused, 1404145557Sharti u_int sub __unused, u_int iidx __unused, enum snmp_op op __unused) 1405145557Sharti{ 1406145557Sharti asn_subid_t which = value->var.subs[sub - 1]; 1407145557Sharti uint32_t peer; 1408145557Sharti uint32_t filt; 1409145557Sharti struct filt *t; 1410145557Sharti 1411145557Sharti if (this_tick > peers_tick) { 1412145557Sharti if (fetch_peers() == -1) 1413145557Sharti return (SNMP_ERR_GENERR); 1414145557Sharti peers_tick = this_tick; 1415145557Sharti } 1416145557Sharti 1417145557Sharti switch (op) { 1418145557Sharti 1419145557Sharti case SNMP_OP_GETNEXT: 1420145557Sharti t = NEXT_OBJECT_OID(&filts, &value->var, sub); 1421145557Sharti if (t == NULL) 1422145557Sharti return (SNMP_ERR_NOSUCHNAME); 1423145557Sharti index_append(&value->var, sub, &t->index); 1424145557Sharti break; 1425145557Sharti 1426145557Sharti case SNMP_OP_GET: 1427145557Sharti t = FIND_OBJECT_OID(&filts, &value->var, sub); 1428145557Sharti if (t == NULL) 1429145557Sharti return (SNMP_ERR_NOSUCHNAME); 1430145557Sharti break; 1431145557Sharti 1432145557Sharti case SNMP_OP_SET: 1433145557Sharti if (index_decode(&value->var, sub, iidx, &peer, &filt)) 1434145557Sharti return (SNMP_ERR_NO_CREATION); 1435145557Sharti t = FIND_OBJECT_OID(&filts, &value->var, sub); 1436145557Sharti if (t != NULL) 1437145557Sharti return (SNMP_ERR_NOT_WRITEABLE); 1438145557Sharti return (SNMP_ERR_NO_CREATION); 1439145557Sharti 1440145557Sharti case SNMP_OP_COMMIT: 1441145557Sharti case SNMP_OP_ROLLBACK: 1442145557Sharti default: 1443145557Sharti abort(); 1444145557Sharti } 1445145557Sharti 1446145557Sharti /* 1447145557Sharti * Come here for GET and COMMIT 1448145557Sharti */ 1449145557Sharti switch (which) { 1450145557Sharti 1451145557Sharti case LEAF_ntpFilterPeersOffset: 1452145557Sharti return (string_get(value, t->offset, -1)); 1453145557Sharti 1454145557Sharti case LEAF_ntpFilterPeersDelay: 1455145557Sharti return (string_get(value, t->delay, -1)); 1456145557Sharti 1457145557Sharti case LEAF_ntpFilterPeersDispersion: 1458145557Sharti return (string_get(value, t->dispersion, -1)); 1459145557Sharti 1460145557Sharti default: 1461145557Sharti abort(); 1462145557Sharti } 1463145557Sharti return (SNMP_ERR_NOERROR); 1464145557Sharti} 1465145557Sharti 1466145557Sharti/* 1467145557Sharti * System variables - read-only scalars only. 1468145557Sharti */ 1469145557Shartiint 1470145557Shartiop_begemot_ntp(struct snmp_context *ctx __unused, struct snmp_value *value, 1471145557Sharti u_int sub, u_int iidx __unused, enum snmp_op op) 1472145557Sharti{ 1473145557Sharti asn_subid_t which = value->var.subs[sub - 1]; 1474145557Sharti int ret; 1475145557Sharti 1476145557Sharti switch (op) { 1477145557Sharti 1478145557Sharti case SNMP_OP_GETNEXT: 1479145557Sharti abort(); 1480145557Sharti 1481145557Sharti case SNMP_OP_GET: 1482145557Sharti switch (which) { 1483145557Sharti 1484145557Sharti case LEAF_begemotNtpHost: 1485145557Sharti return (string_get(value, ntp_host, -1)); 1486145557Sharti 1487145557Sharti case LEAF_begemotNtpPort: 1488145557Sharti return (string_get(value, ntp_port, -1)); 1489145557Sharti 1490145557Sharti case LEAF_begemotNtpTimeout: 1491145557Sharti value->v.uint32 = ntp_timeout; 1492145557Sharti return (SNMP_ERR_NOERROR); 1493145557Sharti 1494145557Sharti case LEAF_begemotNtpDebug: 1495145557Sharti value->v.uint32 = ntp_debug; 1496145557Sharti return (SNMP_ERR_NOERROR); 1497145557Sharti 1498145557Sharti case LEAF_begemotNtpJitter: 1499145557Sharti if (this_tick > sysinfo_tick) { 1500145557Sharti if (fetch_sysinfo() == -1) 1501145557Sharti return (SNMP_ERR_GENERR); 1502145557Sharti sysinfo_tick = this_tick; 1503145557Sharti } 1504145557Sharti if (!sysb_jitter) 1505145557Sharti return (SNMP_ERR_NOSUCHNAME); 1506145557Sharti value->v.counter64 = sys_jitter / 1000 * (1ULL << 32); 1507145557Sharti return (SNMP_ERR_NOERROR); 1508145557Sharti 1509145557Sharti case LEAF_begemotNtpStability: 1510145557Sharti if (this_tick > sysinfo_tick) { 1511145557Sharti if (fetch_sysinfo() == -1) 1512145557Sharti return (SNMP_ERR_GENERR); 1513145557Sharti sysinfo_tick = this_tick; 1514145557Sharti } 1515145557Sharti if (!sysb_stability) 1516145557Sharti return (SNMP_ERR_NOSUCHNAME); 1517145557Sharti value->v.counter64 = sys_stability * (1ULL << 32); 1518145557Sharti return (SNMP_ERR_NOERROR); 1519145557Sharti } 1520145557Sharti abort(); 1521145557Sharti 1522145557Sharti case SNMP_OP_SET: 1523145557Sharti switch (which) { 1524145557Sharti 1525145557Sharti case LEAF_begemotNtpHost: 1526150920Sharti /* only at initialization */ 1527145557Sharti if (community != COMM_INITIALIZE) 1528145557Sharti return (SNMP_ERR_NOT_WRITEABLE); 1529145557Sharti 1530145557Sharti if ((ret = string_save(value, ctx, -1, &ntp_host)) 1531145557Sharti != SNMP_ERR_NOERROR) 1532145557Sharti return (ret); 1533145557Sharti return (SNMP_ERR_NOERROR); 1534145557Sharti 1535145557Sharti case LEAF_begemotNtpPort: 1536150920Sharti /* only at initialization */ 1537145557Sharti if (community != COMM_INITIALIZE) 1538145557Sharti return (SNMP_ERR_NOT_WRITEABLE); 1539145557Sharti 1540145557Sharti if ((ret = string_save(value, ctx, -1, &ntp_port)) 1541145557Sharti != SNMP_ERR_NOERROR) 1542145557Sharti return (ret); 1543145557Sharti return (SNMP_ERR_NOERROR); 1544145557Sharti 1545145557Sharti case LEAF_begemotNtpTimeout: 1546145557Sharti ctx->scratch->int1 = ntp_timeout; 1547145557Sharti if (value->v.uint32 < 1) 1548145557Sharti return (SNMP_ERR_WRONG_VALUE); 1549145557Sharti ntp_timeout = value->v.integer; 1550145557Sharti return (SNMP_ERR_NOERROR); 1551145557Sharti 1552145557Sharti case LEAF_begemotNtpDebug: 1553145557Sharti ctx->scratch->int1 = ntp_debug; 1554145557Sharti ntp_debug = value->v.integer; 1555145557Sharti return (SNMP_ERR_NOERROR); 1556145557Sharti } 1557145557Sharti abort(); 1558145557Sharti 1559145557Sharti case SNMP_OP_ROLLBACK: 1560145557Sharti switch (which) { 1561145557Sharti 1562145557Sharti case LEAF_begemotNtpHost: 1563145557Sharti string_rollback(ctx, &ntp_host); 1564145557Sharti return (SNMP_ERR_NOERROR); 1565145557Sharti 1566145557Sharti case LEAF_begemotNtpPort: 1567145557Sharti string_rollback(ctx, &ntp_port); 1568145557Sharti return (SNMP_ERR_NOERROR); 1569145557Sharti 1570145557Sharti case LEAF_begemotNtpTimeout: 1571145557Sharti ntp_timeout = ctx->scratch->int1; 1572145557Sharti return (SNMP_ERR_NOERROR); 1573145557Sharti 1574145557Sharti case LEAF_begemotNtpDebug: 1575145557Sharti ntp_debug = ctx->scratch->int1; 1576145557Sharti return (SNMP_ERR_NOERROR); 1577145557Sharti } 1578145557Sharti abort(); 1579145557Sharti 1580145557Sharti case SNMP_OP_COMMIT: 1581145557Sharti switch (which) { 1582145557Sharti 1583145557Sharti case LEAF_begemotNtpHost: 1584145557Sharti string_commit(ctx); 1585145557Sharti return (SNMP_ERR_NOERROR); 1586145557Sharti 1587145557Sharti case LEAF_begemotNtpPort: 1588145557Sharti string_commit(ctx); 1589145557Sharti return (SNMP_ERR_NOERROR); 1590145557Sharti 1591145557Sharti case LEAF_begemotNtpTimeout: 1592145557Sharti case LEAF_begemotNtpDebug: 1593145557Sharti return (SNMP_ERR_NOERROR); 1594145557Sharti } 1595145557Sharti abort(); 1596145557Sharti } 1597145557Sharti abort(); 1598145557Sharti} 1599