From ad37c409c9170a5f4e2ee6068f49fcd0911b3215 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Thu, 7 Mar 2024 16:20:27 +0100 Subject: [PATCH] cmdmon: add offset command Add a new command to modify the offset option of NTP sources and reference clocks. --- candm.h | 11 ++++++- client.c | 63 +++++++++++++++++++++++++++++++------ cmdmon.c | 23 ++++++++++++++ doc/chronyc.adoc | 7 +++++ pktlength.c | 1 + test/simulation/110-chronyc | 3 ++ test/system/007-cmdmon | 1 + 7 files changed, 99 insertions(+), 10 deletions(-) diff --git a/candm.h b/candm.h index 65daedf..0894ad5 100644 --- a/candm.h +++ b/candm.h @@ -110,7 +110,8 @@ #define REQ_RELOAD_SOURCES 70 #define REQ_DOFFSET2 71 #define REQ_MODIFY_SELECTOPTS 72 -#define N_REQUEST_TYPES 73 +#define REQ_MODIFY_OFFSET 73 +#define N_REQUEST_TYPES 74 /* Structure used to exchange timespecs independent of time_t size */ typedef struct { @@ -390,6 +391,13 @@ typedef struct { int32_t EOR; } REQ_Modify_SelectOpts; +typedef struct { + IPAddr address; + uint32_t ref_id; + Float new_offset; + int32_t EOR; +} REQ_Modify_Offset; + /* ================================================== */ #define PKT_TYPE_CMD_REQUEST 1 @@ -497,6 +505,7 @@ typedef struct { REQ_AuthData auth_data; REQ_SelectData select_data; REQ_Modify_SelectOpts modify_select_opts; + REQ_Modify_Offset modify_offset; } data; /* Command specific parameters */ /* Padding used to prevent traffic amplification. It only defines the diff --git a/client.c b/client.c index 5ead2b0..0231b9e 100644 --- a/client.c +++ b/client.c @@ -344,6 +344,24 @@ parse_source_address(char *word, IPAddr *address) /* ================================================== */ +static int +parse_source_address_or_refid(char *s, IPAddr *address, uint32_t *ref_id) +{ + address->family = IPADDR_UNSPEC; + *ref_id = 0; + + /* Don't allow hostnames to avoid conflicts with reference IDs */ + if (UTI_StringToIdIP(s, address) || UTI_StringToIP(s, address)) + return 1; + + if (CPS_ParseRefid(s, ref_id) > 0) + return 1; + + return 0; +} + +/* ================================================== */ + static int read_mask_address(char *line, IPAddr *mask, IPAddr *address) { @@ -1031,6 +1049,7 @@ give_help(void) "selectopts <+|-options>\0Modify selection options\0" "reselect\0Force reselecting synchronisation source\0" "reselectdist \0Modify reselection distance\0" + "offset \0Modify offset correction\0" "\0\0" "NTP sources:\0\0" "activity\0Check how many NTP sources are online/offline\0" @@ -1141,7 +1160,8 @@ command_name_generator(const char *text, int state) "clients", "cmdaccheck", "cmdallow", "cmddeny", "cyclelogs", "delete", "deny", "dns", "dump", "exit", "help", "keygen", "local", "makestep", "manual", "maxdelay", "maxdelaydevratio", "maxdelayratio", "maxpoll", - "maxupdateskew", "minpoll", "minstratum", "ntpdata", "offline", "online", "onoffline", + "maxupdateskew", "minpoll", "minstratum", "ntpdata", + "offline", "offset", "online", "onoffline", "polltarget", "quit", "refresh", "rekey", "reload", "reselect", "reselectdist", "reset", "retries", "rtcdata", "selectdata", "selectopts", "serverstats", "settime", "shutdown", "smoothing", "smoothtime", "sourcename", "sources", "sourcestats", @@ -2858,6 +2878,34 @@ process_cmd_activity(const char *line) /* ================================================== */ +static int +process_cmd_offset(CMD_Request *msg, char *line) +{ + uint32_t ref_id; + IPAddr ip_addr; + double offset; + char *src; + + src = line; + line = CPS_SplitWord(line); + + if (!parse_source_address_or_refid(src, &ip_addr, &ref_id) || + sscanf(line, "%lf", &offset) != 1) { + LOG(LOGS_ERR, "Invalid syntax for offset command"); + return 0; + } + + UTI_IPHostToNetwork(&ip_addr, &msg->data.modify_offset.address); + msg->data.modify_offset.ref_id = htonl(ref_id); + msg->data.modify_offset.new_offset = UTI_FloatHostToNetwork(offset); + + msg->command = htons(REQ_MODIFY_OFFSET); + + return 1; +} + +/* ================================================== */ + static int process_cmd_reselectdist(CMD_Request *msg, char *line) { @@ -2939,15 +2987,10 @@ process_cmd_selectopts(CMD_Request *msg, char *line) src = line; line = CPS_SplitWord(line); - ref_id = 0; - /* Don't allow hostnames to avoid conflicts with reference IDs */ - if (!UTI_StringToIdIP(src, &ip_addr) && !UTI_StringToIP(src, &ip_addr)) { - ip_addr.family = IPADDR_UNSPEC; - if (CPS_ParseRefid(src, &ref_id) == 0) { - LOG(LOGS_ERR, "Invalid syntax for selectopts command"); - return 0; - } + if (!parse_source_address_or_refid(src, &ip_addr, &ref_id)) { + LOG(LOGS_ERR, "Invalid syntax for selectopts command"); + return 0; } mask = options = 0; @@ -3249,6 +3292,8 @@ process_line(char *line) ret = process_cmd_ntpdata(line); } else if (!strcmp(command, "offline")) { do_normal_submit = process_cmd_offline(&tx_message, line); + } else if (!strcmp(command, "offset")) { + do_normal_submit = process_cmd_offset(&tx_message, line); } else if (!strcmp(command, "online")) { do_normal_submit = process_cmd_online(&tx_message, line); } else if (!strcmp(command, "onoffline")) { diff --git a/cmdmon.c b/cmdmon.c index 0a0193b..716775f 100644 --- a/cmdmon.c +++ b/cmdmon.c @@ -145,6 +145,7 @@ static const char permissions[] = { PERMIT_AUTH, /* RELOAD_SOURCES */ PERMIT_AUTH, /* DOFFSET2 */ PERMIT_AUTH, /* MODIFY_SELECTOPTS */ + PERMIT_AUTH, /* MODIFY_OFFSET */ }; /* ================================================== */ @@ -1418,6 +1419,24 @@ handle_modify_selectopts(CMD_Request *rx_message, CMD_Reply *tx_message) tx_message->status = htons(STT_NOSUCHSOURCE); } +/* ================================================== */ + +static void +handle_modify_offset(CMD_Request *rx_message, CMD_Reply *tx_message) +{ + uint32_t ref_id; + IPAddr ip_addr; + double offset; + + UTI_IPNetworkToHost(&rx_message->data.modify_offset.address, &ip_addr); + ref_id = ntohl(rx_message->data.modify_offset.ref_id); + offset = UTI_FloatNetworkToHost(rx_message->data.modify_offset.new_offset); + + if ((ip_addr.family != IPADDR_UNSPEC && !NSR_ModifyOffset(&ip_addr, offset)) || + (ip_addr.family == IPADDR_UNSPEC && !RCL_ModifyOffset(ref_id, offset))) + tx_message->status = htons(STT_NOSUCHSOURCE); +} + /* ================================================== */ /* Read a packet and process it */ @@ -1818,6 +1837,10 @@ read_from_cmd_socket(int sock_fd, int event, void *anything) handle_modify_selectopts(&rx_message, &tx_message); break; + case REQ_MODIFY_OFFSET: + handle_modify_offset(&rx_message, &tx_message); + break; + default: DEBUG_LOG("Unhandled command %d", rx_command); tx_message.status = htons(STT_FAILED); diff --git a/doc/chronyc.adoc b/doc/chronyc.adoc index 8e0d426..1386e00 100644 --- a/doc/chronyc.adoc +++ b/doc/chronyc.adoc @@ -556,6 +556,13 @@ The *reselectdist* command sets the reselection distance. It is equivalent to the <> directive in the configuration file. +[[offset]]*offset* _address|refid_ _offset_:: +The *offset* command modifies the offset correction of an NTP source specified +by IP address (or the _ID#XXXXXXXXXX_ identifier used for unknown addresses), +or a reference clock specified by reference ID as a string. It is equivalent to +the *offset* option in the <> or +<> directive respectively. + === NTP sources [[activity]]*activity*:: diff --git a/pktlength.c b/pktlength.c index 3e0b319..3cca306 100644 --- a/pktlength.c +++ b/pktlength.c @@ -130,6 +130,7 @@ static const struct request_length request_lengths[] = { REQ_LENGTH_ENTRY(null, null), /* RELOAD_SOURCES */ REQ_LENGTH_ENTRY(doffset, null), /* DOFFSET2 */ REQ_LENGTH_ENTRY(modify_select_opts, null), /* MODIFY_SELECTOPTS */ + REQ_LENGTH_ENTRY(modify_offset, null), /* MODIFY_OFFSET */ }; static const uint16_t reply_lengths[] = { diff --git a/test/simulation/110-chronyc b/test/simulation/110-chronyc index a261e7a..a4f486a 100755 --- a/test/simulation/110-chronyc +++ b/test/simulation/110-chronyc @@ -165,6 +165,7 @@ for chronyc_conf in \ "offline" \ "offline 255.255.255.0/1.2.3.0" \ "offline 1.2.3.0/24" \ + "offset 1.2.3.4 1.0" \ "online" \ "online 1.2.3.0/24" \ "onoffline" \ @@ -351,6 +352,7 @@ maxpoll 192.168.123.1 5 maxupdateskew 192.168.123.1 10.0 minpoll 192.168.123.1 3 minstratum 192.168.123.1 1 +offset 192.168.123.1 -1.0 polltarget 192.168.123.1 10 selectopts 192.168.123.1 +trust +prefer -require selectdata @@ -375,6 +377,7 @@ check_chronyc_output "^200 OK 200 OK 200 OK 200 OK +200 OK S Name/IP Address Auth COpts EOpts Last Score Interval Leap ======================================================================= M node1\.net1\.clk N \-PT\-\- \-PT\-\- 0 1\.0 \+0ns \+0ns \? diff --git a/test/system/007-cmdmon b/test/system/007-cmdmon index 8599503..953b4f3 100755 --- a/test/system/007-cmdmon +++ b/test/system/007-cmdmon @@ -28,6 +28,7 @@ for command in \ "local" \ "online" \ "onoffline" \ + "offset $server 0.0" \ "maxdelay $server 1e-1" \ "maxdelaydevratio $server 5.0" \ "maxdelayratio $server 3.0" \