Compare commits

...

152 Commits

Author SHA1 Message Date
Miroslav Lichvar
9d869d8709 doc: update NEWS 2021-04-22 10:44:50 +02:00
Miroslav Lichvar
4f94e22b4b doc: update README 2021-04-22 10:20:31 +02:00
Miroslav Lichvar
d9b720471d ntp: fix address in error message 2021-04-22 10:20:31 +02:00
Miroslav Lichvar
039b388c82 nameserv: avoid sockaddr_in6 with disabled IPv6 support
Fixes: 10c760a80c ("nameserv: require getaddrinfo() and getnameinfo()")
2021-04-22 10:20:31 +02:00
Miroslav Lichvar
3f6528da77 test: extend 129-reload test 2021-04-22 10:20:31 +02:00
Miroslav Lichvar
4f43c060a3 sources: fix loading of refclock dump files
Allow zero stratum in loaded dump files.

Fixes: f8610d69f0 ("sources: improve handling of dump files and their format")
2021-04-22 10:20:31 +02:00
Miroslav Lichvar
3e55fe6919 sources: don't print NULL string to dump file
For reference clocks, which don't have a name, print "." instead of
NULL.

Fixes: f8610d69f0 ("sources: improve handling of dump files and their format")
2021-04-22 10:20:31 +02:00
Miroslav Lichvar
754097944b nts: handle negotiated server as FQDN
The NTS RFC requires the recipient of the Server Negotiation NTS-KE
record to handle the name as a fully qualified domain name. Add a
trailing dot if not present to force the name to be resolved as one.
2021-04-22 10:20:31 +02:00
Miroslav Lichvar
dd6a25edf2 test: extend 106-refclock test 2021-04-22 10:20:31 +02:00
Miroslav Lichvar
e697833976 doc: improve description of allow directive
Prefer CIDR notation, clarify use of hostnames and order of allow/deny
directives, refer to the accheck command.
2021-04-22 10:20:31 +02:00
Bryan Christianson
40d80624f6 sys_timex: remove workaround for broken ntp_adjtime on macOS
Early beta releases of macOS Big Sur had a signed/unsigned error in
Apple's implementation of ntp_adjtime. Apple have since fixed this error
and the workaround is no longer required.
2021-04-20 15:30:47 +02:00
Miroslav Lichvar
9a716cc284 doc: improve FAQ 2021-04-15 15:17:13 +02:00
Miroslav Lichvar
13a78ecd2f conf: require sourcedir files to be terminated by newline
When reading a *.sources file require that each line is termined by the
newline character to avoid processing an unfinished line, e.g. due to an
unexpected call of the reload command when the file is being written in
place.
2021-04-15 15:17:13 +02:00
Miroslav Lichvar
a9f0c681cb test: make system tests more reliable 2021-04-15 15:17:13 +02:00
Miroslav Lichvar
862aa285a2 test: update and extend 110-chronyc test 2021-04-15 15:17:13 +02:00
Miroslav Lichvar
84d2811800 ntp: add copy option
When separate client and server instances of chronyd are running on one
computer (e.g. for security or performance reasons) and are synchronized
to each other, the server instance provides a reference ID based on the
local address used for synchronization of its NTP clock, which breaks
detection of synchronization loops for its own clients.

Add a "copy" option to specify that the server and client are closely
related, no loop can form between them, and the client should assume the
reference ID and stratum of the server to fix detection of loops between
the server and clients of the client.
2021-04-15 15:17:13 +02:00
Miroslav Lichvar
635a9d3f5a ntp: clamp remote stratum
Don't set the remote stratum (used for polling adjustments) to values
larger than 16.
2021-04-15 15:17:13 +02:00
Miroslav Lichvar
81f7f6ddf0 ntp: don't update source status with unsynchronized data
Don't update the leap and stratum used in source selection if they
indicate an unsynchronized source.

Fixes: 2582be8754 ("sources: separate update of leap status")
2021-04-15 15:16:39 +02:00
Uwe Kleine-König
aa22c515ce refclock: drop return after LOG_FATAL
The LOG_FATAL macro expands to (emitting the message and then) exit(1).
So a return after LOG_FATAL isn't reached. Drop all those to simplify
the code a bit.
2021-04-12 09:24:07 +02:00
Miroslav Lichvar
2ca2c85365 ntp: fix loop test for special reference modes
It is not sufficient to check for disabled server sockets as they are
not open only after the special reference modes end (e.g. initstepslew).

Fixes: 004986310d ("ntp: skip loop test if no server socket is open")
2021-04-07 17:14:22 +02:00
Foster Snowhill
966e6fd939 sys_linux: allow setsockopt(SOL_IP, IP_TOS) in seccomp
This system call is required by the DSCP marking feature introduced in commit
6a5665ca58 ("conf: add dscp directive").

Before this change, enabling seccomp filtering (chronyd -F 1) and specifying a
custom DSCP value in the configuration (for example "dscp 46") caused the
process to be killed by seccomp due to IP_TOS not being allowed by the filter.

Tested before and after the change on Ubuntu 21.04, kernel 5.11.0-13-generic.
IP_TOS is available since Linux 1.0, so I didn't add any ifdefs for it.

Signed-off-by: Foster Snowhill <forst@forstwoof.ru>
2021-04-07 17:14:22 +02:00
Miroslav Lichvar
4f0dd72cf0 doc: improve chrony.conf man page 2021-04-07 17:14:22 +02:00
Miroslav Lichvar
69aa2eff99 doc: improve FAQ
Add new questions, fix typos and version-specific information.
2021-04-07 17:14:09 +02:00
Miroslav Lichvar
3e1ec36ca5 test: extend 103-initstepslew test 2021-04-07 16:55:38 +02:00
Miroslav Lichvar
224ab8ddb1 test: enable valgrind in more tests 2021-03-24 17:50:33 +01:00
Miroslav Lichvar
307c2ec70f test: extend 106-refclock test 2021-03-18 17:41:36 +01:00
Miroslav Lichvar
5381fb4ee9 refclock: increase PPS lock limit
Increase the maximum acceptable offset of the PPS lock reference from
20% to 40% of the PPS interval to not require the refclock offset to be
specified in configuration so accurately, or enable operation with a
highly unstable reference clock.
2021-03-18 17:41:28 +01:00
Miroslav Lichvar
3812ec2aa2 declare variables set from signal handlers as volatile
Make sure variables set from signal handlers are not cached in
registers.
2021-03-18 17:38:18 +01:00
Kamil Dudka
4e7690ebec configure: use well-known file name conftest.c
... for configuration checks.  Compiler wrappers check for this name
in order to skip any instrumentation of the build that is intended
for regular source files only.
2021-03-15 10:42:48 +01:00
Miroslav Lichvar
cf3d976a68 test: extend ntp_sources unit test 2021-03-11 11:47:48 +01:00
Miroslav Lichvar
26fc28c056 test: drop logging suspension
Instead of selectively suspending logging by redirecting messages to
/dev/null, increase the default minimum log severity to FATAL. In the
debug mode, all messages are printed.
2021-03-11 11:47:31 +01:00
Miroslav Lichvar
d2117ab697 cmdmon: return error if doffset command fails 2021-03-04 17:26:00 +01:00
Miroslav Lichvar
52b29f673f cmdmon: convert doffset request to float 2021-03-04 17:26:00 +01:00
Miroslav Lichvar
e86b60a9d7 local: return status from offset accumulation
Change the functions accumulating offset to return success or failure.
2021-03-04 17:26:00 +01:00
Miroslav Lichvar
53501b743f client: report invalid values in doffset and dfreq commands 2021-03-04 17:26:00 +01:00
Miroslav Lichvar
c61ddb70da test: extend util unit test 2021-03-04 17:26:00 +01:00
Miroslav Lichvar
9339766bfe test: use env shebang in all bash scripts
This allows the scripts to be executed on systems that don't have bash
in /bin. This fixes "make check".
2021-03-04 12:36:36 +01:00
Miroslav Lichvar
f60410016a test: extend 007-cmdmon system test 2021-03-04 12:36:36 +01:00
Miroslav Lichvar
7a02371698 util: require inet_pton()
Always use inet_pton() for converting IP addresses. It should be
available on all currently supported systems.
2021-03-04 12:36:36 +01:00
Miroslav Lichvar
579d8c9907 nameserv: avoid unnecessary getaddrinfo() calls
Check if the name passed to DNS_Name2IPAddress() is an IP address
before calling getaddrinfo(), which can be much slower and work
differently on different systems.
2021-03-04 12:36:36 +01:00
Miroslav Lichvar
10c760a80c nameserv: require getaddrinfo() and getnameinfo()
Remove support for the long-deprecated gethostbyname() and
gethostbyaddr() functions.
2021-03-04 12:36:36 +01:00
Miroslav Lichvar
2d39a12f51 cmdmon: fix responding to IPv4 addresses on FreeBSD
On FreeBSD, the source address cannot be specified when sending a
message on a socket bound to a non-any IPv4 address, e.g. in default
configuration 127.0.0.1. In this case, make the address unspecified.

This is similar to commit 6af39d63aa ("ntp: don't use IP_SENDSRCADDR
on bound socket").

Fixes: f06c1cfa97 ("cmdmon: respond from same address")
2021-03-04 12:36:36 +01:00
Miroslav Lichvar
517b1ae29a main: suppress info messages with -p option
Log (to stderr) only warnings and higher when printing the
configuration to suppress the "chronyd starting" message.
2021-03-04 12:36:23 +01:00
Miroslav Lichvar
b7347d931b sys_linux: check if statx syscall is defined
statx seems to be missing in older kernel and libseccomp headers, still
used on some supported systems.
2021-03-03 10:04:07 +01:00
Miroslav Lichvar
4f878ba144 main: warn if running with root privileges
Log a warning message if the main process has not dropped the root
privileges, i.e. when the compiled-in user or user specified by the user
directive or -u option is root.
2021-02-25 17:06:14 +01:00
Miroslav Lichvar
8acdb5d1e2 refclock: warn if lock refid is invalid
Log a warning message if the specified lock refid doesn't match any
existing refclock or it matches the refclock which has the lock option
itself.
2021-02-25 17:06:13 +01:00
Miroslav Lichvar
62f2d5736d refclock: warn if maxlockage is too small
Log a warning message if the interval covered by the maxlockage at the
PPS rate of a refclock is shorter than driver poll of the locked
refclock.

Reported-by: Matt Corallo <ntp-lists@mattcorallo.com>
2021-02-25 17:06:10 +01:00
Miroslav Lichvar
dc22df93f5 ntp: restart resolving on online command
If the online command is received when the resolver is running, start
it again as soon as it finishes instead of waiting for the timer.

This should reduce the time needed to get all sources resolved on boot
if chronyd is started before the network is online and the chronyc
online command is issued before the first round of resolving can finish,
e.g. due to an unreachable DNS server in resolv.conf.
2021-02-25 17:02:58 +01:00
Miroslav Lichvar
d898bd246b test: extend 139-nts test 2021-02-18 17:44:04 +01:00
Miroslav Lichvar
ebf0ff2c0d cmdmon: set certset for new sources
Add the new certset option to the cmdmon protocol.
2021-02-18 17:44:04 +01:00
Miroslav Lichvar
cc77b0e9fd conf: add certset option to NTP sources
Allow the set of trusted certificates to be selected for each NTP
source individually.
2021-02-18 17:44:04 +01:00
Miroslav Lichvar
a8bc25e543 conf: add set selection to ntstrustedcerts
Add an optional set-ID argument to the ntstrustedcerts directive to
enable multiple sets of trusted certificates to be specified.
2021-02-18 17:44:04 +01:00
Miroslav Lichvar
6615bb1b78 nts: add support for multiple sets of trusted certificates
Modify the session, NTS-KE, and NTS-NTP code to support multiple sets of
trusted certificates and identify the sets by a 32-bit ID.
2021-02-18 17:44:04 +01:00
Miroslav Lichvar
f650b8c515 configure: check for O_NOFOLLOW flag
If the O_NOFOLLOW flag used by open() is not defined, try it with
_GNU_SOURCE. This is needed with glibc-2.11 and earlier.

Reported-by: Marius Rohde <marius.rohde@meinberg.de>
2021-02-16 13:59:41 +01:00
Christian Ehrhardt
ae2e0318d1 sys_linux: allow statx and fstatat64 in seccomp filter
With glibc 2.33 on armhf statx and fstatat64 are triggered.
Allow this call to un-break chrony on such platforms.

Without this e.g. test 005-scfilter fails and with ltrace -rTS reports:
a)
  0.001684 SYS_397(11, 0xf75def08, 6144, 2047 <no return ...>
  0.759239 +++ killed by SIGSYS +++
b)
  0.003749 SYS_327(-100, 0xffdbcc3c, 0xffdbcb50, 0)
  0.000821 --- SIGSYS (Bad system call) ---

Current armhf syscalls from:
https://github.com/torvalds/linux/blob/v5.10/arch/arm/tools/syscall.tbl

Signed-off-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
2021-02-12 11:01:22 +01:00
Miroslav Lichvar
26ce610155 nts: allow ntstrustedcerts to specify directory
If the specified path is a directory, load all certificates in the
directory.
2021-02-11 16:13:39 +01:00
Miroslav Lichvar
316d47e3b4 nts: allow multiple files with trusted certificates
Allow the ntstrustedcerts directive to be specified multiple times.
2021-02-11 16:13:39 +01:00
Miroslav Lichvar
90557cf1ba nts: allow multiple server keys and certificates
Allow the ntsservercert and ntsserverkey directives to be specified
multiple times to enable the NTS-KE server to operate under multiple
names.
2021-02-11 16:13:39 +01:00
Miroslav Lichvar
80e627c86b nts: define type for credentials
Add a NKSN_Credentials type to avoid referring to it as void *.
2021-02-11 16:13:39 +01:00
Miroslav Lichvar
0e4995e10b nts: split creating server and client credentials 2021-02-11 16:13:39 +01:00
Miroslav Lichvar
a598983f9b client: fix sourcename command to accept ID addresses
Fix the command to print the name corresponding to an unresolved
address.
2021-02-11 16:13:39 +01:00
Miroslav Lichvar
27641876c5 ntp: simplify NSR_Finalise() 2021-02-11 16:13:39 +01:00
Miroslav Lichvar
4d139eeca6 ntp: limit number of sources
Don't rely on assertions and running out of memory to terminate if
an extremely large number of sources is added. Set the maximum number
to 65536 to have a practical limit where chronyd still has a chance to
appear functional with some operations having a quadratic time
complexity.
2021-02-11 16:13:39 +01:00
Miroslav Lichvar
3f2806c19c nts: reset NTP address/port if removed in NTS-KE
When an NTS-KE server stops providing the NTP address or port, change
them to the original values to avoid the client getting stuck
with a non-responding address/port.
2021-02-11 15:24:12 +01:00
Miroslav Lichvar
e297df78e4 nts: load cookies early
Instead of waiting for the first request, try to load the cookies as
soon as the instance is created, or the NTS address is changed.

This enables loading of dump files for servers that are negotiated in
NTS-KE.
2021-02-11 09:52:57 +01:00
Miroslav Lichvar
c1d56ede3f nts: rework update of NTP server address
In the NTS-NTP client instance, maintain a local copy of the NTP address
instead of using a pointer to the NCR's address, which may change at
unexpected times.

Also, change the NNC_CreateInstance() to accept only the NTP port to
make it clear the initial NTP address is the same as the NTS-KE address
and to make it consistent with NNC_ChangeAddress(), which accepts only
one address.
2021-02-11 09:52:57 +01:00
Miroslav Lichvar
2e52aca3bf ntp: avoid recursive update of address
Allow NSR_UpdateSourceNtpAddress() to be (indirectly) called from
NCR_CreateInstance() and NCR_ChangeRemoteAddress(). In these cases, save
the addresses and make the update later when the function calls return.
2021-02-11 09:52:57 +01:00
Miroslav Lichvar
b0fc5832f4 ntp: require port match in address update
In NSR_UpdateSourceNtpAddress() and other updates of the address require
that the old port matches the current source's port.
2021-02-11 09:52:57 +01:00
Miroslav Lichvar
cf6af112e1 test: extend 129-reload test 2021-02-04 17:48:51 +01:00
Miroslav Lichvar
fa3052e776 sources: set reference after loading dump files
After loading the dump files with the -r option, immediately perform a
source selection with forced setting of the reference. This shortens the
interval when a restarted server doesn't respond with synchronized time.
It no longer needs to wait for the first measurement from the best
source (which had to pass all the filters).
2021-02-04 17:48:47 +01:00
Miroslav Lichvar
f8610d69f0 sources: improve handling of dump files and their format
Check for write errors when saving dump files. Don't save files with no
samples. Add more sanity checks for loaded data.

Extend the file format to include an identifier, the reachability
register, leap status, name, and authentication flag. Avoid loading
unauthenticated data after switching authentication on. Change format
and order of some fields to simplify parsing. Drop fields that were kept
only for compatibility.

The dump files now contain all information needed to perform the source
selection and update the reference.

There is no support kept for the old file format. Loading of old dump
files will fail after upgrading to new version.
2021-02-04 17:44:27 +01:00
Miroslav Lichvar
1a8dcce84f sources: update stratum with leap status
Remove stratum from the NTP sample and update it together with the leap
status. This enables a faster update when samples are dropped by the NTP
filters.
2021-02-04 17:43:47 +01:00
Miroslav Lichvar
f74eb67567 sourcestats: move stratum to sources
The stratum value is not needed in sourcestats. Keep it in the source
itself.
2021-02-04 17:43:29 +01:00
Miroslav Lichvar
144fcdde34 main: fix typo in comment 2021-02-03 17:51:47 +01:00
Miroslav Lichvar
3cef7f975c main: cancel clock correction before dumping sources
On exit, cancel the remaining clock correction before measurements are
saved to dumpdir to fix them for the state in which chronyd will start
again.
2021-02-03 11:06:00 +01:00
Baruch Siach
a2372b0c3a sys_linux: fix build with older kernel headers
The renameat2 system call was introduced in kernel version 3.15. Fix
build against older headers.
2021-01-28 15:32:03 +01:00
Miroslav Lichvar
362d7c517d test: improve NTS tests 2021-01-14 18:17:48 +01:00
Miroslav Lichvar
62389b7e50 nts: support servers specified by IP address
Certificates can include IP addresses as alternative names to enable
clients to verify such certificates without knowing the hostname.

Accept an IP address as a name in the NTS-NTP client and modify the
session code to not set the SNI in this case.
2021-01-14 18:17:48 +01:00
Miroslav Lichvar
eb9e6701fd ntp: allow replacement of sources specified by IP address
For sources specified by an IP address, keep the original address as the
source's name and pass it to the NCR instance. Allow the sources to go
through the replacement process if their address has changed.

This will be useful with NTS-KE negotiation.

The IP-based source names are now provided via cmdmon. This means
chronyc -n and -N can show two different addresses for a source.
2021-01-14 18:17:48 +01:00
Miroslav Lichvar
b585954b21 ntp: fix NULL pointer 2021-01-14 18:17:48 +01:00
Miroslav Lichvar
82ddc6a883 test: support ss as netstat replacement
netstat is considered obsolete on Linux. It is replaced by ss from
iproute. Support both tools for the test port selection.
2021-01-14 18:17:48 +01:00
Miroslav Lichvar
624b76e86e test: fix port selection to disable grep output 2021-01-14 18:17:48 +01:00
Miroslav Lichvar
4dd0aece02 test: make 120-selectoptions more reliable
Remove packet interval checks with long delays as the tests are much
more likely to end when the client is waiting for a response. Increase
the base delay to make selection with two sources more reliable.

Reported-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
2021-01-14 18:17:48 +01:00
Miroslav Lichvar
e85fb0c25e socket: add debug message for unexpected control message 2021-01-14 18:17:48 +01:00
Miroslav Lichvar
fc8783a933 socket: check length of received control messages
Make sure each processed control messages has the expected length.
Beside improved safety, this should prevent potential issues with broken
timestamps on systems that support both 64-bit and 32-bit time_t.
2021-01-14 18:17:48 +01:00
Miroslav Lichvar
e7897eb9cc sched: stop dispatching timeouts on exit
Check in the dispatch loop whether the need_to_exit flag was set.
2021-01-14 18:17:48 +01:00
Miroslav Lichvar
59e8b79034 sched: improve infinite loop detection
The "infinite loop in scheduling" fatal error was observed on a system
running out of memory. Presumably, the execution of the process slowed
down due to memory thrashing so much that the dispatching loop wasn't
able to break with a single server polled at a 16-second interval.

To allow recovery in such a case, require for the error more than
20 handled timeouts and a rate higher than 100 per second.

Reported-by: Jamie Gruener <jamie.gruener@biospatial.io>
2021-01-14 18:17:39 +01:00
Michael Witten
fb7475bf59 rtc: log error message when driver initialisation fails 2020-12-15 10:49:07 +01:00
Michael Witten
cd98516cae doc: diagnose problem with RTC interrupts on Linux
This commit updates the FAQ with a new entry.

chronyd's Linux RTC driver (rtc_linux.c) requires the following ioctl
requests to be functional:

  RTC_UIE_ON
  RTC_UIE_OFF

However, a Linux system's RTC driver does not necessarily implement them,
as noted in these previous commits:

  d66b2f2b24
  rtc: handle RTCs that don't support interrupts
  Tue Dec 10 17:45:28 2019 +0100

  bff3f51d13
  rtc: extend check for RTCs that don't support interrupts
  Thu Dec 12 12:50:19 2019 +0100

Fortunately, the Linux kernel can be built with software emulation of
these hardware requests, by enabling the following config variable:

  CONFIG_RTC_INTF_DEV_UIE_EMUL
    Provides an emulation for RTC_UIE if the underlying rtc chip
    driver does not expose RTC_UIE ioctls. Those requests generate
    once-per-second update interrupts, used for synchronization.

    The emulation code will read the time from the hardware
    clock several times per second, please enable this option
    only if you know that you really need it.

This commit records these facts for the benefit of the user.
2020-12-15 10:41:53 +01:00
Miroslav Lichvar
e399d8dd1f doc: fix ntsntpserver reference in chrony.conf man page
Fix the name of ntsntpserver directive in ntsrotate description.

Reported-By: Phil Roberts <phil@robertskeys.net>
2020-11-26 15:09:38 +01:00
Miroslav Lichvar
d327cfea5a nts: save new server keys on start
If ntsdumpdir is specified and the server NTS keys are not reloaded from
the file, save the generated keys on start instead of waiting for the
first rotation or exit. This allows the keys to be shared with another
server without having to use the dump command.
2020-10-07 17:27:34 +02:00
Miroslav Lichvar
c94e7c72e7 conf: free refclock strings on exit
Free driver name and parameter of configured refclocks in helpers on
exit.
2020-10-07 17:27:34 +02:00
Miroslav Lichvar
f3aea33ad4 ntp: avoid unnecessary replacement attempts
In the initial resolving of pool sources try to assign each address only
once. If it fails, it means the address is already used (DNS provided
the same address) or the address is not connectable. The same result can
be expected for other unresolved sources of the pool as they don't have
a real address yet.
2020-10-07 17:27:34 +02:00
Miroslav Lichvar
48709d9c4a fix compiler warnings
Fix -Wchar-subscripts warnings on NetBSD and warnings about pointer
aliasing and uninitialized values with an older compiler.
2020-10-07 17:27:32 +02:00
Miroslav Lichvar
4779adcb50 doc: improve FAQ 2020-10-05 18:56:37 +02:00
Miroslav Lichvar
01e29ec685 doc: improve ntsrotate description 2020-10-05 18:56:37 +02:00
Miroslav Lichvar
e4cccc115d sys_netbsd: don't check access to /dev/clockctl with -x
With the -x option there is no need for write access to /dev/clockctl.
2020-10-05 18:56:37 +02:00
Miroslav Lichvar
8e9716d5d4 sys: don't start privops helper for NTS-KE helper
The NTS-KE helper doesn't need to bind sockets or adjust the clock.
Don't start the privops helper, or keep the capabilities, when dropping
root privileges in its context.
2020-10-05 18:56:37 +02:00
Miroslav Lichvar
a96d288027 sys: specify process context for dropping root
Similarly to enabling the syscall filter, specify what kind of chronyd
process is dropping the root privileges.
2020-10-05 18:56:37 +02:00
Miroslav Lichvar
545d2563ef configure: don't check for getrandom when arc4random is present
On FreeBSD 12, both functions seem to be available. Prefer arc4random.
2020-10-05 18:56:37 +02:00
Miroslav Lichvar
1494ef1df3 test: improve sources unit test 2020-10-05 18:56:37 +02:00
Miroslav Lichvar
698f270b5b cmdmon: add leap status to selectdata report 2020-10-05 18:56:37 +02:00
Miroslav Lichvar
f15f6a86b0 sched: include unexpected jumps in monotonic time
Update the monotonic time before the timestamps are corrected for
unexpected jumps, e.g. due to the computer being suspended and resumed,
and switch to the raw timestamps. This should allow the NTS refresh
interval to better follow real time, but it will not be corrected for
a frequency offset if the clock is not synchronized (e.g. with -x).
2020-10-05 18:56:37 +02:00
Miroslav Lichvar
5d60d611ae cmdmon: fix link-local address check
Don't check for a link-local address on path of a Unix domain socket.

Fixes: 4e747da4b4 ("ntp+cmdmon: fix responding to link-local addresses")
2020-10-05 18:56:37 +02:00
Miroslav Lichvar
6e71e902c8 socket: process all message headers
If multiple messages were received, don't stop their processing if some
header fails.

Fixes: 86a3ef9ed1 ("socket: add new socket support")
2020-10-05 18:56:37 +02:00
Miroslav Lichvar
473cb3c968 socket: always process control messages
Even if a received message will not be returned to the caller (e.g.
because it is truncated), process its control messages to avoid leaking
received descriptors.

Fixes: f231efb811 ("socket: add support for sending and receiving descriptors")
2020-10-05 18:56:37 +02:00
Miroslav Lichvar
df43ebe9e0 test: make 007-cmdmon test more reliable 2020-10-01 12:58:17 +02:00
Miroslav Lichvar
642173e864 client: drop unnecessary function
Replace cvt_to_sec_usec() with a UTI_DoubleToTimespec() call.
2020-10-01 12:58:17 +02:00
Miroslav Lichvar
944cf6e318 util: fix UTI_BytesToHex() to handle zero-length input 2020-10-01 12:58:17 +02:00
Miroslav Lichvar
a655eab34f nts: handle invalid algorithm in TLS key export 2020-10-01 12:58:17 +02:00
Miroslav Lichvar
f020d479e0 nts: fix server kod setting
Set the response kod value to zero even if NTS server is disabled.
2020-10-01 12:58:17 +02:00
Miroslav Lichvar
de752b28de nts: save server name in client dump file
Save the NTS-KE server name and require it to match the name of the
instance loading the file.
2020-10-01 12:58:17 +02:00
Miroslav Lichvar
f41d370e6a nts: update client state earlier
Generate a new uniq ID on each client poll to invalidate responses to
the previous request, even if a new request cannot be generated (e.g.
due to missing cookies). Reset the NAK indicator earlier in the request
sequence. Also, drop the cookie even if it's not included in the request
to prevent the client from getting stuck with a cookie that has an
invalid length. Rely on the exponentially increasing interval to avoid
frequent NTS-KE sessions due to a client bug.
2020-10-01 12:57:29 +02:00
Miroslav Lichvar
a97830d9d6 doc+examples: update http links to https 2020-09-23 15:10:43 +02:00
Miroslav Lichvar
ea4fc47cda client: improve help message
Describe all chronyc options in the help message.
2020-09-23 15:10:43 +02:00
Miroslav Lichvar
0e08ca7c89 main: improve help message
Describe all chronyd options in the help message.
2020-09-23 15:10:43 +02:00
Miroslav Lichvar
068cd3c311 doc: document long options
Document the --version and --help options in chronyd and chronyc man
page.
2020-09-23 15:10:43 +02:00
Miroslav Lichvar
455b8e4b44 test: include CMAC keys in ntp_core unit test 2020-09-23 15:10:43 +02:00
Miroslav Lichvar
d9a363606b nts: reset packet length after failed auth encryption
If encryption of the NTS authenticator field fails, don't leave
uninitialized data in the packet in case a bug causes the packet to be
sent.
2020-09-23 15:10:43 +02:00
Miroslav Lichvar
59ad433b6b ntp: improve NTS check in NAU_DestroyInstance()
Check the mode instead of the nts pointer to make it clear the pointer
is not expected to be NULL in an NTS instance (unless the NTS support is
stubbed).
2020-09-23 15:10:37 +02:00
Miroslav Lichvar
35b3a42ed9 ntp: update comments with new RFCs 2020-09-21 14:07:05 +02:00
Miroslav Lichvar
0639205617 doc: update NEWS 2020-09-16 12:09:52 +02:00
Miroslav Lichvar
3916c3366b update copyright years 2020-09-16 12:09:52 +02:00
Miroslav Lichvar
f0a33e7b28 client: drop support for GNU readline
GNU readline switched to GPLv3+ in version 6.0, which is incompatible
with the chrony's GPLv2 license.

Drop support for the readline library. Only editline is supported now.
2020-09-16 12:09:52 +02:00
Miroslav Lichvar
c9b8f8bc70 doc: update and improve FAQ 2020-09-16 12:09:50 +02:00
Miroslav Lichvar
983b0723f6 doc: improve chronyd man page 2020-09-16 12:07:19 +02:00
Miroslav Lichvar
02c38934ea main: add option to disable check for root
The -U option can be used to start chronyd under a non-root user if it
is provided with all capabilities and access to files, directories, and
devices, needed to operate correctly in the specified configuration. It
is not recommended in cases where the configuration is unknown.
2020-09-16 11:39:16 +02:00
Miroslav Lichvar
c28c2cde43 sys_linux: don't keep NET_BIND_SERVICE for unprivileged port
Don't keep the NET_BIND_SERVICE capability if the configured NTP port is
not privileged (i.e. not smaller than 1024).
2020-09-16 11:15:29 +02:00
Miroslav Lichvar
349323dec7 sys_linux: don't keep NET_RAW on new kernels
It seems the NET_RAW capability is no longer needed to bind a socket to
a device since Linux 5.7.
2020-09-16 11:15:29 +02:00
Miroslav Lichvar
ddfaf2e542 ntp: log error when SIOCSHWTSTAMP fails with EPERM
Increase the severity of the log message to "error" when
the SIOCSHWTSTAMP ioctl fails due missing the NET_ADMIN capability.
2020-09-16 11:15:29 +02:00
Miroslav Lichvar
3177474ae8 configure: require TLS1.3 support in gnutls
Before enabling NTS support, explicitly check for TLS1.3 support in
gnutls, which is required by NTS.
2020-09-16 11:15:29 +02:00
Miroslav Lichvar
cc535632d1 test: add ntp_auth unit test 2020-09-16 11:15:29 +02:00
Miroslav Lichvar
cb8ee57b9e test: fix ntp_core unit test
Fix setting of key_id in the response.

Fixes: f6625717cd ("test: improve ntp_core unit test")
2020-09-16 11:15:16 +02:00
Miroslav Lichvar
c0b19b3fea doc: improve chrony.conf man page 2020-09-10 15:04:27 +02:00
Miroslav Lichvar
8235da6885 doc: improve chronyc man page 2020-09-10 14:16:48 +02:00
Miroslav Lichvar
f6625717cd test: improve ntp_core unit test 2020-09-10 13:32:39 +02:00
Miroslav Lichvar
fdfcabd79b ntp: drop support for long NTPv4 MACs
Don't accept NTPv4 packets which have a MAC longer than 24 octets to
strictly follow RFC 7822, which specifies the maximum length of a MAC
and the minimum length of the last extension field to avoid an ambiguity
in parsing of the packet.

This removes an ugly hack that was needed to accept packets that
contained one or more extension fields without a MAC, before RFC 7822
was written and NTP implementations started using truncated MACs.

The long MACs were used by chrony in versions 2.x when configured to
authenticate a server or peer with a key using a 256-bit or longer hash
(e.g. SHA256). For compatibility with chrony >= 4.0, these clients/peers
will need to have "version 3" added to the server/peer line in
chrony.conf.
2020-09-10 13:31:57 +02:00
Miroslav Lichvar
2bb88b45c6 siv: return error if key is not set
Avoid encryption or decryption using uninitialized data, or causing a
crash, if a key was not set for the SIV instance.
2020-09-10 09:36:35 +02:00
Miroslav Lichvar
9820c22c1d nts: improve NTP client code
Reset the client instance more thoroughly and make sure the
nonce cannot be reused.
2020-09-10 09:36:35 +02:00
Miroslav Lichvar
bcd7bad467 client: improve help message for sources command 2020-09-10 09:36:35 +02:00
Miroslav Lichvar
83ea9fe284 cmdmon: rename status constants
Change the naming of reported selection status in the sources report to
better match the internal status.
2020-09-10 09:36:35 +02:00
Miroslav Lichvar
c74d6e458d sources: don't report untrusted sources as selectable
Show untrusted sources with the '?' symbol instead of '-' to make them
consistent with not selectable and selectable sources in the selectdata
description.
2020-09-10 09:36:35 +02:00
Miroslav Lichvar
ff466439fc configure: fix building with -NTP -CMDMON +SCFILTER
Don't enable privileged operations using the nameserv code unless
NTP is enabled.
2020-09-10 09:36:35 +02:00
Miroslav Lichvar
0fcdf4389b nts: log early client NTS-KE socket errors
Log an error message when SCK_OpenTcpSocket() fails in the NTS-KE
client, e.g. when connect() fails due to the port not being allowed in
the SELinux policy.
2020-09-10 09:36:35 +02:00
Miroslav Lichvar
9cb9021c87 cmdmon: remove unused test code 2020-09-09 14:14:54 +02:00
Miroslav Lichvar
9c36236742 cmdmon: check response length before sending
Before sending a cmdmon response, make sure it is not longer than the
request to avoid amplification in case the response/padding length is
incorrectly specified for a request.
2020-09-09 14:14:54 +02:00
Vincent Blut
adebb027be sys_linux: allow readlinkat in seccomp filter 2020-09-01 14:29:43 +02:00
Miroslav Lichvar
7d3798d7cd examples: improve chrony-wait service
Use the systemd TimeoutStartSec setting to report a timeout instead of
an error and reduce the timeout to 3 minutes.
2020-09-01 12:05:06 +02:00
Miroslav Lichvar
b7c7c293e5 conf: add clockprecision directive
Make the precision of the system clock configurable. This can be useful
on servers using hardware timestamping to reduce the amount of noise
added to the NTP timestamps and improve stability of NTP measurements.
2020-09-01 11:21:46 +02:00
Miroslav Lichvar
9ca250755f sys_linux: allow lstat and readlink in seccomp filter
These syscalls seem to be needed when gnutls is loading system trusted
certificates due to p11-kit >= 0.23.21 getting the program name from
/proc/self/exe.
2020-09-01 09:42:31 +02:00
Bryan Christianson
bd3b36865e test: extend frequency in ntp_adjtime() test
Extend the frequency range in the test to cover negative frequencies.
2020-08-31 10:17:21 +02:00
Bryan Christianson
538e1c5eb1 sys_timex: add workaround for broken ntp_adjtime() on macOS
On macOS 11.0 (Big Sur) beta, ntp_adjtime() incorrectly returns
timex.freq as an unsigned number. This patch is a workaround for the bug
and should be removed when Apple fix the problem (assuming they will).
2020-08-31 10:16:51 +02:00
150 changed files with 3628 additions and 1387 deletions

33
NEWS
View File

@@ -1,3 +1,27 @@
New in version 4.1
==================
Enhancements
------------
* Add support for NTS servers specified by IP address (matching
Subject Alternative Name in server certificate)
* Add source-specific configuration of trusted certificates
* Allow multiple files and directories with trusted certificates
* Allow multiple pairs of server keys and certificates
* Add copy option to server/pool directive
* Increase PPS lock limit to 40% of pulse interval
* Perform source selection immediately after loading dump files
* Reload dump files for addresses negotiated by NTS-KE server
* Update seccomp filter
* Restart ongoing name resolution on online command
Bug fixes
---------
* Fix responding to IPv4 command requests on FreeBSD
* Fix dump files to not include uncorrected offset
* Fix initstepslew to accept time from own NTP clients
* Reset NTP address and port when no longer negotiated by NTS-KE server
New in version 4.0
==================
@@ -8,11 +32,13 @@ Enhancements
* Add authselectmode directive to control selection of unauthenticated sources
* Add binddevice, bindacqdevice, bindcmddevice directives
* Add confdir directive to better support fragmented configuration
* Add sourcedir directive and "reload sources" command to support
dynamic NTP sources specified in files
* Add sourcedir directive and "reload sources" command to support dynamic
NTP sources specified in files
* Add clockprecision directive
* Add dscp directive to set Differentiated Services Code Point (DSCP)
* Add -L option to limit log messages by severity
* Add -p option to print whole configuration with included files
* Add -U option to allow start under non-root user
* Allow maxsamples to be set to 1 for faster update with -q/-Q option
* Avoid replacing NTP sources with sources that have unreachable address
* Improve pools to repeat name resolution to get "maxsources" sources
@@ -38,6 +64,9 @@ Bug fixes
Removed features
----------------
* Drop support for RIPEMD keys (RMD128, RMD160, RMD256, RMD320)
* Drop support for long (non-standard) MACs in NTPv4 packets (chrony 2.x
clients using non-MD5/SHA1 keys need to use option "version 3")
* Drop support for line editing with GNU Readline
New in version 3.5.1
====================

