Compare commits

..

56 Commits

Author SHA1 Message Date
Miroslav Lichvar
426fe2ee58 doc: update NEWS 2023-11-22 13:53:23 +01:00
Miroslav Lichvar
3f66202d79 doc: update README 2023-11-22 11:56:16 +01:00
Miroslav Lichvar
ed6b0b55c7 doc: replace foobar naming in examples 2023-11-22 11:56:15 +01:00
Miroslav Lichvar
5e5adbea0c doc: update description of NTP over PTP in FAQ 2023-11-22 11:56:15 +01:00
Miroslav Lichvar
82959431df doc: mention version supporting socket activation in FAQ 2023-11-22 11:56:15 +01:00
Miroslav Lichvar
b92b2da24a doc: improve ntstrustedcerts description 2023-11-22 11:55:27 +01:00
Miroslav Lichvar
68a3d52086 doc: improve cmdport description 2023-11-22 09:48:36 +01:00
Miroslav Lichvar
1a15be1e9e sources: drop unreachable log message
With forced reselection during source removal selected_source_index
can only be INVALID_SOURCE if there are no sources. The "Can't
synchronise: no sources" message couldn't be logged even before that as
SRC_ReselectSource() resets the index before calling SRC_SelectSource().

Replace the message with an assertion.
2023-11-21 12:38:41 +01:00
Miroslav Lichvar
5dd288dc0c sources: reselect earlier when removing selected source
When a selected source is being removed, reset the instance and rerun
the selection while the source is still marked as selected. This forces
a "Can't synchronise" message to be logged when all sources are removed.

Reported-by: Thomas Lange <thomas@corelatus.se>
2023-11-21 12:38:41 +01:00
Miroslav Lichvar
cbee464c75 sources: reselect after resetting selected source
Avoid showing in the sources report a selected source which has no
samples (e.g. after replacement).
2023-11-21 12:38:41 +01:00
Miroslav Lichvar
4e36295889 ntp: allow reusing timestamps of unused samples
When switching from basic mode to interleaved mode following a response
which wasn't accumulated due to failed test A, B, C, or D, allow
timestamps of the failed sample to be reused in interleaved mode, i.e.
replacing the server's less accurate transmit timestamp with a more
accurate timestamp server can turn a failed sample into acceptable one.

Move the presend check into test A to simplify the code.
2023-11-21 12:38:41 +01:00
Miroslav Lichvar
2d2642bb82 ntp: fix presend in interleaved mode
The presend option in interleaved mode uses two presend requests instead
of one to get an interleaved response from servers like chrony which
delay the first interleaved response due to an optimization saving
timestamps only for clients actually using the interleaved mode.

