ntp: add copy option
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.
This commit is contained in:
parent
635a9d3f5a
commit
84d2811800
8 changed files with 49 additions and 3 deletions
1
candm.h
1
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;
|
||||
|
|
1
client.c
1
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) |
|
||||
|
|
1
cmdmon.c
1
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) |
|
||||
|
|
|
@ -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")) {
|
||||
|
|
|
@ -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
|
||||
|
|
15
ntp_core.c
15
ntp_core.c
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
|
19
test/simulation/141-copy
Executable file
19
test/simulation/141-copy
Executable file
|
@ -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
|
Loading…
Reference in a new issue