7
README
View File

@@ -91,7 +91,7 @@ Acknowledgements
In writing the chronyd program, extensive use has been made of the NTPv3 (RFC
1305) and NTPv4 (RFC 5905) specification. The source code of the xntpd/ntpd
implementation written by Dennis Fergusson, Lars Mathiesen, David Mills, and
others, has been used to check the details of the protocol.
others has been used to check the details of the protocol.
The following people have provided patches and other major contributions
to chrony:
@@ -108,6 +108,7 @@ Erik Bryer <ebryer@spots.ab.ca>
Jonathan Cameron <jic23@cam.ac.uk>
Bryan Christianson <bryan@whatroute.net>
Juliusz Chroboczek <jch@pps.jussieu.fr>
Kamil Dudka <kdudka@redhat.com>
Christian Ehrhardt <christian.ehrhardt@canonical.com>
Paul Elliott <pelliott@io.com>
Robert Fairley <rfairley@redhat.com>
@@ -124,6 +125,7 @@ Jachym Holecek <jakym@volny.cz>
Håkan Johansson <f96hajo@chalmers.se>
Jim Knoble <jmknoble@pobox.com>
Antti Jrvinen <costello@iki.fi>
Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Eric Lammerts <eric@lammerts.org>
Stefan Lucke <stefan@lucke.in-berlin.de>
Victor Lum <viclum@vanu.com>
@@ -137,6 +139,8 @@ Denny Page <dennypage@me.com>
Chris Perl <cperl@janestreet.com>
Gautier PHILIPPON <gautier.philippon@ensimag.grenoble-inp.fr>
Andreas Piesk <apiesk@virbus.de>
Baruch Siach <baruch@tkos.co.il>
Foster Snowhill <forst@forstwoof.ru>
Andreas Steinmetz <ast@domdv.de>
NAKAMURA Takumi <takumi@ps.sakura.ne.jp>
Timo Teras <timo.teras@iki.fi>
@@ -148,6 +152,7 @@ Bernhard M. Wiedemann <bwiedemann@suse.de>
Joachim Wiedorn <ad_debian@joonet.de>
Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
Ulrich Windl <ulrich.windl@rz.uni-regensburg.de>
Michael Witten <mfwitten@gmail.com>
Doug Woodward <dougw@whistler.com>
Thomas Zajic <zlatko@zlatko.fdns.net>

23
candm.h
View File