After commit 0ae6f2485b ("ntp: don't use first response in interleaved
mode") the first interleaved response following the two presend
responses in basic mode is dropped as the preferred set of timestamps
minimizing error in delay was already used by the second sample in
basic mode. There are only three responses in the burst and no sample is
accumulated.

Increasing the number of presend requests to three to get a fourth
sample would be wasteful. Instead, allow reusing timestamps of the
second presend sample in basic mode, which is never accumulated.

Reported-by: Aaron Thompson
Fixes: 0ae6f2485b ("ntp: don't use first response in interleaved mode")
2023-11-21 12:38:41 +01:00
Miroslav Lichvar
9c6eaccc32 nts: close reusable sockets in helper process
Close all reusable sockets when the NTS-KE server helper is forked. It
is not supposed to have access to any of the server sockets, just the
socket for getting requests from the main process and the syslog socket.
2023-11-21 12:38:41 +01:00
Miroslav Lichvar
0aa4d5ac14 socket: provide function for closing reusable sockets 2023-11-21 12:38:39 +01:00
Miroslav Lichvar
ee9d721b7b socket: set close-on-exec on all reusable sockets
Set the CLOEXEC flag on all reusable sockets in the initialization to
avoid leaking them to sendmail (mailonchange directive) in case the
chrony configuration doesn't use all sockets provided by systemd.
2023-11-20 13:33:45 +01:00
Luke Valenta
b6eec0068a doc: add FAQ section on minimizing service downtime 2023-11-13 17:05:46 +01:00
Luke Valenta
e6a0476eb7 socket: add support for systemd sockets
Before opening new IPv4/IPv6 server sockets, chronyd will check for
matching reusable sockets passed from the service manager (for example,
passed via systemd socket activation:
https://www.freedesktop.org/software/systemd/man/latest/sd_listen_fds.html)
and use those instead.

Aside from IPV6_V6ONLY (which cannot be set on already-bound sockets),
the daemon sets the same socket options on reusable sockets as it would
on sockets it opens itself.

Unit tests test the correct parsing of the LISTEN_FDS environment
variable.

Add 011-systemd system test to test socket activation for DGRAM and
STREAM sockets (both IPv4 and IPv6).  The tests use the
systemd-socket-activate test tool, which has some limitations requiring
workarounds discussed in inline comments.
2023-11-13 17:05:26 +01:00
Luke Valenta
c063b9e78a logging: move severity_chars to fix compiler warning 2023-11-08 15:09:03 +01:00
Luke Valenta
f6f1863fe2 logging: add log severity to file log prefix when debug is enabled 2023-11-07 15:43:57 +01:00
Miroslav Lichvar
51a621bc2b ntp: initialize network correction of transmitted packets
Initialize the unused value of network correction parsed from
own transmitted packets to avoid a use-of-uninitialized-value error
in NIO_UnwrapMessage() reported by clang.

Fixes: 6372a9f93f ("ntp: save PTP correction from NTP-over-PTP messages")
2023-11-02 12:53:00 +01:00
Luke Valenta
1488b31a38 doc: document '-L -1' option for debug logging output 2023-10-24 11:37:56 +02:00
Miroslav Lichvar
70cdd8b1ef ntp: add client support for network correction
If the network correction is known for both the request and response,
and their sum is not larger that the measured peer delay, allowing the
transparent clocks to be running up to 100 ppm faster than the client's
clock, apply the corrections to the NTP offset and peer delay. Don't
correct the root delay to not change the estimated maximum error.
2023-09-26 15:14:13 +02:00
Miroslav Lichvar
8eef631009 ntp: add server support for network correction
Provide the network correction (PTP correction + RX duration) of the
request in the new extension field if included in the request and
NTP-over-PTP is enabled.
2023-09-26 15:14:13 +02:00
Miroslav Lichvar
d9ae724c60 ntp: add extension field to provide network correction
To be able to verify PTP corrections, the client will need to know both
the correction of the request received by the server and the correction
of the response. Add a new experimental NTP extension field that the
clients will use to request the correction and servers return the
value.
2023-09-26 15:14:13 +02:00
Miroslav Lichvar
6372a9f93f ntp: save PTP correction from NTP-over-PTP messages
When the RX duration is known (HW timestamping), save the PTP correction
from received PTP messages in the local RX timestamp.
2023-09-26 15:14:13 +02:00
Miroslav Lichvar
b0267475e3 ntp: extend local timestamp for PTP correction
Add two new fields to the NTP_Local_Timestamp structure:
- receive duration as the time it takes to receive the ethernet frame,
  currently known only with HW timestamping
- network correction as a generalized PTP correction

The PTP correction is provided by transparent clocks in the correction
field of PTP messages to remove the receive, processing and queueing
delays of network switches and routers. Only one-step end-to-end unicast
transparent clocks are useful for NTP-over-PTP. Two-step transparent
clocks use follow-up messages and peer-to-peer transparent clocks don't
handle delay requests.

The RX duration will be included in the network correction to compensate
for asymmetric link speeds of the server and client as the NTP RX
timestamp corresponds to the end of the reception (in order to
compensate for the asymmetry in the normal case when no corrections
are applied).
2023-09-26 15:10:19 +02:00
Miroslav Lichvar
07134f2625 ntp: add function for detection of experimental fields 2023-09-26 15:03:33 +02:00
Miroslav Lichvar
85db8e3a9c ntp: assert size of exp_mono_root field 2023-09-26 15:02:06 +02:00
Miroslav Lichvar
05f4f79cbf ntp: rename exp1 extension field
Rename the exp1 extension field to exp_mono_root (monotonic timestamp +
root delay/dispersion) to better distinguish it from future experimental
extension fields.
2023-09-26 15:01:24 +02:00
Miroslav Lichvar
bf616eafa1 util: add conversion between intervals and NTP 64-bit format
This will be needed to save PTP correction in NTP timestamp format.
2023-09-26 15:00:06 +02:00
Miroslav Lichvar
e08a0ee668 doc: don't require same version for experimental features 2023-09-26 14:58:42 +02:00
Miroslav Lichvar
f2d7baa94f configure: prefer gnutls over nss and tomcrypt for hashing
Reorder the tests in the configure script to prefer gnutls over nss and
tomcrypt as its support includes AES-CMAC.
2023-09-12 10:36:23 +02:00
Miroslav Lichvar
558931524d configure: don't try AES-SIV-CMAC in nettle when disabled
Avoid confusing message when --without-nettle is specified.
2023-09-12 10:31:36 +02:00
Miroslav Lichvar
a74b63277a siv: add support for AES-GCM-SIV in gnutls
Add support for AES-128-GCM-SIV in the current development code of
gnutls. There doesn't seem to be an API to get the cipher's minimum and
maximum nonce length and it doesn't check for invalid lengths. Hardcode
and check the limits in chrony for now.
2023-09-12 10:31:36 +02:00
Miroslav Lichvar
aa8196328c conf: improve log message for failed additions in sources reload
Describe the error status in the log message when adding a source from
sourcedir failed.
2023-09-12 08:11:25 +02:00
Miroslav Lichvar
37deee7140 conf: cast subtraction operands in source comparison
Cast the values to int to not break the sorting in case they are changed
to unsigned types.
2023-09-12 08:03:23 +02:00
Miroslav Lichvar
7ff74d9efe conf: fix reloading modified sources specified by IP address
When reloading a modified source from sourcedir which is ordered before
the original source (e.g. maxpoll was decreased), the new source is
added before the original one is removed. If the source is specified by
IP address, the addition fails due to the conflict with the original
source. Sources specified by hostname don't conflict. They are resolved
later (repeatedly if the resolver provides only conflicting addresses).

Split the processing of sorted source lists into two phases, so all
modified sources are removed before they are added again to avoid the
conflict.

Reported-by: Thomas Lange <thomas@corelatus.se>
2023-09-12 08:02:36 +02:00
Miroslav Lichvar
43320a1d6b doc: update NEWS and README 2023-08-09 15:20:55 +02:00
Josef 'Jeff' Sipek
8caaa0b056 socket: enable nanosecond resolution RX timestamp on FreeBSD
FreeBSD allows switching the receive timestamp format to struct timespec by
setting the SO_TS_CLOCK socket option to SO_TS_REALTIME after enabling
SO_TIMESTAMP.  If successful, the kernel then starts adding SCM_REALTIME
control messages instead of SCM_TIMESTAMP.
2023-08-09 15:19:46 +02:00
Miroslav Lichvar
e48a34392c test: make 139-nts more reliable 2023-08-08 17:11:46 +02:00
Miroslav Lichvar
8bc8bf9cc4 test: make 114-presend more reliable
Avoid frequently ending in the middle of a client/server exchange with
long delays. This changed after commit 4a11399c2e ("ntp: rework
calculation of transmit timeout").
2023-08-08 16:24:10 +02:00
Miroslav Lichvar
3dc9f1ff92 ntp: don't require previous HW TX timestamp to wait for another
Clients sockets are closed immediately after receiving valid response.
Don't wait for the first early HW TX timestamp to enable waiting for
late timestamps. It may take a long time or never come if the HW/driver
is consistently slow. It's a chicken and egg problem.

Instead, simply check if HW timestamping is enabled on at least one
interface. Responses from NTP sources on other interfaces will always be
saved (for 1 millisecond by default).
2023-08-08 16:06:58 +02:00
Miroslav Lichvar
7bc7d00297 ntp: fix adding noselect to selection options
If noselect is present in the configured options, don't assume it
cannot change and the effective options are equal. This fixes chronyc
selectopts +noselect command.

Fixes: 3877734814 ("sources: add function to modify selection options")
2023-08-07 14:58:48 +02:00
Bryan Christianson
b5cf861cd7 contrib: replace tuxfamily with chrony-project
The chrony project has moved from tuxfamily.org to chrony-project.org.
Reflect these changes in the macOS startup files and documentation.
2023-08-01 12:11:27 +02:00
Miroslav Lichvar
25cc84d5e2 doc: update links to chrony website 2023-07-27 13:05:23 +02:00
Miroslav Lichvar
f74e4cf1fe doc: don't mention mailing lists in README
Current information about mailing lists is available on the project's
website.
2023-07-26 16:33:49 +02:00
Miroslav Lichvar
5f66722b66 update copyright years 2023-07-20 12:57:33 +02:00
Miroslav Lichvar
b31461af7a doc: add more questions to FAQ 2023-07-20 12:55:31 +02:00
Miroslav Lichvar
ae177f2742 doc: fix typo in FAQ 2023-07-20 12:47:11 +02:00
Miroslav Lichvar
1a736078df doc: refer to root distance in chronyc sources report 2023-07-20 12:46:49 +02:00
Miroslav Lichvar
9b46ea7255 test: make 132-logchange more reliable 2023-07-18 15:16:03 +02:00
Miroslav Lichvar
ff4e932f17 test: make 148-replacement more reliable 2023-07-18 15:15:45 +02:00
Miroslav Lichvar
68c35a0072 test: improve ntp_sources unit test 2023-07-18 14:53:54 +02:00
Miroslav Lichvar
b6c634298d ntp: handle negotiated NTS-KE server in refreshment
When refreshing a source, compare the newly resolved addresses with the
originally resolved address instead of the current address to avoid
unnecessary replacements when the address is changed due to the NTS-KE
server negotiation.
2023-07-18 14:53:54 +02:00
Miroslav Lichvar
010df12459 nts: fix log severity for loaded server keys 2023-07-18 14:53:54 +02:00
Miroslav Lichvar
22ef2fbb0e makefile: compile getdate.o with -fwrapv option
The getdate code (copied from gnulib before it was switched to GPLv3)
has multiple issues with signed integer overflows. Use the -fwrapv
compiler option for this object to at least make the operations defined.
2023-07-18 14:52:55 +02:00
57 changed files with 1363 additions and 395 deletions

View File

@@ -33,6 +33,8 @@ CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@ CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@ LDFLAGS = @LDFLAGS@
GETDATE_CFLAGS = @GETDATE_CFLAGS@
EXTRA_OBJS = @EXTRA_OBJS@ EXTRA_OBJS = @EXTRA_OBJS@
OBJS = array.o cmdparse.o conf.o local.o logging.o main.o memory.o quantiles.o \ OBJS = array.o cmdparse.o conf.o local.o logging.o main.o memory.o quantiles.o \
@@ -61,6 +63,8 @@ chronyd : $(OBJS)
chronyc : $(CLI_OBJS) chronyc : $(CLI_OBJS)
$(CC) $(CFLAGS) -o chronyc $(CLI_OBJS) $(LDFLAGS) $(LIBS) $(EXTRA_CLI_LIBS) $(CC) $(CFLAGS) -o chronyc $(CLI_OBJS) $(LDFLAGS) $(LIBS) $(EXTRA_CLI_LIBS)
getdate.o: CFLAGS += $(GETDATE_CFLAGS)
distclean : clean distclean : clean
$(MAKE) -C doc distclean $(MAKE) -C doc distclean
$(MAKE) -C test/unit distclean $(MAKE) -C test/unit distclean

15
NEWS
View File

@@ -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 New in version 4.4
================== ==================
@@ -14,6 +28,7 @@ Enhancements
* Improve source replacement * Improve source replacement
* Log important changes made by command requests (chronyc) * Log important changes made by command requests (chronyc)
* Refresh address of NTP sources periodically * Refresh address of NTP sources periodically
* Request nanosecond kernel RX timestamping on FreeBSD
* Set DSCP for IPv6 packets * Set DSCP for IPv6 packets
* Shorten NTS-KE retry interval when network is down * Shorten NTS-KE retry interval when network is down
* Update seccomp filter for musl * Update seccomp filter for musl

29
README
View File

@@ -47,32 +47,7 @@ Frequently Asked Questions (FAQ).
The documentation is also available on the chrony web pages, accessible The documentation is also available on the chrony web pages, accessible
through the URL through the URL
https://chrony.tuxfamily.org/ https://chrony-project.org/
Where are new versions announced?
=================================
There is a low volume mailing list where new versions and other
important news relating to chrony are announced. You can join this list
by sending mail with the subject "subscribe" to
chrony-announce-request@chrony.tuxfamily.org
How can I get support for chrony?
=================================
There are two other mailing lists relating to chrony. chrony-users is a
discussion list for users, e.g. for questions about chrony configuration
and bug reports. chrony-dev is a more technical list for developers,
e.g. for submitting patches and discussing how new features should be
implemented. To subscribe to either of these lists, send a message with
the subject "subscribe" to
chrony-users-request@chrony.tuxfamily.org
or
chrony-dev-request@chrony.tuxfamily.org
as applicable.
License License
======= =======
@@ -144,11 +119,13 @@ Gautier PHILIPPON <gautier.philippon@ensimag.grenoble-inp.fr>
Andreas Piesk <apiesk@virbus.de> Andreas Piesk <apiesk@virbus.de>
Mike Ryan <msr@hsilop.net> Mike Ryan <msr@hsilop.net>
Baruch Siach <baruch@tkos.co.il> Baruch Siach <baruch@tkos.co.il>
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
Foster Snowhill <forst@forstwoof.ru> Foster Snowhill <forst@forstwoof.ru>
Andreas Steinmetz <ast@domdv.de> Andreas Steinmetz <ast@domdv.de>
NAKAMURA Takumi <takumi@ps.sakura.ne.jp> NAKAMURA Takumi <takumi@ps.sakura.ne.jp>
Timo Teras <timo.teras@iki.fi> Timo Teras <timo.teras@iki.fi>
Bill Unruh <unruh@physics.ubc.ca> Bill Unruh <unruh@physics.ubc.ca>
Luke Valenta <lvalenta@cloudflare.com>
Stephen Wadeley <swadeley@redhat.com> Stephen Wadeley <swadeley@redhat.com>
Bernhard Weiss <lisnablagh@web.de> Bernhard Weiss <lisnablagh@web.de>
Wolfgang Weisselberg <weissel@netcologne.de> Wolfgang Weisselberg <weissel@netcologne.de>

View File

@@ -277,7 +277,8 @@ typedef struct {
#define REQ_ADDSRC_BURST 0x100 #define REQ_ADDSRC_BURST 0x100
#define REQ_ADDSRC_NTS 0x200 #define REQ_ADDSRC_NTS 0x200
#define REQ_ADDSRC_COPY 0x400 #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 { typedef struct {
uint32_t type; uint32_t type;

View File

@@ -4,7 +4,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Lonnie Abelbeck 2016, 2018 * Copyright (C) Lonnie Abelbeck 2016, 2018
* Copyright (C) Miroslav Lichvar 2009-2021 * Copyright (C) Miroslav Lichvar 2009-2023
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of version 2 of the GNU General Public License as
@@ -958,7 +958,10 @@ process_cmd_add_source(CMD_Request *msg, char *line)
(data.params.burst ? REQ_ADDSRC_BURST : 0) | (data.params.burst ? REQ_ADDSRC_BURST : 0) |
(data.params.nts ? REQ_ADDSRC_NTS : 0) | (data.params.nts ? REQ_ADDSRC_NTS : 0) |
(data.params.copy ? REQ_ADDSRC_COPY : 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)); convert_addsrc_sel_options(data.params.sel_options));
msg->data.ntp_source.filter_length = htonl(data.params.filter_length); msg->data.ntp_source.filter_length = htonl(data.params.filter_length);
msg->data.ntp_source.cert_set = htonl(data.params.cert_set); msg->data.ntp_source.cert_set = htonl(data.params.cert_set);
@@ -3380,7 +3383,7 @@ static void
display_gpl(void) display_gpl(void)
{ {
printf("chrony version %s\n" printf("chrony version %s\n"
"Copyright (C) 1997-2003, 2007, 2009-2022 Richard P. Curnow and others\n" "Copyright (C) 1997-2003, 2007, 2009-2023 Richard P. Curnow and others\n"
"chrony comes with ABSOLUTELY NO WARRANTY. This is free software, and\n" "chrony comes with ABSOLUTELY NO WARRANTY. This is free software, and\n"
"you are welcome to redistribute it under certain conditions. See the\n" "you are welcome to redistribute it under certain conditions. See the\n"
"GNU General Public License version 2 for details.\n\n", "GNU General Public License version 2 for details.\n\n",

View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2016, 2018-2021 * Copyright (C) Miroslav Lichvar 2009-2016, 2018-2023
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of version 2 of the GNU General Public License as
@@ -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.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.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.copy = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_COPY ? 1 : 0;
params.ext_fields = params.ext_fields = (ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_EF_EXP_MONO_ROOT ?
ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_EF_EXP1 ? NTP_EF_FLAG_EXP1 : 0; 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)); params.sel_options = convert_addsrc_select_options(ntohl(rx_message->data.ntp_source.flags));
status = NSR_AddSourceByName(name, port, pool, type, &params, NULL); status = NSR_AddSourceByName(name, port, pool, type, &params, NULL);

View File

@@ -115,8 +115,11 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
if (sscanf(line, "%"SCNx32"%n", &ef_type, &n) != 1) if (sscanf(line, "%"SCNx32"%n", &ef_type, &n) != 1)
return 0; return 0;
switch (ef_type) { switch (ef_type) {
case NTP_EF_EXP1: case NTP_EF_EXP_MONO_ROOT:
src->params.ext_fields |= NTP_EF_FLAG_EXP1; 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; break;
default: default:
return 0; return 0;

34
conf.c
View File

@@ -1660,11 +1660,11 @@ compare_sources(const void *a, const void *b)
return 1; return 1;
if ((d = strcmp(sa->params.name, sb->params.name)) != 0) if ((d = strcmp(sa->params.name, sb->params.name)) != 0)
return d; return d;
if ((d = (int)(sa->type) - (int)(sb->type)) != 0) if ((d = (int)sa->type - (int)sb->type) != 0)
return d; return d;
if ((d = sa->pool - sb->pool) != 0) if ((d = (int)sa->pool - (int)sb->pool) != 0)
return d; 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 d;
return memcmp(&sa->params.params, &sb->params.params, sizeof (sa->params.params)); 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; uint32_t *prev_ids, *new_ids;
char buf[MAX_LINE_LENGTH]; char buf[MAX_LINE_LENGTH];
NSR_Status s; NSR_Status s;
int d; int d, pass;
prev_size = ARR_GetSize(ntp_source_ids); prev_size = ARR_GetSize(ntp_source_ids);
if (prev_size > 0 && ARR_GetSize(ntp_sources) != prev_size) if (prev_size > 0 && ARR_GetSize(ntp_sources) != prev_size)
@@ -1713,19 +1713,20 @@ reload_source_dirs(void)
qsort(new_sources, new_size, sizeof (new_sources[0]), compare_sources); qsort(new_sources, new_size, sizeof (new_sources[0]), compare_sources);
for (i = j = 0; i < prev_size || j < new_size; ) { 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) if (i < prev_size && j < new_size)
d = compare_sources(&prev_sources[i], &new_sources[j]); d = compare_sources(&prev_sources[i], &new_sources[j]);
else else
d = i < prev_size ? -1 : 1; d = i < prev_size ? -1 : 1;
if (d < 0) { /* Remove missing sources before adding others to avoid conflicts */
/* Remove the missing source */ if (pass == 0 && d < 0 && prev_sources[i].params.name[0] != '\0') {
if (prev_sources[i].params.name[0] != '\0')
NSR_RemoveSourcesById(prev_ids[i]); NSR_RemoveSourcesById(prev_ids[i]);
i++; }
} else if (d > 0) {
/* Add a newly configured source */ /* Add new sources */
if (pass == 1 && d > 0) {
source = &new_sources[j]; source = &new_sources[j];
s = NSR_AddSourceByName(source->params.name, source->params.port, source->pool, s = NSR_AddSourceByName(source->params.name, source->params.port, source->pool,
source->type, &source->params.params, &new_ids[j]); source->type, &source->params.params, &new_ids[j]);
@@ -1733,16 +1734,17 @@ reload_source_dirs(void)
if (s == NSR_UnresolvedName) { if (s == NSR_UnresolvedName) {
unresolved++; unresolved++;
} else if (s != NSR_Success) { } else if (s != NSR_Success) {
LOG(LOGS_ERR, "Could not add source %s", source->params.name); LOG(LOGS_ERR, "Could not add source %s : %s",
source->params.name, NSR_StatusToString(s));
/* Mark the source as not present */ /* Mark the source as not present */
source->params.name[0] = '\0'; source->params.name[0] = '\0';
} }
j++; }
} else {
/* Keep the existing source */ /* Keep unchanged sources */
if (pass == 1 && d == 0)
new_ids[j] = prev_ids[i]; new_ids[j] = prev_ids[i];
i++, j++;
} }
} }

65
configure vendored
View File

@@ -5,7 +5,7 @@
# #
# Copyright (C) Richard P. Curnow 1997-2003 # Copyright (C) Richard P. Curnow 1997-2003
# Copyright (C) Bryan Christianson 2016 # Copyright (C) Bryan Christianson 2016
# Copyright (C) Miroslav Lichvar 2009, 2012-2021 # Copyright (C) Miroslav Lichvar 2009, 2012-2022
# Copyright (C) Stefan R. Filipek 2019 # Copyright (C) Stefan R. Filipek 2019
# #
# ======================================================================= # =======================================================================
@@ -111,10 +111,10 @@ For better control, use the options below.
--without-editline Don't use editline even if it is available --without-editline Don't use editline even if it is available
--disable-sechash Disable support for hashes other than MD5 --disable-sechash Disable support for hashes other than MD5
--without-nettle Don't use nettle even if it is available --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-nss Don't use NSS even if it is available
--without-tomcrypt Don't use libtomcrypt even if it is available --without-tomcrypt Don't use libtomcrypt even if it is available
--disable-nts Disable NTS support --disable-nts Disable NTS support
--without-gnutls Don't use gnutls even if it is available
--disable-cmdmon Disable command and monitoring support --disable-cmdmon Disable command and monitoring support
--disable-ntp Disable NTP support --disable-ntp Disable NTP support
--disable-refclock Disable reference clock support --disable-refclock Disable reference clock support
@@ -570,6 +570,13 @@ if [ "x$MYCFLAGS" = "x" ]; then
fi fi
fi fi
TESTCFLAGS="-fwrapv"
if test_code '-fwrapv' '' "$TESTCFLAGS" '' ''; then
GETDATE_CFLAGS="-fwrapv"
else
GETDATE_CFLAGS=""
fi
if [ "x$MYCC" = "xgcc" ] || [ "x$MYCC" = "xclang" ]; then if [ "x$MYCC" = "xgcc" ] || [ "x$MYCC" = "xclang" ]; then
MYCFLAGS="$MYCFLAGS -Wmissing-prototypes -Wall" MYCFLAGS="$MYCFLAGS -Wmissing-prototypes -Wall"
fi fi
@@ -919,6 +926,28 @@ if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_nettle = "1" ];
fi fi
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 if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_nss = "1" ]; then
test_cflags="`pkg_config --cflags nss`" test_cflags="`pkg_config --cflags nss`"
test_link="`pkg_config --libs-only-L nss` -lfreebl3 -lnssutil3" test_link="`pkg_config --libs-only-L nss` -lfreebl3 -lnssutil3"
@@ -944,28 +973,6 @@ if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_tomcrypt = "1" ]
fi fi
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_OBJECTS="$EXTRA_OBJECTS $HASH_OBJ"
EXTRA_CLI_OBJECTS="$EXTRA_CLI_OBJECTS $HASH_OBJ" EXTRA_CLI_OBJECTS="$EXTRA_CLI_OBJECTS $HASH_OBJ"
LIBS="$LIBS $HASH_LINK" LIBS="$LIBS $HASH_LINK"
@@ -984,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_priority_init2((void *)1, "", NULL, GNUTLS_PRIORITY_INIT_DEF_APPEND) +
gnutls_prf_rfc5705((void *)1, 0, "", 0, "", 16, (void *)2);' gnutls_prf_rfc5705((void *)1, 0, "", 0, "", 16, (void *)2);'
then 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" \ 'nettle/siv-cmac.h' "" "$LIBS" \
'siv_cmac_aes128_set_key((void *)1, (void *)2);' 'siv_cmac_aes128_set_key((void *)1, (void *)2);'
then then
@@ -1005,6 +1012,13 @@ if [ $feat_ntp = "1" ] && [ $feat_nts = "1" ] && [ $try_gnutls = "1" ]; then
then then
EXTRA_OBJECTS="$EXTRA_OBJECTS siv_gnutls.o" EXTRA_OBJECTS="$EXTRA_OBJECTS siv_gnutls.o"
add_def HAVE_SIV 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' \ if test_code 'gnutls_aead_cipher_set_key()' 'gnutls/crypto.h' \
"$test_cflags" "$test_link $LIBS" ' "$test_cflags" "$test_link $LIBS" '
return gnutls_aead_cipher_set_key((void *)1, (void *)2);' return gnutls_aead_cipher_set_key((void *)1, (void *)2);'
@@ -1122,6 +1136,7 @@ do
s%@CFLAGS@%${MYCFLAGS}%;\ s%@CFLAGS@%${MYCFLAGS}%;\
s%@CPPFLAGS@%${MYCPPFLAGS}%;\ s%@CPPFLAGS@%${MYCPPFLAGS}%;\
s%@LDFLAGS@%${MYLDFLAGS}%;\ s%@LDFLAGS@%${MYLDFLAGS}%;\
s%@GETDATE_CFLAGS@%${GETDATE_CFLAGS}%;\
s%@LIBS@%${LIBS}%;\ s%@LIBS@%${LIBS}%;\
s%@EXTRA_LIBS@%${EXTRA_LIBS}%;\ s%@EXTRA_LIBS@%${EXTRA_LIBS}%;\
s%@EXTRA_CLI_LIBS@%${EXTRA_CLI_LIBS}%;\ s%@EXTRA_CLI_LIBS@%${EXTRA_CLI_LIBS}%;\

View File

@@ -60,8 +60,8 @@ Support files
Dates and sizes may differ Dates and sizes may differ
-rw-r--r-- 1 yourname staff 2084 4 Aug 22:54 README.txt -rw-r--r-- 1 yourname staff 2084 4 Aug 22:54 README.txt
-rwxr-xr-x 1 yourname staff 676 4 Aug 21:18 chronylogrotate.sh -rwxr-xr-x 1 yourname staff 676 4 Aug 21:18 chronylogrotate.sh
-rw-r--r-- 1 yourname staff 543 18 Jul 20:10 org.tuxfamily.chronyc.plist -rw-r--r-- 1 yourname staff 543 18 Jul 20:10 org.chrony-project.chronyc.plist
-rw-r--r-- 1 yourname staff 511 19 Jun 18:30 org.tuxfamily.chronyd.plist -rw-r--r-- 1 yourname staff 511 19 Jun 18:30 org.chrony-project.chronyd.plist
If you have used chrony support directories other than those suggested, you If you have used chrony support directories other than those suggested, you
will need to edit each file and make the appropriate changes. will need to edit each file and make the appropriate changes.
@@ -83,21 +83,21 @@ sudo chmod +x /usr/local/bin/chronylogrotate.sh
sudo chown root:wheel /usr/local/bin/chronylogrotate.sh sudo chown root:wheel /usr/local/bin/chronylogrotate.sh
2. org.tuxfamily.chronyc.plist 2. org.chrony-project.chronyc.plist
This file is the launchd plist that runs logrotation each day. You may This file is the launchd plist that runs logrotation each day. You may
wish to edit this file to change the time of day at which the rotation wish to edit this file to change the time of day at which the rotation
will run, currently 04:05 am will run, currently 04:05 am
sudo cp org.tuxfamily.chronyc.plist /Library/LaunchDaemons sudo cp org.chrony-project.chronyc.plist /Library/LaunchDaemons
sudo chown root:wheel /Library/LaunchDaemons/org.tuxfamily.chronyc.plist sudo chown root:wheel /Library/LaunchDaemons/org.chrony-project.chronyc.plist
sudo chmod 0644 /Library/LaunchDaemons/org.tuxfamily.chronyc.plist sudo chmod 0644 /Library/LaunchDaemons/org.chrony-project.chronyc.plist
sudo launchctl load -w /Library/LaunchDaemons/org.tuxfamily.chronyc.plist sudo launchctl load -w /Library/LaunchDaemons/org.chrony-project.chronyc.plist
3. org.tuxfamily.chronyd.plist 3. org.chrony-project.chronyd.plist
This file is the launchd plist that runs chronyd when the Macintosh starts. This file is the launchd plist that runs chronyd when the Macintosh starts.
sudo cp org.tuxfamily.chronyd.plist /Library/LaunchDaemons sudo cp org.chrony-project.chronyd.plist /Library/LaunchDaemons
sudo chown root:wheel /Library/LaunchDaemons/org.tuxfamily.chronyd.plist sudo chown root:wheel /Library/LaunchDaemons/org.chrony-project.chronyd.plist
sudo chmod 0644 /Library/LaunchDaemons/org.tuxfamily.chronyd.plist sudo chmod 0644 /Library/LaunchDaemons/org.chrony-project.chronyd.plist
sudo launchctl load -w /Library/LaunchDaemons/org.tuxfamily.chronyd.plist sudo launchctl load -w /Library/LaunchDaemons/org.chrony-project.chronyd.plist

View File

@@ -3,7 +3,7 @@
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>Label</key> <key>Label</key>
<string>org.tuxfamily.logrotate</string> <string>org.chrony-project.logrotate</string>
<key>KeepAlive</key> <key>KeepAlive</key>
<false/> <false/>
<key>ProgramArguments</key> <key>ProgramArguments</key>

View File

@@ -3,7 +3,7 @@
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>Label</key> <key>Label</key>
<string>org.tuxfamily.chronyd</string> <string>org.chrony-project.chronyd</string>
<key>Program</key> <key>Program</key>
<string>/usr/local/sbin/chronyd</string> <string>/usr/local/sbin/chronyd</string>
<key>ProgramArguments</key> <key>ProgramArguments</key>

View File

@@ -3,7 +3,7 @@
// Copyright (C) Richard P. Curnow 1997-2003 // Copyright (C) Richard P. Curnow 1997-2003
// Copyright (C) Stephen Wadeley 2016 // Copyright (C) Stephen Wadeley 2016
// Copyright (C) Bryan Christianson 2017 // Copyright (C) Bryan Christianson 2017
// Copyright (C) Miroslav Lichvar 2009-2022 // Copyright (C) Miroslav Lichvar 2009-2023
// //
// This program is free software; you can redistribute it and/or modify // 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 // it under the terms of version 2 of the GNU General Public License as
@@ -322,16 +322,25 @@ server implementations do not respond to requests containing an unknown
extension field (*chronyd* as a server responded to such requests since extension field (*chronyd* as a server responded to such requests since
version 2.0). 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_:::: _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 proposed for the next version of the NTP protocol (NTPv5). The field contains
root delay and dispersion in higher resolution and a monotonic receive root delay and dispersion in higher resolution and a monotonic receive
timestamp, which enables a frequency transfer between the server and client. It timestamp, which enables a frequency transfer between the server and client to
can significantly improve stability of the synchronization. Generally, it significantly improve stability of the synchronisation. This field should be
should be expected to work only between servers and clients running the same enabled only for servers known to be running *chronyd* version 4.2 or later.
version of *chronyd*. _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. This field should be enabled only for servers known to be running
*chronyd* version 4.5 or later.
{blank}::: {blank}:::
[[pool]]*pool* _name_ [_option_]...:: [[pool]]*pool* _name_ [_option_]...::
@@ -418,7 +427,7 @@ error. *chronyd* then enters its normal operating mode.
An example of the use of the directive is: 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 where 3 NTP servers are used to make the measurement. The _30_ indicates that
@@ -833,9 +842,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. refresh the keys on each poll and no NTP packets will be exchanged.
[[ntstrustedcerts]]*ntstrustedcerts* [_set-ID_] _file_|_directory_:: [[ntstrustedcerts]]*ntstrustedcerts* [_set-ID_] _file_|_directory_::
This directive specifies a file or directory containing certificates (in the This directive specifies a file or directory containing trusted certificates
PEM format) of trusted certificate authorities (CA) which can be used to (in the PEM format) which are needed to verify certificates of NTS-KE servers,
verify certificates of NTS 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 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 selects the set of certificates where certificates from the specified file
@@ -855,10 +865,10 @@ they change (e.g. after a renewal).
An example is: An example is:
+ +
---- ----
ntstrustedcerts /etc/pki/nts/foo.crt ntstrustedcerts /etc/pki/nts/ca1.example.net.crt
ntstrustedcerts 1 /etc/pki/nts/bar.crt ntstrustedcerts 1 /etc/pki/nts/ca2.example.net.crt
ntstrustedcerts 1 /etc/pki/nts/baz.crt ntstrustedcerts 1 /etc/pki/nts/ca3.example.net.crt
ntstrustedcerts 2 /etc/pki/nts/qux.crt ntstrustedcerts 2 /etc/pki/nts/ntp2.example.net.crt
---- ----
[[nosystemcert]]*nosystemcert*:: [[nosystemcert]]*nosystemcert*::
@@ -955,9 +965,9 @@ before 4.0.
As an example, the following configuration using the default *mix* mode: As an example, the following configuration using the default *mix* mode:
+ +
---- ----
server foo.example.net nts server ntp1.example.net nts
server bar.example.net nts server ntp2.example.net nts
server baz.example.net server ntp3.example.net
refclock SOCK /var/run/chrony.ttyS0.sock refclock SOCK /var/run/chrony.ttyS0.sock
---- ----
+ +
@@ -965,9 +975,9 @@ is equivalent to the following configuration using the *ignore* mode:
+ +
---- ----
authselectmode ignore authselectmode ignore
server foo.example.net nts require trust server ntp1.example.net nts require trust
server bar.example.net nts require trust server ntp2.example.net nts require trust
server baz.example.net server ntp3.example.net
refclock /var/run/chrony.ttyS0.sock require trust refclock /var/run/chrony.ttyS0.sock require trust
---- ----
@@ -1976,8 +1986,9 @@ all* directive.
[[cmdport]]*cmdport* _port_:: [[cmdport]]*cmdport* _port_::
The *cmdport* directive allows the port that is used for run-time monitoring 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, (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* *chronyd* will not open the port, which disables remote *chronyc* access (with
access from the Internet. (It does not disable the Unix domain command socket.) a non-default *bindcmdaddress*) and local access for unprivileged users. It
does not disable the Unix domain command socket.
+ +
An example shows the syntax: An example shows the syntax:
+ +
@@ -1986,7 +1997,7 @@ cmdport 257
---- ----
+ +
This would make *chronyd* use UDP 257 as its command port. (*chronyc* would 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_]...:: [[cmdratelimit]]*cmdratelimit* [_option_]...::
This directive enables response rate limiting for command packets. It is This directive enables response rate limiting for command packets. It is
@@ -2728,24 +2739,27 @@ pidfile /run/chronyd.pid
The *ptpport* directive enables *chronyd* to send and receive NTP messages The *ptpport* directive enables *chronyd* to send and receive NTP messages
contained in PTP event messages (NTP-over-PTP) to enable hardware timestamping contained in PTP event messages (NTP-over-PTP) to enable hardware timestamping
on NICs which cannot timestamp NTP packets, but can timestamp unicast PTP 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 packets, and also use corrections provided by PTP one-step end-to-end
value is 0 (disabled). 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 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 change in future. It should be used only in local networks.
only between servers and clients running the same version of *chronyd*.
+ +
The PTP port will be open even if *chronyd* is not configured to operate as a 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 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 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 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 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: 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 hwtimestamp * rxfilter ptp
ptpport 319 ptpport 319
---- ----
@@ -2806,13 +2820,13 @@ the following methods:
facilities. facilities.
* Use public servers from the https://www.pool.ntp.org/[pool.ntp.org] project. * 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_ Assuming that your NTP servers are called _ntp1.example.net_, _ntp2.example.net_
and _baz.example.net_, your _chrony.conf_ file could contain as a minimum: and _ntp3.example.net_, your _chrony.conf_ file could contain as a minimum:
---- ----
server foo.example.net server ntp1.example.net
server bar.example.net server ntp2.example.net
server baz.example.net server ntp3.example.net
---- ----
However, you will probably want to include some of the other directives. The However, you will probably want to include some of the other directives. The
@@ -2823,9 +2837,9 @@ synchronisation. The smallest useful configuration file would look something
like: like:
---- ----
server foo.example.net iburst server ntp1.example.net iburst
server bar.example.net iburst server ntp2.example.net iburst
server baz.example.net iburst server ntp3.example.net iburst
driftfile @CHRONYVARDIR@/drift driftfile @CHRONYVARDIR@/drift
makestep 1.0 3 makestep 1.0 3
rtcsync rtcsync
@@ -2849,9 +2863,9 @@ option will enable a secure synchronisation to the servers. The configuration
file could look like: file could look like:
---- ----
server foo.example.net iburst nts server ntp1.example.net iburst nts
server bar.example.net iburst nts server ntp2.example.net iburst nts
server baz.example.net iburst nts server ntp3.example.net iburst nts
driftfile @CHRONYVARDIR@/drift driftfile @CHRONYVARDIR@/drift
makestep 1.0 3 makestep 1.0 3
rtcsync rtcsync
@@ -2865,14 +2879,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 down. This saves the program from continuously trying to poll the servers when
they are inaccessible. they are inaccessible.
Again, assuming that your NTP servers are called _foo.example.net_, Again, assuming that your NTP servers are called _ntp1.example.net_,
_bar.example.net_ and _baz.example.net_, your _chrony.conf_ file would now _ntp2.example.net_ and _ntp3.example.net_, your _chrony.conf_ file would now
contain: contain:
---- ----
server foo.example.net offline server ntp1.example.net offline
server bar.example.net offline server ntp2.example.net offline
server baz.example.net offline server ntp3.example.net offline
driftfile @CHRONYVARDIR@/drift driftfile @CHRONYVARDIR@/drift
makestep 1.0 3 makestep 1.0 3
rtcsync rtcsync
@@ -3056,9 +3070,9 @@ configuration files are shown.
For the _chrony.conf_ file, the following can be used as an example. For the _chrony.conf_ file, the following can be used as an example.
---- ----
server foo.example.net maxdelay 0.4 offline server ntp1.example.net maxdelay 0.4 offline
server bar.example.net maxdelay 0.4 offline server ntp2.example.net maxdelay 0.4 offline
server baz.example.net maxdelay 0.4 offline server ntp3.example.net maxdelay 0.4 offline
logdir /var/log/chrony logdir /var/log/chrony
log statistics measurements tracking log statistics measurements tracking
driftfile @CHRONYVARDIR@/drift driftfile @CHRONYVARDIR@/drift
@@ -3117,10 +3131,10 @@ configuration).
The configuration file could look like: The configuration file could look like:
---- ----
server foo.example.net iburst server ntp1.example.net iburst
server bar.example.net iburst server ntp2.example.net iburst
server baz.example.net iburst server ntp3.example.net iburst
server qux.example.net iburst server ntp4.example.net iburst
makestep 1.0 3 makestep 1.0 3
rtcsync rtcsync
allow allow
@@ -3137,7 +3151,7 @@ dumpdir @CHRONYRUNDIR@
== BUGS == BUGS
For instructions on how to report bugs, please visit For instructions on how to report bugs, please visit
https://chrony.tuxfamily.org/. https://chrony-project.org/.
== AUTHORS == AUTHORS

View File

@@ -2,7 +2,7 @@
// //
// Copyright (C) Richard P. Curnow 1997-2003 // Copyright (C) Richard P. Curnow 1997-2003
// Copyright (C) Stephen Wadeley 2016 // Copyright (C) Stephen Wadeley 2016
// Copyright (C) Miroslav Lichvar 2009-2017, 2019-2022 // Copyright (C) Miroslav Lichvar 2009-2017, 2019-2023
// //
// This program is free software; you can redistribute it and/or modify // 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 // it under the terms of version 2 of the GNU General Public License as
@@ -144,7 +144,7 @@ The *tracking* command displays parameters about the system's clock
performance. An example of the output is shown below. performance. An example of the output is shown below.
+ +
---- ----
Reference ID : CB00710F (foo.example.net) Reference ID : CB00710F (ntp1.example.net)
Stratum : 3 Stratum : 3
Ref time (UTC) : Fri Jan 27 09:49:17 2017 Ref time (UTC) : Fri Jan 27 09:49:17 2017
System time : 0.000006523 seconds slow of NTP time System time : 0.000006523 seconds slow of NTP time
@@ -178,7 +178,7 @@ with an IPv4 address.
*Stratum*::: *Stratum*:::
The stratum indicates how many hops away from a computer with an attached 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 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). stratum-2 and is synchronised from a stratum-1).
*Ref time*::: *Ref time*:::
This is the time (UTC) at which the last measurement from the reference 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 MS Name/IP address Stratum Poll Reach LastRx Last sample
=============================================================================== ===============================================================================
#* GPS0 0 4 377 11 -479ns[ -621ns] +/- 134ns #* GPS0 0 4 377 11 -479ns[ -621ns] +/- 134ns
^? foo.example.net 2 6 377 23 -923us[ -924us] +/- 43ms ^? ntp1.example.net 2 6 377 23 -923us[ -924us] +/- 43ms
^+ bar.example.net 1 6 377 21 -2629us[-2619us] +/- 86ms ^+ ntp2.example.net 1 6 377 21 -2629us[-2619us] +/- 86ms
---- ----
+ +
The columns are as follows: The columns are as follows:
@@ -379,9 +379,9 @@ offset. This can be suffixed by _ns_ (indicating nanoseconds), _us_
(indicating microseconds), _ms_ (indicating milliseconds), or _s_ (indicating (indicating microseconds), _ms_ (indicating milliseconds), or _s_ (indicating
seconds). The number to the left of the square brackets shows the original seconds). The number to the left of the square brackets shows the original
measurement, adjusted to allow for any slews applied to the local clock measurement, adjusted to allow for any slews applied to the local clock
since. The number following the _+/-_ indicator shows the margin of error in since. Positive offsets indicate that the local clock is ahead of the source.
the measurement. Positive offsets indicate that the local clock is ahead of The number following the _+/-_ indicator shows the margin of error in the
the source. measurement (NTP root distance).
[[sourcestats]]*sourcestats* [*-a*] [*-v*]:: [[sourcestats]]*sourcestats* [*-a*] [*-v*]::
The *sourcestats* command displays information about the drift rate and offset The *sourcestats* command displays information about the drift rate and offset
@@ -400,7 +400,7 @@ An example report is:
---- ----
Name/IP Address NP NR Span Frequency Freq Skew Offset Std Dev 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: 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 S Name/IP Address Auth COpts EOpts Last Score Interval Leap
======================================================================= =======================================================================
D foo.example.net Y ----- --TR- 4 1.0 -61ms +62ms N D ntp1.example.net Y ----- --TR- 4 1.0 -61ms +62ms N
* bar.example.net N ----- ----- 0 1.0 -6846us +7305us N * ntp2.example.net N ----- ----- 0 1.0 -6846us +7305us N
+ baz.example.net N ----- ----- 10 1.0 -7381us +7355us N + ntp3.example.net N ----- ----- 10 1.0 -7381us +7355us N
---- ----
+ +
The columns are as follows: The columns are as follows:
@@ -592,9 +592,9 @@ shown below.
---- ----
Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen
========================================================================= =========================================================================
foo.example.net NTS 1 15 256 135m 0 0 8 100 ntp1.example.net NTS 1 15 256 135m 0 0 8 100
bar.example.net SK 30 13 128 - 0 0 0 0 ntp2.example.net SK 30 13 128 - 0 0 0 0
baz.example.net - 0 0 0 - 0 0 0 0 ntp3.example.net - 0 0 0 - 0 0 0 0
---- ----
+ +
The columns are as follows: 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. 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_]...:: [[add_pool]]*add pool* _name_ [_option_]...::
@@ -772,7 +772,7 @@ directive in the configuration file.
An example of using this command is shown below: 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_]...:: [[add_server]]*add server* _name_ [_option_]...::
@@ -786,7 +786,7 @@ directive in the configuration file.
An example of using this command is shown below: 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_:: [[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: 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_:: [[maxdelay]]*maxdelay* _address_ _delay_::
@@ -928,7 +928,7 @@ uses an IP address or a hostname. These forms are illustrated below.
offline offline
offline 255.255.255.0/1.2.3.0 offline 255.255.255.0/1.2.3.0
offline 2001:db8:789a::/48 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 The second form means that the *offline* command is to be applied to any source
@@ -1094,7 +1094,7 @@ particular host.
Examples of use, showing a named host and a numeric IP address, are as follows: 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 1.2.3.4
accheck 2001:db8::1 accheck 2001:db8::1
---- ----
@@ -1121,7 +1121,7 @@ An example of the output is:
Hostname NTP Drop Int IntL Last Cmd Drop Int Last Hostname NTP Drop Int IntL Last Cmd Drop Int Last
=============================================================================== ===============================================================================
localhost 2 0 2 - 133 15 0 -1 7 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 Each row shows the data for a single host. Only hosts that have passed the host
@@ -1321,7 +1321,7 @@ used to check whether monitoring access is permitted from a named host.
Examples of use are as follows: Examples of use are as follows:
+ +
---- ----
cmdaccheck foo.example.net cmdaccheck ntp1.example.net
cmdaccheck 1.2.3.4 cmdaccheck 1.2.3.4
cmdaccheck 2001:db8::1 cmdaccheck 2001:db8::1
---- ----
@@ -1548,7 +1548,7 @@ The *help* command displays a summary of the commands and their arguments.
== BUGS == BUGS
For instructions on how to report bugs, please visit For instructions on how to report bugs, please visit
https://chrony.tuxfamily.org/. https://chrony-project.org/.
== AUTHORS == AUTHORS

View File

@@ -72,9 +72,9 @@ terminal.
*-L* _level_:: *-L* _level_::
This option specifies the minimum severity level of messages to be written to 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: the log file, syslog, or terminal. The following levels can be specified: -1
0 (informational), 1 (warning), 2 (non-fatal error), and 3 (fatal error). The (debug, if compiled with enabled support for debugging), 0 (informational), 1
default value is 0. (warning), 2 (non-fatal error), and 3 (fatal error). The default value is 0.
*-p*:: *-p*::
When run in this mode, *chronyd* will print the configuration and exit. It will 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*:: *-h*, *--help*::
With this option *chronyd* will print a help message to the terminal and exit. 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 == FILES
_@SYSCONFDIR@/chrony.conf_ _@SYSCONFDIR@/chrony.conf_
@@ -217,7 +228,7 @@ _@SYSCONFDIR@/chrony.conf_
== BUGS == BUGS
For instructions on how to report bugs, please visit For instructions on how to report bugs, please visit
https://chrony.tuxfamily.org/. https://chrony-project.org/.
== AUTHORS == AUTHORS

View File

@@ -1,7 +1,7 @@
// This file is part of chrony // This file is part of chrony
// //
// Copyright (C) Richard P. Curnow 1997-2003 // Copyright (C) Richard P. Curnow 1997-2003
// Copyright (C) Miroslav Lichvar 2014-2016, 2020-2022 // Copyright (C) Miroslav Lichvar 2014-2016, 2020-2023
// //
// This program is free software; you can redistribute it and/or modify // 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 // it under the terms of version 2 of the GNU General Public License as
@@ -40,9 +40,36 @@ on an isolated network with no hardware reference clocks in sight, `chrony`
will probably work better for you. will probably work better for you.
For a more detailed comparison of features and performance, see the For a more detailed comparison of features and performance, see the
https://chrony.tuxfamily.org/comparison.html[comparison page] on the `chrony` https://chrony-project.org/comparison.html[comparison page] on the `chrony`
website. website.
=== Should I prefer `chrony` over `timesyncd` if I do not need to run a server?
Generally, yes.
`systemd-timesyncd` is a very simple NTP client included in the `systemd`
suite. It lacks almost all features of `chrony` and other advanced client
implementations listed on the
https://chrony-project.org/comparison.html[comparison page]. One of its main
limitations is that it cannot poll multiple servers at the same time and detect
servers having incorrect time (falsetickers in the NTP terminology). It should
be used only with trusted reliable servers, ideally in local network.
Using `timesyncd` with `pool.ntp.org` is problematic. The pool is very
robust as a whole, but the individual servers run by volunteers cannot be
relied on. Occasionally, servers drift away or make a step to distant past or
future due to misconfiguration, problematic implementation, and other bugs
(e.g. in firmware of a GPS receiver). The pool monitoring system detects such
servers and quickly removes them from the pool DNS, but clients like
`timesyncd` cannot recover from that. They follow the server as long as it
claims to be synchronised. They need to be restarted in order to get a new
address from the pool DNS.
Note that the complexity of NTP and clock synchronisation is on the client
side. The amount of code in `chrony` specific to NTP server is very small and
it is disabled by default. If it was removed, it would not significantly reduce
the amount of memory or storage needed.
== Configuration issues == Configuration issues
=== What is the minimum recommended configuration for an NTP client? === What is the minimum recommended configuration for an NTP client?
@@ -238,11 +265,11 @@ An example of a client configuration limiting the impact of the attacks could
be be
---- ----
server foo.example.net iburst nts maxdelay 0.1 server ntp1.example.net iburst nts maxdelay 0.1
server bar.example.net iburst nts maxdelay 0.2 server ntp2.example.net iburst nts maxdelay 0.2
server baz.example.net iburst nts maxdelay 0.05 server ntp3.example.net iburst nts maxdelay 0.05
server qux.example.net iburst nts maxdelay 0.1 server ntp4.example.net iburst nts maxdelay 0.1
server quux.example.net iburst nts maxdelay 0.1 server ntp5.example.net iburst nts maxdelay 0.1
minsources 3 minsources 3
maxchange 100 0 0 maxchange 100 0 0
makestep 0.001 1 makestep 0.001 1
@@ -291,7 +318,7 @@ An example of the directive for an NTP server on the Internet that you are
allowed to poll frequently could be 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 An example using shorter polling intervals with a server located in the same
@@ -470,6 +497,59 @@ pidfile /var/run/chronyd-server1.pid
driftfile /var/lib/chrony/drift-server1 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? === Should be a leap smear enabled on NTP server?
With the `smoothtime` and `leapsecmode` directives it is possible to enable a With the `smoothtime` and `leapsecmode` directives it is possible to enable a
@@ -484,7 +564,7 @@ identically configured leap-smearing servers. Note that some clients can get
leap seconds from other sources (e.g. with the `leapsectz` directive in leap seconds from other sources (e.g. with the `leapsectz` directive in
`chrony`) and they will not work correctly with a leap smearing server. `chrony`) and they will not work correctly with a leap smearing server.
=== How should `chronyd` be configuration with `gpsd`? === How should `chronyd` be configured with `gpsd`?
A GPS or other GNSS receiver can be used as a reference clock with `gpsd`. It 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 can work as one or two separate time sources for each connected receiver. The
@@ -571,7 +651,28 @@ 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 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 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 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?
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 on the order of initialisation of their drivers. If a PHC
refclock is specified by this name, `chronyd` could be using a wrong refclock
after reboot. To prevent that, you can configure `udev` to create a stable
symlink for `chronyd` with a rule like this (e.g. written to
_/etc/udev/rules.d/80-phc.rules_):
----
KERNEL=="ptp[0-9]*", DEVPATH=="/devices/pci0000:00/0000:00:01.2/0000:02:00.0/ptp/*", SYMLINK+="ptp-i350-1"
----
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.
=== Why are client log records dropped before reaching `clientloglimit`? === Why are client log records dropped before reaching `clientloglimit`?
@@ -624,9 +725,9 @@ this:
---- ----
MS Name/IP address Stratum Poll Reach LastRx Last sample MS Name/IP address Stratum Poll Reach LastRx Last sample
=============================================================================== ===============================================================================
^* foo.example.net 2 6 377 34 +484us[ -157us] +/- 30ms ^* ntp1.example.net 2 6 377 34 +484us[ -157us] +/- 30ms
^- bar.example.net 2 6 377 34 +33ms[ +32ms] +/- 47ms ^- ntp2.example.net 2 6 377 34 +33ms[ +32ms] +/- 47ms
^+ baz.example.net 3 6 377 35 -1397us[-2033us] +/- 60ms ^+ ntp3.example.net 3 6 377 35 -1397us[-2033us] +/- 60ms
---- ----
=== Are NTP servers specified with the `offline` option? === Are NTP servers specified with the `offline` option?
@@ -696,9 +797,9 @@ successful:
# chronyc -N authdata # chronyc -N authdata
Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen
========================================================================= =========================================================================
foo.example.net NTS 1 15 256 33m 0 0 8 100 ntp1.example.net NTS 1 15 256 33m 0 0 8 100
bar.example.net NTS 1 15 256 33m 0 0 8 100 ntp2.example.net NTS 1 15 256 33m 0 0 8 100
baz.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 The KeyID, Type, and KLen columns should have non-zero values. If they are
@@ -822,7 +923,7 @@ Name/IP Address NP NR Span Frequency Freq Skew Offset Std Dev
============================================================================== ==============================================================================
PPS0 0 0 0 +0.000 2000.000 +0ns 4000ms PPS0 0 0 0 +0.000 2000.000 +0ns 4000ms
NMEA 58 30 231 -96.494 38.406 +504ms 6080us 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 the offset of the NMEA source would need to be increased by about 0.504

View File

@@ -27,9 +27,9 @@
# you can access at http://support.ntp.org/bin/view/Servers/WebHome or # you can access at http://support.ntp.org/bin/view/Servers/WebHome or
# you can use servers from the pool.ntp.org project. # you can use servers from the pool.ntp.org project.
! server foo.example.net iburst ! server ntp1.example.net iburst
! server bar.example.net iburst ! server ntp2.example.net iburst
! server baz.example.net iburst ! server ntp3.example.net iburst
! pool pool.ntp.org 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 # and edit the following lines to specify the locations of the certificate and
# key. # key.
! ntsservercert /etc/.../foo.example.net.crt ! ntsservercert /etc/.../nts-server.crt
! ntsserverkey /etc/.../foo.example.net.key ! ntsserverkey /etc/.../nts-server.key
# chronyd can save the measurement history for the servers to files when # chronyd can save the measurement history for the servers to files when
# it exits. This is useful in 2 situations: # 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 # several people, you need to set up a mailing list or sendmail alias
# for them and use the address of that.) # for them and use the address of that.)
! mailonchange wibble@foo.example.net 0.5 ! mailonchange wibble@example.net 0.5
####################################################################### #######################################################################
### COMMAND ACCESS ### COMMAND ACCESS

View File

@@ -145,6 +145,7 @@ void LOG_Message(LOG_Severity severity,
struct tm *tm; struct tm *tm;
assert(initialised); assert(initialised);
severity = CLAMP(LOGS_DEBUG, severity, LOGS_FATAL);
if (!system_log && file_log && severity >= log_min_severity) { if (!system_log && file_log && severity >= log_min_severity) {
/* Don't clutter up syslog with timestamps and internal debugging info */ /* 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); fprintf(file_log, "%s ", buf);
} }
#if DEBUG > 0 #if DEBUG > 0
if (log_min_severity <= LOGS_DEBUG) if (log_min_severity <= LOGS_DEBUG) {
fprintf(file_log, "%s%s:%d:(%s) ", debug_prefix, filename, line_number, function_name); /* 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 #endif
} }

7
main.c
View File

@@ -368,9 +368,9 @@ go_daemon(void)
} }
/* Don't keep stdin/out/err from before. But don't close /* 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++) { for (fd=0; fd<1024; fd++) {
if (fd != pipefd[1]) if (fd != pipefd[1] && !SCK_IsReusable(fd))
close(fd); close(fd);
} }
@@ -560,6 +560,9 @@ int main
if (user_check && getuid() != 0) if (user_check && getuid() != 0)
LOG_FATAL("Not superuser"); LOG_FATAL("Not superuser");
/* Initialise reusable file descriptors before fork */
SCK_PreInitialise();
/* Turn into a daemon */ /* Turn into a daemon */
if (!nofork) { if (!nofork) {
go_daemon(); go_daemon();

19
ntp.h
View File

@@ -115,9 +115,11 @@ typedef struct {
/* Non-authentication extension fields and corresponding internal flags */ /* 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 */ /* Pre-NTPv5 experimental extension field */
typedef struct { typedef struct {
@@ -126,9 +128,18 @@ typedef struct {
NTP_int32 root_dispersion; NTP_int32 root_dispersion;
NTP_int64 mono_receive_ts; NTP_int64 mono_receive_ts;
uint32_t mono_epoch; 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 */ /* Authentication extension fields */

View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2022 * Copyright (C) Miroslav Lichvar 2009-2023
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of version 2 of the GNU General Public License as
@@ -215,9 +215,6 @@ struct NCR_Instance_Record {
SPF_Instance filter; SPF_Instance filter;
int filter_count; int filter_count;
/* Flag indicating HW transmit timestamps are expected */
int had_hw_tx_timestamp;
/* Response waiting for a HW transmit timestamp of the request */ /* Response waiting for a HW transmit timestamp of the request */
struct SavedResponse *saved_response; struct SavedResponse *saved_response;
@@ -317,6 +314,9 @@ static ARR_Instance broadcasts;
/* Maximum acceptable change in server mono<->real offset */ /* Maximum acceptable change in server mono<->real offset */
#define MAX_MONO_DOFFSET 16.0 #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 */ /* Invalid socket, different from the one in ntp_io.c */
#define INVALID_SOCK_FD -2 #define INVALID_SOCK_FD -2
@@ -376,6 +376,9 @@ do_size_checks(void)
assert(offsetof(NTP_Packet, originate_ts) == 24); assert(offsetof(NTP_Packet, originate_ts) == 24);
assert(offsetof(NTP_Packet, receive_ts) == 32); assert(offsetof(NTP_Packet, receive_ts) == 32);
assert(offsetof(NTP_Packet, transmit_ts) == 40); assert(offsetof(NTP_Packet, transmit_ts) == 40);
assert(sizeof (NTP_EFExpMonoRoot) == 24);
assert(sizeof (NTP_EFExpNetCorrection) == 24);
} }
/* ================================================== */ /* ================================================== */
@@ -421,6 +424,8 @@ zero_local_timestamp(NTP_Local_Timestamp *ts)
UTI_ZeroTimespec(&ts->ts); UTI_ZeroTimespec(&ts->ts);
ts->err = 0.0; ts->err = 0.0;
ts->source = NTP_TS_DAEMON; ts->source = NTP_TS_DAEMON;
ts->rx_duration = 0.0;
ts->net_correction = 0.0;
} }
/* ================================================== */ /* ================================================== */
@@ -794,8 +799,6 @@ NCR_ResetInstance(NCR_Instance instance)
if (instance->filter) if (instance->filter)
SPF_DropSamples(instance->filter); SPF_DropSamples(instance->filter);
instance->filter_count = 0; instance->filter_count = 0;
instance->had_hw_tx_timestamp = 0;
} }
/* ================================================== */ /* ================================================== */
@@ -1050,34 +1053,64 @@ receive_timeout(void *arg)
/* ================================================== */ /* ================================================== */
static int static int
add_ext_exp1(NTP_Packet *message, NTP_PacketInfo *info, struct timespec *rx, add_ef_mono_root(NTP_Packet *message, NTP_PacketInfo *info, struct timespec *rx,
double root_delay, double root_dispersion) double root_delay, double root_dispersion)
{ {
struct timespec mono_rx; struct timespec mono_rx;
NTP_ExtFieldExp1 exp1; NTP_EFExpMonoRoot ef;
NTP_int64 ts_fuzz; NTP_int64 ts_fuzz;
memset(&exp1, 0, sizeof (exp1)); memset(&ef, 0, sizeof (ef));
exp1.magic = htonl(NTP_EF_EXP1_MAGIC); ef.magic = htonl(NTP_EF_EXP_MONO_ROOT_MAGIC);
if (info->mode != MODE_CLIENT) { if (info->mode != MODE_CLIENT) {
exp1.root_delay = UTI_DoubleToNtp32f28(root_delay); ef.root_delay = UTI_DoubleToNtp32f28(root_delay);
exp1.root_dispersion = UTI_DoubleToNtp32f28(root_dispersion); ef.root_dispersion = UTI_DoubleToNtp32f28(root_dispersion);
if (rx) if (rx)
UTI_AddDoubleToTimespec(rx, server_mono_offset, &mono_rx); UTI_AddDoubleToTimespec(rx, server_mono_offset, &mono_rx);
else else
UTI_ZeroTimespec(&mono_rx); UTI_ZeroTimespec(&mono_rx);
UTI_GetNtp64Fuzz(&ts_fuzz, message->precision); UTI_GetNtp64Fuzz(&ts_fuzz, message->precision);
UTI_TimespecToNtp64(&mono_rx, &exp1.mono_receive_ts, &ts_fuzz); UTI_TimespecToNtp64(&mono_rx, &ef.mono_receive_ts, &ts_fuzz);
exp1.mono_epoch = htonl(server_mono_epoch); 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"); DEBUG_LOG("Could not add EF");
return 0; 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; return 1;
} }
@@ -1229,11 +1262,15 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
return 0; return 0;
if (ext_field_flags) { if (ext_field_flags) {
if (ext_field_flags & NTP_EF_FLAG_EXP1) { if (ext_field_flags & NTP_EF_FLAG_EXP_MONO_ROOT) {
if (!add_ext_exp1(&message, &info, smooth_time ? NULL : &local_receive, if (!add_ef_mono_root(&message, &info, smooth_time ? NULL : &local_receive,
our_root_delay, our_root_dispersion)) our_root_delay, our_root_dispersion))
return 0; return 0;
} }
if (ext_field_flags & NTP_EF_FLAG_EXP_NET_CORRECTION) {
if (!add_ef_net_correction(&message, &info, local_rx))
return 0;
}
} }
do { do {
@@ -1302,6 +1339,8 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
local_tx->ts = local_transmit; local_tx->ts = local_transmit;
local_tx->err = local_transmit_err; local_tx->err = local_transmit_err;
local_tx->source = NTP_TS_DAEMON; local_tx->source = NTP_TS_DAEMON;
local_tx->rx_duration = 0.0;
local_tx->net_correction = 0.0;
} }
if (local_ntp_rx) if (local_ntp_rx)
@@ -1495,6 +1534,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 static int
parse_packet(NTP_Packet *packet, int length, NTP_PacketInfo *info) parse_packet(NTP_Packet *packet, int length, NTP_PacketInfo *info)
{ {
@@ -1581,10 +1628,15 @@ parse_packet(NTP_Packet *packet, int length, NTP_PacketInfo *info)
case NTP_EF_NTS_AUTH_AND_EEF: case NTP_EF_NTS_AUTH_AND_EEF:
info->auth.mode = NTP_AUTH_NTS; info->auth.mode = NTP_AUTH_NTS;
break; break;
case NTP_EF_EXP1: case NTP_EF_EXP_MONO_ROOT:
if (ef_body_length == sizeof (NTP_ExtFieldExp1) && if (is_exp_ef(ef_body, ef_body_length, sizeof (NTP_EFExpMonoRoot),
ntohl(((NTP_ExtFieldExp1 *)ef_body)->magic) == NTP_EF_EXP1_MAGIC) NTP_EF_EXP_MONO_ROOT_MAGIC))
info->ext_field_flags |= NTP_EF_FLAG_EXP1; 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; break;
default: default:
DEBUG_LOG("Unknown extension field type=%x", (unsigned int)ef_type); DEBUG_LOG("Unknown extension field type=%x", (unsigned int)ef_type);
@@ -1612,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 static int
check_delay_ratio(NCR_Instance inst, SST_Stats stats, check_delay_ratio(NCR_Instance inst, SST_Stats stats,
struct timespec *sample_time, double delay) struct timespec *sample_time, double delay)
@@ -1873,18 +1972,20 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
/* Extension fields */ /* Extension fields */
int parsed, ef_length, ef_type, ef_body_length; int parsed, ef_length, ef_type, ef_body_length;
void *ef_body; void *ef_body;
NTP_ExtFieldExp1 *ef_exp1; NTP_EFExpMonoRoot *ef_mono_root;
NTP_EFExpNetCorrection *ef_net_correction;
NTP_Local_Timestamp local_receive, local_transmit; NTP_Local_Timestamp local_receive, local_transmit;
double remote_interval, local_interval, response_time; double remote_interval, local_interval, response_time;
double delay_time, precision, mono_doffset; double delay_time, precision, mono_doffset, net_correction;
int updated_timestamps; int updated_timestamps;
/* ==================== */ /* ==================== */
stats = SRC_GetSourcestats(inst->source); stats = SRC_GetSourcestats(inst->source);
ef_exp1 = NULL; ef_mono_root = NULL;
ef_net_correction = NULL;
/* Find requested non-authentication extension fields */ /* Find requested non-authentication extension fields */
if (inst->ext_field_flags & info->ext_field_flags) { if (inst->ext_field_flags & info->ext_field_flags) {
@@ -1894,11 +1995,17 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
break; break;
switch (ef_type) { switch (ef_type) {
case NTP_EF_EXP1: case NTP_EF_EXP_MONO_ROOT:
if (inst->ext_field_flags & NTP_EF_FLAG_EXP1 && if (inst->ext_field_flags & NTP_EF_FLAG_EXP_MONO_ROOT &&
ef_body_length == sizeof (*ef_exp1) && is_exp_ef(ef_body, ef_body_length, sizeof (*ef_mono_root),
ntohl(((NTP_ExtFieldExp1 *)ef_body)->magic) == NTP_EF_EXP1_MAGIC) NTP_EF_EXP_MONO_ROOT_MAGIC))
ef_exp1 = ef_body; 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; break;
} }
} }
@@ -1907,9 +2014,9 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
pkt_leap = NTP_LVM_TO_LEAP(message->lvm); pkt_leap = NTP_LVM_TO_LEAP(message->lvm);
pkt_version = NTP_LVM_TO_VERSION(message->lvm); pkt_version = NTP_LVM_TO_VERSION(message->lvm);
pkt_refid = ntohl(message->reference_id); pkt_refid = ntohl(message->reference_id);
if (ef_exp1) { if (ef_mono_root) {
pkt_root_delay = UTI_Ntp32f28ToDouble(ef_exp1->root_delay); pkt_root_delay = UTI_Ntp32f28ToDouble(ef_mono_root->root_delay);
pkt_root_dispersion = UTI_Ntp32f28ToDouble(ef_exp1->root_dispersion); pkt_root_dispersion = UTI_Ntp32f28ToDouble(ef_mono_root->root_dispersion);
} else { } else {
pkt_root_delay = UTI_Ntp32ToDouble(message->root_delay); pkt_root_delay = UTI_Ntp32ToDouble(message->root_delay);
pkt_root_dispersion = UTI_Ntp32ToDouble(message->root_dispersion); pkt_root_dispersion = UTI_Ntp32ToDouble(message->root_dispersion);
@@ -1966,7 +2073,7 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
response to the request, when at least one good response has already been response to the request, when at least one good response has already been
accepted to avoid incorrectly confirming a tentative source. */ accepted to avoid incorrectly confirming a tentative source. */
if (valid_packet && synced_packet && !saved && !inst->valid_rx && if (valid_packet && synced_packet && !saved && !inst->valid_rx &&
inst->had_hw_tx_timestamp && inst->local_tx.source != NTP_TS_HARDWARE && NIO_IsHwTsEnabled() && inst->local_tx.source != NTP_TS_HARDWARE &&
inst->report.total_good_count > 0) { inst->report.total_good_count > 0) {
if (save_response(inst, local_addr, rx_ts, message, info)) if (save_response(inst, local_addr, rx_ts, message, info))
return 1; return 1;
@@ -1994,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 the new sample. In the interleaved mode, cancel the correction out in
remote timestamps of the previous request and response, which were remote timestamps of the previous request and response, which were
captured before the source accumulated the new time corrections. */ captured before the source accumulated the new time corrections. */
if (ef_exp1 && inst->remote_mono_epoch == ntohl(ef_exp1->mono_epoch) && if (ef_mono_root && inst->remote_mono_epoch == ntohl(ef_mono_root->mono_epoch) &&
!UTI_IsZeroNtp64(&ef_exp1->mono_receive_ts) && !UTI_IsZeroNtp64(&ef_mono_root->mono_receive_ts) &&
!UTI_IsZeroNtp64(&inst->remote_ntp_monorx)) { !UTI_IsZeroNtp64(&inst->remote_ntp_monorx)) {
mono_doffset = 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); UTI_DiffNtp64ToDouble(&message->receive_ts, &inst->remote_ntp_rx);
if (fabs(mono_doffset) > MAX_MONO_DOFFSET) if (fabs(mono_doffset) > MAX_MONO_DOFFSET)
mono_doffset = 0.0; mono_doffset = 0.0;
@@ -2006,6 +2113,12 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
mono_doffset = 0.0; 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 */ /* Select remote and local timestamps for the new sample */
if (interleaved_packet) { if (interleaved_packet) {
/* Prefer previous local TX and remote RX timestamps if it will make /* Prefer previous local TX and remote RX timestamps if it will make
@@ -2025,6 +2138,7 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
UTI_Ntp64ToTimespec(&message->receive_ts, &remote_receive); UTI_Ntp64ToTimespec(&message->receive_ts, &remote_receive);
UTI_Ntp64ToTimespec(&inst->remote_ntp_rx, &remote_request_receive); UTI_Ntp64ToTimespec(&inst->remote_ntp_rx, &remote_request_receive);
local_transmit = inst->local_tx; local_transmit = inst->local_tx;
local_transmit.net_correction = net_correction;
root_delay = MAX(pkt_root_delay, inst->remote_root_delay); root_delay = MAX(pkt_root_delay, inst->remote_root_delay);
root_dispersion = MAX(pkt_root_dispersion, inst->remote_root_dispersion); root_dispersion = MAX(pkt_root_dispersion, inst->remote_root_dispersion);
} }
@@ -2039,6 +2153,7 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
remote_request_receive = remote_receive; remote_request_receive = remote_receive;
local_receive = *rx_ts; local_receive = *rx_ts;
local_transmit = inst->local_tx; local_transmit = inst->local_tx;
local_transmit.net_correction = net_correction;
root_delay = pkt_root_delay; root_delay = pkt_root_delay;
root_dispersion = pkt_root_dispersion; root_dispersion = pkt_root_dispersion;
} }
@@ -2083,6 +2198,9 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
sample.root_delay = root_delay + sample.peer_delay; sample.root_delay = root_delay + sample.peer_delay;
sample.root_dispersion = root_dispersion + sample.peer_dispersion; 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 /* If the source is an active peer, this is the minimum assumed interval
between previous two transmissions (if not constrained by minpoll) */ between previous two transmissions (if not constrained by minpoll) */
prev_remote_poll_interval = UTI_Log2ToDouble(MIN(inst->remote_poll, prev_remote_poll_interval = UTI_Log2ToDouble(MIN(inst->remote_poll,
@@ -2090,8 +2208,10 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
/* Additional tests required to pass before accumulating the sample */ /* Additional tests required to pass before accumulating the sample */
/* Test A requires that the minimum estimate of the peer delay is not /* Test A combines multiple tests to avoid changing the measurements log
larger than the configured maximum, in both client modes that the server 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 processing time is sane, in interleaved client/server mode that the
previous response was not in basic mode (which prevents using timestamps previous response was not in basic mode (which prevents using timestamps
that minimise delay error), and in interleaved symmetric mode that the that minimise delay error), and in interleaved symmetric mode that the
@@ -2099,6 +2219,7 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
a missed response */ a missed response */
testA = sample.peer_delay - sample.peer_dispersion <= inst->max_delay && testA = sample.peer_delay - sample.peer_dispersion <= inst->max_delay &&
precision <= inst->max_delay && precision <= inst->max_delay &&
inst->presend_done <= 0 &&
!(inst->mode == MODE_CLIENT && response_time > MAX_SERVER_INTERVAL) && !(inst->mode == MODE_CLIENT && response_time > MAX_SERVER_INTERVAL) &&
!(inst->mode == MODE_CLIENT && interleaved_packet && !(inst->mode == MODE_CLIENT && interleaved_packet &&
UTI_IsZeroTimespec(&inst->prev_local_tx.ts) && UTI_IsZeroTimespec(&inst->prev_local_tx.ts) &&
@@ -2137,6 +2258,7 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
sample.root_delay = sample.root_dispersion = 0.0; sample.root_delay = sample.root_dispersion = 0.0;
sample.time = rx_ts->ts; sample.time = rx_ts->ts;
mono_doffset = 0.0; mono_doffset = 0.0;
net_correction = 0.0;
local_receive = *rx_ts; local_receive = *rx_ts;
local_transmit = inst->local_tx; local_transmit = inst->local_tx;
testA = testB = testC = testD = 0; testA = testB = testC = testD = 0;
@@ -2170,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. /* 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 This needs to be done here to not lose changes in remote_ntp_rx in
symmetric mode when there are multiple responses per request. */ symmetric mode when there are multiple responses per request. */
if (ef_exp1 && !UTI_IsZeroNtp64(&ef_exp1->mono_receive_ts)) { if (ef_mono_root && !UTI_IsZeroNtp64(&ef_mono_root->mono_receive_ts)) {
inst->remote_mono_epoch = ntohl(ef_exp1->mono_epoch); inst->remote_mono_epoch = ntohl(ef_mono_root->mono_epoch);
inst->remote_ntp_monorx = ef_exp1->mono_receive_ts; inst->remote_ntp_monorx = ef_mono_root->mono_receive_ts;
inst->mono_doffset += mono_doffset; inst->mono_doffset += mono_doffset;
} else { } else {
inst->remote_mono_epoch = 0; inst->remote_mono_epoch = 0;
@@ -2180,8 +2302,11 @@ process_response(NCR_Instance inst, int saved, NTP_Local_Address *local_addr,
inst->mono_doffset = 0.0; inst->mono_doffset = 0.0;
} }
/* Don't use the same set of timestamps for the next sample */ inst->local_tx.net_correction = net_correction;
if (interleaved_packet)
/* 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; inst->prev_local_tx = inst->local_tx;
else else
zero_local_timestamp(&inst->prev_local_tx); zero_local_timestamp(&inst->prev_local_tx);
@@ -2200,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 /* Accept at most one response per request. The NTP specification recommends
resetting local_ntp_tx to make the following packets fail test2 or test3, 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 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) { if (inst->valid_rx) {
test2 = test3 = 0; test2 = test3 = 0;
valid_packet = synced_packet = good_packet = 0; valid_packet = synced_packet = good_packet = 0;
} else if (valid_packet) { } else if (valid_packet) {
if (inst->presend_done) {
testA = 0;
good_packet = 0;
}
inst->valid_rx = 1; inst->valid_rx = 1;
} }
@@ -2607,8 +2728,7 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
UTI_CompareNtp64(&message->receive_ts, &message->transmit_ts) != 0) { UTI_CompareNtp64(&message->receive_ts, &message->transmit_ts) != 0) {
ntp_rx = message->originate_ts; ntp_rx = message->originate_ts;
local_ntp_rx = &ntp_rx; local_ntp_rx = &ntp_rx;
UTI_ZeroTimespec(&local_tx.ts); zero_local_timestamp(&local_tx);
local_tx.source = NTP_TS_DAEMON;
interleaved = CLG_GetNtpTxTimestamp(&ntp_rx, &local_tx.ts, &local_tx.source); interleaved = CLG_GetNtpTxTimestamp(&ntp_rx, &local_tx.ts, &local_tx.source);
tx_ts = &local_tx; tx_ts = &local_tx;
@@ -2692,8 +2812,6 @@ NCR_ProcessTxKnown(NCR_Instance inst, NTP_Local_Address *local_addr,
message); message);
if (tx_ts->source == NTP_TS_HARDWARE) { if (tx_ts->source == NTP_TS_HARDWARE) {
inst->had_hw_tx_timestamp = 1;
if (has_saved_response(inst)) if (has_saved_response(inst))
process_saved_response(inst); process_saved_response(inst);
} }

View File

@@ -42,6 +42,8 @@ typedef struct {
struct timespec ts; struct timespec ts;
double err; double err;
NTP_Timestamp_Source source; NTP_Timestamp_Source source;
double rx_duration;
double net_correction;
} NTP_Local_Timestamp; } NTP_Local_Timestamp;
/* This is a private data type used for storing the instance record for /* This is a private data type used for storing the instance record for

View File

@@ -278,6 +278,18 @@ NIO_Finalise(void)
/* ================================================== */ /* ================================================== */
int
NIO_IsHwTsEnabled(void)
{
#ifdef HAVE_LINUX_TIMESTAMPING
return NIO_Linux_IsHwTsEnabled();
#else
return 0;
#endif
}
/* ================================================== */
int int
NIO_OpenClientSocket(NTP_Remote_Address *remote_addr) NIO_OpenClientSocket(NTP_Remote_Address *remote_addr)
{ {
@@ -419,6 +431,9 @@ process_message(SCK_Message *message, int sock_fd, int event)
SCH_GetLastEventTime(&local_ts.ts, &local_ts.err, NULL); SCH_GetLastEventTime(&local_ts.ts, &local_ts.err, NULL);
local_ts.source = NTP_TS_DAEMON; local_ts.source = NTP_TS_DAEMON;
local_ts.rx_duration = 0.0;
local_ts.net_correction = 0.0;
sched_ts = local_ts.ts; sched_ts = local_ts.ts;
if (message->addr_type != SCK_ADDR_IP) { if (message->addr_type != SCK_ADDR_IP) {
@@ -444,7 +459,7 @@ process_message(SCK_Message *message, int sock_fd, int event)
DEBUG_LOG("Updated RX timestamp delay=%.9f tss=%u", DEBUG_LOG("Updated RX timestamp delay=%.9f tss=%u",
UTI_DiffTimespecsToDouble(&sched_ts, &local_ts.ts), local_ts.source); 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; return;
/* Just ignore the packet if it's not of a recognized length */ /* Just ignore the packet if it's not of a recognized length */
@@ -483,8 +498,9 @@ read_from_socket(int sock_fd, int event, void *anything)
/* ================================================== */ /* ================================================== */
int 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; PTP_NtpMessage *msg;
if (!is_ptp_socket(sock_fd)) if (!is_ptp_socket(sock_fd))
@@ -510,7 +526,14 @@ NIO_UnwrapMessage(SCK_Message *message, int sock_fd)
message->data = (char *)message->data + PTP_NTP_PREFIX_LENGTH; message->data = (char *)message->data + PTP_NTP_PREFIX_LENGTH;
message->length -= 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; return 1;
} }

View File

@@ -39,6 +39,9 @@ extern void NIO_Initialise(void);
/* Function to finalise the module */ /* Function to finalise the module */
extern void NIO_Finalise(void); extern void NIO_Finalise(void);
/* Function to check if HW timestamping is enabled on any interface */
extern int NIO_IsHwTsEnabled(void);
/* Function to obtain a socket for sending client packets */ /* Function to obtain a socket for sending client packets */
extern int NIO_OpenClientSocket(NTP_Remote_Address *remote_addr); extern int NIO_OpenClientSocket(NTP_Remote_Address *remote_addr);
@@ -61,7 +64,7 @@ extern int NIO_IsServerSocketOpen(void);
extern int NIO_IsServerConnectable(NTP_Remote_Address *remote_addr); extern int NIO_IsServerConnectable(NTP_Remote_Address *remote_addr);
/* Function to unwrap an NTP message from non-native transport (e.g. PTP) */ /* 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 */ /* Function to transmit a packet */
extern int NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, extern int NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr,

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate. chronyd/chronyc - Programs for keeping computer clocks accurate.
********************************************************************** **********************************************************************
* Copyright (C) Miroslav Lichvar 2016-2019, 2021-2022 * Copyright (C) Miroslav Lichvar 2016-2019, 2021-2023
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of version 2 of the GNU General Public License as
@@ -439,6 +439,14 @@ NIO_Linux_Finalise(void)
/* ================================================== */ /* ================================================== */
int
NIO_Linux_IsHwTsEnabled(void)
{
return ARR_GetSize(interfaces) > 0;
}
/* ================================================== */
int int
NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events) NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events)
{ {
@@ -551,7 +559,7 @@ process_hw_timestamp(struct Interface *iface, struct timespec *hw_ts,
NTP_Local_Timestamp *local_ts, int rx_ntp_length, int family, NTP_Local_Timestamp *local_ts, int rx_ntp_length, int family,
int l2_length) int l2_length)
{ {
double rx_correction, ts_delay, local_err; double rx_correction = 0.0, ts_delay, local_err;
struct timespec ts; struct timespec ts;
poll_phc(iface, &local_ts->ts); poll_phc(iface, &local_ts->ts);
@@ -592,6 +600,10 @@ process_hw_timestamp(struct Interface *iface, struct timespec *hw_ts,
local_ts->ts = ts; local_ts->ts = ts;
local_ts->err = local_err; local_ts->err = local_err;
local_ts->source = NTP_TS_HARDWARE; 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;
} }
/* ================================================== */ /* ================================================== */
@@ -715,6 +727,7 @@ NIO_Linux_ProcessMessage(SCK_Message *message, NTP_Local_Address *local_addr,
{ {
struct Interface *iface; struct Interface *iface;
int is_tx, ts_if_index, l2_length; int is_tx, ts_if_index, l2_length;
double c = 0.0;
is_tx = event == SCH_FILE_EXCEPTION; is_tx = event == SCH_FILE_EXCEPTION;
iface = NULL; iface = NULL;
@@ -775,7 +788,7 @@ NIO_Linux_ProcessMessage(SCK_Message *message, NTP_Local_Address *local_addr,
return 1; return 1;
} }
if (!NIO_UnwrapMessage(message, local_addr->sock_fd)) if (!NIO_UnwrapMessage(message, local_addr->sock_fd, &c))
return 1; return 1;
if (message->length < NTP_HEADER_LENGTH || message->length > sizeof (NTP_Packet)) if (message->length < NTP_HEADER_LENGTH || message->length > sizeof (NTP_Packet))

View File

@@ -33,6 +33,8 @@ extern void NIO_Linux_Initialise(void);
extern void NIO_Linux_Finalise(void); extern void NIO_Linux_Finalise(void);
extern int NIO_Linux_IsHwTsEnabled(void);
extern int NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events); extern int NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events);
extern int NIO_Linux_ProcessMessage(SCK_Message *message, NTP_Local_Address *local_addr, extern int NIO_Linux_ProcessMessage(SCK_Message *message, NTP_Local_Address *local_addr,

View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011-2012, 2014, 2016, 2020-2021 * Copyright (C) Miroslav Lichvar 2011-2012, 2014, 2016, 2020-2023
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of version 2 of the GNU General Public License as
@@ -59,6 +59,8 @@ typedef struct {
NCR_Instance data; /* Data for the protocol engine for this source */ NCR_Instance data; /* Data for the protocol engine for this source */
char *name; /* Name of the source as it was specified char *name; /* Name of the source as it was specified
(may be an IP address) */ (may be an IP address) */
IPAddr resolved_addr; /* Address resolved from the name, which can be
different from remote_addr (e.g. NTS-KE) */
int pool_id; /* ID of the pool from which was this source int pool_id; /* ID of the pool from which was this source
added or INVALID_POOL */ added or INVALID_POOL */
int tentative; /* Flag indicating there was no valid response int tentative; /* Flag indicating there was no valid response
@@ -388,6 +390,7 @@ add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type,
record->name = Strdup(name ? name : UTI_IPToString(&remote_addr->ip_addr)); record->name = Strdup(name ? name : UTI_IPToString(&remote_addr->ip_addr));
record->data = NCR_CreateInstance(remote_addr, type, params, record->name); record->data = NCR_CreateInstance(remote_addr, type, params, record->name);
record->remote_addr = NCR_GetRemoteAddress(record->data); record->remote_addr = NCR_GetRemoteAddress(record->data);
record->resolved_addr = remote_addr->ip_addr;
record->pool_id = pool_id; record->pool_id = pool_id;
record->tentative = 1; record->tentative = 1;
record->conf_id = conf_id; record->conf_id = conf_id;
@@ -440,6 +443,8 @@ change_source_address(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr
record = get_record(slot1); record = get_record(slot1);
NCR_ChangeRemoteAddress(record->data, new_addr, !replacement); NCR_ChangeRemoteAddress(record->data, new_addr, !replacement);
if (replacement)
record->resolved_addr = new_addr->ip_addr;
if (record->remote_addr != NCR_GetRemoteAddress(record->data) || if (record->remote_addr != NCR_GetRemoteAddress(record->data) ||
UTI_CompareIPs(&record->remote_addr->ip_addr, &new_addr->ip_addr, NULL) != 0) UTI_CompareIPs(&record->remote_addr->ip_addr, &new_addr->ip_addr, NULL) != 0)
@@ -523,7 +528,7 @@ process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs
NTP_Remote_Address old_addr, new_addr; NTP_Remote_Address old_addr, new_addr;
SourceRecord *record; SourceRecord *record;
unsigned short first = 0; unsigned short first = 0;
int i, j; int i, j, slot;
/* Keep using the current address if it is being refreshed and it is /* Keep using the current address if it is being refreshed and it is
still included in the resolved addresses */ still included in the resolved addresses */
@@ -531,7 +536,8 @@ process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs
assert(us->pool_id == INVALID_POOL); assert(us->pool_id == INVALID_POOL);
for (i = 0; i < n_addrs; i++) { for (i = 0; i < n_addrs; i++) {
if (UTI_CompareIPs(&us->address.ip_addr, &ip_addrs[i], NULL) == 0) { if (find_slot2(&us->address, &slot) == 2 &&
UTI_CompareIPs(&get_record(slot)->resolved_addr, &ip_addrs[i], NULL) == 0) {
DEBUG_LOG("%s still fresh", UTI_IPToString(&us->address.ip_addr)); DEBUG_LOG("%s still fresh", UTI_IPToString(&us->address.ip_addr));
return; return;
} }
@@ -838,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 void
NSR_SetSourceResolvingEndHandler(NSR_SourceResolvingEndHandler handler) NSR_SetSourceResolvingEndHandler(NSR_SourceResolvingEndHandler handler)
{ {

View File

@@ -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, extern NSR_Status NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type,
SourceParameters *params, uint32_t *conf_id); 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 /* Function type for handlers to be called back when an attempt
* (possibly unsuccessful) to resolve unresolved sources ends */ * (possibly unsuccessful) to resolve unresolved sources ends */
typedef void (*NSR_SourceResolvingEndHandler)(void); typedef void (*NSR_SourceResolvingEndHandler)(void);

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate. chronyd/chronyc - Programs for keeping computer clocks accurate.
********************************************************************** **********************************************************************
* Copyright (C) Miroslav Lichvar 2020 * Copyright (C) Miroslav Lichvar 2020, 2022
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of version 2 of the GNU General Public License as
@@ -651,7 +651,7 @@ load_keys(void)
fclose(f); fclose(f);
LOG(LOGS_ERR, "Loaded %s", "server NTS keys"); LOG(LOGS_INFO, "Loaded %s", "server NTS keys");
return 1; return 1;
error: error:
@@ -685,6 +685,8 @@ run_helper(uid_t uid, gid_t gid, int scfilter_level)
DEBUG_LOG("Helper started"); DEBUG_LOG("Helper started");
SCK_CloseReusableSockets();
/* Suppress a log message about disabled clock control */ /* Suppress a log message about disabled clock control */
log_severity = LOG_GetMinSeverity(); log_severity = LOG_GetMinSeverity();
LOG_SetMinSeverity(LOGS_ERR); LOG_SetMinSeverity(LOGS_ERR);

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate. chronyd/chronyc - Programs for keeping computer clocks accurate.
********************************************************************** **********************************************************************
* Copyright (C) Miroslav Lichvar 2020 * Copyright (C) Miroslav Lichvar 2020, 2022
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of version 2 of the GNU General Public License as

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate. chronyd/chronyc - Programs for keeping computer clocks accurate.
********************************************************************** **********************************************************************
* Copyright (C) Miroslav Lichvar 2013, 2017 * Copyright (C) Miroslav Lichvar 2013, 2017, 2023
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of version 2 of the GNU General Public License as

View File

@@ -37,6 +37,8 @@
struct SIV_Instance_Record { struct SIV_Instance_Record {
gnutls_cipher_algorithm_t algorithm; gnutls_cipher_algorithm_t algorithm;
gnutls_aead_cipher_hd_t cipher; 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) { switch (algorithm) {
case AEAD_AES_SIV_CMAC_256: case AEAD_AES_SIV_CMAC_256:
return GNUTLS_CIPHER_AES_128_SIV; 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: default:
return 0; return 0;
} }
@@ -112,6 +118,19 @@ SIV_CreateInstance(SIV_Algorithm algorithm)
instance->algorithm = calgo; instance->algorithm = calgo;
instance->cipher = NULL; 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++; instance_counter++;
return instance; return instance;
@@ -143,6 +162,8 @@ SIV_GetKeyLength(SIV_Algorithm algorithm)
return 0; return 0;
len = gnutls_cipher_get_key_size(calgo); len = gnutls_cipher_get_key_size(calgo);
if (len == 0)
return 0;
if (len < 1 || len > SIV_MAX_KEY_LENGTH) if (len < 1 || len > SIV_MAX_KEY_LENGTH)
LOG_FATAL("Invalid key length"); LOG_FATAL("Invalid key length");
@@ -198,7 +219,7 @@ SIV_SetKey(SIV_Instance instance, const unsigned char *key, int length)
int int
SIV_GetMinNonceLength(SIV_Instance instance) SIV_GetMinNonceLength(SIV_Instance instance)
{ {
return 1; return instance->min_nonce_length;
} }
/* ================================================== */ /* ================================================== */
@@ -206,7 +227,7 @@ SIV_GetMinNonceLength(SIV_Instance instance)
int int
SIV_GetMaxNonceLength(SIV_Instance instance) 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) if (!instance->cipher)
return 0; 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) plaintext_length < 0 || ciphertext_length < 0)
return 0; return 0;
@@ -269,7 +291,8 @@ SIV_Decrypt(SIV_Instance instance,
if (!instance->cipher) if (!instance->cipher)
return 0; 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) plaintext_length < 0 || ciphertext_length < 0)
return 0; return 0;

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate. chronyd/chronyc - Programs for keeping computer clocks accurate.
********************************************************************** **********************************************************************
* Copyright (C) Miroslav Lichvar 2019 * Copyright (C) Miroslav Lichvar 2019, 2022
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of version 2 of the GNU General Public License as

182
socket.c
View File

@@ -89,6 +89,9 @@ struct MessageHeader {
static int initialised; static int initialised;
static int first_reusable_fd;
static int reusable_fds;
/* Flags indicating in which IP families sockets can be requested */ /* Flags indicating in which IP families sockets can be requested */
static int ip4_enabled; static int ip4_enabled;
static int ip6_enabled; static int ip6_enabled;
@@ -155,6 +158,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) #if defined(SOCK_CLOEXEC) || defined(SOCK_NONBLOCK)
static int static int
check_socket_flag(int sock_flag, int fd_flag, int fs_flag) check_socket_flag(int sock_flag, int fd_flag, int fs_flag)
@@ -212,7 +268,7 @@ static int
set_socket_flags(int sock_fd, int flags) set_socket_flags(int sock_fd, int flags)
{ {
/* Close the socket automatically on exec */ /* Close the socket automatically on exec */
if ( if (!SCK_IsReusable(sock_fd) &&
#ifdef SOCK_CLOEXEC #ifdef SOCK_CLOEXEC
(supported_socket_flags & SOCK_CLOEXEC) == 0 && (supported_socket_flags & SOCK_CLOEXEC) == 0 &&
#endif #endif
@@ -222,7 +278,7 @@ set_socket_flags(int sock_fd, int flags)
/* Enable non-blocking mode */ /* Enable non-blocking mode */
if ((flags & SCK_FLAG_BLOCK) == 0 && if ((flags & SCK_FLAG_BLOCK) == 0 &&
#ifdef SOCK_NONBLOCK #ifdef SOCK_NONBLOCK
(supported_socket_flags & SOCK_NONBLOCK) == 0 && (SCK_IsReusable(sock_fd) || (supported_socket_flags & SOCK_NONBLOCK) == 0) &&
#endif #endif
!set_socket_nonblock(sock_fd)) !set_socket_nonblock(sock_fd))
return 0; return 0;
@@ -279,6 +335,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 static int
set_socket_options(int sock_fd, int flags) set_socket_options(int sock_fd, int flags)
{ {
@@ -295,8 +377,10 @@ static int
set_ip_options(int sock_fd, int family, int flags) set_ip_options(int sock_fd, int family, int flags)
{ {
#if defined(FEAT_IPV6) && defined(IPV6_V6ONLY) #if defined(FEAT_IPV6) && defined(IPV6_V6ONLY)
/* Receive only IPv6 packets on an IPv6 socket */ /* Receive only IPv6 packets on an IPv6 socket, but do not attempt
if (family == IPADDR_INET6 && !SCK_SetIntOption(sock_fd, IPPROTO_IPV6, IPV6_V6ONLY, 1)) 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; return 0;
#endif #endif
@@ -385,6 +469,10 @@ bind_ip_address(int sock_fd, IPSockAddr *addr, int flags)
; ;
#endif #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)); saddr_len = SCK_IPSockAddrToSockaddr(addr, (struct sockaddr *)&saddr, sizeof (saddr));
if (saddr_len == 0) if (saddr_len == 0)
return 0; return 0;
@@ -457,7 +545,7 @@ open_ip_socket(IPSockAddr *remote_addr, IPSockAddr *local_addr, const char *ifac
return INVALID_SOCK_FD; 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) if (sock_fd < 0)
return INVALID_SOCK_FD; return INVALID_SOCK_FD;
@@ -482,7 +570,8 @@ open_ip_socket(IPSockAddr *remote_addr, IPSockAddr *local_addr, const char *ifac
goto error; goto error;
if (remote_addr || local_addr) 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" : "?", type == SOCK_DGRAM ? "UDP" : type == SOCK_STREAM ? "TCP" : "?",
family == IPADDR_INET4 ? "v4" : "v6", family == IPADDR_INET4 ? "v4" : "v6",
sock_fd, sock_fd,
@@ -869,6 +958,11 @@ process_header(struct msghdr *msg, int msg_length, int sock_fd, int flags,
memcpy(&message->timestamp.kernel, CMSG_DATA(cmsg), sizeof (message->timestamp.kernel)); memcpy(&message->timestamp.kernel, CMSG_DATA(cmsg), sizeof (message->timestamp.kernel));
} }
#endif #endif
#ifdef SCM_REALTIME
else if (match_cmsg(cmsg, SOL_SOCKET, SCM_REALTIME, sizeof (message->timestamp.kernel))) {
memcpy(&message->timestamp.kernel, CMSG_DATA(cmsg), sizeof (message->timestamp.kernel));
}
#endif
#ifdef HAVE_LINUX_TIMESTAMPING #ifdef HAVE_LINUX_TIMESTAMPING
#ifdef HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO #ifdef HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO
else if (match_cmsg(cmsg, SOL_SOCKET, SCM_TIMESTAMPING_PKTINFO, else if (match_cmsg(cmsg, SOL_SOCKET, SCM_TIMESTAMPING_PKTINFO,
@@ -1165,9 +1259,44 @@ 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 void
SCK_Initialise(int family) SCK_Initialise(int family)
{ {
int fd;
ip4_enabled = family == IPADDR_INET4 || family == IPADDR_UNSPEC; ip4_enabled = family == IPADDR_INET4 || family == IPADDR_UNSPEC;
#ifdef FEAT_IPV6 #ifdef FEAT_IPV6
ip6_enabled = family == IPADDR_INET6 || family == IPADDR_UNSPEC; ip6_enabled = family == IPADDR_INET6 || family == IPADDR_UNSPEC;
@@ -1196,6 +1325,9 @@ SCK_Initialise(int family)
supported_socket_flags |= SOCK_NONBLOCK; supported_socket_flags |= SOCK_NONBLOCK;
#endif #endif
for (fd = first_reusable_fd; fd < first_reusable_fd + reusable_fds; fd++)
UTI_FdSetCloexec(fd);
initialised = 1; initialised = 1;
} }
@@ -1208,6 +1340,8 @@ SCK_Finalise(void)
ARR_DestroyInstance(recv_headers); ARR_DestroyInstance(recv_headers);
ARR_DestroyInstance(recv_messages); ARR_DestroyInstance(recv_messages);
SCK_CloseReusableSockets();
initialised = 0; initialised = 0;
} }
@@ -1348,6 +1482,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 int
SCK_SetIntOption(int sock_fd, int level, int name, int value) SCK_SetIntOption(int sock_fd, int level, int name, int value)
{ {
@@ -1386,8 +1541,15 @@ SCK_EnableKernelRxTimestamping(int sock_fd)
return 1; return 1;
#endif #endif
#ifdef SO_TIMESTAMP #ifdef SO_TIMESTAMP
if (SCK_SetIntOption(sock_fd, SOL_SOCKET, SO_TIMESTAMP, 1)) if (SCK_SetIntOption(sock_fd, SOL_SOCKET, SO_TIMESTAMP, 1)) {
#if defined(SO_TS_CLOCK) && defined(SO_TS_REALTIME)
/* We don't care about the return value - we'll get either a
SCM_REALTIME (if we succeded) or a SCM_TIMESTAMP (if we failed) */
if (!SCK_SetIntOption(sock_fd, SOL_SOCKET, SO_TS_CLOCK, SO_TS_REALTIME))
;
#endif
return 1; return 1;
}
#endif #endif
return 0; return 0;
@@ -1398,7 +1560,7 @@ SCK_EnableKernelRxTimestamping(int sock_fd)
int int
SCK_ListenOnSocket(int sock_fd, int backlog) 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)); DEBUG_LOG("listen() failed : %s", strerror(errno));
return 0; return 0;
} }
@@ -1561,6 +1723,10 @@ SCK_RemoveSocket(int sock_fd)
void void
SCK_CloseSocket(int sock_fd) SCK_CloseSocket(int sock_fd)
{ {
/* Reusable sockets are closed in finalisation */
if (SCK_IsReusable(sock_fd))
return;
close(sock_fd); close(sock_fd);
} }

View File

@@ -73,6 +73,9 @@ typedef struct {
int descriptor; int descriptor;
} SCK_Message; } SCK_Message;
/* Pre-initialisation function */
extern void SCK_PreInitialise(void);
/* Initialisation function (the specified IP family is enabled, /* Initialisation function (the specified IP family is enabled,
or all if IPADDR_UNSPEC) */ or all if IPADDR_UNSPEC) */
extern void SCK_Initialise(int family); extern void SCK_Initialise(int family);
@@ -106,6 +109,12 @@ extern int SCK_OpenUnixStreamSocket(const char *remote_addr, const char *local_a
int flags); int flags);
extern int SCK_OpenUnixSocketPair(int flags, int *other_fd); 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 */ /* 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_SetIntOption(int sock_fd, int level, int name, int value);
extern int SCK_GetIntOption(int sock_fd, int level, int name, int *value); extern int SCK_GetIntOption(int sock_fd, int level, int name, int *value);

View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011-2016, 2018, 2020-2021 * Copyright (C) Miroslav Lichvar 2011-2016, 2018, 2020-2023
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of version 2 of the GNU General Public License as
@@ -314,8 +314,12 @@ void SRC_DestroyInstance(SRC_Instance instance)
if (last_updated_inst == instance) if (last_updated_inst == instance)
last_updated_inst = NULL; last_updated_inst = NULL;
/* Force reselection if currently selected */
SRC_ResetInstance(instance);
assert(initialised); assert(initialised);
if (instance->index < 0 || instance->index >= n_sources || if (instance->index < 0 || instance->index >= n_sources ||
instance->index == selected_source_index ||
instance != sources[instance->index]) instance != sources[instance->index])
assert(0); assert(0);
@@ -330,10 +334,7 @@ void SRC_DestroyInstance(SRC_Instance instance)
update_sel_options(); update_sel_options();
/* If this was the previous reference source, we have to reselect! */ if (selected_source_index > dead_index)
if (selected_source_index == dead_index)
SRC_ReselectSource();
else if (selected_source_index > dead_index)
--selected_source_index; --selected_source_index;
} }
@@ -357,6 +358,9 @@ SRC_ResetInstance(SRC_Instance instance)
memset(&instance->sel_info, 0, sizeof (instance->sel_info)); memset(&instance->sel_info, 0, sizeof (instance->sel_info));
SST_ResetInstance(instance->stats); SST_ResetInstance(instance->stats);
if (selected_source_index == instance->index)
SRC_SelectSource(NULL);
} }
/* ================================================== */ /* ================================================== */
@@ -587,9 +591,7 @@ update_sel_options(void)
for (i = 0; i < n_sources; i++) { for (i = 0; i < n_sources; i++) {
options = sources[i]->conf_sel_options; options = sources[i]->conf_sel_options;
if (options & SRC_SELECT_NOSELECT) if (!(options & SRC_SELECT_NOSELECT)) {
continue;
switch (sources[i]->type) { switch (sources[i]->type) {
case SRC_NTP: case SRC_NTP:
options |= sources[i]->authenticated ? auth_ntp_options : unauth_ntp_options; options |= sources[i]->authenticated ? auth_ntp_options : unauth_ntp_options;
@@ -600,6 +602,7 @@ update_sel_options(void)
default: default:
assert(0); assert(0);
} }
}
if (sources[i]->sel_options != options) { if (sources[i]->sel_options != options) {
DEBUG_LOG("changing %s from %x to %x", source_to_string(sources[i]), DEBUG_LOG("changing %s from %x to %x", source_to_string(sources[i]),
@@ -851,11 +854,9 @@ SRC_SelectSource(SRC_Instance updated_inst)
} }
if (n_sources == 0) { if (n_sources == 0) {
/* In this case, we clearly cannot synchronise to anything */ /* Removed sources are unselected before actual removal */
if (selected_source_index != INVALID_SOURCE) { if (selected_source_index != INVALID_SOURCE)
log_selection_message(LOGS_INFO, "Can't synchronise: no sources", NULL); assert(0);
selected_source_index = INVALID_SOURCE;
}
return; return;
} }

View File

@@ -207,6 +207,12 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type,
return NSR_TooManySources; return NSR_TooManySources;
} }
const char *
NSR_StatusToString(NSR_Status status)
{
return "NTP not supported";
}
NSR_Status NSR_Status
NSR_RemoveSource(IPAddr *address) NSR_RemoveSource(IPAddr *address)
{ {

View File

@@ -7,9 +7,9 @@ for opts in \
"--host-system=NetBSD" \ "--host-system=NetBSD" \
"--host-system=FreeBSD" \ "--host-system=FreeBSD" \
"--without-nettle" \ "--without-nettle" \
"--without-nettle --without-nss" \ "--without-nettle --without-gnutls" \
"--without-nettle --without-nss --without-tomcrypt" \ "--without-nettle --without-gnutls --without-nss" \
"--without-nettle --without-nss --without-tomcrypt --without-gnutls" "--without-nettle --without-gnutls --without-nss --without-tomcrypt"
do do
./configure $opts ./configure $opts
scan-build make "$@" || exit 1 scan-build make "$@" || exit 1

View File

@@ -25,13 +25,13 @@ touch Makefile
for extra_config_opts in \ for extra_config_opts in \
"--all-privops" \ "--all-privops" \
"--disable-ipv6" \ "--disable-ipv6" \
"--disable-nts" \
"--disable-scfilter" \ "--disable-scfilter" \
"--without-aes-gcm-siv" \ "--without-aes-gcm-siv" \
"--without-gnutls" \
"--without-nettle" \ "--without-nettle" \
"--without-nettle --without-nss" \ "--without-nettle --without-gnutls" \
"--without-nettle --without-nss --without-tomcrypt" \ "--without-nettle --without-gnutls --without-nss" \
"--without-nettle --without-nss --without-tomcrypt --without-gnutls"; \ "--without-nettle --without-gnutls --without-nss --without-tomcrypt"; \
do do
for arch_opts in "-m32" ""; do for arch_opts in "-m32" ""; do
pushd test/simulation/clknetsim || exit 1 pushd test/simulation/clknetsim || exit 1

View File

@@ -114,7 +114,7 @@ limit=1
for chronyc_conf in \ for chronyc_conf in \
"accheck 1.2.3.4" \ "accheck 1.2.3.4" \
"add peer 10.0.0.0 minpoll 2 maxpoll 6" \ "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" \ "add server node1.net1.clk" \
"allow 1.2.3.4" \ "allow 1.2.3.4" \
"allow 1.2" \ "allow 1.2" \
@@ -350,6 +350,8 @@ minstratum 192.168.123.1 1
polltarget 192.168.123.1 10 polltarget 192.168.123.1 10
selectopts 192.168.123.1 +trust +prefer -require selectopts 192.168.123.1 +trust +prefer -require
selectdata selectdata
selectopts 192.168.123.1 +noselect -prefer -trust +require
selectdata
delete 192.168.123.1" delete 192.168.123.1"
run_test || test_fail run_test || test_fail
@@ -372,6 +374,10 @@ check_chronyc_output "^200 OK
S Name/IP Address Auth COpts EOpts Last Score Interval Leap S Name/IP Address Auth COpts EOpts Last Score Interval Leap
======================================================================= =======================================================================
M node1\.net1\.clk N \-PT\-\- \-PT\-\- 0 1\.0 \+0ns \+0ns \? M node1\.net1\.clk N \-PT\-\- \-PT\-\- 0 1\.0 \+0ns \+0ns \?
200 OK
S Name/IP Address Auth COpts EOpts Last Score Interval Leap
=======================================================================
M node1\.net1\.clk N N\-\-R\- N\-\-R\- 0 1\.0 \+0ns \+0ns \?
200 OK$" || test_fail 200 OK$" || test_fail
chronyc_conf=" chronyc_conf="

View File

@@ -3,6 +3,7 @@
. ./test.common . ./test.common
test_start "presend option" test_start "presend option"
limit=9900
min_sync_time=136 min_sync_time=136
max_sync_time=260 max_sync_time=260
client_server_options="presend 6 maxdelay 16" client_server_options="presend 6 maxdelay 16"
@@ -22,4 +23,29 @@ check_source_selection || test_fail
check_packet_interval || test_fail check_packet_interval || test_fail
check_sync || 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 test_pass

View File

@@ -16,6 +16,6 @@ check_chronyd_exit || test_fail
check_source_selection || test_fail check_source_selection || test_fail
check_packet_interval || test_fail check_packet_interval || test_fail
check_sync || test_fail check_sync || test_fail
check_log_messages "clock wrong by" 4 8 || test_fail check_log_messages "clock wrong by" 3 8 || test_fail
test_pass test_pass

View File

@@ -158,10 +158,10 @@ for dns in 1 0; do
check_source_selection && test_fail check_source_selection && test_fail
check_sync && test_fail check_sync && test_fail
check_file_messages " 2 1 .* 4460 " 50 100 log.packets || test_fail check_file_messages " 2 1 .* 4460 " 45 100 log.packets || test_fail
check_file_messages " 2 2 .* 4460 " 0 0 log.packets || test_fail check_file_messages " 2 2 .* 4460 " 0 0 log.packets || test_fail
check_log_messages "Source 192.168.123.1 changed to 192.168.123.2" 4 10 || test_fail check_log_messages "Source 192.168.123.1 changed to 192.168.123.2" 4 10 || test_fail
check_log_messages "Source 192.168.123.2 replaced with 192.168.123.1" 4 10 || test_fail check_log_messages "Source 192.168.123.2 replaced with 192.168.123.1" 3 10 || test_fail
servers=2 servers=2
@@ -225,6 +225,8 @@ for dns in 1 0; do
check_file_messages " 3 2 .* 4460 " 0 0 log.packets || test_fail check_file_messages " 3 2 .* 4460 " 0 0 log.packets || test_fail
done done
min_sync_time=$[default_min_sync_time + 200]
max_sync_time=600
server_conf=" server_conf="
ntsserverkey tmp/server1.key ntsserverkey tmp/server1.key
ntsservercert tmp/server1.crt ntsservercert tmp/server1.crt
@@ -248,6 +250,8 @@ check_file_messages " 3 2 .* 123 " 0 0 log.packets || test_fail
check_file_messages " 3 2 .* 11123 " 3 3 log.packets || test_fail check_file_messages " 3 2 .* 11123 " 3 3 log.packets || test_fail
dns=1 dns=1
min_sync_time=$default_min_sync_time
max_sync_time=400
server_conf=" server_conf="
ntsserverkey tmp/server1.key ntsserverkey tmp/server1.key
ntsservercert tmp/server1.crt ntsservercert tmp/server1.crt

106
test/simulation/142-ntpoverptp Executable file
View File

@@ -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

View File

@@ -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

View File

@@ -2,7 +2,7 @@
. ./test.common . ./test.common
test_start "experimental extension field" test_start "mono+root extension field"
check_config_h 'FEAT_CMDMON 1' || test_skip check_config_h 'FEAT_CMDMON 1' || test_skip

View File

@@ -23,7 +23,7 @@ check_sync || test_fail
check_log_messages "Detected falseticker" 2 10 || test_fail check_log_messages "Detected falseticker" 2 10 || test_fail
check_log_messages "Source 192.168.123.. replaced with" 1 3 || test_fail check_log_messages "Source 192.168.123.. replaced with" 1 3 || test_fail
check_file_messages "20.*192.168.123.* 11.1 6 6 " 15 17 measurements.log || test_fail check_file_messages "20.*192.168.123.* 11.1 6 6 " 15 18 measurements.log || test_fail
check_file_messages "20.*00:[1-5].:.. 192.168.123.* 11.1 6 6 " 1 4 measurements.log || test_fail check_file_messages "20.*00:[1-5].:.. 192.168.123.* 11.1 6 6 " 1 4 measurements.log || test_fail
rm -f tmp/measurements.log rm -f tmp/measurements.log

View File

@@ -31,6 +31,7 @@ default_primary_time_offset=0.0
default_time_offset=1e-1 default_time_offset=1e-1
default_freq_offset=1e-4 default_freq_offset=1e-4
default_base_delay=1e-4 default_base_delay=1e-4
default_delay_correction=""
default_jitter=1e-4 default_jitter=1e-4
default_jitter_asymmetry=0.0 default_jitter_asymmetry=0.0
default_wander=1e-9 default_wander=1e-9
@@ -460,6 +461,10 @@ run_test() {
for j in $(seq 1 $nodes); do for j in $(seq 1 $nodes); do
echo "node${i}_delay${j} = $(get_delay_expr up)" echo "node${i}_delay${j} = $(get_delay_expr up)"
echo "node${j}_delay${i} = $(get_delay_expr down)" 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
done > tmp/conf done > tmp/conf

View File

@@ -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.1" > $TEST_DIR/conf5.d/1.sources
echo "server 127.123.5.2" > $TEST_DIR/conf5.d/2.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.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 start_chronyd || test_fail
@@ -46,12 +48,16 @@ check_chronyc_output "^[^=]*
.. 127\.123\.1\.2 [^^]* .. 127\.123\.1\.2 [^^]*
.. 127\.123\.5\.1 [^^]* .. 127\.123\.5\.1 [^^]*
.. 127\.123\.5\.2 [^^]* .. 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 rm $TEST_DIR/conf5.d/1.sources
echo "server 127.123.5.2 minpoll 7" > $TEST_DIR/conf5.d/2.sources echo "server 127.123.5.2 minpoll 5" > $TEST_DIR/conf5.d/2.sources
echo > $TEST_DIR/conf5.d/3.sources echo "server 127.123.5.3 minpoll 7" > $TEST_DIR/conf5.d/3.sources
echo "server 127.123.5.4" > $TEST_DIR/conf5.d/4.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 run_chronyc "reload sources" || test_fail
@@ -66,9 +72,12 @@ check_chronyc_output "^[^=]*
.. 127\.123\.2\.3 [^^]* .. 127\.123\.2\.3 [^^]*
.. 127\.123\.4\.4 [^^]* .. 127\.123\.4\.4 [^^]*
.. 127\.123\.1\.2 *[05] 6 [^^]* .. 127\.123\.1\.2 *[05] 6 [^^]*
.. 127\.123\.5\.2 *[05] 7 [^^]* .. 127\.123\.5\.5 [^^]*
.. 127\.123\.5\.4 [^^]*$" || test_fail .. 127\.123\.5\.2 *[05] 5 [^^]*
.. 127\.123\.5\.3 *[05] 7 [^^]*
.. 127\.123\.5\.6 [^^]*$" || test_fail
stop_chronyd || test_fail stop_chronyd || test_fail
check_chronyd_message_count "Could not add source" 1 1 || test_fail
test_pass test_pass

140
test/system/011-systemd Executable file
View File

@@ -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

View File

@@ -324,7 +324,7 @@ check_chronyd_messages() {
([ "$clock_control" -ne 0 ] || grep -q 'Disabled control of system clock' "$logfile") && \ ([ "$clock_control" -ne 0 ] || grep -q 'Disabled control of system clock' "$logfile") && \
([ "$minimal_config" -ne 0 ] || grep -q 'Frequency .* read from' "$logfile") && \ ([ "$minimal_config" -ne 0 ] || grep -q 'Frequency .* read from' "$logfile") && \
grep -q 'chronyd exiting' "$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" && \ ! grep -q 'Disabled command socket' "$logfile" && \
test_ok || test_bad test_ok || test_bad
} }

View File

@@ -1,6 +1,6 @@
/* /*
********************************************************************** **********************************************************************
* Copyright (C) Miroslav Lichvar 2017-2018 * Copyright (C) Miroslav Lichvar 2017-2018, 2023
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of version 2 of the GNU General Public License as
@@ -35,6 +35,7 @@ static struct timespec current_time;
static NTP_Packet req_buffer, res_buffer; static NTP_Packet req_buffer, res_buffer;
static int req_length, res_length; static int req_length, res_length;
#define NIO_IsHwTsEnabled() 1
#define NIO_OpenServerSocket(addr) ((addr)->ip_addr.family != IPADDR_UNSPEC ? 100 : 0) #define NIO_OpenServerSocket(addr) ((addr)->ip_addr.family != IPADDR_UNSPEC ? 100 : 0)
#define NIO_CloseServerSocket(fd) assert(fd == 100) #define NIO_CloseServerSocket(fd) assert(fd == 100)
#define NIO_OpenClientSocket(addr) ((addr)->ip_addr.family != IPADDR_UNSPEC ? 101 : 0) #define NIO_OpenClientSocket(addr) ((addr)->ip_addr.family != IPADDR_UNSPEC ? 101 : 0)
@@ -98,20 +99,16 @@ send_request(NCR_Instance inst, int late_hwts)
local_addr.ip_addr.family = IPADDR_UNSPEC; local_addr.ip_addr.family = IPADDR_UNSPEC;
local_addr.if_index = INVALID_IF_INDEX; local_addr.if_index = INVALID_IF_INDEX;
local_addr.sock_fd = 101; local_addr.sock_fd = 101;
zero_local_timestamp(&local_ts);
local_ts.ts = current_time; local_ts.ts = current_time;
local_ts.err = 0.0;
local_ts.source = NTP_TS_KERNEL; local_ts.source = NTP_TS_KERNEL;
NCR_ProcessTxKnown(inst, &local_addr, &local_ts, &req_buffer, req_length); NCR_ProcessTxKnown(inst, &local_addr, &local_ts, &req_buffer, req_length);
} }
if (late_hwts) { if (late_hwts) {
inst->had_hw_tx_timestamp = 1;
inst->report.total_good_count++; inst->report.total_good_count++;
} else { } else {
if (random() % 2)
inst->had_hw_tx_timestamp = 0;
else
inst->report.total_good_count = 0; inst->report.total_good_count = 0;
} }
} }
@@ -125,8 +122,8 @@ process_request(NTP_Remote_Address *remote_addr)
local_addr.ip_addr.family = IPADDR_UNSPEC; local_addr.ip_addr.family = IPADDR_UNSPEC;
local_addr.if_index = INVALID_IF_INDEX; local_addr.if_index = INVALID_IF_INDEX;
local_addr.sock_fd = 100; local_addr.sock_fd = 100;
zero_local_timestamp(&local_ts);
local_ts.ts = current_time; local_ts.ts = current_time;
local_ts.err = 0.0;
local_ts.source = NTP_TS_KERNEL; local_ts.source = NTP_TS_KERNEL;
res_length = 0; res_length = 0;
@@ -292,8 +289,8 @@ proc_response(NCR_Instance inst, int good, int valid, int updated_sync,
local_addr.ip_addr.family = IPADDR_UNSPEC; local_addr.ip_addr.family = IPADDR_UNSPEC;
local_addr.if_index = INVALID_IF_INDEX; local_addr.if_index = INVALID_IF_INDEX;
local_addr.sock_fd = NTP_LVM_TO_MODE(res->lvm) != MODE_SERVER ? 100 : 101; 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.ts = current_time;
local_ts.err = 0.0;
local_ts.source = NTP_TS_KERNEL; local_ts.source = NTP_TS_KERNEL;
prev_rx_count = inst->report.total_rx_count; prev_rx_count = inst->report.total_rx_count;

View File

@@ -28,6 +28,7 @@
#include <nameserv_async.h> #include <nameserv_async.h>
#include <ntp_core.h> #include <ntp_core.h>
#include <ntp_io.h> #include <ntp_io.h>
#include <sched.h>
static char *requested_name = NULL; static char *requested_name = NULL;
static DNS_NameResolveHandler resolve_handler = NULL; static DNS_NameResolveHandler resolve_handler = NULL;
@@ -41,9 +42,11 @@ static void *resolve_handler_arg = NULL;
change_remote_address(inst, remote_addr, ntp_only) change_remote_address(inst, remote_addr, ntp_only)
#define NCR_ProcessRxKnown(remote_addr, local_addr, ts, msg, len) (random() % 2) #define NCR_ProcessRxKnown(remote_addr, local_addr, ts, msg, len) (random() % 2)
#define NIO_IsServerConnectable(addr) (random() % 2) #define NIO_IsServerConnectable(addr) (random() % 2)
#define SCH_GetLastEventMonoTime() get_mono_time()
static void change_remote_address(NCR_Instance inst, NTP_Remote_Address *remote_addr, static void change_remote_address(NCR_Instance inst, NTP_Remote_Address *remote_addr,
int ntp_only); int ntp_only);
static double get_mono_time(void);
#include <ntp_sources.c> #include <ntp_sources.c>
@@ -85,6 +88,8 @@ update_random_address(NTP_Remote_Address *addr, int rand_bits)
TEST_CHECK(status == NSR_Success || status == NSR_AlreadyInUse); TEST_CHECK(status == NSR_Success || status == NSR_AlreadyInUse);
} }
TEST_CHECK(strlen(NSR_StatusToString(status)) > 0);
return status == NSR_Success; return status == NSR_Success;
} }
@@ -96,17 +101,26 @@ change_remote_address(NCR_Instance inst, NTP_Remote_Address *remote_addr, int nt
TEST_CHECK(record_lock); TEST_CHECK(record_lock);
if (update && update_pos == 0) if (update && update_pos == 0)
r = update_random_address(remote_addr, 4); r = update_random_address(random() % 2 ? remote_addr : NCR_GetRemoteAddress(inst), 4);
NCR_ChangeRemoteAddress(inst, remote_addr, ntp_only); NCR_ChangeRemoteAddress(inst, remote_addr, ntp_only);
if (update && update_pos == 1) if (update && update_pos == 1)
r = update_random_address(remote_addr, 4); r = update_random_address(random() % 2 ? remote_addr : NCR_GetRemoteAddress(inst), 4);
if (r) if (r)
TEST_CHECK(UTI_IsIPReal(&saved_address_update.old_address.ip_addr)); TEST_CHECK(UTI_IsIPReal(&saved_address_update.old_address.ip_addr));
} }
static double get_mono_time(void) {
static double t = 0.0;
if (random() % 2)
t += TST_GetRandomDouble(0.0, 100.0);
return t;
}
void void
test_unit(void) test_unit(void)
{ {

61
test/unit/socket.c Normal file
View File

@@ -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();
}

View File

@@ -253,6 +253,47 @@ test_unit(void)
TEST_CHECK(UTI_IsEqualAnyNtp64(&ntp_ts, NULL, NULL, &ntp_ts)); TEST_CHECK(UTI_IsEqualAnyNtp64(&ntp_ts, NULL, NULL, &ntp_ts));
TEST_CHECK(!UTI_IsEqualAnyNtp64(&ntp_ts, &ntp_fuzz, &ntp_fuzz, &ntp_fuzz)); 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_sec = 1;
ts.tv_nsec = 2; ts.tv_nsec = 2;
ts2.tv_sec = 1; ts2.tv_sec = 1;

29
util.c
View File

@@ -3,7 +3,7 @@
********************************************************************** **********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003 * Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009, 2012-2021 * Copyright (C) Miroslav Lichvar 2009, 2012-2023
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of version 2 of the GNU General Public License as
@@ -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 */ /* Maximum offset between two sane times */
#define MAX_OFFSET 4294967296.0 #define MAX_OFFSET 4294967296.0

4
util.h
View File

@@ -163,6 +163,10 @@ extern void UTI_Ntp64ToTimespec(const NTP_int64 *src, struct timespec *dest);
/* Calculate a - b in any epoch */ /* Calculate a - b in any epoch */
extern double UTI_DiffNtp64ToDouble(const NTP_int64 *a, const NTP_int64 *b); 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 */ /* Check if time + offset is sane */
extern int UTI_IsTimeOffsetSane(const struct timespec *ts, double offset); extern int UTI_IsTimeOffsetSane(const struct timespec *ts, double offset);