]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
ntp: add copy option
authorMiroslav Lichvar <mlichvar@redhat.com>
Wed, 14 Apr 2021 13:58:51 +0000 (15:58 +0200)
committerMiroslav Lichvar <mlichvar@redhat.com>
Thu, 15 Apr 2021 13:17:13 +0000 (15:17 +0200)
When separate client and server instances of chronyd are running on one
computer (e.g. for security or performance reasons) and are synchronized
to each other, the server instance provides a reference ID based on the
local address used for synchronization of its NTP clock, which breaks
detection of synchronization loops for its own clients.

Add a "copy" option to specify that the server and client are closely
related, no loop can form between them, and the client should assume the
reference ID and stratum of the server to fix detection of loops between
the server and clients of the client.

candm.h
client.c
cmdmon.c
cmdparse.c
doc/chrony.conf.adoc
ntp_core.c
srcparams.h
test/simulation/141-copy [new file with mode: 0755]

diff --git a/candm.h b/candm.h
index 52edf294f1c18680a4860123c639f0de3ec007e8..fe4d5b4b0a6bf18d768dd924b7160187f9afa588 100644 (file)
--- a/candm.h
+++ b/candm.h
@@ -269,6 +269,7 @@ typedef struct {
 #define REQ_ADDSRC_INTERLEAVED 0x80
 #define REQ_ADDSRC_BURST 0x100
 #define REQ_ADDSRC_NTS 0x200
+#define REQ_ADDSRC_COPY 0x400
 
 typedef struct {
   uint32_t type;
index c0e902200701f05cb0ea7adcc22f1f7e8a00d742..17e4577d8cfc773fb80935c0f7c6768248ee9484 100644 (file)
--- a/client.c
+++ b/client.c
@@ -1098,6 +1098,7 @@ process_cmd_add_source(CMD_Request *msg, char *line)
           (data.params.interleaved ? REQ_ADDSRC_INTERLEAVED : 0) |
           (data.params.burst ? REQ_ADDSRC_BURST : 0) |
           (data.params.nts ? REQ_ADDSRC_NTS : 0) |
+          (data.params.copy ? REQ_ADDSRC_COPY : 0) |
           (data.params.sel_options & SRC_SELECT_PREFER ? REQ_ADDSRC_PREFER : 0) |
           (data.params.sel_options & SRC_SELECT_NOSELECT ? REQ_ADDSRC_NOSELECT : 0) |
           (data.params.sel_options & SRC_SELECT_TRUST ? REQ_ADDSRC_TRUST : 0) |
index 3d17cb7469c53367c220e9b9f8726b569f86d2c9..7ee8c12dc851c1816ad16e5824b879c1fd096858 100644 (file)
--- a/cmdmon.c
+++ b/cmdmon.c
@@ -767,6 +767,7 @@ handle_add_source(CMD_Request *rx_message, CMD_Reply *tx_message)
   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.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) |
index 95d8953272a56ad39dbb11f23b2d1fba9802db11..e2c51153a6bdef31b495d90657f53fe0d38084fd 100644 (file)
@@ -64,6 +64,7 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
   src->params.sel_options = 0;
   src->params.nts = 0;
   src->params.nts_port = SRC_DEFAULT_NTSPORT;
+  src->params.copy = 0;
   src->params.authkey = INACTIVE_AUTHKEY;
   src->params.cert_set = SRC_DEFAULT_CERTSET;
   src->params.max_delay = SRC_DEFAULT_MAXDELAY;
@@ -91,6 +92,8 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
       src->params.auto_offline = 1;
     } else if (!strcasecmp(cmd, "burst")) {
       src->params.burst = 1;
+    } else if (!strcasecmp(cmd, "copy")) {
+      src->params.copy = 1;
     } else if (!strcasecmp(cmd, "iburst")) {
       src->params.iburst = 1;
     } else if (!strcasecmp(cmd, "offline")) {
index 280278fc328013ec583cf9091169e981c2a0f76f..ff95cccf8bb6f957d00e8ed5b0f5ce58bda25050 100644 (file)
@@ -278,6 +278,15 @@ specified by the *key* option and which authentication hash function the key
 is using. If the output size of the hash function is longer than 160 bits, the
 default version is 3 for compatibility with older *chronyd* servers. Otherwise,
 the default version is 4.
+*copy*:::
+This option specifies that the server and client are closely related, their
+configuration does not allow a synchronisation loop to form between them, and
+the client is allowed to assume the reference ID and stratum of the server.
+This is useful when multiple instances of `chronyd` are running on one computer
+(e.g. for security or performance reasons), one primarily operating as a client
+to synchronise the system clock and other instances started with the *-x*
+option to operate as NTP servers for other computers with their NTP clocks
+synchronised to the first instance.
 
 [[pool]]*pool* _name_ [_option_]...::
 The syntax of this directive is similar to that for the <<server,*server*>>
@@ -320,7 +329,7 @@ address of this host. *chronyd* does not support ephemeral associations.
 This directive can be used multiple times to specify multiple peers.
 +
 The following options of the *server* directive do not work in the *peer*
-directive: *iburst*, *burst*, *nts*, *presend*.
+directive: *iburst*, *burst*, *nts*, *presend*, *copy*.
 +
 When using the *xleave* option, both peers must support and have enabled the
 interleaved mode, otherwise the synchronisation will work in one direction
index 51c11fd158f7b97de3e68edad732d82890ea0604..547002217eb5e5345a19d8340c743cfffeaf6a24 100644 (file)
@@ -107,6 +107,8 @@ struct NCR_Instance_Record {
   int min_stratum;              /* Increase stratum in received packets to the
                                    minimum */
 
+  int copy;                     /* Boolean suppressing own refid and stratum */
+
   int poll_target;              /* Target number of sourcestats samples */
 
   int version;                  /* Version set in packets for server/peer */
@@ -560,6 +562,7 @@ NCR_CreateInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type,
   result->auto_iburst = params->iburst;
   result->auto_burst = params->burst;
   result->auto_offline = params->auto_offline;
+  result->copy = params->copy && result->mode == MODE_CLIENT;
   result->poll_target = params->poll_target;
 
   if (params->nts) {
@@ -1766,8 +1769,16 @@ process_response(NCR_Instance inst, NTP_Local_Address *local_addr,
     inst->tx_count = 0;
 
     SRC_UpdateReachability(inst->source, synced_packet);
-    if (synced_packet)
-      SRC_UpdateStatus(inst->source, MAX(message->stratum, inst->min_stratum), pkt_leap);
+
+    if (synced_packet) {
+      if (inst->copy && inst->remote_stratum > 0) {
+        /* Assume the reference ID and stratum of the server */
+        inst->remote_stratum--;
+        SRC_SetRefid(inst->source, ntohl(message->reference_id), &inst->remote_addr.ip_addr);
+      }
+
+      SRC_UpdateStatus(inst->source, MAX(inst->remote_stratum, inst->min_stratum), pkt_leap);
+    }
 
     if (good_packet) {
       /* Adjust the polling interval, accumulate the sample, etc. */
index 81ad889597d0f6a04a4260bda314b452dcc63ca1..6211ec791f6cd72e52591501b52f49df4519d7a6 100644 (file)
@@ -54,6 +54,7 @@ typedef struct {
   int sel_options;
   int nts;
   int nts_port;
+  int copy;
   uint32_t authkey;
   uint32_t cert_set;
   double max_delay;
diff --git a/test/simulation/141-copy b/test/simulation/141-copy
new file mode 100755 (executable)
index 0000000..80e56bc
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+. ./test.common
+
+test_start "copy option"
+
+check_config_h 'FEAT_CMDMON 1' || test_skip
+
+client_server_options="copy"
+chronyc_conf="tracking"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+check_chronyc_output "^Reference ID *: 7F7F0101 \(192\.168\.123\.1\)
+Stratum *: 1" || test_fail
+
+test_pass