@@ -108,7 +108,8 @@
#define REQ_CLIENT_ACCESSES_BY_INDEX3 68
#define REQ_SELECT_DATA 69
#define REQ_RELOAD_SOURCES 70
#define N_REQUEST_TYPES 71
#define REQ_DOFFSET2 71
#define N_REQUEST_TYPES 72
/* Structure used to exchange timespecs independent of time_t size */
typedef struct {
@@ -268,6 +269,7 @@ typedef struct {
#define REQ_ADDSRC_INTERLEAVED 0x80
#define REQ_ADDSRC_BURST 0x100
#define REQ_ADDSRC_NTS 0x200
#define REQ_ADDSRC_COPY 0x400
typedef struct {
uint32_t type;
@@ -292,7 +294,8 @@ typedef struct {
Float offset;
uint32_t flags;
int32_t filter_length;
uint32_t reserved[3];
uint32_t cert_set;
uint32_t reserved[2];
int32_t EOR;
} REQ_NTP_Source;
@@ -307,8 +310,7 @@ typedef struct {
} REQ_Dfreq;
typedef struct {
int32_t sec;
int32_t usec;
Float doffset;
int32_t EOR;
} REQ_Doffset;
@@ -403,7 +405,7 @@ typedef struct {
domain socket.
Version 6 (no authentication) : changed format of client accesses by index
(using new request/reply types) and manual timestamp, added new fields and
(two times), delta offset, and manual timestamp, added new fields and
flags to NTP source request and report, made length of manual list constant,
added new commands: authdata, ntpdata, onoffline, refresh, reset,
selectdata, serverstats, shutdown, sourcename
@@ -553,12 +555,12 @@ typedef struct {
#define RPY_SD_MD_PEER 1
#define RPY_SD_MD_REF 2
#define RPY_SD_ST_SYNC 0
#define RPY_SD_ST_UNREACH 1
#define RPY_SD_ST_SELECTED 0
#define RPY_SD_ST_NONSELECTABLE 1
#define RPY_SD_ST_FALSETICKER 2
#define RPY_SD_ST_JITTERY 3
#define RPY_SD_ST_CANDIDATE 4
#define RPY_SD_ST_OUTLIER 5
#define RPY_SD_ST_UNSELECTED 4
#define RPY_SD_ST_SELECTABLE 5
typedef struct {
IPAddr ip_addr;
@@ -764,7 +766,8 @@ typedef struct {
IPAddr ip_addr;
uint8_t state_char;
uint8_t authentication;
uint8_t pad[2];
uint8_t leap;
uint8_t pad;
uint16_t conf_options;
uint16_t eff_options;
uint32_t last_sample_ago;

126
client.c
View File

@@ -4,7 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Lonnie Abelbeck 2016, 2018
* Copyright (C) Miroslav Lichvar 2009-2018
* Copyright (C) Miroslav Lichvar 2009-2020
*
* 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
@@ -44,12 +44,7 @@
#include "util.h"
#ifdef FEAT_READLINE
#ifdef USE_EDITLINE
#include <editline/readline.h>
#else
#include <readline/readline.h>
#include <readline/history.h>
#endif
#endif
/* ================================================== */
@@ -66,7 +61,7 @@ static ARR_Instance server_addresses;
static int sock_fd = -1;
static int quit = 0;
static volatile int quit = 0;
static int on_terminal = 0;
@@ -992,54 +987,38 @@ process_cmd_cmdaccheck(CMD_Request *msg, char *line)
/* ================================================== */
static void
static int
process_cmd_dfreq(CMD_Request *msg, char *line)
{
double dfreq;
msg->command = htons(REQ_DFREQ);
if (sscanf(line, "%lf", &dfreq) == 1) {
if (sscanf(line, "%lf", &dfreq) != 1) {
LOG(LOGS_ERR, "Invalid value");
return 0;
}
msg->data.dfreq.dfreq = UTI_FloatHostToNetwork(dfreq);
} else {
msg->data.dfreq.dfreq = UTI_FloatHostToNetwork(0.0);
}
return 1;
}
/* ================================================== */
static void
cvt_to_sec_usec(double x, long *sec, long *usec) {
long s, us;
s = (long) x;
us = (long)(0.5 + 1.0e6 * (x - (double) s));
while (us >= 1000000) {
us -= 1000000;
s += 1;
}
while (us < 0) {
us += 1000000;
s -= 1;
}
*sec = s;
*usec = us;
}
/* ================================================== */
static void
static int
process_cmd_doffset(CMD_Request *msg, char *line)
{
double doffset;
long sec, usec;
msg->command = htons(REQ_DOFFSET);
if (sscanf(line, "%lf", &doffset) == 1) {
cvt_to_sec_usec(doffset, &sec, &usec);
msg->data.doffset.sec = htonl(sec);
msg->data.doffset.usec = htonl(usec);
} else {
msg->data.doffset.sec = htonl(0);
msg->data.doffset.usec = htonl(0);
msg->command = htons(REQ_DOFFSET2);
if (sscanf(line, "%lf", &doffset) != 1) {
LOG(LOGS_ERR, "Invalid value");
return 0;
}
msg->data.doffset.doffset = UTI_FloatHostToNetwork(doffset);
return 1;
}
/* ================================================== */
@@ -1119,11 +1098,13 @@ process_cmd_add_source(CMD_Request *msg, char *line)
(data.params.interleaved ? REQ_ADDSRC_INTERLEAVED : 0) |
(data.params.burst ? REQ_ADDSRC_BURST : 0) |
(data.params.nts ? REQ_ADDSRC_NTS : 0) |
(data.params.copy ? REQ_ADDSRC_COPY : 0) |
(data.params.sel_options & SRC_SELECT_PREFER ? REQ_ADDSRC_PREFER : 0) |
(data.params.sel_options & SRC_SELECT_NOSELECT ? REQ_ADDSRC_NOSELECT : 0) |
(data.params.sel_options & SRC_SELECT_TRUST ? REQ_ADDSRC_TRUST : 0) |
(data.params.sel_options & SRC_SELECT_REQUIRE ? REQ_ADDSRC_REQUIRE : 0));
msg->data.ntp_source.filter_length = htonl(data.params.filter_length);
msg->data.ntp_source.cert_set = htonl(data.params.cert_set);
memset(msg->data.ntp_source.reserved, 0, sizeof (msg->data.ntp_source.reserved));
result = 1;
@@ -1267,7 +1248,7 @@ give_help(void)
}
/* ================================================== */
/* Tab-completion when editline/readline is available */
/* Tab-completion when editline is available */
#ifdef FEAT_READLINE
@@ -1887,19 +1868,19 @@ print_report(const char *format, ...)
integer = va_arg(ap, int);
switch (integer) {
case LEAP_Normal:
string = "Normal";
string = width != 1 ? "Normal" : "N";
break;
case LEAP_InsertSecond:
string = "Insert second";
string = width != 1 ? "Insert second" : "+";
break;
case LEAP_DeleteSecond:
string = "Delete second";
string = width != 1 ? "Delete second" : "-";
break;
case LEAP_Unsynchronised:
string = "Not synchronised";
string = width != 1 ? "Not synchronised" : "?";
break;
default:
string = "Invalid";
string = width != 1 ? "Invalid" : "?";
break;
}
printf("%s", string);
@@ -2054,7 +2035,7 @@ get_source_name(IPAddr *ip_addr, char *buf, int size)
/* Make sure the name is printable */
for (i = 0; i < size && buf[i] != '\0'; i++) {
if (!isgraph(buf[i]))
if (!isgraph((unsigned char)buf[i]))
return 0;
}
@@ -2110,7 +2091,7 @@ process_cmd_sourcename(char *line)
IPAddr ip_addr;
char name[256];
if (!UTI_StringToIP(line, &ip_addr)) {
if (!parse_source_address(line, &ip_addr)) {
LOG(LOGS_ERR, "Could not read address");
return 0;
}
@@ -2146,8 +2127,8 @@ process_cmd_sources(char *line)
if (verbose) {
printf("\n");
printf(" .-- Source mode '^' = server, '=' = peer, '#' = local clock.\n");
printf(" / .- Source state '*' = current synced, '+' = combined , '-' = not combined,\n");
printf("| / '?' = unreachable, 'x' = time may be in error, '~' = time too variable.\n");
printf(" / .- Source state '*' = current best, '+' = combined, '-' = not combined,\n");
printf("| / 'x' = may be in error, '~' = too variable, '?' = unusable.\n");
printf("|| .- xxxx [ yyyy ] +/- zzzz\n");
printf("|| Reachability register (octal) -. | xxxx = adjusted offset,\n");
printf("|| Log2(Polling interval) --. | | yyyy = measured offset,\n");
@@ -2189,10 +2170,10 @@ process_cmd_sources(char *line)
}
switch (ntohs(reply.data.source_data.state)) {
case RPY_SD_ST_SYNC:
case RPY_SD_ST_SELECTED:
state_ch = '*';
break;
case RPY_SD_ST_UNREACH:
case RPY_SD_ST_NONSELECTABLE:
state_ch = '?';
break;
case RPY_SD_ST_FALSETICKER:
@@ -2201,10 +2182,10 @@ process_cmd_sources(char *line)
case RPY_SD_ST_JITTERY:
state_ch = '~';
break;
case RPY_SD_ST_CANDIDATE:
case RPY_SD_ST_UNSELECTED:
state_ch = '+';
break;
case RPY_SD_ST_OUTLIER:
case RPY_SD_ST_SELECTABLE:
state_ch = '-';
break;
default:
@@ -2581,9 +2562,9 @@ process_cmd_selectdata(char *line)
printf( "| | | | |\n");
}
print_header("S Name/IP Address Auth COpts EOpts Last Score Interval ");
print_header("S Name/IP Address Auth COpts EOpts Last Score Interval Leap");
/* "S NNNNNNNNNNNNNNNNNNNNNNNNN A OOOO- OOOO- LLLL SSSSS LLLLLLL LLLLLLL" */
/* "S NNNNNNNNNNNNNNNNNNNNNNNNN A OOOO- OOOO- LLLL SSSSS IIIIIII IIIIIII L" */
for (i = 0; i < n_sources; i++) {
request.command = htons(REQ_SELECT_DATA);
@@ -2601,7 +2582,7 @@ process_cmd_selectdata(char *line)
conf_options = ntohs(reply.data.select_data.conf_options);
eff_options = ntohs(reply.data.select_data.eff_options);
print_report("%c %-25s %c %c%c%c%c%c %c%c%c%c%c %I %5.1f %+S %+S\n",
print_report("%c %-25s %c %c%c%c%c%c %c%c%c%c%c %I %5.1f %+S %+S %1L\n",
reply.data.select_data.state_char,
name,
reply.data.select_data.authentication ? 'Y' : 'N',
@@ -2619,6 +2600,7 @@ process_cmd_selectdata(char *line)
UTI_FloatNetworkToHost(reply.data.select_data.score),
UTI_FloatNetworkToHost(reply.data.select_data.lo_limit),
UTI_FloatNetworkToHost(reply.data.select_data.hi_limit),
reply.data.select_data.leap,
REPORT_END);
}
@@ -3289,12 +3271,12 @@ process_line(char *line)
do_normal_submit = process_cmd_deny(&tx_message, line);
}
} else if (!strcmp(command, "dfreq")) {
process_cmd_dfreq(&tx_message, line);
do_normal_submit = process_cmd_dfreq(&tx_message, line);
} else if (!strcmp(command, "dns")) {
ret = process_cmd_dns(line);
do_normal_submit = 0;
} else if (!strcmp(command, "doffset")) {
process_cmd_doffset(&tx_message, line);
do_normal_submit = process_cmd_doffset(&tx_message, line);
} else if (!strcmp(command, "dump")) {
process_cmd_dump(&tx_message, line);
} else if (!strcmp(command, "exit")) {
@@ -3476,7 +3458,7 @@ static void
display_gpl(void)
{
printf("chrony version %s\n"
"Copyright (C) 1997-2003, 2007, 2009-2019 Richard P. Curnow and others\n"
"Copyright (C) 1997-2003, 2007, 2009-2020 Richard P. Curnow and others\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"
"GNU General Public License version 2 for details.\n\n",
@@ -3488,8 +3470,22 @@ display_gpl(void)
static void
print_help(const char *progname)
{
printf("Usage: %s [-h HOST] [-p PORT] [-n] [-N] [-c] [-d] [-4|-6] [-m] [COMMAND]\n",
progname);
printf("Usage: %s [OPTION]... [COMMAND]...\n\n"
"Options:\n"
" -4\t\tUse IPv4 addresses only\n"
" -6\t\tUse IPv6 addresses only\n"
" -n\t\tDon't resolve hostnames\n"
" -N\t\tPrint original source names\n"
" -c\t\tEnable CSV format\n"
#if DEBUG > 0
" -d\t\tEnable debug messages\n"
#endif
" -m\t\tAccept multiple commands\n"
" -h HOST\tSpecify server (%s)\n"
" -p PORT\tSpecify UDP port (%d)\n"
" -v, --version\tPrint version and exit\n"
" --help\tPrint usage and exit\n",
progname, DEFAULT_COMMAND_SOCKET",127.0.0.1,::1", DEFAULT_CANDM_PORT);
}
/* ================================================== */
@@ -3511,7 +3507,7 @@ main(int argc, char **argv)
int opt, ret = 1, multi = 0, family = IPADDR_UNSPEC;
int port = DEFAULT_CANDM_PORT;
/* Parse (undocumented) long command-line options */
/* Parse long command-line options */
for (optind = 1; optind < argc; optind++) {
if (!strcmp("--help", argv[optind])) {
print_help(progname);

View File

@@ -169,7 +169,7 @@ compare_total_hits(Record *x, Record *y)
static Record *
get_record(IPAddr *ip)
{
uint32_t last_hit, oldest_hit = 0;
uint32_t last_hit = 0, oldest_hit = 0;
Record *record, *oldest_record;
unsigned int first, i, j;

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2016, 2018
* Copyright (C) Miroslav Lichvar 2009-2016, 2018-2020
*
* 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
@@ -62,6 +62,9 @@ static int sock_fdu;
static int sock_fd4;
static int sock_fd6;
/* Flag indicating the IPv4 socket is bound to an address */
static int bound_sock_fd4;
/* Flag indicating whether this module has been initialised or not */
static int initialised = 0;
@@ -140,6 +143,7 @@ static const char permissions[] = {
PERMIT_AUTH, /* CLIENT_ACCESSES_BY_INDEX3 */
PERMIT_AUTH, /* SELECT_DATA */
PERMIT_AUTH, /* RELOAD_SOURCES */
PERMIT_AUTH, /* DOFFSET2 */
};
/* ================================================== */
@@ -179,6 +183,9 @@ open_socket(int family)
return INVALID_SOCK_FD;
}
if (family == IPADDR_INET4)
bound_sock_fd4 = local_addr.ip_addr.addr.in4 != INADDR_ANY;
break;
case IPADDR_UNSPEC:
local_path = CNF_GetBindCommandPath();
@@ -244,6 +251,8 @@ CAM_Initialise(void)
initialised = 1;
bound_sock_fd4 = 0;
sock_fdu = INVALID_SOCK_FD;
sock_fd4 = open_socket(IPADDR_INET4);
sock_fd6 = open_socket(IPADDR_INET6);
@@ -294,15 +303,28 @@ CAM_OpenUnixSocket(void)
/* ================================================== */
static void
transmit_reply(int sock_fd, SCK_Message *message)
transmit_reply(int sock_fd, int request_length, SCK_Message *message)
{
message->length = PKL_ReplyLength((CMD_Reply *)message->data);
if (request_length < message->length) {
DEBUG_LOG("Response longer than request req_len=%d res_len=%d",
request_length, message->length);
return;
}
/* Don't require responses to non-link-local addresses to use the same
interface */
if (!SCK_IsLinkLocalIPAddress(&message->remote_addr.ip.ip_addr))
if (message->addr_type == SCK_ADDR_IP &&
!SCK_IsLinkLocalIPAddress(&message->remote_addr.ip.ip_addr))
message->if_index = INVALID_IF_INDEX;
#if !defined(HAVE_IN_PKTINFO) && defined(IP_SENDSRCADDR)
/* On FreeBSD a local IPv4 address cannot be specified on bound socket */
if (message->local_addr.ip.family == IPADDR_INET4 && (sock_fd != sock_fd4 || bound_sock_fd4))
message->local_addr.ip.family = IPADDR_UNSPEC;
#endif
if (!SCK_SendMessage(sock_fd, message, 0))
return;
}
@@ -572,11 +594,8 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
tx_message->data.source_data.stratum = htons(report.stratum);
tx_message->data.source_data.poll = htons(report.poll);
switch (report.state) {
case RPT_SYNC:
tx_message->data.source_data.state = htons(RPY_SD_ST_SYNC);
break;
case RPT_UNREACH:
tx_message->data.source_data.state = htons(RPY_SD_ST_UNREACH);
case RPT_NONSELECTABLE:
tx_message->data.source_data.state = htons(RPY_SD_ST_NONSELECTABLE);
break;
case RPT_FALSETICKER:
tx_message->data.source_data.state = htons(RPY_SD_ST_FALSETICKER);
@@ -584,11 +603,14 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message)
case RPT_JITTERY:
tx_message->data.source_data.state = htons(RPY_SD_ST_JITTERY);
break;
case RPT_CANDIDATE:
tx_message->data.source_data.state = htons(RPY_SD_ST_CANDIDATE);
case RPT_SELECTABLE:
tx_message->data.source_data.state = htons(RPY_SD_ST_SELECTABLE);
break;
case RPT_OUTLIER:
tx_message->data.source_data.state = htons(RPY_SD_ST_OUTLIER);
case RPT_UNSELECTED:
tx_message->data.source_data.state = htons(RPY_SD_ST_UNSELECTED);
break;
case RPT_SELECTED:
tx_message->data.source_data.state = htons(RPY_SD_ST_SELECTED);
break;
}
switch (report.mode) {
@@ -728,6 +750,7 @@ handle_add_source(CMD_Request *rx_message, CMD_Reply *tx_message)
params.filter_length = ntohl(rx_message->data.ntp_source.filter_length);
params.authkey = ntohl(rx_message->data.ntp_source.authkey);
params.nts_port = ntohl(rx_message->data.ntp_source.nts_port);
params.cert_set = ntohl(rx_message->data.ntp_source.cert_set);
params.max_delay = UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay);
params.max_delay_ratio =
UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_ratio);
@@ -744,6 +767,7 @@ handle_add_source(CMD_Request *rx_message, CMD_Reply *tx_message)
params.interleaved = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_INTERLEAVED ? 1 : 0;
params.burst = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_BURST ? 1 : 0;
params.nts = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_NTS ? 1 : 0;
params.copy = ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_COPY ? 1 : 0;
params.sel_options =
(ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_PREFER ? SRC_SELECT_PREFER : 0) |
(ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_NOSELECT ? SRC_SELECT_NOSELECT : 0) |
@@ -834,13 +858,14 @@ handle_dfreq(CMD_Request *rx_message, CMD_Reply *tx_message)
static void
handle_doffset(CMD_Request *rx_message, CMD_Reply *tx_message)
{
long sec, usec;
double doffset;
sec = (int32_t)ntohl(rx_message->data.doffset.sec);
usec = (int32_t)ntohl(rx_message->data.doffset.usec);
doffset = (double) sec + 1.0e-6 * (double) usec;
doffset = UTI_FloatNetworkToHost(rx_message->data.doffset.doffset);
if (!LCL_AccumulateOffset(doffset, 0.0)) {
tx_message->status = htons(STT_FAILED);
} else {
LOG(LOGS_INFO, "Accumulated delta offset of %.6f seconds", doffset);
LCL_AccumulateOffset(doffset, 0.0);
}
}
/* ================================================== */
@@ -1320,6 +1345,7 @@ handle_select_data(CMD_Request *rx_message, CMD_Reply *tx_message)
UTI_IPHostToNetwork(&report.ip_addr, &tx_message->data.select_data.ip_addr);
tx_message->data.select_data.state_char = report.state_char;
tx_message->data.select_data.authentication = report.authentication;
tx_message->data.select_data.leap = report.leap;
tx_message->data.select_data.conf_options = htons(convert_select_options(report.conf_options));
tx_message->data.select_data.eff_options = htons(convert_select_options(report.eff_options));
tx_message->data.select_data.last_sample_ago = htonl(report.last_sample_ago);
@@ -1427,7 +1453,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
if (rx_message.version >= PROTO_VERSION_MISMATCH_COMPAT_SERVER) {
tx_message.status = htons(STT_BADPKTVERSION);
transmit_reply(sock_fd, sck_message);
transmit_reply(sock_fd, read_length, sck_message);
}
return;
}
@@ -1437,7 +1463,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
DEBUG_LOG("Command packet has invalid command %d", rx_command);
tx_message.status = htons(STT_INVALID);
transmit_reply(sock_fd, sck_message);
transmit_reply(sock_fd, read_length, sck_message);
return;
}
@@ -1446,7 +1472,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
expected_length);
tx_message.status = htons(STT_BADPKTLENGTH);
transmit_reply(sock_fd, sck_message);
transmit_reply(sock_fd, read_length, sck_message);
return;
}
@@ -1614,7 +1640,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
handle_dfreq(&rx_message, &tx_message);
break;
case REQ_DOFFSET:
case REQ_DOFFSET2:
handle_doffset(&rx_message, &tx_message);
break;
@@ -1733,19 +1759,7 @@ read_from_cmd_socket(int sock_fd, int event, void *anything)
}
/* Transmit the response */
{
/* Include a simple way to lose one message in three to test resend */
static int do_it=1;
if (do_it) {
transmit_reply(sock_fd, sck_message);
}
#if 0
do_it = ((do_it + 1) % 3);
#endif
}
transmit_reply(sock_fd, read_length, sck_message);
}
/* ================================================== */

View File

@@ -64,7 +64,9 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
src->params.sel_options = 0;
src->params.nts = 0;
src->params.nts_port = SRC_DEFAULT_NTSPORT;
src->params.copy = 0;
src->params.authkey = INACTIVE_AUTHKEY;
src->params.cert_set = SRC_DEFAULT_CERTSET;
src->params.max_delay = SRC_DEFAULT_MAXDELAY;
src->params.max_delay_ratio = SRC_DEFAULT_MAXDELAYRATIO;
src->params.max_delay_dev_ratio = SRC_DEFAULT_MAXDELAYDEVRATIO;
@@ -90,6 +92,8 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
src->params.auto_offline = 1;
} else if (!strcasecmp(cmd, "burst")) {
src->params.burst = 1;
} else if (!strcasecmp(cmd, "copy")) {
src->params.copy = 1;
} else if (!strcasecmp(cmd, "iburst")) {
src->params.iburst = 1;
} else if (!strcasecmp(cmd, "offline")) {
@@ -102,6 +106,9 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
src->params.sel_options |= SRC_SELECT_REQUIRE;
} else if (!strcasecmp(cmd, "trust")) {
src->params.sel_options |= SRC_SELECT_TRUST;
} else if (!strcasecmp(cmd, "certset")) {
if (sscanf(line, "%"SCNu32"%n", &src->params.cert_set, &n) != 1)
return 0;
} else if (!strcasecmp(cmd, "key")) {
if (sscanf(line, "%"SCNu32"%n", &src->params.authkey, &n) != 1 ||
src->params.authkey == INACTIVE_AUTHKEY)

127
conf.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2017
* Copyright (C) Miroslav Lichvar 2009-2017, 2020
*
* 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
@@ -76,6 +76,8 @@ static void parse_log(char *);
static void parse_mailonchange(char *);
static void parse_makestep(char *);
static void parse_maxchange(char *);
static void parse_ntsserver(char *, ARR_Instance files);
static void parse_ntstrustedcerts(char *);
static void parse_ratelimit(char *line, int *enabled, int *interval,
int *burst, int *leak);
static void parse_refclock(char *);
@@ -100,6 +102,7 @@ static double correction_time_ratio = 3.0;
static double max_clock_error = 1.0; /* in ppm */
static double max_drift = 500000.0; /* in ppm */
static double max_slew_rate = 1e6 / 12.0; /* in ppm */
static double clock_precision = 0.0; /* in seconds */
static SRC_AuthSelectMode authselect_mode = SRC_AUTHSELECT_MIX;
static double max_distance = 3.0;
@@ -251,14 +254,15 @@ static char *user;
/* NTS server and client configuration */
static char *nts_dump_dir = NULL;
static char *nts_ntp_server = NULL;
static char *nts_server_cert_file = NULL;
static char *nts_server_key_file = NULL;
static ARR_Instance nts_server_cert_files; /* array of (char *) */
static ARR_Instance nts_server_key_files; /* array of (char *) */
static int nts_server_port = NKE_PORT;
static int nts_server_processes = 1;
static int nts_server_connections = 100;
static int nts_refresh = 2419200; /* 4 weeks */
static int nts_rotate = 604800; /* 1 week */
static char *nts_trusted_cert_file = NULL;
static ARR_Instance nts_trusted_certs_paths; /* array of (char *) */
static ARR_Instance nts_trusted_certs_ids; /* array of uint32_t */
/* Number of clock updates needed to enable certificate time checks */
static int no_cert_time_check = 0;
@@ -387,6 +391,11 @@ CNF_Initialise(int r, int client_only)
ntp_restrictions = ARR_CreateInstance(sizeof (AllowDeny));
cmd_restrictions = ARR_CreateInstance(sizeof (AllowDeny));
nts_server_cert_files = ARR_CreateInstance(sizeof (char *));
nts_server_key_files = ARR_CreateInstance(sizeof (char *));
nts_trusted_certs_paths = ARR_CreateInstance(sizeof (char *));
nts_trusted_certs_ids = ARR_CreateInstance(sizeof (uint32_t));
rtc_device = Strdup(DEFAULT_RTC_DEVICE);
hwclock_file = Strdup(DEFAULT_HWCLOCK_FILE);
user = Strdup(DEFAULT_USER);
@@ -421,6 +430,16 @@ CNF_Finalise(void)
Free(((NTP_Source *)ARR_GetElement(ntp_sources, i))->params.name);
for (i = 0; i < ARR_GetSize(ntp_source_dirs); i++)
Free(*(char **)ARR_GetElement(ntp_source_dirs, i));
for (i = 0; i < ARR_GetSize(refclock_sources); i++) {
Free(((RefclockParameters *)ARR_GetElement(refclock_sources, i))->driver_name);
Free(((RefclockParameters *)ARR_GetElement(refclock_sources, i))->driver_parameter);
}
for (i = 0; i < ARR_GetSize(nts_server_cert_files); i++)
Free(*(char **)ARR_GetElement(nts_server_cert_files, i));
for (i = 0; i < ARR_GetSize(nts_server_key_files); i++)
Free(*(char **)ARR_GetElement(nts_server_key_files, i));
for (i = 0; i < ARR_GetSize(nts_trusted_certs_paths); i++)
Free(*(char **)ARR_GetElement(nts_trusted_certs_paths, i));
ARR_DestroyInstance(init_sources);
ARR_DestroyInstance(ntp_sources);
@@ -432,6 +451,11 @@ CNF_Finalise(void)
ARR_DestroyInstance(ntp_restrictions);
ARR_DestroyInstance(cmd_restrictions);
ARR_DestroyInstance(nts_server_cert_files);
ARR_DestroyInstance(nts_server_key_files);
ARR_DestroyInstance(nts_trusted_certs_paths);
ARR_DestroyInstance(nts_trusted_certs_ids);
Free(drift_file);
Free(dumpdir);
Free(hwclock_file);
@@ -452,9 +476,6 @@ CNF_Finalise(void)
Free(tempcomp_point_file);
Free(nts_dump_dir);
Free(nts_ntp_server);
Free(nts_server_cert_file);
Free(nts_server_key_file);
Free(nts_trusted_cert_file);
}
/* ================================================== */
@@ -544,6 +565,8 @@ CNF_ParseLine(const char *filename, int number, char *line)
parse_broadcast(p);
} else if (!strcasecmp(command, "clientloglimit")) {
parse_clientloglimit(p);
} else if (!strcasecmp(command, "clockprecision")) {
parse_double(p, &clock_precision);
} else if (!strcasecmp(command, "cmdallow")) {
parse_allow_deny(p, cmd_restrictions, 1);
} else if (!strcasecmp(command, "cmddeny")) {
@@ -636,8 +659,6 @@ CNF_ParseLine(const char *filename, int number, char *line)
} else if (!strcasecmp(command, "ntsratelimit")) {
parse_ratelimit(p, &nts_ratelimit_enabled, &nts_ratelimit_interval,
&nts_ratelimit_burst, &nts_ratelimit_leak);
} else if (!strcasecmp(command, "ntstrustedcerts")) {
parse_string(p, &nts_trusted_cert_file);
} else if (!strcasecmp(command, "ntscachedir") ||
!strcasecmp(command, "ntsdumpdir")) {
parse_string(p, &nts_dump_dir);
@@ -652,9 +673,11 @@ CNF_ParseLine(const char *filename, int number, char *line)
} else if (!strcasecmp(command, "ntsrotate")) {
parse_int(p, &nts_rotate);
} else if (!strcasecmp(command, "ntsservercert")) {
parse_string(p, &nts_server_cert_file);
parse_ntsserver(p, nts_server_cert_files);
} else if (!strcasecmp(command, "ntsserverkey")) {
parse_string(p, &nts_server_key_file);
parse_ntsserver(p, nts_server_key_files);
} else if (!strcasecmp(command, "ntstrustedcerts")) {
parse_ntstrustedcerts(p);
} else if (!strcasecmp(command, "peer")) {
parse_source(p, command, 1);
} else if (!strcasecmp(command, "pidfile")) {
@@ -1151,6 +1174,41 @@ parse_mailonchange(char *line)
/* ================================================== */
static void
parse_ntsserver(char *line, ARR_Instance files)
{
char *file = NULL;
parse_string(line, &file);
ARR_AppendElement(files, &file);
}
/* ================================================== */
static void
parse_ntstrustedcerts(char *line)
{
uint32_t id;
char *path;
if (get_number_of_args(line) == 2) {
path = CPS_SplitWord(line);
if (sscanf(line, "%"SCNu32, &id) != 1)
command_parse_error();
} else {
check_number_of_args(line, 1);
path = line;
id = 0;
}
path = Strdup(path);
ARR_AppendElement(nts_trusted_certs_paths, &path);
ARR_AppendElement(nts_trusted_certs_ids, &id);
}
/* ================================================== */
static void
parse_allow_deny(char *line, ARR_Instance restrictions, int allow)
{
@@ -1636,8 +1694,9 @@ load_source_file(const char *filename)
return;
while (fgets(line, sizeof (line), f)) {
if (strlen(line) >= MAX_LINE_LENGTH)
continue;
/* Require lines to be terminated */
if (line[0] == '\0' || line[strlen(line) - 1] != '\n')
break;
CPS_NormalizeLine(line);
if (line[0] == '\0')
@@ -1836,10 +1895,14 @@ CNF_AddSources(void)
void
CNF_AddRefclocks(void)
{
RefclockParameters *refclock;
unsigned int i;
for (i = 0; i < ARR_GetSize(refclock_sources); i++) {
RCL_AddRefclock((RefclockParameters *)ARR_GetElement(refclock_sources, i));
refclock = ARR_GetElement(refclock_sources, i);
RCL_AddRefclock(refclock);
Free(refclock->driver_name);
Free(refclock->driver_parameter);
}
ARR_SetSize(refclock_sources, 0);
@@ -2048,6 +2111,14 @@ CNF_GetMaxSlewRate(void)
/* ================================================== */
double
CNF_GetClockPrecision(void)
{
return clock_precision;
}
/* ================================================== */
double
CNF_GetMaxDistance(void)
{
@@ -2496,18 +2567,16 @@ CNF_GetNtsNtpServer(void)
/* ================================================== */
char *
CNF_GetNtsServerCertFile(void)
int
CNF_GetNtsServerCertAndKeyFiles(const char ***certs, const char ***keys)
{
return nts_server_cert_file;
}
*certs = ARR_GetElements(nts_server_cert_files);
*keys = ARR_GetElements(nts_server_key_files);
/* ================================================== */
if (ARR_GetSize(nts_server_cert_files) != ARR_GetSize(nts_server_key_files))
LOG_FATAL("Uneven number of NTS certs and keys");
char *
CNF_GetNtsServerKeyFile(void)
{
return nts_server_key_file;
return ARR_GetSize(nts_server_cert_files);
}
/* ================================================== */
@@ -2552,10 +2621,16 @@ CNF_GetNtsRotate(void)
/* ================================================== */
char *
CNF_GetNtsTrustedCertFile(void)
int
CNF_GetNtsTrustedCertsPaths(const char ***paths, uint32_t **ids)
{
return nts_trusted_cert_file;
*paths = ARR_GetElements(nts_trusted_certs_paths);
*ids = ARR_GetElements(nts_trusted_certs_ids);
if (ARR_GetSize(nts_trusted_certs_paths) != ARR_GetSize(nts_trusted_certs_ids))
assert(0);
return ARR_GetSize(nts_trusted_certs_paths);
}
/* ================================================== */

6
conf.h
View File

@@ -95,6 +95,7 @@ extern double CNF_GetMaxClockError(void);
extern double CNF_GetMaxDrift(void);
extern double CNF_GetCorrectionTimeRatio(void);
extern double CNF_GetMaxSlewRate(void);
extern double CNF_GetClockPrecision(void);
extern SRC_AuthSelectMode CNF_GetAuthSelectMode(void);
extern double CNF_GetMaxDistance(void);
@@ -152,14 +153,13 @@ extern int CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface);
extern char *CNF_GetNtsDumpDir(void);
extern char *CNF_GetNtsNtpServer(void);
extern char *CNF_GetNtsServerCertFile(void);
extern char *CNF_GetNtsServerKeyFile(void);
extern int CNF_GetNtsServerCertAndKeyFiles(const char ***certs, const char ***keys);
extern int CNF_GetNtsServerPort(void);
extern int CNF_GetNtsServerProcesses(void);
extern int CNF_GetNtsServerConnections(void);
extern int CNF_GetNtsRefresh(void);
extern int CNF_GetNtsRotate(void);
extern char *CNF_GetNtsTrustedCertFile(void);
extern int CNF_GetNtsTrustedCertsPaths(const char ***paths, uint32_t **ids);
extern int CNF_GetNoSystemCert(void);
extern int CNF_GetNoCertTimeCheck(void);

99
configure vendored
View File

@@ -5,7 +5,7 @@
#
# Copyright (C) Richard P. Curnow 1997-2003
# Copyright (C) Bryan Christianson 2016
# Copyright (C) Miroslav Lichvar 2009, 2012-2018
# Copyright (C) Miroslav Lichvar 2009, 2012-2020
# Copyright (C) Stefan R. Filipek 2019
#
# =======================================================================
@@ -33,13 +33,13 @@ test_code () {
echo "int main(int argc, char **argv) {"
echo "$code"
echo "return 0; }"
) > docheck.c
) > conftest.c
echo "docheck.c:" >> config.log
cat docheck.c >> config.log
echo $MYCC $MYCFLAGS $MYCPPFLAGS $cflags -o docheck docheck.c $ldflags \
echo "conftest.c:" >> config.log
cat conftest.c >> config.log
echo $MYCC $MYCFLAGS $MYCPPFLAGS $cflags -o conftest conftest.c $ldflags \
$MYLDFLAGS >> config.log
$MYCC $MYCFLAGS $MYCPPFLAGS $cflags -o docheck docheck.c $ldflags \
$MYCC $MYCFLAGS $MYCPPFLAGS $cflags -o conftest conftest.c $ldflags \
$MYLDFLAGS >> config.log 2>&1
if [ $? -eq 0 ]
@@ -50,7 +50,7 @@ test_code () {
echo "No"
result=1
fi
rm -f docheck.c docheck
rm -f conftest.c conftest
echo >> config.log
return $result
}
@@ -108,11 +108,7 @@ for instance \`--prefix=$HOME'.
For better control, use the options below.
--disable-readline Disable line editing support
--without-readline Don't use GNU readline even if it is available
--without-editline Don't use editline even if it is available
--with-readline-includes=DIR Specify where readline include directory is
--with-readline-library=DIR Specify where readline lib directory is
--with-ncurses-library=DIR Specify where ncurses lib directory is
--disable-sechash Disable support for hashes other than MD5
--without-nettle Don't use nettle even if it is available
--without-nss Don't use NSS even if it is available
@@ -225,7 +221,6 @@ feat_cmdmon=1
feat_ntp=1
feat_refclock=1
feat_readline=1
try_readline=1
try_editline=1
feat_sechash=1
try_nettle=1
@@ -241,9 +236,6 @@ try_clockctl=0
feat_scfilter=0
try_seccomp=-1
priv_ops=""
readline_lib=""
readline_inc=""
ncurses_lib=""
feat_ipv6=1
feat_phc=1
try_phc=0
@@ -274,21 +266,9 @@ do
--disable-readline )
feat_readline=0
;;
--without-readline )
try_readline=0
;;
--without-editline )
try_editline=0
;;
--with-readline-library=* )
readline_lib=-L`echo $option | sed -e 's/^.*=//;'`
;;
--with-readline-includes=* )
readline_inc=-I`echo $option | sed -e 's/^.*=//;'`
;;
--with-ncurses-library=* )
ncurses_lib=-L`echo $option | sed -e 's/^.*=//;'`
;;
--prefix=* | --install_prefix=* )
SETPREFIX=`echo $option | sed -e 's/[^=]*=//;'`
;;
@@ -675,6 +655,20 @@ then
fi
fi
if ! test_code 'O_NOFOLLOW flag' 'sys/types.h sys/stat.h fcntl.h' '' "$LIBS" \
'return open("/dev/null", O_NOFOLLOW);'
then
if test_code 'O_NOFOLLOW flag with _GNU_SOURCE' 'sys/types.h sys/stat.h fcntl.h' \
'-D_GNU_SOURCE' "$LIBS" \
'return open("/dev/null", O_NOFOLLOW);'
then
add_def _GNU_SOURCE
else
echo "error: open() does not support O_NOFOLLOW flag"
exit 1
fi
fi
if [ $try_clock_gettime = "1" ]; then
if test_code 'clock_gettime()' 'time.h' '' '' \
'clock_gettime(CLOCK_REALTIME, NULL);'
@@ -690,10 +684,11 @@ if [ $try_clock_gettime = "1" ]; then
fi
fi
if test_code 'getaddrinfo()' 'sys/types.h sys/socket.h netdb.h' '' "$LIBS" \
if ! test_code 'getaddrinfo()' 'sys/types.h sys/socket.h netdb.h' '' "$LIBS" \
'return getaddrinfo(0, 0, 0, 0);'
then
add_def HAVE_GETADDRINFO
echo "error: getaddrinfo() not found"
exit 1
fi
if [ $feat_asyncdns = "1" ] && \
@@ -709,11 +704,11 @@ fi
if test_code 'arc4random_buf()' 'stdlib.h' '' '' 'arc4random_buf(NULL, 0);'; then
add_def HAVE_ARC4RANDOM
fi
if test_code 'getrandom()' 'stdlib.h sys/random.h' '' '' \
else
if test_code 'getrandom()' 'stdlib.h sys/random.h' '' '' \
'return getrandom(NULL, 256, 0);'; then
add_def HAVE_GETRANDOM
fi
fi
RECVMMSG_CODE='
@@ -804,10 +799,12 @@ if [ $feat_scfilter = "1" ] && [ $try_seccomp = "1" ] && \
'seccomp_init(SCMP_ACT_KILL);'
then
add_def FEAT_SCFILTER
# NAME2IPADDRESS shouldn't be enabled with other operations as the helper
# process works on one request at the time and the async resolver could
# block the main thread
if [ $feat_ntp = "1" ]; then
# NAME2IPADDRESS shouldn't be enabled together with a privops operation
# used by the main thread as the helper process works on one request at
# a time and the async resolver would block the main thread
priv_ops="NAME2IPADDRESS RELOADDNS"
fi
EXTRA_LIBS="$EXTRA_LIBS -lseccomp"
fi
@@ -876,37 +873,11 @@ fi
READLINE_LINK=""
if [ $feat_readline = "1" ]; then
if [ $try_editline = "1" ]; then
if test_code editline 'stdio.h editline/readline.h' \
"$readline_inc" "$readline_lib -ledit" \
if test_code editline 'stdio.h editline/readline.h' '' '-ledit' \
'add_history(readline("prompt"));'
then
add_def FEAT_READLINE
add_def USE_EDITLINE
MYCPPFLAGS="$MYCPPFLAGS $readline_inc"
READLINE_LINK="$readline_lib -ledit"
fi
fi
if [ "x$READLINE_LINK" = "x" ] && [ $try_readline = "1" ]; then
if test_code readline 'stdio.h readline/readline.h readline/history.h' \
"$readline_inc" "$readline_lib -lreadline" \
'add_history(readline("prompt"));'
then
add_def FEAT_READLINE
MYCPPFLAGS="$MYCPPFLAGS $readline_inc"
READLINE_LINK="$readline_lib -lreadline"
fi
fi
if [ "x$READLINE_LINK" = "x" ] && [ $try_readline = "1" ]; then
if test_code 'readline with -lncurses' \
'stdio.h readline/readline.h readline/history.h' \
"$readline_inc" "$readline_lib $ncurses_lib -lreadline -lncurses" \
'add_history(readline("prompt"));'
then
add_def FEAT_READLINE
MYCPPFLAGS="$MYCPPFLAGS $readline_inc"
READLINE_LINK="$readline_lib $ncurses_lib -lreadline -lncurses"
READLINE_LINK="-ledit"
fi
fi
@@ -972,7 +943,7 @@ if [ $feat_ntp = "1" ] && [ $feat_nts = "1" ] && [ $try_gnutls = "1" ]; then
test_link="`pkg_config --libs gnutls`"
if test_code 'gnutls' 'gnutls/gnutls.h' \
"$test_cflags" "$test_link" '
return gnutls_init(NULL, 0) +
return gnutls_init(NULL, 0) + GNUTLS_TLS1_3 +
gnutls_priority_init2(NULL, "", NULL, GNUTLS_PRIORITY_INIT_DEF_APPEND) +
gnutls_prf_rfc5705(NULL, 0, "", 0, "", 16, NULL);'
then

View File

@@ -3,7 +3,7 @@
// Copyright (C) Richard P. Curnow 1997-2003
// Copyright (C) Stephen Wadeley 2016
// Copyright (C) Bryan Christianson 2017
// Copyright (C) Miroslav Lichvar 2009-2017
// Copyright (C) Miroslav Lichvar 2009-2020
//
// 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
@@ -32,12 +32,14 @@ chrony.conf - chronyd configuration file
== DESCRIPTION
This file configures the *chronyd* daemon. The compiled-in location is
_@SYSCONFDIR@/chrony.conf_, but other locations can be specified on the
_@SYSCONFDIR@/chrony.conf_. Other locations can be specified on the
*chronyd* command line with the *-f* option.
Each directive in the configuration file is placed on a separate line. The
following sections describe each of the directives in turn. The directives can
occur in any order in the file and they are not case-sensitive.
following sections describe each of the directives in turn. The directives are
not case-sensitive. Generally, the directives can occur in any order in the file
and if a directive is specified multiple times, only the last one will be
effective. Exceptions are noted in the descriptions.
The configuration directives can also be specified directly on the *chronyd*
command line. In this case each argument is parsed as a new line and the
@@ -61,9 +63,10 @@ source. The client-server relationship is strictly hierarchical: a client might
synchronise its system time to that of the server, but the server's system time
will never be influenced by that of a client.
+
The *server* directive is immediately followed by either the name of the
server, or its IP address. The *server* directive supports the following
options:
This directive can be used multiple times to specify multiple servers.
+
The directive is immediately followed by either the name of the
server, or its IP address. It supports the following options:
+
*minpoll* _poll_:::
This option specifies the minimum interval between requests sent to the server
@@ -113,6 +116,12 @@ mechanism. Unlike with the *key* option, the server and client do not need to
share a key in a key file. NTS has a Key Establishment (NTS-KE) protocol using
the Transport Layer Security (TLS) protocol to get the keys and cookies
required by NTS for authentication of NTP packets.
*certset* _ID_:::
This option specifies which set of trusted certificates should be used to verify
the server's certificate when the *nts* option is enabled. Sets of certificates
can be specified with the <<ntstrustedcerts,*ntstrustedcerts*>> directive. The
default set is 0, which by default contains certificates of the system's
default trusted certificate authorities.
*maxdelay* _delay_:::
*chronyd* uses the network round-trip delay to the server to determine how
accurate a particular measurement is likely to be. Long round-trip delays
@@ -122,9 +131,9 @@ of the messages was delayed the measurement error is likely to be substantial.
For small variations in the round-trip delay, *chronyd* uses a weighting scheme
when processing the measurements. However, beyond a certain level of delay the
measurements are likely to be so corrupted as to be useless. (This is
particularly so on dial-up or other slow links, where a long delay probably
indicates a highly asymmetric delay caused by the response waiting behind a lot
of packets related to a download of some sort).
particularly so on wireless networks and other slow links, where a long delay
probably indicates a highly asymmetric delay caused by the response waiting
behind a lot of packets related to a download of some sort).
+
If the user knows that round trip delays above a certain level should cause the
measurement to be ignored, this level can be defined with the *maxdelay*
@@ -135,7 +144,7 @@ round-trip delay of 0.3 seconds or more should be ignored. The default value is
This option is similar to the *maxdelay* option above. *chronyd* keeps a record
of the minimum round-trip delay amongst the previous measurements that it has
buffered. If a measurement has a round trip delay that is greater than the
maxdelayratio times the minimum delay, it will be rejected.
specified ratio times the minimum delay, it will be rejected.
*maxdelaydevratio* _ratio_:::
If a measurement has a ratio of the increase in the round-trip delay from the
minimum delay amongst the previous measurements to the standard deviation of
@@ -258,7 +267,7 @@ will send two extra packets instead of one.
When the synchronisation source is selected from available sources, sources
with lower stratum are normally slightly preferred. This option can be used to
increase stratum of the source to the specified minimum, so *chronyd* will
avoid selecting that source. This is useful with low stratum sources that are
avoid selecting that source. This is useful with low-stratum sources that are
known to be unreliable or inaccurate and which should be used only when other
sources are unreachable.
*version* _version_:::
@@ -269,6 +278,15 @@ specified by the *key* option and which authentication hash function the key
is using. If the output size of the hash function is longer than 160 bits, the
default version is 3 for compatibility with older *chronyd* servers. Otherwise,
the default version is 4.
*copy*:::
This option specifies that the server and client are closely related, their
configuration does not allow a synchronisation loop to form between them, and
the client is allowed to assume the reference ID and stratum of the server.
This is useful when multiple instances of `chronyd` are running on one computer
(e.g. for security or performance reasons), one primarily operating as a client
to synchronise the system clock and other instances started with the *-x*
option to operate as NTP servers for other computers with their NTP clocks
synchronised to the first instance.
[[pool]]*pool* _name_ [_option_]...::
The syntax of this directive is similar to that for the <<server,*server*>>
@@ -276,6 +294,8 @@ directive, except that it is used to specify a pool of NTP servers rather than
a single NTP server. The pool name is expected to resolve to multiple addresses
which might change over time.
+
This directive can be used multiple times to specify multiple pools.
+
All options valid in the <<server,*server*>> directive can be used in this
directive too. There is one option specific to the *pool* directive:
+
@@ -306,8 +326,10 @@ is mainly useful when the NTP implementation of the peer (e.g. *ntpd*) supports
ephemeral symmetric associations and does not need to be configured with an
address of this host. *chronyd* does not support ephemeral associations.
+
This directive can be used multiple times to specify multiple peers.
+
The following options of the *server* directive do not work in the *peer*
directive: *iburst*, *burst*, *nts*, *presend*.
directive: *iburst*, *burst*, *nts*, *presend*, *copy*.
+
When using the *xleave* option, both peers must support and have enabled the
interleaved mode, otherwise the synchronisation will work in one direction
@@ -334,19 +356,8 @@ recommended to use two separate client/server associations (specified by the
<<server,*server*>> directive on both hosts) instead.
[[initstepslew]]*initstepslew* _step-threshold_ [_hostname_]...::
In normal operation, *chronyd* slews the time when it needs to adjust the
system clock. For example, to correct a system clock which is 1 second slow,
*chronyd* slightly increases the amount by which the system clock is advanced
on each clock interrupt, until the error is removed. Note that at no time does
time run backwards with this method.
+
On most Unix systems it is not desirable to step the system clock, because many
programs rely on time advancing monotonically forwards.
+
When the *chronyd* daemon is initially started, it is possible that the system
clock is considerably in error. Attempting to correct such an error by slewing
might not be sensible, since it might take several hours to correct the error by
this means.
(This directive is deprecated in favour of the <<makestep,*makestep*>>
directive.)
+
The purpose of the *initstepslew* directive is to allow *chronyd* to make a
rapid measurement of the system clock error at boot time, and to correct the
@@ -367,29 +378,30 @@ error. *chronyd* then enters its normal operating mode.
An example of the use of the directive is:
+
----
initstepslew 30 foo.example.net bar.example.net
initstepslew 30 foo.example.net bar.example.net baz.example.net
----
+
where 2 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
if the system's error is found to be 30 seconds or less, a slew will be used to
correct it; if the error is above 30 seconds, a step will be used.
+
The *initstepslew* directive can also be used in an isolated LAN environment,
where the clocks are set manually. The most stable computer is chosen as the
master, and the other computers are slaved to it. If each of the slaves is
configured with the <<local,*local*>> directive, the master can be set up with
an *initstepslew* directive which references some or all of the slaves. Then,
if the master machine has to be rebooted, the slaves can be relied on to act
analogously to a flywheel and preserve the time for a short period while the
master completes its reboot.
primary server and the other computers are its clients. If each of the clients
is configured with the <<local,*local*>> directive, the server can be set up
with an *initstepslew* directive which references some or all of the clients.
Then, if the server machine has to be rebooted, the clients can be relied on to
act analogously to a flywheel and preserve the time for a short period while
the server completes its reboot.
+
The *initstepslew* directive is functionally similar to a combination of the
<<makestep,*makestep*>> and <<server,*server*>> directives with the *iburst*
option. The main difference is that the *initstepslew* servers are used only
before normal operation begins and that the foreground *chronyd* process waits
for *initstepslew* to finish before exiting. This is useful to prevent programs
started in the boot sequence after *chronyd* from reading the clock before it
has been stepped.
for *initstepslew* to finish before exiting. This prevent programs started in
the boot sequence after *chronyd* from reading the clock before it has been
stepped. With the *makestep* directive, the
<<chronyc.adoc#waitsync,*waitsync*>> command of *chronyc* can be used instead.
[[refclock]]*refclock* _driver_ _parameter_[:__option__]... [_option_]...::
The *refclock* directive specifies a hardware reference clock to be used as a
@@ -398,6 +410,8 @@ driver-specific parameter. The two parameters are followed by zero or more
refclock options. Some drivers have special options, which can be appended to
the driver-specific parameter using the *:* character.
+
This directive can be used multiple times to specify multiple reference clocks.
+
There are four drivers included in *chronyd*:
+
*PPS*:::
@@ -610,12 +624,13 @@ behaviour, whereas the *settime* command allows samples of manually entered
time to be provided.)
[[acquisitionport]]*acquisitionport* _port_::
By default, *chronyd* uses a separate client socket for each configured server
and their source port is chosen arbitrarily by the operating system. However,
you can use the *acquisitionport* directive to explicitly specify a port and
use only one socket (per IPv4 or IPv6 address family) for all configured servers.
This can be useful for getting through some firewalls. If set to 0, the source
port of the socket will be chosen arbitrarily.
By default, *chronyd* as an NTP client opens a new socket for each request with
the source port chosen randomly by the operating system. The *acquisitionport*
directive can be used to specify the source port and use only one socket (per
IPv4 or IPv6 address family) for all configured servers. This can be useful for
getting through some firewalls. It should not be used if not necessary as there
is a small impact on security of the client. If set to 0, the source port of
the permanent socket will be chosen randomly by the operating system.
+
It can be set to the same port as is used by the NTP server (which can be
configured with the <<port,*port*>> directive) to use only one socket for all
@@ -632,8 +647,8 @@ You could then persuade the firewall administrator to open that port.
[[bindacqaddress]]*bindacqaddress* _address_::
The *bindacqaddress* directive specifies a local IP address to which
*chronyd* will bind its NTP client sockets. The syntax is similar to the
<<bindaddress,*bindaddress*>> and <<bindcmdaddress,*bindcmdaddress*>>
*chronyd* will bind its NTP and NTS-KE client sockets. The syntax is similar to
the <<bindaddress,*bindaddress*>> and <<bindcmdaddress,*bindcmdaddress*>>
directives.
+
For each of the IPv4 and IPv6 protocols, only one *bindacqaddress* directive
@@ -684,6 +699,10 @@ or the <<chronyc.adoc#dump,*dump*>> command in *chronyc* is issued.
+
If the directory does not exist, it will be created automatically.
+
The *-r* option of *chronyd* enables loading of the dump files on start. All
dump files found in the directory will be removed after start, even if the *-r*
option is not present.
+
An example of the directive is:
+
----
@@ -738,25 +757,49 @@ This directory is used also by the <<ntsdumpdir2,NTS server>> to save keys.
[[ntsrefresh]]*ntsrefresh* _interval_::
This directive specifies the maximum interval between NTS-KE handshakes (in
seconds) in order to refresh the keys authenticating NTP packets. The default
value is 2419200 (4 weeks).
value is 2419200 (4 weeks) and the maximum value is 2^31-1 (68 years).
[[ntstrustedcerts]]*ntstrustedcerts* _file_::
This directive specifies a file containing certificates (in the PEM format) of
trusted certificate authorities (CA) that should be used to verify certificates
of NTS servers in addition to the system's default trusted CAs (if the
*nosystemcert* directive is not present).
[[ntstrustedcerts]]*ntstrustedcerts* [_set-ID_] _file_|_directory_::
This directive specifies a file or directory containing certificates (in the
PEM format) of trusted certificate authorities (CA) which can be used to
verify certificates of NTS servers.
+
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
or directory are added. The default ID is 0, which is a set containing the
system's default trusted CAs (unless the *nosystemcert* directive is present).
All other sets are empty by default. A set of certificates can be selected for
verification of an NTS server by the *certset* option in the *server* or *pool*
directive.
+
This directive can be used multiple times to specify one or more sets of
trusted certificates, each containing certificates from one or more files
and/or directories.
+
It is not necessary to restart *chronyd* in order to reload the certificates if
they change (e.g. after a renewal).
+
An example is:
+
----
ntstrustedcerts /etc/pki/nts/foo.crt
ntstrustedcerts 1 /etc/pki/nts/bar.crt
ntstrustedcerts 1 /etc/pki/nts/baz.crt
ntstrustedcerts 2 /etc/pki/nts/qux.crt
----
[[nosystemcert]]*nosystemcert*::
This directive disables the system's default trusted CAs.
This directive disables the system's default trusted CAs. Only certificates
specified by the *ntstrustedcerts* directive will be trusted.
[[nocerttimecheck]]*nocerttimecheck* _limit_::
This directive disables the checks of the activation and expiration times of
certificates for the specified number of clock updates. It allows the NTS
authentication mechanism to be used on computers which start with wrong time
(e.g. due to not having an RTC or backup battery). Disabling the time checks
has important security implications, e.g. if an NTP server was ever
compromised, its certificate could be used in an attack after the expiration
time. The default value is 0, which means the time checks are always enabled.
has important security implications and should be used only as a last resort,
preferably with a minimal number of trusted certificates. The default value is
0, which means the time checks are always enabled.
+
An example of the directive is:
+
@@ -860,11 +903,11 @@ source combining algorithm and only the selected source will be used to control
the system clock.
[[maxdistance]]*maxdistance* _distance_::
The *maxdistance* directive sets the maximum allowed root distance of the
sources to not be rejected by the source selection algorithm. The distance
includes the accumulated dispersion, which might be large when the source is no
longer synchronised, and half of the total round-trip delay to the primary
source.
The *maxdistance* directive sets the maximum root distance of a source to be
acceptable for synchronisation of the clock. Sources that have a distance
larger than the specified distance will be rejected. The distance estimates the
maximum error of the source. It includes the root dispersion and half of the
root delay (round-trip time) accumulated on the path to the primary source.
+
By default, the maximum root distance is 3 seconds.
+
@@ -908,6 +951,27 @@ distances are in milliseconds.
=== System clock
[[clockprecision]]*clockprecision* _precision_::
The *clockprecision* directive specifies the precision of the system clock (in
seconds). It is used by *chronyd* to estimate the minimum noise in NTP
measurements and randomise low-order bits of timestamps in NTP responses. By
default, the precision is measured on start as the minimum time to read the
clock.
+
The measured value works well in most cases. However, it generally
overestimates the precision and it can be sensitive to the CPU speed, which can
change over time to save power. In some cases with a high-precision clocksource
(e.g. the Time Stamp Counter of the CPU) and hardware timestamping, setting the
precision on the server to a smaller value can improve stability of clients'
NTP measurements. The server's precision is reported on clients by the
<<chronyc.adoc#ntpdata,*ntpdata*>> command.
+
An example setting the precision to 8 nanoseconds is:
+
----
clockprecision 8e-9
----
[[corrtimeratio]]*corrtimeratio* _ratio_::
When *chronyd* is slewing the system clock to correct an offset, the rate at
which it is slewing adds to the frequency error of the clock. On all supported
@@ -1039,7 +1103,7 @@ A recommended configuration to enable a server leap smear is:
----
leapsecmode slew
maxslewrate 1000
smoothtime 400 0.001 leaponly
smoothtime 400 0.001024 leaponly
----
+
The first directive is necessary to disable the clock step which would reset
@@ -1047,17 +1111,23 @@ the smoothing process. The second directive limits the slewing rate of the
local clock to 1000 ppm, which improves the stability of the smoothing process
when the local correction starts and ends. The third directive enables the
server time smoothing process. It will start when the clock gets to 00:00:00
UTC and it will take 17 hours 34 minutes to finish. The frequency offset will
be changing by 0.001 ppm per second and will reach a maximum of 31.623 ppm. The
*leaponly* option makes the duration of the leap smear constant and allows the
clients to safely synchronise with multiple identically configured leap
smearing servers.
UTC and it will take 62500 seconds (about 17.36 hours) to finish. The frequency
offset will be changing by 0.001024 ppm per second and will reach a maximum of
32 ppm in 31250 seconds. The *leaponly* option makes the duration of the leap
smear constant and allows the clients to safely synchronise with multiple
identically configured leap smearing servers.
+
The duration of the leap smear can be calculated from the specified wander as
+
----
duration = sqrt(4 / wander)
----
[[leapsectz]]*leapsectz* _timezone_::
This directive specifies a timezone in the system tz database which *chronyd*
can use to determine when will the next leap second occur and what is the
current offset between TAI and UTC. It will periodically check if 23:59:59 and
23:59:60 are valid times in the timezone. This typically works with the
This directive specifies a timezone in the system timezone database which
*chronyd* can use to determine when will the next leap second occur and what is
the current offset between TAI and UTC. It will periodically check if 23:59:59
and 23:59:60 are valid times in the timezone. This normally works with the
_right/UTC_ timezone.
+
When a leap second is announced, the timezone needs to be updated at least 12
@@ -1094,16 +1164,17 @@ Wed Dec 31 23:59:60 UTC 2008
[[makestep]]*makestep* _threshold_ _limit_::
Normally *chronyd* will cause the system to gradually correct any time offset,
by slowing down or speeding up the clock as required. In certain situations,
the system clock might be so far adrift that this slewing process would take a
very long time to correct the system clock.
e.g. when *chronyd* is initially started, the system clock might be so far
adrift that this slewing process would take a very long time to correct the
system clock.
+
This directive forces *chronyd* to step the system clock if the adjustment is
larger than a threshold value, but only if there were no more clock updates
since *chronyd* was started than a specified limit (a negative value can be
used to disable the limit).
since *chronyd* was started than the specified limit. A negative value disables
the limit.
+
This is particularly useful when using reference clocks, because the
<<initstepslew,*initstepslew*>> directive works only with NTP sources.
On most systems it is desirable to step the system clock only on boot, before
starting programs that rely on time advancing monotonically forwards.
+
An example of the use of this directive is:
+
@@ -1165,8 +1236,8 @@ The *maxupdateskew* directive sets the threshold for determining whether an
estimate might be so unreliable that it should not be used. By default, the
threshold is 1000 ppm.
+
Typical values for _skew-in-ppm_ might be 100 for a dial-up connection to
servers over a phone line, and 5 or 10 for a computer on a LAN.
Typical values for _skew-in-ppm_ might be 100 for NTP sources polled over a
wireless network, and 10 or smaller for sources on a local wired network.
+
It should be noted that this is not the only means of protection against using
unreliable estimates. At all times, *chronyd* keeps track of both the estimated
@@ -1221,7 +1292,7 @@ coefficients _T0_, _k0_, _k1_, _k2_.
The frequency compensation is calculated (in ppm) as
+
----
k0 + (T - T0) * k1 + (T - T0)^2 * k2
comp = k0 + (T - T0) * k1 + (T - T0)^2 * k2
----
+
The result has to be between -10 ppm and 10 ppm, otherwise the measurement is
@@ -1272,38 +1343,34 @@ _tempcomp.log_ file if enabled by the <<log,*log tempcomp*>> directive.
[[allow]]*allow* [*all*] [_subnet_]::
The *allow* directive is used to designate a particular subnet from which NTP
clients are allowed to access the computer as an NTP server.
clients are allowed to access the computer as an NTP server. It also controls
access of NTS-KE clients when NTS is enabled on the server.
+
The default is that no clients are allowed access, i.e. *chronyd* operates
purely as an NTP client. If the *allow* directive is used, *chronyd* will be
both a client of its servers, and a server to other clients.
+
This directive can be used multiple times.
+
Examples of the use of the directive are as follows:
+
----
allow 1.2.3.4
allow 1.2
allow 3.4.5.0/24
allow 3.4.5
allow 6.7.8/22
allow 6.7.8.9/22
allow 2001:db8::/32
allow 0/0
allow ::/0
allow
----
+
The first directive allows a node with IPv4 address _1.2.3.4_ to be an NTP
client of this computer.
The second directive allows any node with an IPv4 address of the form _1.2.x.y_
(with _x_ and _y_ arbitrary) to be an NTP client of this computer. Likewise,
the third directive allows any node with an IPv4 address of the form _3.4.5.x_
to have client NTP access. The fourth and fifth forms allow access from any
node with an IPv4 address of the form _6.7.8.x_, _6.7.9.x_, _6.7.10.x_ or
_6.7.11.x_ (with _x_ arbitrary), i.e. the value 22 is the number of bits
defining the specified subnet. In the fifth form, the final byte is ignored.
The sixth form is used for IPv6 addresses. The seventh and eighth forms allow
access by any IPv4 and IPv6 node respectively. The ninth forms allows access by
any node (IPv4 or IPv6).
The first directive allows access from an IPv4 address. The second directive
allows access from all computers in an IPv4 subnet specified in the CIDR
notation. The third directive specifies the same subnet using a simpler
notation where the prefix length is determined by the number of dots. The
fourth directive specifies an IPv6 subnet. The fifth and sixth directives allow
access from all IPv4 and IPv6 addresses respectively. The seventh directive
allows access from all addresses (both IPv4 or IPv6).
+
A second form of the directive, *allow all*, has a greater effect, depending on
the ordering of directives in the configuration file. To illustrate the effect,
@@ -1311,32 +1378,43 @@ consider the two examples:
+
----
allow 1.2.3.4
deny 1.2.3
allow 1.2
deny 1.2.3.0/24
allow 1.2.0.0/16
----
+
and
+
----
allow 1.2.3.4
deny 1.2.3
allow all 1.2
deny 1.2.3.0/24
allow all 1.2.0.0/16
----
+
In the first example, the effect is the same regardless of what order the three
directives are given in. So the _1.2.x.y_ subnet is allowed access, except for
the _1.2.3.x_ subnet, which is denied access, however the host _1.2.3.4_ is
allowed access.
directives are given in. So the _1.2.0.0/16_ subnet is allowed access, except
for the _1.2.3.0/24_ subnet, which is denied access, however the host _1.2.3.4_
is allowed access.
+
In the second example, the *allow all 1.2* directives overrides the effect of
_any_ previous directive relating to a subnet within the specified subnet.
Within a configuration file this capability is probably rather moot; however,
it is of greater use for reconfiguration at run-time via *chronyc* with the
<<chronyc.adoc#allow,*allow all*>> command.
In the second example, the *allow all 1.2.0.0/16* directive overrides the
effect of _any_ previous directive relating to a subnet within the specified
subnet. Within a configuration file this capability is probably rather moot;
however, it is of greater use for reconfiguration at run-time via *chronyc*
with the <<chronyc.adoc#allow,*allow all*>> command.
+
The directive allows a hostname to be specified instead of an IP address, but
the name must be resolvable when *chronyd* is started (i.e. *chronyd* needs
to be started when the network is already up and DNS is working).
The rules are internally represented as a tree of tables with one level per
four bits of the IPv4 or IPv6 address. The order of the *allow* and *deny*
directives matters if they modify the same records of one table, i.e. if one
subnet is included in the other subnet and their prefix lengths are at the same
level. For example, _1.2.3.0/28_ and _1.2.3.0/29_ are in different tables, but
_1.2.3.0/25_ and _1.2.3.0/28_ are in the same table. The configuration can be
verified for individual addresses with the <<chronyc.adoc#accheck,*accheck*>>
command in *chronyc*.
+
A hostname can be specified in the directives instead of the IP address, but
the name must be resolvable when *chronyd* is started, i.e. the network is
already up and DNS is working. If the hostname resolves to multiple addresses,
only the first address (in the order returned by the system resolver) will be
allowed or denied.
+
Note, if the <<initstepslew,*initstepslew*>> directive is used in the
configuration file, each of the computers listed in that directive must allow
@@ -1344,18 +1422,19 @@ client access by this computer for it to work.
[[deny]]*deny* [*all*] [_subnet_]::
This is similar to the <<allow,*allow*>> directive, except that it denies NTP
client access to a particular subnet or host, rather than allowing it.
and NTS-KE client access to a particular subnet or host, rather than allowing
it.
+
The syntax is identical.
The syntax is identical and the directive can be used multiple times too.
+
There is also a *deny all* directive with similar behaviour to the *allow all*
directive.
[[bindaddress]]*bindaddress* _address_::
The *bindaddress* directive binds the socket on which *chronyd* listens for NTP
requests to a local address of the computer. On systems other than Linux, the
address of the computer needs to be already configured when *chronyd* is
started.
The *bindaddress* directive binds the sockets on which *chronyd* listens for
NTP and NTS-KE requests to a local address of the computer. On systems other
than Linux, the address of the computer needs to be already configured when
*chronyd* is started.
+
An example of the use of the directive is:
+
@@ -1368,9 +1447,9 @@ directive can be specified. Therefore, it is not useful on computers which
should serve NTP on multiple network interfaces.
[[binddevice]]*binddevice* _interface_::
The *binddevice* directive binds the NTP server sockets to a network device
specified by the interface name. This directive can specify only one interface
and it is supported on Linux only.
The *binddevice* directive binds the NTP and NTS-KE server sockets to a network
device specified by the interface name. This directive can specify only one
interface and it is supported on Linux only.
+
An example of the directive is:
+
@@ -1384,17 +1463,19 @@ chronyd should send packets in the NTP broadcast mode (i.e. make *chronyd* act
as a broadcast server). Broadcast clients on that subnet will be able to
synchronise.
+
This directive can be used multiple times to specify multiple addresses.
+
The syntax is as follows:
+
----
broadcast 30 192.168.1.255
broadcast 60 192.168.2.255 12123
broadcast 60 ff02::101
broadcast 32 192.168.1.255
broadcast 64 192.168.2.255 12123
broadcast 64 ff02::101
----
+
In the first example, the destination port defaults to UDP port 123 (the normal NTP
port). In the second example, the destination port is specified as 12123. The
first parameter in each case (30 or 60 respectively) is the interval in seconds
first parameter in each case (32 or 64 respectively) is the interval in seconds
between broadcast packets being sent. The second parameter in each case is the
broadcast address to send the packet to. This should correspond to the
broadcast address of one of the network interfaces on the computer where
@@ -1418,10 +1499,8 @@ This directive specifies the maximum amount of memory that *chronyd* is allowed
to allocate for logging of client accesses and the state that *chronyd* as an
NTP server needs to support the interleaved mode for its clients. The default
limit is 524288 bytes, which is sufficient for monitoring about four thousand
clients at the same time.
+
In older *chrony* versions if the limit was set to 0, the memory allocation was
unlimited.
clients at the same time. The maximum value is 2^32-1 (4 GB) on 32-bit systems
and 2^35 (32 GB) on 64-bit systems.
+
An example of the use of this directive is:
+
@@ -1483,7 +1562,9 @@ configuration and to be synchronised to one another, without confusing clients
that poll more than one server. Each server needs to be configured to poll all
other servers with the *local* directive. This ensures only the server with the
smallest reference ID has the local reference active and others are
synchronised to it. When that server fails, another will take over.
synchronised to it. If that server stops responding, the server with the second
smallest reference ID will take over when its local reference mode activates
(root distance reaches the threshold configured by the *distance* option).
+
The *orphan* mode is compatible with the *ntpd*'s orphan mode (enabled by the
*tos orphan* command).
@@ -1492,7 +1573,7 @@ The *orphan* mode is compatible with the *ntpd*'s orphan mode (enabled by the
An example of the directive is:
+
----
local stratum 10 orphan
local stratum 10 orphan distance 0.1
----
[[ntpsigndsocket]]*ntpsigndsocket* _directory_::
@@ -1521,11 +1602,25 @@ The port will be open only when a certificate and key is specified by the
[[ntsservercert]]*ntsservercert* _file_::
This directive specifies a file containing a certificate in the PEM format
for *chronyd* to operate as an NTS server.
for *chronyd* to operate as an NTS server. The file should also include
any intermediate certificates that the clients will need to validate the
server's certificate.
+
This directive can be used multiple times to specify multiple certificates for
different names of the server.
+
The files are loaded only once. *chronyd* needs to be restarted in order to
load a renewed certificate. The <<ntsdumpdir,*ntsdumpdir*>> and
<<dumpdir,*dumpdir*>> directives with the *-r* option of *chronyd* are
recommended for a near-seamless server operation.
[[ntsserverkey]]*ntsserverkey* _file_::
This directive specifies a file containing a private key in the PEM format
for *chronyd* to operate as an NTS server.
+
This directive can be used multiple times to specify multiple keys. The number
of keys must be the same as the number of certificates and the corresponding
files must be specified in the same order.
[[ntsprocesses]]*ntsprocesses* _processes_::
This directive specifies how many helper processes will *chronyd* operating
@@ -1536,7 +1631,9 @@ process will be started and all NTS-KE requests will be handled by the main
[[maxntsconnections]]*maxntsconnections* _connections_::
This directive specifies the maximum number of concurrent NTS-KE connections
per process that the NTS server will accept. The default value is 100.
per process that the NTS server will accept. The default value is 100. The
maximum practical value is half of the system *FD_SETSIZE* constant (usually
1024).
[[ntsdumpdir2]]*ntsdumpdir* _directory_::
This directive specifies a directory where *chronyd* operating as an NTS server
@@ -1554,7 +1651,8 @@ ntsdumpdir @CHRONYVARDIR@
This directory is used also by the <<ntsdumpdir1,NTS client>> to save NTS cookies.
[[ntsntpserver]]*ntsntpserver* _hostname_::
This directive specifies the hostname or address of the NTP server(s) which is
This directive specifies the hostname (as a fully qualified domain name) or
address of the NTP server(s) which is
provided in the NTS-KE response to the clients. It allows the NTS-KE server to
be separated from the NTP server. However, the servers need to share the keys,
i.e. external key management needs to be enabled by setting
@@ -1563,9 +1661,12 @@ to the clients, which means they should use the same server for NTS-KE and NTP.
[[ntsrotate]]*ntsrotate* _interval_::
This directive specifies the rotation interval (in seconds) of the server key
which encrypts the NTS cookies. New keys are generated automatically. The
server keeps two previous keys to give the clients time to get new cookies
encrypted by the latest key. The default interval is 604800 seconds (1 week).
which encrypts the NTS cookies. New keys are generated automatically from the
_/dev/urandom_ device. The server keeps two previous keys to give the clients
time to get new cookies encrypted by the latest key. The interval is measured
as the server's operating time, i.e. the actual interval can be longer if
*chronyd* is not running continuously. The default interval is 604800 seconds
(1 week). The maximum value is 2^31-1 (68 years).
+
The automatic rotation of the keys can be disabled by setting *ntsrotate* to 0.
In this case the keys are assumed to be managed externally. *chronyd* will not
@@ -1574,7 +1675,7 @@ the <<chronyc.adoc#rekey,*rekey*>> command is issued in *chronyc*. The file can
be periodically copied from another server running *chronyd* (which does
not have *ntsrotate* set to 0) in order to have one or more servers dedicated
to NTS-KE. The NTS-KE servers need to be configured with the
<<ntsntpname,*ntsntpname*>> directive to point the clients to the right NTP
<<ntsntpserver,*ntsntpserver*>> directive to point the clients to the right NTP
server.
+
An example of the directive is:
@@ -1822,7 +1923,8 @@ The *rtcautotrim* directive is used to keep the RTC close to the system clock
automatically. When the system clock is synchronised and the estimated error
between the two clocks is larger than the specified threshold, *chronyd* will
trim the RTC as if the <<chronyc.adoc#trimrtc,*trimrtc*>> command in *chronyc*
was issued.
was issued. The trimming operation is accurate to only about 1 second, which is
the minimum effective threshold.
+
This directive is effective only with the <<rtcfile,*rtcfile*>> directive.
+
@@ -2202,6 +2304,8 @@ name, only the first file in the order of the specified directories will be
included. This enables a fragmented configuration where existing fragments can
be replaced by adding files to a different directory.
+
This directive can be used multiple times.
+
An example of the directive is:
+
----
@@ -2211,12 +2315,15 @@ confdir @SYSCONFDIR@/chrony.d
[[sourcedir]]*sourcedir* _directory_...::
The *sourcedir* directive is identical to the *confdir* directive, except the
configuration files have the _.sources_ suffix, they can only specify NTP
sources (i.e. use the *server*, *pool*, and *peer* directive), and can be
sources (i.e. the *server*, *pool*, and *peer* directives), they are expected
to have all lines terminated by the newline character, and they can be
reloaded by the <<chronyc.adoc#reload,*reload sources*>> command in
*chronyc*. It is particularly useful with dynamic sources like NTP servers
received from a DHCP server, which can be written to a file specific to the
network interface by a networking script.
+
This directive can be used multiple times.
+
An example of the directive is:
+
----
@@ -2229,6 +2336,8 @@ files if a wildcard pattern is specified. Unlike with the *confdir* directive,
the full name of the files needs to be specified and at least one file is
required to exist.
+
This directive can be used multiple times.
+
An example of the directive is:
+
----
@@ -2264,8 +2373,9 @@ indicated in the _measurements.log_ file if enabled by the <<log,*log
measurements*>> directive, and the <<chronyc.adoc#ntpdata,*ntpdata*>> report in
*chronyc*.
+
If the specified interface is _*_, *chronyd* will try to enable HW timestamping
on all available interfaces.
This directive can be used multiple times to enable HW timestamping on multiple
interfaces. If the specified interface is _*_, *chronyd* will try to enable HW
timestamping on all available interfaces.
+
The *hwtimestamp* directive has the following options:
+
@@ -2458,7 +2568,7 @@ the following methods:
stratum 1 and stratum 2 servers. You should find one or more servers that are
near to you. Check that their access policy allows you to use their
facilities.
* Use public servers from the http://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_
and _baz.example.net_, your _chrony.conf_ file could contain as a minimum:
@@ -2497,6 +2607,20 @@ makestep 1.0 3
rtcsync
----
If the servers (or pool) support the Network Time Security (NTS)
authentication mechanism and *chronyd* is compiled with NTS support, the *nts*
option will enable a secure synchronisation to the servers. The configuration
file could look like:
----
server foo.example.net iburst nts
server bar.example.net iburst nts
server baz.example.net iburst nts
driftfile @CHRONYVARDIR@/drift
makestep 1.0 3
rtcsync
----
=== NTP client with infrequent connection to NTP servers
This section shows how to configure *chronyd* for computers that have
@@ -2547,22 +2671,22 @@ This section shows how to configure *chronyd* for computers that never have
network connectivity to any computer which ultimately derives its time from a
reference clock.
In this situation, one computer is selected to be the master timeserver. The
other computers are either direct clients of the master, or clients of clients.
In this situation, one computer is selected to be the primary timeserver. The
other computers are either direct clients of the server, or clients of clients.
The <<local,*local*>> directive enables a local reference mode, which allows
*chronyd* to appear synchronised even when it is not.
The rate value in the master's drift file needs to be set to the average rate
at which the master gains or loses time. *chronyd* includes support for this,
The rate value in the server's drift file needs to be set to the average rate
at which the server gains or loses time. *chronyd* includes support for this,
in the form of the <<manual,*manual*>> directive and the
<<chronyc.adoc#settime,*settime*>> command in the *chronyc* program.
If the master is rebooted, *chronyd* can re-read the drift rate from the drift
file. However, the master has no accurate estimate of the current time. To get
around this, the system can be configured so that the master can initially set
If the server is rebooted, *chronyd* can re-read the drift rate from the drift
file. However, the server has no accurate estimate of the current time. To get
around this, the system can be configured so that the server can initially set
itself to a '`majority-vote`' of selected clients' times; this allows the
clients to '`flywheel`' the master while it is rebooting.
clients to '`flywheel`' the server while it is rebooting.
The <<smoothtime,*smoothtime*>> directive is useful when the clocks of the
clients need to stay close together when the local time is adjusted by the
@@ -2571,8 +2695,8 @@ activated by the <<chronyc.adoc#smoothtime,*smoothtime activate*>> command when
the local time is ready to be served. After that point, any adjustments will be
smoothed out.
A typical configuration file for the master (called _master_) might be
(assuming the clients and the master are in the _192.168.165.x_ subnet):
A typical configuration file for the server (called _ntp.local_) might be
(assuming the clients and the server are in the _192.168.165.x_ subnet):
----
initstepslew 1 client1 client3 client6
@@ -2584,11 +2708,11 @@ smoothtime 400 0.01
rtcsync
----
For the clients that have to resynchronise the master when it restarts,
For the clients that have to resynchronise the server when it restarts,
the configuration file might be:
----
server master iburst
server ntp.local iburst
driftfile @CHRONYVARDIR@/drift
allow 192.168.165.0/24
makestep 1.0 3
@@ -2598,22 +2722,22 @@ rtcsync
The rest of the clients would be the same, except that the *allow* directive is
not required.
If there is no suitable computer to be designated as the master, or there is a
requirement to keep the clients synchronised even when it fails, the *orphan*
option of the *local* directive enables a special mode where the master is
selected from multiple computers automatically. They all need to use the same
*local* configuration and poll one another. The server with the smallest
reference ID (which is based on its IP address) will take the role of the
master and others will be synchronised to it. When it fails, the server with
the second smallest reference ID will take over and so on.
If there is no suitable computer to be designated as the primary server, or
there is a requirement to keep the clients synchronised even when it fails, the
*orphan* option of the *local* directive enables a special mode where the
server is selected from multiple computers automatically. They all need to use
the same *local* configuration and poll one another. The server with the
smallest reference ID (which is based on its IP address) will take the role of
the primary server and others will be synchronised to it. When it fails, the
server with the second smallest reference ID will take over and so on.
A configuration file for the first server might be (assuming there are three
servers called _master1_, _master2_, and _master3_):
servers called _ntp1.local_, _ntp2.local_, and _ntp3.local_):
----
initstepslew 1 master2 master3
server master2
server master3
initstepslew 1 ntp2.local ntp3.local
server ntp2.local
server ntp3.local
driftfile @CHRONYVARDIR@/drift
local stratum 8 orphan
manual
@@ -2736,7 +2860,7 @@ information to be saved.
=== Public NTP server
*chronyd* can be configured to operate as a public NTP server, e.g. to join the
http://www.pool.ntp.org/en/join.html[pool.ntp.org] project. The configuration
https://www.pool.ntp.org/en/join.html[pool.ntp.org] project. The configuration
is similar to the NTP client with permanent connection, except it needs to
allow client access from all addresses. It is recommended to find at least four
good servers (e.g. from the pool, or on the NTP homepage). If the server has a

View File

@@ -2,7 +2,7 @@
//
// Copyright (C) Richard P. Curnow 1997-2003
// Copyright (C) Stephen Wadeley 2016
// Copyright (C) Miroslav Lichvar 2009-2017
// Copyright (C) Miroslav Lichvar 2009-2017, 2019-2020
//
// 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
@@ -39,7 +39,7 @@ running.
If no commands are specified on the command line, *chronyc* will expect input
from the user. The prompt _chronyc>_ will be displayed when it is being run
from a terminal. If *chronyc*'s input or output are redirected from or to a file,
the prompt is not shown.
the prompt will not be shown.
There are two ways *chronyc* can access *chronyd*. One is the Internet
Protocol (IPv4 or IPv6) and the other is a Unix domain socket, which is
@@ -60,9 +60,7 @@ default, the commands are accepted only from localhost (127.0.0.1 or ::1).
All other commands are allowed only through the Unix domain socket. When sent
over the network, *chronyd* will respond with a '`Not authorised`' error, even
if it is from localhost. In chrony versions before 2.2 they were allowed
from the network if they were authenticated with a password, but that is no
longer supported.
if it is from localhost.
Having full access to *chronyd* via *chronyc* is more or less equivalent to
being able to modify the *chronyd*'s configuration file and restart it.
@@ -80,11 +78,10 @@ This option disables resolving of IP addresses to hostnames, e.g. to avoid slow
DNS lookups. Long addresses will not be truncated to fit into the column.
*-N*::
This option enables printing of the original names of NTP sources that were
specified in the configuration file, or *chronyc* commands, and are internally
used by *chronyd*. Without the *-n* and *-N* option, the names of NTP sources
are obtained from reverse DNS lookups and can be different from the original
names.
This option enables printing of original hostnames or IP addresses of NTP
sources that were specified in the configuration file, or *chronyc* commands.
Without the *-n* and *-N* option, the printed hostnames are obtained from
reverse DNS lookups and can be different from the specified hostnames.
*-c*::
This option enables printing of reports in a comma-separated values (CSV)
@@ -120,10 +117,14 @@ This option is ignored and is provided only for compatibility.
*-a*::
This option is ignored and is provided only for compatibility.
*-v*::
*-v*, *--version*::
With this option *chronyc* displays its version number on the terminal and
exits.
*--help*::
With this option *chronyc* displays a help message on the terminal and
exits.
== COMMANDS
This section describes each of the commands available within the *chronyc*
@@ -183,10 +184,12 @@ speeding up or slowing down the system clock until the error has been removed,
and then returning to the system clock's normal speed. A consequence of this is
that there will be a period when the system clock (as read by other programs)
will be different from *chronyd*'s estimate of the current true time (which it
reports to NTP clients when it is operating in server mode). The value reported
reports to NTP clients when it is operating as a server). The value reported
on this line is the difference due to this effect.
*Last offset*:::
This is the estimated local offset on the last clock update.
This is the estimated local offset on the last clock update. A positive value
indicates the local time (as previously estimated true time) was ahead of the
time sources.
*RMS offset*:::
This is a long-term average of the offset value.
*Frequency*:::
@@ -317,18 +320,23 @@ The columns are as follows:
This indicates the mode of the source. _^_ means a server, _=_ means a peer
and _#_ indicates a locally connected reference clock.
*S*:::
This column indicates the state of the source.
* _*_ indicates the source to which *chronyd* is currently synchronised.
* _+_ indicates acceptable sources which are combined with the selected
source.
* _-_ indicates acceptable sources which are excluded by the combining
algorithm.
* _?_ indicates sources to which connectivity has been lost or whose packets
do not pass all tests. It is also shown at start-up, until at least 3 samples
have been gathered from it.
* _x_ indicates a clock which *chronyd* thinks is a falseticker (i.e. its
time is inconsistent with a majority of other sources).
This column indicates the selection state of the source.
* _*_ indicates the best source which is currently selected for
synchronisation.
* _+_ indicates other sources selected for synchronisation, which are combined
with the best source.
* _-_ indicates a source which is considered to be selectable for
synchronisation, but not currently selected.
* _x_ indicates a source which *chronyd* thinks is a falseticker (i.e. its
time is inconsistent with a majority of other sources, or sources specified
with the *trust* option).
* _~_ indicates a source whose time appears to have too much variability.
* _?_ indicates a source which is not considered to be selectable for
synchronisation for other reasons (e.g. unreachable, not synchronised, or
does not have enough measurements).
{blank}:::
The <<selectdata,*selectdata*>> command can be used to get more details about
the selection state.
*Name/IP address*:::
This shows the name or the IP address of the source, or reference ID for reference
clocks.
@@ -423,11 +431,11 @@ lines are shown as a reminder of the meanings of the columns.
An example of the output is shown below.
+
----
S Name/IP Address Auth COpts EOpts Last Score Interval
====================================================================
D foo.example.net Y ----- --TR- 4 1.0 -61ms +62ms
* bar.example.net N ----- ----- 0 1.0 -6846us +7305us
+ baz.example.net N ----- ----- 10 1.0 -7381us +7355us
S Name/IP Address Auth COpts EOpts Last Score Interval Leap
=======================================================================
D foo.example.net Y ----- --TR- 4 1.0 -61ms +62ms N
* bar.example.net N ----- ----- 0 1.0 -6846us +7305us N
+ baz.example.net N ----- ----- 10 1.0 -7381us +7355us N
----
+
The columns are as follows:
@@ -499,6 +507,12 @@ be reselected and the scores will be reset to 1.
This column displays the lower and upper endpoint of the interval which was
expected to contain the true offset of the local clock considering the root
distance at the time of the selection.
*Leap*:::
This column displays the current leap status of the source.
* _N_ indicates the normal status (no leap second).
* _+_ indicates that a leap second will be inserted at the end of the month.
* _-_ indicates that a leap second will be deleted at the end of the month.
* _?_ indicates the unknown status (i.e. no valid measurement was made).
[[reselect]]*reselect*::
To avoid excessive switching between sources, *chronyd* can stay synchronised
@@ -1119,11 +1133,8 @@ The effect of the allow command is identical to the
The syntax is illustrated in the following examples:
+
----
allow foo.example.net
allow all 1.2
allow 3.4.5
allow 6.7.8/22
allow 6.7.8.9/22
allow 1.2.3.4
allow all 3.4.5.0/24
allow 2001:db8:789a::/48
allow 0/0
allow ::/0
@@ -1138,11 +1149,8 @@ The effect of the allow command is identical to the
The syntax is illustrated in the following examples:
+
----
deny foo.example.net
deny all 1.2
deny 3.4.5
deny 6.7.8/22
deny 6.7.8.9/22
deny 1.2.3.4
deny all 3.4.5.0/24
deny 2001:db8:789a::/48
deny 0/0
deny ::/0
@@ -1328,10 +1336,7 @@ purged. An example of how to do this is shown below.
----
# mv /var/log/chrony/measurements.log /var/log/chrony/measurements1.log
# chronyc cyclelogs
# ls -l /var/log/chrony
-rw-r--r-- 1 root root 0 Jun 8 18:17 measurements.log
-rw-r--r-- 1 root root 12345 Jun 8 18:17 measurements1.log
# rm -f measurements1.log
# rm /var/log/chrony/measurements1.log
----
[[dump]]*dump*::
@@ -1356,7 +1361,9 @@ The *reset sources* command causes *chronyd* to drop all measurements and
switch to the unsynchronised state. This command can help *chronyd* with
recovery when the measurements are known to be no longer valid or accurate,
e.g. due to moving the computer to a different network, or resuming the
computer from a low-power state (which resets the system clock).
computer from a low-power state (which resets the system clock). *chronyd* will
drop the measurements automatically when it detects the clock has made an
unexpected jump, but the detection is not completely reliable.
[[shutdown]]*shutdown*::
The *shutdown* command causes *chronyd* to exit. This is equivalent to sending
@@ -1423,7 +1430,13 @@ keygen 73 SHA1 256
+
which generates a 256-bit SHA1 key with number 73. The printed line should
then be securely transferred and added to the key files on both server and
client, or peers.
client, or peers. A different key should be generated for each client or peer.
+
An example using the AES128 cipher is:
+
----
keygen 151 AES128
----
[[exit]]*exit*::
[[quit]]*quit*::

View File

@@ -55,7 +55,7 @@ IPv6 sockets will be created.
*-f* _file_::
This option can be used to specify an alternate location for the configuration
file. The default value is _@SYSCONFDIR@/chrony.conf_.
file. The compiled-in default value is _@SYSCONFDIR@/chrony.conf_.
*-n*::
When run in this mode, the program will not detach itself from the terminal.
@@ -137,7 +137,7 @@ running, but still allow it to adjust the frequency of the system clock.
*-u* _user_::
This option sets the name of the system user to which *chronyd* will switch
after start in order to drop root privileges. It overrides the
<<chrony.conf.adoc#user,*user*>> directive. The default value is
<<chrony.conf.adoc#user,*user*>> directive. The compiled-in default value is
_@DEFAULT_USER@_.
+
On Linux, *chronyd* needs to be compiled with support for the *libcap* library.
@@ -145,6 +145,16 @@ On macOS, FreeBSD, NetBSD and Solaris *chronyd* forks into two processes.
The child process retains root privileges, but can only perform a very limited
range of privileged system calls on behalf of the parent.
*-U*::
This option disables a check for root privileges to allow *chronyd* to be
started under a non-root user, assuming the process will have all capabilities
(e.g. provided by the service manager) and access to all files, directories,
and devices, needed to operate correctly in the specified configuration. Note
that different capabilities might be needed with different configurations and
different Linux kernel versions. Starting *chronyd* under a non-root user is
not recommended when the configuration is not known, or at least limited to
specific directives.
*-F* _level_::
This option configures a system call filter when *chronyd* is compiled with
support for the Linux secure computing (seccomp) facility. In level 1 the
@@ -152,10 +162,10 @@ process is killed when a forbidden system call is made, in level -1 the SIGSYS
signal is thrown instead and in level 0 the filter is disabled. The default
value is 0.
+
It's recommended to enable the filter only when it's known to work on the
It is recommended to enable the filter only when it is known to work on the
version of the system where *chrony* is installed as the filter needs to allow
also system calls made from libraries that *chronyd* is using (e.g. libc) and
different versions or implementations of the libraries may make different
different versions or implementations of the libraries might make different
system calls. If the filter is missing some system call, *chronyd* could be
killed even in normal operation.
@@ -174,14 +184,15 @@ This mode is only supported on Linux.
This option disables the control of the system clock. *chronyd* will not try to
make any adjustments of the clock. It will assume the clock is free running and
still track its offset and frequency relative to the estimated true time. This
option allows *chronyd* to run without the capability to adjust or set the
system clock (e.g. in some containers) in order to operate as an NTP server. It
is not recommended to run *chronyd* (with or without *-x*) when another process
is controlling the system clock.
option allows *chronyd* to be started without the capability to adjust or set
the system clock (e.g. in some containers) to operate as an NTP server.
*-v*::
*-v*, *--version*::
With this option *chronyd* will print version number to the terminal and exit.
*-h*, *--help*::
With this option *chronyd* will print a help message to the terminal and exit.
== FILES
_@SYSCONFDIR@/chrony.conf_

View File

@@ -1,7 +1,7 @@
// This file is part of chrony
//
// Copyright (C) Richard P. Curnow 1997-2003
// Copyright (C) Miroslav Lichvar 2014-2016
// Copyright (C) Miroslav Lichvar 2014-2016, 2020
//
// 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
@@ -24,17 +24,20 @@
=== How does `chrony` compare to `ntpd`?
`chronyd` was designed to work well in a wide range of conditions and it can
usually synchronise the system clock faster and with better time accuracy. It
doesn't implement some of the less useful NTP modes like broadcast client or
multicast server/client.
`chrony` and `ntpd` are two different implementations of the Network Time
Protocol (NTP).
`chrony` is a newer implementation, which was designed to work well in a wider
range of conditions. It can usually synchronise the system clock faster and
with better time accuracy. It has many features, but it does not implement some
of the less useful NTP modes like broadcast client or multicast server/client.
If your computer is connected to the Internet only for few minutes at a time,
the network connection is often congested, you turn your computer off or
suspend it frequently, the clock is not very stable (e.g. there are rapid
changes in the temperature or it's a virtual machine), or you want to use NTP
changes in the temperature or it is a virtual machine), or you want to use NTP
on an isolated network with no hardware reference clocks in sight, `chrony`
will probably work much better for you.
will probably work better for you.
For a more detailed comparison of features and performance, see the
https://chrony.tuxfamily.org/comparison.html[comparison page] on the `chrony`
@@ -46,9 +49,11 @@ website.
First, the client needs to know which NTP servers it should ask for the current
time. They are specified by the `server` or `pool` directive. The `pool`
directive can be used for names that resolve to multiple addresses. For good
reliability the client should have at least three servers. The `iburst` option
speeds up the initial synchronisation.
directive is used with names that resolve to multiple addresses of different
servers. For reliable operation, the client should have at least three servers.
The `iburst` option enables a burst of requests to speed up the initial
synchronisation.
To stabilise the initial synchronisation on the next start, the estimated drift
of the system clock is saved to a file specified by the `driftfile` directive.
@@ -59,13 +64,13 @@ slewing, which would take a very long time. The `makestep` directive does
that.
In order to keep the real-time clock (RTC) close to the true time, so the
system time is reasonably close to the true time when it's initialised on the
system time is reasonably close to the true time when it is initialised on the
next boot from the RTC, the `rtcsync` directive enables a mode in which the
system time is periodically copied to the RTC. It is supported on Linux and
macOS.
If you want to use public NTP servers from the
http://www.pool.ntp.org/[pool.ntp.org] project, the minimal _chrony.conf_ file
If you wanted to use public NTP servers from the
https://www.pool.ntp.org/[pool.ntp.org] project, the minimal _chrony.conf_ file
could be:
----
@@ -75,52 +80,43 @@ makestep 1 3
rtcsync
----
=== How do I make an NTP server from an NTP client?
=== How do I make an NTP server?
You need to add an `allow` directive to the _chrony.conf_ file in order to open
the NTP port and allow `chronyd` to reply to client requests. `allow` with no
specified subnet allows access from all IPv4 and IPv6 addresses.
By default, `chronyd` does not operate as an NTP server. You need to add an
`allow` directive to the _chrony.conf_ file in order for `chronyd` to open the
server NTP port and respond to client requests.
=== I have several computers on a LAN. Should be all clients of an external server?
----
allow 192.168.1.0/24
----
The best configuration is usually to make one computer the server, with
the others as clients of it. Add a `local` directive to the server's
_chrony.conf_ file. This configuration will be better because
An `allow` directive with no specified subnet allows access from all IPv4 and
IPv6 addresses.
=== Should all computers on a LAN be clients of an external server?
It depends on the requirements. Usually, the best configuration is to make one
computer the server, with the others as clients of it. Add a `local` directive
to the server's _chrony.conf_ file. This configuration will be better because
* the load on the external connection is less
* the load on the external NTP server(s) is less
* if your external connection goes down, the computers on the LAN
will maintain a common time with each other.
=== Must I specify servers by IP address if DNS is not available on chronyd start?
=== Must I specify servers by IP address if DNS is not available on `chronyd` start?
No. Starting from version 1.25, `chronyd` will keep trying to resolve
No, `chronyd` will keep trying to resolve
the names specified by the `server`, `pool`, and `peer` directives in an
increasing interval until it succeeds. The `online` command can be issued from
`chronyc` to force `chronyd` to try to resolve the names immediately.
=== How can I make `chronyd` more secure?
If you don't need to serve time to NTP clients or peers, you can add `port 0`
to the _chrony.conf_ file to completely disable the NTP server functionality
and prevent NTP requests from reaching `chronyd`. Starting from version 2.0,
the NTP server port is open only when client access is allowed by the `allow`
directive or command, an NTP peer is configured, or the `broadcast` directive
is used.
If you don't need to use `chronyc` remotely, you can add the following
directives to the configuration file to bind the command sockets to the
loopback interface. This is done by default since version 2.0.
----
bindcmdaddress 127.0.0.1
bindcmdaddress ::1
----
If you don't need to use `chronyc` at all or you need to run `chronyc` only
If you do not need to use `chronyc`, or you want to run `chronyc` only
under the root or _chrony_ user (which can access `chronyd` through a Unix
domain socket since version 2.2), you can disable the internet command sockets
completely by adding `cmdport 0` to the configuration file.
domain socket), you can disable the IPv4 and IPv6 command sockets (by default
listening on localhost) by adding `cmdport 0` to the configuration file.
You can specify an unprivileged user with the `-u` option, or the `user`
directive in the _chrony.conf_ file, to which `chronyd` will switch after start
@@ -133,29 +129,144 @@ a very limited range of privileged system calls on behalf of the parent.
Also, if `chronyd` is compiled with support for the Linux secure computing
(seccomp) facility, you can enable a system call filter with the `-F` option.
It will significantly reduce the kernel attack surface and possibly prevent
kernel exploits from the `chronyd` process if it's compromised. It's
recommended to enable the filter only when it's known to work on the version of
kernel exploits from the `chronyd` process if it is compromised. It is
recommended to enable the filter only when it is known to work on the version of
the system where `chrony` is installed as the filter needs to allow also system
calls made from libraries that `chronyd` is using (e.g. libc) and different
versions or implementations of the libraries may make different system calls.
versions or implementations of the libraries might make different system calls.
If the filter is missing some system call, `chronyd` could be killed even in
normal operation.
=== How can I make the system clock more secure?
An NTP client synchronising the system clock to an NTP server is susceptible to
various attacks, which can break applications and network protocols relying on
accuracy of the clock (e.g. DNSSEC, Kerberos, TLS, WireGuard).
Generally, a man-in-the-middle (MITM) attacker between the client and server
can
* make fake responses, or modify real responses from the server, to create an
arbitrarily large time and frequency offset, make the server appear more
accurate, insert a leap second, etc.
* delay the requests and/or responses to create a limited time offset and
temporarily also a limited frequency offset
* drop the requests or responses to prevent updates of the clock with new
measurements
* redirect the requests to a different server
The attacks can be combined for a greater effect. The attacker can delay
packets to create a significant frequency offset first and then drop all
subsequent packets to let the clock quickly drift away from the true time.
The attacker might also be able to control the server's clock.
Some attacks cannot be prevented. Monitoring is needed for detection, e.g. the
reachability register in the `sources` report shows missing packets. The extent
to which the attacker can control the client's clock depends on its
configuration.
Enable authentication to prevent `chronyd` from accepting modified, fake, or
redirected packets. It can be enabled with a symmetric key specified by the
`key` option, or Network Time Security (NTS) by the `nts` option (supported
since `chrony` version 4.0). The server needs to support the selected
authentication mechanism. Symmetric keys have to be configured on both client
and server, and each client must have its own key (one per server).
The maximum offset that the attacker can insert in an NTP measurement by
delaying packets can be limited by the `maxdelay` option. The default value is
3 seconds. The measured delay is reported as the peer delay in the `ntpdata`
report and `measurements` log. Set the `maxdelay` option to a value larger than
the maximum value that is normally observed. Note that the delay can increase
significantly even when not under an attack, e.g. when the network is congested
or the routing has changed.
The maximum accepted change in time offset between clock updates can be limited
by the `maxchange` directive. Larger changes in the offset will be ignored or
cause `chronyd` to exit. Note that the attacker can get around this limit by
splitting the offset into multiple smaller offsets and/or creating a large
frequency offset. When this directive is used, `chronyd` will have to be
restarted after a successful attack. It will not be able to recover on its own.
It must not be restarted automatically (e.g. by the service manager).
The impact of a large accepted time offset can be reduced by disabling clock
steps, i.e. by not using the `makestep` and `initstepslew` directives. The
offset will be slowly corrected by speeding up or slowing down the clock at a
rate which can be limited by the `maxslewrate` directive. Disabling clock steps
completely is practical only if the clock cannot gain a larger error on its
own, e.g. when the computer is shut down or suspended, and the `maxslewrate`
limit is large enough to correct an expected error in an acceptable time. The
`rtcfile` directive with the `-s` option can be used to compensate for the RTC
drift.
A more practical approach is to enable `makestep` for a limited number of clock
updates (the 2nd argument of the directive) and limit the offset change in all
updates by the `maxchange` directive. The attacker will be able to make only a
limited step and only if the attack starts in a short window after booting the
computer, or when `chronyd` is restarted without the `-R` option.
The frequency offset can be limited by the `maxdrift` directive. The measured
frequency offset is reported in the drift file, `tracking` report, and
`tracking` log. Set `maxdrift` to a value larger than the maximum absolute
value that is normally observed. Note that the frequency of the clock can
change due to aging of the crystal, differences in calibration of the clock
source between reboots, migrated virtual machine, etc. A typical computer clock
has a drift smaller than 100 parts per million (ppm), but much larger drifts
are possible (e.g. in some virtual machines).
Use only trusted servers, which you expect to be well configured and managed,
using authentication for their own servers, etc. Use multiple servers, ideally
in different locations. The attacker will have to deal with a majority of the
servers in order to pass the source selection and update the clock with a large
offset. Use the `minsources` directive to increase the required number of
selectable sources to make the selection more robust.
Do not specify servers as peers. The symmetric mode is less secure than the
client/server mode. If not authenticated, it is vulnerable to off-path
denial-of-service attacks, and even when it is authenticated, it is still
susceptible to replay attacks.
Mixing of authenticated and unauthenticated servers should generally be
avoided. If mixing is necessary (e.g. for a more accurate and stable
synchronisation to a closer server which does not support authentication), the
authenticated servers should be configured as trusted and required to not allow
the unauthenticated servers to override the authenticated servers in the source
selection. Since `chrony` version 4.0, the selection options are enabled in
such a case automatically. This behaviour can be disabled or modified by the
`authselmode` directive.
An example of a client configuration limiting the impact of the attacks could
be
----
server foo.example.net iburst nts maxdelay 0.1
server bar.example.net iburst nts maxdelay 0.2
server baz.example.net iburst nts maxdelay 0.05
server qux.example.net iburst nts maxdelay 0.1
server quux.example.net iburst nts maxdelay 0.1
minsources 3
maxchange 100 0 0
makestep 0.001 1
maxdrift 100
maxslewrate 100
driftfile /var/lib/chrony/drift
ntsdumpdir /var/lib/chrony
rtcsync
----
=== How can I improve the accuracy of the system clock with NTP sources?
Select NTP servers that are well synchronised, stable and close to your
network. It's better to use more than one server, three or four is usually
network. It is better to use more than one server. Three or four is usually
recommended as the minimum, so `chronyd` can detect servers that serve false
time and combine measurements from multiple sources.
If you have a network card with hardware timestamping supported on Linux, it
can be enabled by the *hwtimestamp* directive in the _chrony.conf_ file. It
should make local receive and transmit timestamps of NTP packets much more
accurate.
can be enabled by the `hwtimestamp` directive. It should make local receive and
transmit timestamps of NTP packets much more stable and accurate.
There are also useful options which can be set in the `server` directive, they
are `minpoll`, `maxpoll`, `polltarget`, `maxdelay`, `maxdelayratio`,
`maxdelaydevratio`, and `xleave`.
The `server` directive has some useful options: `minpoll`, `maxpoll`,
`polltarget`, `maxdelay`, `maxdelayratio`, `maxdelaydevratio`, `xleave`,
`filter`.
The first three options set the minimum and maximum allowed polling interval,
and how should be the actual interval adjusted in the specified range. Their
@@ -163,8 +274,8 @@ default values are 6 (64 seconds) for `minpoll`, 10 (1024 seconds) for
`maxpoll` and 8 (samples) for `polltarget`. The default values should be used
for general servers on the Internet. With your own NTP servers, or if you have
permission to poll some servers more frequently, setting these options for
shorter polling intervals may significantly improve the accuracy of the system
clock.
shorter polling intervals might significantly improve the accuracy of the
system clock.
The optimal polling interval depends mainly on two factors, stability of the
network latency and stability of the system clock (which mainly depends on the
@@ -174,7 +285,7 @@ temperature change).
Generally, if the `sourcestats` command usually reports a small number of
samples retained for a source (e.g. fewer than 16), a shorter polling interval
should be considered. If the number of samples is usually at the maximum of 64,
a longer polling interval may work better.
a longer polling interval might work better.
An example of the directive for an NTP server on the Internet that you are
allowed to poll frequently could be
@@ -190,7 +301,7 @@ LAN could be
server ntp.local minpoll 2 maxpoll 4 polltarget 30
----
The maxdelay options are useful to ignore measurements with an unusally large
The maxdelay options are useful to ignore measurements with an unusually large
delay (e.g. due to congestion in the network) and improve the stability of the
synchronisation. The `maxdelaydevratio` option could be added to the example
with local NTP server
@@ -200,8 +311,8 @@ server ntp.local minpoll 2 maxpoll 4 polltarget 30 maxdelaydevratio 2
----
If your server supports the interleaved mode (e.g. it is running `chronyd`),
the `xleave` option should be added to the `server` directive in order to allow
the server to send the client more accurate transmit timestamps (kernel or
the `xleave` option should be added to the `server` directive to enable the
server to provide the client with more accurate transmit timestamps (kernel or
preferably hardware). For example:
----
@@ -210,7 +321,7 @@ server ntp.local minpoll 2 maxpoll 4 xleave
When combined with local hardware timestamping, good network switches, and even
shorter polling intervals, a sub-microsecond accuracy and stability of a few
tens of nanoseconds may be possible. For example:
tens of nanoseconds might be possible. For example:
----
server ntp.local minpoll 0 maxpoll 0 xleave
@@ -221,10 +332,11 @@ For best stability, the CPU should be running at a constant frequency (i.e.
disabled power saving and performance boosting). Energy-Efficient Ethernet
(EEE) should be disabled in the network. The switches should be configured to
prioritize NTP packets, especially if the network is expected to be heavily
loaded.
loaded. The `dscp` directive can be used to set the Differentiated Services
Code Point in transmitted NTP packets if needed.
If it is acceptable for NTP clients in the network to send requests at an
excessive rate, a sub-second polling interval may be specified. A median filter
If it is acceptable for NTP clients in the network to send requests at a high
rate, a sub-second polling interval can be specified. A median filter
can be enabled in order to update the clock at a reduced rate with more stable
measurements. For example:
@@ -237,7 +349,7 @@ hwtimestamp eth0 minpoll -6
Yes. With the `-q` option `chronyd` will set the system clock once and exit.
With the `-Q` option it will print the measured offset without setting the
clock. If you don't want to use a configuration file, NTP servers can be
clock. If you do not want to use a configuration file, NTP servers can be
specified on the command line. For example:
----
@@ -249,17 +361,28 @@ well synchronised and responding to all requests. If not synchronised or
responding, it would take about 10 seconds for `chronyd` to give up and exit
with a non-zero status. A faster configuration is possible. A single server can
be used instead of four servers, the number of measurements can be reduced with
the `maxsamples` option, and a timeout can be specified with the `-t` option.
The following command would take only up to about 1 second.
the `maxsamples` option to one (supported since `chrony` version 4.0), and a
timeout can be specified with the `-t` option. The following command would take
only up to about one second.
----
# chronyd -q -t 1 'server pool.ntp.org iburst maxsamples 1'
----
It is not recommended to run `chronyd` with the `-q` option periodically (e.g.
from a cron job) as a replacement for the daemon mode, because it performs
significantly worse (e.g. the clock is stepped and its frequency is not
corrected). If you must run it this way and you are using a public NTP server,
make sure `chronyd` does not always start around the first second of a minute,
e.g. by adding a random sleep before the `chronyd` command. Public servers
typically receive large bursts of requests around the first second as there is
a large number of NTP clients started from cron with no delay.
=== Can `chronyd` be configured to control the clock like `ntpd`?
It is not possible to perfectly emulate `ntpd`, but there are some options that
can configure `chronyd` to behave more like `ntpd`.
can configure `chronyd` to behave more like `ntpd` if there is a reason to
prefer that.
In the following example the `minsamples` directive slows down the response to
changes in the frequency and offset of the clock. The `maxslewrate` and
@@ -279,10 +402,87 @@ maxchange 1000 1 1
maxclockerror 15
----
Note that increasing `minsamples` may cause the offsets in the `tracking` and
Note that increasing `minsamples` might cause the offsets in the `tracking` and
`sourcestats` reports/logs to be significantly smaller than the actual offsets
and be unsuitable for monitoring.
=== Can NTP server be separated from NTP client?
Yes, it is possible to run multiple instances of `chronyd` on a computer at the
same time. One can operate primarily as an NTP client to synchronise the system
clock and another as a server for other computers. If they use the same
filesystem, they need to be configured with different pidfiles, Unix domain
command sockets, and any other file or directory specified in the configuration
file. If they run in the same network namespace, they need to use different NTP
and command ports, or bind the ports to different addresses or interfaces.
The server instance should be started with the `-x` option to prevent it from
adjusting the system clock and interfering with the client instance. It can be
configured as a client to synchronise its NTP clock to other servers, or the
client instance running on the same computer. In the latter case, the `copy`
option (added in `chrony` version 4.1) can be used to assume the reference ID
and stratum of the client instance, which enables detection of synchronisation
loops with its own clients.
On Linux, starting with `chrony` version 4.0, it is possible to run multiple
server instances sharing a port to better utilise multiple cores of the CPU.
Note that for rate limiting and client/server interleaved mode to work well
it is necessary that all packets received from the same address are handled by
the same server instance.
An example configuration of the client instance could be
----
pool pool.ntp.org iburst
allow 127.0.0.1
port 11123
driftfile /var/lib/chrony/drift
makestep 1 3
rtcsync
----
and configuration of the first server instance could be
----
server 127.0.0.1 port 11123 minpoll 0 maxpoll 0 copy
allow
cmdport 11323
bindcmdaddress /var/run/chrony/chronyd-server1.sock
pidfile /var/run/chronyd-server1.pid
driftfile /var/lib/chrony/drift-server1
----
=== Should be a leap smear enabled on NTP server?
With the `smoothtime` and `leapsecmode` directives it is possible to enable a
server leap smear in order to hide leap seconds from clients and force them to
follow a slow server's adjustment instead.
This feature should be used only in local networks and only when necessary,
e.g. when the clients cannot be configured to handle the leap seconds as
needed, or their number is so large that configuring them all would be
impractical. The clients should use only one leap-smearing server, or multiple
identically configured leap-smearing servers. Note that some clients can get
leap seconds from other sources (e.g. with the `leapsectz` directive in
`chrony`) and they will not work correctly with a leap smearing server.
=== Does `chrony` support PTP?
No, the Precision Time Protocol (PTP) is not supported and there are no plans
to support it. It is a complex protocol, which shares some issues with the
NTP broadcast mode. One of the main differences between NTP and PTP is that PTP
was designed to be easily supported in hardware (e.g. network switches and
routers) in order to make more stable and accurate measurements. PTP relies on
the hardware support. NTP does not rely on any support in the hardware, but if
it had the same support as PTP, it could perform equally well.
On Linux, `chrony` supports hardware clocks that some NICs have for PTP. They
are called PTP hardware clocks (PHC). They can be used as reference clocks
(specified by the `refclock` directive) and for hardware timestamping of NTP
packets (enabled by the `hwtimestamp` directive) if the NIC can timestamp other
packets than PTP, which is usually the case at least for transmitted packets.
The `ethtool -T` command can be used to verify the timestamping support.
=== What happened to the `commandkey` and `generatecommandkey` directives?
They were removed in version 2.2. Authentication is no longer supported in the
@@ -299,18 +499,17 @@ following questions.
=== Behind a firewall?
Check the `Reach` value printed by the ``chronyc``'s `sources` command. If it's
zero, it means `chronyd` did not get any valid responses from the NTP server
Check the `Reach` value printed by the ``chronyc``'s `sources` command. If it
is zero, it means `chronyd` did not get any valid responses from the NTP server
you are trying to use. If there is a firewall between you and the server, the
packets may be blocked. Try using a tool like `wireshark` or `tcpdump` to see
if you're getting any responses from the server.
packets might be blocked. Try using a tool like `wireshark` or `tcpdump` to see
if you are getting any responses from the server.
When `chronyd` is receiving responses from the servers, the output of the
`sources` command issued few minutes after `chronyd` start might look like
this:
----
210 Number of sources = 3
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^* foo.example.net 2 6 377 34 +484us[ -157us] +/- 30ms
@@ -320,9 +519,10 @@ MS Name/IP address Stratum Poll Reach LastRx Last sample
=== Are NTP servers specified with the `offline` option?
Check that you're using ``chronyc``'s `online` and `offline` commands
appropriately. The `activity` command prints the number of sources that are
currently online and offline. For example:
Check that the ``chronyc``'s `online` and `offline` commands are used
appropriately (e.g. in the system networking scripts). The `activity` command
prints the number of sources that are currently online and offline. For
example:
----
200 OK
@@ -333,6 +533,19 @@ currently online and offline. For example:
0 sources with unknown address
----
=== Is name resolution working correctly?
NTP servers specified by their hostname (instead of an IP address) have to have
their names resolved before `chronyd` can send any requests to them. If the
`activity` command prints a non-zero number of sources with unknown address,
there is an issue with the resolution. Typically, a DNS server is specified in
_/etc/resolv.conf_. Make sure it is working correctly.
Since `chrony` version 4.0, you can run `chronyc -N sources -a` command to
print all sources, even those that do not have a known address yet, with their
names as they were specified in the configuration. This can be useful to verify
that the names specified in the configuration are used as expected.
=== Is `chronyd` allowed to step the system clock?
By default, `chronyd` adjusts the clock gradually by slowing it down or
@@ -349,9 +562,9 @@ makestep 1 3
----
the clock would be stepped in the first three updates if its offset was larger
than one second. Normally, it's recommended to allow the step only in the first
than one second. Normally, it is recommended to allow the step only in the first
few updates, but in some cases (e.g. a computer without an RTC or virtual
machine which can be suspended and resumed with an incorrect time) it may be
machine which can be suspended and resumed with an incorrect time) it might be
necessary to allow the step on any clock update. The example above would change
to
@@ -359,11 +572,55 @@ to
makestep 1 -1
----
=== Using NTS?
The Network Time Security (NTS) mechanism uses Transport Layer Security (TLS)
to establish the keys needed for authentication of NTP packets.
Run the `authdata` command to check whether the key establishment was
successful:
----
# chronyc -N authdata
Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen
=========================================================================
foo.example.net NTS 1 15 256 33m 0 0 8 100
bar.example.net NTS 1 15 256 33m 0 0 8 100
baz.example.net NTS 1 15 256 33m 0 0 8 100
----
The KeyID, Type, and KLen columns should have non-zero values. If they are
zero, check the system log for error messages from `chronyd`. One possible
cause of failure is a firewall blocking the client's connection to the server's
TCP port 4460.
Another possible cause of failure is a certificate that is failing to verify
because the client's clock is wrong. This is a chicken-and-egg problem with NTS.
You might need to manually correct the date, or temporarily disable NTS, in
order to get NTS working. If your computer has an RTC and it is backed up by a
good battery, this operation should be needed only once, assuming the RTC will
be set periodically with the `rtcsync` directive, or compensated with the
`rtcfile` directive and the `-s` option.
If the computer does not have an RTC or battery, you can use the `-s` option
without `rtcfile` directive to restore time of the last shutdown or reboot from
the drift file. The clock will start behind the true time, but if the computer
was not shut down for too long and the server's certificate was not renewed too
close to its expiration, it should be sufficient for the time checks to
succeed.
As a last resort, you can disable the time checks by the `nocerttimecheck`
directive. This has some important security implications. To reduce the
security risk, you can use the `nosystemcert` and `ntstrustedcerts` directives
to disable the system's default trusted certificate authorities and trust only
a minimal set of selected authorities needed to validate the certificates of
used NTP servers.
=== Using a Windows NTP server?
A common issue with Windows NTP servers is that they report a very large root
dispersion (e.g. three seconds or more), which causes `chronyd` to ignore the
server for being too inaccurate. The `sources` command may show a valid
server for being too inaccurate. The `sources` command might show a valid
measurement, but the server is not selected for synchronisation. You can check
the root dispersion of the server with the ``chronyc``'s `ntpdata` command.
@@ -374,6 +631,52 @@ synchronisation to such a server. For example:
maxdistance 16.0
----
=== An unreachable source is selected?
When `chronyd` is configured with multiple time sources, it tries to select the
most accurate and stable sources for synchronisation of the system clock. They
are marked with the _*_ or _+_ symbol in the report printed by the `sources`
command.
When the best source (marked with the _*_ symbol) becomes unreachable (e.g. NTP
server stops responding), `chronyd` will not immediately switch
to the second best source in an attempt to minimise the error of the clock. It
will let the clock run free for as long as its estimated error (in terms of
root distance) based on previous measurements is smaller than the estimated
error of the second source, and there is still an interval which contains some
measurements from both sources.
If the first source was significantly better than the second source, it can
take many hours before the second source is selected, depending on its polling
interval. You can force a faster reselection by increasing the clock error rate
(`maxclockerror` directive), shortening the polling interval (`maxpoll`
option), or reducing the number of samples (`maxsamples` option).
=== Does selected source drop new measurements?
`chronyd` can drop a large number of successive NTP measurements if they are
not passing some of the NTP tests. The `sources` command can report for a
selected source the fully-reachable value of 377 in the Reach column and at the
same time a LastRx value that is much larger than the current polling interval.
If the source is online, this indicates that a number of measurements was
dropped. You can use the `ntpdata` command to check the NTP tests for the last
measurement. Usually, it is the test C which fails.
This can be an issue when there is a long-lasting increase in the measured
delay, e.g. due to a routing change in the network. Unfortunately, `chronyd`
does not know for how long it should wait for the delay to come back to the
original values, or whether it is a permanent increase and it should start from
scratch.
The test C is an adaptive filter. It can take many hours before it accepts
a measurement with the larger delay, and even much longer before it drops all
measurements with smaller delay, which determine an expected delay used by the
test. You can use the `reset sources` command to drop all measurements
immediately (available in chrony 4.0 and later). If this issue happens
frequently, you can effectively disable the test by setting the
`maxdelaydevratio` option to a very large value (e.g. 1000000), or speed up the
recovery by increasing the clock error rate with the `maxclockerror` directive.
=== Using a PPS reference clock?
A pulse-per-second (PPS) reference clock requires a non-PPS time source to
@@ -409,15 +712,15 @@ to be used for synchronisation.
When accessing `chronyd` remotely, make sure that the _chrony.conf_ file (on
the computer where `chronyd` is running) has a `cmdallow` entry for the
computer you are running `chronyc` on and an appropriate `bindcmdaddress`
directive. This isn't necessary for localhost.
directive. This is not necessary for localhost.
Perhaps `chronyd` is not running. Try using the `ps` command (e.g. on Linux,
`ps -auxw`) to see if it's running. Or try `netstat -a` and see if the ports
123/udp and 323/udp are listening. If `chronyd` is not running, you may have a
problem with the way you are trying to start it (e.g. at boot time).
`ps -auxw`) to see if it is running. Or try `netstat -a` and see if the UDP
port 323 is listening. If `chronyd` is not running, you might have a problem
with the way you are trying to start it (e.g. at boot time).
Perhaps you have a firewall set up in a way that blocks packets on port
323/udp. You need to amend the firewall configuration in this case.
Perhaps you have a firewall set up in a way that blocks packets on the UDP
port 323. You need to amend the firewall configuration in this case.
=== I keep getting the error `501 Not authorised`
@@ -426,20 +729,16 @@ socket instead of the Unix domain socket (e.g. _/var/run/chrony/chronyd.sock_),
which is required for some commands. For security reasons, only the root and
_chrony_ users are allowed to access the socket.
It is also possible that the socket doesn't exist. `chronyd` will not create
It is also possible that the socket does not exist. `chronyd` will not create
the socket if the directory has a wrong owner or permissions. In this case
there should be an error message from `chronyd` in the system log.
With versions older than 2.2, which don't use the Unix domain socket, you need
to authenticate with the `password` command first,
or use the `-a` option to authenticate automatically on start. The
configuration file needs to specify a file which contains keys (`keyfile`
directive) and which key in the key file should be used for `chronyc`
authentication (`commandkey` directive).
=== What is the reference ID reported by the `tracking` command?
=== Why does `chronyc tracking` always print an IPv4 address as reference ID?
The reference ID is a 32-bit value used in NTP to prevent synchronisation
loops.
The reference ID is a 32-bit value and in versions before 3.0 it was printed in
In `chrony` versions before 3.0 it was printed in the
quad-dotted notation, even if the reference source did not actually have an
IPv4 address. For IPv4 addresses, the reference ID is equal to the address, but
for IPv6 addresses it is the first 32 bits of the MD5 sum of the address. For
@@ -463,12 +762,12 @@ Only by the source code. See _cmdmon.c_ (`chronyd` side) and _client.c_
=== What is the real-time clock (RTC)?
This is the clock which keeps the time even when your computer is turned off.
It is used to initialise the system clock on boot. It normally doesn't drift
It is used to initialise the system clock on boot. It normally does not drift
more than few seconds per day.
There are two approaches how `chronyd` can work with it. One is to use the
`rtcsync` directive, which tells `chronyd` to enable a kernel mode which sets
the RTC from the system clock every 11 minutes. `chronyd` itself won't touch
the RTC from the system clock every 11 minutes. `chronyd` itself will not touch
the RTC. If the computer is not turned off for a long time, the RTC should
still be close to the true time when the system clock will be initialised from
it on the next boot.
@@ -478,17 +777,17 @@ monitor the rate at which the RTC gains or loses time. When `chronyd` is
started with the `-s` option on the next boot, it will set the system time from
the RTC and also compensate for the drift it has measured previously. The
`rtcautotrim` directive can be used to keep the RTC close to the true time, but
it's not strictly necessary if its only purpose is to set the system clock when
it is not strictly necessary if its only purpose is to set the system clock when
`chronyd` is started on boot. See the documentation for details.
=== I want to use ``chronyd``'s RTC support. Must I disable `hwclock`?
=== Does `hwclock` have to be disabled?
The `hwclock` program is often set-up by default in the boot and shutdown
scripts with many Linux installations. With the kernel RTC synchronisation
The `hwclock` program is run by default in the boot and/or shutdown
scripts in some Linux installations. With the kernel RTC synchronisation
(`rtcsync` directive), the RTC will be set also every 11 minutes as long as the
system clock is synchronised. If you want to use ``chronyd``'s RTC monitoring
(`rtcfile` directive), it's important to disable `hwclock` in the shutdown
procedure. If you don't, it will over-write the RTC with a new value, unknown
(`rtcfile` directive), it is important to disable `hwclock` in the shutdown
procedure. If you do not do that, it will overwrite the RTC with a new value, unknown
to `chronyd`. At the next reboot, `chronyd` started with the `-s` option will
compensate this (wrong) time with its estimate of how far the RTC has drifted
whilst the power was off, giving a meaningless initial system time.
@@ -507,7 +806,20 @@ things
=== I get `Could not open /dev/rtc, Device or resource busy` in my syslog file
Some other program running on the system may be using the device.
Some other program running on the system might be using the device.
=== When I start `chronyd`, the log says `Could not enable RTC interrupt : Invalid argument` (or it may say `disable`)
Your real-time clock hardware might not support the required ioctl requests:
* `RTC_UIE_ON`
* `RTC_UIE_OFF`
A possible solution could be to build the Linux kernel with support for software
emulation instead; try enabling the following configuration option when building
the Linux kernel:
* `CONFIG_RTC_INTF_DEV_UIE_EMUL`
=== What if my computer does not have an RTC or backup battery?
@@ -522,7 +834,7 @@ observe backward steps.
=== Can `chronyd` be driven from broadcast/multicast NTP servers?
No, the broadcast/multicast client mode is not supported and there is currently
no plan to implement it. While the mode may be useful to simplify configuration
no plan to implement it. While this mode can simplify configuration
of clients in large networks, it is inherently less accurate and less secure
(even with authentication) than the ordinary client/server mode.
@@ -539,7 +851,8 @@ thousands of clients using the ordinary client/server mode.
Yes, the `broadcast` directive can be used to enable the broadcast server mode
to serve time to clients in the network which support the broadcast client mode
(it's not supported in `chronyd`, see the previous question).
(it is not supported in `chronyd`). Note that this mode should generally be
avoided. See the previous question.
=== Can `chronyd` keep the system clock a fixed offset away from real time?
@@ -555,9 +868,21 @@ offline, `chronyd` would make new measurements immediately after issuing the
`online` command.
Unless the network connection lasts only few minutes (less than the maximum
polling interval), the delay is usually not a problem, and it may be acceptable
polling interval), the delay is usually not a problem, and it might be acceptable
to keep all sources online all the time.
=== Why is an offset measured between two computers synchronised to each another?
When two computers are synchronised to each other using the client/server or
symmetric NTP mode, there is an expectation that NTP measurements between the
two computers made on both ends show an average offset close to zero.
With `chronyd` that can be expected only when the interleaved mode is enabled
by the `xleave` option. Otherwise, `chronyd` will use different transmit
timestamps (e.g. daemon timestamp vs kernel timestamp) for serving time and
synchronisation of its own clock, which will cause the other computer to
measure a significant offset.
== Operating systems
=== Does `chrony` support Windows?

View File

@@ -94,13 +94,13 @@ want to enable the support, specify the `--disable-asyncdns` flag to
If development files for the https://www.lysator.liu.se/~nisse/nettle/[Nettle],
https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS[NSS], or
http://www.libtom.net/LibTomCrypt/[libtomcrypt] library are available,
https://www.libtom.net/LibTomCrypt/[libtomcrypt] library are available,
`chronyd` will be built with support for other cryptographic hash functions
than MD5, which can be used for NTP authentication with a symmetric key. If you
don't want to enable the support, specify the `--disable-sechash` flag to
`configure`.
If development files for the editline or readline library are available,
If development files for the editline library are available,
`chronyc` will be built with line editing support. If you don't want this,
specify the `--disable-readline` flag to `configure`.
@@ -170,43 +170,6 @@ https://github.com/seccomp/libseccomp[libseccomp] library and the
the kernel attack surface and possibly prevent kernel exploits from `chronyd`
if it is compromised.
== Support for line editing libraries
`chronyc` can be built with support for line editing, this allows you to use
the cursor keys to replay and edit old commands. Two libraries are supported
which provide such functionality, editline and GNU readline.
Please note that readline since version 6.0 is licensed under GPLv3+ which is
incompatible with chrony's license GPLv2. You should use editline instead if
you don't want to use older readline versions.
The `configure` script will automatically enable the line editing support if
one of the supported libraries is available. If they are both available, the
editline library will be used.
If you don't want to use it (in which case `chronyc` will use a minimal command
line interface), invoke `configure` like this:
----
./configure --disable-readline other-options...
----
If you have editline, readline or ncurses installed in locations that aren't
normally searched by the compiler and linker, you need to use extra options:
`--with-readline-includes=directory_name`::
This defines the name of the directory above the one where `readline.h` is.
`readline.h` is assumed to be in `editline` or `readline` subdirectory of the
named directory.
`--with-readline-library=directory_name`::
This defines the directory containing the `libedit.a` or `libedit.so` file,
or `libreadline.a` or `libreadline.so` file.
`--with-ncurses-library=directory_name`::
This defines the directory containing the `libncurses.a` or `libncurses.so`
file.
== Extra options for package builders
The `configure` and `make` procedures have some extra options that may be

View File

@@ -8,9 +8,11 @@ Wants=time-sync.target
[Service]
Type=oneshot
# Wait up to ~10 minutes for chronyd to synchronize and the remaining
# clock correction to be less than 0.1 seconds
ExecStart=/usr/bin/chronyc -h 127.0.0.1,::1 waitsync 600 0.1 0.0 1
# Wait for chronyd to update the clock and the remaining
# correction to be less than 0.1 seconds
ExecStart=/usr/bin/chronyc -h 127.0.0.1,::1 waitsync 0 0.1 0.0 1
# Wait for at most 3 minutes
TimeoutStartSec=180
RemainAfterExit=yes
StandardOutput=null

View File

@@ -1,5 +1,5 @@
# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
# Please consider joining the pool (https://www.pool.ntp.org/join.html).
pool pool.ntp.org iburst
# Record the rate at which the system clock gains/losses time.

2
keys.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2012-2016
* Copyright (C) Miroslav Lichvar 2012-2016, 2019-2020
*
* 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

53
local.c
View File

@@ -108,8 +108,8 @@ static double max_clock_error;
#define NSEC_PER_SEC 1000000000
static void
calculate_sys_precision(void)
static double
measure_clock_precision(void)
{
struct timespec ts, old_ts;
int iters, diff, best;
@@ -135,18 +135,7 @@ calculate_sys_precision(void)
assert(best > 0);
precision_quantum = 1.0e-9 * best;
/* Get rounded log2 value of the measured precision */
precision_log = 0;
while (best < 707106781) {
precision_log--;
best *= 2;
}
assert(precision_log >= -30);
DEBUG_LOG("Clock precision %.9f (%d)", precision_quantum, precision_log);
return 1.0e-9 * best;
}
/* ================================================== */
@@ -170,7 +159,16 @@ LCL_Initialise(void)
current_freq_ppm = 0.0;
temp_comp_ppm = 0.0;
calculate_sys_precision();
precision_quantum = CNF_GetClockPrecision();
if (precision_quantum <= 0.0)
precision_quantum = measure_clock_precision();
precision_quantum = CLAMP(1.0e-9, precision_quantum, 1.0);
precision_log = round(log(precision_quantum) / log(2.0));
/* NTP code doesn't support smaller log than -30 */
assert(precision_log >= -30);
DEBUG_LOG("Clock precision %.9f (%d)", precision_quantum, precision_log);
/* This is the maximum allowed frequency offset in ppm, the time must
never stop or run backwards */
@@ -507,7 +505,7 @@ LCL_AccumulateDeltaFrequency(double dfreq)
/* ================================================== */
void
int
LCL_AccumulateOffset(double offset, double corr_rate)
{
struct timespec raw, cooked;
@@ -519,12 +517,14 @@ LCL_AccumulateOffset(double offset, double corr_rate)
LCL_CookTime(&raw, &cooked, NULL);
if (!check_offset(&cooked, offset))
return;
return 0;
(*drv_accrue_offset)(offset, corr_rate);
/* Dispatch to all handlers */
invoke_parameter_change_handlers(&raw, &cooked, 0.0, offset, LCL_ChangeAdjust);
return 1;
}
/* ================================================== */
@@ -588,7 +588,7 @@ LCL_NotifyLeap(int leap)
/* ================================================== */
void
int
LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
{
struct timespec raw, cooked;
@@ -600,7 +600,7 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
LCL_CookTime(&raw, &cooked, NULL);
if (!check_offset(&cooked, doffset))
return;
return 0;
old_freq_ppm = current_freq_ppm;
@@ -622,6 +622,8 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
/* Dispatch to all handlers */
invoke_parameter_change_handlers(&raw, &cooked, dfreq, doffset, LCL_ChangeAdjust);
return 1;
}
/* ================================================== */
@@ -689,6 +691,19 @@ LCL_MakeStep(void)
/* ================================================== */
void
LCL_CancelOffsetCorrection(void)
{
struct timespec raw;
double correction;
LCL_ReadRawTime(&raw);
LCL_GetOffsetCorrection(&raw, &correction, NULL);
LCL_AccumulateOffset(correction, 0.0);
}
/* ================================================== */
int
LCL_CanSystemLeap(void)
{

View File

@@ -149,7 +149,7 @@ extern void LCL_AccumulateDeltaFrequency(double dfreq);
forwards (i.e. it is currently slow of true time). Provided is also
a suggested correction rate (correction time * offset). */
extern void LCL_AccumulateOffset(double offset, double corr_rate);
extern int LCL_AccumulateOffset(double offset, double corr_rate);
/* Routine to apply an immediate offset by doing a sudden step if
possible. (Intended for use after an initial estimate of offset has
@@ -171,7 +171,7 @@ extern void LCL_NotifyLeap(int leap);
/* Perform the combination of modifying the frequency and applying
a slew, in one easy step */
extern void LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate);
extern int LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate);
/* Routine to read the system precision as a log to base 2 value. */
extern int LCL_GetSysPrecisionAsLog(void);
@@ -197,6 +197,9 @@ extern void LCL_Finalise(void);
to a timezone problem. */
extern int LCL_MakeStep(void);
/* Routine to cancel the outstanding system clock correction */
extern void LCL_CancelOffsetCorrection(void);
/* Check if the system driver supports leap seconds, i.e. LCL_SetSystemLeap
does something */
extern int LCL_CanSystemLeap(void);

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011-2014, 2018
* Copyright (C) Miroslav Lichvar 2011-2014, 2018-2020
*
* 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

55
main.c
View File

@@ -4,7 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) John G. Hasler 2009
* Copyright (C) Miroslav Lichvar 2012-2018
* Copyright (C) Miroslav Lichvar 2012-2020
*
* 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
@@ -104,6 +104,7 @@ MAI_CleanupAndExit(void)
{
if (!initialised) exit(exit_status);
LCL_CancelOffsetCorrection();
SRC_DumpSources();
/* Don't update clock when removing sources */
@@ -183,7 +184,7 @@ ntp_source_resolving_end(void)
NSR_AutoStartSources();
/* Special modes can end only when sources update their reachability.
Give up immediatelly if there are no active sources. */
Give up immediately if there are no active sources. */
if (ref_mode != REF_ModeNormal && !SRC_ActiveSources()) {
REF_SetUnsynchronised();
}
@@ -374,8 +375,34 @@ go_daemon(void)
static void
print_help(const char *progname)
{
printf("Usage: %s [-4|-6] [-n|-d] [-p|-q|-Q] [-r] [-R] [-s] [-t TIMEOUT] [-f FILE|COMMAND...]\n",
progname);
printf("Usage: %s [OPTION]... [DIRECTIVE]...\n\n"
"Options:\n"
" -4\t\tUse IPv4 addresses only\n"
" -6\t\tUse IPv6 addresses only\n"
" -f FILE\tSpecify configuration file (%s)\n"
" -n\t\tDon't run as daemon\n"
" -d\t\tDon't run as daemon and log to stderr\n"
#if DEBUG > 0
" -d -d\t\tEnable debug messages\n"
#endif
" -l FILE\tLog to file\n"
" -L LEVEL\tSet logging threshold (0)\n"
" -p\t\tPrint configuration and exit\n"
" -q\t\tSet clock and exit\n"
" -Q\t\tLog offset and exit\n"
" -r\t\tReload dump files\n"
" -R\t\tAdapt configuration for restart\n"
" -s\t\tSet clock from RTC\n"
" -t SECONDS\tExit after elapsed time\n"
" -u USER\tSpecify user (%s)\n"
" -U\t\tDon't check for root\n"
" -F LEVEL\tSet system call filter level (0)\n"
" -P PRIORITY\tSet process priority (0)\n"
" -m\t\tLock memory\n"
" -x\t\tDon't control clock\n"
" -v, --version\tPrint version and exit\n"
" -h, --help\tPrint usage and exit\n",
progname, DEFAULT_CONF_FILE, DEFAULT_USER);
}
/* ================================================== */
@@ -411,13 +438,13 @@ int main
int do_init_rtc = 0, restarted = 0, client_only = 0, timeout = -1;
int scfilter_level = 0, lock_memory = 0, sched_priority = 0;
int clock_control = 1, system_log = 1, log_severity = LOGS_INFO;
int config_args = 0, print_config = 0;
int user_check = 1, config_args = 0, print_config = 0;
do_platform_checks();
LOG_Initialise();
/* Parse (undocumented) long command-line options */
/* Parse long command-line options */
for (optind = 1; optind < argc; optind++) {
if (!strcmp("--help", argv[optind])) {
print_help(progname);
@@ -431,7 +458,7 @@ int main
optind = 1;
/* Parse short command-line options */
while ((opt = getopt(argc, argv, "46df:F:hl:L:mnpP:qQrRst:u:vx")) != -1) {
while ((opt = getopt(argc, argv, "46df:F:hl:L:mnpP:qQrRst:u:Uvx")) != -1) {
switch (opt) {
case '4':
case '6':
@@ -462,9 +489,10 @@ int main
break;
case 'p':
print_config = 1;
client_only = 1;
user_check = 0;
nofork = 1;
system_log = 0;
log_severity = LOGS_WARN;
break;
case 'P':
sched_priority = parse_int_arg(optarg);
@@ -479,6 +507,7 @@ int main
ref_mode = REF_ModePrintOnce;
nofork = 1;
client_only = 1;
user_check = 0;
clock_control = 0;
system_log = 0;
break;
@@ -497,6 +526,9 @@ int main
case 'u':
user = optarg;
break;
case 'U':
user_check = 0;
break;
case 'v':
print_version();
return 0;
@@ -509,7 +541,7 @@ int main
}
}
if (getuid() && !client_only)
if (user_check && getuid() != 0)
LOG_FATAL("Not superuser");
/* Turn into a daemon */
@@ -595,7 +627,10 @@ int main
/* Drop root privileges if the specified user has a non-zero UID */
if (!geteuid() && (pw->pw_uid || pw->pw_gid))
SYS_DropRoot(pw->pw_uid, pw->pw_gid);
SYS_DropRoot(pw->pw_uid, pw->pw_gid, SYS_MAIN_PROCESS);
if (!geteuid())
LOG(LOGS_WARN, "Running with root privileges");
REF_Initialise();
SST_Initialise();

View File

@@ -50,12 +50,24 @@ DNS_SetAddressFamily(int family)
DNS_Status
DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
{
#ifdef HAVE_GETADDRINFO
struct addrinfo hints, *res, *ai;
int i, result;
IPAddr ip;
max_addrs = MIN(max_addrs, DNS_MAX_ADDRESSES);
for (i = 0; i < max_addrs; i++)
ip_addrs[i].family = IPADDR_UNSPEC;
/* Avoid calling getaddrinfo() if the name is an IP address */
if (UTI_StringToIP(name, &ip)) {
if (address_family != IPADDR_UNSPEC && ip.family != address_family)
return DNS_Failure;
if (max_addrs >= 1)
ip_addrs[0] = ip;
return DNS_Success;
}
memset(&hints, 0, sizeof (hints));
switch (address_family) {
@@ -107,48 +119,9 @@ DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
}
}
for (; i < max_addrs; i++)
ip_addrs[i].family = IPADDR_UNSPEC;
freeaddrinfo(res);
return !max_addrs || ip_addrs[0].family != IPADDR_UNSPEC ? DNS_Success : DNS_Failure;
#else
struct hostent *host;
int i;
if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET4)
return DNS_Failure;
max_addrs = MIN(max_addrs, DNS_MAX_ADDRESSES);
host = gethostbyname(name);
if (host == NULL) {
if (h_errno == TRY_AGAIN)
return DNS_TryAgain;
} else {
if (host->h_addrtype != AF_INET || !host->h_addr_list[0])
return DNS_Failure;
for (i = 0; host->h_addr_list[i] && i < max_addrs; i++) {
ip_addrs[i].family = IPADDR_INET4;
ip_addrs[i].addr.in4 = ntohl(*(uint32_t *)host->h_addr_list[i]);
}
for (; i < max_addrs; i++)
ip_addrs[i].family = IPADDR_UNSPEC;
return DNS_Success;
}
#ifdef FORCE_DNSRETRY
return DNS_TryAgain;
#else
return DNS_Failure;
#endif
#endif
}
/* ================================================== */
@@ -157,9 +130,11 @@ int
DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len)
{
char *result = NULL;
#ifdef FEAT_IPV6
struct sockaddr_in6 in6;
struct sockaddr_in6 saddr;
#else
struct sockaddr_in saddr;
#endif
IPSockAddr ip_saddr;
socklen_t slen;
char hbuf[NI_MAXHOST];
@@ -167,29 +142,9 @@ DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len)
ip_saddr.ip_addr = *ip_addr;
ip_saddr.port = 0;
slen = SCK_IPSockAddrToSockaddr(&ip_saddr, (struct sockaddr *)&in6, sizeof (in6));
if (!getnameinfo((struct sockaddr *)&in6, slen, hbuf, sizeof (hbuf), NULL, 0, 0))
slen = SCK_IPSockAddrToSockaddr(&ip_saddr, (struct sockaddr *)&saddr, sizeof (saddr));
if (!getnameinfo((struct sockaddr *)&saddr, slen, hbuf, sizeof (hbuf), NULL, 0, 0))
result = hbuf;
#else
struct hostent *host;
uint32_t addr;
switch (ip_addr->family) {
case IPADDR_INET4:
addr = htonl(ip_addr->addr.in4);
host = gethostbyaddr((const char *) &addr, sizeof (ip_addr), AF_INET);
break;
#ifdef FEAT_IPV6
case IPADDR_INET6:
host = gethostbyaddr((const void *) ip_addr->addr.in6, sizeof (ip_addr->addr.in6), AF_INET6);
break;
#endif
default:
host = NULL;
}
if (host)
result = host->h_name;
#endif
if (result == NULL)
result = UTI_IPToString(ip_addr);

6
ntp.h
View File

@@ -116,10 +116,11 @@ typedef struct {
/* Enumeration for authentication modes of NTP packets */
typedef enum {
NTP_AUTH_NONE = 0, /* No authentication */
NTP_AUTH_SYMMETRIC, /* MAC using symmetric key (RFC 1305, RFC 5905) */
NTP_AUTH_SYMMETRIC, /* NTP MAC or CMAC using a symmetric key
(RFC 1305, RFC 5905, RFC 8573) */
NTP_AUTH_MSSNTP, /* MS-SNTP authenticator field */
NTP_AUTH_MSSNTP_EXT, /* MS-SNTP extended authenticator field */
NTP_AUTH_NTS, /* Network Time Security (RFC ????) */
NTP_AUTH_NTS, /* Network Time Security (RFC 8915) */
} NTP_AuthMode;
/* Structure describing an NTP packet */
@@ -151,7 +152,6 @@ typedef struct {
double peer_dispersion;
double root_delay;
double root_dispersion;
int stratum;
} NTP_Sample;
#endif /* GOT_NTP_H */

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2019
* Copyright (C) Miroslav Lichvar 2019-2020
*
* 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
@@ -161,11 +161,12 @@ NAU_CreateSymmetricInstance(uint32_t key_id)
/* ================================================== */
NAU_Instance
NAU_CreateNtsInstance(IPSockAddr *nts_address, const char *name, const IPSockAddr *ntp_address)
NAU_CreateNtsInstance(IPSockAddr *nts_address, const char *name, uint32_t cert_set,
uint16_t ntp_port)
{
NAU_Instance instance = create_instance(NTP_AUTH_NTS);
instance->nts = NNC_CreateInstance(nts_address, name, ntp_address);
instance->nts = NNC_CreateInstance(nts_address, name, cert_set, ntp_port);
return instance;
}
@@ -175,7 +176,7 @@ NAU_CreateNtsInstance(IPSockAddr *nts_address, const char *name, const IPSockAdd
void
NAU_DestroyInstance(NAU_Instance instance)
{
if (instance->nts)
if (instance->mode == NTP_AUTH_NTS)
NNC_DestroyInstance(instance->nts);
Free(instance);
}
@@ -300,21 +301,9 @@ NAU_ParsePacket(NTP_Packet *packet, NTP_PacketInfo *info)
if (remainder >= NTP_MIN_MAC_LENGTH && remainder <= NTP_MAX_V4_MAC_LENGTH)
break;
/* The NTPv4-specific limit for MAC length enables deterministic parsing of
packets with extension fields (RFC 7822), but we support longer MACs in
packets with no extension fields for compatibility with older chrony
clients. Check if the longer MAC would authenticate the packet before
trying to parse the data as an extension field. */
if (parsed == NTP_HEADER_LENGTH &&
remainder > NTP_MAX_V4_MAC_LENGTH && remainder <= NTP_MAX_MAC_LENGTH &&
KEY_CheckAuth(ntohl(*(uint32_t *)(data + parsed)), data, parsed,
data + parsed + 4, remainder - 4, NTP_MAX_MAC_LENGTH - 4))
break;
/* Check if this is a valid NTPv4 extension field and skip it */
if (!NEF_ParseField(packet, info->length, parsed, &ef_length, &ef_type, NULL, NULL)) {
/* Invalid MAC or format error */
DEBUG_LOG("Invalid format or MAC");
DEBUG_LOG("Invalid format");
return 0;
}
@@ -340,9 +329,6 @@ NAU_ParsePacket(NTP_Packet *packet, NTP_PacketInfo *info)
/* No MAC */
return 1;
} else if (remainder >= NTP_MIN_MAC_LENGTH) {
/* This is not 100% reliable as a MAC could fail to authenticate and could
pass as an extension field, leaving reminder smaller than the minimum MAC
length */
info->auth.mode = NTP_AUTH_SYMMETRIC;
info->auth.mac.start = parsed;
info->auth.mac.length = remainder;

View File

@@ -37,7 +37,7 @@ typedef struct NAU_Instance_Record *NAU_Instance;
extern NAU_Instance NAU_CreateNoneInstance(void);
extern NAU_Instance NAU_CreateSymmetricInstance(uint32_t key_id);
extern NAU_Instance NAU_CreateNtsInstance(IPSockAddr *nts_address, const char *name,
const IPSockAddr *ntp_address);
uint32_t cert_set, uint16_t ntp_port);
/* Destroy an instance */
extern void NAU_DestroyInstance(NAU_Instance instance);

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2018
* Copyright (C) Miroslav Lichvar 2009-2020
*
* 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
@@ -107,6 +107,8 @@ struct NCR_Instance_Record {
int min_stratum; /* Increase stratum in received packets to the
minimum */
int copy; /* Boolean suppressing own refid and stratum */
int poll_target; /* Target number of sourcestats samples */
int version; /* Version set in packets for server/peer */
@@ -560,6 +562,7 @@ NCR_CreateInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type,
result->auto_iburst = params->iburst;
result->auto_burst = params->burst;
result->auto_offline = params->auto_offline;
result->copy = params->copy && result->mode == MODE_CLIENT;
result->poll_target = params->poll_target;
if (params->nts) {
@@ -571,7 +574,8 @@ NCR_CreateInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type,
nts_address.ip_addr = remote_addr->ip_addr;
nts_address.port = params->nts_port;
result->auth = NAU_CreateNtsInstance(&nts_address, name, &result->remote_addr);
result->auth = NAU_CreateNtsInstance(&nts_address, name, params->cert_set,
result->remote_addr.port);
} else if (params->authkey != INACTIVE_AUTHKEY) {
result->auth = NAU_CreateSymmetricInstance(params->authkey);
} else {
@@ -703,7 +707,6 @@ NCR_ChangeRemoteAddress(NCR_Instance inst, NTP_Remote_Address *remote_addr, int
memset(&inst->report, 0, sizeof (inst->report));
NCR_ResetInstance(inst);
/* Update the authentication-specific address before NTP address */
if (!ntp_only)
NAU_ChangeAddress(inst->auth, &remote_addr->ip_addr);
@@ -1381,9 +1384,8 @@ check_sync_loop(NCR_Instance inst, NTP_Packet *message, NTP_Local_Address *local
NTP_Leap leap_status;
uint32_t our_ref_id;
/* Check if a server socket is open, i.e. a client or peer can actually
be synchronised to us */
if (!NIO_IsServerSocketOpen())
/* Check if a client or peer can be synchronised to us */
if (!NIO_IsServerSocketOpen() || REF_GetMode() != REF_ModeNormal)
return 1;
/* Check if the source indicates that it is synchronised to our address
@@ -1678,7 +1680,6 @@ process_response(NCR_Instance inst, NTP_Local_Address *local_addr,
sample.root_delay = pkt_root_delay + sample.peer_delay;
sample.root_dispersion = pkt_root_dispersion + sample.peer_dispersion;
sample.stratum = MAX(message->stratum, inst->min_stratum);
/* Update the NTP timestamps. If it's a valid packet from a synchronised
source, the timestamps may be used later when processing a packet in the
@@ -1761,14 +1762,23 @@ process_response(NCR_Instance inst, NTP_Local_Address *local_addr,
if (valid_packet) {
inst->remote_poll = message->poll;
inst->remote_stratum = message->stratum != NTP_INVALID_STRATUM ?
message->stratum : NTP_MAX_STRATUM;
MIN(message->stratum, NTP_MAX_STRATUM) : NTP_MAX_STRATUM;
inst->prev_local_poll = inst->local_poll;
inst->prev_tx_count = inst->tx_count;
inst->tx_count = 0;
SRC_UpdateReachability(inst->source, synced_packet);
SRC_SetLeapStatus(inst->source, pkt_leap);
if (synced_packet) {
if (inst->copy && inst->remote_stratum > 0) {
/* Assume the reference ID and stratum of the server */
inst->remote_stratum--;
SRC_SetRefid(inst->source, ntohl(message->reference_id), &inst->remote_addr.ip_addr);
}
SRC_UpdateStatus(inst->source, MAX(inst->remote_stratum, inst->min_stratum), pkt_leap);
}
if (good_packet) {
/* Adjust the polling interval, accumulate the sample, etc. */
@@ -2095,15 +2105,6 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
CLG_LogAuthNtpRequest();
}
/* If it is an NTPv4 packet with a long MAC and no extension fields,
respond with an NTPv3 packet to avoid breaking RFC 7822 and keep
the length symmetric. Otherwise, respond with the same version. */
if (info.version == 4 && info.ext_fields == 0 && info.auth.mode == NTP_AUTH_SYMMETRIC &&
info.auth.mac.length > NTP_MAX_V4_MAC_LENGTH)
version = 3;
else
version = info.version;
local_ntp_rx = local_ntp_tx = NULL;
tx_ts = NULL;
interleaved = 0;
@@ -2133,6 +2134,9 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
poll = CLG_GetNtpMinPoll();
poll = MAX(poll, message->poll);
/* Respond with the same version */
version = info.version;
/* Send a reply */
transmit_packet(my_mode, interleaved, poll, version, kod, NULL,
&message->receive_ts, &message->transmit_ts,

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2019
* Copyright (C) Miroslav Lichvar 2019-2020
*
* 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

View File

@@ -4,7 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Timo Teras 2009
* Copyright (C) Miroslav Lichvar 2009, 2013-2016, 2018
* Copyright (C) Miroslav Lichvar 2009, 2013-2016, 2018-2020
*
* 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

View File

@@ -200,7 +200,8 @@ add_interface(CNF_HwTsInterface *conf_iface)
req.ifr_data = (char *)&ts_config;
if (ioctl(sock_fd, SIOCSHWTSTAMP, &req)) {
DEBUG_LOG("ioctl(%s) failed : %s", "SIOCSHWTSTAMP", strerror(errno));
LOG(errno == EPERM ? LOGS_ERR : LOGS_DEBUG,
"ioctl(%s) failed : %s", "SIOCSHWTSTAMP", strerror(errno));
/* Check the current timestamping configuration in case this interface
allows only reading of the configuration and it was already configured

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011-2012, 2014, 2016
* Copyright (C) Miroslav Lichvar 2011-2012, 2014, 2016, 2020
*
* 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
@@ -45,6 +45,9 @@
/* ================================================== */
/* Maximum number of sources */
#define MAX_SOURCES 65536
/* Record type private to this file, used to store information about
particular sources */
typedef struct {
@@ -53,7 +56,8 @@ typedef struct {
(an IPADDR_ID address means the address
is not resolved yet) */
NCR_Instance data; /* Data for the protocol engine for this source */
char *name; /* Name of the source, may be NULL */
char *name; /* Name of the source as it was specified
(may be an IP address) */
int pool_id; /* ID of the pool from which was this source
added or INVALID_POOL */
int tentative; /* Flag indicating there was no valid response
@@ -72,6 +76,9 @@ static int n_sources;
/* Flag indicating new sources will be started automatically when added */
static int auto_start_sources = 0;
/* Flag indicating a record is currently being modified */
static int record_lock;
/* Last assigned address ID */
static uint32_t last_address_id = 0;
@@ -100,6 +107,7 @@ struct UnresolvedSource {
static struct UnresolvedSource *unresolved_sources = NULL;
static int resolving_interval = 0;
static int resolving_restart = 0;
static SCH_TimeoutID resolving_id;
static struct UnresolvedSource *resolving_source = NULL;
static NSR_SourceResolvingEndHandler resolving_end_handler = NULL;
@@ -122,11 +130,21 @@ struct SourcePool {
/* Array of SourcePool (indexed by their ID) */
static ARR_Instance pools;
/* Requested update of a source's address */
struct AddressUpdate {
NTP_Remote_Address old_address;
NTP_Remote_Address new_address;
};
/* Update saved when record_lock is true */
static struct AddressUpdate saved_address_update;
/* ================================================== */
/* Forward prototypes */
static void resolve_sources(void);
static void rehash_records(void);
static void handle_saved_address_update(void);
static void clean_source_record(SourceRecord *record);
static void remove_pool_sources(int pool_id, int tentative, int unresolved);
static void remove_unresolved_source(struct UnresolvedSource *us);
@@ -181,14 +199,7 @@ NSR_Initialise(void)
void
NSR_Finalise(void)
{
SourceRecord *record;
unsigned int i;
for (i = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (record->remote_addr)
clean_source_record(record);
}
NSR_RemoveAllSources();
LCL_RemoveParameterChangeHandler(slew_sources, NULL);
@@ -275,6 +286,8 @@ rehash_records(void)
unsigned int i, old_size, new_size;
int slot;
assert(!record_lock);
old_size = ARR_GetSize(records);
temp_records = MallocArray(SourceRecord, old_size);
@@ -317,6 +330,11 @@ add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type,
/* Find empty bin & check that we don't have the address already */
if (find_slot2(remote_addr, &slot) != 0) {
return NSR_AlreadyInUse;
} else if (!name && !UTI_IsIPReal(&remote_addr->ip_addr)) {
/* Name is required for non-real addresses */
return NSR_InvalidName;
} else if (n_sources >= MAX_SOURCES) {
return NSR_TooManySources;
} else {
if (remote_addr->ip_addr.family != IPADDR_INET4 &&
remote_addr->ip_addr.family != IPADDR_INET6 &&
@@ -331,14 +349,20 @@ add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type,
assert(0);
}
assert(!record_lock);
record_lock = 1;
record = get_record(slot);
record->data = NCR_CreateInstance(remote_addr, type, params, name);
assert(!name || !UTI_IsStringIP(name));
record->name = Strdup(name ? name : UTI_IPToString(&remote_addr->ip_addr));
record->data = NCR_CreateInstance(remote_addr, type, params, record->name);
record->remote_addr = NCR_GetRemoteAddress(record->data);
record->name = name ? Strdup(name) : NULL;
record->pool_id = pool_id;
record->tentative = 1;
record->conf_id = conf_id;
record_lock = 0;
if (record->pool_id != INVALID_POOL) {
get_pool(record->pool_id)->sources++;
if (!UTI_IsIPReal(&remote_addr->ip_addr))
@@ -348,6 +372,9 @@ add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type,
if (auto_start_sources && UTI_IsIPReal(&remote_addr->ip_addr))
NCR_StartInstance(record->data);
/* The new instance is allowed to change its address immediately */
handle_saved_address_update();
return NSR_Success;
}
}
@@ -365,7 +392,7 @@ change_source_address(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr
char *name;
found = find_slot2(old_addr, &slot1);
if (found == 0)
if (found != 2)
return NSR_NoSuchSource;
/* Make sure there is no other source using the new address (with the same
@@ -374,9 +401,16 @@ change_source_address(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr
if (found == 2 || (found != 0 && slot1 != slot2))
return NSR_AlreadyInUse;
assert(!record_lock);
record_lock = 1;
record = get_record(slot1);
NCR_ChangeRemoteAddress(record->data, new_addr, !replacement);
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)
assert(0);
if (!UTI_IsIPReal(&old_addr->ip_addr) && UTI_IsIPReal(&new_addr->ip_addr)) {
if (auto_start_sources)
NCR_StartInstance(record->data);
@@ -391,6 +425,8 @@ change_source_address(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr
get_pool(record->pool_id)->confirmed_sources--;
}
record_lock = 0;
name = record->name;
severity = UTI_IsIPReal(&old_addr->ip_addr) ? LOGS_INFO : LOGS_DEBUG;
@@ -400,10 +436,10 @@ change_source_address(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr
LOG(severity, "Source %s %s %s (%s)", UTI_IPToString(&old_addr->ip_addr),
replacement ? "replaced with" : "changed to",
UTI_IPToString(&new_addr->ip_addr), name ? name : "");
UTI_IPToString(&new_addr->ip_addr), name);
} else {
LOG(severity, "Source %s (%s) changed port to %d",
UTI_IPToString(&new_addr->ip_addr), name ? name : "", new_addr->port);
UTI_IPToString(&new_addr->ip_addr), name, new_addr->port);
}
return NSR_Success;
@@ -411,6 +447,24 @@ change_source_address(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr
/* ================================================== */
static void
handle_saved_address_update(void)
{
if (!UTI_IsIPReal(&saved_address_update.old_address.ip_addr))
return;
if (change_source_address(&saved_address_update.old_address,
&saved_address_update.new_address, 0) != NSR_Success)
/* This is expected to happen only if the old address is wrong */
LOG(LOGS_ERR, "Could not change %s to %s",
UTI_IPSockAddrToString(&saved_address_update.old_address),
UTI_IPSockAddrToString(&saved_address_update.new_address));
saved_address_update.old_address.ip_addr.family = IPADDR_UNSPEC;
}
/* ================================================== */
static int
replace_source_connectable(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr)
{
@@ -422,6 +476,8 @@ replace_source_connectable(NTP_Remote_Address *old_addr, NTP_Remote_Address *new
if (change_source_address(old_addr, new_addr, 1) == NSR_AlreadyInUse)
return 0;
handle_saved_address_update();
return 1;
}
@@ -444,8 +500,8 @@ process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs
DEBUG_LOG("(%d) %s", i + 1, UTI_IPToString(&new_addr.ip_addr));
if (us->pool_id != INVALID_POOL) {
/* In the pool resolving mode, try to replace all sources from
the pool which don't have a real address yet */
/* In the pool resolving mode, try to replace a source from
the pool which does not have a real address yet */
for (j = 0; j < ARR_GetSize(records); j++) {
record = get_record(j);
if (!record->remote_addr || record->pool_id != us->pool_id ||
@@ -454,6 +510,7 @@ process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs
old_addr = *record->remote_addr;
new_addr.port = old_addr.port;
if (replace_source_connectable(&old_addr, &new_addr))
;
break;
}
} else {
@@ -523,6 +580,13 @@ name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *any
if (status == DNS_Failure || UTI_IsIPReal(&us->address.ip_addr) || is_resolved(us))
remove_unresolved_source(us);
/* If a restart was requested and this was the last source in the list,
start with the first source again (if there still is one) */
if (!next && resolving_restart) {
next = unresolved_sources;
resolving_restart = 0;
}
resolving_source = next;
if (next) {
@@ -662,8 +726,7 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type,
NTP_Remote_Address remote_addr;
int i, new_sources, pool_id;
/* If the name is an IP address, don't bother with full resolving now
or later when trying to replace the source */
/* If the name is an IP address, add the source with the address directly */
if (UTI_StringToIP(name, &remote_addr.ip_addr)) {
remote_addr.port = port;
return NSR_AddSource(&remote_addr, type, params, conf_id);
@@ -671,7 +734,7 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type,
/* Make sure the name is at least printable and has no spaces */
for (i = 0; name[i] != '\0'; i++) {
if (!isgraph(name[i]))
if (!isgraph((unsigned char)name[i]))
return NSR_InvalidName;
}
@@ -736,7 +799,7 @@ NSR_ResolveSources(void)
{
/* Try to resolve unresolved sources now */
if (unresolved_sources) {
/* Make sure no resolving is currently running */
/* Allow only one resolving to be running at a time */
if (!resolving_source) {
if (resolving_id != 0) {
SCH_RemoveTimeout(resolving_id);
@@ -744,6 +807,9 @@ NSR_ResolveSources(void)
resolving_interval--;
}
resolve_sources();
} else {
/* Try again as soon as the current resolving ends */
resolving_restart = 1;
}
} else {
/* No unresolved sources, we are done */
@@ -795,7 +861,6 @@ clean_source_record(SourceRecord *record)
record->remote_addr = NULL;
NCR_DestroyInstance(record->data);
if (record->name)
Free(record->name);
n_sources--;
@@ -869,7 +934,8 @@ resolve_source_replacement(SourceRecord *record)
{
struct UnresolvedSource *us;
DEBUG_LOG("trying to replace %s", UTI_IPToString(&record->remote_addr->ip_addr));
DEBUG_LOG("trying to replace %s (%s)",
UTI_IPToString(&record->remote_addr->ip_addr), record->name);
us = MallocNew(struct UnresolvedSource);
us->name = Strdup(record->name);
@@ -893,6 +959,7 @@ NSR_HandleBadSource(IPAddr *address)
static struct timespec last_replacement;
struct timespec now;
SourceRecord *record;
IPAddr ip_addr;
double diff;
int slot;
@@ -901,8 +968,10 @@ NSR_HandleBadSource(IPAddr *address)
record = get_record(slot);
/* Only sources with a name can be replaced */
if (!record->name)
/* Don't try to replace a source specified by an IP address unless the
address changed since the source was added (e.g. by NTS-KE) */
if (UTI_StringToIP(record->name, &ip_addr) &&
UTI_CompareIPs(&record->remote_addr->ip_addr, &ip_addr, NULL) == 0)
return;
/* Don't resolve names too frequently */
@@ -927,7 +996,7 @@ NSR_RefreshAddresses(void)
for (i = 0; i < ARR_GetSize(records); i++) {
record = get_record(i);
if (!record->remote_addr || !record->name)
if (!record->remote_addr)
continue;
resolve_source_replacement(record);
@@ -939,10 +1008,28 @@ NSR_RefreshAddresses(void)
NSR_Status
NSR_UpdateSourceNtpAddress(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr)
{
if (new_addr->ip_addr.family == IPADDR_UNSPEC)
int slot;
if (!UTI_IsIPReal(&old_addr->ip_addr) || !UTI_IsIPReal(&new_addr->ip_addr))
return NSR_InvalidAF;
if (UTI_CompareIPs(&old_addr->ip_addr, &new_addr->ip_addr, NULL) != 0 &&
find_slot(&new_addr->ip_addr, &slot))
return NSR_AlreadyInUse;
/* If a record is being modified (e.g. by change_source_address(), or the
source is just being created), postpone the change to avoid corruption */
if (!record_lock)
return change_source_address(old_addr, new_addr, 0);
if (UTI_IsIPReal(&saved_address_update.old_address.ip_addr))
return NSR_TooManySources;
saved_address_update.old_address = *old_addr;
saved_address_update.new_address = *new_addr;
return NSR_Success;
}
/* ================================================== */
@@ -991,17 +1078,12 @@ NSR_GetLocalRefid(IPAddr *address)
char *
NSR_GetName(IPAddr *address)
{
SourceRecord *record;
int slot;
if (!find_slot(address, &slot))
return 0;
return NULL;
record = get_record(slot);
if (record->name)
return record->name;
return UTI_IPToString(&record->remote_addr->ip_addr);
return get_record(slot)->name;
}
/* ================================================== */

View File

@@ -91,15 +91,16 @@ extern void NSR_HandleBadSource(IPAddr *address);
/* Procedure to resolve all names again */
extern void NSR_RefreshAddresses(void);
/* Procedure to update the address of a source */
/* Procedure to update the address of a source. The update may be
postponed. */
extern NSR_Status NSR_UpdateSourceNtpAddress(NTP_Remote_Address *old_addr,
NTP_Remote_Address *new_addr);
/* Procedure to get local reference ID corresponding to a source */
extern uint32_t NSR_GetLocalRefid(IPAddr *address);
/* Procedure to get the name of a source. If the source doesn't have a name,
it returns a temporary string containing formatted address. */
/* Procedure to get the name of a source as it was specified (it may be
an IP address) */
extern char *NSR_GetName(IPAddr *address);
/* This routine is called by ntp_io when a new packet arrives off the network */

View File

@@ -44,6 +44,7 @@
struct NKC_Instance_Record {
char *name;
IPSockAddr address;
NKSN_Credentials credentials;
NKSN_Instance session;
int destroying;
int got_response;
@@ -52,14 +53,14 @@ struct NKC_Instance_Record {
NKE_Context context;
NKE_Cookie cookies[NKE_MAX_COOKIES];
int num_cookies;
char server_name[NKE_MAX_RECORD_BODY_LENGTH + 1];
char server_name[NKE_MAX_RECORD_BODY_LENGTH + 2];
IPSockAddr ntp_address;
};
/* ================================================== */
static void *client_credentials = NULL;
static int client_credentials_refs = 0;
static NKSN_Credentials default_credentials = NULL;
static int default_credentials_refs = 0;
/* ================================================== */
@@ -196,7 +197,7 @@ process_response(NKC_Instance inst)
inst->server_name[length] = '\0';
/* Make sure the name is printable and has no spaces */
for (i = 0; i < length && isgraph(inst->server_name[i]); i++)
for (i = 0; i < length && isgraph((unsigned char)inst->server_name[i]); i++)
;
if (i != length) {
DEBUG_LOG("Invalid server name");
@@ -253,6 +254,17 @@ handle_message(void *arg)
if (inst->resolving_name)
return 0;
if (!UTI_StringToIP(inst->server_name, &inst->ntp_address.ip_addr)) {
int length = strlen(inst->server_name);
/* Add a trailing dot if not present to force the name to be
resolved as a fully qualified domain name */
if (length < 1 || length + 1 >= sizeof (inst->server_name))
return 0;
if (inst->server_name[length - 1] != '.') {
inst->server_name[length] = '.';
inst->server_name[length + 1] = '\0';
}
DNS_Name2IPAddressAsync(inst->server_name, name_resolve_handler, inst);
inst->resolving_name = 1;
}
@@ -266,9 +278,12 @@ handle_message(void *arg)
/* ================================================== */
NKC_Instance
NKC_CreateInstance(IPSockAddr *address, const char *name)
NKC_CreateInstance(IPSockAddr *address, const char *name, uint32_t cert_set)
{
const char **trusted_certs;
uint32_t *certs_ids;
NKC_Instance inst;
int n_certs;
inst = MallocNew(struct NKC_Instance_Record);
@@ -279,10 +294,21 @@ NKC_CreateInstance(IPSockAddr *address, const char *name)
inst->destroying = 0;
inst->got_response = 0;
/* Share the credentials with other client instances */
if (!client_credentials)
client_credentials = NKSN_CreateCertCredentials(NULL, NULL, CNF_GetNtsTrustedCertFile());
client_credentials_refs++;
n_certs = CNF_GetNtsTrustedCertsPaths(&trusted_certs, &certs_ids);
/* Share the credentials among clients using the default set of trusted
certificates, which likely contains most certificates */
if (cert_set == 0) {
if (!default_credentials)
default_credentials = NKSN_CreateClientCertCredentials(trusted_certs, certs_ids,
n_certs, cert_set);
inst->credentials = default_credentials;
if (default_credentials)
default_credentials_refs++;
} else {
inst->credentials = NKSN_CreateClientCertCredentials(trusted_certs, certs_ids,
n_certs, cert_set);
}
return inst;
}
@@ -296,10 +322,16 @@ NKC_DestroyInstance(NKC_Instance inst)
Free(inst->name);
client_credentials_refs--;
if (client_credentials_refs <= 0 && client_credentials) {
NKSN_DestroyCertCredentials(client_credentials);
client_credentials = NULL;
if (inst->credentials) {
if (inst->credentials == default_credentials) {
default_credentials_refs--;
if (default_credentials_refs <= 0) {
NKSN_DestroyCertCredentials(default_credentials);
default_credentials = NULL;
}
} else {
NKSN_DestroyCertCredentials(inst->credentials);
}
}
/* If the asynchronous resolver is running, let the handler free
@@ -325,7 +357,7 @@ NKC_Start(NKC_Instance inst)
inst->got_response = 0;
if (!client_credentials) {
if (!inst->credentials) {
DEBUG_LOG("Missing client credentials");
return 0;
}
@@ -335,17 +367,19 @@ NKC_Start(NKC_Instance inst)
local_addr.port = 0;
iface = CNF_GetBindAcquisitionInterface();
sock_fd = SCK_OpenTcpSocket(&inst->address, &local_addr, iface, 0);
if (sock_fd < 0)
return 0;
/* Make a label containing both the address and name of the server */
if (snprintf(label, sizeof (label), "%s (%s)",
UTI_IPSockAddrToString(&inst->address), inst->name) >= sizeof (label))
;
sock_fd = SCK_OpenTcpSocket(&inst->address, &local_addr, iface, 0);
if (sock_fd < 0) {
LOG(LOGS_ERR, "Could not connect to %s", label);
return 0;
}
/* Start an NTS-KE session */
if (!NKSN_StartSession(inst->session, sock_fd, label, client_credentials, CLIENT_TIMEOUT)) {
if (!NKSN_StartSession(inst->session, sock_fd, label, inst->credentials, CLIENT_TIMEOUT)) {
SCK_CloseSocket(sock_fd);
return 0;
}

View File

@@ -33,7 +33,7 @@
typedef struct NKC_Instance_Record *NKC_Instance;
/* Create a client NTS-KE instance */
extern NKC_Instance NKC_CreateInstance(IPSockAddr *address, const char *name);
extern NKC_Instance NKC_CreateInstance(IPSockAddr *address, const char *name, uint32_t cert_set);
/* Destroy an instance */
extern void NKC_DestroyInstance(NKC_Instance inst);

View File

@@ -95,7 +95,7 @@ static int initialised = 0;
/* Array of NKSN instances */
static ARR_Instance sessions;
static void *server_credentials;
static NKSN_Credentials server_credentials;
/* ================================================== */
@@ -556,7 +556,7 @@ error:
#define MAX_WORDS 2
static void
static int
load_keys(void)
{
char *dump_dir, line[1024], *words[MAX_WORDS];
@@ -568,11 +568,11 @@ load_keys(void)
dump_dir = CNF_GetNtsDumpDir();
if (!dump_dir)
return;
return 0;
f = UTI_OpenFile(dump_dir, DUMP_FILENAME, NULL, 'r', 0);
if (!f)
return;
return 0;
if (!fgets(line, sizeof (line), f) || strcmp(line, DUMP_IDENTIFIER) != 0 ||
!fgets(line, sizeof (line), f) || UTI_SplitString(line, words, MAX_WORDS) != 2 ||
@@ -607,11 +607,13 @@ load_keys(void)
fclose(f);
return;
return 1;
error:
DEBUG_LOG("Could not %s server keys", "load");
fclose(f);
return 0;
}
/* ================================================== */
@@ -646,7 +648,7 @@ run_helper(uid_t uid, gid_t gid, int scfilter_level)
LOG_SetMinSeverity(log_severity);
if (!geteuid() && (uid || gid))
SYS_DropRoot(uid, gid);
SYS_DropRoot(uid, gid, SYS_NTSKE_HELPER);
NKS_Initialise();
@@ -676,13 +678,14 @@ void
NKS_PreInitialise(uid_t uid, gid_t gid, int scfilter_level)
{
int i, processes, sock_fd1, sock_fd2;
const char **certs, **keys;
char prefix[16];
pid_t pid;
helper_sock_fd = INVALID_SOCK_FD;
is_helper = 0;
if (!CNF_GetNtsServerCertFile() || !CNF_GetNtsServerKeyFile())
if (CNF_GetNtsServerCertAndKeyFiles(&certs, &keys) <= 0)
return;
processes = CNF_GetNtsServerProcesses();
@@ -726,21 +729,19 @@ NKS_PreInitialise(uid_t uid, gid_t gid, int scfilter_level)
void
NKS_Initialise(void)
{
char *cert, *key;
const char **certs, **keys;
int i, n_certs_keys;
double key_delay;
int i;
server_sock_fd4 = INVALID_SOCK_FD;
server_sock_fd6 = INVALID_SOCK_FD;
cert = CNF_GetNtsServerCertFile();
key = CNF_GetNtsServerKeyFile();
if (!cert || !key)
n_certs_keys = CNF_GetNtsServerCertAndKeyFiles(&certs, &keys);
if (n_certs_keys <= 0)
return;
if (helper_sock_fd == INVALID_SOCK_FD) {
server_credentials = NKSN_CreateCertCredentials(cert, key, NULL);
server_credentials = NKSN_CreateServerCertCredentials(certs, keys, n_certs_keys);
if (!server_credentials)
return;
} else {
@@ -764,10 +765,12 @@ NKS_Initialise(void)
server_sock_fd4 = open_socket(IPADDR_INET4);
server_sock_fd6 = open_socket(IPADDR_INET6);
load_keys();
key_rotation_interval = MAX(CNF_GetNtsRotate(), 0);
/* Reload saved keys, or save the new keys */
if (!load_keys())
save_keys();
if (key_rotation_interval > 0) {
key_delay = key_rotation_interval - (SCH_GetLastEventMonoTime() - last_server_key_ts);
SCH_AddTimeoutByDelay(MAX(key_delay, 0.0), key_timeout, NULL);

View File

@@ -225,9 +225,13 @@ create_tls_session(int server_mode, int sock_fd, const char *server_name,
}
if (!server_mode) {
assert(server_name);
if (!UTI_IsStringIP(server_name)) {
r = gnutls_server_name_set(session, GNUTLS_NAME_DNS, server_name, strlen(server_name));
if (r < 0)
goto error;
}
flags = 0;
@@ -637,11 +641,13 @@ deinit_gnutls(void)
/* ================================================== */
void *
NKSN_CreateCertCredentials(char *cert, char *key, char *trusted_certs)
static NKSN_Credentials
create_credentials(const char **certs, const char **keys, int n_certs_keys,
const char **trusted_certs, uint32_t *trusted_certs_ids,
int n_trusted_certs, uint32_t trusted_cert_set)
{
gnutls_certificate_credentials_t credentials = NULL;
int r;
int i, r;
init_gnutls();
@@ -649,29 +655,50 @@ NKSN_CreateCertCredentials(char *cert, char *key, char *trusted_certs)
if (r < 0)
goto error;
if (cert && key) {
r = gnutls_certificate_set_x509_key_file(credentials, cert, key,
if (certs && keys) {
if (trusted_certs || trusted_certs_ids)
assert(0);
for (i = 0; i < n_certs_keys; i++) {
r = gnutls_certificate_set_x509_key_file(credentials, certs[i], keys[i],
GNUTLS_X509_FMT_PEM);
if (r < 0)
goto error;
}
} else {
if (!CNF_GetNoSystemCert()) {
if (certs || keys || n_certs_keys > 0)
assert(0);
if (trusted_cert_set == 0 && !CNF_GetNoSystemCert()) {
r = gnutls_certificate_set_x509_system_trust(credentials);
if (r < 0)
goto error;
}
if (trusted_certs) {
r = gnutls_certificate_set_x509_trust_file(credentials, trusted_certs,
if (trusted_certs && trusted_certs_ids) {
for (i = 0; i < n_trusted_certs; i++) {
struct stat buf;
if (trusted_certs_ids[i] != trusted_cert_set)
continue;
if (stat(trusted_certs[i], &buf) == 0 && S_ISDIR(buf.st_mode))
r = gnutls_certificate_set_x509_trust_dir(credentials, trusted_certs[i],
GNUTLS_X509_FMT_PEM);
else
r = gnutls_certificate_set_x509_trust_file(credentials, trusted_certs[i],
GNUTLS_X509_FMT_PEM);
if (r < 0)
goto error;
DEBUG_LOG("Added %d trusted certs from %s", r, trusted_certs[i]);
}
}
}
credentials_counter++;
return credentials;
return (NKSN_Credentials)credentials;
error:
LOG(LOGS_ERR, "Could not set credentials : %s", gnutls_strerror(r));
@@ -683,10 +710,27 @@ error:
/* ================================================== */
void
NKSN_DestroyCertCredentials(void *credentials)
NKSN_Credentials
NKSN_CreateServerCertCredentials(const char **certs, const char **keys, int n_certs_keys)
{
gnutls_certificate_free_credentials(credentials);
return create_credentials(certs, keys, n_certs_keys, NULL, NULL, 0, 0);
}
/* ================================================== */
NKSN_Credentials
NKSN_CreateClientCertCredentials(const char **certs, uint32_t *ids,
int n_certs_ids, uint32_t trusted_cert_set)
{
return create_credentials(NULL, NULL, 0, certs, ids, n_certs_ids, trusted_cert_set);
}
/* ================================================== */
void
NKSN_DestroyCertCredentials(NKSN_Credentials credentials)
{
gnutls_certificate_free_credentials((gnutls_certificate_credentials_t)credentials);
credentials_counter--;
deinit_gnutls();
}
@@ -734,12 +778,13 @@ NKSN_DestroyInstance(NKSN_Instance inst)
int
NKSN_StartSession(NKSN_Instance inst, int sock_fd, const char *label,
void *credentials, double timeout)
NKSN_Credentials credentials, double timeout)
{
assert(inst->state == KE_STOPPED);
inst->tls_session = create_tls_session(inst->server, sock_fd, inst->server_name,
credentials, priority_cache);
(gnutls_certificate_credentials_t)credentials,
priority_cache);
if (!inst->tls_session)
return 0;
@@ -825,21 +870,27 @@ NKSN_GetRecord(NKSN_Instance inst, int *critical, int *type, int *body_length,
int
NKSN_GetKeys(NKSN_Instance inst, SIV_Algorithm siv, NKE_Key *c2s, NKE_Key *s2c)
{
c2s->length = SIV_GetKeyLength(siv);
s2c->length = SIV_GetKeyLength(siv);
assert(c2s->length <= sizeof (c2s->key));
assert(s2c->length <= sizeof (s2c->key));
int length = SIV_GetKeyLength(siv);
if (length <= 0 || length > sizeof (c2s->key) || length > sizeof (s2c->key)) {
DEBUG_LOG("Invalid algorithm");
return 0;
}
if (gnutls_prf_rfc5705(inst->tls_session,
sizeof (NKE_EXPORTER_LABEL) - 1, NKE_EXPORTER_LABEL,
sizeof (NKE_EXPORTER_CONTEXT_C2S) - 1, NKE_EXPORTER_CONTEXT_C2S,
c2s->length, (char *)c2s->key) < 0)
return 0;
if (gnutls_prf_rfc5705(inst->tls_session,
length, (char *)c2s->key) < 0 ||
gnutls_prf_rfc5705(inst->tls_session,
sizeof (NKE_EXPORTER_LABEL) - 1, NKE_EXPORTER_LABEL,
sizeof (NKE_EXPORTER_CONTEXT_S2C) - 1, NKE_EXPORTER_CONTEXT_S2C,
s2c->length, (char *)s2c->key) < 0)
length, (char *)s2c->key) < 0) {
DEBUG_LOG("Could not export key");
return 0;
}
c2s->length = length;
s2c->length = length;
return 1;
}

View File

@@ -30,19 +30,25 @@
#include "nts_ke.h"
#include "siv.h"
typedef struct NKSN_Credentials_Record *NKSN_Credentials;
typedef struct NKSN_Instance_Record *NKSN_Instance;
/* Handler for received NTS-KE messages. A zero return code stops
the session. */
typedef int (*NKSN_MessageHandler)(void *arg);
/* Get client or server credentials using certificates of trusted CAs,
or a server certificate and key. The credentials may be shared between
/* Get server or client credentials using a server certificate and key,
or certificates of trusted CAs. The credentials may be shared between
different clients or servers. */
extern void *NKSN_CreateCertCredentials(char *cert, char *key, char *trusted_certs);
extern NKSN_Credentials NKSN_CreateServerCertCredentials(const char **certs, const char **keys,
int n_certs_keys);
extern NKSN_Credentials NKSN_CreateClientCertCredentials(const char **certs, uint32_t *ids,
int n_certs_ids,
uint32_t trusted_cert_set);
/* Destroy the credentials */
extern void NKSN_DestroyCertCredentials(void *credentials);
extern void NKSN_DestroyCertCredentials(NKSN_Credentials credentials);
/* Create an instance */
extern NKSN_Instance NKSN_CreateInstance(int server_mode, const char *server_name,
@@ -53,7 +59,7 @@ extern void NKSN_DestroyInstance(NKSN_Instance inst);
/* Start a new NTS-KE session */
extern int NKSN_StartSession(NKSN_Instance inst, int sock_fd, const char *label,
void *credentials, double timeout);
NKSN_Credentials credentials, double timeout);
/* Begin an NTS-KE message. A request should be made right after starting
the session and response should be made in the message handler. */

View File

@@ -112,6 +112,7 @@ NNA_GenerateAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv,
if (!SIV_Encrypt(siv, nonce, nonce_length, packet, assoc_length,
plaintext, plaintext_length, ciphertext, ciphertext_length)) {
DEBUG_LOG("SIV encrypt failed");
info->length = assoc_length;
return 0;
}

View File

@@ -50,13 +50,20 @@
#define DUMP_IDENTIFIER "NNC0\n"
struct NNC_Instance_Record {
const IPSockAddr *ntp_address;
/* Address of NTS-KE server */
IPSockAddr nts_address;
/* Hostname or IP address for certificate verification */
char *name;
/* ID of trusted certificates */
uint32_t cert_set;
/* Configured NTP port */
uint16_t default_ntp_port;
/* Address of NTP server (can be negotiated in NTS-KE) */
IPSockAddr ntp_address;
NKC_Instance nke;
SIV_Instance siv;
int load_attempt;
int nke_attempts;
double next_nke_attempt;
double last_nke_success;
@@ -66,6 +73,7 @@ struct NNC_Instance_Record {
NKE_Cookie cookies[NTS_MAX_COOKIES];
int num_cookies;
int cookie_index;
int auth_ready;
int nak_response;
int ok_response;
unsigned char nonce[NTS_MIN_UNPADDED_NONCE_LENGTH];
@@ -82,7 +90,13 @@ static void load_cookies(NNC_Instance inst);
static void
reset_instance(NNC_Instance inst)
{
inst->load_attempt = 0;
if (inst->nke)
NKC_DestroyInstance(inst->nke);
inst->nke = NULL;
if (inst->siv)
SIV_DestroyInstance(inst->siv);
inst->siv = NULL;
inst->nke_attempts = 0;
inst->next_nke_attempt = 0.0;
inst->last_nke_success = 0.0;
@@ -92,6 +106,7 @@ reset_instance(NNC_Instance inst)
memset(inst->cookies, 0, sizeof (inst->cookies));
inst->num_cookies = 0;
inst->cookie_index = 0;
inst->auth_ready = 0;
inst->nak_response = 0;
inst->ok_response = 1;
memset(inst->nonce, 0, sizeof (inst->nonce));
@@ -101,20 +116,26 @@ reset_instance(NNC_Instance inst)
/* ================================================== */
NNC_Instance
NNC_CreateInstance(IPSockAddr *nts_address, const char *name, const IPSockAddr *ntp_address)
NNC_CreateInstance(IPSockAddr *nts_address, const char *name, uint32_t cert_set, uint16_t ntp_port)
{
NNC_Instance inst;
inst = MallocNew(struct NNC_Instance_Record);
inst->ntp_address = ntp_address;
inst->nts_address = *nts_address;
inst->name = name ? Strdup(name) : NULL;
inst->name = Strdup(name);
inst->cert_set = cert_set;
inst->default_ntp_port = ntp_port;
inst->ntp_address.ip_addr = nts_address->ip_addr;
inst->ntp_address.port = ntp_port;
inst->siv = NULL;
inst->nke = NULL;
reset_instance(inst);
/* Try to reload saved keys and cookies */
load_cookies(inst);
return inst;
}
@@ -125,10 +146,7 @@ NNC_DestroyInstance(NNC_Instance inst)
{
save_cookies(inst);
if (inst->nke)
NKC_DestroyInstance(inst->nke);
if (inst->siv)
SIV_DestroyInstance(inst->siv);
reset_instance(inst);
Free(inst->name);
Free(inst);
@@ -158,13 +176,13 @@ set_ntp_address(NNC_Instance inst, NTP_Remote_Address *negotiated_address)
{
NTP_Remote_Address old_address, new_address;
old_address = *inst->ntp_address;
old_address = inst->ntp_address;
new_address = *negotiated_address;
if (new_address.ip_addr.family == IPADDR_UNSPEC)
new_address.ip_addr = old_address.ip_addr;
new_address.ip_addr = inst->nts_address.ip_addr;
if (new_address.port == 0)
new_address.port = old_address.port;
new_address.port = inst->default_ntp_port;
if (UTI_CompareIPs(&old_address.ip_addr, &new_address.ip_addr, NULL) == 0 &&
old_address.port == new_address.port)
@@ -177,6 +195,8 @@ set_ntp_address(NNC_Instance inst, NTP_Remote_Address *negotiated_address)
return 0;
}
inst->ntp_address = new_address;
return 1;
}
@@ -216,13 +236,7 @@ get_cookies(NNC_Instance inst)
return 0;
}
if (!inst->name) {
LOG(LOGS_ERR, "Missing name of %s for NTS-KE",
UTI_IPToString(&inst->nts_address.ip_addr));
return 0;
}
inst->nke = NKC_CreateInstance(&inst->nts_address, inst->name);
inst->nke = NKC_CreateInstance(&inst->nts_address, inst->name, inst->cert_set);
inst->nke_attempts++;
update_next_nke_attempt(inst, now);
@@ -266,8 +280,6 @@ get_cookies(NNC_Instance inst)
inst->last_nke_success = now;
inst->cookie_index = 0;
inst->nak_response = 0;
return 1;
}
@@ -276,11 +288,12 @@ get_cookies(NNC_Instance inst)
int
NNC_PrepareForAuth(NNC_Instance inst)
{
/* Try to reload saved keys and cookies (once for the NTS-KE address) */
if (!inst->load_attempt) {
load_cookies(inst);
inst->load_attempt = 1;
}
inst->auth_ready = 0;
/* Prepare data for the next request and invalidate any responses to the
previous request */
UTI_GetRandomBytes(inst->uniq_id, sizeof (inst->uniq_id));
UTI_GetRandomBytes(inst->nonce, sizeof (inst->nonce));
/* Get new cookies if there are not any, or they are no longer usable */
if (!check_cookies(inst)) {
@@ -288,6 +301,8 @@ NNC_PrepareForAuth(NNC_Instance inst)
return 0;
}
inst->nak_response = 0;
if (!inst->siv)
inst->siv = SIV_CreateInstance(inst->context.algorithm);
@@ -297,9 +312,7 @@ NNC_PrepareForAuth(NNC_Instance inst)
return 0;
}
/* Prepare data for NNC_GenerateRequestAuth() */
UTI_GetRandomBytes(inst->uniq_id, sizeof (inst->uniq_id));
UTI_GetRandomBytes(inst->nonce, sizeof (inst->nonce));
inst->auth_ready = 1;
return 1;
}
@@ -314,14 +327,22 @@ NNC_GenerateRequestAuth(NNC_Instance inst, NTP_Packet *packet,
int i, req_cookies;
void *ef_body;
if (inst->num_cookies == 0 || !inst->siv)
if (!inst->auth_ready)
return 0;
inst->auth_ready = 0;
if (inst->num_cookies <= 0 || !inst->siv)
return 0;
if (info->mode != MODE_CLIENT)
return 0;
cookie = &inst->cookies[inst->cookie_index];
req_cookies = MIN(NTS_MAX_COOKIES - inst->num_cookies + 1,
inst->num_cookies--;
inst->cookie_index = (inst->cookie_index + 1) % NTS_MAX_COOKIES;
req_cookies = MIN(NTS_MAX_COOKIES - inst->num_cookies,
MAX_TOTAL_COOKIE_LENGTH / (cookie->length + 4));
if (!NEF_AddField(packet, info, NTP_EF_NTS_UNIQUE_IDENTIFIER,
@@ -343,9 +364,6 @@ NNC_GenerateRequestAuth(NNC_Instance inst, NTP_Packet *packet,
(const unsigned char *)"", 0, NTP_MAX_V4_MAC_LENGTH + 4))
return 0;
inst->num_cookies--;
inst->cookie_index = (inst->cookie_index + 1) % NTS_MAX_COOKIES;
inst->nak_response = 0;
inst->ok_response = 0;
return 1;
@@ -427,7 +445,7 @@ NNC_CheckResponseAuth(NNC_Instance inst, NTP_Packet *packet,
return 0;
/* Accept at most one response per request */
if (inst->ok_response)
if (inst->ok_response || inst->auth_ready)
return 0;
if (!inst->siv ||
@@ -506,16 +524,14 @@ NNC_ChangeAddress(NNC_Instance inst, IPAddr *address)
{
save_cookies(inst);
if (inst->nke)
NKC_DestroyInstance(inst->nke);
inst->nke = NULL;
inst->num_cookies = 0;
inst->nts_address.ip_addr = *address;
inst->ntp_address.ip_addr = *address;
reset_instance(inst);
DEBUG_LOG("NTS reset");
load_cookies(inst);
}
/* ================================================== */
@@ -546,9 +562,10 @@ save_cookies(NNC_Instance inst)
context_time = inst->last_nke_success - SCH_GetLastEventMonoTime();
context_time += UTI_TimespecToDouble(&now);
if (fprintf(f, "%s%.1f\n%s %d\n%u %d ",
DUMP_IDENTIFIER, context_time, UTI_IPToString(&inst->ntp_address->ip_addr),
inst->ntp_address->port, inst->context_id, (int)inst->context.algorithm) < 0 ||
if (fprintf(f, "%s%s\n%.1f\n%s %d\n%u %d ",
DUMP_IDENTIFIER, inst->name, context_time,
UTI_IPToString(&inst->ntp_address.ip_addr), inst->ntp_address.port,
inst->context_id, (int)inst->context.algorithm) < 0 ||
!UTI_BytesToHex(inst->context.s2c.key, inst->context.s2c.length, buf, sizeof (buf)) ||
fprintf(f, "%s ", buf) < 0 ||
!UTI_BytesToHex(inst->context.c2s.key, inst->context.c2s.length, buf, sizeof (buf)) ||
@@ -609,6 +626,8 @@ load_cookies(NNC_Instance inst)
inst->siv = NULL;
if (!fgets(line, sizeof (line), f) || strcmp(line, DUMP_IDENTIFIER) != 0 ||
!fgets(line, sizeof (line), f) || UTI_SplitString(line, words, MAX_WORDS) != 1 ||
strcmp(words[0], inst->name) != 0 ||
!fgets(line, sizeof (line), f) || UTI_SplitString(line, words, MAX_WORDS) != 1 ||
sscanf(words[0], "%lf", &context_time) != 1 ||
!fgets(line, sizeof (line), f) || UTI_SplitString(line, words, MAX_WORDS) != 2 ||

View File

@@ -34,7 +34,7 @@
typedef struct NNC_Instance_Record *NNC_Instance;
extern NNC_Instance NNC_CreateInstance(IPSockAddr *nts_address, const char *name,
const IPSockAddr *ntp_address);
uint32_t cert_set, uint16_t ntp_port);
extern void NNC_DestroyInstance(NNC_Instance inst);
extern int NNC_PrepareForAuth(NNC_Instance inst);
extern int NNC_GenerateRequestAuth(NNC_Instance inst, NTP_Packet *packet,

View File

@@ -59,8 +59,10 @@ struct NtsServer *server;
void
NNS_Initialise(void)
{
const char **certs, **keys;
/* Create an NTS-NTP server instance only if NTS-KE server is enabled */
if (!CNF_GetNtsServerCertFile() || !CNF_GetNtsServerKeyFile()) {
if (CNF_GetNtsServerCertAndKeyFiles(&certs, &keys) <= 0) {
server = NULL;
return;
}
@@ -96,11 +98,11 @@ NNS_CheckRequestAuth(NTP_Packet *packet, NTP_PacketInfo *info, uint32_t *kod)
NKE_Cookie cookie;
void *ef_body;
*kod = 0;
if (!server)
return 0;
*kod = 0;
server->num_cookies = 0;
server->req_tx = packet->transmit_ts;

View File

@@ -87,7 +87,7 @@ static const struct request_length request_lengths[] = {
REQ_LENGTH_ENTRY(del_source, null), /* DEL_SOURCE */
REQ_LENGTH_ENTRY(null, null), /* WRITERTC */
REQ_LENGTH_ENTRY(dfreq, null), /* DFREQ */
REQ_LENGTH_ENTRY(doffset, null), /* DOFFSET */
{ 0, 0 }, /* DOFFSET - not supported */
REQ_LENGTH_ENTRY(null, tracking), /* TRACKING */
REQ_LENGTH_ENTRY(sourcestats, sourcestats), /* SOURCESTATS */
REQ_LENGTH_ENTRY(null, rtc), /* RTCREPORT */
@@ -128,6 +128,7 @@ static const struct request_length request_lengths[] = {
client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX3 */
REQ_LENGTH_ENTRY(select_data, select_data), /* SELECT_DATA */
REQ_LENGTH_ENTRY(null, null), /* RELOAD_SOURCES */
REQ_LENGTH_ENTRY(doffset, null), /* DOFFSET2 */
};
static const uint16_t reply_lengths[] = {

View File

@@ -40,6 +40,9 @@
#include "samplefilt.h"
#include "sched.h"
/* Maximum offset of locked reference as a fraction of the PPS interval */
#define PPS_LOCK_LIMIT 0.4
/* list of refclock drivers */
extern RefclockDriver RCL_SHM_driver;
extern RefclockDriver RCL_SOCK_driver;
@@ -181,7 +184,7 @@ RCL_AddRefclock(RefclockParameters *params)
LOG_FATAL("refclock tai option requires leapsectz");
inst->data = NULL;
inst->driver_parameter = params->driver_parameter;
inst->driver_parameter = Strdup(params->driver_parameter);
inst->driver_parameter_length = 0;
inst->driver_poll = params->driver_poll;
inst->poll = params->poll;
@@ -261,15 +264,13 @@ RCL_AddRefclock(RefclockParameters *params)
params->driver_name, UTI_RefidToString(inst->ref_id),
inst->poll, inst->driver_poll, params->filter_length);
Free(params->driver_name);
return 1;
}
void
RCL_StartRefclocks(void)
{
unsigned int i, j, n;
unsigned int i, j, n, lock_index;
n = ARR_GetSize(refclocks);
@@ -279,13 +280,31 @@ RCL_StartRefclocks(void)
SRC_SetActive(inst->source);
inst->timeout_id = SCH_AddTimeoutByDelay(0.0, poll_timeout, (void *)inst);
if (inst->lock_ref) {
/* Replace lock refid with index to refclocks */
for (j = 0; j < n && get_refclock(j)->ref_id != inst->lock_ref; j++)
;
inst->lock_ref = j < n ? j : -1;
} else
inst->lock_ref = -1;
/* Replace lock refid with the refclock's index, or -1 if not valid */
lock_index = -1;
if (inst->lock_ref != 0) {
for (j = 0; j < n; j++) {
RCL_Instance inst2 = get_refclock(j);
if (inst->lock_ref != inst2->ref_id)
continue;
if (inst->driver->poll && inst2->driver->poll &&
(double)inst->max_lock_age / inst->pps_rate < UTI_Log2ToDouble(inst2->driver_poll))
LOG(LOGS_WARN, "%s maxlockage too small for %s",
UTI_RefidToString(inst->ref_id), UTI_RefidToString(inst2->ref_id));
lock_index = j;
break;
}
if (lock_index == -1 || lock_index == i)
LOG(LOGS_WARN, "Invalid lock refid %s", UTI_RefidToString(inst->lock_ref));
}
inst->lock_ref = lock_index;
}
}
@@ -417,12 +436,6 @@ accumulate_sample(RCL_Instance instance, struct timespec *sample_time, double of
sample.peer_dispersion = dispersion;
sample.root_dispersion = dispersion;
/* Handle special case when PPS is used with the local reference */
if (instance->pps_active && instance->lock_ref == -1)
sample.stratum = pps_stratum(instance, &sample.time);
else
sample.stratum = instance->stratum;
return SPF_AccumulateSample(instance->filter, &sample);
}
@@ -567,7 +580,7 @@ RCL_AddCookedPulse(RCL_Instance instance, struct timespec *cooked_time,
offset += shift;
if (fabs(ref_sample.offset - offset) +
ref_sample.root_dispersion + dispersion >= 0.2 / rate) {
ref_sample.root_dispersion + dispersion > PPS_LOCK_LIMIT / rate) {
DEBUG_LOG("refclock pulse ignored offdiff=%.9f refdisp=%.9f disp=%.9f",
ref_sample.offset - offset, ref_sample.root_dispersion, dispersion);
return 0;
@@ -687,7 +700,7 @@ static void
poll_timeout(void *arg)
{
NTP_Sample sample;
int poll;
int poll, stratum;
RCL_Instance inst = (RCL_Instance)arg;
@@ -703,8 +716,14 @@ poll_timeout(void *arg)
inst->driver_polled = 0;
if (SPF_GetFilteredSample(inst->filter, &sample)) {
/* Handle special case when PPS is used with the local reference */
if (inst->pps_active && inst->lock_ref == -1)
stratum = pps_stratum(inst, &sample.time);
else
stratum = inst->stratum;
SRC_UpdateReachability(inst->source, 1);
SRC_SetLeapStatus(inst->source, inst->leap_status);
SRC_UpdateStatus(inst->source, stratum, inst->leap_status);
SRC_AccumulateSample(inst->source, &sample);
SRC_SelectSource(inst->source);

View File

@@ -66,10 +66,8 @@ static int phc_initialise(RCL_Instance instance)
path = RCL_GetDriverParameter(instance);
phc_fd = SYS_Linux_OpenPHC(path, 0);
if (phc_fd < 0) {
if (phc_fd < 0)
LOG_FATAL("Could not open PHC");
return 0;
}
phc = MallocNew(struct phc_instance);
phc->fd = phc_fd;

View File

@@ -61,49 +61,36 @@ static int pps_initialise(RCL_Instance instance) {
edge_clear = RCL_GetDriverOption(instance, "clear") ? 1 : 0;
fd = open(path, O_RDWR);
if (fd < 0) {
if (fd < 0)
LOG_FATAL("Could not open %s : %s", path, strerror(errno));
return 0;
}
UTI_FdSetCloexec(fd);
if (time_pps_create(fd, &handle) < 0) {
if (time_pps_create(fd, &handle) < 0)
LOG_FATAL("time_pps_create() failed on %s : %s", path, strerror(errno));
return 0;
}
if (time_pps_getcap(handle, &mode) < 0) {
if (time_pps_getcap(handle, &mode) < 0)
LOG_FATAL("time_pps_getcap() failed on %s : %s", path, strerror(errno));
return 0;
}
if (time_pps_getparams(handle, &params) < 0) {
if (time_pps_getparams(handle, &params) < 0)
LOG_FATAL("time_pps_getparams() failed on %s : %s", path, strerror(errno));
return 0;
}
if (!edge_clear) {
if (!(mode & PPS_CAPTUREASSERT)) {
if (!(mode & PPS_CAPTUREASSERT))
LOG_FATAL("CAPTUREASSERT not supported on %s", path);
return 0;
}
params.mode |= PPS_CAPTUREASSERT;
params.mode &= ~PPS_CAPTURECLEAR;
} else {
if (!(mode & PPS_CAPTURECLEAR)) {
if (!(mode & PPS_CAPTURECLEAR))
LOG_FATAL("CAPTURECLEAR not supported on %s", path);
return 0;
}
params.mode |= PPS_CAPTURECLEAR;
params.mode &= ~PPS_CAPTUREASSERT;
}
if (time_pps_setparams(handle, &params) < 0) {
if (time_pps_setparams(handle, &params) < 0)
LOG_FATAL("time_pps_setparams() failed on %s : %s", path, strerror(errno));
return 0;
}
pps = MallocNew(struct pps_instance);
pps->handle = handle;

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009-2018
* Copyright (C) Miroslav Lichvar 2009-2018, 2020
*
* 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

View File

@@ -36,7 +36,14 @@ typedef struct {
int stratum;
int poll;
enum {RPT_NTP_CLIENT, RPT_NTP_PEER, RPT_LOCAL_REFERENCE} mode;
enum {RPT_SYNC, RPT_UNREACH, RPT_FALSETICKER, RPT_JITTERY, RPT_CANDIDATE, RPT_OUTLIER} state;
enum {
RPT_NONSELECTABLE,
RPT_FALSETICKER,
RPT_JITTERY,
RPT_SELECTABLE,
RPT_UNSELECTED,
RPT_SELECTED,
} state;
int reachability;
unsigned long latest_meas_ago; /* seconds */
@@ -183,6 +190,7 @@ typedef struct {
IPAddr ip_addr;
char state_char;
int authentication;
NTP_Leap leap;
int conf_options;
int eff_options;
uint32_t last_sample_ago;

2
rtc.c
View File

@@ -148,6 +148,8 @@ RTC_Initialise(int initial_set)
if (driver.init) {
if ((driver.init)()) {
driver_initialised = 1;
} else {
LOG(LOGS_ERR, "RTC driver could not be initialised");
}
} else {
LOG(LOGS_ERR, "RTC not supported on this operating system");

View File

@@ -386,7 +386,6 @@ combine_selected_samples(SPF_Instance filter, int n, NTP_Sample *result)
result->root_dispersion = MAX(disp, mean_root_dispersion);
result->peer_delay = mean_peer_delay;
result->root_delay = mean_root_delay;
result->stratum = last_sample->stratum;
return 1;
}

37
sched.c
View File

@@ -111,7 +111,8 @@ static struct timespec last_class_dispatch[SCH_NumberOfClasses];
/* ================================================== */
static int need_to_exit;
/* Flag terminating the main loop, which can be set from a signal handler */
static volatile int need_to_exit;
/* ================================================== */
@@ -498,12 +499,15 @@ SCH_RemoveTimeout(SCH_TimeoutID id)
static void
dispatch_timeouts(struct timespec *now) {
unsigned long n_done, n_entries_on_start;
TimerQueueEntry *ptr;
SCH_TimeoutHandler handler;
SCH_ArbitraryArgument arg;
int n_done = 0, n_entries_on_start = n_timer_queue_entries;
while (1) {
n_entries_on_start = n_timer_queue_entries;
n_done = 0;
do {
LCL_ReadRawTime(now);
if (!(n_timer_queue_entries > 0 &&
@@ -526,16 +530,21 @@ dispatch_timeouts(struct timespec *now) {
/* Increment count of timeouts handled */
++n_done;
/* If more timeouts were handled than there were in the timer queue on
start and there are now, assume some code is scheduling timeouts with
negative delays and abort. Make the actual limit higher in case the
machine is temporarily overloaded and dispatching the handlers takes
more time than was delay of a scheduled timeout. */
if (n_done > n_timer_queue_entries * 4 &&
n_done > n_entries_on_start * 4) {
/* If the number of dispatched timeouts is significantly larger than the
length of the queue on start and now, assume there is a bug causing
an infinite loop by constantly adding a timeout with a zero or negative
delay. Check the actual rate of timeouts to avoid false positives in
case the execution slowed down so much (e.g. due to memory thrashing)
that it repeatedly takes more time to handle the timeout than is its
delay. This is a safety mechanism intended to stop a full-speed flood
of NTP requests due to a bug in the NTP polling. */
if (n_done > 20 &&
n_done > 4 * MAX(n_timer_queue_entries, n_entries_on_start) &&
fabs(UTI_DiffTimespecsToDouble(now, &last_select_ts_raw)) / n_done < 0.01)
LOG_FATAL("Possible infinite loop in scheduling");
}
}
} while (!need_to_exit);
}
/* ================================================== */
@@ -799,14 +808,14 @@ SCH_MainLoop(void)
LCL_ReadRawTime(&now);
LCL_CookTime(&now, &cooked, &err);
update_monotonic_time(&now, &last_select_ts_raw);
/* Check if the time didn't jump unexpectedly */
if (!check_current_time(&saved_now, &now, status == 0, &saved_tv, ptv)) {
/* Cook the time again after handling the step */
LCL_CookTime(&now, &cooked, &err);
}
update_monotonic_time(&cooked, &last_select_ts);
last_select_ts_raw = now;
last_select_ts = cooked;
last_select_ts_err = err;

View File

@@ -204,6 +204,9 @@ SIV_Encrypt(SIV_Instance instance,
{
size_t clen = ciphertext_length;
if (!instance->cipher)
return 0;
if (nonce_length < 1 || assoc_length < 0 ||
plaintext_length < 0 || ciphertext_length < 0)
return 0;
@@ -232,6 +235,9 @@ SIV_Decrypt(SIV_Instance instance,
{
size_t plen = plaintext_length;
if (!instance->cipher)
return 0;
if (nonce_length < 1 || assoc_length < 0 ||
plaintext_length < 0 || ciphertext_length < 0)
return 0;

View File

@@ -39,6 +39,7 @@
struct SIV_Instance_Record {
struct siv_cmac_aes128_ctx siv;
int key_set;
};
/* ================================================== */
@@ -52,6 +53,7 @@ SIV_CreateInstance(SIV_Algorithm algorithm)
return NULL;
instance = MallocNew(struct SIV_Instance_Record);
instance->key_set = 0;
return instance;
}
@@ -86,6 +88,8 @@ SIV_SetKey(SIV_Instance instance, const unsigned char *key, int length)
siv_cmac_aes128_set_key(&instance->siv, key);
instance->key_set = 1;
return 1;
}
@@ -108,6 +112,9 @@ SIV_Encrypt(SIV_Instance instance,
const void *plaintext, int plaintext_length,
unsigned char *ciphertext, int ciphertext_length)
{
if (!instance->key_set)
return 0;
if (nonce_length < SIV_MIN_NONCE_SIZE || assoc_length < 0 ||
plaintext_length < 0 || plaintext_length > ciphertext_length ||
plaintext_length + SIV_DIGEST_SIZE != ciphertext_length)
@@ -130,6 +137,9 @@ SIV_Decrypt(SIV_Instance instance,
const unsigned char *ciphertext, int ciphertext_length,
void *plaintext, int plaintext_length)
{
if (!instance->key_set)
return 0;
if (nonce_length < SIV_MIN_NONCE_SIZE || assoc_length < 0 ||
plaintext_length < 0 || plaintext_length > ciphertext_length ||
plaintext_length + SIV_DIGEST_SIZE != ciphertext_length)

117
socket.c
View File

@@ -4,7 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Timo Teras 2009
* Copyright (C) Miroslav Lichvar 2009, 2013-2019
* Copyright (C) Miroslav Lichvar 2009, 2013-2020
*
* 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
@@ -737,23 +737,26 @@ init_message_nonaddress(SCK_Message *message)
/* ================================================== */
static int
match_cmsg(struct cmsghdr *cmsg, int level, int type, size_t length)
{
if (cmsg->cmsg_type == type && cmsg->cmsg_level == level &&
(length == 0 || cmsg->cmsg_len == CMSG_LEN(length)))
return 1;
return 0;
}
/* ================================================== */
static int
process_header(struct msghdr *msg, int msg_length, int sock_fd, int flags,
SCK_Message *message)
{
struct cmsghdr *cmsg;
int r = 1;
if (msg->msg_iovlen != 1) {
DEBUG_LOG("Unexpected iovlen");
return 0;
}
if (msg->msg_namelen > sizeof (union sockaddr_all)) {
DEBUG_LOG("Truncated source address");
return 0;
}
if (msg->msg_namelen > sizeof (((struct sockaddr *)msg->msg_name)->sa_family)) {
if (msg->msg_namelen <= sizeof (union sockaddr_all) &&
msg->msg_namelen > sizeof (((struct sockaddr *)msg->msg_name)->sa_family)) {
switch (((struct sockaddr *)msg->msg_name)->sa_family) {
case AF_INET:
#ifdef FEAT_IPV6
@@ -767,31 +770,45 @@ process_header(struct msghdr *msg, int msg_length, int sock_fd, int flags,
message->remote_addr.path = ((struct sockaddr_un *)msg->msg_name)->sun_path;
break;
default:
init_message_addresses(message, SCK_ADDR_UNSPEC);
DEBUG_LOG("Unexpected address");
return 0;
r = 0;
break;
}
} else {
init_message_addresses(message, SCK_ADDR_UNSPEC);
if (msg->msg_namelen > sizeof (union sockaddr_all)) {
DEBUG_LOG("Truncated source address");
r = 0;
}
}
init_message_nonaddress(message);
if (msg->msg_iovlen == 1) {
message->data = msg->msg_iov[0].iov_base;
message->length = msg_length;
} else {
DEBUG_LOG("Unexpected iovlen");
r = 0;
}
if (msg->msg_flags & MSG_TRUNC) {
log_message(sock_fd, 1, message, "Truncated", NULL);
return 0;
r = 0;
}
if (msg->msg_flags & MSG_CTRUNC) {
log_message(sock_fd, 1, message, "Truncated cmsg in", NULL);
return 0;
r = 0;
}
for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
if (0) {
}
#ifdef HAVE_IN_PKTINFO
if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
else if (match_cmsg(cmsg, IPPROTO_IP, IP_PKTINFO, sizeof (struct in_pktinfo))) {
struct in_pktinfo ipi;
if (message->addr_type != SCK_ADDR_IP)
@@ -803,7 +820,7 @@ process_header(struct msghdr *msg, int msg_length, int sock_fd, int flags,
message->if_index = ipi.ipi_ifindex;
}
#elif defined(IP_RECVDSTADDR)
if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) {
else if (match_cmsg(cmsg, IPPROTO_IP, IP_RECVDSTADDR, sizeof (struct in_addr))) {
struct in_addr addr;
if (message->addr_type != SCK_ADDR_IP)
@@ -814,9 +831,8 @@ process_header(struct msghdr *msg, int msg_length, int sock_fd, int flags,
message->local_addr.ip.family = IPADDR_INET4;
}
#endif
#ifdef HAVE_IN6_PKTINFO
if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
else if (match_cmsg(cmsg, IPPROTO_IPV6, IPV6_PKTINFO, sizeof (struct in6_pktinfo))) {
struct in6_pktinfo ipi;
if (message->addr_type != SCK_ADDR_IP)
@@ -829,25 +845,23 @@ process_header(struct msghdr *msg, int msg_length, int sock_fd, int flags,
message->if_index = ipi.ipi6_ifindex;
}
#endif
#ifdef SCM_TIMESTAMP
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMP) {
else if (match_cmsg(cmsg, SOL_SOCKET, SCM_TIMESTAMP, sizeof (struct timeval))) {
struct timeval tv;
memcpy(&tv, CMSG_DATA(cmsg), sizeof (tv));
UTI_TimevalToTimespec(&tv, &message->timestamp.kernel);
}
#endif
#ifdef SCM_TIMESTAMPNS
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPNS) {
else if (match_cmsg(cmsg, SOL_SOCKET, SCM_TIMESTAMPNS, sizeof (message->timestamp.kernel))) {
memcpy(&message->timestamp.kernel, CMSG_DATA(cmsg), sizeof (message->timestamp.kernel));
}
#endif
#ifdef HAVE_LINUX_TIMESTAMPING
#ifdef HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPING_PKTINFO) {
else if (match_cmsg(cmsg, SOL_SOCKET, SCM_TIMESTAMPING_PKTINFO,
sizeof (struct scm_ts_pktinfo))) {
struct scm_ts_pktinfo ts_pktinfo;
memcpy(&ts_pktinfo, CMSG_DATA(cmsg), sizeof (ts_pktinfo));
@@ -855,17 +869,17 @@ process_header(struct msghdr *msg, int msg_length, int sock_fd, int flags,
message->timestamp.l2_length = ts_pktinfo.pkt_length;
}
#endif
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPING) {
else if (match_cmsg(cmsg, SOL_SOCKET, SCM_TIMESTAMPING,
sizeof (struct scm_timestamping))) {
struct scm_timestamping ts3;
memcpy(&ts3, CMSG_DATA(cmsg), sizeof (ts3));
message->timestamp.kernel = ts3.ts[0];
message->timestamp.hw = ts3.ts[2];
}
if ((cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) ||
(cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_RECVERR)) {
else if ((match_cmsg(cmsg, SOL_IP, IP_RECVERR, 0) ||
match_cmsg(cmsg, SOL_IPV6, IPV6_RECVERR, 0)) &&
cmsg->cmsg_len >= CMSG_LEN(sizeof (struct sock_extended_err))) {
struct sock_extended_err err;
memcpy(&err, CMSG_DATA(cmsg), sizeof (err));
@@ -873,25 +887,34 @@ process_header(struct msghdr *msg, int msg_length, int sock_fd, int flags,
if (err.ee_errno != ENOMSG || err.ee_info != SCM_TSTAMP_SND ||
err.ee_origin != SO_EE_ORIGIN_TIMESTAMPING) {
log_message(sock_fd, 1, message, "Unexpected extended error in", NULL);
return 0;
r = 0;
}
}
#endif
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
else if (match_cmsg(cmsg, SOL_SOCKET, SCM_RIGHTS, 0)) {
if (!(flags & SCK_FLAG_MSG_DESCRIPTOR) || cmsg->cmsg_len != CMSG_LEN(sizeof (int))) {
unsigned int i;
int i, fd;
DEBUG_LOG("Unexpected SCM_RIGHTS");
for (i = 0; CMSG_LEN((i + 1) * sizeof (int)) <= cmsg->cmsg_len; i++)
close(((int *)CMSG_DATA(cmsg))[i]);
return 0;
for (i = 0; CMSG_LEN((i + 1) * sizeof (int)) <= cmsg->cmsg_len; i++) {
memcpy(&fd, (char *)CMSG_DATA(cmsg) + i * sizeof (int), sizeof (fd));
close(fd);
}
message->descriptor = *(int *)CMSG_DATA(cmsg);
r = 0;
} else {
memcpy(&message->descriptor, CMSG_DATA(cmsg), sizeof (message->descriptor));
}
}
else {
DEBUG_LOG("Unexpected control message level=%d type=%d len=%d",
cmsg->cmsg_level, cmsg->cmsg_type, (int)cmsg->cmsg_len);
}
}
return 1;
if (!r && message->descriptor != INVALID_SOCK_FD)
close(message->descriptor);
return r;
}
/* ================================================== */
@@ -901,7 +924,7 @@ receive_messages(int sock_fd, int flags, int max_messages, int *num_messages)
{
struct MessageHeader *hdr;
SCK_Message *messages;
unsigned int i, n;
unsigned int i, n, n_ok;
int ret, recv_flags = 0;
assert(initialised);
@@ -945,18 +968,20 @@ receive_messages(int sock_fd, int flags, int max_messages, int *num_messages)
received_messages = n;
for (i = 0; i < n; i++) {
for (i = n_ok = 0; i < n; i++) {
hdr = ARR_GetElement(recv_headers, i);
if (!process_header(&hdr->msg_hdr, hdr->msg_len, sock_fd, flags, &messages[i]))
return NULL;
if (!process_header(&hdr->msg_hdr, hdr->msg_len, sock_fd, flags, &messages[n_ok]))
continue;
log_message(sock_fd, 1, &messages[i],
log_message(sock_fd, 1, &messages[n_ok],
flags & SCK_FLAG_MSG_ERRQUEUE ? "Received error" : "Received", NULL);
n_ok++;
}
*num_messages = n;
*num_messages = n_ok;
return messages;
return n_ok > 0 ? messages : NULL;
}
/* ================================================== */

186
sources.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011-2016, 2018
* Copyright (C) Miroslav Lichvar 2011-2016, 2018, 2020
*
* 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
@@ -54,7 +54,6 @@ static int initialised = 0;
/* ================================================== */
/* Structure used to hold info for selecting between sources */
struct SelectInfo {
int stratum;
int select_ok;
double std_dev;
double root_distance;
@@ -132,7 +131,10 @@ struct SRC_Instance_Record {
struct SelectInfo sel_info;
/* Latest leap status */
/* Current stratum */
int stratum;
/* Current leap status */
NTP_Leap leap;
/* Flag indicating the source has a leap second vote */
@@ -175,6 +177,9 @@ static double reselect_distance;
static double stratum_weight;
static double combine_limit;
/* Identifier of the dump file */
#define DUMP_IDENTIFIER "SRC0\n"
/* ================================================== */
/* Forward prototype */
@@ -313,6 +318,7 @@ SRC_ResetInstance(SRC_Instance instance)
instance->distant = 0;
instance->status = SRC_BAD_STATS;
instance->sel_score = 1.0;
instance->stratum = 0;
instance->leap = LEAP_Unsynchronised;
instance->leap_vote = 0;
@@ -371,8 +377,10 @@ get_leap_status(void)
/* ================================================== */
void
SRC_SetLeapStatus(SRC_Instance inst, NTP_Leap leap)
SRC_UpdateStatus(SRC_Instance inst, int stratum, NTP_Leap leap)
{
inst->stratum = stratum;
if (REF_IsLeapSecondClose(NULL, 0.0))
return;
@@ -398,9 +406,9 @@ SRC_AccumulateSample(SRC_Instance inst, NTP_Sample *sample)
assert(initialised);
DEBUG_LOG("src=%s ts=%s offset=%e delay=%e disp=%e stratum=%d",
DEBUG_LOG("src=%s ts=%s offset=%e delay=%e disp=%e",
source_to_string(inst), UTI_TimespecToString(&sample->time), -sample->offset,
sample->root_delay, sample->root_dispersion, sample->stratum);
sample->root_delay, sample->root_dispersion);
if (REF_IsLeapSecondClose(&sample->time, sample->offset)) {
LOG(LOGS_INFO, "Dropping sample around leap second");
@@ -581,7 +589,7 @@ log_selection_source(const char *format, SRC_Instance inst)
name = source_to_string(inst);
ntp_name = inst->type == SRC_NTP ? NSR_GetName(inst->ip_addr) : NULL;
if (ntp_name && strcmp(name, ntp_name) != 0)
if (ntp_name)
snprintf(buf, sizeof (buf), "%s (%s)", name, ntp_name);
else
snprintf(buf, sizeof (buf), "%s", name);
@@ -808,7 +816,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
}
si = &sources[i]->sel_info;
SST_GetSelectionData(sources[i]->stats, &now, &si->stratum,
SST_GetSelectionData(sources[i]->stats, &now,
&si->lo_limit, &si->hi_limit, &si->root_distance,
&si->std_dev, &first_sample_ago,
&si->last_sample_ago, &si->select_ok);
@@ -890,10 +898,10 @@ SRC_SelectSource(SRC_Instance updated_inst)
source can settle down to a state where only one server is serving its
local unsychronised time and others are synchronised to it. */
if (si->stratum >= orphan_stratum && sources[i]->type == SRC_NTP) {
if (sources[i]->stratum >= orphan_stratum && sources[i]->type == SRC_NTP) {
mark_source(sources[i], SRC_ORPHAN);
if (si->stratum == orphan_stratum && sources[i]->reachability &&
if (sources[i]->stratum == orphan_stratum && sources[i]->reachability &&
(orphan_source == INVALID_SOURCE ||
sources[i]->ref_id < sources[orphan_source]->ref_id))
orphan_source = i;
@@ -1131,10 +1139,10 @@ SRC_SelectSource(SRC_Instance updated_inst)
/* Find minimum stratum */
index = sel_sources[0];
min_stratum = sources[index]->sel_info.stratum;
min_stratum = sources[index]->stratum;
for (i = 1; i < n_sel_sources; i++) {
index = sel_sources[i];
stratum = sources[index]->sel_info.stratum;
stratum = sources[index]->stratum;
if (stratum < min_stratum)
min_stratum = stratum;
}
@@ -1147,7 +1155,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
if (selected_source_index != INVALID_SOURCE)
sel_src_distance = sources[selected_source_index]->sel_info.root_distance +
(sources[selected_source_index]->sel_info.stratum - min_stratum) * stratum_weight;
(sources[selected_source_index]->stratum - min_stratum) * stratum_weight;
for (i = 0; i < n_sources; i++) {
/* Reset score for non-selectable sources */
@@ -1159,7 +1167,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
}
distance = sources[i]->sel_info.root_distance +
(sources[i]->sel_info.stratum - min_stratum) * stratum_weight;
(sources[i]->stratum - min_stratum) * stratum_weight;
if (sources[i]->type == SRC_NTP)
distance += reselect_distance;
@@ -1247,7 +1255,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
combined = combine_sources(n_sel_sources, &ref_time, &src_offset, &src_offset_sd,
&src_frequency, &src_frequency_sd, &src_skew);
REF_SetReference(sources[selected_source_index]->sel_info.stratum,
REF_SetReference(sources[selected_source_index]->stratum,
leap_status, combined,
sources[selected_source_index]->ref_id,
sources[selected_source_index]->ip_addr,
@@ -1320,24 +1328,60 @@ add_dispersion(double dispersion, void *anything)
/* ================================================== */
static
FILE *open_dumpfile(SRC_Instance inst, char mode)
static int
get_dumpfile(SRC_Instance inst, char *filename, size_t len)
{
char filename[64], *dumpdir;
/* Use the IP address, or reference ID with reference clocks */
switch (inst->type) {
case SRC_NTP:
if (!UTI_IsIPReal(inst->ip_addr) ||
snprintf(filename, len, "%s", source_to_string(inst)) >= len)
return 0;
break;
case SRC_REFCLOCK:
if (snprintf(filename, len, "refid:%08"PRIx32, inst->ref_id) >= len)
return 0;
break;
default:
assert(0);
}
return 1;
}
/* ================================================== */
static void
save_source(SRC_Instance inst)
{
char filename[64], *dumpdir, *ntp_name;
FILE *f;
dumpdir = CNF_GetDumpDir();
if (!dumpdir)
return NULL;
return;
/* Include IP address in the name for NTP sources, or reference ID in hex */
if (inst->type == SRC_NTP && UTI_IsIPReal(inst->ip_addr))
snprintf(filename, sizeof (filename), "%s", source_to_string(inst));
else if (inst->type == SRC_REFCLOCK)
snprintf(filename, sizeof (filename), "refid:%08"PRIx32, inst->ref_id);
else
return NULL;
if (!get_dumpfile(inst, filename, sizeof (filename)))
return;
return UTI_OpenFile(dumpdir, filename, ".dat", mode, 0644);
f = UTI_OpenFile(dumpdir, filename, ".dat", 'w', 0644);
if (!f)
return;
ntp_name = inst->type == SRC_NTP ? NSR_GetName(inst->ip_addr) : ".";
if (fprintf(f, "%s%s\n%d %o %d %d %d\n",
DUMP_IDENTIFIER, ntp_name, inst->authenticated,
(unsigned int)inst->reachability, inst->reachability_size,
inst->stratum, (int)inst->leap) < 0 ||
!SST_SaveToFile(inst->stats, f)) {
fclose(f);
if (!UTI_RemoveFile(dumpdir, filename, ".dat"))
;
return;
}
fclose(f);
}
/* ================================================== */
@@ -1346,16 +1390,60 @@ FILE *open_dumpfile(SRC_Instance inst, char mode)
void
SRC_DumpSources(void)
{
FILE *out;
int i;
for (i = 0; i < n_sources; i++) {
out = open_dumpfile(sources[i], 'w');
if (!out)
continue;
SST_SaveToFile(sources[i]->stats, out);
fclose(out);
for (i = 0; i < n_sources; i++)
save_source(sources[i]);
}
/* ================================================== */
#define MAX_WORDS 1
static void
load_source(SRC_Instance inst)
{
char filename[64], line[256], *dumpdir, *ntp_name, *words[MAX_WORDS];
int auth, leap, reach_size, stratum;
unsigned int reach;
FILE *f;
dumpdir = CNF_GetDumpDir();
if (!dumpdir)
return;
if (!get_dumpfile(inst, filename, sizeof (filename)))
return;
f = UTI_OpenFile(dumpdir, filename, ".dat", 'r', 0);
if (!f)
return;
ntp_name = inst->type == SRC_NTP ? NSR_GetName(inst->ip_addr) : NULL;
if (!fgets(line, sizeof (line), f) || strcmp(line, DUMP_IDENTIFIER) != 0 ||
!fgets(line, sizeof (line), f) || UTI_SplitString(line, words, MAX_WORDS) != 1 ||
(inst->type == SRC_NTP && (!ntp_name || strcmp(words[0], ntp_name) != 0)) ||
!fgets(line, sizeof (line), f) ||
sscanf(words[0], "%d %o %d %d %d",
&auth, &reach, &reach_size, &stratum, &leap) != 5 ||
(!auth && inst->authenticated) ||
stratum < 0 || stratum >= NTP_MAX_STRATUM ||
leap < LEAP_Normal || leap >= LEAP_Unsynchronised ||
!SST_LoadFromFile(inst->stats, f)) {
LOG(LOGS_WARN, "Could not load dump file for %s", source_to_string(inst));
fclose(f);
return;
}
inst->reachability = reach & ((1U << SOURCE_REACH_BITS) - 1);
inst->reachability_size = CLAMP(0, reach_size, SOURCE_REACH_BITS);
inst->stratum = stratum;
inst->leap = leap;
LOG(LOGS_INFO, "Loaded dump file for %s", source_to_string(inst));
fclose(f);
}
/* ================================================== */
@@ -1363,21 +1451,17 @@ SRC_DumpSources(void)
void
SRC_ReloadSources(void)
{
FILE *in;
int i;
for (i = 0; i < n_sources; i++) {
in = open_dumpfile(sources[i], 'r');
if (!in)
continue;
if (!SST_LoadFromFile(sources[i]->stats, in))
LOG(LOGS_WARN, "Could not load dump file for %s",
source_to_string(sources[i]));
else
LOG(LOGS_INFO, "Loaded dump file for %s",
source_to_string(sources[i]));
fclose(in);
load_source(sources[i]);
/* Allow an immediate update of the reference */
sources[i]->updates++;
}
/* Select sources and set the reference */
SRC_SelectSource(NULL);
}
/* ================================================== */
@@ -1492,6 +1576,8 @@ SRC_ReportSource(int index, RPT_SourceReport *report, struct timespec *now)
report->ip_addr.family = IPADDR_INET4;
}
report->stratum = src->stratum;
switch (src->status) {
case SRC_FALSETICKER:
report->state = RPT_FALSETICKER;
@@ -1499,22 +1585,21 @@ SRC_ReportSource(int index, RPT_SourceReport *report, struct timespec *now)
case SRC_JITTERY:
report->state = RPT_JITTERY;
break;
case SRC_UNTRUSTED:
case SRC_WAITS_SOURCES:
case SRC_NONPREFERRED:
case SRC_WAITS_UPDATE:
case SRC_DISTANT:
case SRC_OUTLIER:
report->state = RPT_OUTLIER;
report->state = RPT_SELECTABLE;
break;
case SRC_UNSELECTED:
report->state = RPT_CANDIDATE;
report->state = RPT_UNSELECTED;
break;
case SRC_SELECTED:
report->state = RPT_SYNC;
report->state = RPT_SELECTED;
break;
default:
report->state = RPT_UNREACH;
report->state = RPT_NONSELECTABLE;
break;
}
@@ -1611,6 +1696,7 @@ SRC_GetSelectReport(int index, RPT_SelectReport *report)
report->ip_addr.family = IPADDR_UNSPEC;
report->state_char = get_status_char(inst->status);
report->authentication = inst->authenticated;
report->leap = inst->leap;
report->conf_options = inst->conf_sel_options;
report->eff_options = inst->sel_options;
report->last_sample_ago = inst->sel_info.last_sample_ago;

View File

@@ -87,8 +87,8 @@ extern void SRC_SetRefid(SRC_Instance instance, uint32_t ref_id, IPAddr *addr);
/* Function to get access to the sourcestats instance */
extern SST_Stats SRC_GetSourcestats(SRC_Instance instance);
/* Function to set the current leap status according to the source */
extern void SRC_SetLeapStatus(SRC_Instance instance, NTP_Leap leap);
/* Function to update the stratum and leap status of the source */
extern void SRC_UpdateStatus(SRC_Instance instance, int stratum, NTP_Leap leap);
/* Function to accumulate a new sample from the source */
extern void SRC_AccumulateSample(SRC_Instance instance, NTP_Sample *sample);

View File

@@ -177,9 +177,6 @@ struct SST_Stats_Record {
/* This array contains the root dispersions of each sample at the
time of the measurements */
double root_dispersions[MAX_SAMPLES];
/* The stratum from the last accumulated sample */
int stratum;
};
/* ================================================== */
@@ -321,7 +318,6 @@ SST_AccumulateSample(SST_Stats inst, NTP_Sample *sample)
inst->peer_dispersions[m] = sample->peer_dispersion;
inst->root_delays[m] = sample->root_delay;
inst->root_dispersions[m] = sample->root_dispersion;
inst->stratum = sample->stratum;
if (inst->peer_delays[n] < inst->fixed_min_delay)
inst->peer_delays[n] = 2.0 * inst->fixed_min_delay - inst->peer_delays[n];
@@ -650,7 +646,6 @@ SST_GetFrequencyRange(SST_Stats inst,
void
SST_GetSelectionData(SST_Stats inst, struct timespec *now,
int *stratum,
double *offset_lo_limit,
double *offset_hi_limit,
double *root_distance,
@@ -670,7 +665,6 @@ SST_GetSelectionData(SST_Stats inst, struct timespec *now,
i = get_runsbuf_index(inst, inst->best_single_sample);
j = get_buf_index(inst, inst->best_single_sample);
*stratum = inst->stratum;
*std_dev = inst->std_dev;
sample_elapsed = fabs(UTI_DiffTimespecsToDouble(now, &inst->sample_times[i]));
@@ -858,38 +852,30 @@ SST_GetDelayTestData(SST_Stats inst, struct timespec *sample_time,
/* This is used to save the register to a file, so that we can reload
it after restarting the daemon */
void
int
SST_SaveToFile(SST_Stats inst, FILE *out)
{
int m, i, j;
fprintf(out, "%d\n", inst->n_samples);
if (inst->n_samples < 1)
return 0;
if (fprintf(out, "%d %d\n", inst->n_samples, inst->asymmetry_run) < 0)
return 0;
for(m = 0; m < inst->n_samples; m++) {
i = get_runsbuf_index(inst, m);
j = get_buf_index(inst, m);
fprintf(out,
#ifdef HAVE_LONG_TIME_T
"%08"PRIx64" %08lx %.6e %.6e %.6e %.6e %.6e %.6e %.6e %d\n",
(uint64_t)inst->sample_times[i].tv_sec,
#else
"%08lx %08lx %.6e %.6e %.6e %.6e %.6e %.6e %.6e %d\n",
(unsigned long)inst->sample_times[i].tv_sec,
#endif
(unsigned long)inst->sample_times[i].tv_nsec / 1000,
inst->offsets[i],
inst->orig_offsets[j],
inst->peer_delays[i],
inst->peer_dispersions[j],
inst->root_delays[j],
inst->root_dispersions[j],
1.0, /* used to be inst->weights[i] */
inst->stratum /* used to be an array */);
if (fprintf(out, "%s %.6e %.6e %.6e %.6e %.6e %.6e\n",
UTI_TimespecToString(&inst->sample_times[i]),
inst->offsets[i], inst->orig_offsets[j],
inst->peer_delays[i], inst->peer_dispersions[j],
inst->root_delays[j], inst->root_dispersions[j]) < 0)
return 0;
}
fprintf(out, "%d\n", inst->asymmetry_run);
return 1;
}
/* ================================================== */
@@ -898,65 +884,32 @@ SST_SaveToFile(SST_Stats inst, FILE *out)
int
SST_LoadFromFile(SST_Stats inst, FILE *in)
{
#ifdef HAVE_LONG_TIME_T
uint64_t sec;
#else
unsigned long sec;
#endif
unsigned long usec;
int i;
char line[1024];
double weight;
int i, n_samples, arun;
double sample_time;
char line[256];
if (!fgets(line, sizeof (line), in) ||
sscanf(line, "%d %d", &n_samples, &arun) != 2 ||
n_samples < 1 || n_samples > MAX_SAMPLES)
return 0;
SST_ResetInstance(inst);
if (fgets(line, sizeof(line), in) &&
sscanf(line, "%d", &inst->n_samples) == 1 &&
inst->n_samples >= 0 && inst->n_samples <= MAX_SAMPLES) {
for (i=0; i<inst->n_samples; i++) {
if (!fgets(line, sizeof(line), in) ||
(sscanf(line,
#ifdef HAVE_LONG_TIME_T
"%"SCNx64"%lx%lf%lf%lf%lf%lf%lf%lf%d\n",
#else
"%lx%lx%lf%lf%lf%lf%lf%lf%lf%d\n",
#endif
&(sec), &(usec),
&(inst->offsets[i]),
&(inst->orig_offsets[i]),
&(inst->peer_delays[i]),
&(inst->peer_dispersions[i]),
&(inst->root_delays[i]),
&(inst->root_dispersions[i]),
&weight, /* not used anymore */
&inst->stratum) != 10)) {
/* This is the branch taken if the read FAILED */
inst->n_samples = 0; /* Load abandoned if any sign of corruption */
for (i = 0; i < n_samples; i++) {
if (!fgets(line, sizeof (line), in) ||
sscanf(line, "%lf %lf %lf %lf %lf %lf %lf",
&sample_time, &inst->offsets[i], &inst->orig_offsets[i],
&inst->peer_delays[i], &inst->peer_dispersions[i],
&inst->root_delays[i], &inst->root_dispersions[i]) != 7)
return 0;
} else {
/* This is the branch taken if the read is SUCCESSFUL */
inst->sample_times[i].tv_sec = sec;
inst->sample_times[i].tv_nsec = 1000 * usec;
UTI_NormaliseTimespec(&inst->sample_times[i]);
}
/* Some resolution is lost in the double format, but that's ok */
UTI_DoubleToTimespec(sample_time, &inst->sample_times[i]);
}
/* This field was not saved in older versions */
if (!fgets(line, sizeof(line), in) || sscanf(line, "%d\n", &inst->asymmetry_run) != 1)
inst->asymmetry_run = 0;
} else {
inst->n_samples = 0; /* Load abandoned if any sign of corruption */
return 0;
}
if (!inst->n_samples)
return 1;
inst->n_samples = n_samples;
inst->last_sample = inst->n_samples - 1;
inst->asymmetry_run = CLAMP(-MAX_ASYMMETRY_RUN, arun, MAX_ASYMMETRY_RUN);
find_min_delay_sample(inst);
SST_DoNewRegression(inst);
@@ -978,7 +931,6 @@ SST_DoSourceReport(SST_Stats inst, RPT_SourceReport *report, struct timespec *no
report->orig_latest_meas = inst->orig_offsets[j];
report->latest_meas = inst->offsets[i];
report->latest_meas_err = 0.5*inst->root_delays[j] + inst->root_dispersions[j];
report->stratum = inst->stratum;
/* Align the sample time to reduce the leak of the receive timestamp */
last_sample_time = inst->sample_times[i];

View File

@@ -69,7 +69,6 @@ extern void SST_GetFrequencyRange(SST_Stats inst, double *lo, double *hi);
/* Get data needed for selection */
extern void
SST_GetSelectionData(SST_Stats inst, struct timespec *now,
int *stratum,
double *offset_lo_limit,
double *offset_hi_limit,
double *root_distance,
@@ -120,7 +119,7 @@ extern int SST_GetDelayTestData(SST_Stats inst, struct timespec *sample_time,
double *last_sample_ago, double *predicted_offset,
double *min_delay, double *skew, double *std_dev);
extern void SST_SaveToFile(SST_Stats inst, FILE *out);
extern int SST_SaveToFile(SST_Stats inst, FILE *out);
extern int SST_LoadFromFile(SST_Stats inst, FILE *in);

View File

@@ -54,7 +54,9 @@ typedef struct {
int sel_options;
int nts;
int nts_port;
int copy;
uint32_t authkey;
uint32_t cert_set;
double max_delay;
double max_delay_ratio;
double max_delay_dev_ratio;
@@ -77,6 +79,7 @@ typedef struct {
#define SRC_DEFAULT_MAXSAMPLES (-1)
#define SRC_DEFAULT_ASYMMETRY 1.0
#define SRC_DEFAULT_NTSPORT 4460
#define SRC_DEFAULT_CERTSET 0
#define INACTIVE_AUTHKEY 0
/* Flags for source selection */

View File

@@ -49,7 +49,7 @@
#include "sched.h"
#include "util.h"
#ifndef FEAT_ASYNCDNS
#if defined(FEAT_NTP) && !defined(FEAT_ASYNCDNS)
/* This is a blocking implementation used when asynchronous resolving is not available */
@@ -491,7 +491,8 @@ NNS_GenerateResponseAuth(NTP_Packet *request, NTP_PacketInfo *req_info,
}
NNC_Instance
NNC_CreateInstance(IPSockAddr *nts_address, const char *name, const IPSockAddr *ntp_address)
NNC_CreateInstance(IPSockAddr *nts_address, const char *name, uint32_t cert_set,
uint16_t ntp_port)
{
return NULL;
}

12
sys.c
View File

@@ -97,16 +97,16 @@ SYS_Finalise(void)
/* ================================================== */
void SYS_DropRoot(uid_t uid, gid_t gid)
void SYS_DropRoot(uid_t uid, gid_t gid, SYS_ProcessContext context)
{
#if defined(LINUX) && defined (FEAT_PRIVDROP)
SYS_Linux_DropRoot(uid, gid, !null_driver);
SYS_Linux_DropRoot(uid, gid, context, !null_driver);
#elif defined(SOLARIS) && defined(FEAT_PRIVDROP)
SYS_Solaris_DropRoot(uid, gid);
SYS_Solaris_DropRoot(uid, gid, context);
#elif (defined(NETBSD) || defined(FREEBSD)) && defined(FEAT_PRIVDROP)
SYS_NetBSD_DropRoot(uid, gid);
SYS_NetBSD_DropRoot(uid, gid, context, !null_driver);
#elif defined(MACOSX) && defined(FEAT_PRIVDROP)
SYS_MacOSX_DropRoot(uid, gid);
SYS_MacOSX_DropRoot(uid, gid, context);
#else
LOG_FATAL("dropping root privileges not supported");
#endif
@@ -114,7 +114,7 @@ void SYS_DropRoot(uid_t uid, gid_t gid)
/* ================================================== */
void SYS_EnableSystemCallFilter(int level, SYS_SystemCallContext context)
void SYS_EnableSystemCallFilter(int level, SYS_ProcessContext context)
{
#if defined(LINUX) && defined(FEAT_SCFILTER)
SYS_Linux_EnableSystemCallFilter(level, context);

10
sys.h
View File

@@ -35,17 +35,17 @@ extern void SYS_Initialise(int clock_control);
/* Called at the end of the run to do final clean-up */
extern void SYS_Finalise(void);
/* Drop root privileges to the specified user and group */
extern void SYS_DropRoot(uid_t uid, gid_t gid);
typedef enum {
SYS_MAIN_PROCESS,
SYS_NTSKE_HELPER,
} SYS_SystemCallContext;
} SYS_ProcessContext;
/* Switch to the specified user and group in given context */
extern void SYS_DropRoot(uid_t uid, gid_t gid, SYS_ProcessContext context);
/* Enable a system call filter to allow only system calls
which chronyd normally needs after initialization */
extern void SYS_EnableSystemCallFilter(int level, SYS_SystemCallContext context);
extern void SYS_EnableSystemCallFilter(int level, SYS_ProcessContext context);
extern void SYS_SetScheduler(int SchedPriority);
extern void SYS_LockMemory(void);

View File

@@ -426,7 +426,7 @@ SYS_Linux_Finalise(void)
#ifdef FEAT_PRIVDROP
void
SYS_Linux_DropRoot(uid_t uid, gid_t gid, int clock_control)
SYS_Linux_DropRoot(uid_t uid, gid_t gid, SYS_ProcessContext context, int clock_control)
{
char cap_text[256];
cap_t cap;
@@ -437,16 +437,23 @@ SYS_Linux_DropRoot(uid_t uid, gid_t gid, int clock_control)
UTI_DropRoot(uid, gid);
/* Keep CAP_NET_BIND_SERVICE if the NTP server sockets may need to be bound.
Keep CAP_NET_RAW if an NTP socket may need to be bound to a device.
/* Keep CAP_NET_BIND_SERVICE if the NTP server sockets may need to be bound
to a privileged port.
Keep CAP_NET_RAW if an NTP socket may need to be bound to a device on
kernels before 5.7.
Keep CAP_SYS_TIME if the clock control is enabled. */
if (snprintf(cap_text, sizeof (cap_text), "%s %s %s",
CNF_GetNTPPort() ? "cap_net_bind_service=ep" : "",
CNF_GetBindNtpInterface() || CNF_GetBindAcquisitionInterface() ?
"cap_net_raw=ep" : "",
(CNF_GetNTPPort() > 0 && CNF_GetNTPPort() < 1024) ?
"cap_net_bind_service=ep" : "",
(CNF_GetBindNtpInterface() || CNF_GetBindAcquisitionInterface()) &&
!SYS_Linux_CheckKernelVersion(5, 7) ? "cap_net_raw=ep" : "",
clock_control ? "cap_sys_time=ep" : "") >= sizeof (cap_text))
assert(0);
/* Helpers don't need any capabilities */
if (context != SYS_MAIN_PROCESS)
cap_text[0] = '\0';
if ((cap = cap_from_text(cap_text)) == NULL) {
LOG_FATAL("cap_from_text() failed");
}
@@ -477,7 +484,7 @@ void check_seccomp_applicability(void)
/* ================================================== */
void
SYS_Linux_EnableSystemCallFilter(int level, SYS_SystemCallContext context)
SYS_Linux_EnableSystemCallFilter(int level, SYS_ProcessContext context)
{
const int syscalls[] = {
/* Clock */
@@ -530,17 +537,27 @@ SYS_Linux_EnableSystemCallFilter(int level, SYS_SystemCallContext context)
SCMP_SYS(fchownat),
SCMP_SYS(fstat),
SCMP_SYS(fstat64),
SCMP_SYS(fstatat64),
SCMP_SYS(getdents),
SCMP_SYS(getdents64),
SCMP_SYS(lseek),
SCMP_SYS(lstat),
SCMP_SYS(lstat64),
SCMP_SYS(newfstatat),
SCMP_SYS(readlink),
SCMP_SYS(readlinkat),
SCMP_SYS(rename),
SCMP_SYS(renameat),
#ifdef __NR_renameat2
SCMP_SYS(renameat2),
#endif
SCMP_SYS(stat),
SCMP_SYS(stat64),
SCMP_SYS(statfs),
SCMP_SYS(statfs64),
#ifdef __NR_statx
SCMP_SYS(statx),
#endif
SCMP_SYS(unlink),
SCMP_SYS(unlinkat),
@@ -604,7 +621,7 @@ SYS_Linux_EnableSystemCallFilter(int level, SYS_SystemCallContext context)
};
const static int socket_options[][2] = {
{ SOL_IP, IP_PKTINFO }, { SOL_IP, IP_FREEBIND },
{ SOL_IP, IP_PKTINFO }, { SOL_IP, IP_FREEBIND }, { SOL_IP, IP_TOS },
#ifdef FEAT_IPV6
{ SOL_IPV6, IPV6_V6ONLY }, { SOL_IPV6, IPV6_RECVPKTINFO },
#endif

View File

@@ -33,9 +33,9 @@ extern void SYS_Linux_Initialise(void);
extern void SYS_Linux_Finalise(void);
extern void SYS_Linux_DropRoot(uid_t uid, gid_t gid, int clock_control);
extern void SYS_Linux_DropRoot(uid_t uid, gid_t gid, SYS_ProcessContext context, int clock_control);
extern void SYS_Linux_EnableSystemCallFilter(int level, SYS_SystemCallContext context);
extern void SYS_Linux_EnableSystemCallFilter(int level, SYS_ProcessContext context);
extern int SYS_Linux_CheckKernelVersion(int req_major, int req_minor);

View File

@@ -4,7 +4,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2001
* Copyright (C) J. Hannken-Illjes 2001
* Copyright (C) Bryan Christianson 2015, 2017
* Copyright (C) Bryan Christianson 2015, 2017, 2020
*
* 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
@@ -415,8 +415,9 @@ SYS_MacOSX_SetScheduler(int SchedPriority)
/* ================================================== */
#ifdef FEAT_PRIVDROP
void SYS_MacOSX_DropRoot(uid_t uid, gid_t gid)
void SYS_MacOSX_DropRoot(uid_t uid, gid_t gid, SYS_ProcessContext context)
{
if (context == SYS_MAIN_PROCESS)
PRV_StartHelper();
UTI_DropRoot(uid, gid);

View File

@@ -30,8 +30,10 @@
#ifndef GOT_SYS_MACOSX_H
#define GOT_SYS_MACOSX_H
#include "sys.h"
void SYS_MacOSX_SetScheduler(int SchedPriority);
void SYS_MacOSX_DropRoot(uid_t uid, gid_t gid);
void SYS_MacOSX_DropRoot(uid_t uid, gid_t gid, SYS_ProcessContext context);
void SYS_MacOSX_Initialise(void);
void SYS_MacOSX_Finalise(void);

View File

@@ -131,7 +131,7 @@ SYS_NetBSD_Finalise(void)
#ifdef FEAT_PRIVDROP
void
SYS_NetBSD_DropRoot(uid_t uid, gid_t gid)
SYS_NetBSD_DropRoot(uid_t uid, gid_t gid, SYS_ProcessContext context, int clock_control)
{
#ifdef NETBSD
int fd;
@@ -139,11 +139,15 @@ SYS_NetBSD_DropRoot(uid_t uid, gid_t gid)
/* On NetBSD the helper is used only for socket binding, but on FreeBSD
it's used also for setting and adjusting the system clock */
if (context == SYS_MAIN_PROCESS)
PRV_StartHelper();
UTI_DropRoot(uid, gid);
#ifdef NETBSD
if (!clock_control)
return;
/* Check if we have write access to /dev/clockctl */
fd = open("/dev/clockctl", O_WRONLY);
if (fd < 0)

View File

@@ -28,10 +28,12 @@
#ifndef GOT_SYS_NETBSD_H
#define GOT_SYS_NETBSD_H
#include "sys.h"
void SYS_NetBSD_Initialise(void);
void SYS_NetBSD_Finalise(void);
void SYS_NetBSD_DropRoot(uid_t uid, gid_t gid);
void SYS_NetBSD_DropRoot(uid_t uid, gid_t gid, SYS_ProcessContext context, int clock_control);
#endif

View File

@@ -55,8 +55,9 @@ SYS_Solaris_Finalise(void)
#ifdef FEAT_PRIVDROP
void
SYS_Solaris_DropRoot(uid_t uid, gid_t gid)
SYS_Solaris_DropRoot(uid_t uid, gid_t gid, SYS_ProcessContext context)
{
if (context == SYS_MAIN_PROCESS)
PRV_StartHelper();
UTI_DropRoot(uid, gid);
}

View File

@@ -27,10 +27,12 @@
#ifndef GOT_SYS_SOLARIS_H
#define GOT_SYS_SOLARIS_H
#include "sys.h"
void SYS_Solaris_Initialise(void);
void SYS_Solaris_Finalise(void);
void SYS_Solaris_DropRoot(uid_t uid, gid_t gid);
void SYS_Solaris_DropRoot(uid_t uid, gid_t gid, SYS_ProcessContext context);
#endif

View File

@@ -68,6 +68,18 @@ static int sys_tai_offset;
/* ================================================== */
static double
convert_timex_frequency(const struct timex *txc)
{
double freq_ppm;
freq_ppm = txc->freq / FREQ_SCALE;
return -freq_ppm;
}
/* ================================================== */
static double
read_frequency(void)
{
@@ -77,7 +89,7 @@ read_frequency(void)
SYS_Timex_Adjust(&txc, 0);
return txc.freq / -FREQ_SCALE;
return convert_timex_frequency(&txc);
}
/* ================================================== */
@@ -92,7 +104,7 @@ set_frequency(double freq_ppm)
SYS_Timex_Adjust(&txc, 0);
return txc.freq / -FREQ_SCALE;
return convert_timex_frequency(&txc);
}
/* ================================================== */

View File

@@ -28,6 +28,7 @@
#ifndef GOT_SYSINCL_H
#define GOT_SYSINCL_H
#include <arpa/inet.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
@@ -61,11 +62,6 @@
#include <sys/timex.h>
#endif
#ifdef FEAT_IPV6
/* For inet_ntop() */
#include <arpa/inet.h>
#endif
#ifdef HAVE_GETRANDOM
#include <sys/random.h>
#endif

View File

@@ -17,12 +17,15 @@ for opts in \
"--disable-rtc" \
"--disable-sechash" \
"--disable-cmdmon" \
"--disable-cmdmon --enable-scfilter" \
"--disable-ntp" \
"--disable-ntp --enable-scfilter" \
"--disable-nts" \
"--disable-refclock" \
"--disable-timestamping" \
"--disable-timestamping --disable-ntp" \
"--disable-cmdmon --disable-ntp" \
"--disable-cmdmon --disable-ntp --enable-scfilter" \
"--disable-cmdmon --disable-refclock" \
"--disable-cmdmon --disable-ntp --disable-refclock"
do

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
# Run the unit and simulation tests with different compiler sanitizers
# and under valgrind
@@ -80,7 +80,12 @@ for CC in gcc clang; do
echo
pushd test/simulation || exit 1
CLKNETSIM_RANDOM_SEED=101 ./run -i 1 || exit 1
export CLKNETSIM_RANDOM_SEED=101
if [ "$arch_opts" = "" -a "$san_options" = "" ]; then
CLKNETSIM_CLIENT_WRAPPER=valgrind ./run -i 1 || exit 1
else
./run -i 1 || exit 1
fi
popd
done
done

View File

@@ -52,15 +52,15 @@ test_freqrange(void)
printf("freq range:\n");
for (i = 0; i <= 1000; i += 50) {
for (i = -1000; i <= 1000; i += 50) {
t.modes = MOD_FREQUENCY;
t.freq = i << 16;
t.freq = i * (1 << 16);
printf("%4d ppm => ", i);
if (try_ntpadjtime(&t) < 0)
continue;
printf("%4ld ppm : ", t.freq / (1 << 16));
printf("%s\n", t.freq == i << 16 ? "ok" : "fail");
printf("%s\n", t.freq == i * (1 << 16) ? "ok" : "fail");
}
}

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common
test_start "NTP eras"

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common
test_start "minpoll/maxpoll options"

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common
test_start "iburst option"

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common
test_start "initstepslew directive"
@@ -9,6 +9,7 @@ time_rms_limit=1e-3
limit=100
client_conf="initstepslew 5 192.168.123.1"
client_server_conf="#"
min_sync_time=6
max_sync_time=35
@@ -18,6 +19,7 @@ for time_offset in -2.0 -0.2 0.2 2.0; do
check_chronyd_exit || test_fail
check_packet_interval || test_fail
check_sync || test_fail
check_log_messages "00:00:0.Z System's initial.*slew" 1 1 || test_fail
done
min_sync_time=5
@@ -27,6 +29,35 @@ for time_offset in -1e8 -1e2 1e2 1e8; do
run_test || test_fail
check_packet_interval || test_fail
check_sync || test_fail
check_log_messages "System's initial.*step" 1 1 || test_fail
done
time_offset=3
limit=500
servers=2
falsetickers=1
client_conf="initstepslew 5 192.168.123.1 192.168.123.2"
client_server_conf="server 192.168.123.2"
min_sync_time=360
max_sync_time=450
run_test || test_fail
check_chronyd_exit || test_fail
check_packet_interval || test_fail
check_sync || test_fail
check_log_messages "00:03:2.Z No suitable source for initstepslew" 1 1 || test_fail
client_conf="initstepslew 5 192.168.123.1 192.168.123.2"
min_sync_time=1
max_sync_time=500
server_conf="deny all"
run_test || test_fail
check_chronyd_exit || test_fail
check_packet_interval || test_fail
check_sync && test_fail
check_log_messages "00:00:1.Z No suitable source for initstepslew" 1 1 || test_fail
test_pass

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common
test_start "driftfile directive"

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common
test_start "SHM refclock"
@@ -16,7 +16,9 @@ chronyc_start=70
chronyc_conf="tracking"
for refclock in "SHM 0" "PHC /dev/ptp0"; do
client_conf="refclock $refclock stratum 3 delay 1e-3 refid GPS"
client_conf="refclock $refclock stratum 3 delay 1e-3 refid GPS
logdir tmp
log refclocks"
run_test || test_fail
check_chronyd_exit || test_fail
@@ -29,6 +31,79 @@ Root delay : 0.001000000 seconds
.*
Update interval : 16\.. seconds
.*$" || test_fail
check_file_messages "20.* GPS.*[0-9] N " 997 1001 refclocks.log || test_fail
check_file_messages "20.* GPS.*- N " 61 63 refclocks.log || test_fail
rm -f tmp/refclocks.log
done
if check_config_h 'FEAT_PPS 1'; then
refclock_offset=0.35
refclock_jitter=0.05
client_conf="
refclock SHM 0 refid NMEA noselect
refclock PPS /dev/pps0 lock NMEA
logdir tmp
log refclocks"
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_sync || test_fail
check_chronyc_output "^Reference ID.*50505331 \(PPS1\)
Stratum.*: 1
.*
Root delay : 0\.000000001 seconds
.*$" || test_fail
check_file_messages "20.* PPS1.*[0-9] N " 620 740 refclocks.log || test_fail
check_file_messages "20.* PPS1.*- N " 60 63 refclocks.log || test_fail
rm -f tmp/refclocks.log
client_conf="
refclock SHM 0 noselect
refclock PPS /dev/pps0
local
logdir tmp
log refclocks"
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_sync || test_fail
check_chronyc_output "^Reference ID.*50505331 \(PPS1\)
Stratum.*: 10
.*
Root delay : 0\.000000001 seconds
.*$" || test_fail
check_file_messages "20.* PPS1.*[0-9] N " 997 1001 refclocks.log || test_fail
check_file_messages "20.* PPS1.*- N " 60 63 refclocks.log || test_fail
rm -f tmp/refclocks.log
min_sync_time=100
max_sync_time=220
chronyc_start=220
client_conf="
refclock SHM 0 refid NMEA offset 0.35 delay 0.1
refclock PPS /dev/pps0
logdir tmp
log refclocks"
run_test || test_fail
check_chronyd_exit || test_fail
check_source_selection || test_fail
check_sync || test_fail
check_chronyc_output "^Reference ID.*50505331 \(PPS1\)
Stratum.*: 1
.*
Root delay : 0\.000000001 seconds
.*$" || test_fail
check_file_messages "20.* PPS1.*[0-9] N " 800 940 refclocks.log || test_fail
check_file_messages "20.* PPS1.*- N " 50 63 refclocks.log || test_fail
rm -f tmp/refclocks.log
fi
test_pass

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common
test_start "makestep directive"

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common
@@ -101,7 +101,7 @@ limit=1
for chronyc_conf in \
"accheck 1.2.3.4" \
"add peer 10.0.0.0 minpoll 2 maxpoll 6" \
"add server 10.0.0.0 minpoll 6 maxpoll 10 iburst burst key 1 maxdelay 1e-3 maxdelayratio 10.0 maxdelaydevratio 10.0 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" \
"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 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" \
"add server node1.net1.clk" \
"allow 1.2.3.4" \
"allow 1.2" \
@@ -223,4 +223,23 @@ keygen 7 AES256"
7 AES256 HEX:................................................................\$" || test_fail
fi
# Pass every fourth request
base_delay=$(cat <<-EOF | tr -d '\n'
(+ 1e-4
(* -1
(equal 0.1 from 2)
(equal 0.1 (min (% (sum 1) 4) 1) 1)))
EOF
)
limit=15
chronyc_conf="sources"
run_test || test_fail
check_chronyc_output "^506 Cannot talk to daemon$" || test_fail
chronyc_conf="retries 3
sources"
run_test || test_fail
check_chronyc_output "^MS.*0ns$" || test_fail
test_pass

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
. ./test.common

Some files were not shown because too many files have changed in this diff Show More