summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2023-12-07 08:45:18 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2023-12-07 08:45:18 +0000
commit6abfcbafe9d7f382a0eb7072333702eeacc69b1e (patch)
tree18549ff498338f40ecf7aa327620abf4c1c3ee43
parentAdding upstream version 4.4. (diff)
downloadchrony-upstream.tar.xz
chrony-upstream.zip
Adding upstream version 4.5.upstream/4.5upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--FAQ126
-rw-r--r--INSTALL2
-rw-r--r--NEWS14
-rw-r--r--README1
-rw-r--r--candm.h3
-rw-r--r--client.c5
-rw-r--r--cmdmon.c6
-rw-r--r--cmdparse.c7
-rw-r--r--conf.c64
-rwxr-xr-xconfigure55
-rw-r--r--doc/chrony.conf.adoc120
-rw-r--r--doc/chrony.conf.man.in127
-rw-r--r--doc/chronyc.adoc42
-rw-r--r--doc/chronyc.man.in46
-rw-r--r--doc/chronyd.adoc17
-rw-r--r--doc/chronyd.man.in22
-rw-r--r--doc/faq.adoc99
-rw-r--r--examples/chrony.conf.example312
-rw-r--r--logging.c10
-rw-r--r--main.c7
-rw-r--r--ntp.h19
-rw-r--r--ntp_core.c217
-rw-r--r--ntp_core.h2
-rw-r--r--ntp_io.c17
-rw-r--r--ntp_io.h2
-rw-r--r--ntp_io_linux.c9
-rw-r--r--ntp_sources.c25
-rw-r--r--ntp_sources.h2
-rw-r--r--nts_ke_server.c2
-rw-r--r--siv_gnutls.c33
-rw-r--r--socket.c169
-rw-r--r--socket.h9
-rw-r--r--sources.c62
-rw-r--r--stubs.c6
-rwxr-xr-xtest/compilation/002-scanbuild6
-rwxr-xr-xtest/compilation/003-sanitizers8
-rwxr-xr-xtest/simulation/110-chronyc2
-rwxr-xr-xtest/simulation/114-presend25
-rwxr-xr-xtest/simulation/142-ntpoverptp106
-rwxr-xr-xtest/simulation/142-ptpport41
-rwxr-xr-xtest/simulation/144-monoroot (renamed from test/simulation/144-exp1)2
-rw-r--r--test/simulation/test.common5
-rwxr-xr-xtest/system/008-confload21
-rwxr-xr-xtest/system/011-systemd140
-rw-r--r--test/system/test.common2
-rw-r--r--test/unit/ntp_core.c6
-rw-r--r--test/unit/ntp_sources.c2
-rw-r--r--test/unit/socket.c61
-rw-r--r--test/unit/util.c43
-rw-r--r--util.c27
-rw-r--r--util.h4
-rw-r--r--version.txt2
52 files changed, 1440 insertions, 422 deletions
diff --git a/FAQ b/FAQ
index 003a2f2..c96acfa 100644
--- a/FAQ
+++ b/FAQ
@@ -19,13 +19,15 @@ Table of Contents
? 2.8. Does chronyd have an ntpdate mode?
? 2.9. Can chronyd be configured to control the clock like ntpd?
? 2.10. Can NTP server be separated from NTP client?
- ? 2.11. Should be a leap smear enabled on NTP server?
- ? 2.12. How should chronyd be configured with gpsd?
- ? 2.13. Does chrony support PTP?
- ? 2.14. How can I avoid using wrong PHC refclock?
- ? 2.15. Why are client log records dropped before reaching
+ ? 2.11. How can chronyd be configured to minimise downtime during
+ restarts?
+ ? 2.12. Should be a leap smear enabled on NTP server?
+ ? 2.13. How should chronyd be configured with gpsd?
+ ? 2.14. Does chrony support PTP?
+ ? 2.15. How can I avoid using wrong PHC refclock?
+ ? 2.16. Why are client log records dropped before reaching
clientloglimit?
- ? 2.16. What happened to the commandkey and generatecommandkey
+ ? 2.17. What happened to the commandkey and generatecommandkey
directives?
o 3. Computer is not synchronising
? 3.1. Behind a firewall?
@@ -308,11 +310,11 @@ authselectmode directive.
An example of a client configuration limiting the impact of the attacks could
be
-server foo.example.net iburst nts maxdelay 0.1
-server bar.example.net iburst nts maxdelay 0.2
-server baz.example.net iburst nts maxdelay 0.05
-server qux.example.net iburst nts maxdelay 0.1
-server quux.example.net iburst nts maxdelay 0.1
+server ntp1.example.net iburst nts maxdelay 0.1
+server ntp2.example.net iburst nts maxdelay 0.2
+server ntp3.example.net iburst nts maxdelay 0.05
+server ntp4.example.net iburst nts maxdelay 0.1
+server ntp5.example.net iburst nts maxdelay 0.1
minsources 3
maxchange 100 0 0
makestep 0.001 1
@@ -357,7 +359,7 @@ longer polling interval might work better.
An example of the directive for an NTP server on the Internet that you are
allowed to poll frequently could be
-server foo.example.net minpoll 4 maxpoll 6 polltarget 16
+server ntp.example.net minpoll 4 maxpoll 6 polltarget 16
An example using shorter polling intervals with a server located in the same
LAN could be
@@ -407,13 +409,23 @@ outliers corrupting the minimum delay. For example:
server ntp.local minpoll -7 maxpoll -7 filter 31 maxdelayquant 0.3 xleave
-As an experimental feature added in version 4.2, chronyd supports an NTPv4
-extension field containing an additional timestamp to enable frequency transfer
-and significantly improve stability of synchronisation. It can be enabled by
-the extfield F323 option. For example:
+Since version 4.2, chronyd supports an NTPv4 extension field containing an
+additional timestamp to enable frequency transfer and significantly improve
+stability of synchronisation. It can be enabled by the extfield F323 option.
+For example:
server ntp.local minpoll 0 maxpoll 0 xleave extfield F323
+Since version 4.5, chronyd can apply corrections from PTP one-step end-to-end
+transparent clocks (e.g. network switches) to significantly improve accuracy of
+synchronisation in local networks. It requires the PTP transport to be enabled
+by the ptpport directive, HW timestamping, and the extfield F324 option. For
+example:
+
+server ntp.local minpoll -4 maxpoll -4 xleave extfield F323 extfield F324 port 319
+ptpport 319
+hwtimestamp eth0 minpoll -4
+
2.8. Does chronyd have an ntpdate mode?
Yes. With the -q option chronyd will set the system clock once and exit. With
@@ -511,7 +523,56 @@ bindcmdaddress /var/run/chrony/chronyd-server1.sock
pidfile /var/run/chronyd-server1.pid
driftfile /var/lib/chrony/drift-server1
-2.11. Should be a leap smear enabled on NTP server?
+2.11. How can chronyd be configured to minimise downtime during restarts?
+
+The dumpdir directive in chrony.conf provides chronyd a location to save a
+measurement history of the sources it uses when the service exits. The -r
+option then enables chronyd to load state from the dump files, reducing the
+synchronisation time after a restart.
+
+Similarly, the ntsdumpdir directive provides a location for chronyd to save NTS
+cookies received from the server to avoid making a NTS-KE request when chronyd
+is started. When operating as an NTS server, chronyd also saves cookies keys to
+this directory to allow clients to continue to use the old keys after a server
+restart for a more seamless experience.
+
+On Linux systems, systemd socket activation provides a mechanism to reuse
+server sockets across chronyd restarts, so that client requests will be
+buffered until the service is again able to handle the requests. This allows
+for zero-downtime service restarts, simplified dependency logic at boot, and
+on-demand service spawning (for instance, for separated server chronyd
+instances run with the -x flag).
+
+Socket activation is supported since chrony version 4.5. The service manager
+(systemd) creates sockets and passes file descriptors to them to the process
+via the LISTEN_FDS environment variable. Before opening new sockets, chronyd
+first checks for and attempts to reuse matching sockets passed from the service
+manager. For instance, if an IPv4 datagram socket bound on bindaddress and port
+is available, it will be used by the NTP server to accept incoming IPv4
+requests.
+
+An example systemd socket unit is below, where chronyd is configured with
+bindaddress 0.0.0.0, bindaddress ::, port 123, and ntsport 4460.
+
+[Unit]
+Description=chronyd server sockets
+
+[Socket]
+Service=chronyd.service
+# IPv4 NTP server
+ListenDatagram=0.0.0.0:123
+# IPv6 NTP server
+ListenDatagram=[::]:123
+# IPv4 NTS-KE server
+ListenStream=0.0.0.0:4460
+# IPv6 NTS-KE server
+ListenStream=[::]:4460
+BindIPv6Only=ipv6-only
+
+[Install]
+WantedBy=sockets.target
+
+2.12. Should be a leap smear enabled on NTP server?
With the smoothtime and leapsecmode directives it is possible to enable a
server leap smear in order to hide leap seconds from clients and force them to
@@ -525,7 +586,7 @@ identically configured leap-smearing servers. Note that some clients can get
leap seconds from other sources (e.g. with the leapsectz directive in chrony)
and they will not work correctly with a leap smearing server.
-2.12. How should chronyd be configured with gpsd?
+2.13. How should chronyd be configured with gpsd?
A GPS or other GNSS receiver can be used as a reference clock with gpsd. It can
work as one or two separate time sources for each connected receiver. The first
@@ -584,7 +645,7 @@ or the SHM equivalent if using gpsd version before 3.25
refclock SHM 0 offset 0.5 delay 0.1 refid GPS
-2.13. Does chrony support PTP?
+2.14. Does chrony support PTP?
No, the Precision Time Protocol (PTP) is not supported as a protocol for
synchronisation of clocks and there are no plans to support it. It is a complex
@@ -605,9 +666,12 @@ The ethtool -T command can be used to verify the timestamping support.
As an experimental feature added in version 4.2, chrony can use PTP as a
transport for NTP messages (NTP over PTP) to enable hardware timestamping on
hardware which can timestamp PTP packets only. It can be enabled by the ptpport
-directive.
+directive. Since version 4.5, chrony can also apply corrections provided by PTP
+one-step end-to-end transparent clocks to reach the accuracy of ordinary PTP
+clocks. The application of PTP corrections can be enabled by the extfield F324
+option.
-2.14. How can I avoid using wrong PHC refclock?
+2.15. How can I avoid using wrong PHC refclock?
If your system has multiple PHC devices, normally named by udev as /dev/ptp0, /
dev/ptp1, and so on, their order can change randomly across reboots depending
@@ -622,7 +686,7 @@ You can get the full DEVPATH of an existing PHC device with the udevadm info
command. You will need to execute the udevadm trigger command, or reboot the
system, for these changes to take effect.
-2.15. Why are client log records dropped before reaching clientloglimit?
+2.16. Why are client log records dropped before reaching clientloglimit?
The number of dropped client log records reported by the serverstats command
can be increasing before the number of clients reported by the clients command
@@ -643,7 +707,7 @@ than the limit even when the maximum number of records is used.
The absolute maximum number of client records kept at the same time is
16777216.
-2.16. What happened to the commandkey and generatecommandkey directives?
+2.17. What happened to the commandkey and generatecommandkey directives?
They were removed in version 2.2. Authentication is no longer supported in the
command protocol. Commands that required authentication are now allowed only
@@ -671,9 +735,9 @@ command issued few minutes after chronyd start might look like this:
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
-^* foo.example.net 2 6 377 34 +484us[ -157us] +/- 30ms
-^- bar.example.net 2 6 377 34 +33ms[ +32ms] +/- 47ms
-^+ baz.example.net 3 6 377 35 -1397us[-2033us] +/- 60ms
+^* ntp1.example.net 2 6 377 34 +484us[ -157us] +/- 30ms
+^- ntp2.example.net 2 6 377 34 +33ms[ +32ms] +/- 47ms
+^+ ntp3.example.net 3 6 377 35 -1397us[-2033us] +/- 60ms
3.2. Are NTP servers specified with the offline option?
@@ -733,9 +797,9 @@ Run the authdata command to check whether the key establishment was successful:
# chronyc -N authdata
Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen
=========================================================================
-foo.example.net NTS 1 15 256 33m 0 0 8 100
-bar.example.net NTS 1 15 256 33m 0 0 8 100
-baz.example.net NTS 1 15 256 33m 0 0 8 100
+ntp1.example.net NTS 1 15 256 33m 0 0 8 100
+ntp2.example.net NTS 1 15 256 33m 0 0 8 100
+ntp3.example.net NTS 1 15 256 33m 0 0 8 100
The KeyID, Type, and KLen columns should have non-zero values. If they are
zero, check the system log for error messages from chronyd. One possible cause
@@ -850,7 +914,7 @@ Name/IP Address NP NR Span Frequency Freq Skew Offset Std Dev
==============================================================================
PPS0 0 0 0 +0.000 2000.000 +0ns 4000ms
NMEA 58 30 231 -96.494 38.406 +504ms 6080us
-foo.example.net 7 3 200 -2.991 16.141 -107us 492us
+ntp1.example.net 7 3 200 -2.991 16.141 -107us 492us
the offset of the NMEA source would need to be increased by about 0.504
seconds. It does not have to be very accurate. As long as the offset of the
@@ -1092,4 +1156,4 @@ needs to be made to work as a service.
We have no plans to do this. Anyone is welcome to pick this work up and
contribute it back to the project.
-Last updated 2023-08-09 15:20:55 +0200
+Last updated 2023-12-05 14:22:10 +0100
diff --git a/INSTALL b/INSTALL
index 6c542bd..9ca6e22 100644
--- a/INSTALL
+++ b/INSTALL
@@ -162,4 +162,4 @@ tar cvf - . | gzip -9 > chrony.tar.gz
to build a package. When untarred within the root directory, this will install
the files to the intended final locations.
-Last updated 2023-08-09 15:20:55 +0200
+Last updated 2023-12-05 14:22:10 +0100
diff --git a/NEWS b/NEWS
index 2e9a743..93b21ed 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,17 @@
+New in version 4.5
+==================
+
+Enhancements
+------------
+* Add support for AES-GCM-SIV in GnuTLS
+* Add support for corrections from PTP transparent clocks
+* Add support for systemd socket activation
+
+Bug fixes
+---------
+* Fix presend in interleaved mode
+* Fix reloading of modified sources from sourcedir
+
New in version 4.4
==================
diff --git a/README b/README
index 99b0239..1eeac1b 100644
--- a/README
+++ b/README
@@ -125,6 +125,7 @@ Andreas Steinmetz <ast@domdv.de>
NAKAMURA Takumi <takumi@ps.sakura.ne.jp>
Timo Teras <timo.teras@iki.fi>
Bill Unruh <unruh@physics.ubc.ca>
+Luke Valenta <lvalenta@cloudflare.com>
Stephen Wadeley <swadeley@redhat.com>
Bernhard Weiss <lisnablagh@web.de>
Wolfgang Weisselberg <weissel@netcologne.de>
diff --git a/candm.h b/candm.h
index b5b1b7f..033cdb9 100644
--- a/candm.h
+++ b/candm.h
@@ -277,7 +277,8 @@ typedef struct {
#define REQ_ADDSRC_BURST 0x100
#define REQ_ADDSRC_NTS 0x200
#define REQ_ADDSRC_COPY 0x400
-#define REQ_ADDSRC_EF_EXP1 0x800
+#define REQ_ADDSRC_EF_EXP_MONO_ROOT 0x800
+#define REQ_ADDSRC_EF_EXP_NET_CORRECTION 0x1000
typedef struct {
uint32_t type;
diff --git a/client.c b/client.c
index 5c056bc..7cfefba 100644
--- a/client.c
+++ b/client.c
@@ -958,7 +958,10 @@ process_cmd_add_source(CMD_Request *msg, char *line)
(data.params.burst ? REQ_ADDSRC_BURST : 0) |
(data.params.nts ? REQ_ADDSRC_NTS : 0) |
(data.params.copy ? REQ_ADDSRC_COPY : 0) |
- (data.params.ext_fields & NTP_EF_FLAG_EXP1 ? REQ_ADDSRC_EF_EXP1 : 0) |
+ (data.params.ext_fields & NTP_EF_FLAG_EXP_MONO_ROOT ?
+ REQ_ADDSRC_EF_EXP_MONO_ROOT : 0) |
+ (data.params.ext_fields & NTP_EF_FLAG_EXP_NET_CORRECTION ?
+ REQ_ADDSRC_EF_EXP_NET_CORRECTION : 0) |
convert_addsrc_sel_options(data.params.sel_options));
msg->data.ntp_source.filter_length = htonl(data.params.filter_length);
msg->data.ntp_source.cert_set = htonl(data.params.cert_set);
diff --git a/cmdmon.c b/cmdmon.c
index c2c5bf0..9adc9d6 100644
--- a/cmdmon.c
+++ b/cmdmon.c
@@ -783,8 +783,10 @@ handle_add_source(CMD_Request *rx_message, CMD_Reply *tx_message)
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.ext_fields = (ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_EF_EXP_MONO_ROOT ?
+ NTP_EF_FLAG_EXP_MONO_ROOT : 0) |
+ (ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_EF_EXP_NET_CORRECTION ?
+ NTP_EF_FLAG_EXP_NET_CORRECTION : 0);
params.sel_options = convert_addsrc_select_options(ntohl(rx_message->data.ntp_source.flags));
status = NSR_AddSourceByName(name, port, pool, type, &params, NULL);
diff --git a/cmdparse.c b/cmdparse.c
index c20e8a3..ac5ace2 100644
--- a/cmdparse.c
+++ b/cmdparse.c
@@ -115,8 +115,11 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
if (sscanf(line, "%"SCNx32"%n", &ef_type, &n) != 1)
return 0;
switch (ef_type) {
- case NTP_EF_EXP1:
- src->params.ext_fields |= NTP_EF_FLAG_EXP1;
+ case NTP_EF_EXP_MONO_ROOT:
+ src->params.ext_fields |= NTP_EF_FLAG_EXP_MONO_ROOT;
+ break;
+ case NTP_EF_EXP_NET_CORRECTION:
+ src->params.ext_fields |= NTP_EF_FLAG_EXP_NET_CORRECTION;
break;
default:
return 0;
diff --git a/conf.c b/conf.c
index f984060..fa74459 100644
--- a/conf.c
+++ b/conf.c
@@ -1660,11 +1660,11 @@ compare_sources(const void *a, const void *b)
return 1;
if ((d = strcmp(sa->params.name, sb->params.name)) != 0)
return d;
- if ((d = (int)(sa->type) - (int)(sb->type)) != 0)
+ if ((d = (int)sa->type - (int)sb->type) != 0)
return d;
- if ((d = sa->pool - sb->pool) != 0)
+ if ((d = (int)sa->pool - (int)sb->pool) != 0)
return d;
- if ((d = sa->params.port - sb->params.port) != 0)
+ if ((d = (int)sa->params.port - (int)sb->params.port) != 0)
return d;
return memcmp(&sa->params.params, &sb->params.params, sizeof (sa->params.params));
}
@@ -1679,7 +1679,7 @@ reload_source_dirs(void)
uint32_t *prev_ids, *new_ids;
char buf[MAX_LINE_LENGTH];
NSR_Status s;
- int d;
+ int d, pass;
prev_size = ARR_GetSize(ntp_source_ids);
if (prev_size > 0 && ARR_GetSize(ntp_sources) != prev_size)
@@ -1713,36 +1713,38 @@ reload_source_dirs(void)
qsort(new_sources, new_size, sizeof (new_sources[0]), compare_sources);
- for (i = j = 0; i < prev_size || j < new_size; ) {
- if (i < prev_size && j < new_size)
- d = compare_sources(&prev_sources[i], &new_sources[j]);
- else
- d = i < prev_size ? -1 : 1;
+ for (pass = 0; pass < 2; pass++) {
+ for (i = j = 0; i < prev_size || j < new_size; i += d <= 0, j += d >= 0) {
+ if (i < prev_size && j < new_size)
+ d = compare_sources(&prev_sources[i], &new_sources[j]);
+ else
+ d = i < prev_size ? -1 : 1;
- if (d < 0) {
- /* Remove the missing source */
- if (prev_sources[i].params.name[0] != '\0')
+ /* Remove missing sources before adding others to avoid conflicts */
+ if (pass == 0 && d < 0 && prev_sources[i].params.name[0] != '\0') {
NSR_RemoveSourcesById(prev_ids[i]);
- i++;
- } else if (d > 0) {
- /* Add a newly configured source */
- source = &new_sources[j];
- s = NSR_AddSourceByName(source->params.name, source->params.port, source->pool,
- source->type, &source->params.params, &new_ids[j]);
-
- if (s == NSR_UnresolvedName) {
- unresolved++;
- } else if (s != NSR_Success) {
- LOG(LOGS_ERR, "Could not add source %s", source->params.name);
-
- /* Mark the source as not present */
- source->params.name[0] = '\0';
}
- j++;
- } else {
- /* Keep the existing source */
- new_ids[j] = prev_ids[i];
- i++, j++;
+
+ /* Add new sources */
+ if (pass == 1 && d > 0) {
+ source = &new_sources[j];
+ s = NSR_AddSourceByName(source->params.name, source->params.port, source->pool,
+ source->type, &source->params.params, &new_ids[j]);
+
+ if (s == NSR_UnresolvedName) {
+ unresolved++;
+ } else if (s != NSR_Success) {
+ LOG(LOGS_ERR, "Could not add source %s : %s",
+ source->params.name, NSR_StatusToString(s));
+
+ /* Mark the source as not present */
+ source->params.name[0] = '\0';
+ }
+ }
+
+ /* Keep unchanged sources */
+ if (pass == 1 && d == 0)
+ new_ids[j] = prev_ids[i];
}
}
diff --git a/configure b/configure
index 81bb4b8..eefe5de 100755
--- a/configure
+++ b/configure
@@ -111,10 +111,10 @@ For better control, use the options below.
--without-editline Don't use editline even if it is available
--disable-sechash Disable support for hashes other than MD5
--without-nettle Don't use nettle even if it is available
+ --without-gnutls Don't use gnutls even if it is available
--without-nss Don't use NSS even if it is available
--without-tomcrypt Don't use libtomcrypt even if it is available
--disable-nts Disable NTS support
- --without-gnutls Don't use gnutls even if it is available
--disable-cmdmon Disable command and monitoring support
--disable-ntp Disable NTP support
--disable-refclock Disable reference clock support
@@ -926,6 +926,28 @@ if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_nettle = "1" ];
fi
fi
+if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_gnutls = "1" ]; then
+ test_cflags="`pkg_config --cflags gnutls`"
+ test_link="`pkg_config --libs gnutls`"
+ if test_code 'gnutls' 'gnutls/crypto.h' \
+ "$test_cflags" "$test_link" '
+ return gnutls_hash((void *)1, (void *)2, 1);'
+ then
+ HASH_OBJ="hash_gnutls.o"
+ HASH_LINK="$test_link"
+ MYCPPFLAGS="$MYCPPFLAGS $test_cflags"
+ add_def FEAT_SECHASH
+
+ if test_code 'CMAC in gnutls' 'gnutls/crypto.h' "$test_cflags" "$test_link" \
+ 'return gnutls_hmac_init((void *)1, GNUTLS_MAC_AES_CMAC_128, (void *)2, 0);'
+ then
+ add_def HAVE_CMAC
+ EXTRA_OBJECTS="$EXTRA_OBJECTS cmac_gnutls.o"
+ EXTRA_CLI_OBJECTS="$EXTRA_CLI_OBJECTS cmac_gnutls.o"
+ fi
+ fi
+fi
+
if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_nss = "1" ]; then
test_cflags="`pkg_config --cflags nss`"
test_link="`pkg_config --libs-only-L nss` -lfreebl3 -lnssutil3"
@@ -951,28 +973,6 @@ if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_tomcrypt = "1" ]
fi
fi
-if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_gnutls = "1" ]; then
- test_cflags="`pkg_config --cflags gnutls`"
- test_link="`pkg_config --libs gnutls`"
- if test_code 'gnutls' 'gnutls/crypto.h' \
- "$test_cflags" "$test_link" '
- return gnutls_hash((void *)1, (void *)2, 1);'
- then
- HASH_OBJ="hash_gnutls.o"
- HASH_LINK="$test_link"
- MYCPPFLAGS="$MYCPPFLAGS $test_cflags"
- add_def FEAT_SECHASH
-
- if test_code 'CMAC in gnutls' 'gnutls/crypto.h' "$test_cflags" "$test_link" \
- 'return gnutls_hmac_init((void *)1, GNUTLS_MAC_AES_CMAC_128, (void *)2, 0);'
- then
- add_def HAVE_CMAC
- EXTRA_OBJECTS="$EXTRA_OBJECTS cmac_gnutls.o"
- EXTRA_CLI_OBJECTS="$EXTRA_CLI_OBJECTS cmac_gnutls.o"
- fi
- fi
-fi
-
EXTRA_OBJECTS="$EXTRA_OBJECTS $HASH_OBJ"
EXTRA_CLI_OBJECTS="$EXTRA_CLI_OBJECTS $HASH_OBJ"
LIBS="$LIBS $HASH_LINK"
@@ -991,7 +991,7 @@ if [ $feat_ntp = "1" ] && [ $feat_nts = "1" ] && [ $try_gnutls = "1" ]; then
gnutls_priority_init2((void *)1, "", NULL, GNUTLS_PRIORITY_INIT_DEF_APPEND) +
gnutls_prf_rfc5705((void *)1, 0, "", 0, "", 16, (void *)2);'
then
- if test_code 'AES-SIV-CMAC in nettle' \
+ if [ $try_nettle = "1" ] && test_code 'AES-SIV-CMAC in nettle' \
'nettle/siv-cmac.h' "" "$LIBS" \
'siv_cmac_aes128_set_key((void *)1, (void *)2);'
then
@@ -1012,6 +1012,13 @@ if [ $feat_ntp = "1" ] && [ $feat_nts = "1" ] && [ $try_gnutls = "1" ]; then
then
EXTRA_OBJECTS="$EXTRA_OBJECTS siv_gnutls.o"
add_def HAVE_SIV
+ if [ $try_aes_gcm_siv = "1" ] && test_code 'AES-GCM-SIV in gnutls' \
+ 'gnutls/crypto.h' "$test_cflags" "$test_link $LIBS" '
+ return gnutls_aead_cipher_init((void *)1, GNUTLS_CIPHER_AES_128_SIV_GCM,
+ (void *)2);'
+ then
+ add_def HAVE_GNUTLS_SIV_GCM
+ fi
if test_code 'gnutls_aead_cipher_set_key()' 'gnutls/crypto.h' \
"$test_cflags" "$test_link $LIBS" '
return gnutls_aead_cipher_set_key((void *)1, (void *)2);'
diff --git a/doc/chrony.conf.adoc b/doc/chrony.conf.adoc
index 4af870d..cb3f95c 100644
--- a/doc/chrony.conf.adoc
+++ b/doc/chrony.conf.adoc
@@ -322,16 +322,27 @@ server implementations do not respond to requests containing an unknown
extension field (*chronyd* as a server responded to such requests since
version 2.0).
+
-The following extension field can be enabled by this option:
+This option can be used multiple times to enable multiple extension fields.
++
+The following extension fields are supported:
+
_F323_::::
-This is an experimental extension field for some improvements that were
+An experimental extension field to enable several improvements that were
proposed for the next version of the NTP protocol (NTPv5). The field contains
root delay and dispersion in higher resolution and a monotonic receive
-timestamp, which enables a frequency transfer between the server and client. It
-can significantly improve stability of the synchronization. Generally, it
-should be expected to work only between servers and clients running the same
-version of *chronyd*.
+timestamp, which enables a frequency transfer between the server and client to
+significantly improve stability of the synchronisation. This field should be
+enabled only for servers known to be running *chronyd* version 4.2 or later.
+_F324_::::
+An experimental extension field to enable the use of the Precision Time
+Protocol (PTP) correction field in NTP-over-PTP messages updated by one-step
+end-to-end transparent clocks in network switches and routers to significantly
+improve accuracy and stability of the synchronisation. NTP-over-PTP can be
+enabled by the <<ptpport,*ptpport*>> directive and setting the *port* option to
+the PTP port. The corrections are applied only to NTP measurements with HW
+timestamps (enabled by the <<hwtimestamp,*hwtimestamp*>> directive). This
+field should be enabled only for servers known to be running *chronyd* version
+4.5 or later.
{blank}:::
[[pool]]*pool* _name_ [_option_]...::
@@ -418,7 +429,7 @@ error. *chronyd* then enters its normal operating mode.
An example of the use of the directive is:
+
----
-initstepslew 30 foo.example.net bar.example.net baz.example.net
+initstepslew 30 ntp1.example.net ntp2.example.net ntp3.example.net
----
+
where 3 NTP servers are used to make the measurement. The _30_ indicates that
@@ -833,9 +844,10 @@ sources using NTS, otherwise the source with a longer polling interval will
refresh the keys on each poll and no NTP packets will be exchanged.
[[ntstrustedcerts]]*ntstrustedcerts* [_set-ID_] _file_|_directory_::
-This directive specifies a file or directory containing certificates (in the
-PEM format) of trusted certificate authorities (CA) which can be used to
-verify certificates of NTS servers.
+This directive specifies a file or directory containing trusted certificates
+(in the PEM format) which are needed to verify certificates of NTS-KE servers,
+e.g. certificates of trusted certificate authorities (CA) or self-signed
+certificates of the servers.
+
The optional _set-ID_ argument is a number in the range 0 through 2^32-1, which
selects the set of certificates where certificates from the specified file
@@ -855,10 +867,10 @@ they change (e.g. after a renewal).
An example is:
+
----
-ntstrustedcerts /etc/pki/nts/foo.crt
-ntstrustedcerts 1 /etc/pki/nts/bar.crt
-ntstrustedcerts 1 /etc/pki/nts/baz.crt
-ntstrustedcerts 2 /etc/pki/nts/qux.crt
+ntstrustedcerts /etc/pki/nts/ca1.example.net.crt
+ntstrustedcerts 1 /etc/pki/nts/ca2.example.net.crt
+ntstrustedcerts 1 /etc/pki/nts/ca3.example.net.crt
+ntstrustedcerts 2 /etc/pki/nts/ntp2.example.net.crt
----
[[nosystemcert]]*nosystemcert*::
@@ -955,9 +967,9 @@ before 4.0.
As an example, the following configuration using the default *mix* mode:
+
----
-server foo.example.net nts
-server bar.example.net nts
-server baz.example.net
+server ntp1.example.net nts
+server ntp2.example.net nts
+server ntp3.example.net
refclock SOCK /var/run/chrony.ttyS0.sock
----
+
@@ -965,9 +977,9 @@ is equivalent to the following configuration using the *ignore* mode:
+
----
authselectmode ignore
-server foo.example.net nts require trust
-server bar.example.net nts require trust
-server baz.example.net
+server ntp1.example.net nts require trust
+server ntp2.example.net nts require trust
+server ntp3.example.net
refclock /var/run/chrony.ttyS0.sock require trust
----
@@ -1976,8 +1988,9 @@ all* directive.
[[cmdport]]*cmdport* _port_::
The *cmdport* directive allows the port that is used for run-time monitoring
(via the *chronyc* program) to be altered from its default (323). If set to 0,
-*chronyd* will not open the port, this is useful to disable *chronyc*
-access from the Internet. (It does not disable the Unix domain command socket.)
+*chronyd* will not open the port, which disables remote *chronyc* access (with
+a non-default *bindcmdaddress*) and local access for unprivileged users. It
+does not disable the Unix domain command socket.
+
An example shows the syntax:
+
@@ -1986,7 +1999,7 @@ cmdport 257
----
+
This would make *chronyd* use UDP 257 as its command port. (*chronyc* would
-need to be run with the *-p 257* switch to inter-operate correctly.)
+need to be run with the *-p 257* option to inter-operate correctly.)
[[cmdratelimit]]*cmdratelimit* [_option_]...::
This directive enables response rate limiting for command packets. It is
@@ -2728,24 +2741,27 @@ pidfile /run/chronyd.pid
The *ptpport* directive enables *chronyd* to send and receive NTP messages
contained in PTP event messages (NTP-over-PTP) to enable hardware timestamping
on NICs which cannot timestamp NTP packets, but can timestamp unicast PTP
-packets. The port recognized by the NICs is 319 (PTP event port). The default
-value is 0 (disabled).
+packets, and also use corrections provided by PTP one-step end-to-end
+transparent clocks in network switches and routers. The port recognized by the
+NICs and PTP transparent clocks is 319 (PTP event port). The default value is 0
+(disabled).
+
The NTP-over-PTP support is experimental. The protocol and configuration can
-change in future. It should be used only in local networks and expected to work
-only between servers and clients running the same version of *chronyd*.
+change in future. It should be used only in local networks.
+
The PTP port will be open even if *chronyd* is not configured to operate as a
server or client. The directive does not change the default protocol of
specified NTP sources. Each NTP source that should use NTP-over-PTP needs to
be specified with the *port* option set to the PTP port. To actually enable
hardware timestamping on NICs which can timestamp PTP packets only, the
-*rxfilter* option of the *hwtimestamp* directive needs to be set to _ptp_.
+*rxfilter* option of the *hwtimestamp* directive needs to be set to _ptp_. The
+extension field _F324_ needs to be enabled to use the corrections provided by
+the PTP transparent clocks.
+
An example of client configuration is:
+
----
-server foo.example.net minpoll 0 maxpoll 0 xleave port 319
+server ntp1.example.net minpoll 0 maxpoll 0 xleave port 319 extfield F324
hwtimestamp * rxfilter ptp
ptpport 319
----
@@ -2806,13 +2822,13 @@ the following methods:
facilities.
* Use public servers from the https://www.pool.ntp.org/[pool.ntp.org] project.
-Assuming that your NTP servers are called _foo.example.net_, _bar.example.net_
-and _baz.example.net_, your _chrony.conf_ file could contain as a minimum:
+Assuming that your NTP servers are called _ntp1.example.net_, _ntp2.example.net_
+and _ntp3.example.net_, your _chrony.conf_ file could contain as a minimum:
----
-server foo.example.net
-server bar.example.net
-server baz.example.net
+server ntp1.example.net
+server ntp2.example.net
+server ntp3.example.net
----
However, you will probably want to include some of the other directives. The
@@ -2823,9 +2839,9 @@ synchronisation. The smallest useful configuration file would look something
like:
----
-server foo.example.net iburst
-server bar.example.net iburst
-server baz.example.net iburst
+server ntp1.example.net iburst
+server ntp2.example.net iburst
+server ntp3.example.net iburst
driftfile @CHRONYVARDIR@/drift
makestep 1.0 3
rtcsync
@@ -2849,9 +2865,9 @@ option will enable a secure synchronisation to the servers. The configuration
file could look like:
----
-server foo.example.net iburst nts
-server bar.example.net iburst nts
-server baz.example.net iburst nts
+server ntp1.example.net iburst nts
+server ntp2.example.net iburst nts
+server ntp3.example.net iburst nts
driftfile @CHRONYVARDIR@/drift
makestep 1.0 3
rtcsync
@@ -2865,14 +2881,14 @@ additional configuration to tell *chronyd* when the connection goes up and
down. This saves the program from continuously trying to poll the servers when
they are inaccessible.
-Again, assuming that your NTP servers are called _foo.example.net_,
-_bar.example.net_ and _baz.example.net_, your _chrony.conf_ file would now
+Again, assuming that your NTP servers are called _ntp1.example.net_,
+_ntp2.example.net_ and _ntp3.example.net_, your _chrony.conf_ file would now
contain:
----
-server foo.example.net offline
-server bar.example.net offline
-server baz.example.net offline
+server ntp1.example.net offline
+server ntp2.example.net offline
+server ntp3.example.net offline
driftfile @CHRONYVARDIR@/drift
makestep 1.0 3
rtcsync
@@ -3056,9 +3072,9 @@ configuration files are shown.
For the _chrony.conf_ file, the following can be used as an example.
----
-server foo.example.net maxdelay 0.4 offline
-server bar.example.net maxdelay 0.4 offline
-server baz.example.net maxdelay 0.4 offline
+server ntp1.example.net maxdelay 0.4 offline
+server ntp2.example.net maxdelay 0.4 offline
+server ntp3.example.net maxdelay 0.4 offline
logdir /var/log/chrony
log statistics measurements tracking
driftfile @CHRONYVARDIR@/drift
@@ -3117,10 +3133,10 @@ configuration).
The configuration file could look like:
----
-server foo.example.net iburst
-server bar.example.net iburst
-server baz.example.net iburst
-server qux.example.net iburst
+server ntp1.example.net iburst
+server ntp2.example.net iburst
+server ntp3.example.net iburst
+server ntp4.example.net iburst
makestep 1.0 3
rtcsync
allow
diff --git a/doc/chrony.conf.man.in b/doc/chrony.conf.man.in
index f3e52d9..66d2358 100644
--- a/doc/chrony.conf.man.in
+++ b/doc/chrony.conf.man.in
@@ -2,12 +2,12 @@
.\" Title: chrony.conf
.\" Author: [see the "AUTHOR(S)" section]
.\" Generator: Asciidoctor 2.0.20
-.\" Date: 2023-08-09
+.\" Date: 2023-12-05
.\" Manual: Configuration Files
.\" Source: chrony @CHRONY_VERSION@
.\" Language: English
.\"
-.TH "CHRONY.CONF" "5" "2023-08-09" "chrony @CHRONY_VERSION@" "Configuration Files"
+.TH "CHRONY.CONF" "5" "2023-12-05" "chrony @CHRONY_VERSION@" "Configuration Files"
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.ss \n[.ss] 0
@@ -422,17 +422,31 @@ server implementations do not respond to requests containing an unknown
extension field (\fBchronyd\fP as a server responded to such requests since
version 2.0).
.sp
-The following extension field can be enabled by this option:
+This option can be used multiple times to enable multiple extension fields.
+.sp
+The following extension fields are supported:
.sp
\fIF323\fP
.RS 4
-This is an experimental extension field for some improvements that were
+An experimental extension field to enable several improvements that were
proposed for the next version of the NTP protocol (NTPv5). The field contains
root delay and dispersion in higher resolution and a monotonic receive
-timestamp, which enables a frequency transfer between the server and client. It
-can significantly improve stability of the synchronization. Generally, it
-should be expected to work only between servers and clients running the same
-version of \fBchronyd\fP.
+timestamp, which enables a frequency transfer between the server and client to
+significantly improve stability of the synchronisation. This field should be
+enabled only for servers known to be running \fBchronyd\fP version 4.2 or later.
+.RE
+.sp
+\fIF324\fP
+.RS 4
+An experimental extension field to enable the use of the Precision Time
+Protocol (PTP) correction field in NTP\-over\-PTP messages updated by one\-step
+end\-to\-end transparent clocks in network switches and routers to significantly
+improve accuracy and stability of the synchronisation. NTP\-over\-PTP can be
+enabled by the \fBptpport\fP directive and setting the \fBport\fP option to
+the PTP port. The corrections are applied only to NTP measurements with HW
+timestamps (enabled by the \fBhwtimestamp\fP directive). This
+field should be enabled only for servers known to be running \fBchronyd\fP version
+4.5 or later.
.RE
.RE
.sp
@@ -538,7 +552,7 @@ An example of the use of the directive is:
.if n .RS 4
.nf
.fam C
-initstepslew 30 foo.example.net bar.example.net baz.example.net
+initstepslew 30 ntp1.example.net ntp2.example.net ntp3.example.net
.fam
.fi
.if n .RE
@@ -1116,9 +1130,10 @@ refresh the keys on each poll and no NTP packets will be exchanged.
.sp
\fBntstrustedcerts\fP [\fIset\-ID\fP] \fIfile\fP|\fIdirectory\fP
.RS 4
-This directive specifies a file or directory containing certificates (in the
-PEM format) of trusted certificate authorities (CA) which can be used to
-verify certificates of NTS servers.
+This directive specifies a file or directory containing trusted certificates
+(in the PEM format) which are needed to verify certificates of NTS\-KE servers,
+e.g. certificates of trusted certificate authorities (CA) or self\-signed
+certificates of the servers.
.sp
The optional \fIset\-ID\fP argument is a number in the range 0 through 2^32\-1, which
selects the set of certificates where certificates from the specified file
@@ -1140,10 +1155,10 @@ An example is:
.if n .RS 4
.nf
.fam C
-ntstrustedcerts /etc/pki/nts/foo.crt
-ntstrustedcerts 1 /etc/pki/nts/bar.crt
-ntstrustedcerts 1 /etc/pki/nts/baz.crt
-ntstrustedcerts 2 /etc/pki/nts/qux.crt
+ntstrustedcerts /etc/pki/nts/ca1.example.net.crt
+ntstrustedcerts 1 /etc/pki/nts/ca2.example.net.crt
+ntstrustedcerts 1 /etc/pki/nts/ca3.example.net.crt
+ntstrustedcerts 2 /etc/pki/nts/ntp2.example.net.crt
.fam
.fi
.if n .RE
@@ -1269,9 +1284,9 @@ As an example, the following configuration using the default \fBmix\fP mode:
.if n .RS 4
.nf
.fam C
-server foo.example.net nts
-server bar.example.net nts
-server baz.example.net
+server ntp1.example.net nts
+server ntp2.example.net nts
+server ntp3.example.net
refclock SOCK /var/run/chrony.ttyS0.sock
.fam
.fi
@@ -1283,9 +1298,9 @@ is equivalent to the following configuration using the \fBignore\fP mode:
.nf
.fam C
authselectmode ignore
-server foo.example.net nts require trust
-server bar.example.net nts require trust
-server baz.example.net
+server ntp1.example.net nts require trust
+server ntp2.example.net nts require trust
+server ntp3.example.net
refclock /var/run/chrony.ttyS0.sock require trust
.fam
.fi
@@ -2545,8 +2560,9 @@ all\fP directive.
.RS 4
The \fBcmdport\fP directive allows the port that is used for run\-time monitoring
(via the \fBchronyc\fP program) to be altered from its default (323). If set to 0,
-\fBchronyd\fP will not open the port, this is useful to disable \fBchronyc\fP
-access from the Internet. (It does not disable the Unix domain command socket.)
+\fBchronyd\fP will not open the port, which disables remote \fBchronyc\fP access (with
+a non\-default \fBbindcmdaddress\fP) and local access for unprivileged users. It
+does not disable the Unix domain command socket.
.sp
An example shows the syntax:
.sp
@@ -2559,7 +2575,7 @@ cmdport 257
.if n .RE
.sp
This would make \fBchronyd\fP use UDP 257 as its command port. (\fBchronyc\fP would
-need to be run with the \fB\-p 257\fP switch to inter\-operate correctly.)
+need to be run with the \fB\-p 257\fP option to inter\-operate correctly.)
.RE
.sp
\fBcmdratelimit\fP [\fIoption\fP]...
@@ -4511,26 +4527,29 @@ pidfile /run/chronyd.pid
The \fBptpport\fP directive enables \fBchronyd\fP to send and receive NTP messages
contained in PTP event messages (NTP\-over\-PTP) to enable hardware timestamping
on NICs which cannot timestamp NTP packets, but can timestamp unicast PTP
-packets. The port recognized by the NICs is 319 (PTP event port). The default
-value is 0 (disabled).
+packets, and also use corrections provided by PTP one\-step end\-to\-end
+transparent clocks in network switches and routers. The port recognized by the
+NICs and PTP transparent clocks is 319 (PTP event port). The default value is 0
+(disabled).
.sp
The NTP\-over\-PTP support is experimental. The protocol and configuration can
-change in future. It should be used only in local networks and expected to work
-only between servers and clients running the same version of \fBchronyd\fP.
+change in future. It should be used only in local networks.
.sp
The PTP port will be open even if \fBchronyd\fP is not configured to operate as a
server or client. The directive does not change the default protocol of
specified NTP sources. Each NTP source that should use NTP\-over\-PTP needs to
be specified with the \fBport\fP option set to the PTP port. To actually enable
hardware timestamping on NICs which can timestamp PTP packets only, the
-\fBrxfilter\fP option of the \fBhwtimestamp\fP directive needs to be set to \fIptp\fP.
+\fBrxfilter\fP option of the \fBhwtimestamp\fP directive needs to be set to \fIptp\fP. The
+extension field \fIF324\fP needs to be enabled to use the corrections provided by
+the PTP transparent clocks.
.sp
An example of client configuration is:
.sp
.if n .RS 4
.nf
.fam C
-server foo.example.net minpoll 0 maxpoll 0 xleave port 319
+server ntp1.example.net minpoll 0 maxpoll 0 xleave port 319 extfield F324
hwtimestamp * rxfilter ptp
ptpport 319
.fam
@@ -4636,15 +4655,15 @@ Use public servers from the \c
project.
.RE
.sp
-Assuming that your NTP servers are called \fIfoo.example.net\fP, \fIbar.example.net\fP
-and \fIbaz.example.net\fP, your \fIchrony.conf\fP file could contain as a minimum:
+Assuming that your NTP servers are called \fIntp1.example.net\fP, \fIntp2.example.net\fP
+and \fIntp3.example.net\fP, your \fIchrony.conf\fP file could contain as a minimum:
.sp
.if n .RS 4
.nf
.fam C
-server foo.example.net
-server bar.example.net
-server baz.example.net
+server ntp1.example.net
+server ntp2.example.net
+server ntp3.example.net
.fam
.fi
.if n .RE
@@ -4659,9 +4678,9 @@ like:
.if n .RS 4
.nf
.fam C
-server foo.example.net iburst
-server bar.example.net iburst
-server baz.example.net iburst
+server ntp1.example.net iburst
+server ntp2.example.net iburst
+server ntp3.example.net iburst
driftfile @CHRONYVARDIR@/drift
makestep 1.0 3
rtcsync
@@ -4693,9 +4712,9 @@ file could look like:
.if n .RS 4
.nf
.fam C
-server foo.example.net iburst nts
-server bar.example.net iburst nts
-server baz.example.net iburst nts
+server ntp1.example.net iburst nts
+server ntp2.example.net iburst nts
+server ntp3.example.net iburst nts
driftfile @CHRONYVARDIR@/drift
makestep 1.0 3
rtcsync
@@ -4710,16 +4729,16 @@ additional configuration to tell \fBchronyd\fP when the connection goes up and
down. This saves the program from continuously trying to poll the servers when
they are inaccessible.
.sp
-Again, assuming that your NTP servers are called \fIfoo.example.net\fP,
-\fIbar.example.net\fP and \fIbaz.example.net\fP, your \fIchrony.conf\fP file would now
+Again, assuming that your NTP servers are called \fIntp1.example.net\fP,
+\fIntp2.example.net\fP and \fIntp3.example.net\fP, your \fIchrony.conf\fP file would now
contain:
.sp
.if n .RS 4
.nf
.fam C
-server foo.example.net offline
-server bar.example.net offline
-server baz.example.net offline
+server ntp1.example.net offline
+server ntp2.example.net offline
+server ntp3.example.net offline
driftfile @CHRONYVARDIR@/drift
makestep 1.0 3
rtcsync
@@ -4925,9 +4944,9 @@ For the \fIchrony.conf\fP file, the following can be used as an example.
.if n .RS 4
.nf
.fam C
-server foo.example.net maxdelay 0.4 offline
-server bar.example.net maxdelay 0.4 offline
-server baz.example.net maxdelay 0.4 offline
+server ntp1.example.net maxdelay 0.4 offline
+server ntp2.example.net maxdelay 0.4 offline
+server ntp3.example.net maxdelay 0.4 offline
logdir /var/log/chrony
log statistics measurements tracking
driftfile @CHRONYVARDIR@/drift
@@ -4998,10 +5017,10 @@ The configuration file could look like:
.if n .RS 4
.nf
.fam C
-server foo.example.net iburst
-server bar.example.net iburst
-server baz.example.net iburst
-server qux.example.net iburst
+server ntp1.example.net iburst
+server ntp2.example.net iburst
+server ntp3.example.net iburst
+server ntp4.example.net iburst
makestep 1.0 3
rtcsync
allow
diff --git a/doc/chronyc.adoc b/doc/chronyc.adoc
index 302d1d5..96a0551 100644
--- a/doc/chronyc.adoc
+++ b/doc/chronyc.adoc
@@ -144,7 +144,7 @@ The *tracking* command displays parameters about the system's clock
performance. An example of the output is shown below.
+
----
-Reference ID : CB00710F (foo.example.net)
+Reference ID : CB00710F (ntp1.example.net)
Stratum : 3
Ref time (UTC) : Fri Jan 27 09:49:17 2017
System time : 0.000006523 seconds slow of NTP time
@@ -178,7 +178,7 @@ with an IPv4 address.
*Stratum*:::
The stratum indicates how many hops away from a computer with an attached
reference clock we are. Such a computer is a stratum-1 computer, so the
-computer in the example is two hops away (i.e. _foo.example.net_ is a
+computer in the example is two hops away (i.e. _ntp1.example.net_ is a
stratum-2 and is synchronised from a stratum-1).
*Ref time*:::
This is the time (UTC) at which the last measurement from the reference
@@ -321,8 +321,8 @@ extra caption lines are shown as a reminder of the meanings of the columns.
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
#* GPS0 0 4 377 11 -479ns[ -621ns] +/- 134ns
-^? foo.example.net 2 6 377 23 -923us[ -924us] +/- 43ms
-^+ bar.example.net 1 6 377 21 -2629us[-2619us] +/- 86ms
+^? ntp1.example.net 2 6 377 23 -923us[ -924us] +/- 43ms
+^+ ntp2.example.net 1 6 377 21 -2629us[-2619us] +/- 86ms
----
+
The columns are as follows:
@@ -400,7 +400,7 @@ An example report is:
----
Name/IP Address NP NR Span Frequency Freq Skew Offset Std Dev
===============================================================================
-foo.example.net 11 5 46m -0.001 0.045 1us 25us
+ntp1.example.net 11 5 46m -0.001 0.045 1us 25us
----
+
The columns are as follows:
@@ -444,9 +444,9 @@ An example of the output is shown below.
----
S Name/IP Address Auth COpts EOpts Last Score Interval Leap
=======================================================================
-D foo.example.net Y ----- --TR- 4 1.0 -61ms +62ms N
-* bar.example.net N ----- ----- 0 1.0 -6846us +7305us N
-+ baz.example.net N ----- ----- 10 1.0 -7381us +7355us N
+D ntp1.example.net Y ----- --TR- 4 1.0 -61ms +62ms N
+* ntp2.example.net N ----- ----- 0 1.0 -6846us +7305us N
++ ntp3.example.net N ----- ----- 10 1.0 -7381us +7355us N
----
+
The columns are as follows:
@@ -592,9 +592,9 @@ shown below.
----
Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen
=========================================================================
-foo.example.net NTS 1 15 256 135m 0 0 8 100
-bar.example.net SK 30 13 128 - 0 0 0 0
-baz.example.net - 0 0 0 - 0 0 0 0
+ntp1.example.net NTS 1 15 256 135m 0 0 8 100
+ntp2.example.net SK 30 13 128 - 0 0 0 0
+ntp3.example.net - 0 0 0 - 0 0 0 0
----
+
The columns are as follows:
@@ -758,7 +758,7 @@ parameters and options is identical to that for the
An example of using this command is shown below.
+
----
-add peer foo.example.net minpoll 6 maxpoll 10 key 25
+add peer ntp1.example.net minpoll 6 maxpoll 10 key 25
----
[[add_pool]]*add pool* _name_ [_option_]...::
@@ -772,7 +772,7 @@ directive in the configuration file.
An example of using this command is shown below:
+
----
-add pool foo.example.net maxsources 3 iburst
+add pool ntp1.example.net maxsources 3 iburst
----
[[add_server]]*add server* _name_ [_option_]...::
@@ -786,7 +786,7 @@ directive in the configuration file.
An example of using this command is shown below:
+
----
-add server foo.example.net minpoll 6 maxpoll 10 key 25
+add server ntp1.example.net minpoll 6 maxpoll 10 key 25
----
[[delete]]*delete* _address_::
@@ -862,7 +862,7 @@ IPv6 addresses have first 48 bits equal to _2001:db8:789a_.
Example of the three-argument form of the command is:
+
----
-burst 2/10 foo.example.net
+burst 2/10 ntp1.example.net
----
[[maxdelay]]*maxdelay* _address_ _delay_::
@@ -928,7 +928,7 @@ uses an IP address or a hostname. These forms are illustrated below.
offline
offline 255.255.255.0/1.2.3.0
offline 2001:db8:789a::/48
-offline foo.example.net
+offline ntp1.example.net
----
+
The second form means that the *offline* command is to be applied to any source
@@ -986,6 +986,10 @@ command might replace the addresses even if they are still in the pool.
The *reload sources* command causes *chronyd* to re-read all _*.sources_ files
from the directories specified by the
<<chrony.conf.adoc#sourcedir,*sourcedir*>> directive.
++
+Note that modified sources (e.g. specified with a new option) are not modified
+in memory. They are removed and added again, which causes them to lose old
+measurements and reset the selection state.
[[sourcename]]*sourcename* _address_::
The *sourcename* command prints the original hostname or address that was
@@ -1094,7 +1098,7 @@ particular host.
Examples of use, showing a named host and a numeric IP address, are as follows:
+
----
-accheck foo.example.net
+accheck ntp1.example.net
accheck 1.2.3.4
accheck 2001:db8::1
----
@@ -1121,7 +1125,7 @@ An example of the output is:
Hostname NTP Drop Int IntL Last Cmd Drop Int Last
===============================================================================
localhost 2 0 2 - 133 15 0 -1 7
-foo.example.net 12 0 6 - 23 0 0 - -
+ntp1.example.net 12 0 6 - 23 0 0 - -
----
+
Each row shows the data for a single host. Only hosts that have passed the host
@@ -1321,7 +1325,7 @@ used to check whether monitoring access is permitted from a named host.
Examples of use are as follows:
+
----
-cmdaccheck foo.example.net
+cmdaccheck ntp1.example.net
cmdaccheck 1.2.3.4
cmdaccheck 2001:db8::1
----
diff --git a/doc/chronyc.man.in b/doc/chronyc.man.in
index 55a05b7..4541fc6 100644
--- a/doc/chronyc.man.in
+++ b/doc/chronyc.man.in
@@ -2,12 +2,12 @@
.\" Title: chronyc
.\" Author: [see the "AUTHOR(S)" section]
.\" Generator: Asciidoctor 2.0.20
-.\" Date: 2023-08-09
+.\" Date: 2023-12-05
.\" Manual: User manual
.\" Source: chrony @CHRONY_VERSION@
.\" Language: English
.\"
-.TH "CHRONYC" "1" "2023-08-09" "chrony @CHRONY_VERSION@" "User manual"
+.TH "CHRONYC" "1" "2023-12-05" "chrony @CHRONY_VERSION@" "User manual"
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.ss \n[.ss] 0
@@ -174,7 +174,7 @@ performance. An example of the output is shown below.
.if n .RS 4
.nf
.fam C
-Reference ID : CB00710F (foo.example.net)
+Reference ID : CB00710F (ntp1.example.net)
Stratum : 3
Ref time (UTC) : Fri Jan 27 09:49:17 2017
System time : 0.000006523 seconds slow of NTP time
@@ -214,7 +214,7 @@ with an IPv4 address.
.RS 4
The stratum indicates how many hops away from a computer with an attached
reference clock we are. Such a computer is a stratum\-1 computer, so the
-computer in the example is two hops away (i.e. \fIfoo.example.net\fP is a
+computer in the example is two hops away (i.e. \fIntp1.example.net\fP is a
stratum\-2 and is synchronised from a stratum\-1).
.RE
.sp
@@ -411,8 +411,8 @@ extra caption lines are shown as a reminder of the meanings of the columns.
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
#* GPS0 0 4 377 11 \-479ns[ \-621ns] +/\- 134ns
-^? foo.example.net 2 6 377 23 \-923us[ \-924us] +/\- 43ms
-^+ bar.example.net 1 6 377 21 \-2629us[\-2619us] +/\- 86ms
+^? ntp1.example.net 2 6 377 23 \-923us[ \-924us] +/\- 43ms
+^+ ntp2.example.net 1 6 377 21 \-2629us[\-2619us] +/\- 86ms
.fam
.fi
.if n .RE
@@ -582,7 +582,7 @@ An example report is:
.fam C
Name/IP Address NP NR Span Frequency Freq Skew Offset Std Dev
===============================================================================
-foo.example.net 11 5 46m \-0.001 0.045 1us 25us
+ntp1.example.net 11 5 46m \-0.001 0.045 1us 25us
.fam
.fi
.if n .RE
@@ -655,9 +655,9 @@ An example of the output is shown below.
.fam C
S Name/IP Address Auth COpts EOpts Last Score Interval Leap
=======================================================================
-D foo.example.net Y \-\-\-\-\- \-\-TR\- 4 1.0 \-61ms +62ms N
-* bar.example.net N \-\-\-\-\- \-\-\-\-\- 0 1.0 \-6846us +7305us N
-+ baz.example.net N \-\-\-\-\- \-\-\-\-\- 10 1.0 \-7381us +7355us N
+D ntp1.example.net Y \-\-\-\-\- \-\-TR\- 4 1.0 \-61ms +62ms N
+* ntp2.example.net N \-\-\-\-\- \-\-\-\-\- 0 1.0 \-6846us +7305us N
++ ntp3.example.net N \-\-\-\-\- \-\-\-\-\- 10 1.0 \-7381us +7355us N
.fam
.fi
.if n .RE
@@ -1109,9 +1109,9 @@ shown below.
.fam C
Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen
=========================================================================
-foo.example.net NTS 1 15 256 135m 0 0 8 100
-bar.example.net SK 30 13 128 \- 0 0 0 0
-baz.example.net \- 0 0 0 \- 0 0 0 0
+ntp1.example.net NTS 1 15 256 135m 0 0 8 100
+ntp2.example.net SK 30 13 128 \- 0 0 0 0
+ntp3.example.net \- 0 0 0 \- 0 0 0 0
.fam
.fi
.if n .RE
@@ -1502,7 +1502,7 @@ An example of using this command is shown below.
.if n .RS 4
.nf
.fam C
-add peer foo.example.net minpoll 6 maxpoll 10 key 25
+add peer ntp1.example.net minpoll 6 maxpoll 10 key 25
.fam
.fi
.if n .RE
@@ -1522,7 +1522,7 @@ An example of using this command is shown below:
.if n .RS 4
.nf
.fam C
-add pool foo.example.net maxsources 3 iburst
+add pool ntp1.example.net maxsources 3 iburst
.fam
.fi
.if n .RE
@@ -1542,7 +1542,7 @@ An example of using this command is shown below:
.if n .RS 4
.nf
.fam C
-add server foo.example.net minpoll 6 maxpoll 10 key 25
+add server ntp1.example.net minpoll 6 maxpoll 10 key 25
.fam
.fi
.if n .RE
@@ -1651,7 +1651,7 @@ Example of the three\-argument form of the command is:
.if n .RS 4
.nf
.fam C
-burst 2/10 foo.example.net
+burst 2/10 ntp1.example.net
.fam
.fi
.if n .RE
@@ -1732,7 +1732,7 @@ uses an IP address or a hostname. These forms are illustrated below.
offline
offline 255.255.255.0/1.2.3.0
offline 2001:db8:789a::/48
-offline foo.example.net
+offline ntp1.example.net
.fam
.fi
.if n .RE
@@ -1802,6 +1802,10 @@ command might replace the addresses even if they are still in the pool.
The \fBreload sources\fP command causes \fBchronyd\fP to re\-read all \fI*.sources\fP files
from the directories specified by the
\fBsourcedir\fP directive.
+.sp
+Note that modified sources (e.g. specified with a new option) are not modified
+in memory. They are removed and added again, which causes them to lose old
+measurements and reset the selection state.
.RE
.sp
\fBsourcename\fP \fIaddress\fP
@@ -1973,7 +1977,7 @@ Examples of use, showing a named host and a numeric IP address, are as follows:
.if n .RS 4
.nf
.fam C
-accheck foo.example.net
+accheck ntp1.example.net
accheck 1.2.3.4
accheck 2001:db8::1
.fam
@@ -2006,7 +2010,7 @@ An example of the output is:
Hostname NTP Drop Int IntL Last Cmd Drop Int Last
===============================================================================
localhost 2 0 2 \- 133 15 0 \-1 7
-foo.example.net 12 0 6 \- 23 0 0 \- \-
+ntp1.example.net 12 0 6 \- 23 0 0 \- \-
.fam
.fi
.if n .RE
@@ -2401,7 +2405,7 @@ Examples of use are as follows:
.if n .RS 4
.nf
.fam C
-cmdaccheck foo.example.net
+cmdaccheck ntp1.example.net
cmdaccheck 1.2.3.4
cmdaccheck 2001:db8::1
.fam
diff --git a/doc/chronyd.adoc b/doc/chronyd.adoc
index e44aac5..887be48 100644
--- a/doc/chronyd.adoc
+++ b/doc/chronyd.adoc
@@ -72,9 +72,9 @@ terminal.
*-L* _level_::
This option specifies the minimum severity level of messages to be written to
-the log file, syslog, or terminal. The following levels can be specified:
-0 (informational), 1 (warning), 2 (non-fatal error), and 3 (fatal error). The
-default value is 0.
+the log file, syslog, or terminal. The following levels can be specified: -1
+(debug, if compiled with enabled support for debugging), 0 (informational), 1
+(warning), 2 (non-fatal error), and 3 (fatal error). The default value is 0.
*-p*::
When run in this mode, *chronyd* will print the configuration and exit. It will
@@ -206,6 +206,17 @@ With this option *chronyd* will print version number to the terminal and exit.
*-h*, *--help*::
With this option *chronyd* will print a help message to the terminal and exit.
+== ENVIRONMENT VARIABLES
+
+*LISTEN_FDS*::
+On Linux systems, the systemd service manager may pass file descriptors for
+pre-initialised sockets to *chronyd*. The service manager allocates and binds
+the file descriptors, and passes a copy to each spawned instance of the
+service. This allows for zero-downtime service restarts as the sockets buffer
+client requests until the service is able to handle them. The service manager
+sets the LISTEN_FDS environment variable to the number of passed file
+descriptors.
+
== FILES
_@SYSCONFDIR@/chrony.conf_
diff --git a/doc/chronyd.man.in b/doc/chronyd.man.in
index 747bad1..96e87a0 100644
--- a/doc/chronyd.man.in
+++ b/doc/chronyd.man.in
@@ -2,12 +2,12 @@
.\" Title: chronyd
.\" Author: [see the "AUTHOR(S)" section]
.\" Generator: Asciidoctor 2.0.20
-.\" Date: 2023-08-09
+.\" Date: 2023-12-05
.\" Manual: System Administration
.\" Source: chrony @CHRONY_VERSION@
.\" Language: English
.\"
-.TH "CHRONYD" "8" "2023-08-09" "chrony @CHRONY_VERSION@" "System Administration"
+.TH "CHRONYD" "8" "2023-12-05" "chrony @CHRONY_VERSION@" "System Administration"
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.ss \n[.ss] 0
@@ -87,9 +87,9 @@ terminal.
\fB\-L\fP \fIlevel\fP
.RS 4
This option specifies the minimum severity level of messages to be written to
-the log file, syslog, or terminal. The following levels can be specified:
-0 (informational), 1 (warning), 2 (non\-fatal error), and 3 (fatal error). The
-default value is 0.
+the log file, syslog, or terminal. The following levels can be specified: \-1
+(debug, if compiled with enabled support for debugging), 0 (informational), 1
+(warning), 2 (non\-fatal error), and 3 (fatal error). The default value is 0.
.RE
.sp
\fB\-p\fP
@@ -251,6 +251,18 @@ With this option \fBchronyd\fP will print version number to the terminal and exi
.RS 4
With this option \fBchronyd\fP will print a help message to the terminal and exit.
.RE
+.SH "ENVIRONMENT VARIABLES"
+.sp
+\fBLISTEN_FDS\fP
+.RS 4
+On Linux systems, the systemd service manager may pass file descriptors for
+pre\-initialised sockets to \fBchronyd\fP. The service manager allocates and binds
+the file descriptors, and passes a copy to each spawned instance of the
+service. This allows for zero\-downtime service restarts as the sockets buffer
+client requests until the service is able to handle them. The service manager
+sets the LISTEN_FDS environment variable to the number of passed file
+descriptors.
+.RE
.SH "FILES"
.sp
\fI@SYSCONFDIR@/chrony.conf\fP
diff --git a/doc/faq.adoc b/doc/faq.adoc
index 57347c3..8fd350f 100644
--- a/doc/faq.adoc
+++ b/doc/faq.adoc
@@ -1,6 +1,7 @@
// This file is part of chrony
//
// Copyright (C) Richard P. Curnow 1997-2003
+// Copyright (C) Luke Valenta 2023
// Copyright (C) Miroslav Lichvar 2014-2016, 2020-2023
//
// This program is free software; you can redistribute it and/or modify
@@ -265,11 +266,11 @@ An example of a client configuration limiting the impact of the attacks could
be
----
-server foo.example.net iburst nts maxdelay 0.1
-server bar.example.net iburst nts maxdelay 0.2
-server baz.example.net iburst nts maxdelay 0.05
-server qux.example.net iburst nts maxdelay 0.1
-server quux.example.net iburst nts maxdelay 0.1
+server ntp1.example.net iburst nts maxdelay 0.1
+server ntp2.example.net iburst nts maxdelay 0.2
+server ntp3.example.net iburst nts maxdelay 0.05
+server ntp4.example.net iburst nts maxdelay 0.1
+server ntp5.example.net iburst nts maxdelay 0.1
minsources 3
maxchange 100 0 0
makestep 0.001 1
@@ -318,7 +319,7 @@ An example of the directive for an NTP server on the Internet that you are
allowed to poll frequently could be
----
-server foo.example.net minpoll 4 maxpoll 6 polltarget 16
+server ntp.example.net minpoll 4 maxpoll 6 polltarget 16
----
An example using shorter polling intervals with a server located in the same
@@ -381,7 +382,7 @@ outliers corrupting the minimum delay. For example:
server ntp.local minpoll -7 maxpoll -7 filter 31 maxdelayquant 0.3 xleave
----
-As an experimental feature added in version 4.2, `chronyd` supports an NTPv4
+Since version 4.2, `chronyd` supports an NTPv4
extension field containing an additional timestamp to enable frequency transfer
and significantly improve stability of synchronisation. It can be enabled by
the `extfield F323` option. For example:
@@ -390,6 +391,18 @@ the `extfield F323` option. For example:
server ntp.local minpoll 0 maxpoll 0 xleave extfield F323
----
+Since version 4.5, `chronyd` can apply corrections from PTP one-step end-to-end
+transparent clocks (e.g. network switches) to significantly improve accuracy of
+synchronisation in local networks. It requires the PTP transport to be enabled
+by the `ptpport` directive, HW timestamping, and the `extfield F324` option.
+For example:
+
+----
+server ntp.local minpoll -4 maxpoll -4 xleave extfield F323 extfield F324 port 319
+ptpport 319
+hwtimestamp eth0 minpoll -4
+----
+
=== Does `chronyd` have an ntpdate mode?
Yes. With the `-q` option `chronyd` will set the system clock once and exit.
@@ -497,6 +510,59 @@ pidfile /var/run/chronyd-server1.pid
driftfile /var/lib/chrony/drift-server1
----
+=== How can `chronyd` be configured to minimise downtime during restarts?
+
+The `dumpdir` directive in _chrony.conf_ provides `chronyd` a location to save
+a measurement history of the sources it uses when the service exits. The `-r`
+option then enables `chronyd` to load state from the dump files, reducing the
+synchronisation time after a restart.
+
+Similarly, the `ntsdumpdir` directive provides a location for `chronyd` to save
+NTS cookies received from the server to avoid making a NTS-KE request when
+`chronyd` is started. When operating as an NTS server, `chronyd` also saves
+cookies keys to this directory to allow clients to continue to use the old keys
+after a server restart for a more seamless experience.
+
+On Linux systems,
+https://www.freedesktop.org/software/systemd/man/latest/sd_listen_fds.html[systemd
+socket activation] provides a mechanism to reuse server sockets across
+`chronyd` restarts, so that client requests will be buffered until the service
+is again able to handle the requests. This allows for zero-downtime service
+restarts, simplified dependency logic at boot, and on-demand service spawning
+(for instance, for separated server `chronyd` instances run with the `-x`
+flag).
+
+Socket activation is supported since `chrony` version 4.5.
+The service manager (systemd) creates sockets and
+passes file descriptors to them to the process via the `LISTEN_FDS` environment
+variable. Before opening new sockets, `chronyd` first checks for and attempts
+to reuse matching sockets passed from the service manager. For instance, if an
+IPv4 datagram socket bound on `bindaddress` and `port` is available, it will be
+used by the NTP server to accept incoming IPv4 requests.
+
+An example systemd socket unit is below, where `chronyd` is configured with
+`bindaddress 0.0.0.0`, `bindaddress ::`, `port 123`, and `ntsport 4460`.
+
+----
+[Unit]
+Description=chronyd server sockets
+
+[Socket]
+Service=chronyd.service
+# IPv4 NTP server
+ListenDatagram=0.0.0.0:123
+# IPv6 NTP server
+ListenDatagram=[::]:123
+# IPv4 NTS-KE server
+ListenStream=0.0.0.0:4460
+# IPv6 NTS-KE server
+ListenStream=[::]:4460
+BindIPv6Only=ipv6-only
+
+[Install]
+WantedBy=sockets.target
+----
+
=== Should be a leap smear enabled on NTP server?
With the `smoothtime` and `leapsecmode` directives it is possible to enable a
@@ -598,7 +664,10 @@ The `ethtool -T` command can be used to verify the timestamping support.
As an experimental feature added in version 4.2, `chrony` can use PTP as a
transport for NTP messages (NTP over PTP) to enable hardware timestamping on
hardware which can timestamp PTP packets only. It can be enabled by the
-`ptpport` directive.
+`ptpport` directive. Since version 4.5, `chrony` can also apply corrections
+provided by PTP one-step end-to-end transparent clocks to reach the accuracy of
+ordinary PTP clocks. The application of PTP corrections can be enabled by the
+`extfield F324` option.
=== How can I avoid using wrong PHC refclock?
@@ -669,9 +738,9 @@ this:
----
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
-^* foo.example.net 2 6 377 34 +484us[ -157us] +/- 30ms
-^- bar.example.net 2 6 377 34 +33ms[ +32ms] +/- 47ms
-^+ baz.example.net 3 6 377 35 -1397us[-2033us] +/- 60ms
+^* ntp1.example.net 2 6 377 34 +484us[ -157us] +/- 30ms
+^- ntp2.example.net 2 6 377 34 +33ms[ +32ms] +/- 47ms
+^+ ntp3.example.net 3 6 377 35 -1397us[-2033us] +/- 60ms
----
=== Are NTP servers specified with the `offline` option?
@@ -741,9 +810,9 @@ successful:
# chronyc -N authdata
Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen
=========================================================================
-foo.example.net NTS 1 15 256 33m 0 0 8 100
-bar.example.net NTS 1 15 256 33m 0 0 8 100
-baz.example.net NTS 1 15 256 33m 0 0 8 100
+ntp1.example.net NTS 1 15 256 33m 0 0 8 100
+ntp2.example.net NTS 1 15 256 33m 0 0 8 100
+ntp3.example.net NTS 1 15 256 33m 0 0 8 100
----
The KeyID, Type, and KLen columns should have non-zero values. If they are
@@ -867,7 +936,7 @@ Name/IP Address NP NR Span Frequency Freq Skew Offset Std Dev
==============================================================================
PPS0 0 0 0 +0.000 2000.000 +0ns 4000ms
NMEA 58 30 231 -96.494 38.406 +504ms 6080us
-foo.example.net 7 3 200 -2.991 16.141 -107us 492us
+ntp1.example.net 7 3 200 -2.991 16.141 -107us 492us
----
the offset of the NMEA source would need to be increased by about 0.504
diff --git a/examples/chrony.conf.example3 b/examples/chrony.conf.example3
index 4e3e3a8..6d84c01 100644
--- a/examples/chrony.conf.example3
+++ b/examples/chrony.conf.example3
@@ -27,9 +27,9 @@
# you can access at http://support.ntp.org/bin/view/Servers/WebHome or
# you can use servers from the pool.ntp.org project.
-! server foo.example.net iburst
-! server bar.example.net iburst
-! server baz.example.net iburst
+! server ntp1.example.net iburst
+! server ntp2.example.net iburst
+! server ntp3.example.net iburst
! pool pool.ntp.org iburst
@@ -99,8 +99,8 @@ ntsdumpdir /var/lib/chrony
# and edit the following lines to specify the locations of the certificate and
# key.
-! ntsservercert /etc/.../foo.example.net.crt
-! ntsserverkey /etc/.../foo.example.net.key
+! ntsservercert /etc/.../nts-server.crt
+! ntsserverkey /etc/.../nts-server.key
# chronyd can save the measurement history for the servers to files when
# it exits. This is useful in 2 situations:
@@ -238,7 +238,7 @@ ntsdumpdir /var/lib/chrony
# several people, you need to set up a mailing list or sendmail alias
# for them and use the address of that.)
-! mailonchange wibble@foo.example.net 0.5
+! mailonchange wibble@example.net 0.5
#######################################################################
### COMMAND ACCESS
diff --git a/logging.c b/logging.c
index 22c326c..ec9ec53 100644
--- a/logging.c
+++ b/logging.c
@@ -145,6 +145,7 @@ void LOG_Message(LOG_Severity severity,
struct tm *tm;
assert(initialised);
+ severity = CLAMP(LOGS_DEBUG, severity, LOGS_FATAL);
if (!system_log && file_log && severity >= log_min_severity) {
/* Don't clutter up syslog with timestamps and internal debugging info */
@@ -155,8 +156,13 @@ void LOG_Message(LOG_Severity severity,
fprintf(file_log, "%s ", buf);
}
#if DEBUG > 0
- if (log_min_severity <= LOGS_DEBUG)
- fprintf(file_log, "%s%s:%d:(%s) ", debug_prefix, filename, line_number, function_name);
+ if (log_min_severity <= LOGS_DEBUG) {
+ /* Log severity to character mapping (debug, info, warn, err, fatal) */
+ const char severity_chars[LOGS_FATAL - LOGS_DEBUG + 1] = {'D', 'I', 'W', 'E', 'F'};
+
+ fprintf(file_log, "%c:%s%s:%d:(%s) ", severity_chars[severity - LOGS_DEBUG],
+ debug_prefix, filename, line_number, function_name);
+ }
#endif
}
diff --git a/main.c b/main.c
index 3233707..21d0fe7 100644
--- a/main.c
+++ b/main.c
@@ -368,9 +368,9 @@ go_daemon(void)
}
/* Don't keep stdin/out/err from before. But don't close
- the parent pipe yet. */
+ the parent pipe yet, or reusable file descriptors. */
for (fd=0; fd<1024; fd++) {
- if (fd != pipefd[1])
+ if (fd != pipefd[1] && !SCK_IsReusable(fd))
close(fd);
}
@@ -560,6 +560,9 @@ int main
if (user_check && getuid() != 0)
LOG_FATAL("Not superuser");
+ /* Initialise reusable file descriptors before fork */
+ SCK_PreInitialise();
+
/* Turn into a daemon */
if (!nofork) {
go_daemon();
diff --git a/ntp.h b/ntp.h
index 906adc3..165adbc 100644
--- a/ntp.h
+++ b/ntp.h
@@ -115,9 +115,11 @@ typedef struct {
/* Non-authentication extension fields and corresponding internal flags */
-#define NTP_EF_EXP1 0xF323
+#define NTP_EF_EXP_MONO_ROOT 0xF323
+#define NTP_EF_EXP_NET_CORRECTION 0xF324
-#define NTP_EF_FLAG_EXP1 0x1
+#define NTP_EF_FLAG_EXP_MONO_ROOT 0x1
+#define NTP_EF_FLAG_EXP_NET_CORRECTION 0x2
/* Pre-NTPv5 experimental extension field */
typedef struct {
@@ -126,9 +128,18 @@ typedef struct {
NTP_int32 root_dispersion;
NTP_int64 mono_receive_ts;
uint32_t mono_epoch;
-} NTP_ExtFieldExp1;
+} NTP_EFExpMonoRoot;
-#define NTP_EF_EXP1_MAGIC 0xF5BEDD9AU
+#define NTP_EF_EXP_MONO_ROOT_MAGIC 0xF5BEDD9AU
+
+/* Experimental extension field to provide PTP corrections */
+typedef struct {
+ uint32_t magic;
+ NTP_int64 correction;
+ uint32_t reserved[3];
+} NTP_EFExpNetCorrection;
+
+#define NTP_EF_EXP_NET_CORRECTION_MAGIC 0x07AC2CEBU
/* Authentication extension fields */
diff --git a/ntp_core.c b/ntp_core.c
index 22cab43..023e60b 100644
--- a/ntp_core.c
+++ b/ntp_core.c
@@ -314,6 +314,9 @@ static ARR_Instance broadcasts;
/* Maximum acceptable change in server mono<->real offset */
#define MAX_MONO_DOFFSET 16.0
+/* Maximum assumed frequency error in network corrections */
+#define MAX_NET_CORRECTION_FREQ 100.0e-6
+
/* Invalid socket, different from the one in ntp_io.c */
#define INVALID_SOCK_FD -2
@@ -373,6 +376,9 @@ do_size_checks(void)
assert(offsetof(NTP_Packet, originate_ts) == 24);
assert(offsetof(NTP_Packet, receive_ts) == 32);
assert(offsetof(NTP_Packet, transmit_ts) == 40);
+
+ assert(sizeof (NTP_EFExpMonoRoot) == 24);
+ assert(sizeof (NTP_EFExpNetCorrection) == 24);
}
/* ================================================== */
@@ -418,6 +424,8 @@ zero_local_timestamp(NTP_Local_Timestamp *ts)
UTI_ZeroTimespec(&ts->ts);
ts->err = 0.0;
ts->source = NTP_TS_DAEMON;
+ ts->rx_duration = 0.0;
+ ts->net_correction = 0.0;
}
/* ================================================== */
@@ -1045,34 +1053,64 @@ receive_timeout(void *arg)
/* ================================================== */
static int
-add_ext_exp1(NTP_Packet *message, NTP_PacketInfo *info, struct timespec *rx,
- double root_delay, double root_dispersion)
+add_ef_mono_root(NTP_Packet *message, NTP_PacketInfo *info, struct timespec *rx,
+ double root_delay, double root_dispersion)
{
struct timespec mono_rx;
- NTP_ExtFieldExp1 exp1;
+ NTP_EFExpMonoRoot ef;
NTP_int64 ts_fuzz;
- memset(&exp1, 0, sizeof (exp1));
- exp1.magic = htonl(NTP_EF_EXP1_MAGIC);
+ memset(&ef, 0, sizeof (ef));
+ ef.magic = htonl(NTP_EF_EXP_MONO_ROOT_MAGIC);
if (info->mode != MODE_CLIENT) {
- exp1.root_delay = UTI_DoubleToNtp32f28(root_delay);
- exp1.root_dispersion = UTI_DoubleToNtp32f28(root_dispersion);
+ ef.root_delay = UTI_DoubleToNtp32f28(root_delay);
+ ef.root_dispersion = UTI_DoubleToNtp32f28(root_dispersion);
if (rx)
UTI_AddDoubleToTimespec(rx, server_mono_offset, &mono_rx);
else
UTI_ZeroTimespec(&mono_rx);
UTI_GetNtp64Fuzz(&ts_fuzz, message->precision);
- UTI_TimespecToNtp64(&mono_rx, &exp1.mono_receive_ts, &ts_fuzz);
- exp1.mono_epoch = htonl(server_mono_epoch);
+ UTI_TimespecToNtp64(&mono_rx, &ef.mono_receive_ts, &ts_fuzz);
+ ef.mono_epoch = htonl(server_mono_epoch);
}
- if (!NEF_AddField(message, info, NTP_EF_EXP1, &exp1, sizeof (exp1))) {
+ if (!NEF_AddField(message, info, NTP_EF_EXP_MONO_ROOT, &ef, sizeof (ef))) {
DEBUG_LOG("Could not add EF");
return 0;
}
- info->ext_field_flags |= NTP_EF_FLAG_EXP1;
+ info->ext_field_flags |= NTP_EF_FLAG_EXP_MONO_ROOT;
+
+ return 1;
+}
+
+/* ================================================== */
+
+static int
+add_ef_net_correction(NTP_Packet *message, NTP_PacketInfo *info,
+ NTP_Local_Timestamp *local_rx)
+{
+ NTP_EFExpNetCorrection ef;
+
+ if (CNF_GetPtpPort() == 0) {
+ DEBUG_LOG("ptpport disabled");
+ return 1;
+ }
+
+ memset(&ef, 0, sizeof (ef));
+ ef.magic = htonl(NTP_EF_EXP_NET_CORRECTION_MAGIC);
+
+ if (info->mode != MODE_CLIENT && local_rx->net_correction > local_rx->rx_duration) {
+ UTI_DoubleToNtp64(local_rx->net_correction, &ef.correction);
+ }
+
+ if (!NEF_AddField(message, info, NTP_EF_EXP_NET_CORRECTION, &ef, sizeof (ef))) {
+ DEBUG_LOG("Could not add EF");
+ return 0;
+ }
+
+ info->ext_field_flags |= NTP_EF_FLAG_EXP_NET_CORRECTION;
return 1;
}
@@ -1224,9 +1262,13 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
return 0;
if (ext_field_flags) {
- if (ext_field_flags & NTP_EF_FLAG_EXP1) {
- if (!add_ext_exp1(&message, &info, smooth_time ? NULL : &local_receive,
- our_root_delay, our_root_dispersion))
+ if (ext_field_flags & NTP_EF_FLAG_EXP_MONO_ROOT) {
+ if (!add_ef_mono_root(&message, &info, smooth_time ? NULL : &local_receive,
+ our_root_delay, our_root_dispersion))
+ return 0;
+ }
+ if (ext_field_flags & NTP_EF_FLAG_EXP_NET_CORRECTION) {
+ if (!add_ef_net_correction(&message, &info, local_rx))
return 0;
}
}
@@ -1297,6 +1339,8 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
local_tx->ts = local_transmit;
local_tx->err = local_transmit_err;
local_tx->source = NTP_TS_DAEMON;
+ local_tx->rx_duration = 0.0;
+ local_tx->net_correction = 0.0;
}
if (local_ntp_rx)
@@ -1491,6 +1535,14 @@ is_zero_data(unsigned char *data, int length)
/* ================================================== */
static int
+is_exp_ef(void *body, int body_length, int expected_body_length, uint32_t magic)
+{
+ return body_length == expected_body_length && *(uint32_t *)body == htonl(magic);
+}
+
+/* ================================================== */
+
+static int
parse_packet(NTP_Packet *packet, int length, NTP_PacketInfo *info)
{
int parsed, remainder, ef_length, ef_type, ef_body_length;
@@ -1576,10 +1628,15 @@ parse_packet(NTP_Packet *packet, int length, NTP_PacketInfo *info)
case NTP_EF_NTS_AUTH_AND_EEF:
info->auth.mode = NTP_AUTH_NTS;
break;
- case NTP_EF_EXP1:
- if (ef_body_length == sizeof (NTP_ExtFieldExp1) &&
- ntohl(((NTP_ExtFieldExp1 *)ef_body)->magic) == NTP_EF_EXP1_MAGIC)
- info->ext_field_flags |= NTP_EF_FLAG_EXP1;
+ case NTP_EF_EXP_MONO_ROOT:
+ if (is_exp_ef(ef_body, ef_body_length, sizeof (NTP_EFExpMonoRoot),
+ NTP_EF_EXP_MONO_ROOT_MAGIC))
+ info->ext_field_flags |= NTP_EF_FLAG_EXP_MONO_ROOT;
+ break;
+ case NTP_EF_EXP_NET_CORRECTION:
+ if (is_exp_ef(ef_body, ef_body_length, sizeof (NTP_EFExpNetCorrection),
+ NTP_EF_EXP_NET_CORRECTION_MAGIC))
+ info->ext_field_flags |= NTP_EF_FLAG_EXP_NET_CORRECTION;
break;
default:
DEBUG_LOG("Unknown extension field type=%x", (unsigned int)ef_type);
@@ -1607,6 +1664,53 @@ parse_packet(NTP_Packet *packet, int length, NTP_PacketInfo *info)
/* ================================================== */
+static void
+apply_net_correction(NTP_Sample *sample, NTP_Local_Timestamp *rx, NTP_Local_Timestamp *tx,
+ double precision)
+{
+ double rx_correction, tx_correction, low_delay_correction;
+
+ /* Require some correction from transparent clocks to be present
+ in both directions (not just the local RX timestamp correction) */
+ if (rx->net_correction <= rx->rx_duration || tx->net_correction <= 0.0)
+ return;
+
+ /* With perfect corrections from PTP transparent clocks and short cables
+ the peer delay would be close to zero, or even negative if the server or
+ transparent clocks were running faster than client, which would invert the
+ sample weighting. Adjust the correction to get a delay corresponding to
+ a direct connection to the server. For simplicity, assume the TX and RX
+ link speeds are equal. If not, the reported delay will be wrong, but it
+ will not cause an error in the offset. */
+ rx_correction = rx->net_correction - rx->rx_duration;
+ tx_correction = tx->net_correction - rx->rx_duration;
+
+ /* Use a slightly smaller value in the correction of delay to not overcorrect
+ if the transparent clocks run up to 100 ppm fast and keep a part of the
+ uncorrected delay for the sample weighting */
+ low_delay_correction = (rx_correction + tx_correction) *
+ (1.0 - MAX_NET_CORRECTION_FREQ);
+
+ /* Make sure the correction is sane. The values are not authenticated! */
+ if (low_delay_correction < 0.0 || low_delay_correction > sample->peer_delay) {
+ DEBUG_LOG("Invalid correction %.9f peer_delay=%.9f",
+ low_delay_correction, sample->peer_delay);
+ return;
+ }
+
+ /* Correct the offset and peer delay, but not the root delay to not
+ change the estimated maximum error */
+ sample->offset += (rx_correction - tx_correction) / 2.0;
+ sample->peer_delay -= low_delay_correction;
+ if (sample->peer_delay < precision)
+ sample->peer_delay = precision;
+
+ DEBUG_LOG("Applied correction rx=%.9f tx=%.9f dur=%.9f",
+ rx->net_correction, tx->net_correction, rx->rx_duration);
+}
+
+/* ================================================== */
+
static int
check_delay_ratio(NCR_Instance inst, SST_Stats stats,
struct timespec *sample_time, double delay)
@@ -1868,18 +1972,20 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
/* Extension fields */
int parsed, ef_length, ef_type, ef_body_length;
void *ef_body;
- NTP_ExtFieldExp1 *ef_exp1;
+ NTP_EFExpMonoRoot *ef_mono_root;
+ NTP_EFExpNetCorrection *ef_net_correction;
NTP_Local_Timestamp local_receive, local_transmit;
double remote_interval, local_interval, response_time;
- double delay_time, precision, mono_doffset;
+ double delay_time, precision, mono_doffset, net_correction;
int updated_timestamps;
/* ==================== */
stats = SRC_GetSourcestats(inst->source);
- ef_exp1 = NULL;
+ ef_mono_root = NULL;
+ ef_net_correction = NULL;
/* Find requested non-authentication extension fields */
if (inst->ext_field_flags & info->ext_field_flags) {
@@ -1889,11 +1995,17 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
break;
switch (ef_type) {
- case NTP_EF_EXP1:
- if (inst->ext_field_flags & NTP_EF_FLAG_EXP1 &&
- ef_body_length == sizeof (*ef_exp1) &&
- ntohl(((NTP_ExtFieldExp1 *)ef_body)->magic) == NTP_EF_EXP1_MAGIC)
- ef_exp1 = ef_body;
+ case NTP_EF_EXP_MONO_ROOT:
+ if (inst->ext_field_flags & NTP_EF_FLAG_EXP_MONO_ROOT &&
+ is_exp_ef(ef_body, ef_body_length, sizeof (*ef_mono_root),
+ NTP_EF_EXP_MONO_ROOT_MAGIC))
+ ef_mono_root = ef_body;
+ break;
+ case NTP_EF_EXP_NET_CORRECTION:
+ if (inst->ext_field_flags & NTP_EF_FLAG_EXP_NET_CORRECTION &&
+ is_exp_ef(ef_body, ef_body_length, sizeof (*ef_net_correction),
+ NTP_EF_EXP_NET_CORRECTION_MAGIC))
+ ef_net_correction = ef_body;
break;
}
}
@@ -1902,9 +2014,9 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
pkt_leap = NTP_LVM_TO_LEAP(message->lvm);
pkt_version = NTP_LVM_TO_VERSION(message->lvm);
pkt_refid = ntohl(message->reference_id);
- if (ef_exp1) {
- pkt_root_delay = UTI_Ntp32f28ToDouble(ef_exp1->root_delay);
- pkt_root_dispersion = UTI_Ntp32f28ToDouble(ef_exp1->root_dispersion);
+ if (ef_mono_root) {
+ pkt_root_delay = UTI_Ntp32f28ToDouble(ef_mono_root->root_delay);
+ pkt_root_dispersion = UTI_Ntp32f28ToDouble(ef_mono_root->root_dispersion);
} else {
pkt_root_delay = UTI_Ntp32ToDouble(message->root_delay);
pkt_root_dispersion = UTI_Ntp32ToDouble(message->root_dispersion);
@@ -1989,11 +2101,11 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
the new sample. In the interleaved mode, cancel the correction out in
remote timestamps of the previous request and response, which were
captured before the source accumulated the new time corrections. */
- if (ef_exp1 && inst->remote_mono_epoch == ntohl(ef_exp1->mono_epoch) &&
- !UTI_IsZeroNtp64(&ef_exp1->mono_receive_ts) &&
+ if (ef_mono_root && inst->remote_mono_epoch == ntohl(ef_mono_root->mono_epoch) &&
+ !UTI_IsZeroNtp64(&ef_mono_root->mono_receive_ts) &&
!UTI_IsZeroNtp64(&inst->remote_ntp_monorx)) {
mono_doffset =
- UTI_DiffNtp64ToDouble(&ef_exp1->mono_receive_ts, &inst->remote_ntp_monorx) -
+ UTI_DiffNtp64ToDouble(&ef_mono_root->mono_receive_ts, &inst->remote_ntp_monorx) -
UTI_DiffNtp64ToDouble(&message->receive_ts, &inst->remote_ntp_rx);
if (fabs(mono_doffset) > MAX_MONO_DOFFSET)
mono_doffset = 0.0;
@@ -2001,6 +2113,12 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
mono_doffset = 0.0;
}
+ if (ef_net_correction) {
+ net_correction = UTI_Ntp64ToDouble(&ef_net_correction->correction);
+ } else {
+ net_correction = 0.0;
+ }
+
/* Select remote and local timestamps for the new sample */
if (interleaved_packet) {
/* Prefer previous local TX and remote RX timestamps if it will make
@@ -2020,6 +2138,7 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
UTI_Ntp64ToTimespec(&message->receive_ts, &remote_receive);
UTI_Ntp64ToTimespec(&inst->remote_ntp_rx, &remote_request_receive);
local_transmit = inst->local_tx;
+ local_transmit.net_correction = net_correction;
root_delay = MAX(pkt_root_delay, inst->remote_root_delay);
root_dispersion = MAX(pkt_root_dispersion, inst->remote_root_dispersion);
}
@@ -2034,6 +2153,7 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
remote_request_receive = remote_receive;
local_receive = *rx_ts;
local_transmit = inst->local_tx;
+ local_transmit.net_correction = net_correction;
root_delay = pkt_root_delay;
root_dispersion = pkt_root_dispersion;
}
@@ -2077,6 +2197,9 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
skew * fabs(local_interval);
sample.root_delay = root_delay + sample.peer_delay;
sample.root_dispersion = root_dispersion + sample.peer_dispersion;
+
+ /* Apply corrections from PTP transparent clocks if available and sane */
+ apply_net_correction(&sample, &local_receive, &local_transmit, precision);
/* If the source is an active peer, this is the minimum assumed interval
between previous two transmissions (if not constrained by minpoll) */
@@ -2085,8 +2208,10 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
/* Additional tests required to pass before accumulating the sample */
- /* Test A requires that the minimum estimate of the peer delay is not
- larger than the configured maximum, in both client modes that the server
+ /* Test A combines multiple tests to avoid changing the measurements log
+ format and ntpdata report. It requires that the minimum estimate of the
+ peer delay is not larger than the configured maximum, it is not a
+ response in the 'warm up' exchange, in both client modes that the server
processing time is sane, in interleaved client/server mode that the
previous response was not in basic mode (which prevents using timestamps
that minimise delay error), and in interleaved symmetric mode that the
@@ -2094,6 +2219,7 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
a missed response */
testA = sample.peer_delay - sample.peer_dispersion <= inst->max_delay &&
precision <= inst->max_delay &&
+ inst->presend_done <= 0 &&
!(inst->mode == MODE_CLIENT && response_time > MAX_SERVER_INTERVAL) &&
!(inst->mode == MODE_CLIENT && interleaved_packet &&
UTI_IsZeroTimespec(&inst->prev_local_tx.ts) &&
@@ -2132,6 +2258,7 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
sample.root_delay = sample.root_dispersion = 0.0;
sample.time = rx_ts->ts;
mono_doffset = 0.0;
+ net_correction = 0.0;
local_receive = *rx_ts;
local_transmit = inst->local_tx;
testA = testB = testC = testD = 0;
@@ -2165,9 +2292,9 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
/* If available, update the monotonic timestamp and accumulate the offset.
This needs to be done here to not lose changes in remote_ntp_rx in
symmetric mode when there are multiple responses per request. */
- if (ef_exp1 && !UTI_IsZeroNtp64(&ef_exp1->mono_receive_ts)) {
- inst->remote_mono_epoch = ntohl(ef_exp1->mono_epoch);
- inst->remote_ntp_monorx = ef_exp1->mono_receive_ts;
+ if (ef_mono_root && !UTI_IsZeroNtp64(&ef_mono_root->mono_receive_ts)) {
+ inst->remote_mono_epoch = ntohl(ef_mono_root->mono_epoch);
+ inst->remote_ntp_monorx = ef_mono_root->mono_receive_ts;
inst->mono_doffset += mono_doffset;
} else {
inst->remote_mono_epoch = 0;
@@ -2175,8 +2302,11 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
inst->mono_doffset = 0.0;
}
- /* Don't use the same set of timestamps for the next sample */
- if (interleaved_packet)
+ inst->local_tx.net_correction = net_correction;
+
+ /* Avoid reusing timestamps of an accumulated sample when switching
+ from basic mode to interleaved mode */
+ if (interleaved_packet || !good_packet)
inst->prev_local_tx = inst->local_tx;
else
zero_local_timestamp(&inst->prev_local_tx);
@@ -2195,15 +2325,11 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
/* Accept at most one response per request. The NTP specification recommends
resetting local_ntp_tx to make the following packets fail test2 or test3,
but that would not allow the code above to make multiple updates of the
- timestamps in symmetric mode. Also, ignore presend responses. */
+ timestamps in symmetric mode. */
if (inst->valid_rx) {
test2 = test3 = 0;
valid_packet = synced_packet = good_packet = 0;
} else if (valid_packet) {
- if (inst->presend_done) {
- testA = 0;
- good_packet = 0;
- }
inst->valid_rx = 1;
}
@@ -2602,8 +2728,7 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
UTI_CompareNtp64(&message->receive_ts, &message->transmit_ts) != 0) {
ntp_rx = message->originate_ts;
local_ntp_rx = &ntp_rx;
- UTI_ZeroTimespec(&local_tx.ts);
- local_tx.source = NTP_TS_DAEMON;
+ zero_local_timestamp(&local_tx);
interleaved = CLG_GetNtpTxTimestamp(&ntp_rx, &local_tx.ts, &local_tx.source);
tx_ts = &local_tx;
diff --git a/ntp_core.h b/ntp_core.h
index a3c5546..5c5a614 100644
--- a/ntp_core.h
+++ b/ntp_core.h
@@ -42,6 +42,8 @@ typedef struct {
struct timespec ts;
double err;
NTP_Timestamp_Source source;
+ double rx_duration;
+ double net_correction;
} NTP_Local_Timestamp;
/* This is a private data type used for storing the instance record for
diff --git a/ntp_io.c b/ntp_io.c
index fce7b17..ec2fd7b 100644
--- a/ntp_io.c
+++ b/ntp_io.c
@@ -431,6 +431,9 @@ process_message(SCK_Message *message, int sock_fd, int event)
SCH_GetLastEventTime(&local_ts.ts, &local_ts.err, NULL);
local_ts.source = NTP_TS_DAEMON;
+ local_ts.rx_duration = 0.0;
+ local_ts.net_correction = 0.0;
+
sched_ts = local_ts.ts;
if (message->addr_type != SCK_ADDR_IP) {
@@ -456,7 +459,7 @@ process_message(SCK_Message *message, int sock_fd, int event)
DEBUG_LOG("Updated RX timestamp delay=%.9f tss=%u",
UTI_DiffTimespecsToDouble(&sched_ts, &local_ts.ts), local_ts.source);
- if (!NIO_UnwrapMessage(message, sock_fd))
+ if (!NIO_UnwrapMessage(message, sock_fd, &local_ts.net_correction))
return;
/* Just ignore the packet if it's not of a recognized length */
@@ -495,8 +498,9 @@ read_from_socket(int sock_fd, int event, void *anything)
/* ================================================== */
int
-NIO_UnwrapMessage(SCK_Message *message, int sock_fd)
+NIO_UnwrapMessage(SCK_Message *message, int sock_fd, double *net_correction)
{
+ double ptp_correction;
PTP_NtpMessage *msg;
if (!is_ptp_socket(sock_fd))
@@ -522,7 +526,14 @@ NIO_UnwrapMessage(SCK_Message *message, int sock_fd)
message->data = (char *)message->data + PTP_NTP_PREFIX_LENGTH;
message->length -= PTP_NTP_PREFIX_LENGTH;
- DEBUG_LOG("Unwrapped PTP->NTP len=%d", message->length);
+ ptp_correction = UTI_Integer64NetworkToHost(*(Integer64 *)msg->header.correction) /
+ ((1 << 16) * 1.0e9);
+
+ /* Use the correction only if the RX duration is known (i.e. HW timestamp) */
+ if (*net_correction > 0.0)
+ *net_correction += ptp_correction;
+
+ DEBUG_LOG("Unwrapped PTP->NTP len=%d corr=%.9f", message->length, ptp_correction);
return 1;
}
diff --git a/ntp_io.h b/ntp_io.h
index 427bd96..30f4992 100644
--- a/ntp_io.h
+++ b/ntp_io.h
@@ -64,7 +64,7 @@ extern int NIO_IsServerSocketOpen(void);
extern int NIO_IsServerConnectable(NTP_Remote_Address *remote_addr);
/* Function to unwrap an NTP message from non-native transport (e.g. PTP) */
-extern int NIO_UnwrapMessage(SCK_Message *message, int sock_fd);
+extern int NIO_UnwrapMessage(SCK_Message *message, int sock_fd, double *net_correction);
/* Function to transmit a packet */
extern int NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr,
diff --git a/ntp_io_linux.c b/ntp_io_linux.c
index 8f93f59..3b6874e 100644
--- a/ntp_io_linux.c
+++ b/ntp_io_linux.c
@@ -559,7 +559,7 @@ process_hw_timestamp(struct Interface *iface, struct timespec *hw_ts,
NTP_Local_Timestamp *local_ts, int rx_ntp_length, int family,
int l2_length)
{
- double rx_correction, ts_delay, local_err;
+ double rx_correction = 0.0, ts_delay, local_err;
struct timespec ts;
poll_phc(iface, &local_ts->ts);
@@ -600,6 +600,10 @@ process_hw_timestamp(struct Interface *iface, struct timespec *hw_ts,
local_ts->ts = ts;
local_ts->err = local_err;
local_ts->source = NTP_TS_HARDWARE;
+ local_ts->rx_duration = rx_correction;
+ /* Network correction needs to include the RX duration to avoid
+ asymmetric correction with asymmetric link speeds */
+ local_ts->net_correction = rx_correction;
}
/* ================================================== */
@@ -723,6 +727,7 @@ NIO_Linux_ProcessMessage(SCK_Message *message, NTP_Local_Address *local_addr,
{
struct Interface *iface;
int is_tx, ts_if_index, l2_length;
+ double c = 0.0;
is_tx = event == SCH_FILE_EXCEPTION;
iface = NULL;
@@ -783,7 +788,7 @@ NIO_Linux_ProcessMessage(SCK_Message *message, NTP_Local_Address *local_addr,
return 1;
}
- if (!NIO_UnwrapMessage(message, local_addr->sock_fd))
+ if (!NIO_UnwrapMessage(message, local_addr->sock_fd, &c))
return 1;
if (message->length < NTP_HEADER_LENGTH || message->length > sizeof (NTP_Packet))
diff --git a/ntp_sources.c b/ntp_sources.c
index 28af1c1..d8bd2d8 100644
--- a/ntp_sources.c
+++ b/ntp_sources.c
@@ -844,6 +844,31 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type,
/* ================================================== */
+const char *
+NSR_StatusToString(NSR_Status status)
+{
+ switch (status) {
+ case NSR_Success:
+ return "Success";
+ case NSR_NoSuchSource:
+ return "No such source";
+ case NSR_AlreadyInUse:
+ return "Already in use";
+ case NSR_TooManySources:
+ return "Too many sources";
+ case NSR_InvalidAF:
+ return "Invalid address";
+ case NSR_InvalidName:
+ return "Invalid name";
+ case NSR_UnresolvedName:
+ return "Unresolved name";
+ default:
+ return "?";
+ }
+}
+
+/* ================================================== */
+
void
NSR_SetSourceResolvingEndHandler(NSR_SourceResolvingEndHandler handler)
{
diff --git a/ntp_sources.h b/ntp_sources.h
index ba3b9c4..5aeb1a3 100644
--- a/ntp_sources.h
+++ b/ntp_sources.h
@@ -60,6 +60,8 @@ extern NSR_Status NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type
extern NSR_Status NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type,
SourceParameters *params, uint32_t *conf_id);
+extern const char *NSR_StatusToString(NSR_Status status);
+
/* Function type for handlers to be called back when an attempt
* (possibly unsuccessful) to resolve unresolved sources ends */
typedef void (*NSR_SourceResolvingEndHandler)(void);
diff --git a/nts_ke_server.c b/nts_ke_server.c
index 5e25c50..3fe99db 100644
--- a/nts_ke_server.c
+++ b/nts_ke_server.c
@@ -685,6 +685,8 @@ run_helper(uid_t uid, gid_t gid, int scfilter_level)
DEBUG_LOG("Helper started");
+ SCK_CloseReusableSockets();
+
/* Suppress a log message about disabled clock control */
log_severity = LOG_GetMinSeverity();
LOG_SetMinSeverity(LOGS_ERR);
diff --git a/siv_gnutls.c b/siv_gnutls.c
index 95387f0..a0a712c 100644
--- a/siv_gnutls.c
+++ b/siv_gnutls.c
@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
- * Copyright (C) Miroslav Lichvar 2020
+ * Copyright (C) Miroslav Lichvar 2020, 2023
*
* 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
@@ -37,6 +37,8 @@
struct SIV_Instance_Record {
gnutls_cipher_algorithm_t algorithm;
gnutls_aead_cipher_hd_t cipher;
+ int min_nonce_length;
+ int max_nonce_length;
};
/* ================================================== */
@@ -81,6 +83,10 @@ get_cipher_algorithm(SIV_Algorithm algorithm)
switch (algorithm) {
case AEAD_AES_SIV_CMAC_256:
return GNUTLS_CIPHER_AES_128_SIV;
+#if HAVE_GNUTLS_SIV_GCM
+ case AEAD_AES_128_GCM_SIV:
+ return GNUTLS_CIPHER_AES_128_SIV_GCM;
+#endif
default:
return 0;
}
@@ -112,6 +118,19 @@ SIV_CreateInstance(SIV_Algorithm algorithm)
instance->algorithm = calgo;
instance->cipher = NULL;
+ switch (algorithm) {
+ case AEAD_AES_SIV_CMAC_256:
+ instance->min_nonce_length = 1;
+ instance->max_nonce_length = INT_MAX;
+ break;
+ case AEAD_AES_128_GCM_SIV:
+ instance->min_nonce_length = 12;
+ instance->max_nonce_length = 12;
+ break;
+ default:
+ assert(0);
+ }
+
instance_counter++;
return instance;
@@ -143,6 +162,8 @@ SIV_GetKeyLength(SIV_Algorithm algorithm)
return 0;
len = gnutls_cipher_get_key_size(calgo);
+ if (len == 0)
+ return 0;
if (len < 1 || len > SIV_MAX_KEY_LENGTH)
LOG_FATAL("Invalid key length");
@@ -198,7 +219,7 @@ SIV_SetKey(SIV_Instance instance, const unsigned char *key, int length)
int
SIV_GetMinNonceLength(SIV_Instance instance)
{
- return 1;
+ return instance->min_nonce_length;
}
/* ================================================== */
@@ -206,7 +227,7 @@ SIV_GetMinNonceLength(SIV_Instance instance)
int
SIV_GetMaxNonceLength(SIV_Instance instance)
{
- return INT_MAX;
+ return instance->max_nonce_length;
}
/* ================================================== */
@@ -238,7 +259,8 @@ SIV_Encrypt(SIV_Instance instance,
if (!instance->cipher)
return 0;
- if (nonce_length < 1 || assoc_length < 0 ||
+ if (nonce_length < instance->min_nonce_length ||
+ nonce_length > instance->max_nonce_length || assoc_length < 0 ||
plaintext_length < 0 || ciphertext_length < 0)
return 0;
@@ -269,7 +291,8 @@ SIV_Decrypt(SIV_Instance instance,
if (!instance->cipher)
return 0;
- if (nonce_length < 1 || assoc_length < 0 ||
+ if (nonce_length < instance->min_nonce_length ||
+ nonce_length > instance->max_nonce_length || assoc_length < 0 ||
plaintext_length < 0 || ciphertext_length < 0)
return 0;
diff --git a/socket.c b/socket.c
index aa060a8..5b22db5 100644
--- a/socket.c
+++ b/socket.c
@@ -5,6 +5,7 @@
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Timo Teras 2009
* Copyright (C) Miroslav Lichvar 2009, 2013-2020
+ * Copyright (C) Luke Valenta 2023
*
* 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
@@ -89,6 +90,9 @@ struct MessageHeader {
static int initialised;
+static int first_reusable_fd;
+static int reusable_fds;
+
/* Flags indicating in which IP families sockets can be requested */
static int ip4_enabled;
static int ip6_enabled;
@@ -155,6 +159,59 @@ domain_to_string(int domain)
/* ================================================== */
+static int
+get_reusable_socket(int type, IPSockAddr *spec)
+{
+#ifdef LINUX
+ union sockaddr_all sa;
+ IPSockAddr ip_sa;
+ int sock_fd, opt;
+ socklen_t l;
+
+ /* Abort early if not an IPv4/IPv6 server socket */
+ if (!spec || spec->ip_addr.family == IPADDR_UNSPEC || spec->port == 0)
+ return INVALID_SOCK_FD;
+
+ /* Loop over available reusable sockets */
+ for (sock_fd = first_reusable_fd; sock_fd < first_reusable_fd + reusable_fds; sock_fd++) {
+
+ /* Check that types match */
+ l = sizeof (opt);
+ if (getsockopt(sock_fd, SOL_SOCKET, SO_TYPE, &opt, &l) < 0 ||
+ l != sizeof (opt) || opt != type)
+ continue;
+
+ /* Get sockaddr for reusable socket */
+ l = sizeof (sa);
+ if (getsockname(sock_fd, &sa.sa, &l) < 0 || l < sizeof (sa_family_t))
+ continue;
+ SCK_SockaddrToIPSockAddr(&sa.sa, l, &ip_sa);
+
+ /* Check that reusable socket matches specification */
+ if (ip_sa.port != spec->port || UTI_CompareIPs(&ip_sa.ip_addr, &spec->ip_addr, NULL) != 0)
+ continue;
+
+ /* Check that STREAM socket is listening */
+ l = sizeof (opt);
+ if (type == SOCK_STREAM && (getsockopt(sock_fd, SOL_SOCKET, SO_ACCEPTCONN, &opt, &l) < 0 ||
+ l != sizeof (opt) || opt == 0))
+ continue;
+
+#if defined(FEAT_IPV6) && defined(IPV6_V6ONLY)
+ if (spec->ip_addr.family == IPADDR_INET6 &&
+ (!SCK_GetIntOption(sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt) || opt != 1))
+ LOG(LOGS_WARN, "Reusable IPv6 socket missing IPV6_V6ONLY option");
+#endif
+
+ return sock_fd;
+ }
+#endif
+
+ return INVALID_SOCK_FD;
+}
+
+/* ================================================== */
+
#if defined(SOCK_CLOEXEC) || defined(SOCK_NONBLOCK)
static int
check_socket_flag(int sock_flag, int fd_flag, int fs_flag)
@@ -212,7 +269,7 @@ static int
set_socket_flags(int sock_fd, int flags)
{
/* Close the socket automatically on exec */
- if (
+ if (!SCK_IsReusable(sock_fd) &&
#ifdef SOCK_CLOEXEC
(supported_socket_flags & SOCK_CLOEXEC) == 0 &&
#endif
@@ -222,7 +279,7 @@ set_socket_flags(int sock_fd, int flags)
/* Enable non-blocking mode */
if ((flags & SCK_FLAG_BLOCK) == 0 &&
#ifdef SOCK_NONBLOCK
- (supported_socket_flags & SOCK_NONBLOCK) == 0 &&
+ (SCK_IsReusable(sock_fd) || (supported_socket_flags & SOCK_NONBLOCK) == 0) &&
#endif
!set_socket_nonblock(sock_fd))
return 0;
@@ -280,6 +337,32 @@ open_socket_pair(int domain, int type, int flags, int *other_fd)
/* ================================================== */
static int
+get_ip_socket(int domain, int type, int flags, IPSockAddr *ip_sa)
+{
+ int sock_fd;
+
+ /* Check if there is a matching reusable socket */
+ sock_fd = get_reusable_socket(type, ip_sa);
+
+ if (sock_fd < 0) {
+ sock_fd = open_socket(domain, type, flags);
+
+ /* Unexpected, but make sure the new socket is not in the reusable range */
+ if (SCK_IsReusable(sock_fd))
+ LOG_FATAL("Could not open %s socket : file descriptor in reusable range",
+ domain_to_string(domain));
+ } else {
+ /* Set socket flags on reusable socket */
+ if (!set_socket_flags(sock_fd, flags))
+ return INVALID_SOCK_FD;
+ }
+
+ return sock_fd;
+}
+
+/* ================================================== */
+
+static int
set_socket_options(int sock_fd, int flags)
{
/* Make the socket capable of sending broadcast packets if requested */
@@ -295,8 +378,10 @@ static int
set_ip_options(int sock_fd, int family, int flags)
{
#if defined(FEAT_IPV6) && defined(IPV6_V6ONLY)
- /* Receive only IPv6 packets on an IPv6 socket */
- if (family == IPADDR_INET6 && !SCK_SetIntOption(sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, 1))
+ /* Receive only IPv6 packets on an IPv6 socket, but do not attempt
+ to set this option on pre-initialised reuseable sockets */
+ if (family == IPADDR_INET6 && !SCK_IsReusable(sock_fd) &&
+ !SCK_SetIntOption(sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, 1))
return 0;
#endif
@@ -385,6 +470,10 @@ bind_ip_address(int sock_fd, IPSockAddr *addr, int flags)
;
#endif
+ /* Do not attempt to bind pre-initialised reusable socket */
+ if (SCK_IsReusable(sock_fd))
+ return 1;
+
saddr_len = SCK_IPSockAddrToSockaddr(addr, (struct sockaddr *)&saddr, sizeof (saddr));
if (saddr_len == 0)
return 0;
@@ -457,7 +546,7 @@ open_ip_socket(IPSockAddr *remote_addr, IPSockAddr *local_addr, const char *ifac
return INVALID_SOCK_FD;
}
- sock_fd = open_socket(domain, type, flags);
+ sock_fd = get_ip_socket(domain, type, flags, local_addr);
if (sock_fd < 0)
return INVALID_SOCK_FD;
@@ -482,7 +571,8 @@ open_ip_socket(IPSockAddr *remote_addr, IPSockAddr *local_addr, const char *ifac
goto error;
if (remote_addr || local_addr)
- DEBUG_LOG("Opened %s%s socket fd=%d%s%s%s%s",
+ DEBUG_LOG("%s %s%s socket fd=%d%s%s%s%s",
+ SCK_IsReusable(sock_fd) ? "Reusing" : "Opened",
type == SOCK_DGRAM ? "UDP" : type == SOCK_STREAM ? "TCP" : "?",
family == IPADDR_INET4 ? "v4" : "v6",
sock_fd,
@@ -1171,8 +1261,43 @@ send_message(int sock_fd, SCK_Message *message, int flags)
/* ================================================== */
void
+SCK_PreInitialise(void)
+{
+#ifdef LINUX
+ char *s, *ptr;
+
+ /* On Linux systems, the systemd service manager may pass file descriptors
+ for pre-initialised sockets to the chronyd daemon. The service manager
+ allocates and binds the file descriptors, and passes a copy to each
+ spawned instance of the service. This allows for zero-downtime service
+ restarts as the sockets buffer client requests until the service is able
+ to handle them. The service manager sets the LISTEN_FDS environment
+ variable to the number of passed file descriptors, and the integer file
+ descriptors start at 3 (see SD_LISTEN_FDS_START in
+ https://www.freedesktop.org/software/systemd/man/latest/sd_listen_fds.html). */
+ first_reusable_fd = 3;
+ reusable_fds = 0;
+
+ s = getenv("LISTEN_FDS");
+ if (s) {
+ errno = 0;
+ reusable_fds = strtol(s, &ptr, 10);
+ if (errno != 0 || *ptr != '\0' || reusable_fds < 0)
+ reusable_fds = 0;
+ }
+#else
+ first_reusable_fd = 0;
+ reusable_fds = 0;
+#endif
+}
+
+/* ================================================== */
+
+void
SCK_Initialise(int family)
{
+ int fd;
+
ip4_enabled = family == IPADDR_INET4 || family == IPADDR_UNSPEC;
#ifdef FEAT_IPV6
ip6_enabled = family == IPADDR_INET6 || family == IPADDR_UNSPEC;
@@ -1201,6 +1326,9 @@ SCK_Initialise(int family)
supported_socket_flags |= SOCK_NONBLOCK;
#endif
+ for (fd = first_reusable_fd; fd < first_reusable_fd + reusable_fds; fd++)
+ UTI_FdSetCloexec(fd);
+
initialised = 1;
}
@@ -1213,6 +1341,8 @@ SCK_Finalise(void)
ARR_DestroyInstance(recv_headers);
ARR_DestroyInstance(recv_messages);
+ SCK_CloseReusableSockets();
+
initialised = 0;
}
@@ -1354,6 +1484,27 @@ SCK_OpenUnixSocketPair(int flags, int *other_fd)
/* ================================================== */
int
+SCK_IsReusable(int fd)
+{
+ return fd >= first_reusable_fd && fd < first_reusable_fd + reusable_fds;
+}
+
+/* ================================================== */
+
+void
+SCK_CloseReusableSockets(void)
+{
+ int fd;
+
+ for (fd = first_reusable_fd; fd < first_reusable_fd + reusable_fds; fd++)
+ close(fd);
+ reusable_fds = 0;
+ first_reusable_fd = 0;
+}
+
+/* ================================================== */
+
+int
SCK_SetIntOption(int sock_fd, int level, int name, int value)
{
if (setsockopt(sock_fd, level, name, &value, sizeof (value)) < 0) {
@@ -1410,7 +1561,7 @@ SCK_EnableKernelRxTimestamping(int sock_fd)
int
SCK_ListenOnSocket(int sock_fd, int backlog)
{
- if (listen(sock_fd, backlog) < 0) {
+ if (!SCK_IsReusable(sock_fd) && listen(sock_fd, backlog) < 0) {
DEBUG_LOG("listen() failed : %s", strerror(errno));
return 0;
}
@@ -1573,6 +1724,10 @@ SCK_RemoveSocket(int sock_fd)
void
SCK_CloseSocket(int sock_fd)
{
+ /* Reusable sockets are closed in finalisation */
+ if (SCK_IsReusable(sock_fd))
+ return;
+
close(sock_fd);
}
diff --git a/socket.h b/socket.h
index cdbae2d..8b178e2 100644
--- a/socket.h
+++ b/socket.h
@@ -73,6 +73,9 @@ typedef struct {
int descriptor;
} SCK_Message;
+/* Pre-initialisation function */
+extern void SCK_PreInitialise(void);
+
/* Initialisation function (the specified IP family is enabled,
or all if IPADDR_UNSPEC) */
extern void SCK_Initialise(int family);
@@ -106,6 +109,12 @@ extern int SCK_OpenUnixStreamSocket(const char *remote_addr, const char *local_a
int flags);
extern int SCK_OpenUnixSocketPair(int flags, int *other_fd);
+/* Check if a file descriptor was passed from the service manager */
+extern int SCK_IsReusable(int sock_fd);
+
+/* Close all reusable sockets before finalisation (e.g. in a helper process) */
+extern void SCK_CloseReusableSockets(void);
+
/* Set and get a socket option of int size */
extern int SCK_SetIntOption(int sock_fd, int level, int name, int value);
extern int SCK_GetIntOption(int sock_fd, int level, int name, int *value);
diff --git a/sources.c b/sources.c
index e8e9705..e7ec4b8 100644
--- a/sources.c
+++ b/sources.c
@@ -174,6 +174,9 @@ static int selected_source_index; /* Which source index is currently
if no current valid reference) */
static int reported_no_majority; /* Flag to avoid repeated log message
about no majority */
+static int report_selection_loss; /* Flag to force logging a message if
+ selection is lost in a transient state
+ (SRC_WAITS_STATS, SRC_WAITS_UPDATE) */
/* Score needed to replace the currently selected source */
#define SCORE_LIMIT 10.0
@@ -201,6 +204,8 @@ static LOG_FileID logfileid;
/* Forward prototype */
static void update_sel_options(void);
+static void unselect_selected_source(LOG_Severity severity, const char *format,
+ const char *arg);
static void slew_sources(struct timespec *raw, struct timespec *cooked, double dfreq,
double doffset, LCL_ChangeType change_type, void *anything);
static void add_dispersion(double dispersion, void *anything);
@@ -330,11 +335,12 @@ void SRC_DestroyInstance(SRC_Instance instance)
update_sel_options();
- /* If this was the previous reference source, we have to reselect! */
- if (selected_source_index == dead_index)
- SRC_ReselectSource();
- else if (selected_source_index > dead_index)
+ if (selected_source_index > dead_index)
--selected_source_index;
+ else if (selected_source_index == dead_index)
+ unselect_selected_source(LOGS_INFO, NULL, NULL);
+
+ SRC_SelectSource(NULL);
}
/* ================================================== */
@@ -357,6 +363,9 @@ SRC_ResetInstance(SRC_Instance instance)
memset(&instance->sel_info, 0, sizeof (instance->sel_info));
SST_ResetInstance(instance->stats);
+
+ if (selected_source_index == instance->index)
+ SRC_SelectSource(NULL);
}
/* ================================================== */
@@ -734,6 +743,26 @@ mark_ok_sources(SRC_Status status)
}
/* ================================================== */
+/* Reset the index of selected source and report the selection loss. If no
+ message is provided, assume it is a transient state and wait for another
+ call providing a message or selection of another source, which resets the
+ report_selection_loss flag. */
+
+static void
+unselect_selected_source(LOG_Severity severity, const char *format, const char *arg)
+{
+ if (selected_source_index != INVALID_SOURCE) {
+ selected_source_index = INVALID_SOURCE;
+ report_selection_loss = 1;
+ }
+
+ if (report_selection_loss && format) {
+ log_selection_message(severity, format, arg);
+ report_selection_loss = 0;
+ }
+}
+
+/* ================================================== */
static int
combine_sources(int n_sel_sources, struct timespec *ref_time, double *offset,
@@ -850,11 +879,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
}
if (n_sources == 0) {
- /* In this case, we clearly cannot synchronise to anything */
- if (selected_source_index != INVALID_SOURCE) {
- log_selection_message(LOGS_INFO, "Can't synchronise: no sources", NULL);
- selected_source_index = INVALID_SOURCE;
- }
+ unselect_selected_source(LOGS_INFO, "Can't synchronise: no sources", NULL);
return;
}
@@ -1039,15 +1064,13 @@ SRC_SelectSource(SRC_Instance updated_inst)
if (n_badstats_sources && n_sel_sources && selected_source_index == INVALID_SOURCE &&
max_sel_reach_size < SOURCE_REACH_BITS && max_sel_reach >> 1 == max_badstat_reach) {
mark_ok_sources(SRC_WAITS_STATS);
+ unselect_selected_source(LOGS_INFO, NULL, NULL);
return;
}
if (n_endpoints == 0) {
/* No sources provided valid endpoints */
- if (selected_source_index != INVALID_SOURCE) {
- log_selection_message(LOGS_INFO, "Can't synchronise: no selectable sources", NULL);
- selected_source_index = INVALID_SOURCE;
- }
+ unselect_selected_source(LOGS_INFO, "Can't synchronise: no selectable sources", NULL);
return;
}
@@ -1128,6 +1151,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
if (!reported_no_majority) {
log_selection_message(LOGS_WARN, "Can't synchronise: no majority", NULL);
reported_no_majority = 1;
+ report_selection_loss = 0;
}
if (selected_source_index != INVALID_SOURCE) {
@@ -1184,12 +1208,9 @@ SRC_SelectSource(SRC_Instance updated_inst)
}
if (!n_sel_sources || sel_req_source || n_sel_sources < CNF_GetMinSources()) {
- if (selected_source_index != INVALID_SOURCE) {
- log_selection_message(LOGS_INFO, "Can't synchronise: %s selectable sources",
- !n_sel_sources ? "no" :
- sel_req_source ? "no required source in" : "not enough");
- selected_source_index = INVALID_SOURCE;
- }
+ unselect_selected_source(LOGS_INFO, "Can't synchronise: %s selectable sources",
+ !n_sel_sources ? "no" :
+ sel_req_source ? "no required source in" : "not enough");
mark_ok_sources(SRC_WAITS_SOURCES);
return;
}
@@ -1296,7 +1317,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
/* Before selecting the new synchronisation source wait until the reference
can be updated */
if (sources[max_score_index]->updates == 0) {
- selected_source_index = INVALID_SOURCE;
+ unselect_selected_source(LOGS_INFO, NULL, NULL);
mark_ok_sources(SRC_WAITS_UPDATE);
return;
}
@@ -1312,6 +1333,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
}
reported_no_majority = 0;
+ report_selection_loss = 0;
}
mark_source(sources[selected_source_index], SRC_SELECTED);
diff --git a/stubs.c b/stubs.c
index cb7b9a6..b729c2f 100644
--- a/stubs.c
+++ b/stubs.c
@@ -207,6 +207,12 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type,
return NSR_TooManySources;
}
+const char *
+NSR_StatusToString(NSR_Status status)
+{
+ return "NTP not supported";
+}
+
NSR_Status
NSR_RemoveSource(IPAddr *address)
{
diff --git a/test/compilation/002-scanbuild b/test/compilation/002-scanbuild
index 35a3faf..0395df9 100755
--- a/test/compilation/002-scanbuild
+++ b/test/compilation/002-scanbuild
@@ -7,9 +7,9 @@ for opts in \
"--host-system=NetBSD" \
"--host-system=FreeBSD" \
"--without-nettle" \
- "--without-nettle --without-nss" \
- "--without-nettle --without-nss --without-tomcrypt" \
- "--without-nettle --without-nss --without-tomcrypt --without-gnutls"
+ "--without-nettle --without-gnutls" \
+ "--without-nettle --without-gnutls --without-nss" \
+ "--without-nettle --without-gnutls --without-nss --without-tomcrypt"
do
./configure $opts
scan-build make "$@" || exit 1
diff --git a/test/compilation/003-sanitizers b/test/compilation/003-sanitizers
index 2edd6e6..9287223 100755
--- a/test/compilation/003-sanitizers
+++ b/test/compilation/003-sanitizers
@@ -25,13 +25,13 @@ touch Makefile
for extra_config_opts in \
"--all-privops" \
"--disable-ipv6" \
+ "--disable-nts" \
"--disable-scfilter" \
"--without-aes-gcm-siv" \
- "--without-gnutls" \
"--without-nettle" \
- "--without-nettle --without-nss" \
- "--without-nettle --without-nss --without-tomcrypt" \
- "--without-nettle --without-nss --without-tomcrypt --without-gnutls"; \
+ "--without-nettle --without-gnutls" \
+ "--without-nettle --without-gnutls --without-nss" \
+ "--without-nettle --without-gnutls --without-nss --without-tomcrypt"; \
do
for arch_opts in "-m32" ""; do
pushd test/simulation/clknetsim || exit 1
diff --git a/test/simulation/110-chronyc b/test/simulation/110-chronyc
index 97abc21..46b0a3f 100755
--- a/test/simulation/110-chronyc
+++ b/test/simulation/110-chronyc
@@ -114,7 +114,7 @@ limit=1
for chronyc_conf in \
"accheck 1.2.3.4" \
"add peer 10.0.0.0 minpoll 2 maxpoll 6" \
- "add server 10.0.0.0 minpoll 6 maxpoll 10 iburst burst key 1 certset 2 maxdelay 1e-3 maxdelayratio 10.0 maxdelaydevratio 10.0 maxdelayquant 0.5 mindelay 1e-4 asymmetry 0.5 offset 1e-5 minsamples 6 maxsamples 6 filter 3 offline auto_offline prefer noselect trust require xleave polltarget 20 port 123 presend 7 minstratum 3 version 4 nts ntsport 4460 copy extfield F323" \
+ "add server 10.0.0.0 minpoll 6 maxpoll 10 iburst burst key 1 certset 2 maxdelay 1e-3 maxdelayratio 10.0 maxdelaydevratio 10.0 maxdelayquant 0.5 mindelay 1e-4 asymmetry 0.5 offset 1e-5 minsamples 6 maxsamples 6 filter 3 offline auto_offline prefer noselect trust require xleave polltarget 20 port 123 presend 7 minstratum 3 version 4 nts ntsport 4460 copy extfield F323 extfield F324" \
"add server node1.net1.clk" \
"allow 1.2.3.4" \
"allow 1.2" \
diff --git a/test/simulation/114-presend b/test/simulation/114-presend
index 19400ab..3b89a70 100755
--- a/test/simulation/114-presend
+++ b/test/simulation/114-presend
@@ -23,4 +23,29 @@ check_source_selection || test_fail
check_packet_interval || test_fail
check_sync || test_fail
+limit=10
+base_delay=$default_base_delay
+client_conf="logdir tmp
+log measurements"
+
+client_server_options="presend 5"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_packet_interval || test_fail
+
+check_file_messages "20.*123\.1.* 111 111 0111" 1 1 measurements.log || test_fail
+check_file_messages "20.*123\.1.* 111 111 1111" 1 1 measurements.log || test_fail
+rm -f tmp/measurements.log
+
+client_server_options="presend 5 xleave"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_packet_interval || test_fail
+
+check_file_messages "20.*123\.1.* 111 111 0111" 2 2 measurements.log || test_fail
+check_file_messages "20.*123\.1.* 111 111 1111" 1 1 measurements.log || test_fail
+rm -f tmp/measurements.log
+
test_pass
diff --git a/test/simulation/142-ntpoverptp b/test/simulation/142-ntpoverptp
new file mode 100755
index 0000000..2996dc0
--- /dev/null
+++ b/test/simulation/142-ntpoverptp
@@ -0,0 +1,106 @@
+#!/usr/bin/env bash
+
+. ./test.common
+
+test_start "NTP over PTP"
+
+# Block communication between 3 and 1
+base_delay="(+ 1e-4 (* -1 (equal 0.1 from 3) (equal 0.1 to 1)))"
+
+cat > tmp/peer.keys <<-EOF
+1 MD5 1234567890
+EOF
+
+clients=2
+peers=2
+max_sync_time=420
+
+server_conf="
+ptpport 319"
+client_conf="
+ptpport 319
+authselectmode ignore
+keyfile tmp/peer.keys"
+client_server_options="minpoll 6 maxpoll 6 port 319"
+client_peer_options="minpoll 6 maxpoll 6 port 319 key 1"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+
+check_file_messages " 2 1 .* 319 319 1 96 " 150 160 \
+ log.packets || test_fail
+check_file_messages " 1 2 .* 319 319 1 96 " 150 160 \
+ log.packets || test_fail
+check_file_messages " 2 3 .* 319 319 1 116 " 150 160 \
+ log.packets || test_fail
+check_file_messages " 3 2 .* 319 319 1 116 " 150 160 \
+ log.packets || test_fail
+
+check_config_h 'HAVE_LINUX_TIMESTAMPING 1' || test_skip
+
+export CLKNETSIM_TIMESTAMPING=2
+export CLKNETSIM_LINK_SPEED=100
+
+client_server_options+=" extfield F324 minpoll 0 maxpoll 0"
+client_peer_options+=" extfield F324 minpoll 0 maxpoll 0 maxdelaydevratio 1e6"
+server_conf+="
+clockprecision 1e-9
+hwtimestamp eth0"
+client_conf+="
+clockprecision 1e-9
+hwtimestamp eth0"
+delay_correction="(+ delay (* -8e-8 (+ length 46)))"
+wander=1e-9
+limit=1000
+freq_offset=-1e-4
+min_sync_time=5
+max_sync_time=20
+time_max_limit=1e-7
+time_rms_limit=2e-8
+freq_max_limit=1e-7
+freq_rms_limit=5e-8
+client_chronyd_options="-d"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+
+if check_config_h 'FEAT_DEBUG 1'; then
+ check_log_messages "apply_net_correction.*Applied" 900 2100 || test_fail
+ check_log_messages "apply_net_correction.*Invalid" 0 4 || test_fail
+fi
+
+client_server_options+=" xleave"
+client_peer_options+=" xleave"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+
+if check_config_h 'FEAT_DEBUG 1'; then
+ check_log_messages "apply_net_correction.*Applied" 900 2100 || test_fail
+ check_log_messages "apply_net_correction.*Invalid" 0 4 || test_fail
+
+ freq_offset=0.0
+ delay_correction="(+ -1.0e-9 (* 1.0001 delay))"
+
+ run_test || test_fail
+ check_chronyd_exit || test_fail
+
+ check_log_messages "apply_net_correction.*Applied" 350 1400 || test_fail
+ check_log_messages "apply_net_correction.*Invalid" 350 1400 || test_fail
+
+ server_conf="ptpport 319"
+ client_conf="ptpport 319"
+
+ run_test || test_fail
+ check_chronyd_exit || test_fail
+
+ check_log_messages "apply_net_correction.*Applied" 0 0 || test_fail
+fi
+
+test_pass
diff --git a/test/simulation/142-ptpport b/test/simulation/142-ptpport
deleted file mode 100755
index 060932c..0000000
--- a/test/simulation/142-ptpport
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env bash
-
-. ./test.common
-
-test_start "PTP port"
-
-# Block communication between 3 and 1
-base_delay="(+ 1e-4 (* -1 (equal 0.1 from 3) (equal 0.1 to 1)))"
-
-cat > tmp/peer.keys <<-EOF
-1 MD5 1234567890
-EOF
-
-clients=2
-peers=2
-max_sync_time=420
-
-server_conf="
-ptpport 319"
-client_conf="
-ptpport 319
-authselectmode ignore
-keyfile tmp/peer.keys"
-client_server_options="minpoll 6 maxpoll 6 port 319"
-client_peer_options="minpoll 6 maxpoll 6 port 319 key 1"
-
-run_test || test_fail
-check_chronyd_exit || test_fail
-check_source_selection || test_fail
-check_sync || test_fail
-
-check_file_messages " 2 1 .* 319 319 1 96 " 150 160 \
- log.packets || test_fail
-check_file_messages " 1 2 .* 319 319 1 96 " 150 160 \
- log.packets || test_fail
-check_file_messages " 2 3 .* 319 319 1 116 " 150 160 \
- log.packets || test_fail
-check_file_messages " 3 2 .* 319 319 1 116 " 150 160 \
- log.packets || test_fail
-
-test_pass
diff --git a/test/simulation/144-exp1 b/test/simulation/144-monoroot
index 4a2042d..20fae12 100755
--- a/test/simulation/144-exp1
+++ b/test/simulation/144-monoroot
@@ -2,7 +2,7 @@
. ./test.common
-test_start "experimental extension field"
+test_start "mono+root extension field"
check_config_h 'FEAT_CMDMON 1' || test_skip
diff --git a/test/simulation/test.common b/test/simulation/test.common
index 3f6e80b..42a2917 100644
--- a/test/simulation/test.common
+++ b/test/simulation/test.common
@@ -31,6 +31,7 @@ default_primary_time_offset=0.0
default_time_offset=1e-1
default_freq_offset=1e-4
default_base_delay=1e-4
+default_delay_correction=""
default_jitter=1e-4
default_jitter_asymmetry=0.0
default_wander=1e-9
@@ -460,6 +461,10 @@ run_test() {
for j in $(seq 1 $nodes); do
echo "node${i}_delay${j} = $(get_delay_expr up)"
echo "node${j}_delay${i} = $(get_delay_expr down)"
+ if [ -n "$delay_correction" ]; then
+ echo "node${i}_delay_correction${j} = $delay_correction"
+ echo "node${j}_delay_correction${i} = $delay_correction"
+ fi
done
done > tmp/conf
diff --git a/test/system/008-confload b/test/system/008-confload
index a7fc1d5..7e80698 100755
--- a/test/system/008-confload
+++ b/test/system/008-confload
@@ -30,6 +30,8 @@ echo "server 127.123.4.4" > $TEST_DIR/conf4.d/4.conf
echo "server 127.123.5.1" > $TEST_DIR/conf5.d/1.sources
echo "server 127.123.5.2" > $TEST_DIR/conf5.d/2.sources
echo "server 127.123.5.3" > $TEST_DIR/conf5.d/3.sources
+echo "server 127.123.5.4" > $TEST_DIR/conf5.d/4.sources
+echo "server 127.123.5.5" > $TEST_DIR/conf5.d/5.sources
start_chronyd || test_fail
@@ -46,12 +48,16 @@ check_chronyc_output "^[^=]*
.. 127\.123\.1\.2 [^^]*
.. 127\.123\.5\.1 [^^]*
.. 127\.123\.5\.2 [^^]*
-.. 127\.123\.5\.3 [^^]*$" || test_fail
+.. 127\.123\.5\.3 [^^]*
+.. 127\.123\.5\.4 [^^]*
+.. 127\.123\.5\.5 [^^]*$" || test_fail
rm $TEST_DIR/conf5.d/1.sources
-echo "server 127.123.5.2 minpoll 7" > $TEST_DIR/conf5.d/2.sources
-echo > $TEST_DIR/conf5.d/3.sources
-echo "server 127.123.5.4" > $TEST_DIR/conf5.d/4.sources
+echo "server 127.123.5.2 minpoll 5" > $TEST_DIR/conf5.d/2.sources
+echo "server 127.123.5.3 minpoll 7" > $TEST_DIR/conf5.d/3.sources
+echo > $TEST_DIR/conf5.d/4.sources
+echo "server 127.123.5.5" >> $TEST_DIR/conf5.d/5.sources
+echo "server 127.123.5.6" > $TEST_DIR/conf5.d/6.sources
run_chronyc "reload sources" || test_fail
@@ -66,9 +72,12 @@ check_chronyc_output "^[^=]*
.. 127\.123\.2\.3 [^^]*
.. 127\.123\.4\.4 [^^]*
.. 127\.123\.1\.2 *[05] 6 [^^]*
-.. 127\.123\.5\.2 *[05] 7 [^^]*
-.. 127\.123\.5\.4 [^^]*$" || test_fail
+.. 127\.123\.5\.5 [^^]*
+.. 127\.123\.5\.2 *[05] 5 [^^]*
+.. 127\.123\.5\.3 *[05] 7 [^^]*
+.. 127\.123\.5\.6 [^^]*$" || test_fail
stop_chronyd || test_fail
+check_chronyd_message_count "Could not add source" 1 1 || test_fail
test_pass
diff --git a/test/system/011-systemd b/test/system/011-systemd
new file mode 100755
index 0000000..1049966
--- /dev/null
+++ b/test/system/011-systemd
@@ -0,0 +1,140 @@
+#!/usr/bin/env bash
+
+. ./test.common
+
+check_chronyd_features NTS || test_skip "NTS support disabled"
+certtool --help &> /dev/null || test_skip "certtool missing"
+check_chronyd_features DEBUG || test_skip "DEBUG support disabled"
+systemd-socket-activate -h &> /dev/null || test_skip "systemd-socket-activate missing"
+has_ipv6=$(check_chronyd_features IPV6 && ping6 -c 1 ::1 > /dev/null 2>&1 && echo 1 || echo 0)
+
+test_start "systemd socket activation"
+
+cat > $TEST_DIR/cert.cfg <<EOF
+cn = "chrony-nts-test"
+dns_name = "chrony-nts-test"
+ip_address = "$server"
+$([ "$has_ipv6" = "1" ] && echo 'ip_address = "::1"')
+serial = 001
+activation_date = "$[$(date '+%Y') - 1]-01-01 00:00:00 UTC"
+expiration_date = "$[$(date '+%Y') + 2]-01-01 00:00:00 UTC"
+signing_key
+encryption_key
+EOF
+
+certtool --generate-privkey --key-type=ed25519 --outfile $TEST_DIR/server.key \
+ &> $TEST_DIR/certtool.log
+certtool --generate-self-signed --load-privkey $TEST_DIR/server.key \
+ --template $TEST_DIR/cert.cfg --outfile $TEST_DIR/server.crt &>> $TEST_DIR/certtool.log
+chown $user $TEST_DIR/server.*
+
+ntpport=$(get_free_port)
+ntsport=$(get_free_port)
+
+server_options="port $ntpport nts ntsport $ntsport"
+extra_chronyd_directives="
+port $ntpport
+ntsport $ntsport
+ntsserverkey $TEST_DIR/server.key
+ntsservercert $TEST_DIR/server.crt
+ntstrustedcerts $TEST_DIR/server.crt
+ntsdumpdir $TEST_LIBDIR
+ntsprocesses 3"
+
+if [ "$has_ipv6" = "1" ]; then
+ extra_chronyd_directives="$extra_chronyd_directives
+ bindaddress ::1
+ server ::1 minpoll -6 maxpoll -6 $server_options"
+fi
+
+# enable debug logging
+extra_chronyd_options="-L -1"
+# Hack to trigger systemd-socket-activate to activate the service. Normally,
+# chronyd.service would be configured with the WantedBy= directive so it starts
+# without waiting for socket activation.
+# (https://0pointer.de/blog/projects/socket-activation.html).
+for i in $(seq 10); do
+ sleep 1
+ (echo "wake up" > /dev/udp/127.0.0.1/$ntpport) 2>/dev/null
+ (echo "wake up" > /dev/tcp/127.0.0.1/$ntsport) 2>/dev/null
+done &
+
+# Test with UDP sockets (unfortunately systemd-socket-activate doesn't support
+# both datagram and stream sockets in the same invocation:
+# https://github.com/systemd/systemd/issues/9983).
+CHRONYD_WRAPPER="systemd-socket-activate \
+ --datagram \
+ --listen 127.0.0.1:$ntpport \
+ --listen 127.0.0.1:$ntsport"
+if [ "$has_ipv6" = "1" ]; then
+ CHRONYD_WRAPPER="$CHRONYD_WRAPPER \
+ --listen [::1]:$ntpport \
+ --listen [::1]:$ntsport"
+fi
+
+start_chronyd || test_fail
+wait_for_sync || test_fail
+
+if [ "$has_ipv6" = "1" ]; then
+ run_chronyc "ntpdata ::1" || test_fail
+ check_chronyc_output "Total RX +: [1-9]" || test_fail
+fi
+run_chronyc "authdata" || test_fail
+check_chronyc_output "^Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen
+=========================================================================\
+$([ "$has_ipv6" = "1" ] && printf "\n%s\n" '::1 NTS 1 (30|15) (128|256) [0-9] 0 0 [78] ( 64|100)')
+127\.0\.0\.1 NTS 1 (30|15) (128|256) [0-9] 0 0 [78] ( 64|100)$" || test_fail
+
+stop_chronyd || test_fail
+# DGRAM ntpport socket should be used
+check_chronyd_message_count "Reusing UDPv4 socket fd=3 local=127.0.0.1:$ntpport" 1 1 || test_fail
+# DGRAM ntsport socket should be ignored
+check_chronyd_message_count "Reusing TCPv4 socket fd=4 local=127.0.0.1:$ntsport" 0 0 || test_fail
+if [ "$has_ipv6" = "1" ]; then
+ # DGRAM ntpport socket should be used
+ check_chronyd_message_count "Reusing UDPv6 socket fd=5 local=\[::1\]:$ntpport" 1 1 || test_fail
+ # DGRAM ntsport socket should be ignored
+ check_chronyd_message_count "Reusing TCPv6 socket fd=6 local=\[::1\]:$ntsport" 0 0 || test_fail
+fi
+
+check_chronyd_messages || test_fail
+check_chronyd_files || test_fail
+
+# Test with TCP sockets
+CHRONYD_WRAPPER="systemd-socket-activate \
+ --listen 127.0.0.1:$ntpport \
+ --listen 127.0.0.1:$ntsport"
+if [ "$has_ipv6" = "1" ]; then
+ CHRONYD_WRAPPER="$CHRONYD_WRAPPER \
+ --listen [::1]:$ntpport \
+ --listen [::1]:$ntsport"
+fi
+
+start_chronyd || test_fail
+wait_for_sync || test_fail
+
+if [ "$has_ipv6" = "1" ]; then
+ run_chronyc "ntpdata ::1" || test_fail
+ check_chronyc_output "Total RX +: [1-9]" || test_fail
+fi
+run_chronyc "authdata" || test_fail
+check_chronyc_output "^Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen
+=========================================================================\
+$([ "$has_ipv6" = "1" ] && printf "\n%s\n" '::1 NTS 1 (30|15) (128|256) [0-9] 0 0 [78] ( 64|100)')
+127\.0\.0\.1 NTS 1 (30|15) (128|256) [0-9] 0 0 [78] ( 64|100)$" || test_fail
+
+stop_chronyd || test_fail
+# STREAM ntpport should be ignored
+check_chronyd_message_count "Reusing TCPv4 socket fd=3 local=127.0.0.1:$ntpport" 0 0 || test_fail
+# STREAM ntsport should be used
+check_chronyd_message_count "Reusing TCPv4 socket fd=4 local=127.0.0.1:$ntsport" 1 1 || test_fail
+if [ "$has_ipv6" = "1" ]; then
+ # STREAM ntpport should be ignored
+ check_chronyd_message_count "Reusing TCPv6 socket fd=5 local=\[::1\]:$ntpport" 0 0 || test_fail
+ # STREAM ntsport should be used
+ check_chronyd_message_count "Reusing TCPv6 socket fd=6 local=\[::1\]:$ntsport" 1 1 || test_fail
+fi
+check_chronyd_messages || test_fail
+check_chronyd_files || test_fail
+
+test_pass
diff --git a/test/system/test.common b/test/system/test.common
index aa48ac6..c389b48 100644
--- a/test/system/test.common
+++ b/test/system/test.common
@@ -324,7 +324,7 @@ check_chronyd_messages() {
([ "$clock_control" -ne 0 ] || grep -q 'Disabled control of system clock' "$logfile") && \
([ "$minimal_config" -ne 0 ] || grep -q 'Frequency .* read from' "$logfile") && \
grep -q 'chronyd exiting' "$logfile" && \
- ! grep -q 'Could not' "$logfile" && \
+ ! (grep -v '^.\{19\}Z D:' "$logfile" | grep -q 'Could not') && \
! grep -q 'Disabled command socket' "$logfile" && \
test_ok || test_bad
}
diff --git a/test/unit/ntp_core.c b/test/unit/ntp_core.c
index 08a1532..989b294 100644
--- a/test/unit/ntp_core.c
+++ b/test/unit/ntp_core.c
@@ -99,8 +99,8 @@ send_request(NCR_Instance inst, int late_hwts)
local_addr.ip_addr.family = IPADDR_UNSPEC;
local_addr.if_index = INVALID_IF_INDEX;
local_addr.sock_fd = 101;
+ zero_local_timestamp(&local_ts);
local_ts.ts = current_time;
- local_ts.err = 0.0;
local_ts.source = NTP_TS_KERNEL;
NCR_ProcessTxKnown(inst, &local_addr, &local_ts, &req_buffer, req_length);
@@ -122,8 +122,8 @@ process_request(NTP_Remote_Address *remote_addr)
local_addr.ip_addr.family = IPADDR_UNSPEC;
local_addr.if_index = INVALID_IF_INDEX;
local_addr.sock_fd = 100;
+ zero_local_timestamp(&local_ts);
local_ts.ts = current_time;
- local_ts.err = 0.0;
local_ts.source = NTP_TS_KERNEL;
res_length = 0;
@@ -289,8 +289,8 @@ proc_response(NCR_Instance inst, int good, int valid, int updated_sync,
local_addr.ip_addr.family = IPADDR_UNSPEC;
local_addr.if_index = INVALID_IF_INDEX;
local_addr.sock_fd = NTP_LVM_TO_MODE(res->lvm) != MODE_SERVER ? 100 : 101;
+ zero_local_timestamp(&local_ts);
local_ts.ts = current_time;
- local_ts.err = 0.0;
local_ts.source = NTP_TS_KERNEL;
prev_rx_count = inst->report.total_rx_count;
diff --git a/test/unit/ntp_sources.c b/test/unit/ntp_sources.c
index 1626552..e3d7c4d 100644
--- a/test/unit/ntp_sources.c
+++ b/test/unit/ntp_sources.c
@@ -88,6 +88,8 @@ update_random_address(NTP_Remote_Address *addr, int rand_bits)
TEST_CHECK(status == NSR_Success || status == NSR_AlreadyInUse);
}
+ TEST_CHECK(strlen(NSR_StatusToString(status)) > 0);
+
return status == NSR_Success;
}
diff --git a/test/unit/socket.c b/test/unit/socket.c
new file mode 100644
index 0000000..c4edea0
--- /dev/null
+++ b/test/unit/socket.c
@@ -0,0 +1,61 @@
+/*
+ **********************************************************************
+ * Copyright (C) Luke Valenta 2023
+ *
+ * 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.
+ *
+ **********************************************************************
+ */
+
+#include <socket.c>
+#include "test.h"
+
+static void
+test_preinitialise(void)
+{
+#ifdef LINUX
+ /* Test LISTEN_FDS environment variable parsing */
+
+ /* normal */
+ putenv("LISTEN_FDS=2");
+ SCK_PreInitialise();
+ TEST_CHECK(reusable_fds == 2);
+
+ /* negative */
+ putenv("LISTEN_FDS=-2");
+ SCK_PreInitialise();
+ TEST_CHECK(reusable_fds == 0);
+
+ /* trailing characters */
+ putenv("LISTEN_FDS=2a");
+ SCK_PreInitialise();
+ TEST_CHECK(reusable_fds == 0);
+
+ /* non-integer */
+ putenv("LISTEN_FDS=a2");
+ SCK_PreInitialise();
+ TEST_CHECK(reusable_fds == 0);
+
+ /* not set */
+ unsetenv("LISTEN_FDS");
+ SCK_PreInitialise();
+ TEST_CHECK(reusable_fds == 0);
+#endif
+}
+
+void
+test_unit(void)
+{
+ test_preinitialise();
+}
diff --git a/test/unit/util.c b/test/unit/util.c
index fa294c4..d52a268 100644
--- a/test/unit/util.c
+++ b/test/unit/util.c
@@ -1,6 +1,6 @@
/*
**********************************************************************
- * Copyright (C) Miroslav Lichvar 2017-2018, 2021
+ * Copyright (C) Miroslav Lichvar 2017-2018, 2021, 2023
*
* 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
@@ -253,6 +253,47 @@ test_unit(void)
TEST_CHECK(UTI_IsEqualAnyNtp64(&ntp_ts, NULL, NULL, &ntp_ts));
TEST_CHECK(!UTI_IsEqualAnyNtp64(&ntp_ts, &ntp_fuzz, &ntp_fuzz, &ntp_fuzz));
+ ntp_ts.hi = htonl(0);
+ ntp_ts.lo = htonl(0);
+ x = UTI_Ntp64ToDouble(&ntp_ts);
+ TEST_CHECK(fabs(x) < 1e-10);
+ UTI_DoubleToNtp64(x, &ntp_ts2);
+ TEST_CHECK(UTI_CompareNtp64(&ntp_ts, &ntp_ts2) == 0);
+
+ ntp_ts.hi = htonl(0);
+ ntp_ts.lo = htonl(0xffffffff);
+ x = UTI_Ntp64ToDouble(&ntp_ts);
+ TEST_CHECK(fabs(x - 1.0 + 0.23e-9) < 1e-10);
+ UTI_DoubleToNtp64(x, &ntp_ts2);
+ TEST_CHECK(fabs(UTI_DiffNtp64ToDouble(&ntp_ts, &ntp_ts2)) < 0.3e-9);
+
+ ntp_ts.hi = htonl(0xffffffff);
+ ntp_ts.lo = htonl(0xffffffff);
+ x = UTI_Ntp64ToDouble(&ntp_ts);
+ TEST_CHECK(fabs(x + 0.23e-9) < 1e-10);
+ UTI_DoubleToNtp64(x, &ntp_ts2);
+ TEST_CHECK(fabs(UTI_DiffNtp64ToDouble(&ntp_ts, &ntp_ts2)) < 0.3e-9);
+
+ ntp_ts.hi = htonl(0x80000000);
+ ntp_ts.lo = htonl(0);
+ x = UTI_Ntp64ToDouble(&ntp_ts);
+ TEST_CHECK(fabs(x + 0x80000000) < 1e-10);
+ UTI_DoubleToNtp64(x, &ntp_ts2);
+ TEST_CHECK(fabs(UTI_DiffNtp64ToDouble(&ntp_ts, &ntp_ts2)) < 0.3e-9);
+
+ ntp_ts.hi = htonl(0x7fffffff);
+ ntp_ts.lo = htonl(0xffffffff);
+ x = UTI_Ntp64ToDouble(&ntp_ts);
+ TEST_CHECK(fabs(x - 2147483648) < 1.0);
+
+ ntp_ts.lo = htonl(0);
+ ntp_ts.hi = htonl(0x7fffffff);
+ UTI_DoubleToNtp64(0x7fffffff + 0.1, &ntp_ts2);
+ TEST_CHECK(UTI_CompareNtp64(&ntp_ts, &ntp_ts2) == 0);
+ ntp_ts.hi = htonl(0x80000000);
+ UTI_DoubleToNtp64(0x80000000 - 0.1, &ntp_ts);
+ TEST_CHECK(UTI_CompareNtp64(&ntp_ts, &ntp_ts2) == 0);
+
ts.tv_sec = 1;
ts.tv_nsec = 2;
ts2.tv_sec = 1;
diff --git a/util.c b/util.c
index a240e3e..a4c8288 100644
--- a/util.c
+++ b/util.c
@@ -818,6 +818,33 @@ UTI_DiffNtp64ToDouble(const NTP_int64 *a, const NTP_int64 *b)
/* ================================================== */
+double
+UTI_Ntp64ToDouble(NTP_int64 *src)
+{
+ NTP_int64 zero;
+
+ UTI_ZeroNtp64(&zero);
+ return UTI_DiffNtp64ToDouble(src, &zero);
+}
+
+/* ================================================== */
+
+void
+UTI_DoubleToNtp64(double src, NTP_int64 *dest)
+{
+ int32_t hi;
+
+ src = CLAMP(INT32_MIN, src, INT32_MAX);
+ hi = round(src);
+ if (hi > src)
+ hi -= 1;
+
+ dest->hi = htonl(hi);
+ dest->lo = htonl((src - hi) * (1.0e9 * NSEC_PER_NTP64));
+}
+
+/* ================================================== */
+
/* Maximum offset between two sane times */
#define MAX_OFFSET 4294967296.0
diff --git a/util.h b/util.h
index d38abf0..9f11ba6 100644
--- a/util.h
+++ b/util.h
@@ -163,6 +163,10 @@ extern void UTI_Ntp64ToTimespec(const NTP_int64 *src, struct timespec *dest);
/* Calculate a - b in any epoch */
extern double UTI_DiffNtp64ToDouble(const NTP_int64 *a, const NTP_int64 *b);
+/* Convert a difference in double (not a timestamp) from and to NTP format */
+extern double UTI_Ntp64ToDouble(NTP_int64 *src);
+extern void UTI_DoubleToNtp64(double src, NTP_int64 *dest);
+
/* Check if time + offset is sane */
extern int UTI_IsTimeOffsetSane(const struct timespec *ts, double offset);
diff --git a/version.txt b/version.txt
index 515be8f..4caecc7 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-4.4
+4.5