In the FreeBSD-specific code checking for a bound IPv4 socket, make sure it is not a Unix domain address to avoid reading uninitialized IP-specific fields. This fixes an error reported by valgrind.
1811 lines
56 KiB
C
1811 lines
56 KiB
C
/*
|
|
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
|
|
|
**********************************************************************
|
|
* Copyright (C) Richard P. Curnow 1997-2003
|
|
* Copyright (C) Miroslav Lichvar 2009-2016, 2018-2021
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of version 2 of the GNU General Public License as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
**********************************************************************
|
|
|
|
=======================================================================
|
|
|
|
Command and monitoring module in the main program
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "sysincl.h"
|
|
|
|
#include "cmdmon.h"
|
|
#include "candm.h"
|
|
#include "sched.h"
|
|
#include "util.h"
|
|
#include "logging.h"
|
|
#include "keys.h"
|
|
#include "ntp_sources.h"
|
|
#include "ntp_core.h"
|
|
#include "smooth.h"
|
|
#include "socket.h"
|
|
#include "sources.h"
|
|
#include "sourcestats.h"
|
|
#include "reference.h"
|
|
#include "manual.h"
|
|
#include "memory.h"
|
|
#include "nts_ke_server.h"
|
|
#include "local.h"
|
|
#include "addrfilt.h"
|
|
#include "conf.h"
|
|
#include "rtc.h"
|
|
#include "pktlength.h"
|
|
#include "clientlog.h"
|
|
#include "refclock.h"
|
|
|
|
/* ================================================== */
|
|
|
|
#define INVALID_SOCK_FD (-5)
|
|
|
|
/* File descriptors for command and monitoring sockets */
|
|
static int sock_fdu;
|
|
static int sock_fd4;
|
|
static int sock_fd6;
|
|
|
|
/* Flag indicating the IPv4 socket is bound to an address */
|
|
static int bound_sock_fd4;
|
|
|
|
/* Flag indicating whether this module has been initialised or not */
|
|
static int initialised = 0;
|
|
|
|
/* ================================================== */
|
|
/* Array of permission levels for command types */
|
|
|
|
static const char permissions[] = {
|
|
PERMIT_OPEN, /* NULL */
|
|
PERMIT_AUTH, /* ONLINE */
|
|
PERMIT_AUTH, /* OFFLINE */
|
|
PERMIT_AUTH, /* BURST */
|
|
PERMIT_AUTH, /* MODIFY_MINPOLL */
|
|
PERMIT_AUTH, /* MODIFY_MAXPOLL */
|
|
PERMIT_AUTH, /* DUMP */
|
|
PERMIT_AUTH, /* MODIFY_MAXDELAY */
|
|
PERMIT_AUTH, /* MODIFY_MAXDELAYRATIO */
|
|
PERMIT_AUTH, /* MODIFY_MAXUPDATESKEW */
|
|
PERMIT_OPEN, /* LOGON */
|
|
PERMIT_AUTH, /* SETTIME */
|
|
PERMIT_AUTH, /* LOCAL */
|
|
PERMIT_AUTH, /* MANUAL */
|
|
PERMIT_OPEN, /* N_SOURCES */
|
|
PERMIT_OPEN, /* SOURCE_DATA */
|
|
PERMIT_AUTH, /* REKEY */
|
|
PERMIT_AUTH, /* ALLOW */
|
|
PERMIT_AUTH, /* ALLOWALL */
|
|
PERMIT_AUTH, /* DENY */
|
|
PERMIT_AUTH, /* DENYALL */
|
|
PERMIT_AUTH, /* CMDALLOW */
|
|
PERMIT_AUTH, /* CMDALLOWALL */
|
|
PERMIT_AUTH, /* CMDDENY */
|
|
PERMIT_AUTH, /* CMDDENYALL */
|
|
PERMIT_AUTH, /* ACCHECK */
|
|
PERMIT_AUTH, /* CMDACCHECK */
|
|
PERMIT_AUTH, /* ADD_SERVER */
|
|
PERMIT_AUTH, /* ADD_PEER */
|
|
PERMIT_AUTH, /* DEL_SOURCE */
|
|
PERMIT_AUTH, /* WRITERTC */
|
|
PERMIT_AUTH, /* DFREQ */
|
|
PERMIT_AUTH, /* DOFFSET */
|
|
PERMIT_OPEN, /* TRACKING */
|
|
PERMIT_OPEN, /* SOURCESTATS */
|
|
PERMIT_OPEN, /* RTCREPORT */
|
|
PERMIT_AUTH, /* TRIMRTC */
|
|
PERMIT_AUTH, /* CYCLELOGS */
|
|
PERMIT_AUTH, /* SUBNETS_ACCESSED */
|
|
PERMIT_AUTH, /* CLIENT_ACCESSES (by subnet) */
|
|
PERMIT_AUTH, /* CLIENT_ACCESSES_BY_INDEX */
|
|
PERMIT_OPEN, /* MANUAL_LIST */
|
|
PERMIT_AUTH, /* MANUAL_DELETE */
|
|
PERMIT_AUTH, /* MAKESTEP */
|
|
PERMIT_OPEN, /* ACTIVITY */
|
|
PERMIT_AUTH, /* MODIFY_MINSTRATUM */
|
|
PERMIT_AUTH, /* MODIFY_POLLTARGET */
|
|
PERMIT_AUTH, /* MODIFY_MAXDELAYDEVRATIO */
|
|
PERMIT_AUTH, /* RESELECT */
|
|
PERMIT_AUTH, /* RESELECTDISTANCE */
|
|
PERMIT_AUTH, /* MODIFY_MAKESTEP */
|
|
PERMIT_OPEN, /* SMOOTHING */
|
|
PERMIT_AUTH, /* SMOOTHTIME */
|
|
PERMIT_AUTH, /* REFRESH */
|
|
PERMIT_AUTH, /* SERVER_STATS */
|
|
PERMIT_AUTH, /* CLIENT_ACCESSES_BY_INDEX2 */
|
|
PERMIT_AUTH, /* LOCAL2 */
|
|
PERMIT_AUTH, /* NTP_DATA */
|
|
PERMIT_AUTH, /* ADD_SERVER2 */
|
|
PERMIT_AUTH, /* ADD_PEER2 */
|
|
PERMIT_AUTH, /* ADD_SERVER3 */
|
|
PERMIT_AUTH, /* ADD_PEER3 */
|
|
PERMIT_AUTH, /* SHUTDOWN */
|
|
PERMIT_AUTH, /* ONOFFLINE */
|
|
PERMIT_AUTH, /* ADD_SOURCE */
|
|
PERMIT_OPEN, /* NTP_SOURCE_NAME */
|
|
PERMIT_AUTH, /* RESET_SOURCES */
|
|
PERMIT_AUTH, /* AUTH_DATA */
|
|
PERMIT_AUTH, /* CLIENT_ACCESSES_BY_INDEX3 */
|
|
PERMIT_AUTH, /* SELECT_DATA */
|
|
PERMIT_AUTH, /* RELOAD_SOURCES */
|
|
PERMIT_AUTH, /* DOFFSET2 */
|
|
};
|
|
|
|
/* ================================================== */
|
|
|
|
/* This authorisation table is used for checking whether particular
|
|
machines are allowed to make command and monitoring requests. */
|
|
static ADF_AuthTable access_auth_table;
|
|
|
|
/* ================================================== */
|
|
/* Forward prototypes */
|
|
static void read_from_cmd_socket(int sock_fd, int event, void *anything);
|
|
|
|
/* ================================================== */
|
|
|
|
static int
|
|
open_socket(int family)
|
|
{
|
|
const char *local_path, *iface;
|
|
IPSockAddr local_addr;
|
|
int sock_fd, port;
|
|
|
|
switch (family) {
|
|
case IPADDR_INET4:
|
|
case IPADDR_INET6:
|
|
port = CNF_GetCommandPort();
|
|
if (port == 0 || !SCK_IsIpFamilyEnabled(family))
|
|
return INVALID_SOCK_FD;
|
|
|
|
CNF_GetBindCommandAddress(family, &local_addr.ip_addr);
|
|
local_addr.port = port;
|
|
iface = CNF_GetBindCommandInterface();
|
|
|
|
sock_fd = SCK_OpenUdpSocket(NULL, &local_addr, iface, SCK_FLAG_RX_DEST_ADDR);
|
|
if (sock_fd < 0) {
|
|
LOG(LOGS_ERR, "Could not open command socket on %s",
|
|
UTI_IPSockAddrToString(&local_addr));
|
|
return INVALID_SOCK_FD;
|
|
}
|
|
|
|
if (family == IPADDR_INET4)
|
|
bound_sock_fd4 = local_addr.ip_addr.addr.in4 != INADDR_ANY;
|
|
|
|
break;
|
|
case IPADDR_UNSPEC:
|
|
local_path = CNF_GetBindCommandPath();
|
|
|
|
sock_fd = SCK_OpenUnixDatagramSocket(NULL, local_path, 0);
|
|
if (sock_fd < 0) {
|
|
LOG(LOGS_ERR, "Could not open command socket on %s", local_path);
|
|
return INVALID_SOCK_FD;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
|
|
/* Register handler for read events on the socket */
|
|
SCH_AddFileHandler(sock_fd, SCH_FILE_INPUT, read_from_cmd_socket, NULL);
|
|
|
|
return sock_fd;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
do_size_checks(void)
|
|
{
|
|
int i, request_length, padding_length, reply_length;
|
|
CMD_Request request;
|
|
CMD_Reply reply;
|
|
|
|
assert(offsetof(CMD_Request, data) == 20);
|
|
assert(offsetof(CMD_Reply, data) == 28);
|
|
|
|
for (i = 0; i < N_REQUEST_TYPES; i++) {
|
|
request.version = PROTO_VERSION_NUMBER;
|
|
request.command = htons(i);
|
|
request_length = PKL_CommandLength(&request);
|
|
padding_length = PKL_CommandPaddingLength(&request);
|
|
if (padding_length > MAX_PADDING_LENGTH || padding_length > request_length ||
|
|
request_length > sizeof (CMD_Request) ||
|
|
(request_length && request_length < offsetof(CMD_Request, data)))
|
|
assert(0);
|
|
}
|
|
|
|
for (i = 1; i < N_REPLY_TYPES; i++) {
|
|
reply.reply = htons(i);
|
|
reply.status = STT_SUCCESS;
|
|
reply_length = PKL_ReplyLength(&reply);
|
|
if ((reply_length && reply_length < offsetof(CMD_Reply, data)) ||
|
|
reply_length > sizeof (CMD_Reply))
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CAM_Initialise(void)
|
|
{
|
|
assert(!initialised);
|
|
assert(sizeof (permissions) / sizeof (permissions[0]) == N_REQUEST_TYPES);
|
|
do_size_checks();
|
|
|
|
initialised = 1;
|
|
|
|
bound_sock_fd4 = 0;
|
|
|
|
sock_fdu = INVALID_SOCK_FD;
|
|
sock_fd4 = open_socket(IPADDR_INET4);
|
|
sock_fd6 = open_socket(IPADDR_INET6);
|
|
|
|
access_auth_table = ADF_CreateTable();
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CAM_Finalise(void)
|
|
{
|
|
if (sock_fdu != INVALID_SOCK_FD) {
|
|
SCH_RemoveFileHandler(sock_fdu);
|
|
SCK_RemoveSocket(sock_fdu);
|
|
SCK_CloseSocket(sock_fdu);
|
|
sock_fdu = INVALID_SOCK_FD;
|
|
}
|
|
|
|
if (sock_fd4 != INVALID_SOCK_FD) {
|
|
SCH_RemoveFileHandler(sock_fd4);
|
|
SCK_CloseSocket(sock_fd4);
|
|
sock_fd4 = INVALID_SOCK_FD;
|
|
}
|
|
|
|
if (sock_fd6 != INVALID_SOCK_FD) {
|
|
SCH_RemoveFileHandler(sock_fd6);
|
|
SCK_CloseSocket(sock_fd6);
|
|
sock_fd6 = INVALID_SOCK_FD;
|
|
}
|
|
|
|
ADF_DestroyTable(access_auth_table);
|
|
|
|
initialised = 0;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
void
|
|
CAM_OpenUnixSocket(void)
|
|
{
|
|
/* This is separated from CAM_Initialise() as it needs to be called when
|
|
the process has already dropped the root privileges */
|
|
if (CNF_GetBindCommandPath())
|
|
sock_fdu = open_socket(IPADDR_UNSPEC);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
transmit_reply(int sock_fd, int request_length, SCK_Message *message)
|
|
{
|
|
message->length = PKL_ReplyLength((CMD_Reply *)message->data);
|
|
|
|
if (request_length < message->length) {
|
|
DEBUG_LOG("Response longer than request req_len=%d res_len=%d",
|
|
request_length, message->length);
|
|
return;
|
|
}
|
|
|
|
/* Don't require responses to non-link-local addresses to use the same
|
|
interface */
|
|
if (message->addr_type == SCK_ADDR_IP &&
|
|
!SCK_IsLinkLocalIPAddress(&message->remote_addr.ip.ip_addr))
|
|
message->if_index = INVALID_IF_INDEX;
|
|
|
|
#if !defined(HAVE_IN_PKTINFO) && defined(IP_SENDSRCADDR)
|
|
/* On FreeBSD a local IPv4 address cannot be specified on bound socket */
|
|
if (message->addr_type == SCK_ADDR_IP && message->local_addr.ip.family == IPADDR_INET4 &&
|
|
(sock_fd != sock_fd4 || bound_sock_fd4))
|
|
message->local_addr.ip.family = IPADDR_UNSPEC;
|
|
#endif
|
|
|
|
if (!SCK_SendMessage(sock_fd, message, 0))
|
|
return;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_dump(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
SRC_DumpSources();
|
|
NSR_DumpAuthData();
|
|
NKS_DumpKeys();
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_online(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
IPAddr address, mask;
|
|
|
|
UTI_IPNetworkToHost(&rx_message->data.online.mask, &mask);
|
|
UTI_IPNetworkToHost(&rx_message->data.online.address, &address);
|
|
if (!NSR_SetConnectivity(&mask, &address, SRC_ONLINE))
|
|
tx_message->status = htons(STT_NOSUCHSOURCE);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_offline(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
IPAddr address, mask;
|
|
|
|
UTI_IPNetworkToHost(&rx_message->data.offline.mask, &mask);
|
|
UTI_IPNetworkToHost(&rx_message->data.offline.address, &address);
|
|
if (!NSR_SetConnectivity(&mask, &address, SRC_OFFLINE))
|
|
tx_message->status = htons(STT_NOSUCHSOURCE);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_onoffline(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
IPAddr address, mask;
|
|
|
|
address.family = mask.family = IPADDR_UNSPEC;
|
|
if (!NSR_SetConnectivity(&mask, &address, SRC_MAYBE_ONLINE))
|
|
;
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_burst(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
IPAddr address, mask;
|
|
|
|
UTI_IPNetworkToHost(&rx_message->data.burst.mask, &mask);
|
|
UTI_IPNetworkToHost(&rx_message->data.burst.address, &address);
|
|
if (!NSR_InitiateSampleBurst(ntohl(rx_message->data.burst.n_good_samples),
|
|
ntohl(rx_message->data.burst.n_total_samples),
|
|
&mask, &address))
|
|
tx_message->status = htons(STT_NOSUCHSOURCE);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_modify_minpoll(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
IPAddr address;
|
|
|
|
UTI_IPNetworkToHost(&rx_message->data.modify_minpoll.address, &address);
|
|
if (!NSR_ModifyMinpoll(&address,
|
|
ntohl(rx_message->data.modify_minpoll.new_minpoll)))
|
|
tx_message->status = htons(STT_NOSUCHSOURCE);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_modify_maxpoll(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
IPAddr address;
|
|
|
|
UTI_IPNetworkToHost(&rx_message->data.modify_minpoll.address, &address);
|
|
if (!NSR_ModifyMaxpoll(&address,
|
|
ntohl(rx_message->data.modify_minpoll.new_minpoll)))
|
|
tx_message->status = htons(STT_NOSUCHSOURCE);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_modify_maxdelay(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
IPAddr address;
|
|
|
|
UTI_IPNetworkToHost(&rx_message->data.modify_maxdelay.address, &address);
|
|
if (!NSR_ModifyMaxdelay(&address,
|
|
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelay.new_max_delay)))
|
|
tx_message->status = htons(STT_NOSUCHSOURCE);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_modify_maxdelayratio(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
IPAddr address;
|
|
|
|
UTI_IPNetworkToHost(&rx_message->data.modify_maxdelayratio.address, &address);
|
|
if (!NSR_ModifyMaxdelayratio(&address,
|
|
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelayratio.new_max_delay_ratio)))
|
|
tx_message->status = htons(STT_NOSUCHSOURCE);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_modify_maxdelaydevratio(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
IPAddr address;
|
|
|
|
UTI_IPNetworkToHost(&rx_message->data.modify_maxdelaydevratio.address, &address);
|
|
if (!NSR_ModifyMaxdelaydevratio(&address,
|
|
UTI_FloatNetworkToHost(rx_message->data.modify_maxdelaydevratio.new_max_delay_dev_ratio)))
|
|
tx_message->status = htons(STT_NOSUCHSOURCE);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_modify_minstratum(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
IPAddr address;
|
|
|
|
UTI_IPNetworkToHost(&rx_message->data.modify_minpoll.address, &address);
|
|
if (!NSR_ModifyMinstratum(&address,
|
|
ntohl(rx_message->data.modify_minstratum.new_min_stratum)))
|
|
tx_message->status = htons(STT_NOSUCHSOURCE);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_modify_polltarget(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
IPAddr address;
|
|
|
|
UTI_IPNetworkToHost(&rx_message->data.modify_polltarget.address, &address);
|
|
if (!NSR_ModifyPolltarget(&address,
|
|
ntohl(rx_message->data.modify_polltarget.new_poll_target)))
|
|
tx_message->status = htons(STT_NOSUCHSOURCE);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_modify_maxupdateskew(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
REF_ModifyMaxupdateskew(UTI_FloatNetworkToHost(rx_message->data.modify_maxupdateskew.new_max_update_skew));
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_modify_makestep(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
REF_ModifyMakestep(ntohl(rx_message->data.modify_makestep.limit),
|
|
UTI_FloatNetworkToHost(rx_message->data.modify_makestep.threshold));
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_settime(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
struct timespec ts;
|
|
double offset, dfreq_ppm, new_afreq_ppm;
|
|
UTI_TimespecNetworkToHost(&rx_message->data.settime.ts, &ts);
|
|
if (!MNL_IsEnabled()) {
|
|
tx_message->status = htons(STT_NOTENABLED);
|
|
} else if (MNL_AcceptTimestamp(&ts, &offset, &dfreq_ppm, &new_afreq_ppm)) {
|
|
tx_message->reply = htons(RPY_MANUAL_TIMESTAMP2);
|
|
tx_message->data.manual_timestamp.offset = UTI_FloatHostToNetwork(offset);
|
|
tx_message->data.manual_timestamp.dfreq_ppm = UTI_FloatHostToNetwork(dfreq_ppm);
|
|
tx_message->data.manual_timestamp.new_afreq_ppm = UTI_FloatHostToNetwork(new_afreq_ppm);
|
|
} else {
|
|
tx_message->status = htons(STT_FAILED);
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_local(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
if (ntohl(rx_message->data.local.on_off)) {
|
|
REF_EnableLocal(ntohl(rx_message->data.local.stratum),
|
|
UTI_FloatNetworkToHost(rx_message->data.local.distance),
|
|
ntohl(rx_message->data.local.orphan));
|
|
} else {
|
|
REF_DisableLocal();
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_manual(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
int option;
|
|
option = ntohl(rx_message->data.manual.option);
|
|
switch (option) {
|
|
case 0:
|
|
MNL_Disable();
|
|
break;
|
|
case 1:
|
|
MNL_Enable();
|
|
break;
|
|
case 2:
|
|
MNL_Reset();
|
|
break;
|
|
default:
|
|
tx_message->status = htons(STT_INVALID);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_n_sources(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
int n_sources;
|
|
n_sources = SRC_ReadNumberOfSources();
|
|
tx_message->reply = htons(RPY_N_SOURCES);
|
|
tx_message->data.n_sources.n_sources = htonl(n_sources);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
RPT_SourceReport report;
|
|
struct timespec now_corr;
|
|
|
|
/* Get data */
|
|
SCH_GetLastEventTime(&now_corr, NULL, NULL);
|
|
if (SRC_ReportSource(ntohl(rx_message->data.source_data.index), &report, &now_corr)) {
|
|
switch (SRC_GetType(ntohl(rx_message->data.source_data.index))) {
|
|
case SRC_NTP:
|
|
NSR_ReportSource(&report, &now_corr);
|
|
break;
|
|
case SRC_REFCLOCK:
|
|
RCL_ReportSource(&report, &now_corr);
|
|
break;
|
|
}
|
|
|
|
tx_message->reply = htons(RPY_SOURCE_DATA);
|
|
|
|
UTI_IPHostToNetwork(&report.ip_addr, &tx_message->data.source_data.ip_addr);
|
|
tx_message->data.source_data.stratum = htons(report.stratum);
|
|
tx_message->data.source_data.poll = htons(report.poll);
|
|
switch (report.state) {
|
|
case RPT_NONSELECTABLE:
|
|
tx_message->data.source_data.state = htons(RPY_SD_ST_NONSELECTABLE);
|
|
break;
|
|
case RPT_FALSETICKER:
|
|
tx_message->data.source_data.state = htons(RPY_SD_ST_FALSETICKER);
|
|
break;
|
|
case RPT_JITTERY:
|
|
tx_message->data.source_data.state = htons(RPY_SD_ST_JITTERY);
|
|
break;
|
|
case RPT_SELECTABLE:
|
|
tx_message->data.source_data.state = htons(RPY_SD_ST_SELECTABLE);
|
|
break;
|
|
case RPT_UNSELECTED:
|
|
tx_message->data.source_data.state = htons(RPY_SD_ST_UNSELECTED);
|
|
break;
|
|
case RPT_SELECTED:
|
|
tx_message->data.source_data.state = htons(RPY_SD_ST_SELECTED);
|
|
break;
|
|
}
|
|
switch (report.mode) {
|
|
case RPT_NTP_CLIENT:
|
|
tx_message->data.source_data.mode = htons(RPY_SD_MD_CLIENT);
|
|
break;
|
|
case RPT_NTP_PEER:
|
|
tx_message->data.source_data.mode = htons(RPY_SD_MD_PEER);
|
|
break;
|
|
case RPT_LOCAL_REFERENCE:
|
|
tx_message->data.source_data.mode = htons(RPY_SD_MD_REF);
|
|
break;
|
|
}
|
|
tx_message->data.source_data.flags = htons(0);
|
|
tx_message->data.source_data.reachability = htons(report.reachability);
|
|
tx_message->data.source_data.since_sample = htonl(report.latest_meas_ago);
|
|
tx_message->data.source_data.orig_latest_meas = UTI_FloatHostToNetwork(report.orig_latest_meas);
|
|
tx_message->data.source_data.latest_meas = UTI_FloatHostToNetwork(report.latest_meas);
|
|
tx_message->data.source_data.latest_meas_err = UTI_FloatHostToNetwork(report.latest_meas_err);
|
|
} else {
|
|
tx_message->status = htons(STT_NOSUCHSOURCE);
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_rekey(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
KEY_Reload();
|
|
NKS_ReloadKeys();
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_allowdeny(CMD_Request *rx_message, CMD_Reply *tx_message, int allow, int all)
|
|
{
|
|
IPAddr ip;
|
|
int subnet_bits;
|
|
|
|
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
|
|
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
|
|
if (!NCR_AddAccessRestriction(&ip, subnet_bits, allow, all))
|
|
tx_message->status = htons(STT_BADSUBNET);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_cmdallowdeny(CMD_Request *rx_message, CMD_Reply *tx_message, int allow, int all)
|
|
{
|
|
IPAddr ip;
|
|
int subnet_bits;
|
|
|
|
UTI_IPNetworkToHost(&rx_message->data.allow_deny.ip, &ip);
|
|
subnet_bits = ntohl(rx_message->data.allow_deny.subnet_bits);
|
|
if (!CAM_AddAccessRestriction(&ip, subnet_bits, allow, all))
|
|
tx_message->status = htons(STT_BADSUBNET);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_accheck(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
IPAddr ip;
|
|
UTI_IPNetworkToHost(&rx_message->data.ac_check.ip, &ip);
|
|
if (NCR_CheckAccessRestriction(&ip)) {
|
|
tx_message->status = htons(STT_ACCESSALLOWED);
|
|
} else {
|
|
tx_message->status = htons(STT_ACCESSDENIED);
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_cmdaccheck(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
IPAddr ip;
|
|
UTI_IPNetworkToHost(&rx_message->data.ac_check.ip, &ip);
|
|
if (CAM_CheckAccessRestriction(&ip)) {
|
|
tx_message->status = htons(STT_ACCESSALLOWED);
|
|
} else {
|
|
tx_message->status = htons(STT_ACCESSDENIED);
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_add_source(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
NTP_Source_Type type;
|
|
SourceParameters params;
|
|
NSR_Status status;
|
|
char *name;
|
|
int pool, port;
|
|
|
|
switch (ntohl(rx_message->data.ntp_source.type)) {
|
|
case REQ_ADDSRC_SERVER:
|
|
type = NTP_SERVER;
|
|
pool = 0;
|
|
break;
|
|
case REQ_ADDSRC_PEER:
|
|
type = NTP_PEER;
|
|
pool = 0;
|
|
break;
|
|
case REQ_ADDSRC_POOL:
|
|
type = NTP_SERVER;
|
|
pool = 1;
|
|
break;
|
|
default:
|
|
tx_message->status = htons(STT_INVALID);
|
|
return;
|
|
}
|
|
|
|
name = (char *)rx_message->data.ntp_source.name;
|
|
|
|
/* Make sure the name is terminated */
|
|
if (name[sizeof (rx_message->data.ntp_source.name) - 1] != '\0') {
|
|
tx_message->status = htons(STT_INVALIDNAME);
|
|
return;
|
|
}
|
|
|
|
port = ntohl(rx_message->data.ntp_source.port);
|
|
params.minpoll = ntohl(rx_message->data.ntp_source.minpoll);
|
|
params.maxpoll = ntohl(rx_message->data.ntp_source.maxpoll);
|
|
params.presend_minpoll = ntohl(rx_message->data.ntp_source.presend_minpoll);
|
|
params.min_stratum = ntohl(rx_message->data.ntp_source.min_stratum);
|
|
params.poll_target = ntohl(rx_message->data.ntp_source.poll_target);
|
|
params.version = ntohl(rx_message->data.ntp_source.version);
|
|
params.max_sources = ntohl(rx_message->data.ntp_source.max_sources);
|
|
params.min_samples = ntohl(rx_message->data.ntp_source.min_samples);
|
|
params.max_samples = ntohl(rx_message->data.ntp_source.max_samples);
|
|
params.filter_length = ntohl(rx_message->data.ntp_source.filter_length);
|
|
params.authkey = ntohl(rx_message->data.ntp_source.authkey);
|
|
params.nts_port = ntohl(rx_message->data.ntp_source.nts_port);
|
|
params.cert_set = ntohl(rx_message->data.ntp_source.cert_set);
|
|
params.max_delay = UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay);
|
|
params.max_delay_ratio =
|
|
UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_ratio);
|
|
params.max_delay_dev_ratio =
|
|
UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_dev_ratio);
|
|
params.min_delay = UTI_FloatNetworkToHost(rx_message->data.ntp_source.min_delay);
|
|
params.asymmetry = UTI_FloatNetworkToHost(rx_message->data.ntp_source.asymmetry);
|
|
params.offset = UTI_FloatNetworkToHost(rx_message->data.ntp_source.offset);
|
|
|
|
params.connectivity = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_ONLINE ?
|
|
SRC_ONLINE : SRC_OFFLINE;
|
|
params.auto_offline = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_AUTOOFFLINE ? 1 : 0;
|
|
params.iburst = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_IBURST ? 1 : 0;
|
|
params.interleaved = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_INTERLEAVED ? 1 : 0;
|
|
params.burst = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_BURST ? 1 : 0;
|
|
params.nts = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_NTS ? 1 : 0;
|
|
params.copy = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_COPY ? 1 : 0;
|
|
params.ext_fields =
|
|
ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_EF_EXP1 ? NTP_EF_FLAG_EXP1 : 0;
|
|
params.sel_options =
|
|
(ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_PREFER ? SRC_SELECT_PREFER : 0) |
|
|
(ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_NOSELECT ? SRC_SELECT_NOSELECT : 0) |
|
|
(ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_TRUST ? SRC_SELECT_TRUST : 0) |
|
|
(ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_REQUIRE ? SRC_SELECT_REQUIRE : 0);
|
|
|
|
status = NSR_AddSourceByName(name, port, pool, type, ¶ms, NULL);
|
|
switch (status) {
|
|
case NSR_Success:
|
|
break;
|
|
case NSR_UnresolvedName:
|
|
/* Try to resolve the name now */
|
|
NSR_ResolveSources();
|
|
break;
|
|
case NSR_AlreadyInUse:
|
|
tx_message->status = htons(STT_SOURCEALREADYKNOWN);
|
|
break;
|
|
case NSR_TooManySources:
|
|
tx_message->status = htons(STT_TOOMANYSOURCES);
|
|
break;
|
|
case NSR_InvalidName:
|
|
tx_message->status = htons(STT_INVALIDNAME);
|
|
break;
|
|
case NSR_InvalidAF:
|
|
case NSR_NoSuchSource:
|
|
assert(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_del_source(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
NSR_Status status;
|
|
IPAddr ip_addr;
|
|
|
|
UTI_IPNetworkToHost(&rx_message->data.del_source.ip_addr, &ip_addr);
|
|
|
|
status = NSR_RemoveSource(&ip_addr);
|
|
switch (status) {
|
|
case NSR_Success:
|
|
break;
|
|
case NSR_NoSuchSource:
|
|
tx_message->status = htons(STT_NOSUCHSOURCE);
|
|
break;
|
|
case NSR_TooManySources:
|
|
case NSR_AlreadyInUse:
|
|
case NSR_InvalidAF:
|
|
case NSR_InvalidName:
|
|
case NSR_UnresolvedName:
|
|
assert(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_writertc(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
switch (RTC_WriteParameters()) {
|
|
case RTC_ST_OK:
|
|
break;
|
|
case RTC_ST_NODRV:
|
|
tx_message->status = htons(STT_NORTC);
|
|
break;
|
|
case RTC_ST_BADFILE:
|
|
tx_message->status = htons(STT_BADRTCFILE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_dfreq(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
double dfreq;
|
|
dfreq = UTI_FloatNetworkToHost(rx_message->data.dfreq.dfreq);
|
|
LCL_AccumulateDeltaFrequency(dfreq * 1.0e-6);
|
|
LOG(LOGS_INFO, "Accumulated delta freq of %.3fppm", dfreq);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_doffset(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
double doffset;
|
|
|
|
doffset = UTI_FloatNetworkToHost(rx_message->data.doffset.doffset);
|
|
if (!LCL_AccumulateOffset(doffset, 0.0)) {
|
|
tx_message->status = htons(STT_FAILED);
|
|
} else {
|
|
LOG(LOGS_INFO, "Accumulated delta offset of %.6f seconds", doffset);
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_tracking(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
RPT_TrackingReport rpt;
|
|
|
|
REF_GetTrackingReport(&rpt);
|
|
tx_message->reply = htons(RPY_TRACKING);
|
|
tx_message->data.tracking.ref_id = htonl(rpt.ref_id);
|
|
UTI_IPHostToNetwork(&rpt.ip_addr, &tx_message->data.tracking.ip_addr);
|
|
tx_message->data.tracking.stratum = htons(rpt.stratum);
|
|
tx_message->data.tracking.leap_status = htons(rpt.leap_status);
|
|
UTI_TimespecHostToNetwork(&rpt.ref_time, &tx_message->data.tracking.ref_time);
|
|
tx_message->data.tracking.current_correction = UTI_FloatHostToNetwork(rpt.current_correction);
|
|
tx_message->data.tracking.last_offset = UTI_FloatHostToNetwork(rpt.last_offset);
|
|
tx_message->data.tracking.rms_offset = UTI_FloatHostToNetwork(rpt.rms_offset);
|
|
tx_message->data.tracking.freq_ppm = UTI_FloatHostToNetwork(rpt.freq_ppm);
|
|
tx_message->data.tracking.resid_freq_ppm = UTI_FloatHostToNetwork(rpt.resid_freq_ppm);
|
|
tx_message->data.tracking.skew_ppm = UTI_FloatHostToNetwork(rpt.skew_ppm);
|
|
tx_message->data.tracking.root_delay = UTI_FloatHostToNetwork(rpt.root_delay);
|
|
tx_message->data.tracking.root_dispersion = UTI_FloatHostToNetwork(rpt.root_dispersion);
|
|
tx_message->data.tracking.last_update_interval = UTI_FloatHostToNetwork(rpt.last_update_interval);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_smoothing(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
RPT_SmoothingReport report;
|
|
struct timespec now;
|
|
|
|
SCH_GetLastEventTime(&now, NULL, NULL);
|
|
|
|
if (!SMT_GetSmoothingReport(&report, &now)) {
|
|
tx_message->status = htons(STT_NOTENABLED);
|
|
return;
|
|
}
|
|
|
|
tx_message->reply = htons(RPY_SMOOTHING);
|
|
tx_message->data.smoothing.flags = htonl((report.active ? RPY_SMT_FLAG_ACTIVE : 0) |
|
|
(report.leap_only ? RPY_SMT_FLAG_LEAPONLY : 0));
|
|
tx_message->data.smoothing.offset = UTI_FloatHostToNetwork(report.offset);
|
|
tx_message->data.smoothing.freq_ppm = UTI_FloatHostToNetwork(report.freq_ppm);
|
|
tx_message->data.smoothing.wander_ppm = UTI_FloatHostToNetwork(report.wander_ppm);
|
|
tx_message->data.smoothing.last_update_ago = UTI_FloatHostToNetwork(report.last_update_ago);
|
|
tx_message->data.smoothing.remaining_time = UTI_FloatHostToNetwork(report.remaining_time);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_smoothtime(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
struct timespec now;
|
|
int option;
|
|
|
|
if (!SMT_IsEnabled()) {
|
|
tx_message->status = htons(STT_NOTENABLED);
|
|
return;
|
|
}
|
|
|
|
option = ntohl(rx_message->data.smoothtime.option);
|
|
SCH_GetLastEventTime(&now, NULL, NULL);
|
|
|
|
switch (option) {
|
|
case REQ_SMOOTHTIME_RESET:
|
|
SMT_Reset(&now);
|
|
break;
|
|
case REQ_SMOOTHTIME_ACTIVATE:
|
|
SMT_Activate(&now);
|
|
break;
|
|
default:
|
|
tx_message->status = htons(STT_INVALID);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_sourcestats(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
int status;
|
|
RPT_SourcestatsReport report;
|
|
struct timespec now_corr;
|
|
|
|
SCH_GetLastEventTime(&now_corr, NULL, NULL);
|
|
status = SRC_ReportSourcestats(ntohl(rx_message->data.sourcestats.index),
|
|
&report, &now_corr);
|
|
|
|
if (status) {
|
|
tx_message->reply = htons(RPY_SOURCESTATS);
|
|
tx_message->data.sourcestats.ref_id = htonl(report.ref_id);
|
|
UTI_IPHostToNetwork(&report.ip_addr, &tx_message->data.sourcestats.ip_addr);
|
|
tx_message->data.sourcestats.n_samples = htonl(report.n_samples);
|
|
tx_message->data.sourcestats.n_runs = htonl(report.n_runs);
|
|
tx_message->data.sourcestats.span_seconds = htonl(report.span_seconds);
|
|
tx_message->data.sourcestats.resid_freq_ppm = UTI_FloatHostToNetwork(report.resid_freq_ppm);
|
|
tx_message->data.sourcestats.skew_ppm = UTI_FloatHostToNetwork(report.skew_ppm);
|
|
tx_message->data.sourcestats.sd = UTI_FloatHostToNetwork(report.sd);
|
|
tx_message->data.sourcestats.est_offset = UTI_FloatHostToNetwork(report.est_offset);
|
|
tx_message->data.sourcestats.est_offset_err = UTI_FloatHostToNetwork(report.est_offset_err);
|
|
} else {
|
|
tx_message->status = htons(STT_NOSUCHSOURCE);
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_rtcreport(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
int status;
|
|
RPT_RTC_Report report;
|
|
status = RTC_GetReport(&report);
|
|
if (status) {
|
|
tx_message->reply = htons(RPY_RTC);
|
|
UTI_TimespecHostToNetwork(&report.ref_time, &tx_message->data.rtc.ref_time);
|
|
tx_message->data.rtc.n_samples = htons(report.n_samples);
|
|
tx_message->data.rtc.n_runs = htons(report.n_runs);
|
|
tx_message->data.rtc.span_seconds = htonl(report.span_seconds);
|
|
tx_message->data.rtc.rtc_seconds_fast = UTI_FloatHostToNetwork(report.rtc_seconds_fast);
|
|
tx_message->data.rtc.rtc_gain_rate_ppm = UTI_FloatHostToNetwork(report.rtc_gain_rate_ppm);
|
|
} else {
|
|
tx_message->status = htons(STT_NORTC);
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_trimrtc(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
if (!RTC_Trim())
|
|
tx_message->status = htons(STT_NORTC);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_cyclelogs(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
LOG_CycleLogFiles();
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_client_accesses_by_index(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
RPT_ClientAccessByIndex_Report report;
|
|
RPY_ClientAccesses_Client *client;
|
|
int n_indices;
|
|
uint32_t i, j, req_first_index, req_n_clients, req_min_hits, req_reset;
|
|
struct timespec now;
|
|
|
|
SCH_GetLastEventTime(&now, NULL, NULL);
|
|
|
|
req_first_index = ntohl(rx_message->data.client_accesses_by_index.first_index);
|
|
req_n_clients = ntohl(rx_message->data.client_accesses_by_index.n_clients);
|
|
if (req_n_clients > MAX_CLIENT_ACCESSES)
|
|
req_n_clients = MAX_CLIENT_ACCESSES;
|
|
req_min_hits = ntohl(rx_message->data.client_accesses_by_index.min_hits);
|
|
req_reset = ntohl(rx_message->data.client_accesses_by_index.reset);
|
|
|
|
n_indices = CLG_GetNumberOfIndices();
|
|
if (n_indices < 0) {
|
|
tx_message->status = htons(STT_INACTIVE);
|
|
return;
|
|
}
|
|
|
|
tx_message->reply = htons(RPY_CLIENT_ACCESSES_BY_INDEX3);
|
|
tx_message->data.client_accesses_by_index.n_indices = htonl(n_indices);
|
|
|
|
for (i = req_first_index, j = 0; i < (uint32_t)n_indices && j < req_n_clients; i++) {
|
|
if (!CLG_GetClientAccessReportByIndex(i, req_reset, req_min_hits, &report, &now))
|
|
continue;
|
|
|
|
client = &tx_message->data.client_accesses_by_index.clients[j++];
|
|
|
|
UTI_IPHostToNetwork(&report.ip_addr, &client->ip);
|
|
client->ntp_hits = htonl(report.ntp_hits);
|
|
client->nke_hits = htonl(report.nke_hits);
|
|
client->cmd_hits = htonl(report.cmd_hits);
|
|
client->ntp_drops = htonl(report.ntp_drops);
|
|
client->nke_drops = htonl(report.nke_drops);
|
|
client->cmd_drops = htonl(report.cmd_drops);
|
|
client->ntp_interval = report.ntp_interval;
|
|
client->nke_interval = report.nke_interval;
|
|
client->cmd_interval = report.cmd_interval;
|
|
client->ntp_timeout_interval = report.ntp_timeout_interval;
|
|
client->last_ntp_hit_ago = htonl(report.last_ntp_hit_ago);
|
|
client->last_nke_hit_ago = htonl(report.last_nke_hit_ago);
|
|
client->last_cmd_hit_ago = htonl(report.last_cmd_hit_ago);
|
|
}
|
|
|
|
tx_message->data.client_accesses_by_index.next_index = htonl(i);
|
|
tx_message->data.client_accesses_by_index.n_clients = htonl(j);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_manual_list(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
int n_samples;
|
|
int i;
|
|
RPY_ManualListSample *sample;
|
|
RPT_ManualSamplesReport report[MAX_MANUAL_LIST_SAMPLES];
|
|
|
|
tx_message->reply = htons(RPY_MANUAL_LIST2);
|
|
|
|
MNL_ReportSamples(report, MAX_MANUAL_LIST_SAMPLES, &n_samples);
|
|
tx_message->data.manual_list.n_samples = htonl(n_samples);
|
|
|
|
for (i=0; i<n_samples; i++) {
|
|
sample = &tx_message->data.manual_list.samples[i];
|
|
UTI_TimespecHostToNetwork(&report[i].when, &sample->when);
|
|
sample->slewed_offset = UTI_FloatHostToNetwork(report[i].slewed_offset);
|
|
sample->orig_offset = UTI_FloatHostToNetwork(report[i].orig_offset);
|
|
sample->residual = UTI_FloatHostToNetwork(report[i].residual);
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_manual_delete(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
int index;
|
|
|
|
index = ntohl(rx_message->data.manual_delete.index);
|
|
if (!MNL_DeleteSample(index))
|
|
tx_message->status = htons(STT_BADSAMPLE);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_make_step(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
if (!LCL_MakeStep())
|
|
tx_message->status = htons(STT_FAILED);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_activity(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
RPT_ActivityReport report;
|
|
NSR_GetActivityReport(&report);
|
|
tx_message->data.activity.online = htonl(report.online);
|
|
tx_message->data.activity.offline = htonl(report.offline);
|
|
tx_message->data.activity.burst_online = htonl(report.burst_online);
|
|
tx_message->data.activity.burst_offline = htonl(report.burst_offline);
|
|
tx_message->data.activity.unresolved = htonl(report.unresolved);
|
|
tx_message->reply = htons(RPY_ACTIVITY);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_reselect_distance(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
double dist;
|
|
dist = UTI_FloatNetworkToHost(rx_message->data.reselect_distance.distance);
|
|
SRC_SetReselectDistance(dist);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_reselect(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
SRC_ReselectSource();
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_refresh(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
NSR_RefreshAddresses();
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_server_stats(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
RPT_ServerStatsReport report;
|
|
|
|
CLG_GetServerStatsReport(&report);
|
|
tx_message->reply = htons(RPY_SERVER_STATS3);
|
|
tx_message->data.server_stats.ntp_hits = htonl(report.ntp_hits);
|
|
tx_message->data.server_stats.nke_hits = htonl(report.nke_hits);
|
|
tx_message->data.server_stats.cmd_hits = htonl(report.cmd_hits);
|
|
tx_message->data.server_stats.ntp_drops = htonl(report.ntp_drops);
|
|
tx_message->data.server_stats.nke_drops = htonl(report.nke_drops);
|
|
tx_message->data.server_stats.cmd_drops = htonl(report.cmd_drops);
|
|
tx_message->data.server_stats.log_drops = htonl(report.log_drops);
|
|
tx_message->data.server_stats.ntp_auth_hits = htonl(report.ntp_auth_hits);
|
|
tx_message->data.server_stats.ntp_interleaved_hits = htonl(report.ntp_interleaved_hits);
|
|
tx_message->data.server_stats.ntp_timestamps = htonl(report.ntp_timestamps);
|
|
tx_message->data.server_stats.ntp_span_seconds = htonl(report.ntp_span_seconds);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_ntp_data(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
RPT_NTPReport report;
|
|
|
|
UTI_IPNetworkToHost(&rx_message->data.ntp_data.ip_addr, &report.remote_addr);
|
|
|
|
if (!NSR_GetNTPReport(&report)) {
|
|
tx_message->status = htons(STT_NOSUCHSOURCE);
|
|
return;
|
|
}
|
|
|
|
tx_message->reply = htons(RPY_NTP_DATA);
|
|
UTI_IPHostToNetwork(&report.remote_addr, &tx_message->data.ntp_data.remote_addr);
|
|
UTI_IPHostToNetwork(&report.local_addr, &tx_message->data.ntp_data.local_addr);
|
|
tx_message->data.ntp_data.remote_port = htons(report.remote_port);
|
|
tx_message->data.ntp_data.leap = report.leap;
|
|
tx_message->data.ntp_data.version = report.version;
|
|
tx_message->data.ntp_data.mode = report.mode;
|
|
tx_message->data.ntp_data.stratum = report.stratum;
|
|
tx_message->data.ntp_data.poll = report.poll;
|
|
tx_message->data.ntp_data.precision = report.precision;
|
|
tx_message->data.ntp_data.root_delay = UTI_FloatHostToNetwork(report.root_delay);
|
|
tx_message->data.ntp_data.root_dispersion = UTI_FloatHostToNetwork(report.root_dispersion);
|
|
tx_message->data.ntp_data.ref_id = htonl(report.ref_id);
|
|
UTI_TimespecHostToNetwork(&report.ref_time, &tx_message->data.ntp_data.ref_time);
|
|
tx_message->data.ntp_data.offset = UTI_FloatHostToNetwork(report.offset);
|
|
tx_message->data.ntp_data.peer_delay = UTI_FloatHostToNetwork(report.peer_delay);
|
|
tx_message->data.ntp_data.peer_dispersion = UTI_FloatHostToNetwork(report.peer_dispersion);
|
|
tx_message->data.ntp_data.response_time = UTI_FloatHostToNetwork(report.response_time);
|
|
tx_message->data.ntp_data.jitter_asymmetry = UTI_FloatHostToNetwork(report.jitter_asymmetry);
|
|
tx_message->data.ntp_data.flags = htons((report.tests & RPY_NTP_FLAGS_TESTS) |
|
|
(report.interleaved ? RPY_NTP_FLAG_INTERLEAVED : 0) |
|
|
(report.authenticated ? RPY_NTP_FLAG_AUTHENTICATED : 0));
|
|
tx_message->data.ntp_data.tx_tss_char = report.tx_tss_char;
|
|
tx_message->data.ntp_data.rx_tss_char = report.rx_tss_char;
|
|
tx_message->data.ntp_data.total_tx_count = htonl(report.total_tx_count);
|
|
tx_message->data.ntp_data.total_rx_count = htonl(report.total_rx_count);
|
|
tx_message->data.ntp_data.total_valid_count = htonl(report.total_valid_count);
|
|
memset(tx_message->data.ntp_data.reserved, 0xff, sizeof (tx_message->data.ntp_data.reserved));
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_shutdown(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
LOG(LOGS_INFO, "Received shutdown command");
|
|
SCH_QuitProgram();
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_ntp_source_name(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
IPAddr addr;
|
|
char *name;
|
|
|
|
UTI_IPNetworkToHost(&rx_message->data.ntp_source_name.ip_addr, &addr);
|
|
name = NSR_GetName(&addr);
|
|
|
|
if (!name) {
|
|
tx_message->status = htons(STT_NOSUCHSOURCE);
|
|
return;
|
|
}
|
|
|
|
tx_message->reply = htons(RPY_NTP_SOURCE_NAME);
|
|
|
|
/* Avoid compiler warning */
|
|
if (strlen(name) >= sizeof (tx_message->data.ntp_source_name.name))
|
|
memcpy(tx_message->data.ntp_source_name.name, name,
|
|
sizeof (tx_message->data.ntp_source_name.name));
|
|
else
|
|
strncpy((char *)tx_message->data.ntp_source_name.name, name,
|
|
sizeof (tx_message->data.ntp_source_name.name));
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_reload_sources(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
CNF_ReloadSources();
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_reset_sources(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
struct timespec cooked_now, now;
|
|
|
|
SRC_ResetSources();
|
|
SCH_GetLastEventTime(&cooked_now, NULL, &now);
|
|
LCL_NotifyExternalTimeStep(&now, &cooked_now, 0.0, 0.0);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_auth_data(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
RPT_AuthReport report;
|
|
IPAddr ip_addr;
|
|
|
|
UTI_IPNetworkToHost(&rx_message->data.auth_data.ip_addr, &ip_addr);
|
|
|
|
if (!NSR_GetAuthReport(&ip_addr, &report)) {
|
|
tx_message->status = htons(STT_NOSUCHSOURCE);
|
|
return;
|
|
}
|
|
|
|
tx_message->reply = htons(RPY_AUTH_DATA);
|
|
|
|
switch (report.mode) {
|
|
case NTP_AUTH_NONE:
|
|
tx_message->data.auth_data.mode = htons(RPY_AD_MD_NONE);
|
|
break;
|
|
case NTP_AUTH_SYMMETRIC:
|
|
tx_message->data.auth_data.mode = htons(RPY_AD_MD_SYMMETRIC);
|
|
break;
|
|
case NTP_AUTH_NTS:
|
|
tx_message->data.auth_data.mode = htons(RPY_AD_MD_NTS);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
tx_message->data.auth_data.key_type = htons(report.key_type);
|
|
tx_message->data.auth_data.key_id = htonl(report.key_id);
|
|
tx_message->data.auth_data.key_length = htons(report.key_length);
|
|
tx_message->data.auth_data.ke_attempts = htons(report.ke_attempts);
|
|
tx_message->data.auth_data.last_ke_ago = htonl(report.last_ke_ago);
|
|
tx_message->data.auth_data.cookies = htons(report.cookies);
|
|
tx_message->data.auth_data.cookie_length = htons(report.cookie_length);
|
|
tx_message->data.auth_data.nak = htons(report.nak);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static uint16_t
|
|
convert_select_options(int options)
|
|
{
|
|
return (options & SRC_SELECT_PREFER ? RPY_SD_OPTION_PREFER : 0) |
|
|
(options & SRC_SELECT_NOSELECT ? RPY_SD_OPTION_NOSELECT : 0) |
|
|
(options & SRC_SELECT_TRUST ? RPY_SD_OPTION_TRUST : 0) |
|
|
(options & SRC_SELECT_REQUIRE ? RPY_SD_OPTION_REQUIRE : 0);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
static void
|
|
handle_select_data(CMD_Request *rx_message, CMD_Reply *tx_message)
|
|
{
|
|
RPT_SelectReport report;
|
|
|
|
if (!SRC_GetSelectReport(ntohl(rx_message->data.select_data.index), &report)) {
|
|
tx_message->status = htons(STT_NOSUCHSOURCE);
|
|
return;
|
|
}
|
|
|
|
tx_message->reply = htons(RPY_SELECT_DATA);
|
|
|
|
tx_message->data.select_data.ref_id = htonl(report.ref_id);
|
|
UTI_IPHostToNetwork(&report.ip_addr, &tx_message->data.select_data.ip_addr);
|
|
tx_message->data.select_data.state_char = report.state_char;
|
|
tx_message->data.select_data.authentication = report.authentication;
|
|
tx_message->data.select_data.leap = report.leap;
|
|
tx_message->data.select_data.conf_options = htons(convert_select_options(report.conf_options));
|
|
tx_message->data.select_data.eff_options = htons(convert_select_options(report.eff_options));
|
|
tx_message->data.select_data.last_sample_ago = htonl(report.last_sample_ago);
|
|
tx_message->data.select_data.score = UTI_FloatHostToNetwork(report.score);
|
|
tx_message->data.select_data.hi_limit = UTI_FloatHostToNetwork(report.hi_limit);
|
|
tx_message->data.select_data.lo_limit = UTI_FloatHostToNetwork(report.lo_limit);
|
|
}
|
|
|
|
/* ================================================== */
|
|
/* Read a packet and process it */
|
|
|
|
static void
|
|
read_from_cmd_socket(int sock_fd, int event, void *anything)
|
|
{
|
|
SCK_Message *sck_message;
|
|
CMD_Request rx_message;
|
|
CMD_Reply tx_message;
|
|
IPAddr loopback_addr, remote_ip;
|
|
int read_length, expected_length;
|
|
int localhost, allowed, log_index;
|
|
uint16_t rx_command;
|
|
struct timespec now, cooked_now;
|
|
|
|
sck_message = SCK_ReceiveMessage(sock_fd, 0);
|
|
if (!sck_message)
|
|
return;
|
|
|
|
read_length = sck_message->length;
|
|
|
|
/* Get current time cheaply */
|
|
SCH_GetLastEventTime(&cooked_now, NULL, &now);
|
|
|
|
/* Check if it's from localhost (127.0.0.1, ::1, or Unix domain),
|
|
or an authorised address */
|
|
switch (sck_message->addr_type) {
|
|
case SCK_ADDR_IP:
|
|
assert(sock_fd == sock_fd4 || sock_fd == sock_fd6);
|
|
remote_ip = sck_message->remote_addr.ip.ip_addr;
|
|
SCK_GetLoopbackIPAddress(remote_ip.family, &loopback_addr);
|
|
localhost = UTI_CompareIPs(&remote_ip, &loopback_addr, NULL) == 0;
|
|
|
|
if (!localhost && !ADF_IsAllowed(access_auth_table, &remote_ip)) {
|
|
DEBUG_LOG("Unauthorised host %s",
|
|
UTI_IPSockAddrToString(&sck_message->remote_addr.ip));
|
|
return;
|
|
}
|
|
|
|
assert(remote_ip.family != IPADDR_UNSPEC);
|
|
|
|
break;
|
|
case SCK_ADDR_UNIX:
|
|
assert(sock_fd == sock_fdu);
|
|
remote_ip.family = IPADDR_UNSPEC;
|
|
localhost = 1;
|
|
break;
|
|
default:
|
|
DEBUG_LOG("Unexpected address type");
|
|
return;
|
|
}
|
|
|
|
if (read_length < offsetof(CMD_Request, data) ||
|
|
read_length < offsetof(CMD_Reply, data) ||
|
|
read_length > sizeof (CMD_Request)) {
|
|
/* We don't know how to process anything like this or an error reply
|
|
would be larger than the request */
|
|
DEBUG_LOG("Unexpected length");
|
|
return;
|
|
}
|
|
|
|
memcpy(&rx_message, sck_message->data, read_length);
|
|
|
|
if (rx_message.pkt_type != PKT_TYPE_CMD_REQUEST ||
|
|
rx_message.res1 != 0 ||
|
|
rx_message.res2 != 0) {
|
|
DEBUG_LOG("Command packet dropped");
|
|
return;
|
|
}
|
|
|
|
log_index = CLG_LogServiceAccess(CLG_CMDMON, &remote_ip, &cooked_now);
|
|
|
|
/* Don't reply to all requests from hosts other than localhost if the rate
|
|
is excessive */
|
|
if (!localhost && log_index >= 0 && CLG_LimitServiceRate(CLG_CMDMON, log_index)) {
|
|
DEBUG_LOG("Command packet discarded to limit response rate");
|
|
return;
|
|
}
|
|
|
|
expected_length = PKL_CommandLength(&rx_message);
|
|
rx_command = ntohs(rx_message.command);
|
|
|
|
memset(&tx_message, 0, sizeof (tx_message));
|
|
sck_message->data = &tx_message;
|
|
sck_message->length = 0;
|
|
|
|
tx_message.version = PROTO_VERSION_NUMBER;
|
|
tx_message.pkt_type = PKT_TYPE_CMD_REPLY;
|
|
tx_message.command = rx_message.command;
|
|
tx_message.reply = htons(RPY_NULL);
|
|
tx_message.status = htons(STT_SUCCESS);
|
|
tx_message.sequence = rx_message.sequence;
|
|
|
|
if (rx_message.version != PROTO_VERSION_NUMBER) {
|
|
DEBUG_LOG("Command packet has invalid version (%d != %d)",
|
|
rx_message.version, PROTO_VERSION_NUMBER);
|
|
|
|
if (rx_message.version >= PROTO_VERSION_MISMATCH_COMPAT_SERVER) {
|
|
tx_message.status = htons(STT_BADPKTVERSION);
|
|
transmit_reply(sock_fd, read_length, sck_message);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (rx_command >= N_REQUEST_TYPES ||
|
|
expected_length < (int)offsetof(CMD_Request, data)) {
|
|
DEBUG_LOG("Command packet has invalid command %d", rx_command);
|
|
|
|
tx_message.status = htons(STT_INVALID);
|
|
transmit_reply(sock_fd, read_length, sck_message);
|
|
return;
|
|
}
|
|
|
|
if (read_length < expected_length) {
|
|
DEBUG_LOG("Command packet is too short (%d < %d)", read_length,
|
|
expected_length);
|
|
|
|
tx_message.status = htons(STT_BADPKTLENGTH);
|
|
transmit_reply(sock_fd, read_length, sck_message);
|
|
return;
|
|
}
|
|
|
|
/* OK, we have a valid message. Now dispatch on message type and process it. */
|
|
|
|
if (rx_command >= N_REQUEST_TYPES) {
|
|
/* This should be already handled */
|
|
assert(0);
|
|
} else {
|
|
/* Check level of authority required to issue the command. All commands
|
|
from the Unix domain socket (which is accessible only by the root and
|
|
chrony user/group) are allowed. */
|
|
if (remote_ip.family == IPADDR_UNSPEC) {
|
|
assert(sock_fd == sock_fdu);
|
|
allowed = 1;
|
|
} else {
|
|
switch (permissions[rx_command]) {
|
|
case PERMIT_AUTH:
|
|
allowed = 0;
|
|
break;
|
|
case PERMIT_LOCAL:
|
|
allowed = localhost;
|
|
break;
|
|
case PERMIT_OPEN:
|
|
allowed = 1;
|
|
break;
|
|
default:
|
|
assert(0);
|
|
allowed = 0;
|
|
}
|
|
}
|
|
|
|
if (allowed) {
|
|
switch(rx_command) {
|
|
case REQ_NULL:
|
|
/* Do nothing */
|
|
break;
|
|
|
|
case REQ_DUMP:
|
|
handle_dump(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_ONLINE:
|
|
handle_online(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_OFFLINE:
|
|
handle_offline(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_BURST:
|
|
handle_burst(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_MODIFY_MINPOLL:
|
|
handle_modify_minpoll(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_MODIFY_MAXPOLL:
|
|
handle_modify_maxpoll(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_MODIFY_MAXDELAY:
|
|
handle_modify_maxdelay(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_MODIFY_MAXDELAYRATIO:
|
|
handle_modify_maxdelayratio(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_MODIFY_MAXDELAYDEVRATIO:
|
|
handle_modify_maxdelaydevratio(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_MODIFY_MAXUPDATESKEW:
|
|
handle_modify_maxupdateskew(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_MODIFY_MAKESTEP:
|
|
handle_modify_makestep(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_LOGON:
|
|
/* Authentication is no longer supported, log-on always fails */
|
|
tx_message.status = htons(STT_FAILED);
|
|
break;
|
|
|
|
case REQ_SETTIME:
|
|
handle_settime(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_LOCAL2:
|
|
handle_local(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_MANUAL:
|
|
handle_manual(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_N_SOURCES:
|
|
handle_n_sources(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_SOURCE_DATA:
|
|
handle_source_data(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_REKEY:
|
|
handle_rekey(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_ALLOW:
|
|
handle_allowdeny(&rx_message, &tx_message, 1, 0);
|
|
break;
|
|
|
|
case REQ_ALLOWALL:
|
|
handle_allowdeny(&rx_message, &tx_message, 1, 1);
|
|
break;
|
|
|
|
case REQ_DENY:
|
|
handle_allowdeny(&rx_message, &tx_message, 0, 0);
|
|
break;
|
|
|
|
case REQ_DENYALL:
|
|
handle_allowdeny(&rx_message, &tx_message, 0, 1);
|
|
break;
|
|
|
|
case REQ_CMDALLOW:
|
|
handle_cmdallowdeny(&rx_message, &tx_message, 1, 0);
|
|
break;
|
|
|
|
case REQ_CMDALLOWALL:
|
|
handle_cmdallowdeny(&rx_message, &tx_message, 1, 1);
|
|
break;
|
|
|
|
case REQ_CMDDENY:
|
|
handle_cmdallowdeny(&rx_message, &tx_message, 0, 0);
|
|
break;
|
|
|
|
case REQ_CMDDENYALL:
|
|
handle_cmdallowdeny(&rx_message, &tx_message, 0, 1);
|
|
break;
|
|
|
|
case REQ_ACCHECK:
|
|
handle_accheck(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_CMDACCHECK:
|
|
handle_cmdaccheck(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_ADD_SOURCE:
|
|
handle_add_source(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_DEL_SOURCE:
|
|
handle_del_source(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_WRITERTC:
|
|
handle_writertc(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_DFREQ:
|
|
handle_dfreq(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_DOFFSET2:
|
|
handle_doffset(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_TRACKING:
|
|
handle_tracking(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_SMOOTHING:
|
|
handle_smoothing(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_SMOOTHTIME:
|
|
handle_smoothtime(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_SOURCESTATS:
|
|
handle_sourcestats(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_RTCREPORT:
|
|
handle_rtcreport(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_TRIMRTC:
|
|
handle_trimrtc(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_CYCLELOGS:
|
|
handle_cyclelogs(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_CLIENT_ACCESSES_BY_INDEX3:
|
|
handle_client_accesses_by_index(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_MANUAL_LIST:
|
|
handle_manual_list(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_MANUAL_DELETE:
|
|
handle_manual_delete(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_MAKESTEP:
|
|
handle_make_step(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_ACTIVITY:
|
|
handle_activity(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_RESELECTDISTANCE:
|
|
handle_reselect_distance(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_RESELECT:
|
|
handle_reselect(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_MODIFY_MINSTRATUM:
|
|
handle_modify_minstratum(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_MODIFY_POLLTARGET:
|
|
handle_modify_polltarget(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_REFRESH:
|
|
handle_refresh(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_SERVER_STATS:
|
|
handle_server_stats(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_NTP_DATA:
|
|
handle_ntp_data(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_SHUTDOWN:
|
|
handle_shutdown(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_ONOFFLINE:
|
|
handle_onoffline(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_NTP_SOURCE_NAME:
|
|
handle_ntp_source_name(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_RESET_SOURCES:
|
|
handle_reset_sources(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_AUTH_DATA:
|
|
handle_auth_data(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_SELECT_DATA:
|
|
handle_select_data(&rx_message, &tx_message);
|
|
break;
|
|
|
|
case REQ_RELOAD_SOURCES:
|
|
handle_reload_sources(&rx_message, &tx_message);
|
|
break;
|
|
|
|
default:
|
|
DEBUG_LOG("Unhandled command %d", rx_command);
|
|
tx_message.status = htons(STT_FAILED);
|
|
break;
|
|
}
|
|
} else {
|
|
tx_message.status = htons(STT_UNAUTH);
|
|
}
|
|
}
|
|
|
|
/* Transmit the response */
|
|
transmit_reply(sock_fd, read_length, sck_message);
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CAM_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all)
|
|
{
|
|
ADF_Status status;
|
|
|
|
if (allow) {
|
|
if (all) {
|
|
status = ADF_AllowAll(access_auth_table, ip_addr, subnet_bits);
|
|
} else {
|
|
status = ADF_Allow(access_auth_table, ip_addr, subnet_bits);
|
|
}
|
|
} else {
|
|
if (all) {
|
|
status = ADF_DenyAll(access_auth_table, ip_addr, subnet_bits);
|
|
} else {
|
|
status = ADF_Deny(access_auth_table, ip_addr, subnet_bits);
|
|
}
|
|
}
|
|
|
|
if (status == ADF_BADSUBNET) {
|
|
return 0;
|
|
} else if (status == ADF_SUCCESS) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* ================================================== */
|
|
|
|
int
|
|
CAM_CheckAccessRestriction(IPAddr *ip_addr)
|
|
{
|
|
return ADF_IsAllowed(access_auth_table, ip_addr);
|
|
}
|
|
|
|
|
|
/* ================================================== */
|
|
/* ================================================== */
|