Compare commits

...

1341 Commits

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Fixes: 3877734814 ("sources: add function to modify selection options")
2023-08-07 14:58:48 +02:00
Bryan Christianson
b5cf861cd7 contrib: replace tuxfamily with chrony-project
The chrony project has moved from tuxfamily.org to chrony-project.org.
Reflect these changes in the macOS startup files and documentation.
2023-08-01 12:11:27 +02:00
Miroslav Lichvar
25cc84d5e2 doc: update links to chrony website 2023-07-27 13:05:23 +02:00
Miroslav Lichvar
f74e4cf1fe doc: don't mention mailing lists in README
Current information about mailing lists is available on the project's
website.
2023-07-26 16:33:49 +02:00
Miroslav Lichvar
5f66722b66 update copyright years 2023-07-20 12:57:33 +02:00
Miroslav Lichvar
b31461af7a doc: add more questions to FAQ 2023-07-20 12:55:31 +02:00
Miroslav Lichvar
ae177f2742 doc: fix typo in FAQ 2023-07-20 12:47:11 +02:00
Miroslav Lichvar
1a736078df doc: refer to root distance in chronyc sources report 2023-07-20 12:46:49 +02:00
Miroslav Lichvar
9b46ea7255 test: make 132-logchange more reliable 2023-07-18 15:16:03 +02:00
Miroslav Lichvar
ff4e932f17 test: make 148-replacement more reliable 2023-07-18 15:15:45 +02:00
Miroslav Lichvar
68c35a0072 test: improve ntp_sources unit test 2023-07-18 14:53:54 +02:00
Miroslav Lichvar
b6c634298d ntp: handle negotiated NTS-KE server in refreshment
When refreshing a source, compare the newly resolved addresses with the
originally resolved address instead of the current address to avoid
unnecessary replacements when the address is changed due to the NTS-KE
server negotiation.
2023-07-18 14:53:54 +02:00
Miroslav Lichvar
010df12459 nts: fix log severity for loaded server keys 2023-07-18 14:53:54 +02:00
Miroslav Lichvar
22ef2fbb0e makefile: compile getdate.o with -fwrapv option
The getdate code (copied from gnulib before it was switched to GPLv3)
has multiple issues with signed integer overflows. Use the -fwrapv
compiler option for this object to at least make the operations defined.
2023-07-18 14:52:55 +02:00
Miroslav Lichvar
7a03206222 doc: update NEWS 2023-06-21 11:28:54 +02:00
Miroslav Lichvar
b86c50bb9f ntp: refresh IP addresses periodically
Refresh NTP sources specified by hostname periodically (every 2 weeks
by default) to avoid long-running instances using a server which is no
longer intended for service, even if it is still responding correctly
and would not be replaced as unreachable, and help redistributing load
in large pools like pool.ntp.org. Only one source is refreshed at a time
to not interrupt clock updates if there are multiple selectable servers.

The refresh directive configures the interval. A value of 0 disables
the periodic refreshment.

Suggested-by: Ask Bjørn Hansen <ask@develooper.com>
2023-06-21 11:28:42 +02:00
Miroslav Lichvar
36f9b24dfe doc: remove out-of-date statement in server description
chronyc refresh no longer forces replacement of sources.

Fixes: b2dac47c82 ("ntp: avoid unneccessary replacements on refresh command")
2023-06-20 15:28:07 +02:00
Miroslav Lichvar
e0b75b87bf ntp: remove resolving timeout in finalization
Don't assume NSR_Finalise() can be called only on exit when the
scheduler is finalized.
2023-06-20 13:03:53 +02:00
Miroslav Lichvar
6661a61486 sched: reset timer queue in finalization
Don't leave dangling pointers to timer queue entries when they are
freed in the scheduler finalization in case some code tried to remove
a timer later.

Fixes: 6ea1082a72 ("sched: free timer blocks on exit")
2023-06-19 16:15:07 +02:00
Miroslav Lichvar
bc76291750 examples: don't set ProcSubset=pid in systemd unit files
This option seems to break detection of the FIPS mode, which is needed
by gnutls.
2023-06-15 15:23:40 +02:00
Miroslav Lichvar
2aefadd129 sources: delay source replacement
Wait for four consecutive source selections giving a bad status
(falseticker, bad distance or jittery) before triggering the source
replacement. This should reduce the rate of unnecessary replacements
and shorten the time needed to find a solution when unreplaceable
falsetickers are preventing other sources from forming a majority due
to switching back and forth to unreachable servers.
2023-06-15 14:23:47 +02:00
Miroslav Lichvar
123cb497b9 sources: replace reachable sources in selection
Instead of waiting for the next update of reachability, trigger
replacement of falsetickers, jittery and distant sources as soon as
the selection status is updated in their SRC_SelectSource() call.
2023-06-15 14:23:47 +02:00
Miroslav Lichvar
0c38e4a6ca ntp: reset poll score
When the polling interval is reset (e.g. after replacement), don't
forget to reset also the score impacting the next poll adjustment.
2023-06-15 14:23:47 +02:00
Miroslav Lichvar
0db30fd0b1 main: wait for parent process to terminate
When starting the daemon, wait in the grandparent process for the parent
process to terminate before exiting to avoid systemd logging a warning
"Supervising process $PID which is not our child". Waiting for the pipe
to be closed by the kernel when the parent process exits is not
sufficient.

Reported-by: Jan Pazdziora <jpazdziora@redhat.com>
2023-06-12 16:40:53 +02:00
Miroslav Lichvar
b90d2c084f ntp: randomize replacement interval
Replacement attempts are globally rate limited to one per 7*2^8 seconds
to limit the rate of DNS requests for public servers like pool.ntp.org.
If multiple sources are repeatedly attempting replacement (at their
polling intervals), one source can be getting all attempts for periods
of time.

Use a randomly generated interval to randomize the order of source
replacements without changing the average rate.
2023-06-08 16:14:48 +02:00
Miroslav Lichvar
ab8da7ecb9 ntp: use monotonic time for replacement interval
Avoid errors in the measured interval due to clock steps.
2023-06-08 16:10:26 +02:00
Miroslav Lichvar
05809e937c ntp: add debug message for bad sources 2023-06-08 16:10:26 +02:00
Miroslav Lichvar
8265fe2e30 client: check for allocation errors in tab completition 2023-06-08 16:10:26 +02:00
Miroslav Lichvar
c11a052955 client: avoid passing uninitialized address to format_name()
The clang memory sanitizer seems to trigger on an uninitialized value
passed to format_name() when the source is a refclock, even though the
value is not used for anything. Pass 0 in this case to avoid the error.
2023-06-08 15:56:19 +02:00
Miroslav Lichvar
109970f687 memory: use free() instead of realloc() for size 0
valgrind 3.21.0 reports realloc() of 0 bytes as an error due to having
different behavior on different systems. The only place where this can
happen in chrony is the array, which doesn't care what value realloc()
returns.

Modify the realloc wrapper to call free() in this case to make valgrind
happy.
2023-06-08 14:31:52 +02:00
Miroslav Lichvar
ca10b9e072 sys_linux: allow writev and TIOCGWINSZ in seccomp filter
Allow more syscalls for musl.

Reported-by: jvoisin <julien.voisin@dustri.org>
2023-06-01 14:52:56 +02:00
Miroslav Lichvar
19da1d95a8 test: set root ownership of tmp directory in system tests
Allow the tests to be started under a non-zero GID.
2023-06-01 14:52:56 +02:00
Miroslav Lichvar
61da7d0913 test: modify order of scfilter levels in system tests
Start with positive levels to get the offending system calls in the
system or audit log.
2023-06-01 14:52:56 +02:00
Miroslav Lichvar
105f1f90c1 test: fix 010-nts test for AES-GCM-SIV support 2023-06-01 14:52:51 +02:00
Miroslav Lichvar
c9d791e02d nts: don't load zero-length keys with unsupported algorithm
Don't load keys and cookies from the client's dump file if it has an
unsupported algorithm and unparseable keys (matching the algorithm's
expected length of zero). They would fail all SIV operations and trigger
new NTS-KE session.
2023-05-29 16:08:13 +02:00
Miroslav Lichvar
de678ff780 doc: clarify limitation of refresh command 2023-05-25 10:28:56 +02:00
Miroslav Lichvar
e16bcca617 sys_linux: allow membarrier in seccomp filter
This system call is used by musl.

Reported-by: jvoisin <julien.voisin@dustri.org>
2023-05-25 10:28:56 +02:00
Miroslav Lichvar
b57d7040b3 configure: add option to disable AES-GCM-SIV support 2023-05-25 10:28:56 +02:00
Miroslav Lichvar
c80858f738 nts: remove superfluous semicolon 2023-05-25 10:28:56 +02:00
Miroslav Lichvar
81bf7cdcdc nts: initialize unused part of server key
Initialize the unused part of shorter server NTS keys (AES-128-GCM-SIV)
loaded from ntsdumpdir to avoid sending uninitialized data in requests
to the NTS-KE helper process.

Do that also for newly generated keys in case the memory will be
allocated dynamically.

Fixes: b1230efac3 ("nts: add support for encrypting cookies with AES-128-GCM-SIV")
2023-05-25 10:28:50 +02:00
Miroslav Lichvar
b8b3830dc4 ntp: randomize address selection on all source replacements
If the resolver orders addresses by IP family, there is more than one
address in the preferred IP family, and they are all reachable, but
not selectable (e.g. falsetickers in a small pool which cannot remove
them from DNS), chronyd is unable to switch to addresses in the other IP
family as it follows the resolver's order.

Enable randomization of the address selection for all source
replacements and not just replacement of (unreachable) tentative
sources. If the system doesn't have connectivity in the other family,
the addresses will be skipped and no change in behavior should be
observed.
2023-05-23 09:33:48 +02:00
Miroslav Lichvar
d4738e1259 ntp: set minimum polltarget
The polltarget value is used in a floating-point division in the
calculation of the poll adjustment. Set 1 as the minimum accepted
polltarget value to avoid working with infinite values.
2023-05-18 10:46:46 +02:00
Miroslav Lichvar
5ba42cee45 ntp: reset polling interval when replacing sources
Set the polling interval to minpoll when changing address of a source,
but only if it is reachable to avoid increasing load on server or
network in case that is the reason for the source being unreachable.

This shortens the time needed to replace a falseticker or
unsynchronized source with a selectable source.
2023-05-18 10:46:42 +02:00
Miroslav Lichvar
b2dac47c82 ntp: avoid unneccessary replacements on refresh command
When the refresh command is issued, instead of trying to replace all
NTP sources as if they were unreachable or falsetickers, keep using the
current address if it is still returned by the resolver for the name.
This avoids unnecessary loss of measurements and switching to
potentially unreachable addresses.
2023-05-15 17:23:48 +02:00
Miroslav Lichvar
6a6161dc0f doc: update NEWS 2023-05-10 14:28:42 +02:00
Miroslav Lichvar
a4eb5be8ea doc: update list of contributors in README 2023-05-10 10:46:57 +02:00
Rupesh Patel
3050e29b1d examples: improve chrony.nm-dispatcher.onoffline script 2023-05-10 10:46:57 +02:00
Miroslav Lichvar
fb1af6e55b test: add 146-offline test 2023-04-18 11:39:27 +02:00
Miroslav Lichvar
47a13ae88c md5: fix old-style function definitions
This fixes -Wdeprecated-non-prototype clang warnings.

Reported-by: Bryan Christianson <bryan@whatroute.net>
2023-04-17 11:40:18 +02:00
Miroslav Lichvar
a8496658a0 test: free memory in unit tests on exit 2023-04-13 16:22:50 +02:00
Miroslav Lichvar
6ea1082a72 sched: free timer blocks on exit
Save pointers to allocated timer blocks and free them on exit. This
fixes the long-standing annoying "possibly lost" leak reported by
valgrind.
2023-04-13 16:22:50 +02:00
Miroslav Lichvar
4f674539fd test: add 145-rtc test 2023-04-13 16:22:50 +02:00
Miroslav Lichvar
68d3fb4af8 doc: improve description of chronyd -Q option 2023-04-13 16:22:47 +02:00
Miroslav Lichvar
3c24f2c2ed test: add option to dump traffic to pcaps
This will be useful for debugging.
2023-04-03 14:36:30 +02:00
Miroslav Lichvar
0189dac7d8 ntp: save response when waiting for HW TX timestamp
Rework handling of late HW TX timestamps. Instead of suspending reading
from client-only sockets that have HW TX timestamping enabled, save the
whole response if it is valid and a HW TX timestamp was received for the
source before. When the timestamp is received, or the configurable
timeout is reached, process the saved response again, but skip the
authentication test as the NTS code allows only one response per
request. Only one valid response per source can be saved. If a second
valid response is received while waiting for the timestamp, process both
responses immediately in the order they were received.

The main advantage of this approach is that it works on all sockets, i.e.
even in the symmetric mode and with NTP-over-PTP, and the kernel does
not need to buffer invalid responses.
2023-03-30 15:44:19 +02:00
Miroslav Lichvar
4a11399c2e ntp: rework calculation of transmit timeout
Previously, in the calculation of the next transmission time
corresponding to the current polling interval, the reference point was
the current time in the client mode (i.e. the time when the response is
processed) and the last transmission time in the symmetric mode.

Rework the code to use the last transmission in both modes and make it
independent from the time when the response is processed to avoid extra
delays due to waiting for HW TX timestamps.
2023-03-30 15:28:08 +02:00
Miroslav Lichvar
cf98551ea1 client: avoid casting to long
Use the PRI*32 specifiers in printf formats to avoid casting received
values to unsigned long.
2023-03-30 15:17:52 +02:00
Miroslav Lichvar
5508b01bd8 cmdmon: switch serverstats to 64-bit integers
Update the serverstats response to use the new 64-bit integers.

Don't define a new value for the response as it already had an
incompatible change since the latest release (new fields added for
timestamp counters).
2023-03-30 15:17:52 +02:00
Miroslav Lichvar
907accec87 clientlog: extend serverstats counters to 64 bits
On a busy server the 32-bit counters included in the serverstats report
may overflow every few hours or days. Extend them to 64 bits.
2023-03-30 15:17:52 +02:00
Miroslav Lichvar
a511029cc2 cmdmon: define 64-bit integer
Add a structure for 64-bit integers without requiring 64-bit alignment
to be usable in CMD_Reply without struct packing.

Add utility functions for conversion to/from network order. Avoid using
be64toh() and htobe64() as they don't seem to be available on all
supported systems.
2023-03-30 15:17:50 +02:00
Miroslav Lichvar
0845df7684 cmdmon: add timestamp counters to serverstats report
Add the new RX/TX daemon/kernel/hardware timestamp counters to the
serverstats report.
2023-03-22 10:47:22 +01:00
Miroslav Lichvar
2f961ab36a clientlog: count RX and TX timestamps for each source
Count served timestamps in all combinations of RX/TX and
daemon/kernel/hardware. Repurpose CLG_LogAuthNtpRequest() to update all
NTP-specific stats in one call per accepted request and response.
2023-03-22 09:42:35 +01:00
Miroslav Lichvar
a0cf7f7f12 clientlog: save source of transmit timestamps
Add the timestamp source to the data kept for clients using interleaved
mode to allow extending server statistics.
2023-03-22 09:42:06 +01:00
Miroslav Lichvar
a5f1a113f0 ntp: remove unnecessary check for NULL local timestamp
After 5f4cbaab7e ("ntp: optimize detection of clients using
interleaved mode") the local TX timestamp is saved for all requests
indicating interleaved mode even when no previous RX timestamp is found.
2023-03-22 09:13:53 +01:00
Miroslav Lichvar
5160f14fdc ntp: add maximum PHC poll interval
Specify maxpoll for HW timestamping (default minpoll + 1) to track the
PHC well even when there is little NTP traffic on the interface. After
each PHC reading schedule a timeout according to the maxpoll. Polling
between minpoll and maxpoll is still triggered by HW timestamps.

Wait for the first HW timestamp before adding the timeout to avoid
polling PHCs on interfaces that are enabled in the configuration but
not used for NTP. Add a new scheduling class to separate polling of
different PHCs to avoid too long intervals between processing I/O
events.
2023-03-22 09:13:53 +01:00
Miroslav Lichvar
b0a2ad2535 doc: add missing word in serverstats description 2023-03-22 09:13:53 +01:00
Miroslav Lichvar
ecdde75f8f doc: replace offensive words 2023-03-22 09:13:47 +01:00
Miroslav Lichvar
2d80be9541 doc: mention NTP port number in FAQ 2023-03-22 08:58:20 +01:00
Miroslav Lichvar
ab776ed9d8 ntp: make socket resume timeout configurable
In some cases even the new timeout of 1 millisecond is not sufficient to
get all HW TX timestamps. Add a new directive to allow users to
specify longer timeouts.
2023-03-09 16:13:27 +01:00
Miroslav Lichvar
ccebec3eb6 ntp: increase socket resume timeout to 1 millisecond
This seems to work significantly better on some hardware and is still
shorter than burst interval at the minimum configurable poll.
2023-03-09 16:05:38 +01:00
Miroslav Lichvar
3ea3e0efd7 ntp: add support for multiple suspended sockets
With some hardware it takes milliseconds to get the HW TX timestamp.

Rework the code to handle multiple suspended client-only sockets at the
same time in order to allow longer timeouts, which may overlap for
different sources. Instead of waiting for the first read event simply
suspend the socket and create timeout when the HW TX timestamp is
requested.
2023-03-09 15:49:43 +01:00
Dan Drown
c3e4e3e47a ntp: increment sequence id in PTP messages 2023-03-07 17:00:08 +01:00
Miroslav Lichvar
e949e1d991 test: update description of 106-refclock 2023-03-02 15:34:03 +01:00
Miroslav Lichvar
c8649ccb7e refclock_phc: support multiple extpps refclocks on one PHC
The Linux kernel (as of 6.2) has a shared queue of external timestamps
for all descriptors of the same PHC. If multiple refclocks using the
same PHC and the same or different channels were specified, some
refclocks didn't receive any or most of their timestamps, depending on
the rate and timing of the events (with the previous commit avoiding
blocking reads).

Track extpps-enabled refclocks in an array. Add PHC index to the PHC
instance. When a timestamp is read from the descriptor, provide it to
all refclocks that have the same PHC index and a channel matching the
event.

Make sure the timestamp is different from the previous one in case the
kernel will be improved to duplicate the timestamps for different
descriptors.

Reported-by: Matt Corallo <ntp-lists@mattcorallo.com>
2023-03-02 15:33:59 +01:00
Miroslav Lichvar
39ff7ceeca sys_linux: avoid blocking in reading of external PHC timestamp
The kernel has a common queue for all readers of a PHC device. With
multiple PHC refclocks using the same device some reads blocked. PHC
devices don't seem to support non-blocking reads. Use poll() to check if
a timestamp is available before reading from the descriptor.
2023-03-02 15:13:18 +01:00
Miroslav Lichvar
06945d927b test: add array unit test 2023-03-02 10:41:28 +01:00
Miroslav Lichvar
caf82b1a45 array: add function for removing elements 2023-03-02 10:41:28 +01:00
Miroslav Lichvar
f99b2f633b ntp: count missing samples when waiting for NTS-KE
Count missing samples for the median filter when
NAU_PrepareRequestAuth() is failing.

Fixes: 4234732b08 ("ntp: rework filter option to count missing samples")
2023-02-28 10:02:40 +01:00
Miroslav Lichvar
6270a3eb7c ntp: don't adjust poll interval when waiting for NTS-KE
Don't adjust the NTP polling interval and decrement the burst count when
NAU_PrepareRequestAuth() fails (e.g. no NTS-KE response received yet,
network being down, or the server refusing connections), same as if an
NTP request could not be sent. Rely on the rate limiting implemented in
the NTS code.
2023-02-27 15:36:30 +01:00
Miroslav Lichvar
1daa40a2f7 nts: use shorter NTS-KE retry interval when network is down
When chronyd configured with an NTS source not specified as offline and
resolvable without network was started before the network was up, it was
using an unnecessarily long NTS-KE retry interval, same as if the server
was refusing the connections.

When the network is down, the connect() call made from NKC_Start() on
the non-blocking TCP socket should fail with a different error than
EINPROGRESS and cause NKC_Start() to return with failure. Add a constant
2-second retry interval (matching default iburst) for this case.
2023-02-27 11:43:22 +01:00
Miroslav Lichvar
a1406eded3 nts: destroy NTS-KE client right after failed start
When NKC_Start() fails (e.g. due to unreachable network), don't wait for
the next poll to destroy the client and another poll to create and start
it again.
2023-02-23 15:01:45 +01:00
Miroslav Lichvar
1eb8994c00 client: add -e option to indicate end of response
In a non-tty session with chronyc it is not possible to detect the
end of the response without relying on timeouts, or separate responses
to a repeated command if using the -c option.

Add -e option to end each response with a line containing a single dot.
2023-02-02 17:06:46 +01:00
Miroslav Lichvar
221e5fb501 doc: improve description of refclock filter option 2023-02-02 15:05:05 +01:00
Miroslav Lichvar
ecfbde9872 doc: describe minimum useful ntsrefresh 2023-02-02 14:47:31 +01:00
Miroslav Lichvar
dec07aa844 sourcestats: don't fudge refclock LastRx in sources report
The sample time used in calculation of the last_meas_ago (LastRx) value
in the sources report is aligned to the second to minimize the leak
of the NTP receive timestamp, which could be useful in some attacks.

There is no need to do that with reference clocks, which are often used
with very short polling intervals and an extra second in the LastRx
value can be misinterpreted as a missed sample.
2023-02-02 11:26:04 +01:00
Miroslav Lichvar
5b3d4dfe76 sources: warn about detected falsetickers
Log a warning message for each detected falseticker, but only once
between changes in the selection of the best source. Don't print all
sources when no majority is reached as that case has its own warning
message.
2023-01-26 17:03:35 +01:00
Miroslav Lichvar
dc0f0cd134 sources: enable no majority message before first selection
Add a separate flag to allow the "no majority" message to be logged even
before the first successful selection.
2023-01-26 16:15:47 +01:00
Miroslav Lichvar
bd37efa52e sources: increase log level of no majority message
When the selection fails due to no majority, log the message as a
warning to get the admin's attention.
2023-01-26 16:05:57 +01:00
Miroslav Lichvar
c71185a0e5 doc: add missing description of selection log field 2023-01-26 12:04:28 +01:00
Miroslav Lichvar
f149b7b758 examples: add AES keys to chrony.keys.example 2023-01-25 15:59:45 +01:00
Miroslav Lichvar
883b0dde94 conf: warn if not having read-only access to keys
After dropping root privileges, log a warning message if chronyd
doesn't have read access or has (unnecessary) write access to the
files containing symmetric and server NTS keys.
2023-01-25 14:44:59 +01:00
Miroslav Lichvar
9cba9c8585 keys+nts: warn if loading world-readable/writable key
Log a warning message if the file specified by the keyfile or
ntsserverkey directive is world-readable or writable, which is likely
an insecure misconfiguration. There is no check of directories
containing the file.
2023-01-19 16:39:40 +01:00
Miroslav Lichvar
88e711ad9a refclock: fix preprocessor conditional
Split the new SOCK conditional using __GLIBC_PREREQ macro (which has
arguments) to fix compilation when it is not defined.

Fix also debug message using sizeof(time_t) in case it's enabled on
64-bit systems.

Reported-by: Bryan Christianson <bryan@whatroute.net>
Fixes: badaa83c31 ("refclock: convert mismatched timeval in SOCK messages")
2023-01-19 11:51:41 +01:00
Miroslav Lichvar
badaa83c31 refclock: convert mismatched timeval in SOCK messages
On 32-bit glibc-based (>=2.34) systems, allow the SOCK client to send
messages with timevals using the other time_t size than chrony. If the
length of the received message corresponds to the other size, convert
the timeval and move the rest of the message before its processing.

This is needed for compatibility with the current development version of
gpsd, which forces 64-bit time_t on these systems, while chrony needs to
be compiled with the same time_t as gnutls.
2023-01-18 16:39:25 +01:00
Miroslav Lichvar
bbeec7361c doc: deprecate SHM refclocks in favor of SOCK
The NTP SHM refclock protocol has the following properties:

- the memory segments have a predictable key (first segment 0x4e545030)
- it's expected to work in any order of starting chronyd and the program
  providing samples to chronyd, i.e. both the consumer and producer need
  to be able to create the segment
- the producer and consumer generally don't know under which user is
  the other side running (e.g. gpsd can create the segment as root and
  also as nobody after it drops root privileges)
- there is no authentication of data provided via SHM
- there is no way to restart the protocol

This makes it difficult for chronyd to ensure it is receiving
measurements from the process that the admin expects it to and not some
other process that managed to create the segment before it was started.
It's up to the admin to configure the system so that chronyd or the
producer is started before untrusted applications or users can create
the segment, or at least verify at some point later that the segment was
created with the expected owner and permissions.

There doesn't seem to be a backward-compatible fix of the protocol. Even
if one side could detect the segment had a wrong owner or permissions,
it wouldn't be able to tell the other side to reattach after recreating
the segment with the expected owner and permissions, if it still had the
permissions to do that.

The protocol would need to specify which side is responsible for
creating the segment and the start order would need to strictly follow
that.

As gpsd (likely the most common refclock source for chronyd) now
supports in the latest version SOCK even for message-based timing,
update the man page and FAQ to deprecate SHM in favor of SOCK.
2023-01-12 16:23:15 +01:00
Miroslav Lichvar
6fba5a4a7f examples: add chronyd-restricted.service
This is a more restricted version of the chronyd service intended for
minimal NTP/NTS client configurations. The daemon is started without
root privileges and is allowed to write only to its own runtime, state,
and log directories. It cannot bind to privileged ports in order to
operate as an NTP server, or provide monitoring access over IPv4/IPv6.
It cannot use reference clocks, HW timestamping, RTC tracking, and other
features.
2023-01-11 15:53:24 +01:00
Miroslav Lichvar
26889a8cb7 cmdmon+client: add selectopts command
This command uses the new source function to modify configured selection
options of an NTP source or reference clock.
2022-12-14 17:04:49 +01:00
Miroslav Lichvar
cd278d1826 cmdmon+client: split out conversion of selection options
This will be shared with new command modifying the selection options.
2022-12-14 17:04:49 +01:00
Miroslav Lichvar
3877734814 sources: add function to modify selection options
Add a function to add new selection options or remove existing options
specified in the configuration for both NTP sources and reference
clocks.

Provide a pair of IP address and reference ID to identify the source
depending on the type. Find the source directly in the array of sources
instead of going through the NSR hashtable for NTP sources to not
complicate it unnecessarily.
2022-12-14 17:04:49 +01:00
Miroslav Lichvar
19f2ab9e09 sources: add assertion for instance index 2022-12-14 17:04:46 +01:00
Miroslav Lichvar
3260dc82fe cmdparse: add functions for parsing refclock refid and select options
This will be used in new chronyc command working on refclocks.
2022-12-14 17:04:23 +01:00
Miroslav Lichvar
1a98c5ffa9 ntp: update comment about minimum request spacing 2022-12-05 16:44:38 +01:00
Miroslav Lichvar
8247b8525f log more changes made by chronyc commands
Log important changes from chronyc for auditing purposes.

Add log messages for:
- loaded symmetric keys and server NTS keys (logged also on start)
- modified maxupdateskew and makestep
- enabled/disabled local reference mode (logged also on start)
- reset time smoothing (logged also on clock steps)
- reset sources
2022-12-01 16:58:23 +01:00
Mike Ryan
8901293be8 ntp: set DSCP for IPv6
Chrony's dscp setting currently applies to IPv4 only. This patch sets
the necessary option for IPv6 as well.
2022-11-16 17:15:11 +01:00
Miroslav Lichvar
e789b0817f ntp+cmdmon: log allow/deny commands
Log added NTP and command access restrictions, using INFO severity if
from a chronyc command, DEBUG otherwise (i.e. from the config).
2022-11-16 17:15:07 +01:00
Miroslav Lichvar
d0fd04c0a2 util: add function for printing access subnets 2022-11-16 17:00:45 +01:00
Miroslav Lichvar
7122321249 ntp: log added and removed sources
Log a message when a single NTP source or pool of sources is added or
removed. Use the INFO severity if it's a result of a chronyc command or
(re)load of sourcefiles (which are assumed to change over time), and
DEBUG for other contexts, e.g. sources loaded from the config, sources
removed when pruning pools after reaching maxsources, and other parts of
normal operation.
2022-11-16 17:00:39 +01:00
Miroslav Lichvar
b328c8c348 logging: support context-specific severity
Allow messages to have severity set to INFO or DEBUG depending on the
context in which they are made to allow logging important changes made
from chronyc or sourcefile, but not spam the system log if those changes
are normally expected (e.g. specified in the config).
2022-11-16 16:57:49 +01:00
Holger Hoffstätte
7b97668319 getdate: fix various warnings which will be errors with clang-16
These were found by Gentoo's QA while rebuilding the world with
clang-16: https://bugs.gentoo.org/880519

Signed-off-by: Holger Hoffstätte <holger@applied-asynchrony.com>
2022-11-09 09:17:14 +01:00
Miroslav Lichvar
6f5df7e4a4 nts: warn if server started without ntsdumpdir
If an NTS server is configured without ntsdumpdir, keys will not be
saved and reloaded after restart, which will cause existing cookies
to be invalidated and can cause a short-term denial of service if
the server has so many clients that it cannot handle them all
making an NTS-KE session within one polling interval.

Log a warning message if a server key+certificate is specified without
ntsdumpdir.
2022-10-24 16:39:29 +02:00
Miroslav Lichvar
5a39074e01 nts: fix number of extension fields after failed encryption
If the authenticator SIV encryption fails (e.g. due to wrong nonce
length), decrement the number of extension fields to keep the packet
info consistent.
2022-10-19 15:50:39 +02:00
Miroslav Lichvar
c8e57f4350 nts: change ntskeys format to support different algorithms
Specify the AEAD ID for each key saved in the ntskeys file instead of
one ID for all keys. Keep support for loading files in the old format.

This will allow servers to save their keys after upgrading to a new
version with AES-128-GCM-SIV support before the loaded AES-SIV-CMAC-256
keys are rotated out.

If an unsupported key is found, don't load any keys. Also, change the
severity of the error message from debug to error.
2022-10-19 15:50:39 +02:00
Miroslav Lichvar
b1230efac3 nts: add support for encrypting cookies with AES-128-GCM-SIV
If AES-128-GCM-SIV is available on the server, use it for encryption of
cookies. This makes them shorter by 4 bytes due to shorter nonce and it
might also improve the server performance.

After server upgrade and restart with ntsdumpdir, the switch will happen
on the second rotation of the server key. Clients should accept shorter
cookies without restarting NTS-KE. The first response will have extra
padding in the authenticator field to make the length symmetric.
2022-10-19 15:50:39 +02:00
Miroslav Lichvar
4e1ce88981 nts: make server key access more readable
Get a pointer to the server key instead of repeated indexing.
2022-10-19 15:50:39 +02:00
Miroslav Lichvar
790a336eb2 nts: add server support for authentication with AES-128-GCM-SIV
Keep a server SIV instance for each available algorithm.

Select AES-128-GCM-SIV if requested by NTS-KE client as the first
supported algorithm.

Instead of encoding the AEAD ID in the cookie, select the algorithm
according to the length of decrypted keys. (This can work as a long as
all supported algorithms use keys with different lengths.)
2022-10-19 15:50:39 +02:00
Miroslav Lichvar
cc706b50b9 nts: add client support for authentication with AES-128-GCM-SIV
If AES-128-GCM-SIV is available on the client, add it to the requested
algorithms in NTS-KE as the first (preferred) entry.

If supported on the server, it will make the cookies shorter, which
will get the length of NTP messages containing only one cookie below
200 octets. This should make NTS more reliable in networks where longer
NTP packets are filtered as a mitigation against amplification attacks
exploiting the ntpd mode 6/7 protocol.
2022-10-19 15:50:39 +02:00
Miroslav Lichvar
73042494bd nts: add support for NTP authenticator field using AES-GCM-SIV
Add support for SIV algorithms which have maximum nonce length shorter
than 16 bytes.
2022-10-19 15:50:39 +02:00
Miroslav Lichvar
ec89739d50 nts: make sure encrypted S2C and C2S keys have equal length
Don't allow a cookie to contain keys with different lengths to not break
the assumption made in decoding, if there will ever be a case where this
could be requested.
2022-10-19 15:50:39 +02:00
Miroslav Lichvar
4baf999cc3 nts: don't connect to server if missing AES-SIV-CMAC-256
Avoid wasting server resources if the client doesn't support
AES-SIV-CMAC-256 (the only algorithm required on servers).
2022-10-19 15:50:39 +02:00
Miroslav Lichvar
9afd19c29b nts: use signed lengths in NNA_DecryptAuthEF()
Make the types consistent with the rest of the file.
2022-10-19 15:50:39 +02:00
Miroslav Lichvar
5dd173c050 siv: add functions to return min and max nonce length
While AES-SIV-CMAC allows nonces of any length, AES-GCM-SIV requires
exactly 12 bytes, which is less than the unpadded minimum length of 16
used in the NTS authenticator field. These functions will be needed to
support both ciphers in the NTS code.
2022-10-19 15:50:39 +02:00
Miroslav Lichvar
5caf0ad187 siv: add support for AES-128-GCM-SIV in Nettle
This is a newer nonce misuse-resistant cipher specified in RFC 8452,
which is now supported in the development code of the Nettle library.

The advantages over AES-SIV-CMAC-256 are shorter keys and better
performance.
2022-10-19 15:50:31 +02:00
Miroslav Lichvar
17d2291a84 doc: improve ntsrotate description 2022-10-19 15:33:04 +02:00
Miroslav Lichvar
a6179261a7 doc: fix wrong name of authselectmode directive 2022-10-17 15:24:24 +02:00
Miroslav Lichvar
098e0c43fc test: add float-cast-overflow to 003-sanitizers test 2022-09-20 10:56:28 +02:00
Miroslav Lichvar
7b197953e8 update copyright years 2022-08-29 15:04:33 +02:00
Miroslav Lichvar
9dcace0fc4 doc: improve description of server directive 2022-08-29 15:03:59 +02:00
Miroslav Lichvar
a07ac38331 doc: improve description of system time in tracking report 2022-08-29 12:39:22 +02:00
Miroslav Lichvar
166e43b13e cmdmon: add good responses to ntpdata report 2022-08-18 11:59:40 +02:00
Miroslav Lichvar
b84d6759f9 ntp: initialize remote address in ntpdata report
Don't wait for the first response with setting the address.
2022-08-17 16:14:38 +02:00
Miroslav Lichvar
f323c814af doc: update NEWS 2022-08-11 10:32:58 +02:00
Miroslav Lichvar
19b47dcbc9 doc: mention maxdelayquant in FAQ 2022-08-10 15:32:54 +02:00
Miroslav Lichvar
5edeadcbd9 test: extend 106-refclock test 2022-08-09 16:53:12 +02:00
Miroslav Lichvar
d91ae2094f configure: disable arc4random on Linux
In glibc 2.36 was added the arc4random family of functions. However,
unlike on other supported systems, it is not a user-space PRNG
implementation. It just wraps the getrandom() system call with no
buffering, which causes a performance loss on NTP servers due to
the function being called twice for each response to add randomness
to the RX and TX timestamp below the clock precision.

Don't check for arc4random on Linux to keep using the buffered
getrandom().
2022-08-03 15:23:38 +02:00
Miroslav Lichvar
30a5845098 configure: avoid -Wnonnull warnings
Replace NULL in test code of functions which have (at least in glibc) or
could have arguments marked as nonnull to avoid the -Wnonnull warnings,
which breaks the detection with the -Werror option.
2022-08-03 14:53:35 +02:00
Miroslav Lichvar
0f367efac5 doc: suggest self-signed certificates for NTS in FAQ 2022-08-03 13:58:28 +02:00
Miroslav Lichvar
24c011d4a6 test: catch definite leaks with valgrind 2022-08-02 15:09:47 +02:00
Miroslav Lichvar
0c2cdd2fb1 test: fix ntp_core unit test to disable source selection
If the randomly generated timestamps are close to the current time, the
source can be selected for synchronization, which causes a crash when
logging the source name due to uninitialized ntp_sources.

Specify the source with the noselect option to prevent selection.
2022-08-02 14:44:05 +02:00
Miroslav Lichvar
cd1a666e1b test: fix sources unit test to call SRC_ReportSource() correctly
Call the function with current time instead of latest sample of the
first source to avoid undefined conversion of negative double to long
int.

Fixes: 07600cbd71 ("test: extend sources unit test")
2022-08-02 14:44:05 +02:00
Miroslav Lichvar
070b4f69d0 ntp: add maxdelayquant option
Add a new test for maximum delay using a long-term estimate of a
p-quantile of the peer delay. If enabled, it replaces the
maxdelaydevratio test. It's main advantage is that it is not sensitive
to outliers corrupting the minimum delay.

As it can take a large number of samples for the estimate to reach the
expected value and adapt to a new value after a network change, the
option is recommended only for local networks with very short polling
intervals.
2022-07-21 16:05:48 +02:00
Miroslav Lichvar
851c823b42 doc: improve description of maxdelay* options 2022-07-21 15:33:35 +02:00
Miroslav Lichvar
df80274644 quantiles: add function to get minimum k 2022-07-21 15:33:35 +02:00
Miroslav Lichvar
bb2d68ddf9 test: extend 101-poll and 127-filter tests 2022-07-21 15:33:35 +02:00
Miroslav Lichvar
685d8f725b ntp: change minimum allowed poll to -7
Change the minimum poll allowed in configuration from -6 to -7. This
matches some PTP profiles using 128 sync messages per second.
2022-07-21 15:33:35 +02:00
Miroslav Lichvar
4234732b08 ntp: rework filter option to count missing samples
Instead of waiting for the sample filter to accumulate the specified
number of samples and then deciding if the result is acceptable, count
missing samples and get the result after the specified number of polls.

This should work better when samples are dropped at a high rate. The
source and clock update interval will be stable as long as at least
one sample can be collected.
2022-07-21 15:33:08 +02:00
Miroslav Lichvar
a16094adfb samplefilt: add debug message for selected samples 2022-07-21 14:17:22 +02:00
Miroslav Lichvar
a4349b13df samplefilt: add function to get maximum number of samples 2022-07-21 14:17:22 +02:00
Miroslav Lichvar
3556dadea1 ntp: enable sub-second poll sooner with filter option
When the minimum round-trip time is checked to enable a sub-second
polling interval, consider also the last sample in the filter to avoid
waiting for the first sample to be accumulated in sourcestats.
2022-07-21 14:17:22 +02:00
Miroslav Lichvar
220e6d1907 ntp: fix initial poll to follow non-LAN minimum
If a sub-second polling interval is configured, initialize the local
poll to 0 to avoid a shorter interval between the first and second
request in case no response to the first request is received (in time).
2022-07-21 14:17:22 +02:00
Miroslav Lichvar
a738037705 client: check for stdout errors
Return with an error code from chronyc if the command is expected to
print some data and fflush() or ferror() indicates an error. This should
make it easier for scripts to detect missing data when redirected to a
file.
2022-07-21 14:17:11 +02:00
Yury Vostrikov
7daf34675a refclock: remove unused struct MedianFilter
Filtering was moved to a separate source file in commit
c498c21fad ("refclock: split off median filter). It looks like
MedianFilter struct somehow survived the split. Remove it to reduce
confusion.
2022-07-11 10:20:44 +02:00
Miroslav Lichvar
de598c2310 main: add log message for timeout reached with -t option
This should make it more clear why chronyd exits if -q/-Q does not
finish before the timeout is reached.
2022-06-30 14:46:18 +02:00
Miroslav Lichvar
91cc4dbb12 doc: improve description of test A in measurements log 2022-06-30 10:20:49 +02:00
Miroslav Lichvar
0ae6f2485b ntp: don't use first response in interleaved mode
With the first interleaved response coming after a basic response the
client is forced to select the four timestamps covering most of the last
polling interval, which makes measured delay very sensitive to the
frequency offset between server and client. To avoid corrupting the
minimum delay held in sourcestats (which can cause testC failures),
reject the first interleaved response in the client/server mode as
failing the test A.

This does not change anything for the symmetric mode, where both sets of
the four timestamps generally cover a significant part of the polling
interval.
2022-06-30 10:18:48 +02:00
Miroslav Lichvar
52ec694d2b test: fix server interleaved mode in ntp_core unit test 2022-06-28 15:43:25 +02:00
Miroslav Lichvar
e2e07af8a4 doc: improve and add more questions to FAQ 2022-06-23 14:29:21 +02:00
Miroslav Lichvar
2ed88c31c7 sys_generic: damp slew oscillation due to delayed stop
If the computer is overloaded so much that chronyd cannot stop a slew
within one second of the scheduled end and the actual duration is more
than doubled (2 seconds with the minimum duration of 1 second), the
overshoot will be larger than the intended correction. If these
conditions persist, the oscillation will grow up to the maximum offset
allowed by maxslewrate and the delay in stopping.

Monitor the excess duration as an exponentially decaying maximum value
and don't allow any slews shorter than 5 times the value to damp the
oscillation. Ignore delays longer than 100 seconds, assuming they have a
different cause (e.g. the system was suspended and resumed) and are
already handled in the scheduler by triggering cancellation of the
ongoing slew.

This should also make it safer to shorten the minimum duration if
needed.

Reported-by: Daniel Franke <dff@amazon.com>
2022-06-15 17:42:49 +02:00
Miroslav Lichvar
af8e4a5115 sys_generic: rename slew constants 2022-06-14 16:02:06 +02:00
Miroslav Lichvar
f503a9a490 test: improve 133-hwtimestamp test 2022-06-09 16:01:22 +02:00
Miroslav Lichvar
9c64fbb9c4 hwclock: improve filtering of readings
Estimate the 1st and 2nd 10-quantile of the reading delay and accept
only readings between them unless the error of the offset predicted from
previous samples is larger than the minimum reading error. With the 25
PHC readings per ioctl it should combine about 2-3 readings.

This should improve hwclock tracking and synchronization stability when
a PHC reading delay occasionally falls below the normal expected
minimum, or all readings in the batch are delayed significantly (e.g.
due to high PCIe load).
2022-06-09 16:01:22 +02:00
Miroslav Lichvar
b428f901c7 quantiles: add support for quantile estimation
Add estimation of quantiles using the Frugal-2U streaming algorithm
(https://arxiv.org/pdf/1407.1121v1.pdf). It does not need to save
previous samples and adapts to changes in the distribution.

Allow multiple estimates of the same quantile and select the median for
better stability.
2022-06-09 16:01:19 +02:00
Miroslav Lichvar
09b7f77f9a hwclock: refactor processing of PHC readings
Move processing of PHC readings from sys_linux to hwclock, where
statistics can be collected and filtering improved.

In the PHC refclock driver accumulate the samples even if not in the
external timestamping mode to update the context which will be needed
for improved filtering.
2022-06-09 12:04:20 +02:00
Miroslav Lichvar
c23c0b8484 ntp: convert HW timestamp even if PHC reading fails
Reading of PHC can fail occasionally on some hardware. If that happens,
don't abort the conversion of the timestamp that triggered the reading.
2022-06-08 15:30:05 +02:00
Miroslav Lichvar
d530055917 sys_linux: increase number of PHC readings
Increase the number of requested readings from 10 to 25 - the maximum
accepted by the PTP_SYS_OFFSET* ioctls. This should improve stability of
HW clock tracking and PHC refclock.
2022-06-08 14:29:35 +02:00
Miroslav Lichvar
f41d09e19f doc: improve hwtimestamp description
Latest versions of ethtool print only the shorter lower-case names of
capabilities and filters. Explain that chronyd doesn't synchronize the
PHC and refer to the new vclock feature of the kernel, which should be
used by applications that need a synchronized PHC (e.g. ptp4l and
phc2sys) in order to not interfere with chronyd.
2022-05-19 10:50:10 +02:00
Miroslav Lichvar
46030d9d3e sources: add selection log
Add an option to enable selection log, capturing some data from the
selectdata report.
2022-05-19 08:23:05 +02:00
Miroslav Lichvar
02ccd3a3c7 sourcestats: don't load samples from future
When loading a dumped file, make sure there are no sample times in
future relative to the current system time (e.g. after reboot with
missing RTC).
2022-05-18 16:38:41 +02:00
Miroslav Lichvar
9cc609c4b0 local: cancel remaining correction after external step
Instead of the generic clock driver silently zeroing the remaining
offset after detecting an external step, cancel it properly with the
slew handlers in order to correct timestamps that are not reset in
handling of the unknown step (e.g. the NTP local TX).
2022-05-16 16:28:36 +02:00
Miroslav Lichvar
a0a496dcb4 refclock: set minimum maxlockage in local mode
Use 3 as the minimum maxlockage in the local mode to avoid disruptions
due to losing the lock when a single sample is missed, e.g. when the PPS
driver polling interval is slightly longer than the pulse interval and a
pulse is skipped.
2022-05-11 14:28:58 +02:00
Miroslav Lichvar
8d08486edf refclock: restart local mode after losing lock
A refclock in the local mode is locked to itself. When the maxlockage
check failed after missing some samples, it failed permanently and the
refclock was not able to accumulate any new samples.

When the check fails, drop all samples and reset the source to start
from scratch.

Reported-by: Dan Drown <dan-ntp@drown.org>
2022-05-11 14:27:18 +02:00
Miroslav Lichvar
a3b376cf0a refclock: fix invalid warning in local mode
A refclock in the local mode is locked to itself by design.

Reported-by: Dan Drown <dan-ntp@drown.org>
2022-05-11 14:22:41 +02:00
Miroslav Lichvar
e66f1df89d samplefilt: drop last sample in SPF_DropSamples()
When SPF_DropSamples() is called, don't keep the last sample to be
retrieved by SPF_GetLastSample(). It should be kept only after
filtering.
2022-05-11 14:21:09 +02:00
Miroslav Lichvar
35220aac9d siv: set key directly with gnutls
A new function is provided by the latest gnutls (should be in 3.7.5) to
set the key of an AEAD cipher. If available, use it to avoid destroying
and creating a new SIV instance with each key change.

This improves the server NTS-NTP performance if using gnutls for SIV.
2022-05-11 12:22:33 +02:00
Miroslav Lichvar
5b04f3ca90 doc: improve description of chronyc -h option 2022-05-05 14:34:15 +02:00
Miroslav Lichvar
beb1c36136 doc: improve maxchange description 2022-05-05 14:34:08 +02:00
Miroslav Lichvar
da3495c472 nts: don't exit if initialization of priority cache fails
Initialization of the gnutls priority cache can fail depending on the
system crypto policy (e.g. disabled TLS1.3). Log an error mentioning
TLS, but continue to run without the server/client credentials.
2022-05-05 10:27:48 +02:00
Miroslav Lichvar
356771c0c3 client: rework command catenation
Use snprintf() instead of strcat() and don't try to parse commands
longer than 2048 characters to make it consistent with the chrony.conf
parser, avoid memory allocation, and not rely on the system ARG_MAX to
keep the length sane.
2022-05-04 14:17:32 +02:00
Miroslav Lichvar
fca8966ada examples: replace grep command in NM dispatcher script
Some grep implementations detect binary data and return success without
matching whole line. This might be an issue for the DHCPv6 NTP FQDN
check. The GNU grep in the C locale seems to check only for the NUL
character, which cannot be passed in an environment variable, but other
implementations might behave differently and there doesn't seem to be a
portable way to force matching the whole line.

Instead of the grep command, check for invalid characters by comparing
the length of the input passed through "tr -d -c".
2022-03-23 15:36:17 +01:00
Miroslav Lichvar
25f80a1a9d doc: include gnutls in libraries providing SECHASH feature 2022-03-16 14:54:12 +01:00
Miroslav Lichvar
1219f99935 ntp: keep original source IP address
When an added source is specified by IP address, save the original
string instead of formatting a new string from the parsed address, which
can be different (e.g. compressed vs expanded IPv6 address).

This fixes the chronyc sourcename command and -N option to print the IP
address exactly as it was specified in the configuration file or chronyc
add command.
2022-03-10 09:54:31 +01:00
Miroslav Lichvar
33a1fe7a9c ntp: split out conf_id allocation 2022-03-10 09:53:29 +01:00
Miroslav Lichvar
eed0a0de56 test: update 007-cmdmon system test for recent changes
The new unsynchronised source state is now reported in selectdata before
the first measurement.

Fixes: c29f8888c767 ("sources: handle unsynchronized sources in selection")
2022-03-07 16:00:20 +01:00
Miroslav Lichvar
07600cbd71 test: extend sources unit test 2022-03-02 12:17:02 +01:00
Miroslav Lichvar
f2e341b5ed sources: improve debug messages
Print source status as char and print the name instead of index in
combining.
2022-03-02 12:11:24 +01:00
Miroslav Lichvar
55717c1ccd refclock: trim offset in local mode
With the local option, trim offset larger than 1 second to not lose
precision after large steps of the clock.
2022-02-24 11:40:26 +01:00
Miroslav Lichvar
d5e645eb38 samplefilt: add function to correct accumulated offsets
Analogously to SST_CorrectOffset(), add SPF_CorrectOffset() to correct
the offsets accumulated in the filter.
2022-02-24 11:40:01 +01:00
Miroslav Lichvar
3196630fb9 sys_linux: don't require configurable pin for external PPS
Some PHCs that have a PPS input don't have configurable pins (their
function is hardcoded). Accept a negative pin index to skip the pin
configuration before requesting external timestamping.
2022-02-23 14:43:39 +01:00
Miroslav Lichvar
663dde1ad7 refclock: improve precision with large offset
If a SHM or PHC refclock has a very large offset compensated by the
offset option, or ignored with the pps or local option, there is a
persistent loss of precision in the calculation of the sample offset
using the double format.

Rework the code to delay the calculation of the accumulated offset to
include the specificed compensation and remaining correction of the
system clock, where the calculation can be split to improve the
precision. In the pps mode ignore integer seconds competely.

The precision of the SOCK refclock is now limited to 1 nanosecond due to
the extra double->timespec->double conversion.
2022-02-23 14:43:39 +01:00
Miroslav Lichvar
62757cda49 refclock: add local option
Add "local" option to specify that the reference clock is an
unsynchronized clock which is more stable than the system clock (e.g.
TCXO, OCXO, or atomic clock) and it should be used as a local standard
to stabilize the system clock.

Handle the local refclock as a PPS refclock locked to itself which gives
the unsynchronized status to be ignored in the source selection. Wait
for the refclock to get at least minsamples samples and adjust the clock
directly to follow changes in the refclock's sourcestats frequency and
offset.

There should be at most one refclock specified with this option.
2022-02-23 14:43:39 +01:00
Miroslav Lichvar
af6ae9186b reference: allow clock adjustments without updating reference
Add support for accumulating frequency and time offset without changing
the reference parameters and calling the local parameter change
handlers.

This will allow an unsynchronized source to operate below other sources
in order to stabilize the clock.
2022-02-23 14:43:39 +01:00
Miroslav Lichvar
4c29f8888c sources: handle unsynchronized sources in selection
Allow sources to accumulate samples with the leap status set to not
synchronized. Define a new state for them to be ignored in the
selection. This is intended for sources that are never synchronized and
will be used only for stabilization.
2022-02-23 14:42:40 +01:00
Miroslav Lichvar
d06ae4a60e sourcestats: add function to get minsamples 2022-02-10 16:38:50 +01:00
Miroslav Lichvar
f9af2f9733 sourcestats: clamp minsamples and maxsamples in initialization
Don't leave the variables set to values outside their effective range.
This has no functional impact, but makes it clear what is the precedence
of the two settings.
2022-02-10 16:31:46 +01:00
Miroslav Lichvar
43ae0131cd sourcestats: use constant for required number of samples 2022-02-10 15:16:08 +01:00
Michael Hudson-Doyle
8bb8f15a7d sys_linux: allow rseq in seccomp filter
Libc 2.35 will use rseq syscalls [1][2] by default and thereby
break chrony in seccomp isolation.

[1]: https://www.efficios.com/blog/2019/02/08/linux-restartable-sequences/
[2]: https://sourceware.org/pipermail/libc-alpha/2022-February/136040.html

Tested-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
Reviewed-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
Signed-off-by: Michael Hudson-Doyle <michael.hudson@canonical.com>
Signed-off-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
2022-02-09 10:46:09 +01:00
Miroslav Lichvar
e55f174bd3 examples: handle more actions in NM dispatcher script
Run the chronyc onoffline command also when the connectivity-change
and dhcp6-change actions are reported by the NetworkManager dispatcher.

The latter should not be necessary, but there currently doesn't seem to
be any action for IPv6 becoming routable after duplicate address
detection, so at least in networks using DHCPv6, IPv6 NTP servers should
not be stuck in the offline state from a previously reported action.
2022-02-07 17:04:19 +01:00
Miroslav Lichvar
5bd13c8d59 examples: support DHCPv6 NTP servers in NM dispatcher script
Latest NetworkManager code provides NTP servers from the DHCPv6 NTP
option (RFC 5908) in the DHCP6_DHCP6_NTP_SERVERS variable to dispatcher
scripts.

Check for invalid characters (which can come from the FQDN suboption)
and include the servers in the interface-specific sources file.
2022-02-07 16:59:10 +01:00
Miroslav Lichvar
759580aa6f client: fix waitsync command to reconnect to server
If chronyc waitsync was started before chronyd, it would try all
addresses (Unix socket, IPv4, IPv6) and get stuck with no address, not
getting any response later when chronyd was running.

Reset the address index in open_io() when returning with failure to
allow the next call to start with the first address again.

Reported-by: Jan Mikkelsen <janm@transactionware.com>
2022-01-26 16:11:01 +01:00
Vincent Blut
b61cbed689 test: ensure awk commands in 008-ntpera return an integer
Some awk interpreters (e.g. mawk) print long integers in exponential
notation skewing the test result.
2022-01-13 09:40:12 +01:00
Miroslav Lichvar
2ac2247756 doc: update NEWS 2021-12-16 13:17:42 +01:00
Miroslav Lichvar
55f48b14b7 update copyright years 2021-12-16 13:17:42 +01:00
Miroslav Lichvar
3dfac33858 ntp: set local address on PTP socket on FreeBSD
Fix the FreeBSD-specific code checking for a bound IPv4 socket to
include the new PTP port. This should fix a multihomed server to respond
to NTP-over-PTP requests from the address which received the request.

Fixes: be3158c4e5 ("ntp: add support for NTP over PTP")
2021-12-16 13:17:42 +01:00
Miroslav Lichvar
d5f2401421 cmdmon: fix transmit_reply() to not read uninitialized data
In the FreeBSD-specific code checking for a bound IPv4 socket, make
sure it is not a Unix domain address to avoid reading uninitialized
IP-specific fields.

This fixes an error reported by valgrind.
2021-12-16 11:49:15 +01:00
Miroslav Lichvar
fb0570cc73 socket: zero sockaddr_un to initialize sa_len
Zero the whole sockaddr struct before calling bind() and connect() to
initialize the FreeBSD-specific sa_len field.

This fixes errors reported by valgrind.
2021-12-16 10:48:31 +01:00
Miroslav Lichvar
43936ba0d1 clientlog: remove unnecessary operation in timestamp conversion 2021-12-14 10:47:26 +01:00
Miroslav Lichvar
f2ba20f293 ntp: avoid unnecessary source lookups
Avoid searching the hash table of sources when a packet in the client
mode is received. It cannot be a response from our source. Analogously,
avoid source lookups for transmitted packets in the server mode. This
doesn't change anything for packets in symmetric modes, which can be
requests and responses at the same time.

This slightly improves the maximum packet rate handled as a server.
2021-12-14 10:47:10 +01:00
Miroslav Lichvar
fcd384523b ntp: fix typo in comment 2021-12-14 10:34:19 +01:00
Miroslav Lichvar
48bce351bf doc: describe use case for leapsecmode ignore option 2021-12-09 17:13:09 +01:00
Miroslav Lichvar
25f93875d9 doc: switch Solaris support to illumos
For a long time, the Solaris support in chrony wasn't tested on a real
Solaris system, but on illumos/OpenIndiana, which was forked from
OpenSolaris when it was discontinued in 2010.

While Solaris and illumos might have not diverged enough to make a
difference for chrony, replace Solaris in the documentation with illumos
to make it clear which system is actually supported by the chrony
project.
2021-12-09 17:03:56 +01:00
Miroslav Lichvar
ebc610fcb3 sys_solaris: disable kernel dosynctodr
The dosynctodr kernel variable needs to be set to 0 to block automatic
synchronization of the system clock to the hardware clock. chronyd used
to disable dosynctodr on Solaris versions before 2.6, but it seems it is
now needed even on current versions as the clock driver sets frequency
only without calling adjtime() or setting the ntp_adjtime() PLL offset.

This issue was reproduced and fix tested on current OpenIndiana.

Fixes: 8feb37df2b ("sys_solaris: use timex driver")
2021-12-07 12:18:56 +01:00
Miroslav Lichvar
264957a443 doc: update NEWS 2021-12-02 11:19:40 +01:00
Miroslav Lichvar
af611b5842 ntp: limit total monotonic offset correction
In addition to the 16s limit in per-response change in the monotonic
offset, don't allow the total accumulated offset injected in sourcestats
to be larger than 16 seconds.
2021-12-02 11:01:01 +01:00
Miroslav Lichvar
1c1ca1d12f test: update and improve 003-sanitizers test 2021-12-01 10:13:14 +01:00
Miroslav Lichvar
c506b9aac8 test: allow another inaccuracy in util unit test
A 1ns error in UTI_AdjustTimespec() was observed with an i686 build.
2021-12-01 09:26:41 +01:00
Miroslav Lichvar
2eefa61f10 test: fix 008-ntpera test for arbitrary NTP era split 2021-12-01 09:24:13 +01:00
Miroslav Lichvar
89a5e21e4d reference: check for unset leap_when in is_leap_close()
Check that the leap_when variable is set before testing a timestamp for
being close to a leap second. This allows the first measurement to be
accepted if starting at the Unix epoch (e.g. in a test).
2021-12-01 09:22:26 +01:00
Miroslav Lichvar
6a79771898 ntp: check for zero timestamp in initial TX timeout
Calculate the delay since the previous transmission only if the
TX timestamp is actually set. This removes an unnecessary delay when
starting at the Unix epoch in 1970 (e.g. in a test).
2021-12-01 09:22:26 +01:00
Miroslav Lichvar
53353529cf rtc: don't drop first sample after initial trim
It seems there is no longer an issue with the first sample after the
initial trim and it can be accumulated. It might have been a workaround
for an unrelated bug which was fixed since then.

This fixes the number of samples reported in rtcdata briefly jumping to
65535 and also brings back the expectation that n_samples is never
negative.
2021-12-01 09:22:26 +01:00
Miroslav Lichvar
22bfdf204f rtc: drop rtc_trim array
It always contained zero values and had no effect on anything.
2021-12-01 09:22:26 +01:00
Miroslav Lichvar
fc28e9ae56 rtc: remove unnecessary variable initializations 2021-12-01 09:22:26 +01:00
Miroslav Lichvar
17e6258694 doc: update FAQ 2021-11-24 15:07:22 +01:00
Miroslav Lichvar
d7a444593f ntp: improve check for PTP socket
Check for INVALID_SOCK_FD in case the PTP port is enabled, but opening
one of the PTP sockets failed.
2021-11-24 15:07:04 +01:00
Miroslav Lichvar
701b9415a5 test: update 110-chronyc test 2021-11-24 15:06:36 +01:00
Miroslav Lichvar
d5894c0738 main: add assertions for timespec signedness
Some of the code (e.g. util and clientlog) may work with negative
values. Require that time_t and the tv_nsec types are signed. This seems
to be the case on all supported systems, but it it is not required by
POSIX.
2021-11-24 11:17:24 +01:00
Miroslav Lichvar
a0a9560258 util: reset GetRandom functions in helpers after fork
Close /dev/urandom and drop cached getrandom() data after forking helper
processes to avoid them getting the same sequence of random numbers
(e.g. two NTS-KE helpers generating cookies with identical nonces).
arc4random() is assumed to be able to detect forks and reseed
automatically.

This is not strictly necessary with the current code, which does not use
the GetRandom functions before the NTS-KE helper processes are forked,
but that could change in future.

Also, call the reset function before exit to close /dev/urandom in order
to avoid valgrind reporting the file object as "still reachable".
2021-11-24 11:17:24 +01:00
Miroslav Lichvar
09067e06d3 ntp: fix exp1 EF search in process_response()
Don't ignore the magic field when searching for the exp1 extension
field in a received response. If there were two exp1 fields in the
packet, and only one of them had the expected magic value, it should
pick the right one.

Fixes: 2319f72b29 ("ntp: add client support for experimental extension field")
2021-11-24 11:17:24 +01:00
Miroslav Lichvar
dbbdd5af06 ntp: make default NTP version with xleave to be always 4
If the xleave option is enabled, ignore the key option and the hash
length. Always use version 4 as the default to get interleaved responses
from new chrony servers.
2021-11-22 17:03:40 +01:00
Miroslav Lichvar
7f984cf7fa ntp: limit interleaved responses to NTPv4
The interleaved modes are being specified for NTPv4 only. As a server,
detect interleaved requests only in NTPv4 packets.

Clients and peers can still send interleaved requests in lower-version
packets if configured with the version option.
2021-11-22 17:02:49 +01:00
Miroslav Lichvar
8df49b799f ntp: suppress monotonic timestamp if smoothing is enabled
Frequency transfer and time smoothing are conflicting features. Set the
monotonic timestamp in the experimental extension field to zero
(invalid) if time smoothing is activated.
2021-11-22 15:52:01 +01:00
Miroslav Lichvar
e7c2f71cea ntp: add special value to experimental root delay/disp
The maximum value of the new 32-bit fields is slightly less than 16,
which can cause the NTP test #7 to pass for a server which has a zero
root delay but maximum root dispersion.

Interpret the maximum value as the maximum value of the original 32-bit
fields (~65536.0 seconds) for better compatibility with NTPv4.
2021-11-22 15:21:29 +01:00
Miroslav Lichvar
219085b8f6 test: add 144-exp1 test 2021-11-16 10:36:26 +01:00
Miroslav Lichvar
2319f72b29 ntp: add client support for experimental extension field
Add "extfield F323" option to include the new extension field in
requests. If the server responds with this field, use the root
delay/dispersion and monotonic timestamp. Accumulate changes in the
offset between the monotonic and real-time receive timestamps and use
it for the correction of previous offsets in sourcestats. In the
interleaved mode, cancel out the latest change in the offset in
timestamps of the previous request and response, which were captured
before the change actually happened.
2021-11-16 10:34:32 +01:00
Miroslav Lichvar
72f7d09f58 sourcestats: add function to correct accumulated offsets
This will be needed to follow server time corrections in order to
better estimate frequency.
2021-11-16 10:23:20 +01:00
Miroslav Lichvar
0bf39c0ab9 ntp: add server support for experimental extension field
Maintain a server monotonic timescale needed for the experimental
extension field. It follows the best estimate of frequency without
time corrections. Implement it as an offset relative to the NTP time,
starting at zero, using a slew handler to cancel time corrections of the
NTP clock. The 32-bit epoch ID is set to a random value on start and
every step of the system clock.
2021-11-16 10:23:20 +01:00
Miroslav Lichvar
2e126ed2b5 util: add functions for converting new root delay/dispersion 2021-11-16 10:23:20 +01:00
Miroslav Lichvar
a652ce7d0e util: add function to subtract NTP timestamps
This will be needed to work with monotonic timestamps, which don't have
a stable epoch and cannot be converted to timespec.
2021-11-16 10:23:20 +01:00
Miroslav Lichvar
a97ca73704 ntp: add pre-NTPv5 experimental extension field
Add an experimental extension field for some features that were proposed
for NTPv5. Higher-resolution root delay and dispersion (using 28-bit
fraction) are added. A monotonic receive timestamp will allow a
frequency transfer between the server and client. The client will be
able to separate the server's time corrections from frequency
corrections by tracking the offset between the real-time and monotonic
receive timestamps.

The field has a type of 0xF323 from the new experimental range proposed
by the NTP working group. Include a magic 32-bit value in the field to
avoid interoperability issues if a different implementation choses the
same type for its own experimental field. The value will be changed on
incompatible changes to avoid issues between two different chrony
versions.
2021-11-16 10:23:15 +01:00
Miroslav Lichvar
125d7a5c32 ntp: prepare for non-authentication extension fields
Add a new variable to the packet info structure with flags for extension
fields included in received packets and add a new parameter to
transmit_packet() to add the fields to transmitted packets.
2021-11-16 10:21:39 +01:00
Miroslav Lichvar
36356ef033 ntp: move initial packet parsing from ntp_auth to ntp_core
Since commit fdfcabd79b ("ntp: drop support for long NTPv4 MACs"), the
parser doesn't need to check validify of MACs in NTPv4 packets to
distinguish them from extension fields. Move the parser to ntp_core to
avoid having a separate iteration looking for non-authentication
extension fields.
2021-11-16 10:00:31 +01:00
Miroslav Lichvar
a2d1569455 socket: increase message buffer length
Add extra space to the socket message buffer to be able to receive
maximum-length NTP-over-PTP SW/HW-timestamped messages from the Linux
error queue (which are looped back as layer-2 frames).
2021-10-27 16:22:12 +02:00
Miroslav Lichvar
952c3b2528 ntp: use previous root delay/disp in interleaved mode
When calculating the root delay and dispersion of a sample measured in
the interleaved mode, use the root delay and dispersion values from
the previous response (to which the TX timestamp corresponds). If the TX
timestamp is combined with the RX timestamp of the latest response (e.g.
in the symmetric mode), use the maximum of the previous and latest root
delay/dispersion.
2021-10-27 16:22:12 +02:00
Miroslav Lichvar
d92d24ad7f test: extend 122-xleave test 2021-10-27 16:22:12 +02:00
Miroslav Lichvar
bc33e1cda1 clientlog: undo clock adjustments in updated TX timestamps
When the server clock was updated between saving of the RX timestamp and
updating the TX timestamp, a client using interleaved mode with the four
timestamps which minimize error in measured delay (e.g. chrony) had the
server clock adjustment included in the measured delay, which could
disrupt the sample filtering and weighting.

Add a handler to track the slew epoch and remember the last offset. Undo
the adjustment in TX timestamps which have their RX timestamp in the
previous epoch to fix the delay observed by the clients.

If an unknown clock step is detected, drop all timestamps.
2021-10-27 16:22:12 +02:00
Miroslav Lichvar
189bf9c536 ntp: don't save timestamps if transmit_packet() failed
Don't save server RX and TX timestamp to clientlog if the transmission
or authentication failed (e.g. packet is handled in ntp_signd). They
will not be needed.
2021-10-27 16:22:08 +02:00
Miroslav Lichvar
c5dde9b66a ntp: initialize saved TX timestamp
Zero the initial TX timestamp which is saved for the interleaved
mode in case there is no previous timestamp saved in clientlog and
transmit_packet() does not generate a new one (e.g. due to failure in
authentication).

Fixes: 5f4cbaab7e ("ntp: optimize detection of clients using interleaved mode")
2021-10-27 12:31:36 +02:00
Miroslav Lichvar
1fb60f8db8 cmdmon: add interleaved stats to serverstats
Report the number of received interleaved requests and current timestamp
count with their span.

Expand the serverstats description in chronyc man page.
2021-10-21 17:04:51 +02:00
Miroslav Lichvar
2f05287e15 test: improve clientlog unit test
Test also timestamp maps with smaller maximum sizes.
2021-10-19 15:15:46 +02:00
Miroslav Lichvar
61226cda8c ntp: don't capture TX timestamps if clientlog is disabled
When responding to a request, don't waste time with TX timestamping
if the timestamp will not be saved (i.e. clientlog is disabled).

Fixes: 5f4cbaab7e ("ntp: optimize detection of clients using interleaved mode")
2021-10-19 15:15:46 +02:00
Miroslav Lichvar
26b51d841e doc: improve clientloglimit description 2021-10-14 17:17:10 +02:00
Miroslav Lichvar
5f4cbaab7e ntp: optimize detection of clients using interleaved mode
Use the lowest bit of the server RX and TX timestamp as a flag
indicating RX timestamp. This allows the server to detect potential
interleaved requests without having to save all its RX timestamps. It
significantly reduces the amount of memory needed to support clients
using the interleaved mode if most of the server's clients are using the
basic mode (e.g. a public server).

Capture the TX timestamp on the first response to the request which has
the flag set to not further delay the first interleaved response.

False positives are possible with broken clients which set the origin
timestamp to something else than zero or the server RX or TX timestamp.
This causes an unnecessary RX timestamp to be saved and TX timestamp
captured and saved.
2021-10-14 17:17:05 +02:00
Miroslav Lichvar
7a80647fb4 ntp: move authentication calls in transmit_packet()
Move the calls resetting and generating authentication data out of the
loop checking for unique TX timestamp. This allows the timestamps to be
manipulated after the check.
2021-10-14 16:42:23 +02:00
Miroslav Lichvar
14b8df3702 clientlog: separate NTP timestamps from IP addresses
Instead of keeping one pair of RX and TX timestamp for each address, add
a separate RX->TX map using an ordered circular buffer. Save the RX
timestamps as 64-bit integers and search them with a combined linear
interpolation and binary algorithm.

This enables the server to support multiple interleaved clients sharing
the same IP address (e.g. NAT) and it will allow other improvements to
be implemented later. A drawback is that a single broken client sending
interleaved requests at a high rate (without spoofing the source
address) can now prevent clients on other addresses from getting
interleaved responses.

The total number of saved timestamps does not change. It's still
determined by the clientloglimit directive. A new option may be added
later if needed. The whole buffer is allocated at once, but only on
first use to not waste memory on client-only configurations.
2021-10-14 16:42:20 +02:00
Miroslav Lichvar
5cb469b204 clientlog: fix debug message for maximum number of records 2021-10-14 15:03:26 +02:00
Miroslav Lichvar
29d7d3176d sys_linux: fix seccomp filter for BINDTODEVICE option
The BINDTODEVICE socket option is the first option in the seccomp filter
setting a string instead of int. Remove the length check from the
setsockopt rules to allow a device name longer than 3 characters.

This was reported in Debian bug #995207.

Fixes: b9f5ce83b0 ("sys_linux: allow BINDTODEVICE option in seccomp filter")
2021-10-06 10:09:35 +02:00
Miroslav Lichvar
76a905d652 examples: improve chronyd service
Allow writing logfiles (enabled by logdir or -l option) to /var/log and
don't require /var/spool to exist.
2021-10-04 10:54:40 +02:00
Miroslav Lichvar
83f96efdfd examples: harden systemd services
Add various settings to the example chronyd and chrony-wait services to
decrease the exposure reported by the "systemd-analyze security"
command. The original exposure was high as the analyzer does not check
the actual process (e.g. that it dropped the root privileges or that it
has its own seccomp filter).

Limit read-write access to /run, /var/lib/chrony, and /var/spool.
Access to /run (instead of /run/chrony) is needed for the refclock
socket expected by gpsd.

The mailonchange directive is most likely to break as it executes
/usr/sbin/sendmail, which can do unexpected operations depending on the
implementation. It should work with a setuid/setgid binary, but it is
not expected to write outside of /var/spool and the private /tmp.
2021-09-29 15:56:55 +02:00
Miroslav Lichvar
127826a399 ntp: check software timestamps on Linux
Apparently some routers with hardware NAT acceleration have a bug
causing the kernel timestamps to be corrupted and break NTP. Similarly
to the sanity check applied to hardware timestamps, require the
kernel/driver timestamps to be within one second of the daemon timestamp
to be accepted.
2021-09-23 15:51:35 +02:00
Miroslav Lichvar
7ee5f4888e ntp: print stratum 1 refid in ASCII in debug message 2021-09-23 15:51:35 +02:00
Miroslav Lichvar
9ed1d1afc2 doc: show arguments of ratelimit options 2021-09-23 15:51:35 +02:00
Miroslav Lichvar
d0d9a3fa43 use round() for rounding
Replace casting of values incremented by +0.5/-0.5 with round().
2021-09-23 15:51:35 +02:00
Miroslav Lichvar
9600993c28 test: fix incorrect use of RAND_MAX
On some systems (e.g. Solaris/OpenIndiana) rand() and random() have
different ranges. RAND_MAX is the maximum value returned by rand(),
but random() should always have a range of 0 through 2^31-1.

This fixes multiple failures in different tests.
2021-09-23 15:51:35 +02:00
Miroslav Lichvar
5e6f8458ff client: replace allow/deny parser
Use the new cmdparse function for parsing the (cmd)allow/deny commands
and refactor the code a bit to reduce the number of functions needed for
all the (cmd)allow/deny(all) combinations.
2021-09-23 15:50:05 +02:00
Miroslav Lichvar
f5fe5452f6 conf: rework allow/deny parser
Refactor the (cmd)allow/deny parser and make it more strict in what
input it accepts. Check the scanned numbers and require whole input to
be processed.

Move the parser to cmdparse to make it available to the client.
2021-09-23 15:16:33 +02:00
Miroslav Lichvar
3ac6a0c26c cmdmon: move comment to make its scope clearer 2021-09-23 14:48:59 +02:00
Miroslav Lichvar
c2872d1e12 test: extend 110-chronyc test 2021-09-23 14:48:59 +02:00
Miroslav Lichvar
e47e7e3661 test: fix chronyc test with disabled IPv6 support 2021-09-23 14:48:59 +02:00
Miroslav Lichvar
d8f14ec59b test: add 143-manual test 2021-09-23 14:48:59 +02:00
Miroslav Lichvar
274a51bc38 test: enable chronyc to use Unix domain socket 2021-09-23 14:48:59 +02:00
Miroslav Lichvar
92700e194c test: fix 002-scanbuild test 2021-09-23 14:48:59 +02:00
Miroslav Lichvar
87df268723 test: update compilation tests 2021-09-02 16:10:17 +02:00
Miroslav Lichvar
17a9caf5c8 cmac: add gnutls support
Similarly to hashing, add support for AES-CMAC in gnutls to avoid
linking directly with nettle.
2021-09-02 16:10:09 +02:00
Miroslav Lichvar
36441fabde hash: allow non-security MD5 use in FIPS mode
gnutls running in the FIPS140-2 mode does not allow MD5 to be
initialized, which breaks chronyd using MD5 to calculate reference ID
of IPv6 addresses. Specify a new hash algorithm for non-security MD5 use
and temporarily switch to the lax mode when initializing the hash
function.
2021-09-02 15:17:08 +02:00
Miroslav Lichvar
f363998517 hash: add gnutls support
Add support for crypto hash functions in gnutls (internally using
nettle). This can be useful to avoid directly linking with nettle to
avoid ABI breaks.
2021-09-02 15:17:08 +02:00
Miroslav Lichvar
6fc30baba8 configure: fix SIV detection in gnutls
gnutls_aead_cipher_init() is declared in gnutls/crypto.h. If the
compiler handles implicit declarations as errors, the SIV support was
not detected. Fix the check to use the correct header.
2021-09-02 15:17:00 +02:00
Miroslav Lichvar
70a0f18d52 siv: deinit gnutls on unsupported SIV 2021-09-02 13:35:35 +02:00
Miroslav Lichvar
0ad5f5ea89 privops: allow binding to PTP port
Fixes: be3158c4e5 ("ntp: add support for NTP over PTP")
2021-09-02 13:35:33 +02:00
Miroslav Lichvar
d676f39b84 doc: improve ptpport example 2021-09-01 16:56:54 +02:00
Miroslav Lichvar
31690261f5 doc: remove obsolete comment in maxslewrate description 2021-08-19 14:51:42 +02:00
Miroslav Lichvar
93326488a3 doc: shorten lock_all description 2021-08-19 14:51:42 +02:00
Miroslav Lichvar
d5ca98eaaa test: add 142-ptpport test 2021-08-19 14:51:42 +02:00
Miroslav Lichvar
be3158c4e5 ntp: add support for NTP over PTP
Allow NTP messages to be exchanged as a payload of PTP messages to
enable full hardware timestamping on NICs that can timestamp PTP packets
only. Implemented is the protocol described in this draft (version 00):

https://datatracker.ietf.org/doc/draft-mlichvar-ntp-over-ptp/

This is an experimental feature. It can be changed or removed in future.
The used PTP domain is 123 and the NTP TLV type is 0x2023 from the "do
not propagate" experimental range.

The ptpport directive enables NTP-over-PTP as a server and as a client
for all sources that have the port option set to the PTP port. The port
should be the PTP event port (319) to trigger timestamping in the
hardware.

The implementation is contained to ntp_io. It is transparent to
ntp_core.
2021-08-19 14:51:38 +02:00
Miroslav Lichvar
2f1d5d9255 ntp: add PTP rxfilter
Setting rxfilter to ptp enables timestamping of PTPv2 packets (UDP or
all transports). It will be needed for NTP-over-PTP support.
2021-08-18 16:56:09 +02:00
Miroslav Lichvar
b2c2132e4b ntp: provide remote port to NIO_OpenServerSocket()
This will allow selection of different protocols based on the remote
port. Zero means the default (NTP).
2021-08-16 14:53:46 +02:00
Stefan R. Filipek
aab6d1b153 doc: fix chronyd platform support for -P and -m
A while back, support for memory locking and real-time scheduling was
added to more platforms. The chronyd documentation wasn't updated at
that time (chronyd.conf was). This patch fixes that.
2021-08-09 12:08:12 +02:00
Miroslav Lichvar
bbbd80bf03 sys_linux: allow clone3 and pread64 in seccomp filter
These seem to be needed with the latest glibc.
2021-08-09 11:48:21 +02:00
Miroslav Lichvar
f27d719a4e rtc: avoid printing and scanning time_t
With the latest glibc it's now possible to define _TIME_BITS=64 to get
64-bit time_t on 32-bit Linux systems. This breaks the %ld printf/scanf
modifier used with the RTC drift timestamp. Process it as a double.
2021-08-05 14:41:28 +02:00
Miroslav Lichvar
789817cd91 doc: improve ntsserverkey/cert description
The files are read after dropping root privileges. They need to be
readable by the chrony user. The error message "Could not set
credentials : Error while reading file." does not make this requirement
very obvious.
2021-07-07 16:45:46 +02:00
Miroslav Lichvar
885e7774fd doc: update NEWS 2021-05-12 13:06:15 +02:00
Miroslav Lichvar
883b7eed8a update copyright years 2021-05-12 13:06:15 +02:00
Miroslav Lichvar
4049ed8766 test: make 007-cmdmon test more reliable
Reorder the local off command with respect to offline and online to
prevent the client from getting an unsynchronized response.
2021-05-12 13:06:15 +02:00
Miroslav Lichvar
f9f6803b8a test: allow inaccurate math in util unit test
Don't require timespec/timeval-double conversion tests to produce
correctly rounded results to handle x86 and other archs with wider
intermediate results.
2021-05-10 18:15:45 +02:00
Miroslav Lichvar
385f7ebfd9 test: disable privdrop in nts test
They are unrelated features. Not setting privdrop avoids a skip due to
the nobody user not having access to the test directory.
2021-05-10 16:04:34 +02:00
Miroslav Lichvar
f9cbc4803d sys_linux: check if execveat is defined
The syscall is missing on older systems.
2021-05-06 15:43:04 +02:00
Miroslav Lichvar
97973b1833 sys_linux: add second scfilter level
Add level "2" to enable a filter which blocks only specific system calls
like fork and exec* instead of blocking everything unknown. It should
be reliable with respect to changes in libraries, but it provides only a
very limited protection.
2021-05-06 13:37:21 +02:00
Miroslav Lichvar
9cdfc15e31 sys_linux: allow getuid32 in seccomp filter
This was triggered on x86 in an NTS test.
2021-05-06 13:11:10 +02:00
Miroslav Lichvar
fc99317291 sourcestats: check samples loaded from dump files
When loading a dump file with the -r option, check also sanity of the
sample time, offset, peer/root delay/dispersion, and the sample order to
better handle corrupted files.
2021-05-06 13:10:51 +02:00
Miroslav Lichvar
bb9ba3e4bd source: don't print duplicated address in selection message
Don't print the original IP address in parentheses in the "Selected
source ..." message if it is identical to the current address. That is
expected to be the usual case for sources specified by IP address.
2021-05-05 12:41:23 +02:00
Miroslav Lichvar
649f54a1e6 conf: log error when source cannot be added
Log an error message when adding of a source fails, e.g. due to the new
limit on number of sources, or when the same address is specified
multiple times.
2021-05-05 12:41:23 +02:00
Miroslav Lichvar
4070d7ffa6 nts: close file after loading cookies
Don't forget to close the file with cookies in ntsdumpdir if
successfully loaded.

Fixes: 2fa83b541c ("nts: save and load cookies on client")
2021-05-05 12:41:23 +02:00
Miroslav Lichvar
0493abb68a nts: ignore long non-critical records
In the NTS-KE client don't reject the response if it has non-critical
records that are too long for the processing buffer. This is not
expected to happen with the current specification, but it might be
needed with future extensions.

Fixes: 7925ed39b8 ("nts: fix handling of long server negotiation record")
2021-05-05 12:41:22 +02:00
Miroslav Lichvar
8c1e16711d test: fix date use in 010-nts system test
Avoid using nonportable -d option of date.
2021-04-29 15:03:37 +02:00
Miroslav Lichvar
1d03908646 test: remove logs before chronyd start in system tests 2021-04-29 13:26:01 +02:00
Miroslav Lichvar
49d718c025 test: extend configuration in system tests 2021-04-29 13:23:34 +02:00
Miroslav Lichvar
c536b2561b test: rework seccomp testing
Instead of a single test with enabled seccomp, rerun all other
non-destructive and destructive tests for each seccomp level.
2021-04-29 13:23:34 +02:00
Miroslav Lichvar
b9f5ce83b0 sys_linux: allow BINDTODEVICE option in seccomp filter
Fixes: 4ef944b734 ("socket: add support for binding sockets to device")
2021-04-29 12:37:26 +02:00
Miroslav Lichvar
8baab00ae0 doc: warn about -F and mailonchange in chronyd man page 2021-04-29 09:44:32 +02:00
Miroslav Lichvar
d01cb5af46 nts: avoid assumption about cookie record
The cookie record is currently assumed to be the longest record that
needs to be accepted by the client, but that does not have to be always
the case. Define the processing buffer using the maximum body record
constant instead and add an assertion to make sure it's not smaller than
the maximum accepted cookie length.
2021-04-29 09:44:32 +02:00
Miroslav Lichvar
7925ed39b8 nts: fix handling of long server negotiation record
Recent change in handling of the NTPv4 server negotiation record (commit
754097944b) increased the length of the instance name buffer to make
room for the trailing dot. This allowed a record with body truncated in
the processing buffer to be accepted and caused an over-read of 1 byte
in the memcpy() call saving the name to the instance buffer.

Modify the client to accept only records that fit in the processing
buffer.

Fixes: 754097944b ("nts: handle negotiated server as FQDN")
2021-04-29 09:44:18 +02:00
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
Miroslav Lichvar
009f1a5ae8 doc: update NEWS 2020-08-25 11:49:44 +02:00
Miroslav Lichvar
4f1418abf9 doc: update README 2020-08-25 11:49:44 +02:00
Miroslav Lichvar
79b348f075 util: don't open symlink when appending to file
When opening a file for appending (i.e. a log file), use the O_NOFOLLOW
flag to get an error if the path is a symlink. Opening log files through
symlinks is no longer supported.

This is a protection against symlink attacks if chronyd is misconfigured
to write a log in a world-writable directory (e.g. /tmp). That is not
meant to become a recommended practice. Log messages will be lost, or
chronyd won't start, if a symlink exists at the location of the log
file.
2020-08-25 11:49:44 +02:00
Miroslav Lichvar
9d88c028e2 test: fix cookie length in nts_ke_client unit test 2020-08-25 11:49:44 +02:00
Miroslav Lichvar
51172b3510 nts: avoid key corruption on failed loading
Don't save a loaded key to the server key slot until it is fully
decoded.
2020-08-20 16:19:13 +02:00
Miroslav Lichvar
892636036a nts: explicitly disable session tickets
Session tickets should never be enabled with the currect code on both
clients and servers. Set the GNUTLS_NO_TICKETS flag when opening a TLS
session in case this understanding is wrong, or it changes in future, to
reduce the TLS attack surface.
2020-08-20 16:19:13 +02:00
Miroslav Lichvar
4cf6b29397 test: fix 102-hwtimestamp test for new ethtool
New ethtool using netlink messages has a different output.
2020-08-20 16:19:13 +02:00
Miroslav Lichvar
571359b366 test: extend 110-chronyc test 2020-08-20 13:27:53 +02:00
Miroslav Lichvar
0f009e7718 test: extend 007-cmdmon system test 2020-08-20 13:27:53 +02:00
Miroslav Lichvar
24effd7340 test: add 105-nts system test 2020-08-20 13:27:53 +02:00
Miroslav Lichvar
5289fc5f80 test: add 009-binddevice system test 2020-08-20 13:27:53 +02:00
Miroslav Lichvar
ca49304bd6 test: add 008-confload system test 2020-08-20 13:27:53 +02:00
Miroslav Lichvar
b7fbac617d conf: rename confdirs and sourcedirs directives
Rename the directives to confdir and sourcedir to better match an
expected use case with only one specified directory.
2020-08-20 13:27:46 +02:00
Miroslav Lichvar
839e9aa4af reference: fix assignment of frequency_sd
Fixes: 8afd62d954 ("reference: update synchronization status more frequently")
2020-08-19 09:39:26 +02:00
Miroslav Lichvar
c5ac15ad33 client: improve parsing of keygen arguments
Detect invalid syntax for the keygen command.
2020-08-19 09:39:26 +02:00
Miroslav Lichvar
598cd10c34 client: ignore case in add command
For consistency with chronyd configuration, make the source type in the
add command case insensitive.
2020-08-19 09:39:18 +02:00
Miroslav Lichvar
1885729024 client: drop unnecessary parsing of IPv4 address 2020-08-18 14:22:55 +02:00
Miroslav Lichvar
2127f63961 cmdmon: change name fields to unsigned type 2020-08-17 16:28:36 +02:00
Miroslav Lichvar
97a8b1e43b test: fix random failures in nts_ntp_client unit test
Fixes: 18d9243eb9 ("test: improve NTS unit tests")
2020-08-17 16:28:36 +02:00
Miroslav Lichvar
aeee1feda6 test: improve siv unit test 2020-08-13 16:37:38 +02:00
Miroslav Lichvar
18d9243eb9 test: improve NTS unit tests 2020-08-13 16:37:38 +02:00
Miroslav Lichvar
1aa4827b3b test: extend 139-nts test 2020-08-13 16:37:38 +02:00
Miroslav Lichvar
ed1077a788 nts: check all encrypted fields before saving cookies
Don't save any cookies if an encrypted extension field fails parsing.
2020-08-13 16:37:20 +02:00
Miroslav Lichvar
356c475a6a cmdmon: fix data field name in handle_ntp_source_name()
Fixes: 93f6358916 ("cmdmon: add request to get source name")
2020-08-13 10:40:18 +02:00
Miroslav Lichvar
9ac582fa35 socket: improve code
Add more assertions and other checks, and improve coding style a bit.
2020-08-13 10:40:18 +02:00
Miroslav Lichvar
8c75f44603 ntp: fix comments
Fix typos and remove an obsolete comment.
2020-08-13 10:40:18 +02:00
Miroslav Lichvar
0a63ad95ce ntp: reuse pool IDs for new pools
When adding a new pool, reuse unused pool IDs to avoid increasing the
pools array.
2020-08-13 10:39:37 +02:00
Miroslav Lichvar
d274fe44da ntp: rename pool fields to pool_id
Rename the pool fields holding the ID of the pool to avoid confusion
with the pool record and pool flag.
2020-08-10 12:27:33 +02:00
Miroslav Lichvar
6d1cb58d8f examples: add leapsecmode to chrony.conf examples 2020-08-06 11:34:32 +02:00
Miroslav Lichvar
784122d44f client: add missing option to help message 2020-08-04 13:04:04 +02:00
Miroslav Lichvar
32fb8d41ca test: fix compiler warning in ntp unit test 2020-08-04 12:24:51 +02:00
Miroslav Lichvar
4993c35e11 util: fix compiler warning
Replace the snprintf() call with memcpy() in UTI_PathToDir() to make it
clear a truncated string is expected.
2020-08-04 12:24:51 +02:00
Miroslav Lichvar
6a5665ca58 conf: add dscp directive
The directive sets the DSCP value in transmitted NTP packets, which can
be useful in local networks where switches/routers are configured to
prioritise packets with specific DSCP values.
2020-08-04 12:24:49 +02:00
Miroslav Lichvar
e5cf006378 sources: reset leap voting flag earlier in selection
Remove the leap vote from sources that get the noselect option, or
have too large distance or jitter.
2020-08-04 12:19:52 +02:00
Miroslav Lichvar
0e51552d2d ntp: improve auth code
Before generating a MAC, make sure there is enough space in the packet.
This is always true with the current code, but it may change when a
non-NTS extension field is supported.

Update the packet auth info after generating a MAC in case it's needed
before the transmission.

Add more assertions and make other changes for better readability.
2020-08-04 12:19:41 +02:00
Miroslav Lichvar
cc007ad93b test: improve nts_ntp_client unit test 2020-07-28 12:48:23 +02:00
Miroslav Lichvar
3096926547 nts: disable TLS 1.2 on server
It seems gnutls (at least in version 3.6.14) allows clients to connect
using TLS1.2 when it has a DTLS version enabled in the priority cache.

Disable all DTLS versions in order to disable TLS1.2.
2020-07-28 12:48:23 +02:00
Miroslav Lichvar
d48f012809 nts: improve NTS-NTP server/client code
Add more comments, assertions, debug messages, and other minor
changes to make the code more robust.
2020-07-28 12:48:23 +02:00
Miroslav Lichvar
def137bc80 nts: scale server listening backlog with number of helpers 2020-07-28 12:48:23 +02:00
Miroslav Lichvar
3e0272e55f nts: fix destroying of NTS-KE client
Destroy the NTS-KE session of the client immediately even when the
resolver of the NTP address is running. This removes the session
local change handler and avoids an assertion failure in the local
finalization.
2020-07-28 12:48:23 +02:00
Miroslav Lichvar
be503bbcf6 nts: move loading of syscall filter in NTS-KE server
Load the filter after NKS_Initialise() to avoid hitting
a fcntl syscall.

Fixes: 66e097e3e6 ("nts: improve NTS-KE server/client code")
2020-07-28 12:48:20 +02:00
Miroslav Lichvar
72bf3d26eb nts: fix error response to NTS-KE request
When the request has an unrecognized critical record before the
NEXT_PROTOCOL and AEAD_ALGORITHM records, respond with error 0
(unrecognized critical record) instead of 1 (bad request).

When the request has multiple NEXT_PROTOCOL or AEAD_ALGORITHM records,
respond with error 1 (bad request).
2020-07-23 15:53:24 +02:00
Miroslav Lichvar
cc20ead3dc nts: reset NAK indicator with new request
Don't restart NTS-KE if a spoofed NAK response was received and no valid
response is received for a subsequent request.
2020-07-20 16:52:46 +02:00
Miroslav Lichvar
fd8fbcd090 nts: don't allow malformed encrypted extension fields
Require data decrypted from the NTS authenticator field to contain
correctly formatted extension fields (known or unknown).
2020-07-20 16:52:42 +02:00
Miroslav Lichvar
77bd0f83fe main: remove unneeded code in signal handler
The handler is set up when the main code is already initialized.
2020-07-16 16:02:16 +02:00
Miroslav Lichvar
32a82a38fd siv: add more assertions
Make sure the returned tag and key lengths are sane.
2020-07-16 16:02:16 +02:00
Miroslav Lichvar
66e097e3e6 nts: improve NTS-KE server/client code
Add more assertions and comments, refactor initialization of the helper,
and make other changes to make the code more robust.
2020-07-16 16:02:08 +02:00
Miroslav Lichvar
51d77d6cfc logging: extend functionality
Add a function to get the current minimum severity and a function to set
a global prefix for debug messages in order to identify messages from
helpers.
2020-07-16 13:24:59 +02:00
Miroslav Lichvar
2bb0769516 conf: improve error message
Replace "command" with "directive" for consistency with the
documentation.
2020-07-16 12:07:43 +02:00
Miroslav Lichvar
58da0c0ad2 conf: adopt default bind*address values
Move the default values of the bind*address settings from the
ntp/nts/cmdmon code to conf.
2020-07-16 12:07:43 +02:00
Miroslav Lichvar
c10b66b579 nts: follow bind*device settings for NTS-KE sockets
Bind the server and client NTS-KE sockets to the specified device.
2020-07-16 12:07:35 +02:00
Miroslav Lichvar
55a90c3735 nts: deinit gnutls when setting of credentials fails
This is needed to cleanly exit when the server key/cert couldn't be
loaded.
2020-07-16 12:06:27 +02:00
Miroslav Lichvar
962afb9e7d nts: disable input when sending data in NTS-KE session
Ignore read events when sending data to avoid spinning with blocked
output.
2020-07-16 12:03:43 +02:00
Miroslav Lichvar
7abd982f87 doc: fix formatting with new asciidoctor
With newer asciidoctor versions a blank character seems to be required
in an empty description used to set the indentation level in a nested
list.

https://github.com/asciidoctor/asciidoctor/issues/2766
2020-07-16 12:02:29 +02:00
Miroslav Lichvar
c099aac79c socket: fix debug message for unsupported binding
Fixes: 4ef944b734 ("socket: add support for binding sockets to device")
Reported-by: Bryan Christianson <bryan@whatroute.net>
2020-07-10 09:04:20 +02:00
Miroslav Lichvar
828e6ce30f doc: mention automatic creation of directories 2020-07-09 14:47:33 +02:00
Miroslav Lichvar
dc08cbfe59 conf: create ntsdumpdir directory
Create the directory specified by the ntsdumpdir directive if it doesn't
exist, similarly to logdir and dumpdir.
2020-07-09 14:47:33 +02:00
Miroslav Lichvar
3bdcce6903 conf: restrict permissions of created directories
If logdir or dumpdir doesn't exist, create the directory with no
permissions for other users (mode 0750 instead of 0755).
2020-07-09 14:47:33 +02:00
Miroslav Lichvar
d93aa10bac cmac+hash: change parameter types
For consistency and safety, change the CMC and HSH functions to accept
signed lengths and handle negative values as errors. Also, change the
input data type to void * to not require casting in the caller.
2020-07-09 14:47:33 +02:00
Miroslav Lichvar
de4ecc72d1 nts: don't assume field position in NNA_DecryptAuthEF()
Modify NNA_DecryptAuthEF() to not assume that the authenticator is the
last extension field in the packet as some extension fields specified in
future may need to be placed after the authenticator. The caller of the
function is supposed to verify the position.
2020-07-09 14:47:33 +02:00
Miroslav Lichvar
db54bfc0c1 nts: check for negative length in NNA_DecryptAuthEF()
As other functions that accept a signed length, make sure it is sane in
NNA_DecryptAuthEF() too.
2020-07-09 14:47:33 +02:00
Miroslav Lichvar
72ee80debe nts: fix comment about message handler 2020-07-09 14:47:33 +02:00
Miroslav Lichvar
a3436c26f0 nts: improve session code
Add more comments and assertions, replace getsockopt() call with
SCK_GetIntOption(), replace strncmp() with memcmp(), move a return
statement for clarity, and remove an unused field from the instance
record.
2020-07-09 14:47:30 +02:00
Miroslav Lichvar
b0f5024d56 nts: log details about failed certificate verification 2020-07-09 14:46:57 +02:00
Miroslav Lichvar
eae4b2abe5 ntp: drop precompensation of TX timestamp
The daemon transmit timestamps are precompensated for the time it takes
to generate a MAC using a symmetric key (as measured on chronyd start)
and also an average round-trip time of the Samba signing of MS-SNTP
responses. This improves accuracy of the transmit timestamp, but it
has some issues.

The correction has a random error which is changing over time due to
variable CPU frequency, system load, migration to a different machine,
etc. If the measured delay is too large, the correction may cause the
transmit timestamp to be later than the actual transmission. Also, the
delay is measured for a packet of a minimal length with no extension
fields, and there is no support for NTS.

Drop the precompensation in favor of the interleaved mode, which now
avoids the authentication delay even when no kernel/hardware timestamps
are available.
2020-07-09 14:46:57 +02:00
Miroslav Lichvar
ff03b813b0 ntp: get TX timestamp after authentication
If the daemon transmit timestamp is saved for processing of a future
response or responding in the interleaved mode, get a more accurate
timestamp right before calling NIO_SendPacket(). Avoid unnecessary
reading of the clock for the transmit timestamp in the packet (i.e.
in interleaved modes and client basic mode).

This should improve accuracy and stability when authentication is
enabled in the client and symmetric basic modes and also interleaved
modes if kernel/hardware timestamps are not available.
2020-07-09 14:46:53 +02:00
Miroslav Lichvar
4e747da4b4 ntp+cmdmon: fix responding to link-local addresses
After commit e49aececce ("socket: don't set interface for sent
packets") the NTP and cmdmon server stopped responding to requests from
link-local addresses.

Set the interface specifically for packets sent to a link-local address.
2020-07-01 16:19:44 +02:00
Miroslav Lichvar
99e3c67a81 socket: add support for selecting interface again
Revert commit e49aececce ("socket: don't set interface for sent
packets") to allow the interface to be selected for outgoing packets,
but don't set it in the callers yet.
2020-07-01 16:19:44 +02:00
Miroslav Lichvar
c4a2550518 conf: add directives to specify interfaces for binding sockets
Add binddevice, bindacqdevice, and bindcmddevice directive to specify
the interface for binding the NTP server, NTP client, and command socket
respectively.
2020-07-01 16:19:44 +02:00
Miroslav Lichvar
4ef944b734 socket: add support for binding sockets to device
As a Linux-specific feature, allow sockets to be bound to a device using
the SO_BINDTODEVICE socket option. The CAP_NET_RAW capability is
required for setting the option.
2020-07-01 16:19:44 +02:00
Robert Fairley
0f04baeb97 examples: align onoffline with DHCP NM dispatcher
Similar to the DHCP dispatcher, add a variable for the chronyc
executable path, which can be overwritten more easily by
downstream packages if needed.

Also give an `.onoffline` suffix to more clearly differentiate
this script from `chrony.nm-dispatcher.dhcp`.
2020-06-29 17:43:49 +02:00
Robert Fairley
bf7f63eaed examples: add dispatcher for NTP servers from DHCP
Add new NM dispatcher script for NTP servers given by DHCP through
NetworkManager in a similar way to how distributions have done in
11-dhclient, e.g. [1]. New NTP servers are written as entries to a
file per-interface in /var/run/chrony-dhcp, which is re-read by
chronyd upon executing `chronyc reload sources`.

This provides a way for NTP server configuration to be carried over
from NetworkManager DHCP events to chrony, for DHCP clients other
than dhclient. Part of fixing integration where the NetworkManager
internal client is used, e.g [2].

Paths to the chronyc executable and sources directory are set in
variables, which may be overwritten by downstream packages, but
should work for distributions for the most part.

[1] https://src.fedoraproject.org/rpms/dhcp/blob/master/f/11-dhclient
[2] https://bugzilla.redhat.com/show_bug.cgi?id=1800901
2020-06-29 17:43:49 +02:00
Miroslav Lichvar
59cf4e0b96 nameserv: don't return scoped IPv6 addresses
Ignore IPv6 addresses returned by getaddrinfo() that have a non-zero
scope ID to avoid silently ignoring the ID if it was specified with the
% sign in the provided string.

This can be removed when the scope ID is returned from the function and
the callers handle it.
2020-06-29 17:43:35 +02:00
Miroslav Lichvar
3fc72c0cfa ntp: fix comment about find_slot() 2020-06-29 16:46:05 +02:00
Miroslav Lichvar
ad69f4f32b configure: link with libnssutil3 for NSS hash support
With recent NSS versions, the NSS low hash initialization seems to fail
unless the executable is linked with the libnssutil3 library.
2020-06-25 12:43:25 +02:00
Miroslav Lichvar
81c2b2e886 socket: handle negative sa_length
As the type of the sa_length parameter is signed, negative values
should be handled as invalid.
2020-06-25 12:43:25 +02:00
Miroslav Lichvar
c9f03fb222 logging: handle too many file logs
Don't rely on an assert to catch insufficient maximum number of file
logs (e.g. after introducing a new file log).
2020-06-25 12:43:25 +02:00
Miroslav Lichvar
b0fe443632 ntp: rework initial burst
Instead of making the initial burst only once and immediately after
chronyd start (even when iburst is specified together with the offline
option), trigger the burst whenever the connectivity changes from
offline to online.
2020-06-25 12:42:57 +02:00
Miroslav Lichvar
8882fb21e0 example: update chrony.conf examples
Add some new directives, remove dumponexit (it's a no-op), remove
broadcast (to not encourage its use), fix a typo, and remove a
OS-specific limitation.
2020-06-25 12:39:15 +02:00
Miroslav Lichvar
7d551d34a0 test: update cmdmon and chronyc tests with new commands 2020-06-17 15:59:29 +02:00
Miroslav Lichvar
feef0dd983 ntp: reduce poll adjustment with specific failed tests
Reduce the poll increment for measurements that are rejected due to a
failed maxdelay* test in order to better track the source.
2020-06-17 15:59:29 +02:00
Miroslav Lichvar
d29f7b7c70 nts: warn about missing NTS support
Log a warning message if an NTP source is specified with the nts option
and the request fails due to missing NTS support.
2020-06-17 15:59:29 +02:00
Miroslav Lichvar
e3cd248f0d nts: update NTS-KE port number
The port assigned by IANA for NTS-KE is 4460.
2020-06-17 15:59:18 +02:00
Miroslav Lichvar
27e20a568b socket: enable only specified IP families
Allow an IP family to be specified in the socket initialization in order
to globally disable the other family. This replaces the ntp_io and
cmdmon code handling the -4/-6 options and fixes a case where the NTP
client could still use a disabled family if the source was specified
with an IP address.
2020-06-17 15:24:55 +02:00
Miroslav Lichvar
80316de3b8 socket: don't log errors on removing socket
Call unlink() directly to avoid an error log message when a Unix domain
socket cannot be removed (e.g. SOCK refclock created for gpsd in
/var/run).
2020-06-17 15:24:55 +02:00
Miroslav Lichvar
f9e2a5852d cmdmon: avoid unsigned shorts
Change unsigned shorts to uint16_t or longer types to avoid any
assumptions about length of the short type.
2020-06-17 15:24:55 +02:00
Miroslav Lichvar
500c9cbf3b ntp: combine parameters of NCR_AddBroadcastDestination() 2020-06-17 15:24:25 +02:00
Miroslav Lichvar
46714fec2d conf: fix missing format string
Fixes: 519796de37 ("conf: add sourcedirs directive")
2020-06-10 15:55:32 +02:00
Miroslav Lichvar
e1d9a57bd0 conf: reset global pointers after parsing line
Don't leave dangling pointers in CNF_ParseLine().
2020-06-10 15:36:40 +02:00
Miroslav Lichvar
1b82604f61 main: add option to print configuration
Add -p option to chronyd to print lines from the configuration as they
are parsed and exit. It can be used to verify the syntax and get the
whole configuration when it is split into multiple files.
2020-06-10 14:10:59 +02:00
Miroslav Lichvar
d69ac07183 cmdmon: add reload sources command
Add the command which reloads the files from the directories specified
by the sourcedirs directive.
2020-06-10 13:56:43 +02:00
Miroslav Lichvar
519796de37 conf: add sourcedirs directive
Add a new directive to include configuration files that only specify NTP
sources and which will be possible to reload with a chronyc command.
2020-06-10 13:56:43 +02:00
Miroslav Lichvar
ea4811b3b3 conf: detect truncated lines
If the buffer filled by fgets() is full, indicating it might not contain
the whole line, abort with a fatal message.
2020-06-10 13:56:43 +02:00
Miroslav Lichvar
951f14ae06 ntp: add configuration ID to sources
Provide an ID for each configured NTP source to enable tracking and
removing of its corresponding sources, even after they change their
address.
2020-06-10 13:56:43 +02:00
Miroslav Lichvar
428f9e4228 test: disable object dependencies in main makefile
When the main makefile is used to get the list of chronyd objects in
order to build the unit tests, clang started (with the -MM option) to
generate the dependency files prints error messages about wrong
inclusions. Set a NODEPS variable to completely disable the generation
of the files.
2020-06-08 15:27:57 +02:00
Miroslav Lichvar
ea425bf01e client: add tab-completition for authdata command 2020-06-04 14:50:17 +02:00
Miroslav Lichvar
8567a0e466 client: add verbose text to authdata command 2020-06-04 14:50:17 +02:00
Miroslav Lichvar
f6bf12bdcd test: extend siv unit test 2020-06-04 14:50:17 +02:00
Miroslav Lichvar
e8968ea429 siv: add gnutls support
Add support for the AES-SIV-CMAC cipher in gnutls using the AEAD
interface. It should be available in gnutls-3.6.14.

This will enable NTS support on systems that have a pre-3.6 version of
Nettle, without falling back to the internal SIV implementation.
2020-06-04 14:50:17 +02:00
Miroslav Lichvar
cf10ce1b68 nts: allow missing SIV support
When compiled with NTS support, don't require a SIV cipher to be always
supported (e.g. due to a different version of a library used for
building). Handle this case with a fatal message instead of crash.
Also, check the support early in the client unit test to prevent a hang.
2020-06-04 14:50:17 +02:00
Miroslav Lichvar
15dc83420d test: fix sources unit test
Use different source addresses, fix a debug message and a memory leak.
2020-06-04 14:50:17 +02:00
Miroslav Lichvar
37dbc211cd sources: add more assertions 2020-06-04 14:50:17 +02:00
Miroslav Lichvar
ed78cda6ad sources: check for negative distance
This is not expected to happen, but make sure the endpoints of each
source are in the right order (i.e. the distance is not negative) to
prevent getting a negative depth in the selection.
2020-06-04 14:50:17 +02:00
Miroslav Lichvar
faff931a76 sources: require majority for trusted sources
Handle trusted sources as a separate set of sources which is required to
have a majority for the selection to proceed. This should improve the
selection with multiple trusted sources (e.g. due to the auth selection
mode).
2020-06-04 14:50:17 +02:00
Miroslav Lichvar
1e68671690 sources: relax selection of non-trusted sources
When the selection has some trusted sources, don't require non-trusted
sources to be contained in the best interval as that can usually pass
only one source if the best interval is the interval of the source, or
no source at all if the best interval is an intersection of multiple
sources.

Relax the requirement for non-trusted sources to be contained in the
best interval of trusted sources alone instead of all sources in the
trusted interval.
2020-06-04 14:50:17 +02:00
Miroslav Lichvar
8eb167fd21 sources: extend mark debug message 2020-06-04 14:50:17 +02:00
Miroslav Lichvar
bc46174e98 sources: include hostname in selection log message
When selecting an NTP source, include the hostname in the log message.
2020-06-04 14:50:17 +02:00
Miroslav Lichvar
b86c89460a cmdmon: update protocol changelog 2020-06-04 14:50:17 +02:00
Miroslav Lichvar
03541f3626 cmdmon: add selectdata command
Add a command to report selection-specific data.
2020-06-04 14:40:18 +02:00
Miroslav Lichvar
39a462496a cmdmon: don't report selection options in source report
The selection options returned as flags are not reported by the
client and will be better reported in a separate command with other
selection-specific data.
2020-06-02 08:53:56 +02:00
Miroslav Lichvar
7ba8994838 client: fix help message to indicate mask is optional 2020-05-25 17:58:53 +02:00
Miroslav Lichvar
8da025da99 test: add 140-noclientlog test 2020-05-21 16:19:59 +02:00
Miroslav Lichvar
5dc7242703 clientlog: fix check for ratelimit and noclientlog
Fixes: 3a2d33d5a3 ("clientlog: refactor client record and API")
2020-05-21 16:07:52 +02:00
Miroslav Lichvar
11bffa0d55 doc: improve answer for chronyc error in FAQ 2020-05-21 12:42:20 +02:00
Miroslav Lichvar
5f6f265f80 local: don't remove handlers in finalization
Require all handlers to be deregistered by their users before the local
finalization.
2020-05-21 12:42:18 +02:00
Miroslav Lichvar
bf92314dc4 test: check logs for assertion failures 2020-05-21 12:42:18 +02:00
Miroslav Lichvar
a3fda9f992 nts: free client cert credentials when not used
Destroy the client cert credentials when destroying the last NKC
instance instead of NKC_Finalise(). This allows the client to reload the
trusted cert file between NTS-KE sessions.
2020-05-21 12:42:18 +02:00
Miroslav Lichvar
cd34b377aa nts: add debug messages for gnutls init/deinit 2020-05-21 12:42:18 +02:00
Miroslav Lichvar
145423068b ntp: change NSR_RemoveSource() to accept IP address only
Change the function to accept IP address alone to make it clear that the
port is ignored.
2020-05-21 12:42:18 +02:00
Miroslav Lichvar
fb4c3f31c0 ntp: refactor slot finding
Change the find_slot() function to not match port and return the found
status directly. Add a separate function for matching both address and
port.
2020-05-21 12:42:18 +02:00
Miroslav Lichvar
60049f1551 conf: replace empty strings with NULL
Avoid mixing empty strings with NULLs in configuration strings to make
the handling of default or disabled values consistent.
2020-05-21 12:42:18 +02:00
Miroslav Lichvar
e555548dda reference: fix offset sign in log message
In the maxchange check, log the original offset instead of the absolute
value.
2020-05-21 12:20:11 +02:00
Miroslav Lichvar
eedf61b3a2 clientlog: add debug message for maximum number of records 2020-05-21 12:20:11 +02:00
Miroslav Lichvar
ab54f76a38 cmdmon: report new client and server statistics
Report the new clientlog data in the clients and serverstats reports.

Add -k option to the clients command to select between command and
NTS-KE data.
2020-05-21 12:20:08 +02:00
Miroslav Lichvar
f8df4789b1 clientlog: count authenticated NTP requests 2020-05-21 12:01:39 +02:00
Miroslav Lichvar
6366ebc17e clientlog: add NTS-KE service
Instead of sharing the NTP rate limiting with NTS-KE, specify a new
service for NTS-KE and use it in the NTS-KE server.

Add ntsratelimit directive for configuration.
2020-05-21 12:01:39 +02:00
Miroslav Lichvar
3a2d33d5a3 clientlog: refactor client record and API
Refactor the client record and clientlog API to reuse more code between
different services and enumerate the services instead of hardcoding NTP
and cmdmon.
2020-05-21 12:01:37 +02:00
Miroslav Lichvar
1afd5b23d7 clientlog: fix time_t variables
The last_hit and oldest_hit timestamps are uint32_t, not time_t.
2020-05-21 11:50:04 +02:00
Miroslav Lichvar
17fb9e3709 stubs: add NSR_GetAuthReport()
Fixes: 79c7384e5e ("cmdmon: add authdata command")
2020-05-21 11:50:04 +02:00
Vincent Blut
7a7295992f sys_linux: allow some *time64 syscalls in seccomp filter
These are needed for 32-bit architectures with new system calls using
64-bit time_t.
2020-05-18 17:39:22 +02:00
Vincent Blut
526974366f sys_linux: restructure syscalls in seccomp filter
Having one syscall per line improves the seccomp filter reading. It
should also make updates more straightforward.
2020-05-18 17:39:22 +02:00
Miroslav Lichvar
51fe589aeb cmdmon: add cookie length to authdata report 2020-05-18 17:39:22 +02:00
Miroslav Lichvar
28cf4acf13 cmdmon: limit reported clients by number of packets
Add a new field to the CLIENT_ACCESSES_BY_INDEX request to specify the
minimum number of NTP or cmdmon packets for a client to be reported.

Add -p option to the chronyc clients command to specify the threshold
(by default 0). This option can be used to minimize the number of cmdmon
requests when interested only in clients sending a large number
of requests.
2020-05-18 17:39:22 +02:00
Miroslav Lichvar
ee2220f2e7 cmdmon: allow client records to be reset
Add a flag to the CLIENT_ACCESSES_BY_INDEX request to reset the
NTP/cmdmon hits/dropped counters after reporting the current values.

Add -r option to the chronyc clients command to perform the reset. This
should make it easier to find clients that send large number of requests
over short periods of time.
2020-05-18 17:39:18 +02:00
Miroslav Lichvar
a6ec6ec3ac sources: ignore noselect sources when updating selection options
Ignore any sources specified with the noselect option with respect to
the auth selection mode.
2020-05-18 17:38:09 +02:00
Miroslav Lichvar
4f5343f086 doc: fix formatting of example in chrony.conf man page 2020-05-14 15:37:38 +02:00
Miroslav Lichvar
79c7384e5e cmdmon: add authdata command
Add a command to display information about authentication of NTP
sources.
2020-05-14 15:37:38 +02:00
Miroslav Lichvar
75beeaf2b0 nts: assign ID to NTS context
For monitoring purposes, assign an incrementing ID to the client NTS
context.
2020-05-14 15:37:38 +02:00
Miroslav Lichvar
f4ed2abdca keys: provide key type and length
Save the type and length of each key and add a function to get this
information.
2020-05-14 15:37:38 +02:00
Miroslav Lichvar
11a5c7337a keys: remove forgotten declaration 2020-05-14 15:37:38 +02:00
Miroslav Lichvar
972c476c5a cmac: enumerate cipher algorithms
Identify the CMAC ciphers with an enum instead of string.
2020-05-14 15:37:38 +02:00
Miroslav Lichvar
a8c8f2f309 hash: enumerate hash algorithms
Identify the algorithms with an enum instead of string.
2020-05-14 15:37:38 +02:00
Miroslav Lichvar
a0d2513be6 cmdmon: fix ntp_source_name declaration in request
Fixes: 93f6358916 ("cmdmon: add request to get source name")
2020-05-14 15:37:38 +02:00
Miroslav Lichvar
43dc0b3295 cmdmon: rename reset command to reset sources
Add a sources option for the reset command in case there are other
components that would need to be reset.
2020-05-14 15:37:38 +02:00
Miroslav Lichvar
195ff5c51b reference: shorten logchange log message
Remove the "adjustment started" part from the "System clock wrong by *
seconds, adjustment started" log message as it might be confusing in
some cases. There may be a step instead of a slow adjustment, or there
may be no adjustment at all when running with the -x option.
2020-05-14 15:37:38 +02:00
Miroslav Lichvar
e49aececce socket: don't set interface for sent packets
With asymmetric routing (e.g. with BGP) it may not be possible to
respond to a request using the same interface. In such case, setting the
interface index in IP*_PKTINFO* causes the packet to be silently dropped
by the kernel.

Until we can predict if sending with the specified interface will
succeed, or provide only a hint, don't set the interface and leave it
to the kernel to select an interface.

This reverts commit 5fc7674e36 ("ntp: set interface index in
IP*_PKTINFO when responding").

Reported-by: Arkadiusz Miśkiewicz <arekm@maven.pl>
2020-05-14 15:37:38 +02:00
Miroslav Lichvar
814b07c3a2 conf: detect infinite inclusion
Don't allow more than 10 nested inclusions using the include or
confdirs directive to cleanly handle a misconfiguration with a circular
inclusion.
2020-05-14 15:37:38 +02:00
Miroslav Lichvar
3470ab66f0 conf: add better support for fragmented configuration
Add a confdirs directive to include *.conf files from multiple
directories. If a file with the same name exists in multiple
directories, only the first one in the order of the specified
directories will be included.
2020-05-14 15:37:38 +02:00
Miroslav Lichvar
6901df5c18 sources: improve and add more debug messages 2020-05-14 15:37:38 +02:00
Miroslav Lichvar
bddb3b3228 sources: enable selection options with authentication
When authentication is enabled for an NTP source, unauthenticated NTP
sources need to be disabled or limited in selection. That might be
difficult to do when the configuration comes from different sources
(e.g. networking scripts adding servers from DHCP).

Define four modes for the source selection to consider authentication:
require, prefer, mix, ignore. In different modes different selection
options (require, trust, noselect) are added to authenticated and
unauthenticated sources.

The mode can be selected by the authselectmode directive. The mix mode
is the default. The ignore mode enables the old behavior, where all
sources are used exactly as specified in the configuration.
2020-05-14 15:37:38 +02:00
Miroslav Lichvar
dfe877144a sources: allow modifications of selection options
Refactor the code to allow the selection options of the current sources
to be modified when other sources are added and removed. Also, make the
authentication status of each source available to the code which makes
the modifications.
2020-05-14 15:37:38 +02:00
Miroslav Lichvar
59a9b7a9f6 sources: reformat forward prototypes 2020-05-14 15:37:38 +02:00
Miroslav Lichvar
ad8fb64276 doc: improve NEWS
Add a notable enhancement from 4.0-pre1 and make the description of
another enhancement less ambiguous.
2020-04-20 15:49:58 +02:00
Miroslav Lichvar
436c1d3ea2 doc: update README 2020-04-20 15:44:12 +02:00
Miroslav Lichvar
7fc5da5f80 check return value of SCK_OpenUnixSocketPair() 2020-04-20 15:44:12 +02:00
Miroslav Lichvar
105b3faa46 samplefilt: remove useless assignment 2020-04-20 15:44:12 +02:00
Miroslav Lichvar
709223826f doc: update documentation for recent NTS changes 2020-04-16 18:09:32 +02:00
Miroslav Lichvar
eace93f2af nts: allow disabling certificate time checks
Add "nocerttimecheck" directive to specify the number of clock updates
that need to be made before the time validation of certificates is
enabled. This makes NTS usable on machines that don't have a RTC.
2020-04-16 18:09:32 +02:00
Miroslav Lichvar
2775846db7 nts: provide time function to gnutls
Use the internal time instead of system time for validation checks in
gnutls.
2020-04-16 18:09:29 +02:00
Miroslav Lichvar
4aff08e95d nts: add server support for NTP server negotiation
Add ntsntpserver directive to specify the hostname of the NTP server
provided in NTS-KE response to clients.
2020-04-16 17:47:27 +02:00
Miroslav Lichvar
958d66f8a7 cmdmon: reload NTS server keys on rekey command
When ntsrotate is set to 0, allow the keys to be reloaded with the rekey
command of chronyc.
2020-04-16 15:25:51 +02:00
Miroslav Lichvar
85fa29c43d nts: enable external management of server keys
If ntsrotate is set to 0, don't generate new server keys and don't save
them to ntsdumpdir. This allows the keys to be managed externally and
shared with other servers.
2020-04-16 15:25:50 +02:00
Miroslav Lichvar
0344b9a9c9 nts: generate cookies from second newest key
Generate one server key in advance to give it time to be distributed to
other servers before it is actually used.
2020-04-16 15:23:25 +02:00
Miroslav Lichvar
04f6329773 nts: encode key ID in cookie in network order
This allows the server cookie to be decoded on different platforms.
2020-04-15 16:30:54 +02:00
Miroslav Lichvar
d690faeb19 cmdmon: save NTS cookies and server keys on dump command
Extend the dump command to save also the server NTS keys and client NTS
cookies. Remove the warning for unset dumpdir.
2020-04-15 16:30:54 +02:00
Miroslav Lichvar
0b2e77ae64 ntp: update auth-specific address sooner
When replacing an NTP source, update the NTS address before the NTP
address to save cookies with the old NTP address instead of the newly
resolved address (which may immediately change to an address provided by
NTS-KE).
2020-04-15 16:30:54 +02:00
Miroslav Lichvar
2a4fd0a5c6 nts: update TLS exporter label
Change the string to "EXPORTER-network-time-security" as specified in
the latest NTS draft.
2020-04-09 17:08:52 +02:00
Miroslav Lichvar
e569e1c9d9 test: extend 139-nts test 2020-04-09 17:08:52 +02:00
Miroslav Lichvar
7be360041c nts: extend server key file format
Include in the key dump file an identifier, the AEAD number, and the
age of the last key to improve robustness and avoid generating a new key
immediately on start.

Also, improve the code that saves and loads the file.
2020-04-09 17:08:46 +02:00
Miroslav Lichvar
2fa83b541c nts: save and load cookies on client
Save the NTS context and cookies to files in the NTS dumpdir when the
client NTS instances are destroyed or the address is changed, and reload
the data to avoid unnecessary NTS-KE requests when chronyd is restarted
or it is switching between different addresses resolved from the NTS-KE
or NTP name.
2020-04-09 16:57:32 +02:00
Miroslav Lichvar
8db9d59dac nts: rename ntscachedir directive to ntsdumpdir
This makes the naming consistent with the existing dumpdir directive and
the dump command.
2020-04-09 16:57:32 +02:00
Miroslav Lichvar
adcf073484 nts: refactor NTS context
Add a context structure for the algorithm and keys established by
NTS-KE. Modify the client to save the context and reset the SIV key to
the C2S/S2C key before each request/response instead of keeping two SIV
instances.

This will make it easier for the server to support different algorithms
and allow the client to save the context with cookies to disk.
2020-04-09 16:57:31 +02:00
Miroslav Lichvar
5296858411 nts: drop unused constant 2020-04-09 16:42:20 +02:00
Miroslav Lichvar
d603426389 util: add function to split string into words 2020-04-09 16:42:20 +02:00
Miroslav Lichvar
d3f4292968 util: constify input parameters 2020-04-09 16:42:20 +02:00
Miroslav Lichvar
4dde7198c8 sources: constify parameters of log_selection_message() 2020-04-09 16:42:20 +02:00
Miroslav Lichvar
b145d3ff51 doc: add sourcename to list of remote commands 2020-04-09 16:42:20 +02:00
Miroslav Lichvar
9b98247d9c nts: zero cookie placeholder
Zero the body of the cookie placeholder in client requests as
recommended by the latest NTS draft.
2020-03-26 15:30:34 +01:00
Miroslav Lichvar
eedabb3d27 nts: disable TLS version 1.2
Require TLS version 1.3 or later as specified in the latest NTS draft.
2020-03-26 15:30:27 +01:00
Miroslav Lichvar
66dc2b6d6b nts: rework NTS-KE retry interval
Make the NTS-KE retry interval exponentially increasing, using a factor
provided by the NKE session. Use shorter intervals when the server is
refusing TCP connections or the connection is closed or timing out
before the TLS handshake.
2020-03-26 15:30:27 +01:00
Miroslav Lichvar
bcdbbbd694 nts: include server address in client NTS-KE log messages 2020-03-26 15:30:27 +01:00
Miroslav Lichvar
7b07e47c08 nts: fix address in server NTS-KE log messages
The server session instances are reused for different clients. Separate
the server name from the label used in log messages and set it on each
start of the session.
2020-03-26 15:30:27 +01:00
Miroslav Lichvar
a608496faf ntp: fix log message for replaced source
When a source was replaced and the new source had the same slot as the
old source, a wrong message was logged. Fix the condition to distinguish
correctly between changed address and port.

Fixes: 9468fd4aa6 ("ntp: allow changing port of source")
2020-03-26 15:26:58 +01:00
Miroslav Lichvar
c687224a11 reference: improve check for close leap second
Improve the check to work with the actual timestamp of the leap second
instead of the closest midnight and don't turn it off on the leap
timeout. Also allow sample times to be checked in addition to the system
time and NTP time to avoid accumulation of samples mixing pre-leap and
post-leap timestamps (causing error of +/-0.5 or +/-1.0 seconds).
2020-03-26 11:10:08 +01:00
Miroslav Lichvar
a6f2a613f3 socket: remove obsolete comment 2020-03-26 11:06:54 +01:00
Miroslav Lichvar
cfa39af345 socket: fix severity check in debug logging
Don't waste time formatting the debug message in log_message() when
debug output is disabled.

Fixes: 86a3ef9ed1 ("socket: add new socket support")
2020-03-26 11:06:54 +01:00
Miroslav Lichvar
8bab35c122 socket: increase maximum number of received messages
The buffers are no longer on stack. Increase their number for better
performance on heavily loaded servers.
2020-03-26 11:06:54 +01:00
Miroslav Lichvar
b20ef4cd7f socket: simplify receiving messages
Don't require the caller to provide a SCK_Message (on stack). Modify the
SCK_ReceiveMessage*() functions to return a pointer to static buffers,
as the message buffer which SCK_Message points to already is.
2020-03-26 11:04:18 +01:00
Miroslav Lichvar
b8b751a932 socket: enable port sharing on Linux
On Linux, enable the SO_REUSEPORT option on sockets bound to a port in
order to support load balancing with multiple chronyd instances
(configured to not adjust the system clock).

The IP_FREEBIND option already allowed different instances to bind to
the same address and port, but only one was actually receiving packets.

As the instances don't share their state, sharing the NTP port doesn't
work well with the interleaved mode, symmetric mode, and rate limiting.

Sharing the NTS-KE port will not work until the server keys can be
derived from a shared key.
2020-03-24 16:29:33 +01:00
Miroslav Lichvar
4a390841eb doc: fix typo in smoothtime description 2020-03-19 17:03:25 +01:00
David Bohman
f506f44033 sys_macosx: fix build issue on Sierra and presumably earlier 2020-03-18 12:23:26 +01:00
Miroslav Lichvar
1f8355f154 test: make 139-nts more reliable 2020-03-18 12:23:26 +01:00
Miroslav Lichvar
ddc2761498 doc: fix typo in NEWS 2020-03-16 18:34:26 +01:00
Miroslav Lichvar
8b50a8298a doc: update NEWS 2020-03-16 13:16:14 +01:00
Bryan Christianson
3eab329042 sys_macosx: don't require clock_gettime()
Earlier versions of macOS do not provide clock_gettime(). This patch
checks for clock_gettime() at run-time and falls back to gettimeofday()
if the symbol is not present.
2020-03-16 11:35:56 +01:00
Miroslav Lichvar
552d3b53b1 main: accept zero timeout
Allow -t to specify zero timeout to exit immediately. It might be
useful for testing.
2020-03-12 14:25:21 +01:00
Miroslav Lichvar
8afd62d954 reference: update synchronization status more frequently
Update the local clock errors with each update of the leap status to
avoid the kernel marking the clock as unsynchronized when a large
number of NTP samples is dropped.
2020-03-12 14:07:12 +01:00
Miroslav Lichvar
4883086fc1 sources: update reference leap status early
When a leap second status is updated by a source, don't wait for the
next source selection and full update of the reference. Count votes from
sources that passed the previous selection and update the reference leap
status directly.

This should allow leap seconds to spread quickly even when the
samples are dropped or delayed by the filters.
2020-03-12 14:07:12 +01:00
Miroslav Lichvar
2582be8754 sources: separate update of leap status
Remove leap status from the NTP sample and set it independently from
the sample accumulation in order to accept a leap second sooner when
samples are filtered.
2020-03-12 14:07:12 +01:00
Miroslav Lichvar
ff9301567e sourcestats: move leap status to sources 2020-03-12 12:09:50 +01:00
Miroslav Lichvar
e7a254265f cmdmon: add reset command
The reset command drops all measurements and switches the reference 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).
2020-03-12 12:09:50 +01:00
Miroslav Lichvar
d5311adafb doc: fix tag in chronyc man page 2020-03-12 12:09:50 +01:00
Miroslav Lichvar
18d7ea62b3 reference: don't report synchronized status after unknown step
The source handler resets SST instances on an unknown step, which
makes the sources unselectable, but SRC_SelectSource() doesn't call
REF_SetUnsynchronised() when no source is selectable.

Handle the step in the reference handler.

Fixes: 049eae661a ("sources: keep synchronized status with unreachable/unselectable sources")
2020-03-12 12:09:50 +01:00
Miroslav Lichvar
fb2849b230 reference: convert to monotonic time
Calculate the update interval and drift file age from increments in the
monotonic time instead of real time.
2020-03-12 12:09:50 +01:00
Miroslav Lichvar
fd59877692 nts: convert to monotonic time
Use the monotonic timestamp provided by the scheduler for NTS-KE rate
limiting and refresh.
2020-03-12 12:09:50 +01:00
Miroslav Lichvar
bb0553e4c4 sched: provide low-precision monotonic time
Measure the interval since the start in order to provide a monotonic
time for periodical tasks not using timers like driftfile updates, key
refresh, etc. Return the interval in the double format, but keep an
integer remainder limiting the precision to 0.01 second to avoid issues
with very small increments in a long-running process.
2020-03-12 12:09:49 +01:00
Miroslav Lichvar
46f954490d configure: improve nettle and gnutls check
Before enabling NTS, check for more gnutls functions (some added in
3.6.3) to avoid build failures with older gnutls versions. Also, make
sure that nettle supports the new AES interface (added in 3.0).
2020-03-10 15:52:28 +01:00
Miroslav Lichvar
31e6a50386 doc: add missing dependencies to installation document 2020-03-10 11:16:23 +01:00
Miroslav Lichvar
9a9c0d7b99 configure: improve pkg-config support 2020-03-10 11:16:23 +01:00
Miroslav Lichvar
0c80f00d0b doc: update description of on/offline commands 2020-03-09 13:05:02 +01:00
Miroslav Lichvar
27b3bf48ea ntp: ignore onoffline command for unresolved sources
The onoffline command switches an unresolved source to the offline
status, even when the network is already up.

Ignore the onoffline command for unresolved sources to prevent sources
unexpectedly staying in the offline status, e.g. when the command is
issued from a network dispatcher script (and no other call is expected
later when the name is resolved).
2020-03-09 13:02:23 +01:00
Miroslav Lichvar
c3e34b8145 doc: update installation document 2020-03-05 16:02:15 +01:00
Miroslav Lichvar
7bf3ec4aeb doc: describe NTS directives and options 2020-03-05 16:02:15 +01:00
Miroslav Lichvar
50204a125b test: add nts unit tests 2020-03-05 16:02:15 +01:00
Miroslav Lichvar
111d170542 test: update compilation tests 2020-03-05 16:02:15 +01:00
Miroslav Lichvar
d6dd6f0bc9 test: add 139-nts test 2020-03-05 16:02:15 +01:00
Miroslav Lichvar
44aac84feb cmdmon: add NTS support
Allow the nts and ntsport options to be specified for sources added from
chronyc. This is an incompatible change in the request, but there was no
release using the new REQ_ADD_SOURCE command yet.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
c41508723f ntp: enable NTS support
Add an option to enable NTS for an NTP source. Check for NTS-specific
extension fields and pass the packets to the NTS-NTP code in order to
enable the NTS client and server.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
6043632f80 nts: add NTS-NTP server and client
Add support for the NTS NTP extension fields.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
a420ed57a1 nts: add NTS-KE server and client
Add a client and server implementing the Network Time Security (NTS) Key
Establishment. Use the GnuTLS library for TLS.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
72f99033fe test: add siv unit test 2020-03-05 16:02:15 +01:00
Miroslav Lichvar
2d798bc4cf siv: add internal implementation based on Nettle
This adds an internal implementation of the AES-SIV-CMAC-256 cipher
based on GNU Nettle and the following patch (which was later reworked
and included in Nettle):

https://gitlab.com/gnutls/gnutls/uploads/1ab02c51e317264f9dba07ddfbc01d9a/0001-Added-support-for-AES_SIV_CMAC_256-and-AES_SIV_CMAC_.patch

This implementation will be dropped when the cipher is widely supported
by gnutls or Nettle.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
881d07fa0a siv: add support for Nettle 2020-03-05 16:02:15 +01:00
Miroslav Lichvar
c5306bed39 siv: introduce API for SIV
Add a header file for Synthetic Initialization Vector (SIV) cipher mode,
which will be used by NTS.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
934b8712a5 sys_linux: allow getuid() in seccomp filter
This will be needed by gnutls when loading certificates.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
1d4690eb64 sys_linux: add syscall filter context for NTS-KE
The NTS-KE helper process will use a more restrictive filter than the
main process.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
e6848b1e3f sys: specify context for syscall filter
Specify a context to enable different processes using different (more
restrictive) syscall filters.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
3e537416a9 sched: remove slew handler in finalization
This allows repeated calls of SCH_Initialise() and SCH_Finalise().
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
26a1ed8bc3 sched: add function to remove all timers and descriptors
This allows a helper process to be started in an *_Initialise() call
and use the scheduler (unlike the privops helper, which has its own
loop).
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
24538fe3e9 nameserv: allow concurrent asynchronous requests
Allow multiple resolving threads to be running at the same time in order
to support multiple callers, but use a mutex to avoid sending multiple
requests to the privops helper. This will be needed for the NTS-KE
server negotiation.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
e43d699973 util: add functions for printing and parsing hexadecimal data 2020-03-05 16:02:15 +01:00
Miroslav Lichvar
1e727c4497 sources: don't reset active status
Avoid resetting the active status when an NTP source changes its
address in NCR_ChangeRemoteAddress().

This will allow an NTP source to update its address with NTS-KE
hostname negotiation and continue in a special reference mode
(e.g. -q/-Q option).
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
83010590af ntp: move definition of invalid stratum to ntp.h 2020-03-05 16:02:15 +01:00
Miroslav Lichvar
fa402a173a ntp: pass server name to ntp_core instances
The server name will be needed for certificate verification in NTS-KE.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
ca83d2a804 test: add ntp_ext unit test 2020-03-05 16:02:15 +01:00
Miroslav Lichvar
725beb360a ntp: add functions for adding extension fields 2020-03-05 16:02:15 +01:00
Miroslav Lichvar
86d29221f3 ntp: add function to change authentication-specific address
When an NTS source will be replaced, the authentication-specific address
of the NTS-KE server will need to be changed too.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
e8062b7ff1 ntp: add function to update source NTP address
This will allow a source to have its address changed due to NTS-KE
server negotiation, which allows the NTS-KE server to have a different
address than the NTP server.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
9468fd4aa6 ntp: allow changing port of source
Modify the replace_source() function to not require a different IP
address when replacing a source with the same address but different
port. This will enable the NTS-KE port negotiation.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
5ed9b888ff ntp: don't accept packets with unexpected authentication
If authentication is not enabled in configuration, responses are not
expected to be authenticated. Handle such responses as having failed
authentication.

A case where this could happen is a misconfigured symmetric association
where only one peer has specified the other with a key. Before this
change synchronization would work in one direction and used packets
with an asymmetric length.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
7661a6e95b ntp: don't allow long MACs in NTPv4 packets with extension fields
MAC longer than 24 octets in NTPv4 packet is supported only for
compatibility with some pre-RFC7822 chrony versions. They didn't use
any extension fields.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
aca1daf7c9 ntp: add support for sending KoD responses
Enable the server to respond with a KoD when authentication fails. This
will be used by NTS to respond with a NAK when a client has expired
cookies.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
46cac4e22f ntp: prefix NTP_AuthMode enums 2020-03-05 16:02:15 +01:00
Miroslav Lichvar
56a102ed4d ntp: move auth parsing to ntp_auth
Move the remaining authentication-specific code to the new file.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
ca28dbd2c3 ntp: refactor authentication
Move most of the authentication-specific code to a new file and
introduce authenticator instances in order to support other
authentication mechanisms (e.g. NTS).
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
588785e160 ntp: rework packet parsing
Rework the code to detect the authentication mode and count extension
fields in the first parsing of the packet and store this information in
the new packet info structure.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
cabcccd6c3 ntp: add functions for parsing extension fields 2020-03-05 16:02:15 +01:00
Miroslav Lichvar
567e66a0bb ntp: count packets with invalid format
Include packets that cannot be parsed in the total RX count.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
b8ee6d6e56 ntp: don't send response longer than request
When sending a response in the server or passive mode, make sure the
response is not longer than the request to prevent amplification
attacks when resposes may contain extension fields (e.g. NTS).
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
9ea1e4e40f ntp: provide access to request in transmit_packet()
This will allow new authentication code (e.g. NTS) to get data from the
request when generating a response.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
2d492eacb5 ntp: rename receive_packet() to process_response() 2020-03-05 16:02:15 +01:00
Miroslav Lichvar
cb8660e79a ntp: add structure with packet info
Add a structure for length and other information about received and
transmitted NTP packets to minimize the number of parameters and avoid
repeated parsing of the packet.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
d29bef93e9 ntp: refactor NTP_Packet structure for extension fields 2020-03-05 16:02:15 +01:00
Miroslav Lichvar
5a09adebfd ntp: don't replace sources with unroutable addresses
When changing an address of a source (both known and unknown), make sure
the new address is connectable. This should avoid useless replacements,
e.g. polling an IPv6 address on IPv4-only systems.
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
8c0ee9c175 doc: list unsupported options in peer directive 2020-03-05 16:02:15 +01:00
Miroslav Lichvar
f20fabdbf4 test: make 132-logchange more reliable 2020-03-05 16:02:15 +01:00
Miroslav Lichvar
57cea56e6e test: extend 001-features test 2020-03-05 16:02:15 +01:00
Miroslav Lichvar
db7d9639b4 test: fix unit tests to build with -NTP and -CMDMON 2020-03-05 16:02:15 +01:00
Miroslav Lichvar
beb40d63ed test: extend 122-xleave test 2020-03-05 16:02:15 +01:00
Miroslav Lichvar
672b98dd3f sources: don't save or load dumpfiles for unknown addresses
Don't open a dumpfile for reading or writing if the NTP source doesn't
have a real address.

Fixes: d7e3ad17ff ("ntp: create sources for unresolved addresses")
2020-03-05 16:02:15 +01:00
Miroslav Lichvar
a24d2713cd client: add option to print all sources
Add -a option to the sources and sourcestats commands to print all
sources, including those that don't have a resolved address yet. By
default, only sources that have a real address are printed for
compatibility. Remove the "210 Number of sources" messages to avoid
confusion. Also, modify the ntpdata command to always print only sources
with a resolved address.
2020-02-19 15:03:20 +01:00
Miroslav Lichvar
a5110d3ed9 client: add support for source identifiers
Allow the new identifiers to be specified as addresses in commands that
modify or remove NTP sources.
2020-02-19 15:03:20 +01:00
Miroslav Lichvar
9d1c1505b9 ntp: repeat resolving until all pool sources are resolved
When resolving of a pool name succeeds, don't remove the remaining
unresolved sources, i.e. try to get all maxsources (default 4) sources,
even if it takes multiple DNS requests.
2020-02-19 15:03:20 +01:00
Miroslav Lichvar
8c25632321 ntp: stop resolving if unresolved source is removed
If an individual unresolved source or all unresolved sources from a pool
are removed, stop resolving their addresses on the next attempt (don't
remove them immediately as the resolver may be running).
2020-02-19 15:03:20 +01:00
Miroslav Lichvar
2507b66640 ntp: update resolving timeout ID
This will allow unresolved sources to be removed before resolving.
2020-02-19 15:03:20 +01:00
Miroslav Lichvar
d7e3ad17ff ntp: create sources for unresolved addresses
Rework the ntp_sources code to create sources for addresses that are not
resolved yet using the new identifiers.
2020-02-19 14:52:03 +01:00
Miroslav Lichvar
84902d0e00 addressing: introduce identifiers for unresolved addresses
Add a new type of address for NTP sources that don't have a resolved
address yet. This will allow the sources to be displayed, modified and
deleted by chronyc.

Update utility functions to support the new addresses.
2020-02-19 11:37:15 +01:00
Miroslav Lichvar
f7f3667bcb addrfilt: explicitly handle unexpected addresses 2020-02-18 16:01:25 +01:00
Miroslav Lichvar
794cbfbbb5 logging: restrict file log permissions
With the new file utility functions permissions can be restricted for
newly created files. For the log file specified by the -l option it
is better to remove the "other" permissions (0640) to make it similar
to the system log.
2020-02-18 16:01:25 +01:00
Miroslav Lichvar
1858104b5c util: don't log unlink() error if file is not accessible
Try stat() before calling unlink() to make sure the file is accessible.

This fixes chronyc running under a non-root/chrony user printing an
error message due to missing permissions on /var/run/chrony before
trying to bind its socket.
2020-02-18 16:01:25 +01:00
Vincent Blut
994409a036 sys_linux: allow renameat2 in seccomp filter
This is needed for architectures that support neither rename() nor
renameat() (e.g. riscv64)
2020-01-20 12:26:54 +01:00
Miroslav Lichvar
2d9eb5b6fa test: fix util unit test for NTP era split
The current default NTP era split passed the Unix epoch (~50 years ago),
which means the epoch converted to an NTP timestamp and back ends up in
the next NTP era (year 2106).

Fix the test to take into account the era split.
2020-01-03 12:01:55 +01:00
Miroslav Lichvar
3477cbe28f stubs: add NSR_GetName()
Fixes: 93f6358916 ("cmdmon: add request to get source name")
2020-01-03 11:47:53 +01:00
Miroslav Lichvar
8634158de0 stubs: update NSR_AddSourceByName()
Fixes: 3763befd62 ("ntp: check name and return status from NSR_AddSourceByName()")
2020-01-03 11:47:53 +01:00
Miroslav Lichvar
3eaf0765b0 client: add missing commands to tab-completion
Reported-by: Lonnie Abelbeck <lonnie@abelbeck.com>
2020-01-03 11:47:53 +01:00
Miroslav Lichvar
dd0679ad45 socket: add function to check supported family
Don't log error when an IPv6 socket cannot be opened and chronyd was
built without IPv6 support.

Reported-by: Lonnie Abelbeck <lonnie@abelbeck.com>
2020-01-03 11:47:41 +01:00
Miroslav Lichvar
bfcd8ecc56 client: add sourcename command
Add a new command to print the original name of a source specified by
address. This could be useful in scripts to avoid having to run the
sources command with and without -N.
2019-12-12 16:17:45 +01:00
Miroslav Lichvar
50e5865c73 client: add option to print original names
Add -N option to chronyc to print the original names by which the
sources were specified instead of using reverse DNS lookup. The option
works in the sources, sourcestats and tracking commands.
2019-12-12 16:17:44 +01:00
Miroslav Lichvar
93f6358916 cmdmon: add request to get source name
Specify a new request to get the name of the NTP source corresponding to
an address, which was originally specified in the configuration file or
chronyc add command.
2019-12-12 16:06:58 +01:00
Miroslav Lichvar
9300854439 cmdmon: add support for adding pool sources
Specify a new type for pool sources and extend the syntax of the chronyc
"add" command to add a pool.
2019-12-12 14:44:03 +01:00
Miroslav Lichvar
02914ac637 cmdmon: specify name instead of address in add request
Modify the request for adding a source to provide the name of the source
instead of its address (resolved in chronyc) in order to enable chronyd
to replace the source, support an "add pool" command, and enable an NTS
client to verify the server's certificate.

The name resolving does not block the response. Success is indicated
even if the name cannot be resolved, or a source with the same address
is already present.

To prevent unresolvable names from getting to chronyd, chronyc does not
send the request if it could not resolve the name itself (assuming they
are both running on the same host using the same resolver).
2019-12-12 14:44:03 +01:00
Miroslav Lichvar
00fff161cf cmdmon: merge add server/peer requests
Instead of having two separate requests in the protocol for adding a
server and peer, specify the type of the new source in the request data.
2019-12-12 14:44:03 +01:00
Miroslav Lichvar
3763befd62 ntp: check name and return status from NSR_AddSourceByName()
Return an error status when the name is not printable or contains a
space (don't bother with full hostname validation). If the name is an
address, return the same status as NSR_AddSource(). Otherwise, return a
"not resolved yet" status.
2019-12-12 14:44:03 +01:00
Miroslav Lichvar
2ae008bcee ntp: print name of replaced source in log message 2019-12-12 14:44:03 +01:00
Miroslav Lichvar
ea41f7ab09 doc: remove unsupported options of add commands
All options from the configuration file are supported in the chronyc add
commands.

This fixes commit 65fd30a547.
2019-12-12 14:43:55 +01:00
Miroslav Lichvar
c673b1e8b7 privops: convert to new socket API 2019-12-12 13:03:31 +01:00
Miroslav Lichvar
2bf1ba22f2 socket: change SCK_Send() declaration to const buffer 2019-12-12 13:03:31 +01:00
Miroslav Lichvar
dfc2f70876 socket: add support for opening socket pairs 2019-12-12 13:03:31 +01:00
Miroslav Lichvar
0dba2b9689 socket: add support for blocking sockets
Add a flag to open a blocking socket. The default stays non-blocking.
2019-12-12 13:03:31 +01:00
Miroslav Lichvar
e7fc2d31cc socket: remove unnecessary MSG_DONTWAIT flag
This is not needed since sockets are non-blocking by default.
2019-12-12 13:03:31 +01:00
Miroslav Lichvar
f231efb811 socket: add support for sending and receiving descriptors
Add support for the SCM_RIGHTS control message used in communication
with the privops helper.
2019-12-12 13:03:31 +01:00
Christian Ehrhardt
c4d6f98bed test: accept test result if RTC can't enable RTC_UIE_ON
The test might run on different platforms. If the platform happens
to have a RTC that does exist but unable to have RTC_UIE_ON set the
test will fail, while the chrony code is actually good.

Examples of bad clocks are:
- ppc64el: rtc-generic
- arm64: rtc-efi

To avoid that extend the log message check on 101-rtc to accept
that condition as a valid test result as well.

Signed-off-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
2019-12-12 13:03:26 +01:00
Christian Ehrhardt
bff3f51d13 rtc: extend check for RTCs that don't support interrupts
Several RTCs would only expose the broken behavior on enabling
interrupts. The reason for that is that the kernel only returns the
error if the state changes. Therefore the check has to probe
switch_interrupts(1) as well.

On platforms that work it will be switched on and off, while on those it
never works it will just stay off.

Clocks known to expose that behavior include, but are not limited to:
PPC64# dmesg | grep -i rtc   
[    0.241872] rtc-generic rtc-generic: registered as rtc0
[    0.270221] rtc-generic rtc-generic: setting system clock to ...
ARM64# dmesg | grep -i rtc
[    0.876198] rtc-efi rtc-efi: registered as rtc0
[    1.046869] rtc-efi rtc-efi: setting system clock to ...

Signed-off-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
2019-12-12 12:50:19 +01:00
Miroslav Lichvar
f5eb7daf20 rtc: disable interrupts in finalization
Don't leave interrupts enabled if chronyd is stopped when making an RTC
measurement.
2019-12-10 17:45:28 +01:00
Miroslav Lichvar
d66b2f2b24 rtc: handle RTCs that don't support interrupts
Some RTCs supported by the Linux kernel don't support the RTC_UIE_ON/OFF
ioctls, which causes chronyd started with the -s option to get stuck in
the initial RTC mode.

After opening the RTC device in the initialization, return error if
the ioctls are not supported to prevent the upper layer from calling the
time_init() function and expecting it to finish.
2019-12-10 17:45:28 +01:00
Miroslav Lichvar
a57e1eb542 rtc: don't finalize driver if initialization failed 2019-12-10 17:45:20 +01:00
Miroslav Lichvar
25bdee7a0e rtc: simplify and move switch_interrupts() 2019-12-10 17:03:15 +01:00
Miroslav Lichvar
f6001202ec test: update log checks in system tests
Measurements are no longer accepted and clock updated when polling
itself.

This fixes commit 7a88e0a87b.
2019-12-10 15:56:48 +01:00
Miroslav Lichvar
0cf506c929 sys_linux: allow clock_adjtime in seccomp filter
The adjtimex() function in glibc was switched to the clock_adjtime
system call.
2019-12-02 18:06:25 +01:00
Miroslav Lichvar
d05e9fb2ec logging: enable line buffering on stderr
This should avoid mixed lines on console or in file log when multiple
processes will be logging messages at the same time.
2019-12-02 18:06:15 +01:00
Vincent Blut
54d7e3e94a doc: fix typo in chrony.conf man page 2019-11-28 16:41:45 +01:00
Miroslav Lichvar
c7223f4c8f logging: disable all debug messages in non-debug build
For consistency, don't print debug messages that are compiled in due to
using the LOG macro instead of DEBUG_LOG.
2019-11-19 14:59:21 +01:00
Miroslav Lichvar
07badbede7 client: don't print log messages with lower severity 2019-11-19 14:43:01 +01:00
Miroslav Lichvar
468cfeeb71 privops: keep stdin/out/err open 2019-11-19 14:43:01 +01:00
Miroslav Lichvar
b3fc549622 privops: remove debug message from PRV_Name2IPAddress()
The function may be called from a separate thread, but logging is not
considered thread safe (e.g. due to using functions which read
environment variables).
2019-11-19 14:43:01 +01:00
Miroslav Lichvar
077dbd5692 main: don't try to open unspecified pidfile 2019-11-19 14:34:51 +01:00
Miroslav Lichvar
e18903a6b5 switch to new util file functions
Replace all fopen(), rename(), and unlink() calls with the new util
functions.
2019-10-24 12:48:45 +02:00
Miroslav Lichvar
7dfd4ae556 test: extend util unit test 2019-10-24 12:48:45 +02:00
Miroslav Lichvar
429c4468b0 sys_linux: allow F_GETFL in seccomp filter
This is needed for fdopen().
2019-10-24 12:48:45 +02:00
Miroslav Lichvar
7a4c396bba util: add functions for common file operations
Add a function to open a file for reading, writing, or appending.
In uppercase modes errors are handled as fatal, i.e. the caller doesn't
need to check for NULL. To avoid string manipulations in the callers,
the function accepts an optional directory and suffix. New files are
created with specified permissions, which will be needed for saving
keys. The O_EXCL flag is used in the writing mode to make sure a new
file is created (on filesystems that support it).

Also, add a function to rename a temporary file by changing its suffix,
and a function to remove a file.

All functions log all errors, at least as debug messages.
2019-10-24 12:48:45 +02:00
Miroslav Lichvar
88f846f656 rtc: don't clone file attributes of rtc file
When replacing an existing rtc file with the temporary file, don't
change the ownership or permissions of the temporary file to match the
old rtc file, as if it didn't exist.
2019-10-24 11:03:47 +02:00
Miroslav Lichvar
27c8a64977 reference: don't clone file attributes of drift file
When replacing an existing drift file with the temporary file, don't
change the ownership or permissions of the temporary file to match the
old drift file, as if it didn't exist.
2019-10-24 11:03:47 +02:00
Miroslav Lichvar
2fc8edacb8 use PATH_MAX
Include <limits.h> and use the PATH_MAX macro to define the length of
buffers containing paths to make it constistent. (It's not supposed to
fit all possible paths.)
2019-10-24 11:03:47 +02:00
Miroslav Lichvar
903fa247f8 logging: include <syslog.h>
Move the inclusion of <syslog.h> from sysincl.h to logging.c to avoid
accidentally using the LOG_* constants from the header.
2019-10-24 11:03:47 +02:00
Miroslav Lichvar
96771d6857 logging: make banner printing safer
Don't rely on the buffer filled with '=' characters to be always at
least as long as the log-specific banner string.
2019-10-24 11:03:41 +02:00
Miroslav Lichvar
f4c6a00b2a logging: call exit() in LOG_Message()
Call exit() in LOG_Message() after printing a fatal message to allow the
LOG macro or LOG_Message() to be used directly instead of the LOG_FATAL
macro.
2019-10-10 18:05:00 +02:00
Miroslav Lichvar
990f8cd89b test: extend 110-chronyc test 2019-09-24 16:39:49 +02:00
Miroslav Lichvar
813ea71b50 test: extend 105-ntpauth test 2019-09-24 16:39:49 +02:00
Miroslav Lichvar
e8be384cdf test: extend keys unit test 2019-09-24 16:39:49 +02:00
Miroslav Lichvar
61773a2c07 test: add cmac unit test 2019-09-24 16:39:49 +02:00
Miroslav Lichvar
510aa8b050 client: add CMAC support to keygen command
Allow a CMAC cipher to be specified in the keygen command. Ignore the
specified length as the key length is determined by the cipher.
2019-09-24 16:39:01 +02:00
Miroslav Lichvar
57957ab6cf keys: add support for CMAC keys
Allow a cipher (AES128 or AES256) to be specified as the type of a key
in the key file to authenticate NTP packets with a CMAC instead of the
NTPv4 (RFC 5905) MAC using a hash function. This follows RFC 8573.
2019-09-24 16:38:12 +02:00
Miroslav Lichvar
e8069a0179 cmac: add support for Nettle
Add support for AES128 and AES256 CMAC in Nettle.
2019-09-24 14:04:44 +02:00
Miroslav Lichvar
f3f840551a cmac: add CMAC interface
Add cmac.h and stubs for cipher-based message authentication code
(CMAC).
2019-09-24 11:56:05 +02:00
Miroslav Lichvar
10a42c1e04 keys: don't fudge authentication delay
Remove the magic constant compensating for copying, conversions, etc.
It cannot possibly be accurate on all hardware. The delay is supposed to
be a minimum delay.
2019-09-24 11:35:51 +02:00
Miroslav Lichvar
4a219ecbf1 hash: drop support for RIPEMD hash functions
An analysis by Tim Ruffing [1] shows that a length extension attack
adding valid extension fields to NTPv4 packets is possible with some
specific key lengths and hash functions using little-endian length like
MD5 and RIPEMD160.

chronyd currently doesn't process or generate any extension fields, but
it could be a problem in future when a non-authentication extension
field is supported.

Drop support for all RIPEMD functions as they don't seem to be secure in
the context of the NTPv4 MAC. MD5 is kept only for compatibility.

[1] https://mailarchive.ietf.org/arch/msg/ntp/gvibuB6bTbDRBumfHNdJ84Kq4kA
2019-09-24 11:32:31 +02:00
Miroslav Lichvar
0d298bfc4c makefile: improve coding style 2019-09-19 17:30:28 +02:00
Miroslav Lichvar
792c241e3a makefile: refactor to support extra client-specific objects 2019-09-19 17:30:28 +02:00
Miroslav Lichvar
6336a87855 configure: move duplicated libraries to LIBS 2019-09-19 17:30:28 +02:00
Miroslav Lichvar
f5721b1212 configure: remove unused variables 2019-09-19 17:30:28 +02:00
Miroslav Lichvar
7d3e9180c6 test: disable server on client-only nodes by default 2019-09-12 14:51:12 +02:00
Miroslav Lichvar
03b8ca186a test: add 138-syncloop test 2019-09-12 14:51:12 +02:00
Miroslav Lichvar
435cbef31a test: allow nodes to poll themselves 2019-09-12 14:51:12 +02:00
Miroslav Lichvar
4adcf58368 test: remove subdirectories in tmp directory 2019-09-12 14:50:58 +02:00
Miroslav Lichvar
004986310d ntp: skip loop test if no server socket is open
If there is no socket that could receive a request from a client or
peer, we know that nothing can be synchronized to us and no loop is
possible.
2019-09-12 13:01:18 +02:00
Miroslav Lichvar
7a88e0a87b ntp: prevent synchronization to itself
Improve the client's test D to compare the stratum, reference ID,
reference timestamp, and root delay from the received packet with its
own reference data in order to prevent it from synchronizing to itself,
e.g. due to a misconfiguration.
2019-09-12 13:01:18 +02:00
Miroslav Lichvar
64e21d6281 reference: make local reference timestamp consistent
In the local reference mode, instead of returning the adjusted current
time as the reference time, return the same timestamp updated only once
per about 62.5 seconds.

This will enable chronyd to detect polling of itself even when the local
reference mode is active.
2019-09-12 13:01:06 +02:00
Miroslav Lichvar
9ef7ea2bcb reference: rework adjustment of reference timestamp
Instead of converting the reference timestamp to the NTP format and
back, add a negative double value to the timestamp directly. Move the
code to a separate function. This will allow the timestamp to stay
outside the compiled-in NTP era, which is useful for testing of the
cmdmon protocol.
2019-09-11 17:33:57 +02:00
Miroslav Lichvar
6d1796d6be test: extend 110-chronyc test 2019-09-03 13:17:44 +02:00
Miroslav Lichvar
fcaba98101 test: add 137-pool test 2019-09-03 12:41:01 +02:00
Miroslav Lichvar
9bbda5c964 test: add 013-nameserv test 2019-09-02 16:32:58 +02:00
Miroslav Lichvar
2c81d38861 test: add option to enable name/address resolving 2019-09-02 16:27:05 +02:00
Miroslav Lichvar
78fec3f05a test: add copyright header to util unit test 2019-08-27 17:11:49 +02:00
Miroslav Lichvar
392a1a5ff6 test: extend 105-ntpauth test 2019-08-27 17:11:49 +02:00
Miroslav Lichvar
219a414cb7 test: add debug message to ntp unit test 2019-08-27 17:11:49 +02:00
Miroslav Lichvar
58fc81441b ntp: update setting of socket option 2019-08-27 17:11:49 +02:00
Miroslav Lichvar
02ada36838 socket: add support for TCP sockets
TCP sockets will be needed for NTS key establishment.
2019-08-27 17:10:13 +02:00
Miroslav Lichvar
81978f0ba0 socket: fix typo in union declaration 2019-08-08 17:32:48 +02:00
Miroslav Lichvar
622769cdfd util: add debug messages to UTI_FdSetCloexec() 2019-08-08 17:32:48 +02:00
Miroslav Lichvar
3038047f9b makefile: clean unit tests in clean target 2019-08-06 16:11:07 +02:00
Miroslav Lichvar
3e3f045ab7 doc: improve ntpdate answer in FAQ 2019-08-06 16:11:07 +02:00
Miroslav Lichvar
a6d9f41eda sourcestats: report offset even with single sample 2019-08-06 16:11:07 +02:00
Miroslav Lichvar
bf6a4e1a81 sourcestats: simplify SST_DoSourcestatsReport() 2019-08-06 16:11:07 +02:00
Miroslav Lichvar
5982d96b75 test: extend 130-quit test 2019-08-06 16:11:07 +02:00
Miroslav Lichvar
28e3e4cdca sourcestats: enable selection with maxsamples < 3
Setting maxsamples to 1 or 2 prevented the source from being selected as
the regression would always fail. Handle this as a special case with
disabled frequency tracking in order to enable a fast reference update
with the -q/-Q option.
2019-08-06 16:11:07 +02:00
Miroslav Lichvar
24134c78e8 sourcestats: update offset estimate when regression fails
If there are too few samples to make a regression, at least update the
offset estimate from the last sample and keep the previous frequency
offset unchanged. Also, reset the error estimates.
2019-08-06 13:04:59 +02:00
Miroslav Lichvar
5e8ed72b89 socket: fix compiler warning
Don't define check_socket_flag() if no supported socket flag is defined.
2019-07-25 09:52:33 +02:00
Miroslav Lichvar
45e41b7ac1 socket: avoid unnecessary bind() call
Don't call bind() if the specified local address of a socket has port 0
and the "any" address. It will be bound automatically on connect() or
sendmsg().
2019-07-24 16:27:07 +02:00
Miroslav Lichvar
27fd751915 socket: add support for socket() flags
On start, check if the SOCK_CLOEXEC and SOCK_NONBLOCK flags are
supported in the socket() call and use them instead of fcntl() in order
to reduce the number of system calls required to send a client request.
2019-07-24 15:35:00 +02:00
Miroslav Lichvar
4d26cfc92b socket: make all sockets non-blocking
All networking code in chronyd (NTP server/client, signd client, cmdmon
server) assumes sending a message will not block, but only the signd
client actually checks for a write event and only the NTP server
requests a non-blocking socket. The cmdmon server and NTP client
(if using one socket for all servers) might be blocked.

chronyc doesn't need a non-blocking socket, but it is not expected to
block as it sends only one message at a time.

Prefer dropped messages over blocking in all cases. Remove the
SCK_FLAG_NONBLOCK flag and make all sockets non-blocking.
2019-07-24 10:21:14 +02:00
Miroslav Lichvar
d78680912e ntp: improve debug messages with port number 2019-07-18 17:29:44 +02:00
Miroslav Lichvar
47e4cb31b2 util: move and improve sockaddr-specific functions
Move the functions to socket.c and improve them to require and check the
sockaddr length.
2019-07-18 17:29:44 +02:00
Miroslav Lichvar
91da65a782 util: remove UTI_SockaddrToString()
It is no longer used after the conversions.
2019-07-18 17:29:44 +02:00
Miroslav Lichvar
bb1c02e9f5 client: convert to new socket API 2019-07-18 17:29:44 +02:00
Miroslav Lichvar
c651ea9b6b refclock: remove SOCK socket on exit 2019-07-18 17:29:44 +02:00
Miroslav Lichvar
207f9fb128 refclock: convert SOCK to new socket API 2019-07-18 17:29:44 +02:00
Miroslav Lichvar
f06c1cfa97 cmdmon: respond from same address
Enable the destination address of received messages in order to respond
from the same address on multihomed hosts.
2019-07-18 17:29:44 +02:00
Miroslav Lichvar
6cd47bff8f cmdmon: convert to new socket API 2019-07-18 17:29:44 +02:00
Miroslav Lichvar
2de24cfd82 ntp: convert to new socket API
Rework the NTP I/O code to use the new socket support. There are
differences in debug messages and handling of some errors.
2019-07-18 17:29:35 +02:00
Miroslav Lichvar
86a3ef9ed1 socket: add new socket support
Add a new file implementing support for opening sockets, sending and
receiving messages with control messages (e.g. addresses, timestamps),
and related operations, which should be simpler to use than the system
functions and allow their features to be reused between different parts
of the chrony code.

It is based on the ntp_io.c and ntp_io_linux.c files. It will be used by
the NTP client/server, cmdmon server, client, and others.
2019-07-18 16:54:48 +02:00
Miroslav Lichvar
3f8c57c8f2 util: add UTI_IPSockAddrToString()
This function prints an IPSockAddr. IPv6 addresses are printed in
brackets to separate the address from the port.
2019-07-18 13:37:52 +02:00
Miroslav Lichvar
ca96946416 addressing: introduce IPSockAddr
Rename NTP_Remote_Address to IPSockAddr to make it usable in non-NTP
context and provide NTP_Remote_Address for compatibility. Also, change
the type of port to uint16_t.
2019-07-18 13:37:52 +02:00
Miroslav Lichvar
e5b9b6d701 cmdmon: limit rate of all responses
Include responses to invalid requests in the rate limiting enabled by
the cmdratelimit directive.
2019-07-18 13:37:52 +02:00
Miroslav Lichvar
8cb689a5e6 cmdmon: don't require bound UDP socket
Don't abort on start when no UDP socket could be opened/bound for
cmdmon. The Unix socket is more important and with the IP_FREEBIND
option this case was not caught anyway.
2019-07-18 13:35:54 +02:00
Miroslav Lichvar
2270234115 privops: add assertion for bind address length 2019-07-16 13:46:37 +02:00
Miroslav Lichvar
a073f383e6 test: fix building of unit tests
This fixes commit 1227873b88.
2019-07-16 13:46:37 +02:00
Miroslav Lichvar
8e74655b03 doc: improve chronyd man page 2019-07-04 17:38:13 +02:00
Miroslav Lichvar
70fa3a6905 main: add option to specify minimum log severity level
The -L option can be used to disable logging of less severe messages,
e.g informational or warnings.
2019-07-04 17:38:13 +02:00
Miroslav Lichvar
1227873b88 logging: refactor enabling of debug messages
Reorder the LOGS_Severity enum in order of severity and change the code
to not log/print messages with severity below the specified minimum
instead of having a separate debug level.
2019-07-04 17:38:13 +02:00
Miroslav Lichvar
d30e73d0d9 nameserv: request SOCK_DGRAM socktype
Specify SOCK_DGRAM socktype instead of SOCK_STREAM in hints for
getaddrinfo() as chronyd is (and will mainly be) using the returned
addresses to open UDP sockets. This shouldn't make a difference in
practice, but it might avoid some confusion.
2019-06-26 17:21:47 +02:00
Miroslav Lichvar
9e7a7008de configure: fix warnings in tests
Fix some warnings in configure tests reported by clang and coverity
static analyzer.
2019-06-18 16:24:01 +02:00
Miroslav Lichvar
62d6aed6a6 test: update processing of packet log
Two new fields have been added to the packet log, which broke some
of the simulation tests.
2019-06-18 15:42:11 +02:00
Miroslav Lichvar
ffb9887cce doc: update NEWS 2019-05-10 12:22:57 +02:00
Miroslav Lichvar
9220c9b8a2 update copyright years 2019-05-10 11:01:27 +02:00
Miroslav Lichvar
2e28b19112 doc: add note about minsamples to FAQ 2019-05-10 11:01:27 +02:00
Miroslav Lichvar
636a4e2794 refclock: remove unnecessary strlen() call 2019-05-10 11:01:27 +02:00
Miroslav Lichvar
5c9e1e0b69 test: extend 133-hwtimestamp test 2019-05-10 11:01:27 +02:00
Miroslav Lichvar
64fd1b8ba5 ntp: check value returned by CMSG_FIRSTHDR
In NIO_Linux_RequestTxTimestamp(), check the returned pointer and the
length of the buffer before adding the control message. This fixes an
issue reported by the Clang static analyzer.
2019-05-10 10:58:37 +02:00
Miroslav Lichvar
69d3913f3e ntp: check timestamping configuration when SIOCSHWTSTAMP fails
With future kernels it may be possible to get, but not set, the HW
timestamping configuration on some specific interfaces like macvlan in
containers. This would require the admin to configure the timestamping
before starting chronyd.

If SIOCSHWTSTAMP failed on an interface, try SIOCGHWTSTAMP to check if
the current configuration matches the expected configuration and allow
the interface to be used for HW timestamping.
2019-05-09 14:44:58 +02:00
Miroslav Lichvar
08fd011b6a examples: remove /var from PIDFile in chronyd.service
Recent systemd versions complain when loading a unit using a PIDFile
that relies on the /var/run -> /run symlink.
2019-05-06 15:44:24 +02:00
Miroslav Lichvar
c172268cfe doc: update NEWS 2019-05-02 11:50:41 +02:00
Miroslav Lichvar
94b014865c doc: add more recommendations for best stability to FAQ 2019-04-30 14:46:19 +02:00
Miroslav Lichvar
099aaf2cb1 doc: update list of contributors
Include all authors from the git repository.
2019-04-30 12:56:25 +02:00
Miroslav Lichvar
4481a8b24f doc: simplify acknowledgements in README
Stop trying to maintain a list of individual contributions. Just list
the contributors. For tracking individual changes in the source code
there is git.
2019-04-30 12:56:25 +02:00
Miroslav Lichvar
b626fe661e doc: list build requirements in installation 2019-04-30 12:56:25 +02:00
Miroslav Lichvar
ba8fcd145d doc: improve combinelimit description 2019-04-26 11:19:20 +02:00
Miroslav Lichvar
981d09de40 doc: improve rtconutc description 2019-04-26 11:12:41 +02:00
Miroslav Lichvar
86a99bb257 test: use env in shebang of system tests
This should allow the tests to run on systems where bash is not in /bin.
2019-04-26 10:54:02 +02:00
Miroslav Lichvar
3093a11cd0 test: add 104-systemdirs system test 2019-04-25 18:58:01 +02:00
Miroslav Lichvar
058b788d38 test: fix owner of driftfile and keys in system tests 2019-04-25 18:57:39 +02:00
Miroslav Lichvar
66a42fa493 test: allow separate lib/log/run directories in system tests 2019-04-25 18:55:56 +02:00
Miroslav Lichvar
a85f63cc15 test: check if non-root user can access test directory 2019-04-25 18:24:50 +02:00
Miroslav Lichvar
bbe1e69dcc test: redirect error messages in system tests 2019-04-25 18:24:41 +02:00
Miroslav Lichvar
1b52bba7b9 test: allow TEST_DIR and CHRONYC_WRAPPER to be set for system tests 2019-04-25 17:29:34 +02:00
Stefan R. Filipek
c5c80ef400 sys_posix: support SCHED_FIFO and mlockall on more OSs
Real-time scheduling and memory locking is available on posix compliant
OSs. This patch centralizes this functionality and brings support to
FreeBSD, NetBSD, and Solaris.

[ML: updated coding style]
2019-04-24 12:18:07 +02:00
Miroslav Lichvar
a78031ce0d refclock: check all driver options
In each driver provide a list of supported options and abort when an
unknown option is specified in the refclock directive.
2019-04-18 16:27:47 +02:00
Miroslav Lichvar
34e9dd13ce doc: fix syntax of refclock directive
When multiple driver options are specified, they need to be separated by
colon, not comma.
2019-04-18 16:27:19 +02:00
Miroslav Lichvar
6e52a9be7a test: add system tests
Add a new set of tests for testing basic functionality, starting chronyd
with root privileges on the actual system instead of the simulator.

Tests numbered in the 100-199 range are considered destructive and
intended to be used only on machines dedicated for development or
testing. They are started by the run script only with the -d option.
They may adjust/step the system clock and other clocks, block the RTC,
enable HW timestamping, create SHM segments, etc.

Other tests should not interfere with the system and should work even
when another NTP server/client is running.
2019-04-18 16:11:45 +02:00
Stefan R. Filipek
69c6dffd63 sys_linux: use pthread_setschedparam instead of sched_setscheduler
Fix an issue with Linux and musl libc where sched_setscheduler is not
implemented. It seems that pthread_setschedparam is more widely
supported across different C libraries and OSs. For our use case, it
should make no difference which call is used.
2019-04-08 16:38:38 +02:00
Vincent Blut
2ddd0ae231 sys_linux: allow further syscalls in seccomp filter
These are needed on arm64.
2019-03-18 14:24:54 +01:00
Leigh Brown
79db0b7eca sys_linux: allow recv and send in seccomp filter 2019-03-14 09:07:15 +01:00
Vincent Blut
2ebba7fbaa sys_linux: allow waitpid in seccomp filter 2019-02-28 17:42:02 +01:00
Vincent Blut
e392d1fde9 sys_linux: allow _llseek in seccomp filter
This is needed on various 32-bit platforms to reposition read/write file
offset on {raw}measurements and statistics log files.
2019-02-28 16:19:05 +01:00
Miroslav Lichvar
d7c93ec950 test: fix distribution of settings in ntp_core unit test 2019-02-20 10:11:58 +01:00
Miroslav Lichvar
6af39d63aa ntp: don't use IP_SENDSRCADDR on bound socket
On FreeBSD, sendmsg() fails when IP_SENDSRCADDR specifies a source
address on a socket that is bound to the address. This prevents a server
configured with the bindaddress directive from responding to clients.

Add a new variable to check whether the server IPv4 socket is not bound
before setting the source address.
2018-12-03 16:08:08 +01:00
Miroslav Lichvar
cc8414b1b3 sys_linux: add support for PTP_SYS_OFFSET_EXTENDED ioctl
A new ioctl will probably be added in Linux 4.21. It should enable a
significantly more accurate measurement of the offset between PHC and
system clock.
2018-11-27 14:56:17 +01:00
Miroslav Lichvar
6b44055e3d sys_linux: split reading and processing of PHC samples 2018-11-27 14:51:25 +01:00
Miroslav Lichvar
9f9c6cc6ab ntp: fix transposition with timestamping packet info
Don't forget to include the length of the frame check sequence (FCS) in
the RX timestamp transposition when the L2 length of the received packet
is from SCM_TIMESTAMPING_PKTINFO.

This fixes commit 934d4047f1.
2018-10-08 15:54:07 +02:00
Bryan Christianson
f176193d35 sys_macosx: remove adjtime() check
Remove the runtime checking of adjtime(). adjtime() was broken in beta
releases of macOS 10.13 but is ok now.
2018-10-02 10:50:04 +02:00
Miroslav Lichvar
e8bc41e862 test: fix tests to skip when missing required feature 2018-09-27 11:42:38 +02:00
Miroslav Lichvar
91dbe3c6c2 test: allow unit tests to be skipped 2018-09-27 11:42:38 +02:00
Miroslav Lichvar
3e876d4218 test: add function for checking config.h in tests 2018-09-27 11:42:38 +02:00
Miroslav Lichvar
31b1f2e8a1 test: include util.h for MIN macro 2018-09-27 11:42:38 +02:00
Miroslav Lichvar
4169e94b1d nameserv: adopt some include directives from sysincl.h
Move headers specific to name resolving to nameserv.c. This should hide
the system MIN/MAX macros from the rest of the code.
2018-09-20 15:34:24 +02:00
Miroslav Lichvar
948ecf8431 hash: include util.h for MIN macro
The hash_intmd5.c file inadvertently relied on the system headers to
provide the MIN macro, but it is missing with some libc implementations.
2018-09-20 15:34:24 +02:00
Miroslav Lichvar
91f3f97ea7 test: fix Makefile to not create .deps in project root 2018-09-19 16:38:15 +02:00
Miroslav Lichvar
65bb65b440 doc: add new question to FAQ 2018-09-17 18:38:46 +02:00
Miroslav Lichvar
ea6e8d85a3 doc: improve description of minsamples directive 2018-09-17 18:38:24 +02:00
Miroslav Lichvar
add932501f test: add 136-broadcast test 2018-09-17 18:36:22 +02:00
Miroslav Lichvar
89390a738f test: add 012-daemonts test 2018-09-17 18:36:22 +02:00
Miroslav Lichvar
ac4f6ab93b test: improve Makefile
The -s option of make apparently doesn't work when called from make -C.
Add another filter to ignore the Entering/Leaving messages.

Also, fix a typo.
2018-09-13 16:29:49 +02:00
Miroslav Lichvar
dbcb1b9b0b test: include all objects in prerequisites of unit tests 2018-09-13 11:23:16 +02:00
Miroslav Lichvar
6375307798 test: get list of objects from main Makefile
Instead of linking unit tests with *.o in the root directory, which may
include conflicting objects from a different configuration (e.g. hash),
add a print target to the main Makefile and use it in the unit test
Makefile to link only with objects that are relevant in the current
configuration.
2018-09-13 11:23:16 +02:00
Miroslav Lichvar
fb78e60d26 test: add 135-ratelimit test 2018-09-12 19:27:48 +02:00
Miroslav Lichvar
b822c7164f test: add 134-log test 2018-09-12 19:04:11 +02:00
Miroslav Lichvar
aa295730a0 test: extend 110-chronyc test 2018-09-12 18:17:35 +02:00
Miroslav Lichvar
69d70703b2 git: update .gitignore 2018-09-12 17:16:33 +02:00
Miroslav Lichvar
b2b6ef00dc makefile: remove gcov files and core dumps 2018-09-12 17:15:30 +02:00
Miroslav Lichvar
5dc86c236b update copyright years 2018-09-12 11:38:10 +02:00
Miroslav Lichvar
2563dd9d29 examples: drop chrony.spec
The example spec file was too limited to be recommended for use in any
rpm-based distribution, e.g. it didn't configure chronyd to drop the
root privileges.

Users that want to build a package from the latest source code should
start with the official package of their distribution.
2018-09-12 11:38:10 +02:00
Miroslav Lichvar
a899e3df33 examples: improve description in chrony.keys example 2018-09-12 11:38:08 +02:00
Miroslav Lichvar
692cea49f8 doc: warn about permissions in keyfile description 2018-09-12 10:43:01 +02:00
Miroslav Lichvar
bcedacaa3d test: fix samplefilt unit test to work with low-precision clock 2018-09-10 14:56:03 +02:00
Miroslav Lichvar
be3c1b5243 samplefilt: use SQUARE macro in SPF_CreateInstance() 2018-09-10 13:20:14 +02:00
Miroslav Lichvar
e626ec6c37 examples: update chrony.conf example for new default pidfile 2018-09-10 10:37:37 +02:00
Miroslav Lichvar
49d52b547f test: make 129-reload more reliable 2018-08-31 12:48:36 +02:00
Miroslav Lichvar
74a546a9e7 configure: fix compiler warning in pthread test code 2018-08-31 11:04:36 +02:00
Miroslav Lichvar
d1777087c1 doc: update NEWS 2018-08-31 10:11:17 +02:00
Miroslav Lichvar
cf7b5363cd test: extend 110-chronyc test 2018-08-31 09:55:43 +02:00
Miroslav Lichvar
7f3183cc72 test: extend 106-refclock test 2018-08-31 09:55:43 +02:00
Miroslav Lichvar
f1b8da085b doc: update FAQ 2018-08-30 11:56:13 +02:00
Miroslav Lichvar
09dfca49ec configure: fix detection of timepps.h on NetBSD
The header requires <time.h> for struct timespec.
2018-08-30 11:56:13 +02:00
Miroslav Lichvar
88e0ec07aa refclock: fix compiler warning on FreeBSD 2018-08-30 11:56:13 +02:00
Miroslav Lichvar
0adc8e8f92 ntp: add support for IP_RECVDSTADDR and IP_SENDSRCADDR
FreeBSD doesn't support IP_PKTINFO. Instead it provides IP_RECVDSTADDR
and IP_SENDSRCADDR, which can be used to get/set the destination/source
address.

In future IP_RECVIF and IP_SENDIF may be supported to get and set also
the interface.
2018-08-30 11:56:13 +02:00
Miroslav Lichvar
5fc7674e36 ntp: set interface index in IP*_PKTINFO when responding
When a server with multiple interfaces in the same network is sending a
response, setting the ipi_spec_dst/ipi6_addr field of the IP*_PKTINFO
control message selects the source address, but not necessarily the
interface. The packet has the expected source address, but it may be
sent by an interface that doesn't have the address.

Set the ipi_ifindex/ipi6_ifindex field to respond on the same interface
as the request was received from to avoid asymmetries in delay and
timestamping.
2018-08-30 11:56:13 +02:00
Miroslav Lichvar
018977044a test: add 133-hwtimestamp test 2018-08-30 08:08:19 +02:00
Miroslav Lichvar
cc49d8e6e6 test: add 132-logchange test 2018-08-28 18:27:43 +02:00
Miroslav Lichvar
933bd017b4 test: add 131-maxchange test 2018-08-28 18:27:43 +02:00
Miroslav Lichvar
d558b33d85 test: extend 108-peer test 2018-08-28 18:27:43 +02:00
Miroslav Lichvar
9268bf2cff test: don't override user settings with default values
This fixes commit 671daf06b8.
2018-08-28 18:27:43 +02:00
Miroslav Lichvar
dbf2c22467 test: extend ntp_core unit test 2018-08-28 18:27:03 +02:00
Miroslav Lichvar
af4fe92095 test: update hash unit test 2018-08-28 18:18:07 +02:00
Miroslav Lichvar
e034a07be8 test: enable unit tests to suspend logging 2018-08-28 18:18:07 +02:00
Miroslav Lichvar
eb8c9ad601 logging: allow reopening stderr
LOG_OpenFileLog(NULL) can be now used to reopen stderr.
2018-08-28 18:18:07 +02:00
Miroslav Lichvar
6847536669 logging: close previous file log after opening new one
Currently, the log is always opened only once, but that will change with
tests temporarily suspending logging.
2018-08-28 15:42:38 +02:00
Miroslav Lichvar
f5206db9b0 ntp: optimize MAC truncation
When generating a MAC for an NTP packet, request only the bytes that
will be sent.
2018-08-27 19:00:08 +02:00
Miroslav Lichvar
6ab2ed0da6 hash: allow truncated output
Tomcrypt, some NSS hash functions, and the internal MD5 require the
output buffer to be at least as long as the digest. To provide the same
hashing API with all four options, use an extra buffer for the digest
when necessary and copy only the requested bytes to the caller.
2018-08-27 19:00:08 +02:00
Miroslav Lichvar
7352e470e1 ntp: remove unnecessary constant 2018-08-27 17:30:47 +02:00
Miroslav Lichvar
5bc9c0d07a sources: check maximum reach size before postponing update
Don't wait for other sources to be selectable when the maximum
selectable and non-selectable reachability registers happen to match
and a register is already full (e.g. after heavy packet loss).
2018-08-27 13:33:47 +02:00
Miroslav Lichvar
a2146e82ef doc: improve description of LastRx column in chronyc sources 2018-08-27 11:26:51 +02:00
Miroslav Lichvar
6e10e6740c test: add 130-quit test 2018-08-24 18:09:29 +02:00
Miroslav Lichvar
bfaa10f2b0 test: add 129-reload test 2018-08-24 18:09:29 +02:00
Miroslav Lichvar
9f167a7997 test: add 128-nocontrol test 2018-08-24 18:09:29 +02:00
Miroslav Lichvar
6908163464 test: separate client/server chronyd options 2018-08-24 18:09:29 +02:00
Miroslav Lichvar
671daf06b8 test: avoid using eval in shell scripts 2018-08-24 18:09:29 +02:00
Miroslav Lichvar
b189a5386b test: extend util unit test 2018-08-24 18:09:29 +02:00
Miroslav Lichvar
7889d108c2 test: add samplefilt unit test 2018-08-24 18:09:29 +02:00
Miroslav Lichvar
3cfa8ce9d3 test: add sanitizers test 2018-08-24 18:09:29 +02:00
Miroslav Lichvar
570573fe28 test: detect configure errors in compilation test 2018-08-24 18:09:29 +02:00
Miroslav Lichvar
62b1a11736 test: add -Werror to CFLAGS in compilation test 2018-08-24 18:09:29 +02:00
Miroslav Lichvar
c00d517e12 doc: update description of -r option 2018-08-24 18:09:29 +02:00
Miroslav Lichvar
001f3d5e27 sourcestats: improve debug message in SST_GetTrackingData() 2018-08-24 18:09:29 +02:00
Miroslav Lichvar
6045023a49 sources: use SQUARE macro in combine_sources() 2018-08-24 18:09:29 +02:00
Miroslav Lichvar
bba29a0ee7 samplefilt: check for non-increasing sample times
Adopt the check from the refclock code to check also samples from NTP.
2018-08-24 18:09:29 +02:00
Miroslav Lichvar
cffc856b50 test: update hwclock unit test 2018-08-21 16:54:54 +02:00
Miroslav Lichvar
419077e04b sys_linux: extend debug message 2018-08-21 15:52:35 +02:00
Miroslav Lichvar
7db9d4acea sys_linux: improve support for upcoming kernel versions
Starting with Linux 4.19, the frequency of the system clock should be
updated immediately in the system call itself, which will significantly
reduce the maximum delay of the update.

Increase the assumed tick rate in order to reduce the dispersion
accumulated by the driver when it sets the frequency.
2018-08-21 15:52:35 +02:00
Miroslav Lichvar
8d5b86efe7 test: make 121-orphan more reliable 2018-08-21 15:52:35 +02:00
Miroslav Lichvar
6cf16aea7b reference: refactor estimation of clock frequency
Reorder code in REF_SetReference(), clean it up a bit, and split off the
parts specific to the weighting and estimation of the new frequency.
2018-08-21 15:52:33 +02:00
Miroslav Lichvar
870545d3cb reference: include skew in local sync status setting 2018-08-21 12:06:57 +02:00
Miroslav Lichvar
2a030c0d0c sourcestats: include offset SD in tracking root dispersion 2018-08-21 12:06:57 +02:00
Miroslav Lichvar
0b709ab1bc util: introduce SQUARE macro 2018-08-21 12:06:57 +02:00
Miroslav Lichvar
a1f2f17385 reference: fix offset SD to include elapsed time
This should slow down corrections based on old measurements with large
estimated error in frequency.
2018-08-21 12:06:57 +02:00
Miroslav Lichvar
2240eefbd0 sources: fix combined offset SD to include elapsed time 2018-08-21 12:06:44 +02:00
Miroslav Lichvar
706d0c281a sources: combine frequencies by variance instead of skew
This seems to slightly improve the stability.
2018-08-21 10:15:19 +02:00
Miroslav Lichvar
ca73e34f30 sources: provide frequency SD to reference update 2018-08-17 17:40:06 +02:00
Miroslav Lichvar
cca2ef4649 sourcestats: provide frequency SD in tracking data 2018-08-17 17:40:06 +02:00
Miroslav Lichvar
05d9edbf8f sourcestats: replace constant with macro 2018-08-17 17:40:06 +02:00
Miroslav Lichvar
c5bdc52a59 test: don't require exit message to be on last line
This is useful with enabled debug output.
2018-08-17 17:39:50 +02:00
Miroslav Lichvar
74f0c0924a ntp: change maxdelay* info messages to use option names 2018-08-13 12:17:57 +02:00
Miroslav Lichvar
05492d1d23 test: improve 101-poll test 2018-08-10 16:46:38 +02:00
Miroslav Lichvar
eea343b93f refclock: improve error messages 2018-08-09 14:52:08 +02:00
Miroslav Lichvar
afff06c88c ntp: add options to set minsamples/maxsamples of hwclock 2018-08-09 14:52:08 +02:00
Miroslav Lichvar
c0717a27f6 hwclock: add parameters for minimum/maximum number of samples
Allocate the arrays which hold the samples dynamically and limit the
number of dropped samples to not fall below the minimum.
2018-08-09 14:52:08 +02:00
Miroslav Lichvar
159bd73f76 test: add 127-filter test 2018-08-09 14:52:08 +02:00
Miroslav Lichvar
9931a9166b cmdmon: include filter length in ADD_SERVER/ADD_PEER request 2018-08-09 14:33:48 +02:00
Miroslav Lichvar
8aa4ae027b ntp: add assertion to get_seperation() 2018-08-09 14:33:48 +02:00
Miroslav Lichvar
dcce79fdbe ntp: shorten minimum allowed polling interval
With the filter option it is useful to collect NTP measurements at
a higher rate.
2018-08-09 14:33:48 +02:00
Miroslav Lichvar
189aafde9d ntp: add filter option
Add an option to use the median filter to reduce noise in measurements
before they are accumulated to sourcestats, similarly to reference
clocks. The option specifies how many samples are reduced to a single
sample.

The filter is intended to be used with very short polling intervals in
local networks where it is acceptable to generate a lot of NTP traffic.
2018-08-09 14:33:47 +02:00
Miroslav Lichvar
99e3045df4 ntp: enable auto burst with very short polling intervals
This fixes commit 5b75d4afef.
2018-08-08 11:36:06 +02:00
Miroslav Lichvar
c498c21fad refclock: split off median filter
Move the implementation of the median filter to a separate file to make
it useful for NTP. Replace some constants with parameters and generalize
the code to work with full NTP samples (including root dispersion/delay,
stratum, and leap).

For refclocks it should give the same results as before.
2018-08-03 17:21:02 +02:00
Miroslav Lichvar
6bef8aa0e9 use common structure for NTP samples
Define a structure for NTP samples and use it to pass samples from
the ntp_core and refclock code to sources and sourcestats.
2018-08-03 17:21:02 +02:00
Miroslav Lichvar
108d112272 sourcestats: don't save stratum for all samples
Save stratum only from the last accumulated sample as only that is
currently needed.
2018-08-03 17:21:02 +02:00
Miroslav Lichvar
05078e4252 sourcestats: track leap status
This moves the leap status of the last sample from the source instance
to the sourcestats instance in order to make them both accumulate the
same data.
2018-08-03 17:21:02 +02:00
Miroslav Lichvar
4ceb9e4cd0 sys_linux: allow fcntl(F_SETFL) in seccomp filter
This fixes commit 76bed76289.
2018-08-03 17:21:02 +02:00
Miroslav Lichvar
a9f237a395 configure: fix detection of timepps.h on FreeBSD
The header requires inttypes.h to be useful.
2018-08-03 17:21:02 +02:00
Miroslav Lichvar
e7ca560c3d configure: drop detection of stdint.h and inttypes.h
The current code uses macros from inttypes.h. There is no point in
detecting and selecting between stdint.h and inttypes.h as the latter is
always needed.
2018-08-03 17:21:02 +02:00
Miroslav Lichvar
d9f86f6f70 memory: add missing include 2018-08-03 17:21:02 +02:00
Miroslav Lichvar
879d936277 util: handle or ignore SIGPIPE signal
In chronyc handle SIGPIPE similarly to SIGTERM. In chronyd ignore the
signal to avoid crashing when a TCP socket will be needed (e.g. for
NTS-KE) and will be unexpectedly closed from the other side.
2018-08-03 17:21:02 +02:00
Miroslav Lichvar
5bb2bf9361 util: handle errors in setting of signal handler as fatal 2018-08-03 17:21:02 +02:00
Miroslav Lichvar
a8167b7959 sched: allow file handler with multiple events to remove itself
Before dispatching a handler, check if it is still valid. This allows a
handler to remove itself when a descriptor has two different events at
the same time.
2018-08-03 17:21:02 +02:00
Miroslav Lichvar
b33b682356 doc: update chrony.conf man page for recent changes 2018-06-22 12:12:11 +02:00
Miroslav Lichvar
2c47602c33 ntp: allow sub-second maxpoll
Remove the maxpoll-specific limit and allow both minpoll and maxpoll to
be set to a negative value.
2018-06-22 12:12:11 +02:00
Miroslav Lichvar
59d1b41716 ntp: restrict use of sub-second polling intervals
When the local polling interval is adjusted between minpoll and maxpoll
to a sub-second value, check if the source is reachable and the minimum
measured delay is 10 milliseconds or less. If it's not, ignore the
maxpoll value and set the interval to 1 second.

This should prevent clients (mis)configured with an extremely short
minpoll/maxpoll from flooding servers on the Internet.
2018-06-22 12:11:36 +02:00
Miroslav Lichvar
5b75d4afef ntp: make burst interval proportional to polling interval
If the polling interval is shorter than 8 seconds, set the burst
interval to the 1/4th of the polling interval instead of the 2-second
constant. This should make the burst option and command useful with
very short polling intervals.
2018-06-22 10:57:03 +02:00
Miroslav Lichvar
e15c7cd236 refclock_sock: downgrade error messages to debug messages
Turn error messages which are not expected to happen with a correctly
working SOCK client into debug messages.
2018-06-20 16:57:24 +02:00
Miroslav Lichvar
9bc774d6af fix printf()/scanf() format signedness
Fix mismatches between the format and sign of variables passed to
printf() or scanf(), which were found in a Frama-C analysis and gcc
using the -Wformat-signedness option.
2018-06-20 16:57:04 +02:00
Miroslav Lichvar
9b34556952 keys: initialize data used for measuring authentication delay
This issue was found in a Frama-C analysis.
2018-06-20 16:45:26 +02:00
Miroslav Lichvar
9a6369d8f1 reference: specify recipient in message when sending email
Instead of adding the recipient to the sendmail command line (which is
interpretted by the shell) add a "To" line to the message and run
sendmail with the -t option to read the recipient from the message.
2018-06-20 16:45:26 +02:00
Miroslav Lichvar
49cdd6bf09 reference: terminate string returned by gethostname()
POSIX doesn't require the string to be terminated if it didn't fit in
the buffer.

This issue was found in a Frama-C analysis.
2018-06-20 16:45:21 +02:00
Miroslav Lichvar
63fe34e890 check values returned by gmtime() and localtime()
While it is not expected to happen with any time that can be represented
by the system clock, the functions are allowed to return NULL. Check the
pointer before dereferencing.

This issue was found in a Frama-C analysis.
2018-06-20 16:45:14 +02:00
Lonnie Abelbeck
85465afb62 client: re-work tab-completion to work with libedit 20180525-3.1
Remove spaces from tab-completion results and now break on a space.
Tested with both readline and editline (libedit)
Incorporated Miroslav's suggestions.
2018-06-18 12:30:45 +02:00
Miroslav Lichvar
339cb06a49 doc: fix description of pidfile directive to mention -Q option
This fixes commit 778fce4039.
2018-06-08 16:44:53 +02:00
Miroslav Lichvar
10150bfcab examples: update pidfile in chronyd.service 2018-06-08 16:44:53 +02:00
Miroslav Lichvar
e50dc739d8 configure: move default pidfile to /var/run/chrony
This allows chronyd to remove its pidfile on exit after dropping the
root privileges in order to prevent another chronyd instance from
failing to start, e.g. due to a wrong SELinux label from chronyd -q.
2018-06-08 16:44:53 +02:00
Miroslav Lichvar
26e08abe71 main: create directories before writing pidfile
This makes it possible to save pidfile in /var/run/chrony.
2018-06-08 16:42:49 +02:00
Miroslav Lichvar
7637faa0d0 ntp: change auto_offline to trigger on failed transmissions
Instead of counting missing responses, switch to the offline state
immediately when sendmsg() fails.

This makes the option usable with servers and networks that may drop
packets, and the effect will be consistent with the onoffline command.
2018-05-25 10:53:21 +02:00
Miroslav Lichvar
8a57a28177 examples: update NetworkManager dispatcher script
Replace most of the code with the new onoffline command.
2018-05-25 10:53:21 +02:00
Miroslav Lichvar
34db671b57 cmdmon: add onoffline command
The onoffline command tells chronyd to switch all sources to the online
or offline status according to the current network configuration. A
source is considered online if it is possible to send requests to it,
i.e. a route to the network is present.
2018-05-25 10:53:21 +02:00
Miroslav Lichvar
8b9021bf34 ntp: allow online/offline state to be selected by connectability
Allow SRC_MAYBE_ONLINE to be specified for new NTP sources and
connectivity setting to select between SRC_ONLINE and SRC_OFFLINE
according to the result of the connect() system call, i.e. check whether
the client has a route to send its requests.
2018-05-25 10:53:21 +02:00
Miroslav Lichvar
ce6b896948 ntp: refactor switching between online and offline state
Use an enum to describe connectivity of a source and merge
the NCR and NSR TakeSourceOnline/Offline() functions into
SetConnectivity() functions.
2018-05-25 10:53:21 +02:00
Miroslav Lichvar
2962fc6286 ntp: check PHC index before opening device
Apparently, it is possible for an interface to report all necessary
flags for HW timestamping without having a PHC. Check the PHC index to
avoid an error message in the system log saying that /dev/ptp-1 cannot
be opened.
2018-05-25 10:53:21 +02:00
Miroslav Lichvar
76bed76289 ntp: enable non-blocking mode on server sockets
Avoid blocking in sendmsg() due to a full send buffer.
2018-05-25 10:53:21 +02:00
Miroslav Lichvar
113f2ebec0 doc: add new questions to FAQ 2018-05-25 10:53:21 +02:00
Miroslav Lichvar
7c5bd948bb util: fall back to reading /dev/urandom when getrandom() blocks
With recent changes in the Linux kernel, the getrandom() system call may
block for a long time after boot on machines that don't have enough
entropy. It blocks the chronyd's initialization before it can detach
from the terminal and may cause a chronyd service to fail to start due
to a timeout.

At least for now, enable the GRND_NONBLOCK flag to make the system call
non-blocking and let the code fall back to reading /dev/urandom (which
never blocks) if the system call failed with EAGAIN or any other error.

This makes the start of chronyd non-deterministic with respect to files
that it needs to open and possibly also makes it slightly easier to
guess the transmit/receive timestamp in client requests until the
urandom source is fully initialized.
2018-05-25 10:53:21 +02:00
Christian Ehrhardt
8cbc68f28f examples: make nm-dispatcher script usable for networkd-dispatcher
Historically there were plenty of callback based implementations around
ifupdown via /etc/network/if-up and similar. NetworkManager added the
dispatcher [1] feature for such a kind of functionality.

But so far a systemd-networkd (only) systemd had no means to handle those
cases. This is solved by networkd-dispatcher which is currently available
at least in ArchLinux and Ubuntu.
It takes away the responsibility to listen on netlink events in each
application and provides a more classic script-drop-in interface to respond
to networkd events [3].

This commit makes the NM example compatible to be used by NetworkManager
dispatcher as well as by networkd-dispatcher. That way we avoid too much
code duplication and can from now on handle special cases in the
beginning so that the tail can stay commonly used.

After discussion on IRC the current check differs by checking the
argument count (only in NetworkManager), if ever needed we could extend
that to check for known custom environment vars (NetworkManager =>
CONNECTION_UUID; networkd-dispatcher => OperationalState).

[1]: https://developer.gnome.org/NetworkManager/stable/NetworkManager.html
[2]: https://github.com/craftyguy/networkd-dispatcher
[3]: https://github.com/systemd/systemd/blob/master/src/systemd/sd-network.h#L86

Signed-off-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
2018-04-18 15:55:07 +02:00
Miroslav Lichvar
bf7aa52394 sys_linux: fix building with old libcap versions
The cap_get_bound() function and CAP_IS_SUPPORTED macro were added in
libcap-2.21. Check if the macro is defined before use.

The sys/capability.h header from libcap-2.16 and earlier disables the
linux/types.h header, which breaks the linux/ptp_clock.h header. Change
the order to include sys/capability.h as the last system header.
2018-04-05 16:18:23 +02:00
Miroslav Lichvar
366345790d doc: update NEWS 2018-04-04 09:18:44 +02:00
Miroslav Lichvar
f881c153bf client: update copyright years 2018-04-04 09:18:44 +02:00
Miroslav Lichvar
19f3ab2225 ntp: fix handling of socket errors with error queue
In the next Linux version the recvmmsg() system call will be probably
fixed to not return socket errors (e.g. due to ICMP) when reading from
the error queue.

The NTP I/O code assumed this was the correct behavior. When the system
call is fixed, a socket error on a client socket will cause chronyd to
enter a busy loop consuming the CPU until the receive timeout is reached
(8 seconds by default).

Use getsockopt(SO_ERROR) to clear the socket error when reading from the
error queue failed.
2018-04-04 09:18:44 +02:00
Miroslav Lichvar
fd1e80802f privops: allow binding to acquisition port
Fix the privileged helper process to allow binding of client sockets to
a non-zero acquisition port which is not equal to the server port.
2018-04-04 09:18:34 +02:00
Miroslav Lichvar
4b7cb161a8 doc: improve FAQ 2018-03-28 16:57:48 +02:00
Miroslav Lichvar
7848794222 doc: improve description of fallbackdrift directive 2018-03-28 16:57:48 +02:00
Miroslav Lichvar
94822d5156 doc: improve description of key option in chrony.conf man page 2018-03-28 16:57:48 +02:00
Miroslav Lichvar
e3f840aae9 doc: update installation document 2018-03-28 16:57:48 +02:00
Miroslav Lichvar
5aae563277 update copyright years 2018-03-28 16:57:48 +02:00
Miroslav Lichvar
02de782fa3 ntp: fix compiler warnings
Warnings about using uninitialized variables were seen with gcc-7.3.1
and -O3 in CFLAGS.
2018-03-28 16:57:48 +02:00
Miroslav Lichvar
3f6df33feb configure: include SECHASH in chronyc features
chronyc is linked with the crypto library and the keygen command checks
if the specified hash function is known.
2018-03-28 16:57:48 +02:00
Miroslav Lichvar
a94f5fe007 test: extend 126-burst 2018-03-28 16:57:48 +02:00
Miroslav Lichvar
63f0234748 test: fix hash unit test for NSS
Some hash functions in the freebl3 library ignore the length of the
output buffer and always return the length of the digest.
2018-03-28 16:57:48 +02:00
Miroslav Lichvar
47921c7c0c hash: initialize return value before calling NSS hash functions
Some hash functions in the freebl3 library don't support truncated
digests and either return immediately with no update of the output
length, or ignore the length of the output buffer and always write whole
digest.

Initialize the return value to zero to get correct result with the
former.

This is triggered only in the hash unit test. chronyd always provides a
sufficient buffer for the digest.
2018-03-28 16:57:48 +02:00
Miroslav Lichvar
42a85f685e doc: update NEWS 2018-03-15 09:00:47 +01:00
Miroslav Lichvar
feca2399e4 hash: add support for older nettle versions
Use nettle_hashes[] instead of nettle_get_hashes(), which is available
only in nettle >= 3.4. nettle_hashes[] is a symbol available in older
versions and may be renamed in future. In nettle >= 3.4 it is a macro
using nettle_get_hashes() for compatibility.
2018-03-15 09:00:09 +01:00
Miroslav Lichvar
d34e611ec8 doc: update README 2018-03-14 16:14:56 +01:00
Christian Ehrhardt
02098ed830 sys_linux: report if CAP_SYS_TIME is not present
Instead of having adjtimex just fail with a permission issue
improve the error messaging by warning for the lack of
CAP_SYS_TIME on SYS_Linux_Initialise.

Message will look like (instead of only the latter message):
 CAP_SYS_TIME not present
 adjtimex(0x8001) failed : Operation not permitted

Signed-off-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
2018-03-14 16:14:56 +01:00
Miroslav Lichvar
aa4228bf1b doc: improve description of -x in chronyd man page 2018-03-14 14:59:41 +01:00
Miroslav Lichvar
b296441708 ntp: fix adjustment of init_local_rx timestamp
This fixes commit f0f18a02a7.
2018-03-14 14:59:41 +01:00
Miroslav Lichvar
b827475378 ntp: add debug message to update of link speed 2018-03-14 14:59:41 +01:00
Miroslav Lichvar
78a6698ae1 test: update compilation test to disable nettle 2018-03-13 10:46:57 +01:00
Miroslav Lichvar
e7b6feb34b doc: update supported hash functions in chrony.conf man apge 2018-03-13 10:46:57 +01:00
Miroslav Lichvar
84be834385 hash: add support for nettle 2018-03-13 10:46:57 +01:00
Miroslav Lichvar
e83d808dfd hash: add support for SHA-3 with libtomcrypt 2018-03-13 10:44:24 +01:00
Miroslav Lichvar
35a68d5b59 test: add hash unit test 2018-03-13 10:44:24 +01:00
Miroslav Lichvar
3c593137b0 doc: fix typo in chrony.conf man page 2018-03-12 12:42:05 +01:00
Miroslav Lichvar
deaf0ffed3 ntp: add missing breaks in switch statement
Fortunately, they didn't change the behavior of the code.
2018-03-12 12:42:05 +01:00
Miroslav Lichvar
af145e871e test: use random version in ntp_core unit test 2018-03-07 13:17:55 +01:00
Miroslav Lichvar
fbca570d0b ntp: respond to NTPv1 client requests with zero mode
NTPv1 packets have a reserved field instead of the mode field and the
actual mode is determined from the port numbers. It seems there is still
a large number of clients sending NTPv1 requests with a zero value in
the field (per RFC 1059).

Follow ntpd and respond to the requests with server mode packets.
2018-03-07 11:36:11 +01:00
Miroslav Lichvar
448ef779c2 client: improve handling of unknown responses
Rework the code to not ignore valid packets with unknown or obsolete
responses and return immediately with "bad reply from daemon" instead of
timing out with "cannot talk to daemon".
2018-03-06 13:47:25 +01:00
Miroslav Lichvar
499a69e611 cmdmon: initialize all bytes of reply buffer
Instead of zeroing individual fields, zero all bytes of the buffer
before the reply is formed.

This may have a small impact on performance, but it simplifies the code
and minimizes the risk of leaking uninitialized memory.
2018-03-06 13:47:25 +01:00
Miroslav Lichvar
58c2915878 cmdmon: update protocol changelog 2018-03-06 13:47:25 +01:00
Miroslav Lichvar
eda4b111d3 cmdmon: make length of manual list constant
Make the length of responses containing manual samples constant to
simplify the protocol. It was the only type of response that had a
variable length.

This reverts commit 2343e7a89c.
2018-03-06 13:47:25 +01:00
Miroslav Lichvar
c6dd749687 ntp: check RX and TX timestamp in interleaved client requests
Clients sending packets in the interleaved mode are supposed to use
a different receive and transmit timestamp in order to reliably detect
the mode of the response. If an interleaved request with the receive
timestamp equal to the transmit timestamp is detected, respond in the
basic mode.
2018-03-06 13:47:25 +01:00
Miroslav Lichvar
d2a96f5fbc doc: update README 2018-03-02 14:46:08 +01:00
Miroslav Lichvar
499f513d40 cmdmon: add shutdown command
The command is functionally equivalent to sending the process the
SIGTERM signal.
2018-03-02 13:04:14 +01:00
Miroslav Lichvar
8b1f68b1b4 ntp: delay enabling permanent kernel RX timestamping on Linux
Wait until a kernel RX timestamp is actually missing before opening the
dummy socket in order to avoid a small performance impact in case the
servers are so slow/distant that the kernel can constantly win the race.
2018-03-02 13:03:26 +01:00
Miroslav Lichvar
8e4c776900 test: add 126-burst test 2018-02-28 10:09:47 +01:00
Miroslav Lichvar
d0eb9427c2 ntp: add burst option
When the burst option is specified in the server/pool directive and the
current poll is longer than the minimum poll, initiate on each poll a
burst with 1 good sample and 2 or 4 total samples according to the
difference between the current and minimum poll.
2018-02-28 10:09:47 +01:00
Miroslav Lichvar
7d100b89fc doc: improve description of server options 2018-02-28 10:08:58 +01:00
Miroslav Lichvar
a4bd7f1800 test: make 119-smoothtime more reliable 2018-02-26 17:24:08 +01:00
Miroslav Lichvar
5308e0a25f sources: include maxclockerror in source selection
In the source selection algorithm, include extra dispersion due to
maxclockerror in the root distance of sources that don't have new
samples (the last sample is older than span of all samples) to not
prefer unreachable sources with a short distance and small skew over
reachable sources for too long, and also to decrease their chances of
becoming falsetickers.
2018-02-26 13:42:04 +01:00
Miroslav Lichvar
da862158bf main: open /dev/null as stdin/out/err in daemonization
chronyd doesn't normally write anything to stdout or stderr when running
as a daemon, but it is a good practice to replace them with descriptors
of /dev/null to prevent accidental writes to other files or sockets that
would otherwise take their place.
2018-02-26 13:42:04 +01:00
Miroslav Lichvar
7b98443a13 logging: don't write fatal messages to invalid descriptor
If opening the log file specified with the -l option failed (after
closing all descriptors), the error message is written to an invalid
descriptor as no log file or syslog is opened yet. Fix the code to track
when the output is usable.
2018-02-26 13:42:04 +01:00
Miroslav Lichvar
4da9f74d24 util: replace assert for missing MD5 with fatal log message
Apparently, on some systems the MD5 function is missing with the NSS
support (freebl3). Instead of failing an assertion, exit with a log
message.
2018-02-26 13:42:04 +01:00
Miroslav Lichvar
e41042e258 test: update util unit test 2018-02-26 13:42:04 +01:00
Miroslav Lichvar
5581466c63 test: improve and extend ntp_core unit test 2018-02-26 13:42:04 +01:00
Miroslav Lichvar
e79a6c2116 sourcestats: limit minimum value of std_dev 2018-02-26 13:42:04 +01:00
Miroslav Lichvar
666ece122e ntp: compare receive timestamp when checking for duplicate
Compare both receive and transmit timestamps in the NTP test number 1.

This prevents a client from dropping a valid response in the interleaved
mode if it follows a response in the basic mode and the server did not
have a kernel/hardware transmit timestamp, and the random bits of the
two timestamps happen to be the same (chance of 1 in 2^(32-precision)).
2018-02-26 13:42:04 +01:00
Miroslav Lichvar
2c7ab98370 ntp: don't send packets with RX/TX timestamp equal to another timestamp
Before sending a new packet, check if the receive/transmit timestamp
is not equal to the origin timestamp or the previous receive/transmit
timestamp in order to prevent the packet from being its own valid
response (in the symmetric mode) and invalidate responses to the
previous packet.

This improves protection against replay attacks in the symmetric mode.
2018-02-26 13:42:04 +01:00
Miroslav Lichvar
f0f18a02a7 ntp: separate timestamps for restarting symmetric protocol
Save the local receive and remote transmit timestamp needed for
(re)starting the symmetric protocol when no valid reply was received
separately from the timestamps that are used for synchronization of the
local clock.

This extends the interval in which the local NTP state is (partially)
protected against replay attacks in order to complete a measurement
in the interleaved symmetric mode from [last valid RX, next TX] to
[last TX, next TX], i.e. it should be the same as in the basic mode.
2018-02-26 13:42:04 +01:00
Miroslav Lichvar
c5d8af0285 main: create directories before refclock initialization
This allows the SOCK refclock to open sockets in the /var/run/chrony
directory.
2018-02-16 11:09:54 +01:00
Miroslav Lichvar
0ce15a8472 main: improve error message for failed getpwnam() 2018-02-16 11:09:54 +01:00
Miroslav Lichvar
da60629201 configure: improve check for timestamping options
The socket.h header provided by musl doesn't seem to include the kernel
headers and is missing SCM_TIMESTAMPING_PKTINFO, which causes the
Linux-specific code in chrony to fail to build.
2018-02-16 11:09:54 +01:00
Miroslav Lichvar
2343e7a89c pktlength: handle truncated MANUAL_LIST reply
Before reading the n_samples field of the MANUAL_LIST reply, check if it
is actually contained in the received message. This does not change the
outcome of the client's length check as the returned length was always
larger than the length of the truncated reply and it was dropped anyway,
but it prevents the client from reading uninitialized memory.
2018-02-16 11:09:54 +01:00
Miroslav Lichvar
45f27f4f5e sourcestats: reset instance before loading dump file
Don't rely on the caller to reset the instance and always reset it
before loading data to make sure it can't get to an unexpected state.
2018-02-16 11:09:54 +01:00
Miroslav Lichvar
0bc112f8b4 doc: improve description of refclock tai option
Emphasize that tzdata must be kept up to date in order for the
correction to work as expected.
2018-02-16 11:09:54 +01:00
Miroslav Lichvar
bfc2fa645c test: add 125-packetloss test 2018-02-16 11:09:54 +01:00
Miroslav Lichvar
11111804fd test: extend 106-refclock 2018-02-16 11:09:54 +01:00
Miroslav Lichvar
87ec67247e test: extend 110-chronyc 2018-02-16 11:09:54 +01:00
Miroslav Lichvar
0df8328ceb ntp: keep kernel RX timestamping permanently enabled on Linux
The Linux kernel has a counter for sockets using kernel RX timestamping
and timestamps (all) received packets only when it is not zero. However,
this counter is updated asynchronously from setsockopt(). If there are
currently no other sockets using the timestamping, it is possible that a
fast server response is received before the kernel timestamping is
actually enabled after setting the socket option and sending a request.

Open a dummy socket on start to make sure there is always at least one
timestamping socket to avoid the race condition.
2018-02-16 11:09:54 +01:00
Miroslav Lichvar
b563048ee2 examples: ignore non-up/down events in nm-dispatcher script 2018-02-16 11:09:54 +01:00
Miroslav Lichvar
e8096330be sys_linux: don't keep CAP_SYS_TIME with -x option
When dropping the root privileges, don't try to keep the CAP_SYS_TIME
capability if the -x option was enabled. This allows chronyd to be
started without the capability (e.g. in containers) and also drop the
root privileges.
2018-02-05 14:05:19 +01:00
Miroslav Lichvar
b1647dbcb7 ntp: wait for late HW TX timestamps
When sending client requests to a close and fast server, it is possible
that a response will be received before the HW transmit timestamp of
the request itself. To avoid processing of the response without the HW
timestamp, monitor events returned by select() and suspend reading of
packets from the receive queue for up to 200 microseconds. As the
requests are normally separated by at least 200 milliseconds, it is
sufficient to monitor and suspend one socket at a time.
2018-02-02 11:36:38 +01:00
Miroslav Lichvar
4ddadd5622 ntp: don't request TX timestamp when SW/HW timestamping is disabled 2018-02-01 17:27:45 +01:00
Miroslav Lichvar
3e854006c7 ntp: add missing header guard 2018-01-31 17:23:40 +01:00
Miroslav Lichvar
2c4c235147 sched: allow enabling/disabling individual file handler events 2018-01-30 15:56:51 +01:00
Miroslav Lichvar
6863e43269 client: avoid reading clock after sending request
If chronyc sent a request which caused chronyd to step the clock (e.g.
makestep, settime) and the second reading of the clock before calling
select() to wait for a response happened after the clock was stepped, a
new request could be sent immediately and chronyd would process the same
command twice. If the second request failed (e.g. a settime request too
close to the first request), chronyc would report an error.

Change the submit_request() function to read the clock only once per
select() to wait for the first response even when the clock was stepped.
2017-12-12 11:37:36 +01:00
Miroslav Lichvar
de8708f331 client: remove unused file descriptor sets 2017-12-05 12:13:40 +01:00
Miroslav Lichvar
d0b2486036 client: don't call select() with invalid timeout
If the system clock was stepped forward after chronyc sent a request and
before it read the clock in order to calculate the receive timeout,
select() could be called with a negative timeout, which resulted in an
infinite loop waiting for select() to succeed.

Fix the submit_request() function to not call select() with a negative
timeout. Also, return immediately on any error of select().
2017-12-05 12:13:37 +01:00
Miroslav Lichvar
5384a93645 test: extend util unit test 2017-12-05 10:14:19 +01:00
Miroslav Lichvar
4bbc768652 util: avoid casting to long in UTI_DoubleToTimeval() 2017-12-05 09:44:59 +01:00
Vincent Blut
fead915b45 doc: fix typo in chronyd man page 2017-12-04 11:16:20 +01:00
Miroslav Lichvar
5422e49026 doc: improve leapsectz description 2017-10-12 14:07:12 +02:00
Miroslav Lichvar
77a1f27a1d test: add 124-tai test 2017-10-11 17:49:30 +02:00
Miroslav Lichvar
b45d864f73 test: check for maxchange message in check_chronyd_exit() 2017-10-11 17:49:21 +02:00
Miroslav Lichvar
f35c81c871 refclock: improve TAI-UTC conversion
Instead of using the TAI-UTC offset which corresponds to the current
system time, get the offset for the reference time. This allows the
clock to be accurately stepped from a time with different TAI-UTC
offset.
2017-10-11 17:45:21 +02:00
Miroslav Lichvar
a349b2803c refclock: remove unnecessary return statements 2017-10-11 17:28:34 +02:00
Chris Perl
f5d1b8fb74 refclock: add tai option
This option is for indicating to chronyd that the reference clock is
kept in TAI and that chrony should attempt to convert from TAI to UTC by
using the timezone configured by the "leapsectz" directive.
2017-10-11 17:28:34 +02:00
Chris Perl
a0fe71eef1 reference: add function to get TAI-UTC offset 2017-10-11 17:28:34 +02:00
Andreas Steinmetz
154b39cf7a refclock: add stratum option 2017-10-09 10:39:20 +02:00
Bernhard M. Wiedemann
6f54210db2 configure: allow to override build date
in order to make builds reproducible.
See https://reproducible-builds.org/ for why this is good
and https://reproducible-builds.org/specs/source-date-epoch/
for the definition of this variable.
2017-10-05 18:18:07 +02:00
Miroslav Lichvar
f6539449c5 nameserv: set hints for getaddrinfo() according to -4/-6 option
Avoid sending unnecessary DNS requests when the -4/-6 option is
specified.
2017-10-04 11:20:10 +02:00
Miroslav Lichvar
b8d546a0d1 examples: add leapsectz to configuration examples 2017-09-15 08:32:09 +02:00
Miroslav Lichvar
04e6474b75 reference: check for gmtime() error
Although gmtime() is expected to convert any time of the system clock at
least in the next few NTP eras, a correct code should always check the
returned value and this shouldn't be a fatal error in handling of leap
seconds.
2017-09-15 08:32:08 +02:00
Vincent Blut
eb51c500e8 doc: fix typo in chrony.conf man page 2017-09-11 11:21:13 +02:00
Miroslav Lichvar
6f8fba9a3f conf: check if GLOB_NOMAGIC is defined
This option is not supported by musl and possibly other libc
implementations.
2017-09-01 11:32:16 +02:00
Miroslav Lichvar
750afc30f2 test: fix keys unit test 2017-09-01 11:28:55 +02:00
Miroslav Lichvar
e0e6ec0d84 doc: update NEWS 2017-08-29 14:17:35 +02:00
Miroslav Lichvar
c9f50fc686 update copyright years 2017-08-28 14:38:23 +02:00
Miroslav Lichvar
83c26b458b doc: fix spelling
Don't mix UK and US spelling.
2017-08-28 14:38:19 +02:00
Miroslav Lichvar
b711873f45 test: add 123-mindelay test 2017-08-28 14:27:14 +02:00
Miroslav Lichvar
c68ca40ce4 ntp: improve maxdelayratio test
Similarly to the maxdelaydevratio test, include in the maximum delay
dispersion which accumulated in the interval since the last sample.
Also, enable the test for symmetric associations.
2017-08-28 14:27:14 +02:00
Miroslav Lichvar
51fe80ad95 sourcestats: move maxdelaydevratio test to ntp_core
Instead of giving NTP-specific data to sourcestats in order to perform
the test, provide a function to get all data needed for the test in
ntp_core. While at it, improve the naming of variables.
2017-08-28 14:27:14 +02:00
Miroslav Lichvar
7ffee73524 memory: check for overflow when (re)allocating array
When (re)allocating an array with very large number of elements using
the MallocArray or ReallocArray macros, the calculated size of the array
could overflow size_t and less memory would be allocated than requested.

Add new functions for (re)allocating arrays that check the size and use
them in the MallocArray and ReallocArray macros.

This couldn't be exploited, because all arrays that can grow with cmdmon
or NTP requests already have their size checked before allocation, or
they are much smaller than memory allocated for structures to which they
are related (i.e. ntp_core and sourcestats instances), so a memory
allocation would fail before their size could overflow.

This issue was found in an audit performed by Cure53 and sponsored by
Mozilla.
2017-08-28 14:27:14 +02:00
Miroslav Lichvar
f40b0024bd util: check for gmtime() error
Fix the UTI_TimeToLogForm() function to check if gmtime() didn't fail.
This caused chronyc to crash due to dereferencing a NULL pointer when
a response to the "manual list" request contained time which gmtime()
could not convert to broken-down representation.

This issue was found in an audit performed by Cure53 and sponsored by
Mozilla.
2017-08-28 14:27:14 +02:00
Miroslav Lichvar
a06c9909a6 conf: use enum for RX filter 2017-08-23 15:01:30 +02:00
Miroslav Lichvar
aee42fada8 ntp: allow TX-only HW timestamping by default
If no rxfilter is specified in the hwtimestamp directive and the NIC
doesn't support the all or ntp filter, enable TX-only HW timestamping
with the none filter.
2017-08-23 15:01:30 +02:00
Miroslav Lichvar
3e93068c43 hwclock: improve debug message 2017-08-23 15:01:30 +02:00
Miroslav Lichvar
36291b707b hwclock: check if estimated frequency is sane 2017-08-23 15:01:30 +02:00
Miroslav Lichvar
6dad2c24bf hwclock: drop all samples on reset
On some HW it seems it's possible to get an occasional bad reading of
the PHC (with normal delay), or in a worse case the clock can step due
to a HW/driver bug, which triggers reset of the HW clock instance. To
avoid having a bad estimate of the frequency when the next (good) sample
is accumulated, drop also the last sample which triggered the reset.
2017-08-23 15:01:30 +02:00
Miroslav Lichvar
27cbf20d23 doc: include uncorrected offset in bound on maximum error 2017-08-23 15:01:30 +02:00
Miroslav Lichvar
5c571bbbe7 reference: add new fields to tracking log
Add the root delay, root dispersion and maximum estimated error in the
interval since the previous update to the tracking log.
2017-08-23 15:01:30 +02:00
Miroslav Lichvar
33d65c8614 reference: separate calculation of root dispersion 2017-08-23 15:01:30 +02:00
Miroslav Lichvar
d87db7cdb8 reference: refactor log writing
Remove unnecessary parameters of the write_log() function.
2017-08-23 15:01:30 +02:00
Miroslav Lichvar
45fa4750da reference: don't update fallback drift on manual input
This fixes a crash due to assertion failure in update_fb_drifts() when
fallbackdrift is enabled and manual input is provided.
2017-08-23 15:01:30 +02:00
Miroslav Lichvar
8472fd8133 reference: simplify check for NaN 2017-08-23 15:01:30 +02:00
Miroslav Lichvar
5ab645e310 cmdmon: add new fields to ADD_SERVER/ADD_PEER request 2017-08-23 15:01:30 +02:00
Miroslav Lichvar
8ccda538d3 conf: add mindelay and asymmetry options to NTP sources 2017-08-23 15:01:28 +02:00
Miroslav Lichvar
b06d74ab73 sourcestats: add fixed asymmetry
Rework the code to allow the jitter asymmetry to be specified.
2017-08-23 14:33:23 +02:00
Miroslav Lichvar
d0964ffa83 sourcestats: add fixed minimum delay
If the minimum delay is known (in a static network configuration), it
can replace the measured minimum from the register. This should improve
the stability of corrections for asymmetric jitter, sample weighting and
maxdelay* tests.
2017-08-23 14:14:06 +02:00
Miroslav Lichvar
3d08815efb sys_linux: fix building with older kernel headers
Programming pins for external PHC timestamping was added in Linux 3.15,
but the PHC subsystem is older than that. Compile the programming code
only when the ioctl is defined.
2017-08-15 13:39:39 +02:00
Miroslav Lichvar
a83f0d3cdc util: simplify clamping in UTI_TimespecNetworkToHost()
This should fix a coverity warning.
2017-08-15 13:27:50 +02:00
Miroslav Lichvar
702db726d3 util: add assertion for NTP timestamp size 2017-08-15 13:27:50 +02:00
Miroslav Lichvar
ed5c43204b smooth: don't adjust invalid time of last update 2017-08-15 13:27:50 +02:00
Miroslav Lichvar
f91bdd604d reference: don't adjust invalid reference time 2017-08-15 13:27:50 +02:00
Miroslav Lichvar
3a1dbb1354 test: fix ntp_core unit test
This fixes commit b896bb5a78.
2017-08-09 10:41:30 +02:00
Bryan Christianson
4b511143b8 sys_netbsd: fix adjtime() fault on macOS
On some systems, passing NULL as the first argument to adjtime, will
result in returning the amount of adjustment outstanding from a previous
call to adjtime().

On macOS this is not allowed and the adjtime call will fault. We can
simulate the behaviour of the other systems by cancelling the current
adjustment then restarting the adjustment using the outstanding time
that was returned. On macOS 10.13 and later, the netbsd driver is now
used and must use these semantics when making/measuring corrections.
2017-08-09 09:57:14 +02:00
Miroslav Lichvar
93076e7e1c client: fix parsing of -v command option
The sources and sourcestats commands accept -v as an option, but the
glibc implementation of getopt() reorders the arguments and parses the
option as a command-line option of chronyc.

Add '+' to the getopt string to disable this feature. Other getopt()
implementations should consider it a new command-line option, which will
be handled as an error if present.
2017-08-09 09:57:14 +02:00
Miroslav Lichvar
1c51feb3c5 sched: add new timeout class for peer transmissions
This allows transmissions in symmetric mode to be scheduled
independently from client transmissions. This reduces maximum delay
in scheduling when chronyd is configured with a larger number of
servers.
2017-08-09 09:57:14 +02:00
Miroslav Lichvar
c2773dbc2f test: improve hwclock unit test 2017-08-09 09:57:14 +02:00
Miroslav Lichvar
4534db84c4 hwclock: fix conversion of HW timestamps
Fix a sign error in conversion of HW time to local time, which caused
the jitter to be amplified instead of reduced. NTP with HW timestamping
should now be more stable and able to ignore occasionally delayed
readings of PHC.
2017-08-09 09:57:14 +02:00
Miroslav Lichvar
be8215e181 ntp: minimize data in client mode packets
In basic client mode, set the origin and receive timestamp to zero.
This reduces the amount of information useful for fingerprinting and
improves privacy as the origin timestamp allows a passive observer to
track individual NTP clients as they move across networks. (With chrony
clients that assumes the timestamp wasn't reset by the chronyc offline
and online commands.)

This follows recommendations from the current version of IETF draft on
NTP data minimization [1].

The timestamp could be theoretically useful for enhanced rate limiting
which can limit individual clients behind NAT and better deal with DoS
attacks, but no server implementation is known to do that.

[1] https://tools.ietf.org/html/draft-ietf-ntp-data-minimization-01
2017-08-09 09:57:13 +02:00
Miroslav Lichvar
ae82bbbace examples: improve NetworkManager dispatcher script
When no default route is configured, check each source if it has a
route. If the system has multiple network interfaces, this prevents
setting local NTP servers to offline when they can still be reached over
one of the interfaces.
2017-08-09 09:57:13 +02:00
Miroslav Lichvar
2b6ea41062 doc: fix server mode number in chrony.conf man page 2017-08-09 09:57:13 +02:00
Miroslav Lichvar
d9f745fe70 doc: update chrony.conf man page for recent changes 2017-08-09 09:57:13 +02:00
Miroslav Lichvar
9aac179367 ntp: skip IPv6 extension headers
Handle IPv6 packets with extension headers received from the error queue
on Linux.
2017-08-09 09:57:13 +02:00
Miroslav Lichvar
b896bb5a78 ntp: don't send useless requests in interleaved client mode
In interleaved client mode, when so many consecutive requests were lost
that the first valid (interleaved) response would be dropped for being
too old, switch to basic mode so the response can be accepted if it
doesn't fail in the other tests.

This reworks commit 16afa8eb50.
2017-08-09 09:57:13 +02:00
Miroslav Lichvar
64c2fd9888 ntp: limit number of interleaved responses in symmetric mode
In symmetric mode, don't send a packet in interleaved mode unless it is
the first response to the last valid request received from the peer and
there was just one response to the previous valid request. This prevents
the peer from matching the transmit timestamp with an older response if
it can't detect missed responses.
2017-08-09 09:57:13 +02:00
Miroslav Lichvar
2668a12e4e ntp: improve detection of missed packets in interleaved mode
In interleaved symmetric mode, check if the remote TX timestamp is
before RX timestamp. Only the first response from the peer after
receiving a request should pass this test. Check also the interval
between last two remote transmit timestamps when we know the remote poll
can't be constrained by minpoll. Use the minimum of previous remote and
local poll as a lower bound of the actual interval between peer's
transmissions.
2017-08-09 09:57:13 +02:00
Miroslav Lichvar
e1645966ec ntp: enable maxdelayratio test in interleaved client mode
With more accurate delay in interleaved mode the test should now be as
reliable as in basic mode.
2017-08-09 09:57:13 +02:00
Bryan Christianson
4f1fc1ee78 main: fix -q option
Attempting to step the system clock by using the -q option with chronyd
would fail.
2017-08-09 09:57:13 +02:00
Miroslav Lichvar
d70df3daab logging: enable line buffering of file log
The file log specified with the -l option should have the messages as
soon as they are produced.
2017-08-08 15:37:59 +02:00
Miroslav Lichvar
554b9b06de doc: update NEWS 2017-07-25 17:54:01 +02:00
Miroslav Lichvar
f734bd1a7c sys_linux: allow getrandom in seccomp filter
This fixes commit c5735ebfe9.
2017-07-25 17:40:35 +02:00
Miroslav Lichvar
77fc5c42b9 client: don't allow slash with hostname in allow/deny command 2017-07-25 17:40:35 +02:00
Miroslav Lichvar
ea85bc43e0 conf: don't allow slash with hostname in allow/deny directive 2017-07-25 17:40:35 +02:00
Miroslav Lichvar
e8fb11c433 reference: don't report zero stratum when synchronised
If synchronised to a stratum 15 source, return stratum of 16 instead of
0 in the tracking report. It will not match the value in server mode
packets, but it should be less confusing.
2017-07-25 17:40:35 +02:00
Miroslav Lichvar
01a29c7a11 cmdmon: report offset after manual timestamp as float
Modify the protocol to report the offset as seconds in floating point
instead of integer number of centiseconds.
2017-07-25 17:40:35 +02:00
Miroslav Lichvar
6ec3dc1650 manual: handle failed robust regression 2017-07-25 17:40:35 +02:00
Miroslav Lichvar
0c54cf316d util: avoid undefined behavior in timestamp conversion 2017-07-25 17:40:35 +02:00
Miroslav Lichvar
bd3fb49a1e client: avoid undefined bit shifts 2017-07-25 17:40:35 +02:00
Miroslav Lichvar
f6e72a80e1 regress: avoid undefined behavior in pointer arithmetic 2017-07-21 17:14:15 +02:00
Miroslav Lichvar
c2ab1426e5 ntp: simplify get_poll_adj() 2017-07-21 16:27:03 +02:00
Miroslav Lichvar
fa2c59d78d sourcestats: increase number of samples needed to check delay
Require at least 6 samples to check the increase in the delay of a new
sample to make it more reliable.
2017-07-21 16:27:03 +02:00
Miroslav Lichvar
16afa8eb50 ntp: don't accumulate old samples in interleaved client mode
Check how many responses were missing before accumulating a sample using
old timestamps to avoid correcting the clock with an offset extrapolated
over a long interval.

This should be eventually done in sourcestats for all sources.
2017-07-21 16:27:03 +02:00
Miroslav Lichvar
992590e99c ntp: revert reversed poll tracking in interleaved mode
With the new selection of timestamps in the interleaved mode it's no
longer necessary to reverse the poll tracking in order to reduce the
local and remote intervals of measurements that makes the peer with
higher stratum.

This reverts commit 4a24368763.
2017-07-21 16:27:03 +02:00
Miroslav Lichvar
0baa35eade ntp: select timestamps in interleaved mode
Use previous local TX and remote RX timestamps for the new sample in the
interleaved mode if it will make the local and remote intervals
significantly shorter in order to improve the accuracy of the measured
delay.
2017-07-21 16:27:03 +02:00
Miroslav Lichvar
2e0870ee0c ntp: refactor timestamp selection and interval calculation
Prepare the code for a third option in the timestamp selection and clean
it up a bit.
2017-07-21 16:27:03 +02:00
Miroslav Lichvar
43cd119d6d ntp: add function for zeroing local timestamps 2017-07-21 16:27:03 +02:00
Miroslav Lichvar
62cd319a51 ntp: fix poll in source report
The source report used the local interval, which in symmetric mode may
be longer than the actual interval used for transmission.
2017-07-14 20:25:50 +02:00
Miroslav Lichvar
d0f789425b ntp: ignore saved remote poll when peer is not responding
When a peer stops responding, allow our actual polling interval to be
longer than poll saved from the last valid response.
2017-07-14 20:06:31 +02:00
Miroslav Lichvar
30e6549692 ntp: reset TX counter on all valid responses
Also change it to an unsigned type.
2017-07-14 19:40:44 +02:00
Miroslav Lichvar
043c7d7c9f configure: fix compiler warning in getrandom() test 2017-07-14 10:21:31 +02:00
Miroslav Lichvar
1c277a8850 configure: check for hardening compiler options
If no CFLAGS are specified, check if common security hardening options
are supported and add them to the CFLAGS/LDFLAGS. These are typically
enabled in downstream packages, but users compiling chrony from sources
with default CFLAGS should get hardened binaries too.
2017-07-13 16:12:25 +02:00
Bryan Christianson
ccb94ac5fb sys_macosx: add support for ntp_adjtime() on macOS 10.13+
macOS 10.13 will implement the ntp_adjtime() system call, allowing
better control over the system clock than is possible with the existing
adjtime() system call. chronyd will support both the older and newer
calls, enabling binary code to run without recompilation on macOS 10.9
through macOS 10.13.

Early releases of macOS 10.13 have a very buggy adjtime() call. The
macOS driver tests adjtime() to see if the bug has been fixed. If the
bug persists then the timex driver is invoked otherwise the netbsd
driver.
2017-07-13 16:10:54 +02:00
Miroslav Lichvar
778fce4039 main: don't require root privileges with -Q option
If the -Q option is specified, disable by default pidfile, ntpport,
cmdport, Unix domain command socket, and clock control, in order to
allow starting chronyd without root privileges and/or when another
chronyd instance is already running.
2017-07-13 16:10:54 +02:00
Miroslav Lichvar
9983185d6d ntp: define NTP port for configuration code 2017-07-13 16:10:54 +02:00
Miroslav Lichvar
7bd1c02781 main: refactor check of pidfile 2017-07-13 16:10:54 +02:00
Miroslav Lichvar
760285218f sys_timex: fix update of TAI offset on non-Linux systems
The tai field in struct timex is a Linux-specific feature. It's possible
to read the current offset with ntp_gettime() (or ntp_gettimex() on
Linux), but apparently not all libc implementations support it.

Rework the code to save and adjust the last value instead of reading
the current value from the kernel.
2017-07-11 11:28:34 +02:00
Miroslav Lichvar
4fe0e6b7fd sys_timex: rename status variable 2017-07-10 14:48:47 +02:00
Miroslav Lichvar
0773a1e630 ntp: fix debug message about unknown HW timestamping ifindex 2017-06-30 17:01:06 +02:00
Miroslav Lichvar
4a24368763 ntp: reverse poll tracking in interleaved symmetric mode
Unlike in the basic mode, the peer with a higher stratum needs to wait
for a response before sending the next request in order to minimize the
delay of the measurement and error in the measured delay.

Slightly increase the delay adjustment to make it work with older chrony
versions.
2017-06-30 17:01:06 +02:00
Miroslav Lichvar
577290c5bc ntp: fix poll interleaving with unsynchronised peers
Update the remote poll and remote stratum even for unsychronised peers,
and handle stratum of 0 as 16, so the peers work with the opposite
differences between their strata and can adjust their polling intervals
in order to interleave the packets.
2017-06-30 17:01:01 +02:00
Miroslav Lichvar
854ff69f78 hwclock: decrease tolerance of robust regression to 0.1 ppb 2017-06-30 16:58:57 +02:00
Miroslav Lichvar
29b0ad894c reference: get TAI-UTC offset from leap second timezone
Use the timezone specified by the leapsectz directive to get the
current TAI-UTC offset and set the offset of the system clock in order
to provide correct TAI time to applications using ntp_adjtime(),
ntp_gettime(), or clock_gettime(CLOCK_TAI).
2017-06-30 16:58:53 +02:00
Miroslav Lichvar
cde0a20307 sys_timex: add support for setting TAI-UTC offset 2017-06-30 13:43:35 +02:00
Miroslav Lichvar
a768578a26 local: add support for setting TAI-UTC offset 2017-06-30 13:43:35 +02:00
Miroslav Lichvar
5d838729ef reference: move static tz variables to function using them 2017-06-30 13:43:35 +02:00
Miroslav Lichvar
d6b763dc24 client: check IP address family before printing as refid 2017-06-30 13:43:27 +02:00
Miroslav Lichvar
95adb52a45 configure: add missing object for PHC refclock
This fixes commit eceb8d9937.
2017-06-27 15:29:02 +02:00
Miroslav Lichvar
707d9a3484 test: add regress unit test 2017-06-27 15:29:01 +02:00
Miroslav Lichvar
1872d4d195 test: fix crash when printing debug messages
This fixes commit 6cbeb107db.
2017-06-27 15:29:01 +02:00
Miroslav Lichvar
17f32c266e sourcestats: use median distance in weight calculation
Replace mean distance with median distance in the weight calculation.
This should make the weights less sensitive to outliers.
2017-06-27 15:29:01 +02:00
Miroslav Lichvar
6207655ab2 regress: provide function to find median 2017-06-27 15:29:01 +02:00
Miroslav Lichvar
5e1e31ad5f regress: reduce maximum number of points to 64
This corresponds to the maximum number of points used by regress users.
2017-06-27 15:29:01 +02:00
Miroslav Lichvar
13111c1dd8 regress: use chars instead of ints for flags
This reduces the size of the flags array on stack.
2017-06-27 15:29:01 +02:00
Miroslav Lichvar
85c84073c1 regress: fix assertion in robust regression 2017-06-27 15:29:01 +02:00
Miroslav Lichvar
c2944d8727 regress: speed up range expansion in robust regression
Instead of repeatedly expanding the range of b with the same increment,
double the range on each iteration to speed up the expansion. Also, add
a sanity check for the interval.
2017-06-27 15:29:01 +02:00
Miroslav Lichvar
e118b9b1e8 regress: fix robust regression
The bisection always terminated after one iteration. Change the code to
check if the middle is different from the lower and upper limits as
suggested in the original recipe.

This fixes commit b14689d59b.
2017-06-27 15:29:01 +02:00
Miroslav Lichvar
7fb7f95979 sourcestats: include precision in weight calculation
In order to stabilize the weights of refclock samples which have only
slightly different distances, don't allow the stddev value used in the
weight calculation to be smaller than the precision and also assign
weight of 1 to all samples which have distance < minimum + precision.
2017-06-27 15:29:01 +02:00
Miroslav Lichvar
cc507bffae conf: abort when include directive fails
When parsing the include directive, call glob() with the GLOB_ERR and
GLOB_NOMAGIC flags, and abort with an error message when matching of the
pattern failed with other error than GLOB_NOMATCH.

This restores the original behavior of the directive when it didn't
allow patterns, but it will still not fail with patterns not matching
any files in an existing directory.
2017-06-27 15:29:01 +02:00
Miroslav Lichvar
0dbfe020ad refclock: set default precision to precision of system clock 2017-06-27 15:29:01 +02:00
Miroslav Lichvar
018a1c42b0 ntp: suggest clients to increase their polling interval
When the poll value in a client request is smaller than the server's NTP
rate limiting interval, set poll in the response to the rate limiting
interval to suggest the client to increase its polling interval.

This follows ntpd as a server. No current client implementation seems to
be increasing its interval by the poll, but it may change in the future.
2017-06-27 15:29:01 +02:00
Miroslav Lichvar
c5735ebfe9 util: add support for getrandom()
Add support for the Linux getrandom() system call, which is available
in glibc since 2.25.
2017-06-27 15:29:01 +02:00
Miroslav Lichvar
db93180ce1 ntp: apply HW TX/RX compensation to system time
Apply the compensation to the cooked local time instead of HW time. This
might make a difference when the HW clock has a large frequency error.
2017-06-27 15:29:01 +02:00
Miroslav Lichvar
39da10d939 doc: update description of hwtimestamp directive 2017-06-27 15:29:01 +02:00
Miroslav Lichvar
f2da253bc3 ntp: add option to select HW RX timestamping filter
Add an rxfilter option to the hwtimestamp directive to select which
received packets should be timestamped. It can be set to "none", "ntp",
or "all". The default value is ntp, which falls back to all when ntp is
not supported.
2017-06-27 15:29:01 +02:00
Miroslav Lichvar
934d4047f1 ntp: add support for new Linux timestamping options
New timestamping options may be available in kernel 4.13. They can be
used to get the index of the interface which timestamped incoming packet
together with its length at layer 2, enable simultaneous SW and HW TX
timestamping, and enable a new RX filter for NTP packets.
2017-06-27 15:29:01 +02:00
Miroslav Lichvar
b799cfd1c4 ntp: always try to enable SW timestamping on Linux
Request SW timestamps with SCM_TIMESTAMPING even if HW timestamping is
enabled. This replaces SCM_TIMESTAMP(NS) for RX and enables TX SW
timestamping on interfaces that don't support HW timestamping (or don't
have it enabled) if another interface has HW timestamping enabled.
2017-06-27 15:29:01 +02:00
Miroslav Lichvar
b712c100d7 main: close logs as last thing before exit
This should prevent losing messages from other finalisation code.
2017-05-26 13:33:53 +02:00
Miroslav Lichvar
c049bce007 client: try to connect to all addresses before giving up
Don't give up when one of the addresses/hostnames specified by -h fails
to resolve in DNS_Name2IPAddress(), e.g. with the default setting try to
connect to ::1 even when 127.0.0.1 failed due to the -6 option.
2017-05-26 13:33:53 +02:00
Miroslav Lichvar
46fad717e5 client: use getopt() for command line parsing 2017-05-26 13:33:53 +02:00
Miroslav Lichvar
ae0c3bbbe8 main: use getopt() for command line parsing
This allows multiple options to be specified together and also may
options follow configuration directives on systems where getopt()
permutates the arguments.
2017-05-26 13:33:53 +02:00
Miroslav Lichvar
f95d57e0d9 doc: fix typo in chronyd man page 2017-05-26 13:33:53 +02:00
Miroslav Lichvar
a1cbd4eb82 main: add option to specify log file
Add -l option to log to a file instead of syslog or terminal.
2017-05-26 13:33:53 +02:00
Miroslav Lichvar
6cbeb107db logging: allow logging to file instead of syslog 2017-05-26 13:33:53 +02:00
Miroslav Lichvar
3a5566c6c3 main: use LOG_FATAL to print error when UID is not zero 2017-05-26 13:33:53 +02:00
Miroslav Lichvar
73c548ad01 sourcestats: handle negative elapsed time in SST_GetSelectionData()
Source selection uses the last event time as current time. If it was
called from a refclock which generates a sample in its poll function
(e.g. PHC), the sample time may be later than the event time. This
gives a negative elapsed time in SST_GetSelectionData() and possibly
also a negative root distance, which causes the source to be rejected as
a falseticker.

Use absolute value of the difference in order to always get a positive
root distance.
2017-05-26 13:33:53 +02:00
Miroslav Lichvar
82203e12c8 doc: update refclock documentation 2017-05-26 13:33:53 +02:00
Miroslav Lichvar
1ca099473f refclock: add option to filter wrong pulse edges
Add width option to the refclock directive to set expected width of
pulses in a PPS signal. The width adds a limit for the maximum offset
and root distance in order to reject PPS samples from wrong events, e.g.
PHCs which cannot be configured to timestamp only rising of falling
edges.
2017-05-26 13:33:53 +02:00
Miroslav Lichvar
eceb8d9937 refclock_phc: add support for timestamping of external PPS
Add extpps driver option to the PHC refclock to enable external
timestamping of PPS signal and also options to configure the channel and
pin index. In this mode, the driver polling function accumulates samples
for hwclock, which is used to convert received timestamping events to
local time.
2017-05-26 13:33:53 +02:00
Miroslav Lichvar
4ba92bb6d6 sys_linux: add support for external PHC timestamping 2017-05-26 13:33:53 +02:00
Miroslav Lichvar
f31f68ae8e refclock: add option to treat non-PPS refclocks as PPS
Add pps option to the refclock directive to force chronyd to treat any
refclock as a PPS refclock. This is intended for refclocks that may
provide time off by a whole number of seconds due to missing or wrong
TAI/GPS->UTC conversion.
2017-05-26 13:33:53 +02:00
Miroslav Lichvar
cff15f91d4 refclock: allow all drivers to provide PPS samples 2017-05-26 13:33:53 +02:00
Miroslav Lichvar
6b74917954 refclock: allow drivers to provide cooked PPS samples
Split RCL_AddPulse() in order to provide a new function for refclock
drivers which can make PPS samples without having raw system time, e.g.
from PHC timestamps.
2017-05-26 13:33:53 +02:00
Miroslav Lichvar
1bf2384a1f refclock: don't require raw time in valid_sample_time()
This makes the check a bit more expensive, but it will be needed to
allow refclocks that don't have raw system time.
2017-05-26 13:33:53 +02:00
Miroslav Lichvar
54a12779e2 ntp: include local error in hwclock samples 2017-05-26 13:33:53 +02:00
Miroslav Lichvar
e8b06fef9f ntp: remove unnecessary include 2017-05-26 13:33:53 +02:00
Miroslav Lichvar
653d70ec4e sys_linux: allow sysinfo in seccomp filter
It may be used by glob() in latest glibc.
2017-04-19 14:38:51 +02:00
Miroslav Lichvar
abb09418b1 sys_linux: don't drop PHC samples with zero delay
When processing data from the PTP_SYS_OFFSET ioctl, the sample is
dropped when an interval between two consecutive readings of the system
clock is negative or zero, assuming the clock has been stepped between
the two readings.

With a real PHC the interval is normally expected to be at least a
microsecond, but with a virtual PHC and a low-resolution system clock
it's possible to get two readings with the same system time. Modify the
check to drop only samples with a negative delay.
2017-04-19 13:03:10 +02:00
Miroslav Lichvar
c103bebd9f configure: check for clang
Try clang as the C compiler before cc and use the same -W* CFLAGS as
with gcc.
2017-04-19 13:03:10 +02:00
Miroslav Lichvar
935d855b47 util: indicate truncated Unix socket path in UTI_SockaddrToString()
Specify the maximum length of the path in the snprintf() format to avoid
a new gcc warning (-Wformat-truncation). If the path doesn't fit in the
buffer, indicate with the '>' symbol that it was truncated. The function
is used only for debug messages.
2017-04-19 13:03:10 +02:00
Miroslav Lichvar
f8f9100a0d makefile: run tests in multiple iterations on check
Use the new options of the run script in the check target to make it
reliable for automatic testing without using a fixed random seed and add
a new quickcheck target for the original check using just one iteration.
2017-03-31 14:53:27 +02:00
Miroslav Lichvar
6de7b98e76 test: improve run script
Add options to allow running the tests in multiple iterations while
allowing a small number of failures per test. Some tests are expected to
fail occasionally as they are basically statistical tests. Improving
their reliability is possible, but it's always a compromise between
sensitivity, reliability, and execution time.
2017-03-31 14:53:27 +02:00
Miroslav Lichvar
c390351c65 test: make 118-maxdelay more reliable 2017-03-31 14:53:27 +02:00
Miroslav Lichvar
768bce799b sys_linux: allow getpid in seccomp filter
It seems to be used by syslog() in latest glibc.
2017-03-13 14:42:44 +01:00
Miroslav Lichvar
d3a30142e5 test: fix DEBUG_LOG use in unit tests
This was missing in commit f282856c72.
2017-03-13 12:04:26 +01:00
Chris Perl
3a635fc51f sourcestats: reorder arguments to DEBUG_LOG in SST_IsGoodSample
The delay_increase and allowed_increase variables are backwards with
respect to the ordering of the words in the message.
2017-03-10 16:55:22 +01:00
Miroslav Lichvar
10078566da test: make 117-fallbackdrift more reliable 2017-03-10 16:51:03 +01:00
Miroslav Lichvar
c44346096c sys: add null driver
Add a new clock driver that doesn't actually try to adjust the clock.
It allows chronyd to run without the capability to adjust/set the system
clock, e.g. in some containers. It can be enabled by the -x option.
2017-03-10 16:51:03 +01:00
Miroslav Lichvar
0ff449e6a6 local: improve log message for failed clock step 2017-03-10 16:51:03 +01:00
Miroslav Lichvar
f3a16383b9 main: dump history by default
Always write the measurement history on exit when the dump directory is
specified and silently ignore the dumponexit directive. There doesn't
seem to be a good use case for dumpdir and -r without dumponexit as the
history would be invalidated by adjustments of the clock that happened
between the dump command and chronyd exit.
2017-03-10 16:51:03 +01:00
Miroslav Lichvar
539ef3f770 main: rewrite some error messages 2017-03-10 16:51:03 +01:00
Miroslav Lichvar
f282856c72 logging: remove facility parameter
It was never used for anything and messages in debug output already
include filenames, which can be easily grepped if there is a need
to see log messages only from a particular file.
2017-03-10 16:51:03 +01:00
Miroslav Lichvar
6db8ec1ba2 privops: separate res_init() call
Move the res_init() call from do_name_to_ipaddress() into a separate
privops operation. Use it in ntp_sources and avoid unnecessary
res_init() calls in the main thread.
2017-03-10 16:51:02 +01:00
Miroslav Lichvar
5187c08c90 doc: update NEWS 2017-01-31 11:22:11 +01:00
Miroslav Lichvar
c8076ac10d makefile: fix distclean target to not print errors 2017-01-31 11:22:11 +01:00
Miroslav Lichvar
362d155558 examples: improve configuration examples 2017-01-31 11:22:11 +01:00
Miroslav Lichvar
7b7eb0a6e5 examples: improve systemd unit files
Add the PrivateTmp, ProtectHome, and ProtectSystem directives to better
secure the system from chronyd. It's taken from the Debian chrony
package.
2017-01-31 11:22:11 +01:00
Miroslav Lichvar
d96f49f67d test: add keys unit test 2017-01-31 11:22:11 +01:00
Miroslav Lichvar
43ba5d2126 doc: document rekey in chronyc man page
For some reason this useful command was never documented.
2017-01-31 11:22:11 +01:00
Miroslav Lichvar
48f7598fed client: add rekey to help text 2017-01-31 11:22:11 +01:00
Miroslav Lichvar
510b22e96b util: fix more coverity warnings
Coverity doesn't seem to like the new field in the IPAddr struct (used
as explicit padding of the structure) to be left uninitialized, even
though it's never used for anything and is cleared by memset() in
UTI_IPHostToNetwork() before leaving the process.
2017-01-31 11:22:10 +01:00
Miroslav Lichvar
0a0aff14d8 conf: add rawmeasurements log option
While the measurements log can be useful for debugging problems in NTP
configuration (e.g. authentication failures with symmetric keys), it
seems most users are interested only in valid measurements (e.g. for
producing graphs) and don't expect/handle entries where some of the RFC
5905 tests 1-7 failed. Modify the measurements log option to log only
valid measurements, and for debugging purposes add a new rawmeasurements
option.
2017-01-31 11:22:10 +01:00
Miroslav Lichvar
e225ac68bc test: update 110-chronyc 2017-01-27 11:54:12 +01:00
Miroslav Lichvar
58060c40a5 doc: improve FAQ 2017-01-27 11:45:50 +01:00
Miroslav Lichvar
2ac1b3d5c4 client: print tracking delay/dispersion in nanosecond resolution 2017-01-27 11:35:38 +01:00
Miroslav Lichvar
c174566982 ntp: check supported flags before enabling HW timestamping 2017-01-27 11:35:38 +01:00
Miroslav Lichvar
60fca19d40 ntp: log info message when HW timestamping is enabled 2017-01-27 10:55:28 +01:00
Miroslav Lichvar
8bcb15b02f doc: improve description of some server options 2017-01-27 10:55:28 +01:00
Miroslav Lichvar
65c2cebcd5 reference: report zero root dispersion with local reference
The server's precision is supposed to be included in client's
dispersion. Don't include it in the server's dispersion.
2017-01-27 10:55:28 +01:00
Miroslav Lichvar
2a51b45a43 test: fix memory leaks in unit tests 2017-01-27 10:55:28 +01:00
Miroslav Lichvar
5ac791665e doc: update NEWS 2017-01-24 15:03:24 +01:00
Miroslav Lichvar
a4e3f83611 update copyright years 2017-01-24 15:01:38 +01:00
Miroslav Lichvar
8a837f9c2b test: extend 119-smoothtime 2017-01-23 16:17:39 +01:00
Miroslav Lichvar
da2d33e9a8 ntp: fix time smoothing in interleaved mode
When the server's transmit timestamp was updated with a kernel/HW
timestamp, it didn't include the time smoothing offset. If the offset
was larger than one second, the update failed and clients using the
interleaved mode received less accurate timestamps. If the update
succeeded, the clients received timestamps that were not adjusted for
the time smoothing offset, which added an error of up to 0.5s/1s to
their measured offset/delay.

Fix the update to include the smoothing offset in the new timestamp.
2017-01-23 15:58:55 +01:00
Miroslav Lichvar
4b98dadae9 ntp: simplify UTI_Ntp64ToTimespec() callers
Since UTI_Ntp64ToTimespec() was modified to handle zero timestamps, some
of its callers don't need to do that anymore.
2017-01-23 15:58:55 +01:00
Miroslav Lichvar
86acea5c46 ntp: add interface index to NTP_Local_Address
This will allow us to get the interface index when sending responses to
clients.
2017-01-23 15:58:55 +01:00
Miroslav Lichvar
a60fc73e7b refclock_phc: add nocrossts option 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
50f99ec5f4 conf: add nocrossts option to hwtimestamp directive
This option disables the use of the PTP_SYS_OFFSET_PRECISE ioctl.
2017-01-23 15:58:55 +01:00
Miroslav Lichvar
31b6a14444 sys_linux: add support for PTP_SYS_OFFSET_PRECISE
This is for hardware that can precisely cross timestamp the PHC with the
system clock.
2017-01-23 15:58:55 +01:00
Miroslav Lichvar
9df4d36157 refclock_phc: use sys_linux code for reading PHC
This drops support for non-ioctl reading of PHC.
2017-01-23 15:58:55 +01:00
Miroslav Lichvar
b70f0b674f ntp: move PHC-specific code to sys_linux
This will allow sharing of the code with the PHC refclock driver.
2017-01-23 15:58:55 +01:00
Miroslav Lichvar
510784077f conf: add minpoll option to hwtimestamp directive 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
9800e397fb hwclock: make minimum sampling separation configurable 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
1436d9961f conf: add precision option to hwtimestamp directive 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
98f5d05925 ntp: include precision of PHC readings in their selection
Include a fixed non-zero precision (100 nanosecond) in the selection of
PHC readings.
2017-01-23 15:58:55 +01:00
Miroslav Lichvar
7a937c7652 conf: return hwtimestamp data in struct 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
b198d76676 ntp: include precision in maxdelay test 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
97d4203354 ntp: adapt sampling separation for short polling intervals 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
beaaaad162 ntp: allow sub-second polling intervals
Change the minimum minpoll to -4, but keep the minimum maxpoll at 0 in
order to not make it too easy to flood distant servers.
2017-01-23 15:58:55 +01:00
Miroslav Lichvar
4e78975909 ntp: use current poll when backing off on KoD RATE 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
99147ed8f2 ntp: rename maxdelay constants 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
dec0d3bfc2 ntp: reset ntpdata report on address change 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
cd84c99e70 examples: improve chronyd.service 2017-01-23 15:58:55 +01:00
Miroslav Lichvar
d5c507975c doc: update README 2017-01-12 16:34:28 +01:00
Miroslav Lichvar
b4235abd36 update copyright years 2017-01-12 16:34:28 +01:00
Miroslav Lichvar
1966085a97 test: add ntp_core unit test 2017-01-12 16:34:28 +01:00
Miroslav Lichvar
e31e7af48f test: make 119-smoothtime more reliable 2017-01-12 16:34:28 +01:00
Miroslav Lichvar
adb9123fc3 test: extend util unit test 2017-01-12 16:34:28 +01:00
Miroslav Lichvar
b0f7efd59e util: handle zero in conversion of NTP timestamps
Handle zero NTP timestamp in UTI_Ntp64ToTimespec() as a special value to
make it symmetric with UTI_TimespecToNtp64(). This is needed since
commit d75f6830f1, in which a timestamp is
converted back and forth without checking for zero.

It also makes zero NTP timestamps more apparent in debug output.
2017-01-12 16:34:28 +01:00
Miroslav Lichvar
e28dfada8c rtc: check for backward RTC steps
When accumulating a new sample, check if the new RTC time is newer the
last sample time. If it is not, discard all previous samples, assuming
something has stepped the RTC, or it's a broken RTC/driver.
2017-01-12 16:34:28 +01:00
Miroslav Lichvar
ac0b28cce6 sourcestats: align sample time used for source report
This reduces leak of sample times (and receive timestamps which are
related to sample times), which could be useful in off-path attacks on
unauthenticated symmetric interleaved mode.
2017-01-12 16:34:28 +01:00
Miroslav Lichvar
48b16ae66c local: add assertion for precision 2017-01-12 16:34:28 +01:00
Miroslav Lichvar
061579ec28 ntp: don't send packets with RX equal to TX
Before sending an NTP packet, check whether the TX timestamp is not
equal to the RX timestamp. If it is, generate a new TX timestamp and try
again. This is extremely unlikely to happen in normal operation, but it
is needed for reliable detection of the interleaved mode.
2017-01-12 16:34:28 +01:00
Miroslav Lichvar
f2f834e7e7 ntp: limit maxdelay parameters 2017-01-12 16:34:27 +01:00
Miroslav Lichvar
a7802e9a76 fix some coverity warnings 2017-01-12 16:34:27 +01:00
Miroslav Lichvar
8f7ab95ff0 doc: update NEWS 2017-01-06 13:12:19 +01:00
Miroslav Lichvar
042c670747 doc: improve chrony.conf man page 2017-01-06 13:12:19 +01:00
Miroslav Lichvar
cacbe9976f ntp: add options for compensating HW timestamping errors 2017-01-06 13:12:19 +01:00
Miroslav Lichvar
8efec1d640 ntp: add sanity check for HW timestamps
Accept HW timestamp only if it doesn't differ from the kernel/daemon
timestamp by more than one second.
2017-01-06 13:12:19 +01:00
Miroslav Lichvar
c44d282f0b ntp: ignore zero HW timestamps
Apparently, zero HW timestamps are possible with buggy drivers/HW.
2017-01-06 13:12:19 +01:00
Miroslav Lichvar
4432f29bd2 sources: try to replace jittery sources
Similarly to falsetickers, distant, and unreachable sources, try to
replace sources that have jitter larger than maxjitter.
2017-01-06 13:12:19 +01:00
Miroslav Lichvar
5fee3ed5e9 client: print refid also as string in ntpdata output 2017-01-06 13:12:19 +01:00
Miroslav Lichvar
b76ea64263 ntp: log warning when KoD RATE is received in non-burst mode 2017-01-06 13:12:19 +01:00
Miroslav Lichvar
ed904f08a4 hwclock: return timestamp error
For now, when converting a raw timestamp, return error of the last
sample as the maximum error of the timestamp. This is needed to include
the PHC reading delay in the NTP dispersion.
2017-01-06 13:12:19 +01:00
Miroslav Lichvar
96cc80ffc8 ntp: improve dispersion calculation
Instead of adding precision (sum of the local and remote precision) to
the TX and RX timestamp error, include only the maximum.
2017-01-06 13:12:19 +01:00
Miroslav Lichvar
ab99373cfc conf: change default rate limiting parameters
Change the default NTP rate limiting leak to 2 (25%). Change the default
command rate limiting interval to -4 (16 packets per second) and burst
to 8, so the interval is the only difference between NTP and command
rate limiting defaults.
2017-01-06 13:12:19 +01:00
Miroslav Lichvar
dbfb49384b clientlog: disable NTP response rate limiting by default
This reverts commit 50022e9286.

Testing showed that ntpd as an NTP client performs poorly when it's
getting only 25% of responses. At least for now, disable rate limiting
by default again.
2017-01-06 13:12:18 +01:00
Miroslav Lichvar
14bb9f29a3 ntp: calculate delay relative to local frequency
This should be more accurate as local frequency is usually
combined from multiple sources. This is a partial revert of commit
23a4e8b38d.
2017-01-06 13:12:18 +01:00
270 changed files with 34811 additions and 7896 deletions

3
.gitignore vendored
View File

@@ -1,9 +1,12 @@
.deps
.vimrc
*.gcda
*.gcno
*.o
*.swp
*.dSYM
*.DS_Store
core.*
tags
/RELEASES
/Makefile

View File

@@ -21,56 +21,60 @@
#
# Makefile template
SYSCONFDIR=@SYSCONFDIR@
BINDIR=@BINDIR@
SBINDIR=@SBINDIR@
LOCALSTATEDIR=@LOCALSTATEDIR@
CHRONYVARDIR=@CHRONYVARDIR@
SYSCONFDIR = @SYSCONFDIR@
BINDIR = @BINDIR@
SBINDIR = @SBINDIR@
LOCALSTATEDIR = @LOCALSTATEDIR@
CHRONYVARDIR = @CHRONYVARDIR@
DESTDIR =
CC = @CC@
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
DESTDIR=
GETDATE_CFLAGS = @GETDATE_CFLAGS@
HASH_OBJ = @HASH_OBJ@
EXTRA_OBJS = @EXTRA_OBJS@
OBJS = array.o cmdparse.o conf.o local.o logging.o main.o memory.o \
reference.o regress.o rtc.o sched.o sources.o sourcestats.o stubs.o \
sys.o smooth.o tempcomp.o util.o $(HASH_OBJ)
OBJS = array.o cmdparse.o conf.o local.o logging.o main.o memory.o quantiles.o \
reference.o regress.o rtc.o samplefilt.o sched.o socket.o sources.o sourcestats.o \
stubs.o smooth.o sys.o sys_null.o tempcomp.o util.o $(EXTRA_OBJS)
EXTRA_OBJS=@EXTRA_OBJECTS@
EXTRA_CLI_OBJS = @EXTRA_CLI_OBJS@
CLI_OBJS = array.o client.o cmdparse.o getdate.o memory.o nameserv.o \
pktlength.o util.o $(HASH_OBJ)
pktlength.o socket.o util.o $(EXTRA_CLI_OBJS)
ALL_OBJS = $(OBJS) $(EXTRA_OBJS) $(CLI_OBJS)
ALL_OBJS = $(OBJS) $(CLI_OBJS)
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
EXTRA_LIBS=@EXTRA_LIBS@
EXTRA_CLI_LIBS=@EXTRA_CLI_LIBS@
EXTRA_LIBS = @EXTRA_LIBS@
EXTRA_CLI_LIBS = @EXTRA_CLI_LIBS@
# Until we have a main procedure we can link, just build object files
# to test compilation
all : chronyd chronyc
chronyd : $(OBJS) $(EXTRA_OBJS)
$(CC) $(CFLAGS) -o chronyd $(OBJS) $(EXTRA_OBJS) $(LDFLAGS) $(LIBS) $(EXTRA_LIBS)
chronyd : $(OBJS)
$(CC) $(CFLAGS) -o chronyd $(OBJS) $(LDFLAGS) $(LIBS) $(EXTRA_LIBS)
chronyc : $(CLI_OBJS)
$(CC) $(CFLAGS) -o chronyc $(CLI_OBJS) $(LDFLAGS) $(LIBS) $(EXTRA_CLI_LIBS)
getdate.o: CFLAGS += $(GETDATE_CFLAGS)
distclean : clean
-rm -f .DS_Store
-rm -f Makefile config.h config.log
$(MAKE) -C doc distclean
$(MAKE) -C test/unit distclean
-rm -f .DS_Store
-rm -f Makefile config.h config.log
clean :
-rm -f *.o *.s chronyc chronyd core *~
$(MAKE) -C test/unit clean
-rm -f *.o *.s chronyc chronyd core.* *~
-rm -f *.gcda *.gcno
-rm -rf .deps
-rm -rf *.dSYM
@@ -109,9 +113,18 @@ install-docs :
%.s : %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -S $<
check : chronyd chronyc
quickcheck : chronyd chronyc
$(MAKE) -C test/unit check
cd test/simulation && ./run
cd test/system && ./run
check : chronyd chronyc
$(MAKE) -C test/unit check
cd test/simulation && ./run -i 20 -m 2
cd test/system && ./run
print-chronyd-objects :
@echo $(OBJS)
Makefile : Makefile.in configure
@echo
@@ -125,4 +138,6 @@ Makefile : Makefile.in configure
.deps/%.d: %.c | .deps
@$(CC) -MM $(CPPFLAGS) -MT '$(<:%.c=%.o) $@' $< -o $@
ifndef NODEPS
-include $(ALL_OBJS:%.o=.deps/%.d)
endif

285
NEWS
View File

@@ -1,3 +1,285 @@
New in version 4.5
==================
Enhancements
------------
* Add support for AES-GCM-SIV in GnuTLS
* Add support for corrections from PTP transparent clocks
* Add support for systemd socket activation
Bug fixes
---------
* Fix presend in interleaved mode
* Fix reloading of modified sources from sourcedir
New in version 4.4
==================
Enhancements
------------
* Add support for AES-GCM-SIV with Nettle >= 3.9 to shorten NTS
cookies to avoid some length-specific blocking of NTP on Internet
* Add support for multiple refclocks using extpps option on one PHC
* Add maxpoll option to hwtimestamp directive to improve PHC tracking
with low packet rates
* Add hwtstimeout directive to configure timeout for late timestamps
* Handle late hardware transmit timestamps of NTP requests on all sockets
* Handle mismatched 32/64-bit time_t in SOCK refclock samples
* Improve source replacement
* Log important changes made by command requests (chronyc)
* Refresh address of NTP sources periodically
* Request nanosecond kernel RX timestamping on FreeBSD
* Set DSCP for IPv6 packets
* Shorten NTS-KE retry interval when network is down
* Update seccomp filter for musl
* Warn if loading keys from file with unexpected permissions
* Warn if source selection fails or falseticker is detected
* Add selectopts command to modify source-specific selection options
* Add timestamp sources to serverstats report and make its fields 64-bit
* Add -e option to chronyc to indicate end of response
New in version 4.3
==================
Enhancements
------------
* Add local option to refclock directive to stabilise system clock
with more stable free-running clock (e.g. TCXO, OCXO)
* Add maxdelayquant option to server/pool/peer directive to replace
maxdelaydevratio filter with long-term quantile-based filtering
* Add selection option to log directive
* Allow external PPS in PHC refclock without configurable pin
* Don't accept first interleaved response to minimise error in delay
* Don't use arc4random on Linux to avoid server performance loss
* Improve filter option to better handle missing NTP samples
* Improve stability with hardware timestamping and PHC refclock
* Update seccomp filter
Bug fixes
---------
* Fix waitsync command to reconnect when not getting response
New in version 4.2
==================
Enhancements
------------
* Add support for NTPv4 extension field improving synchronisation
stability and resolution of root delay and dispersion (experimental)
* Add support for NTP over PTP (experimental)
* Add support for AES-CMAC and hash functions in GnuTLS
* Improve server interleaved mode to be more reliable and support
multiple clients behind NAT
* Update seccomp filter
* Add statistics about interleaved mode to serverstats report
Bug fixes
---------
* Fix RTC support with 64-bit time_t on 32-bit Linux
* Fix seccomp filter to work correctly with bind*device directives
* Suppress kernel adjustments of system clock (dosynctodr) on illumos
Other changes
-------------
* Switch Solaris support to illumos
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 and add less restrictive level
* 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
==================
Enhancements
------------
* Add support for Network Time Security (NTS) authentication
* Add support for AES-CMAC keys (AES128, AES256) with Nettle
* 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 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
* Improve source selection with trusted sources
* Improve NTP loop test to prevent synchronisation to itself
* Repeat iburst when NTP source is switched from offline state to online
* Update clock synchronisation status and leap status more frequently
* Update seccomp filter
* Add "add pool" command
* Add "reset sources" command to drop all measurements
* Add authdata command to print details about NTP authentication
* Add selectdata command to print details about source selection
* Add -N option and sourcename command to print original names of sources
* Add -a option to some commands to print also unresolved sources
* Add -k, -p, -r options to clients command to select, limit, reset data
Bug fixes
---------
* Don't set interface for NTP responses to allow asymmetric routing
* Handle RTCs that don't support interrupts
* Respond to command requests with correct address on multihomed hosts
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
====================
Security fixes
--------------
* Create new file when writing pidfile (CVE-2020-14367)
New in version 3.5
==================
Enhancements
------------
* Add support for more accurate reading of PHC on Linux 5.0
* Add support for hardware timestamping on interfaces with read-only
timestamping configuration
* Add support for memory locking and real-time priority on FreeBSD,
NetBSD, Solaris
* Update seccomp filter to work on more architectures
* Validate refclock driver options
Bug fixes
---------
* Fix bindaddress directive on FreeBSD
* Fix transposition of hardware RX timestamp on Linux 4.13 and later
* Fix building on non-glibc systems
New in version 3.4
==================
Enhancements
------------
* Add filter option to server/pool/peer directive
* Add minsamples and maxsamples options to hwtimestamp directive
* Add support for faster frequency adjustments in Linux 4.19
* Change default pidfile to /var/run/chrony/chronyd.pid to allow
chronyd without root privileges to remove it on exit
* Disable sub-second polling intervals for distant NTP sources
* Extend range of supported sub-second polling intervals
* Get/set IPv4 destination/source address of NTP packets on FreeBSD
* Make burst options and command useful with short polling intervals
* Modify auto_offline option to activate when sending request failed
* Respond from interface that received NTP request if possible
* Add onoffline command to switch between online and offline state
according to current system network configuration
* Improve example NetworkManager dispatcher script
Bug fixes
---------
* Avoid waiting in Linux getrandom system call
* Fix PPS support on FreeBSD and NetBSD
New in version 3.3
==================
Enhancements
------------
* Add burst option to server/pool directive
* Add stratum and tai options to refclock directive
* Add support for Nettle crypto library
* Add workaround for missing kernel receive timestamps on Linux
* Wait for late hardware transmit timestamps
* Improve source selection with unreachable sources
* Improve protection against replay attacks on symmetric mode
* Allow PHC refclock to use socket in /var/run/chrony
* Add shutdown command to stop chronyd
* Simplify format of response to manual list command
* Improve handling of unknown responses in chronyc
Bug fixes
---------
* Respond to NTPv1 client requests with zero mode
* Fix -x option to not require CAP_SYS_TIME under non-root user
* Fix acquisitionport directive to work with privilege separation
* Fix handling of socket errors on Linux to avoid high CPU usage
* Fix chronyc to not get stuck in infinite loop after clock step
New in version 3.2
==================
Enhancements
------------
* Improve stability with NTP sources and reference clocks
* Improve stability with hardware timestamping
* Improve support for NTP interleaved modes
* Control frequency of system clock on macOS 10.13 and later
* Set TAI-UTC offset of system clock with leapsectz directive
* Minimise data in client requests to improve privacy
* Allow transmit-only hardware timestamping
* Add support for new timestamping options introduced in Linux 4.13
* Add root delay, root dispersion and maximum error to tracking log
* Add mindelay and asymmetry options to server/peer/pool directive
* Add extpps option to PHC refclock to timestamp external PPS signal
* Add pps option to refclock directive to treat any refclock as PPS
* Add width option to refclock directive to filter wrong pulse edges
* Add rxfilter option to hwtimestamp directive
* Add -x option to disable control of system clock
* Add -l option to log to specified file instead of syslog
* Allow multiple command-line options to be specified together
* Allow starting without root privileges with -Q option
* Update seccomp filter for new glibc versions
* Dump history on exit by default with dumpdir directive
* Use hardening compiler options by default
Bug fixes
---------
* Don't drop PHC samples with low-resolution system clock
* Ignore outliers in PHC tracking, RTC tracking, manual input
* Increase polling interval when peer is not responding
* Exit with error message when include directive fails
* Don't allow slash after hostname in allow/deny directive/command
* Try to connect to all addresses in chronyc before giving up
New in version 3.1
==================
Enhancements
------------
* Add support for precise cross timestamping of PHC on Linux
* Add minpoll, precision, nocrossts options to hwtimestamp directive
* Add rawmeasurements option to log directive and modify measurements
option to log only valid measurements from synchronised sources
* Allow sub-second polling interval with NTP sources
Bug fixes
---------
* Fix time smoothing in interleaved mode
New in version 3.0
==================
@@ -16,8 +298,7 @@ Enhancements
* Add -t option to chronyd to exit after specified time
* Add partial protection against replay attacks on symmetric mode
* Don't reset polling interval when switching sources to online state
* Enable NTP response rate limiting by default
(1024 packets per second per IP address and 25% leak)
* Allow rate limiting with very short intervals
* Improve maximum server throughput on Linux and NetBSD
* Remove dump files after start
* Add tab-completion to chronyc with libedit/readline

192
README
View File

@@ -4,7 +4,7 @@ What is chrony?
===============
chrony is a versatile implementation of the Network Time Protocol (NTP).
It can synchronize the system clock with NTP servers, reference clocks
It can synchronise the system clock with NTP servers, reference clocks
(e.g. GPS receiver), and manual input using wristwatch and keyboard.
It can also operate as an NTPv4 (RFC 5905) server and peer to provide
a time service to other computers in the network.
@@ -16,7 +16,7 @@ and systems that do not run continuosly, or run on a virtual machine.
Typical accuracy between two machines synchronised over the Internet is
within a few milliseconds; on a LAN, accuracy is typically in tens of
microseconds. With hardware timestamping or a hardware reference clock
microseconds. With hardware timestamping, or a hardware reference clock,
sub-microsecond accuracy may be possible.
Two programs are included in chrony, chronyd is a daemon that can be
@@ -28,67 +28,26 @@ What will chrony run on?
========================
The software is known to work on Linux, FreeBSD, NetBSD, macOS and
Solaris. Closely related systems may work too. Any other system will
likely require a porting exercise. You would need to start from one
of the existing system-specific drivers and look into the quirks of
certain system calls and the kernel on your target system.
illumos. Closely related systems may work too. Any other system will
likely require a porting exercise.
How do I set it up?
===================
The file INSTALL gives instructions. On supported systems the
compilation process should be automatic.
You will need an ANSI C compiler -- gcc is recommended.
The manual (in texinfo and text formats) describes how to set the
software up for the less straightforward cases.
compilation process should be automatic. You will need a C compiler,
e.g. gcc or clang.
What documentation is there?
============================
A manual is supplied in Texinfo format (chrony.texi) and
ready-formatted plain text (chrony.txt) in the distribution.
The distribution includes manual pages and a document containing
Frequently Asked Questions (FAQ).
There is also information available on the chrony web pages, accessible
The documentation is also available on the chrony web pages, accessible
through the URL
https://chrony.tuxfamily.org/
Where are new versions announced?
=================================
There is a low volume mailing list where new versions and other
important news relating to chrony is announced. You can join this list
by sending mail with the subject "subscribe" to
chrony-announce-request@chrony.tuxfamily.org
These messages will be copied to chrony-users (see below).
How can I get support for chrony?
and where can I discuss new features, possible bugs etc?
========================================================
There are 3 mailing lists relating to chrony. chrony-announce was
mentioned above. chrony-users is a users' discussion list, e.g. for
general questions and answers about using chrony. chrony-dev is a more
technical list, e.g. for discussing how new features should be
implemented, exchange of information between developers etc. To
subscribe to either of these lists, send a message with the subject
"subscribe" to
chrony-users-request@chrony.tuxfamily.org
or
chrony-dev-request@chrony.tuxfamily.org
as applicable.
When you are reporting a bug, please send us all the information you can.
Unfortunately, chrony has proven to be one of those programs where it is very
difficult to reproduce bugs in a different environment. So we may have to
interact with you quite a lot to obtain enough extra logging and tracing to
pin-point the problem in some cases. Please be patient and plan for this!
https://chrony-project.org/
License
=======
@@ -104,132 +63,79 @@ Miroslav Lichvar <mlichvar@redhat.com>
Acknowledgements
================
In writing the chronyd program, extensive use has been made of RFC 1305
and RFC 5905, written by David Mills. The source code of the NTP reference
implementation has been used to check the details of the protocol.
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.
The following people have provided patches and other major contributions
to the program :
to chrony:
Lonnie Abelbeck <lonnie@abelbeck.com>
Patch to add tab-completion to chronyc
Benny Lyne Amorsen <benny@amorsen.dk>
Patch to add minstratum option
Andrew Bishop <amb@gedanken.demon.co.uk>
Fixes for bugs in logging when in daemon mode
Fixes for compiler warnings
Robustness improvements for drift file
Improve installation (directory checking etc)
Entries in contrib directory
Improvements to 'sources' and 'sourcestats' output from chronyc
Improvements to documentation
Investigation of required dosynctodr behaviour for various Solaris
versions.
Vincent Blut <vincent.debian@free.fr>
Stephan I. Boettcher <stephan@nevis1.columbia.edu>
Entries in contrib directory
David Bohman <debohman@gmail.com>
Goswin Brederlow <brederlo@informatik.uni-tuebingen.de>
Leigh Brown <leigh@solinno.co.uk>
Erik Bryer <ebryer@spots.ab.ca>
Entries in contrib directory
Jonathan Cameron <jic23@cam.ac.uk>
Bryan Christianson <bryan@whatroute.net>
Support for macOS
Support for privilege separation
Entries in contrib directory
Juliusz Chroboczek <jch@pps.jussieu.fr>
Fix install rule in Makefile if chronyd file is in use.
Dan Drown <dan-ntp@drown.org>
Kamil Dudka <kdudka@redhat.com>
Christian Ehrhardt <christian.ehrhardt@canonical.com>
Paul Elliott <pelliott@io.com>
DNSchrony (in contrib directory), a tool for handling NTP servers
with variable IP addresses.
Robert Fairley <rfairley@redhat.com>
Stefan R. Filipek <srfilipek@gmail.com>
Mike Fleetwood <mike@rockover.demon.co.uk>
Fixes for compiler warnings
Alexander Gretencord <arutha@gmx.de>
Changes to installation directory system to make it easier for
package builders.
Andrew Griffiths <agriffit@redhat.com>
Patch to add support for seccomp filter
Walter Haidinger <walter.haidinger@gmx.at>
Providing me with login access to a Linux installation where v1.12
wouldn't compile, so I could develop the fixes for v1.13. Also, for
providing the disc space so I can keep an independent backup of the
sources.
Juergen Hannken-Illjes <hannken@eis.cs.tu-bs.de>
Port to NetBSD
John Hasler <john@dhh.gt.org>
Project and website at tuxfamily.org
Changes to support 64 bit machines (i.e. those where
sizeof(unsigned long) > 4)
Bug fix to initstepslew directive
Fix to remove potential buffer overrun errors.
Memory locking and real-time scheduler support
Fix fault where chronyd enters an endless loop
Tjalling Hattink <t.hattink@fugro.nl>
Fix scheduler to allow stepping clock from timeout handler
Patch to take leap second in PPS refclock from locked source
Patch to make reading of RTC for initial trim more reliable
Liam Hatton <me@liamhatton.com>
Advice on configuring for Linux on PPC
Holger Hoffstätte <holger@applied-asynchrony.com>
Jachym Holecek <jakym@volny.cz>
Patch to make Linux real time clock work with devfs
Håkan Johansson <f96hajo@chalmers.se>
Patch to avoid large values in sources and sourcestats output
Jim Knoble <jmknoble@pobox.com>
Fixes for compiler warnings
Antti Jrvinen <costello@iki.fi>
Advice on configuring for BSD/386
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>
Kevin Lyda <kevin@ie.suberic.net>
Paul Menzel <paulepanter@users.sourceforge.net>
Vladimir Michl <vladimir.michl@seznam.cz>
Victor Moroz <vim@prv.adlum.ru>
Patch to support Linux with HZ!=100
Kalle Olavi Niemitalo <tosi@stekt.oulu.fi>
acquisitionport support
Frank Otto <sandwichmacher@web.de>
Handling arbitrary HZ values
Denny Page <dennypage@me.com>
Rupesh Patel <rupatel@redhat.com>
Chris Perl <cperl@janestreet.com>
Gautier PHILIPPON <gautier.philippon@ensimag.grenoble-inp.fr>
Patch to add refresh command to chronyc
Andreas Piesk <apiesk@virbus.de>
Patch to make chronyc use the readline library if available
Mike Ryan <msr@hsilop.net>
Baruch Siach <baruch@tkos.co.il>
Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
Foster Snowhill <forst@forstwoof.ru>
Andreas Steinmetz <ast@domdv.de>
NAKAMURA Takumi <takumi@ps.sakura.ne.jp>
Timo Teras <timo.teras@iki.fi>
Patch to reply correctly on multihomed hosts
Bill Unruh <unruh@physics.ubc.ca>
Advice on statistics
Luke Valenta <lvalenta@cloudflare.com>
Stephen Wadeley <swadeley@redhat.com>
Improvements to man pages
Bernhard Weiss <lisnablagh@web.de>
Wolfgang Weisselberg <weissel@netcologne.de>
Entries in contrib directory
Bernhard M. Wiedemann <bwiedemann@suse.de>
Joachim Wiedorn <ad_debian@joonet.de>
Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
Many robustness and security improvements
Ulrich Windl <ulrich.windl@rz.uni-regensburg.de> for the
Providing me with information about the Linux 2.2 kernel
functionality compared to 2.0.
Ulrich Windl <ulrich.windl@rz.uni-regensburg.de>
Michael Witten <mfwitten@gmail.com>
Doug Woodward <dougw@whistler.com>
Advice on configuring for Solaris 2.8 on x86
Thomas Zajic <zlatko@zlatko.fdns.net>
Many other people have contributed bug reports and suggestions. We are sorry
we cannot identify all of you individually.

View File

@@ -30,16 +30,19 @@
#include "sysincl.h"
/* This type is used to represent an IPv4 address or IPv6 address.
Addresses which are not resolved yet can be represented with an ID.
All parts are in HOST order, NOT network order. */
#define IPADDR_UNSPEC 0
#define IPADDR_INET4 1
#define IPADDR_INET6 2
#define IPADDR_ID 3
typedef struct {
union {
uint32_t in4;
uint8_t in6[16];
uint32_t id;
} addr;
uint16_t family;
uint16_t _pad;
@@ -47,11 +50,16 @@ typedef struct {
typedef struct {
IPAddr ip_addr;
unsigned short port;
} NTP_Remote_Address;
uint16_t port;
} IPSockAddr;
typedef IPSockAddr NTP_Remote_Address;
#define INVALID_IF_INDEX -1
typedef struct {
IPAddr ip_addr;
int if_index;
int sock_fd;
} NTP_Local_Address;

View File

@@ -247,6 +247,8 @@ set_subnet_(ADF_AuthTable table,
set_subnet(&table->base6, ip6, 4, 0, new_state, delete_children) == ADF_SUCCESS)
return ADF_SUCCESS;
break;
default:
break;
}
return ADF_BADSUBNET;
@@ -359,9 +361,9 @@ ADF_IsAllowed(ADF_AuthTable table,
case IPADDR_INET6:
split_ip6(ip_addr, ip6);
return check_ip_in_node(&table->base6, ip6);
default:
return 0;
}
return 0;
}
/* ================================================== */

22
array.c
View File

@@ -66,8 +66,6 @@ ARR_DestroyInstance(ARR_Instance array)
static void
realloc_array(ARR_Instance array, unsigned int min_size)
{
size_t data_size;
assert(min_size <= 2 * min_size);
if (array->allocated >= min_size && array->allocated <= 2 * min_size)
return;
@@ -79,10 +77,7 @@ realloc_array(ARR_Instance array, unsigned int min_size)
array->allocated = min_size;
}
data_size = (size_t)array->elem_size * array->allocated;
assert(data_size / array->elem_size == array->allocated);
array->data = Realloc(array->data, data_size);
array->data = Realloc2(array->data, array->allocated, array->elem_size);
}
void *
@@ -121,6 +116,21 @@ ARR_AppendElement(ARR_Instance array, void *element)
memcpy(e, element, array->elem_size);
}
void
ARR_RemoveElement(ARR_Instance array, unsigned int index)
{
void *e, *l;
e = ARR_GetElement(array, index);
l = ARR_GetElement(array, array->used - 1);
if (e < l)
memmove(e, (char *)e + array->elem_size, (char *)l - (char *)e);
array->used--;
realloc_array(array, array->used);
}
void
ARR_SetSize(ARR_Instance array, unsigned int size)
{

View File

@@ -47,6 +47,9 @@ extern void *ARR_GetElements(ARR_Instance array);
/* Add a new element to the end of the array */
extern void ARR_AppendElement(ARR_Instance array, void *element);
/* Remove element with given index */
extern void ARR_RemoveElement(ARR_Instance array, unsigned int index);
/* Set the size of the array */
extern void ARR_SetSize(ARR_Instance array, unsigned int size);

192
candm.h
View File

@@ -97,7 +97,20 @@
#define REQ_NTP_DATA 57
#define REQ_ADD_SERVER2 58
#define REQ_ADD_PEER2 59
#define N_REQUEST_TYPES 60
#define REQ_ADD_SERVER3 60
#define REQ_ADD_PEER3 61
#define REQ_SHUTDOWN 62
#define REQ_ONOFFLINE 63
#define REQ_ADD_SOURCE 64
#define REQ_NTP_SOURCE_NAME 65
#define REQ_RESET_SOURCES 66
#define REQ_AUTH_DATA 67
#define REQ_CLIENT_ACCESSES_BY_INDEX3 68
#define REQ_SELECT_DATA 69
#define REQ_RELOAD_SOURCES 70
#define REQ_DOFFSET2 71
#define REQ_MODIFY_SELECTOPTS 72
#define N_REQUEST_TYPES 73
/* Structure used to exchange timespecs independent of time_t size */
typedef struct {
@@ -109,6 +122,12 @@ typedef struct {
/* This is used in tv_sec_high for 32-bit timestamps */
#define TV_NOHIGHSEC 0x7fffffff
/* Structure for 64-bit integers (not requiring 64-bit alignment) */
typedef struct {
uint32_t high;
uint32_t low;
} Integer64;
/* 32-bit floating-point format consisting of 7-bit signed exponent
and 25-bit signed coefficient without hidden bit.
The result is calculated as: 2^(exp - 25) * coef */
@@ -241,6 +260,11 @@ typedef struct {
int32_t EOR;
} REQ_Ac_Check;
/* Source types in NTP source requests */
#define REQ_ADDSRC_SERVER 1
#define REQ_ADDSRC_PEER 2
#define REQ_ADDSRC_POOL 3
/* Flags used in NTP source requests */
#define REQ_ADDSRC_ONLINE 0x1
#define REQ_ADDSRC_AUTOOFFLINE 0x2
@@ -250,9 +274,15 @@ typedef struct {
#define REQ_ADDSRC_TRUST 0x20
#define REQ_ADDSRC_REQUIRE 0x40
#define REQ_ADDSRC_INTERLEAVED 0x80
#define REQ_ADDSRC_BURST 0x100
#define REQ_ADDSRC_NTS 0x200
#define REQ_ADDSRC_COPY 0x400
#define REQ_ADDSRC_EF_EXP_MONO_ROOT 0x800
#define REQ_ADDSRC_EF_EXP_NET_CORRECTION 0x1000
typedef struct {
IPAddr ip_addr;
uint32_t type;
uint8_t name[256];
uint32_t port;
int32_t minpoll;
int32_t maxpoll;
@@ -264,11 +294,18 @@ typedef struct {
int32_t min_samples;
int32_t max_samples;
uint32_t authkey;
uint32_t nts_port;
Float max_delay;
Float max_delay_ratio;
Float max_delay_dev_ratio;
Float min_delay;
Float asymmetry;
Float offset;
uint32_t flags;
int32_t filter_length;
uint32_t cert_set;
Float max_delay_quant;
uint32_t reserved[1];
int32_t EOR;
} REQ_NTP_Source;
@@ -283,8 +320,7 @@ typedef struct {
} REQ_Dfreq;
typedef struct {
int32_t sec;
int32_t usec;
Float doffset;
int32_t EOR;
} REQ_Doffset;
@@ -300,6 +336,8 @@ typedef struct {
typedef struct {
uint32_t first_index;
uint32_t n_clients;
uint32_t min_hits;
uint32_t reset;
int32_t EOR;
} REQ_ClientAccessesByIndex;
@@ -326,6 +364,30 @@ typedef struct {
int32_t EOR;
} REQ_NTPData;
typedef struct {
IPAddr ip_addr;
int32_t EOR;
} REQ_NTPSourceName;
typedef struct {
IPAddr ip_addr;
int32_t EOR;
} REQ_AuthData;
typedef struct {
uint32_t index;
int32_t EOR;
} REQ_SelectData;
/* Mask and options reuse the REQ_ADDSRC flags */
typedef struct {
IPAddr address;
uint32_t ref_id;
uint32_t mask;
uint32_t options;
int32_t EOR;
} REQ_Modify_SelectOpts;
/* ================================================== */
#define PKT_TYPE_CMD_REQUEST 1
@@ -362,8 +424,10 @@ typedef struct {
domain socket.
Version 6 (no authentication) : changed format of client accesses by index
(using new request/reply types), new fields and flags in NTP source request
and report, new commands: ntpdata, refresh, serverstats
(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
*/
#define PROTO_VERSION_NUMBER 6
@@ -377,8 +441,8 @@ typedef struct {
#define PROTO_VERSION_PADDING 6
/* The maximum length of padding in request packet, currently
defined by MANUAL_LIST */
#define MAX_PADDING_LENGTH 396
defined by CLIENT_ACCESSES_BY_INDEX3 */
#define MAX_PADDING_LENGTH 484
/* ================================================== */
@@ -427,6 +491,10 @@ typedef struct {
REQ_ReselectDistance reselect_distance;
REQ_SmoothTime smoothtime;
REQ_NTPData ntp_data;
REQ_NTPSourceName ntp_source_name;
REQ_AuthData auth_data;
REQ_SelectData select_data;
REQ_Modify_SelectOpts modify_select_opts;
} data; /* Command specific parameters */
/* Padding used to prevent traffic amplification. It only defines the
@@ -461,7 +529,16 @@ typedef struct {
#define RPY_SERVER_STATS 14
#define RPY_CLIENT_ACCESSES_BY_INDEX2 15
#define RPY_NTP_DATA 16
#define N_REPLY_TYPES 17
#define RPY_MANUAL_TIMESTAMP2 17
#define RPY_MANUAL_LIST2 18
#define RPY_NTP_SOURCE_NAME 19
#define RPY_AUTH_DATA 20
#define RPY_CLIENT_ACCESSES_BY_INDEX3 21
#define RPY_SERVER_STATS2 22
#define RPY_SELECT_DATA 23
#define RPY_SERVER_STATS3 24
#define RPY_SERVER_STATS4 25
#define N_REPLY_TYPES 26
/* Status codes */
#define STT_SUCCESS 0
@@ -474,8 +551,7 @@ typedef struct {
#define STT_BADSUBNET 7
#define STT_ACCESSALLOWED 8
#define STT_ACCESSDENIED 9
/* Deprecated */
#define STT_NOHOSTACCESS 10
#define STT_NOHOSTACCESS 10 /* Deprecated */
#define STT_SOURCEALREADYKNOWN 11
#define STT_TOOMANYSOURCES 12
#define STT_NORTC 13
@@ -485,6 +561,7 @@ typedef struct {
#define STT_INVALIDAF 17
#define STT_BADPKTVERSION 18
#define STT_BADPKTLENGTH 19
#define STT_INVALIDNAME 21
typedef struct {
int32_t EOR;
@@ -499,17 +576,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_FLAG_NOSELECT 0x1
#define RPY_SD_FLAG_PREFER 0x2
#define RPY_SD_FLAG_TRUST 0x4
#define RPY_SD_FLAG_REQUIRE 0x8
#define RPY_SD_ST_UNSELECTED 4
#define RPY_SD_ST_SELECTABLE 5
typedef struct {
IPAddr ip_addr;
@@ -569,7 +641,7 @@ typedef struct {
} RPY_Rtc;
typedef struct {
uint32_t centiseconds;
Float offset;
Float dfreq_ppm;
Float new_afreq_ppm;
int32_t EOR;
@@ -578,14 +650,17 @@ typedef struct {
typedef struct {
IPAddr ip;
uint32_t ntp_hits;
uint32_t nke_hits;
uint32_t cmd_hits;
uint32_t ntp_drops;
uint32_t nke_drops;
uint32_t cmd_drops;
int8_t ntp_interval;
int8_t nke_interval;
int8_t cmd_interval;
int8_t ntp_timeout_interval;
int8_t pad;
uint32_t last_ntp_hit_ago;
uint32_t last_nke_hit_ago;
uint32_t last_cmd_hit_ago;
} RPY_ClientAccesses_Client;
@@ -598,11 +673,24 @@ typedef struct {
} RPY_ClientAccessesByIndex;
typedef struct {
uint32_t ntp_hits;
uint32_t cmd_hits;
uint32_t ntp_drops;
uint32_t cmd_drops;
uint32_t log_drops;
Integer64 ntp_hits;
Integer64 nke_hits;
Integer64 cmd_hits;
Integer64 ntp_drops;
Integer64 nke_drops;
Integer64 cmd_drops;
Integer64 log_drops;
Integer64 ntp_auth_hits;
Integer64 ntp_interleaved_hits;
Integer64 ntp_timestamps;
Integer64 ntp_span_seconds;
Integer64 ntp_daemon_rx_timestamps;
Integer64 ntp_daemon_tx_timestamps;
Integer64 ntp_kernel_rx_timestamps;
Integer64 ntp_kernel_tx_timestamps;
Integer64 ntp_hw_rx_timestamps;
Integer64 ntp_hw_tx_timestamps;
Integer64 reserved[4];
int32_t EOR;
} RPY_ServerStats;
@@ -672,10 +760,55 @@ typedef struct {
uint32_t total_tx_count;
uint32_t total_rx_count;
uint32_t total_valid_count;
uint32_t reserved[4];
uint32_t total_good_count;
uint32_t reserved[3];
int32_t EOR;
} RPY_NTPData;
typedef struct {
uint8_t name[256];
int32_t EOR;
} RPY_NTPSourceName;
#define RPY_AD_MD_NONE 0
#define RPY_AD_MD_SYMMETRIC 1
#define RPY_AD_MD_NTS 2
typedef struct {
uint16_t mode;
uint16_t key_type;
uint32_t key_id;
uint16_t key_length;
uint16_t ke_attempts;
uint32_t last_ke_ago;
uint16_t cookies;
uint16_t cookie_length;
uint16_t nak;
uint16_t pad;
int32_t EOR;
} RPY_AuthData;
#define RPY_SD_OPTION_NOSELECT 0x1
#define RPY_SD_OPTION_PREFER 0x2
#define RPY_SD_OPTION_TRUST 0x4
#define RPY_SD_OPTION_REQUIRE 0x8
typedef struct {
uint32_t ref_id;
IPAddr ip_addr;
uint8_t state_char;
uint8_t authentication;
uint8_t leap;
uint8_t pad;
uint16_t conf_options;
uint16_t eff_options;
uint32_t last_sample_ago;
Float score;
Float lo_limit;
Float hi_limit;
int32_t EOR;
} RPY_SelectData;
typedef struct {
uint8_t version;
uint8_t pkt_type;
@@ -705,6 +838,9 @@ typedef struct {
RPY_Activity activity;
RPY_Smoothing smoothing;
RPY_NTPData ntp_data;
RPY_NTPSourceName ntp_source_name;
RPY_AuthData auth_data;
RPY_SelectData select_data;
} data; /* Reply specific parameters */
} CMD_Reply;

1706
client.c

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2009, 2015-2016
* Copyright (C) Miroslav Lichvar 2009, 2015-2017, 2021
*
* 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
@@ -38,28 +38,24 @@
#include "array.h"
#include "clientlog.h"
#include "conf.h"
#include "local.h"
#include "memory.h"
#include "ntp.h"
#include "reports.h"
#include "util.h"
#include "logging.h"
#define MAX_SERVICES 3
typedef struct {
IPAddr ip_addr;
uint32_t last_ntp_hit;
uint32_t last_cmd_hit;
uint32_t ntp_hits;
uint32_t cmd_hits;
uint16_t ntp_drops;
uint16_t cmd_drops;
uint16_t ntp_tokens;
uint16_t cmd_tokens;
int8_t ntp_rate;
int8_t cmd_rate;
uint32_t last_hit[MAX_SERVICES];
uint32_t hits[MAX_SERVICES];
uint16_t drops[MAX_SERVICES];
uint16_t tokens[MAX_SERVICES];
int8_t rate[MAX_SERVICES];
int8_t ntp_timeout_rate;
uint8_t flags;
NTP_int64 ntp_rx_ts;
NTP_int64 ntp_tx_ts;
uint8_t drop_flags;
} Record;
/* Hash table of records, there is a fixed number of records per slot */
@@ -104,45 +100,81 @@ static uint32_t ts_offset;
#define MIN_LIMIT_BURST 1
#define MAX_LIMIT_BURST 255
static uint16_t max_ntp_tokens;
static uint16_t max_cmd_tokens;
static uint16_t ntp_tokens_per_packet;
static uint16_t cmd_tokens_per_packet;
static uint16_t max_tokens[MAX_SERVICES];
static uint16_t tokens_per_hit[MAX_SERVICES];
/* Reduction of token rates to avoid overflow of 16-bit counters. Negative
shift is used for coarse limiting with intervals shorter than -TS_FRAC. */
static int ntp_token_shift;
static int cmd_token_shift;
static int token_shift[MAX_SERVICES];
/* Rates at which responses are randomly allowed (in log2) when the
buckets don't have enough tokens. This is necessary in order to
prevent an attacker sending requests with spoofed source address
from blocking responses to the address completely. */
#define MIN_LEAK_RATE 0
#define MIN_LEAK_RATE 1
#define MAX_LEAK_RATE 4
static int ntp_leak_rate;
static int cmd_leak_rate;
static int leak_rate[MAX_SERVICES];
/* Flag indicating whether the last response was dropped */
#define FLAG_NTP_DROPPED 0x1
/* Limit intervals in log2 */
static int limit_interval[MAX_SERVICES];
/* Flag indicating whether facility is turned on or not */
static int active;
/* RX and TX timestamp saved for clients using interleaved mode */
typedef struct {
uint64_t rx_ts;
uint8_t flags;
uint8_t tx_ts_source;
uint16_t slew_epoch;
int32_t tx_ts_offset;
} NtpTimestamps;
/* Flags for NTP timestamps */
#define NTPTS_DISABLED 1
#define NTPTS_VALID_TX 2
/* RX->TX map using a circular buffer with ordered timestamps */
typedef struct {
ARR_Instance timestamps;
uint32_t first;
uint32_t size;
uint32_t max_size;
uint32_t cached_index;
uint64_t cached_rx_ts;
uint16_t slew_epoch;
double slew_offset;
} NtpTimestampMap;
static NtpTimestampMap ntp_ts_map;
/* Maximum interval of NTP timestamps in future after a backward step */
#define NTPTS_FUTURE_LIMIT (1LL << 32) /* 1 second */
/* Maximum number of timestamps moved in the array to insert a new timestamp */
#define NTPTS_INSERT_LIMIT 64
/* Maximum expected value of the timestamp source */
#define MAX_NTP_TS NTP_TS_HARDWARE
/* Global statistics */
static uint32_t total_ntp_hits;
static uint32_t total_cmd_hits;
static uint32_t total_ntp_drops;
static uint32_t total_cmd_drops;
static uint32_t total_record_drops;
static uint64_t total_hits[MAX_SERVICES];
static uint64_t total_drops[MAX_SERVICES];
static uint64_t total_ntp_auth_hits;
static uint64_t total_ntp_interleaved_hits;
static uint64_t total_record_drops;
static uint64_t total_ntp_rx_timestamps[MAX_NTP_TS + 1];
static uint64_t total_ntp_tx_timestamps[MAX_NTP_TS + 1];
#define NSEC_PER_SEC 1000000000U
/* ================================================== */
static int expand_hashtable(void);
static void handle_slew(struct timespec *raw, struct timespec *cooked, double dfreq,
double doffset, LCL_ChangeType change_type, void *anything);
/* ================================================== */
@@ -158,12 +190,28 @@ compare_ts(uint32_t x, uint32_t y)
/* ================================================== */
static int
compare_total_hits(Record *x, Record *y)
{
uint32_t x_hits, y_hits;
int i;
for (i = 0, x_hits = y_hits = 0; i < MAX_SERVICES; i++) {
x_hits += x->hits[i];
y_hits += y->hits[i];
}
return x_hits > y_hits ? 1 : -1;
}
/* ================================================== */
static Record *
get_record(IPAddr *ip)
{
unsigned int first, i;
time_t last_hit, oldest_hit = 0;
uint32_t last_hit = 0, oldest_hit = 0;
Record *record, *oldest_record;
unsigned int first, i, j;
if (!active || (ip->family != IPADDR_INET4 && ip->family != IPADDR_INET6))
return NULL;
@@ -181,12 +229,13 @@ get_record(IPAddr *ip)
if (record->ip_addr.family == IPADDR_UNSPEC)
break;
last_hit = compare_ts(record->last_ntp_hit, record->last_cmd_hit) > 0 ?
record->last_ntp_hit : record->last_cmd_hit;
for (j = 0; j < MAX_SERVICES; j++) {
if (j == 0 || compare_ts(last_hit, record->last_hit[j]) < 0)
last_hit = record->last_hit[j];
}
if (!oldest_record || compare_ts(oldest_hit, last_hit) > 0 ||
(oldest_hit == last_hit && record->ntp_hits + record->cmd_hits <
oldest_record->ntp_hits + oldest_record->cmd_hits)) {
(oldest_hit == last_hit && compare_total_hits(oldest_record, record) > 0)) {
oldest_record = record;
oldest_hit = last_hit;
}
@@ -208,16 +257,18 @@ get_record(IPAddr *ip)
}
record->ip_addr = *ip;
record->last_ntp_hit = record->last_cmd_hit = INVALID_TS;
record->ntp_hits = record->cmd_hits = 0;
record->ntp_drops = record->cmd_drops = 0;
record->ntp_tokens = max_ntp_tokens;
record->cmd_tokens = max_cmd_tokens;
record->ntp_rate = record->cmd_rate = INVALID_RATE;
for (i = 0; i < MAX_SERVICES; i++)
record->last_hit[i] = INVALID_TS;
for (i = 0; i < MAX_SERVICES; i++)
record->hits[i] = 0;
for (i = 0; i < MAX_SERVICES; i++)
record->drops[i] = 0;
for (i = 0; i < MAX_SERVICES; i++)
record->tokens[i] = max_tokens[i];
for (i = 0; i < MAX_SERVICES; i++)
record->rate[i] = INVALID_RATE;
record->ntp_timeout_rate = INVALID_RATE;
record->flags = 0;
UTI_ZeroNtp64(&record->ntp_rx_ts);
UTI_ZeroNtp64(&record->ntp_tx_ts);
record->drop_flags = 0;
return record;
}
@@ -294,7 +345,7 @@ set_bucket_params(int interval, int burst, uint16_t *max_tokens,
*tokens_per_packet = 1U << (TS_FRAC + interval - *token_shift);
*max_tokens = *tokens_per_packet * burst;
DEBUG_LOG(LOGF_ClientLog, "Tokens max %d packet %d shift %d",
DEBUG_LOG("Tokens max %d packet %d shift %d",
*max_tokens, *tokens_per_packet, *token_shift);
}
@@ -303,27 +354,56 @@ set_bucket_params(int interval, int burst, uint16_t *max_tokens,
void
CLG_Initialise(void)
{
int interval, burst, leak_rate;
int i, interval, burst, lrate, slots2;
CNF_GetNTPRateLimit(&interval, &burst, &leak_rate);
set_bucket_params(interval, burst, &max_ntp_tokens, &ntp_tokens_per_packet,
&ntp_token_shift);
ntp_leak_rate = CLAMP(MIN_LEAK_RATE, leak_rate, MAX_LEAK_RATE);
for (i = 0; i < MAX_SERVICES; i++) {
max_tokens[i] = 0;
tokens_per_hit[i] = 0;
token_shift[i] = 0;
leak_rate[i] = 0;
limit_interval[i] = MIN_LIMIT_INTERVAL;
CNF_GetCommandRateLimit(&interval, &burst, &leak_rate);
set_bucket_params(interval, burst, &max_cmd_tokens, &cmd_tokens_per_packet,
&cmd_token_shift);
cmd_leak_rate = CLAMP(MIN_LEAK_RATE, leak_rate, MAX_LEAK_RATE);
switch (i) {
case CLG_NTP:
if (!CNF_GetNTPRateLimit(&interval, &burst, &lrate))
continue;
break;
case CLG_NTSKE:
if (!CNF_GetNtsRateLimit(&interval, &burst, &lrate))
continue;
break;
case CLG_CMDMON:
if (!CNF_GetCommandRateLimit(&interval, &burst, &lrate))
continue;
break;
default:
assert(0);
}
set_bucket_params(interval, burst, &max_tokens[i], &tokens_per_hit[i], &token_shift[i]);
leak_rate[i] = CLAMP(MIN_LEAK_RATE, lrate, MAX_LEAK_RATE);
limit_interval[i] = CLAMP(MIN_LIMIT_INTERVAL, interval, MAX_LIMIT_INTERVAL);
}
active = !CNF_GetNoClientLog();
if (!active)
if (!active) {
for (i = 0; i < MAX_SERVICES; i++) {
if (leak_rate[i] != 0)
LOG_FATAL("Rate limiting cannot be enabled with noclientlog");
}
return;
}
/* Calculate the maximum number of slots that can be allocated in the
configured memory limit. Take into account expanding of the hash
table where two copies exist at the same time. */
max_slots = CNF_GetClientLogLimit() / (sizeof (Record) * SLOT_SIZE * 3 / 2);
max_slots = CNF_GetClientLogLimit() /
((sizeof (Record) + sizeof (NtpTimestamps)) * SLOT_SIZE * 3 / 2);
max_slots = CLAMP(MIN_SLOTS, max_slots, MAX_SLOTS);
for (slots2 = 0; 1U << (slots2 + 1) <= max_slots; slots2++)
;
DEBUG_LOG("Max records %u", 1U << (slots2 + SLOT_BITS));
slots = 0;
records = NULL;
@@ -332,6 +412,17 @@ CLG_Initialise(void)
UTI_GetRandomBytes(&ts_offset, sizeof (ts_offset));
ts_offset %= NSEC_PER_SEC / (1U << TS_FRAC);
ntp_ts_map.timestamps = NULL;
ntp_ts_map.first = 0;
ntp_ts_map.size = 0;
ntp_ts_map.max_size = 1U << (slots2 + SLOT_BITS);
ntp_ts_map.cached_index = 0;
ntp_ts_map.cached_rx_ts = 0ULL;
ntp_ts_map.slew_epoch = 0;
ntp_ts_map.slew_offset = 0.0;
LCL_AddParameterChangeHandler(handle_slew, NULL);
}
/* ================================================== */
@@ -343,6 +434,10 @@ CLG_Finalise(void)
return;
ARR_DestroyInstance(records);
if (ntp_ts_map.timestamps)
ARR_DestroyInstance(ntp_ts_map.timestamps);
LCL_RemoveParameterChangeHandler(handle_slew, NULL);
}
/* ================================================== */
@@ -365,30 +460,33 @@ get_ts_from_timespec(struct timespec *ts)
/* ================================================== */
static void
update_record(struct timespec *now, uint32_t *last_hit, uint32_t *hits,
uint16_t *tokens, uint32_t max_tokens, int token_shift, int8_t *rate)
update_record(CLG_Service service, Record *record, struct timespec *now)
{
uint32_t interval, now_ts, prev_hit, new_tokens;
int interval2;
uint32_t interval, now_ts, prev_hit, tokens;
int interval2, tshift, mtokens;
int8_t *rate;
now_ts = get_ts_from_timespec(now);
prev_hit = *last_hit;
*last_hit = now_ts;
(*hits)++;
prev_hit = record->last_hit[service];
record->last_hit[service] = now_ts;
record->hits[service]++;
interval = now_ts - prev_hit;
if (prev_hit == INVALID_TS || (int32_t)interval < 0)
return;
if (token_shift >= 0)
new_tokens = (now_ts >> token_shift) - (prev_hit >> token_shift);
else if (now_ts - prev_hit > max_tokens)
new_tokens = max_tokens;
tshift = token_shift[service];
mtokens = max_tokens[service];
if (tshift >= 0)
tokens = (now_ts >> tshift) - (prev_hit >> tshift);
else if (now_ts - prev_hit > mtokens)
tokens = mtokens;
else
new_tokens = (now_ts - prev_hit) << -token_shift;
*tokens = MIN(*tokens + new_tokens, max_tokens);
tokens = (now_ts - prev_hit) << -tshift;
record->tokens[service] = MIN(record->tokens[service] + tokens, mtokens);
/* Convert the interval to scaled and rounded log2 */
if (interval) {
@@ -403,6 +501,11 @@ update_record(struct timespec *now, uint32_t *last_hit, uint32_t *hits,
interval2 = -RATE_SCALE * (TS_FRAC + 1);
}
/* For the NTP service, update one of the two rates depending on whether
the previous request of the client had a reply or it timed out */
rate = service == CLG_NTP && record->drop_flags & (1U << service) ?
&record->ntp_timeout_rate : &record->rate[service];
/* Update the rate in a rough approximation of exponential moving average */
if (*rate == INVALID_RATE) {
*rate = -interval2;
@@ -442,50 +545,33 @@ CLG_GetClientIndex(IPAddr *client)
/* ================================================== */
int
CLG_LogNTPAccess(IPAddr *client, struct timespec *now)
static void
check_service_number(CLG_Service service)
{
Record *record;
total_ntp_hits++;
record = get_record(client);
if (record == NULL)
return -1;
/* Update one of the two rates depending on whether the previous request
of the client had a reply or it timed out */
update_record(now, &record->last_ntp_hit, &record->ntp_hits,
&record->ntp_tokens, max_ntp_tokens, ntp_token_shift,
record->flags & FLAG_NTP_DROPPED ?
&record->ntp_timeout_rate : &record->ntp_rate);
DEBUG_LOG(LOGF_ClientLog, "NTP hits %"PRIu32" rate %d trate %d tokens %d",
record->ntp_hits, record->ntp_rate, record->ntp_timeout_rate,
record->ntp_tokens);
return get_index(record);
assert(service >= 0 && service <= MAX_SERVICES);
}
/* ================================================== */
int
CLG_LogCommandAccess(IPAddr *client, struct timespec *now)
CLG_LogServiceAccess(CLG_Service service, IPAddr *client, struct timespec *now)
{
Record *record;
total_cmd_hits++;
check_service_number(service);
total_hits[service]++;
record = get_record(client);
if (record == NULL)
return -1;
update_record(now, &record->last_cmd_hit, &record->cmd_hits,
&record->cmd_tokens, max_cmd_tokens, cmd_token_shift,
&record->cmd_rate);
update_record(service, record, now);
DEBUG_LOG(LOGF_ClientLog, "Cmd hits %"PRIu32" rate %d tokens %d",
record->cmd_hits, record->cmd_rate, record->cmd_tokens);
DEBUG_LOG("service %d hits %"PRIu32" rate %d trate %d tokens %d",
(int)service, record->hits[service], record->rate[service],
service == CLG_NTP ? record->ntp_timeout_rate : INVALID_RATE,
record->tokens[service]);
return get_index(record);
}
@@ -515,83 +601,396 @@ limit_response_random(int leak_rate)
/* ================================================== */
int
CLG_LimitNTPResponseRate(int index)
CLG_LimitServiceRate(CLG_Service service, int index)
{
Record *record;
int drop;
if (!ntp_leak_rate)
check_service_number(service);
if (tokens_per_hit[service] == 0)
return 0;
record = ARR_GetElement(records, index);
record->flags &= ~FLAG_NTP_DROPPED;
record->drop_flags &= ~(1U << service);
if (record->ntp_tokens >= ntp_tokens_per_packet) {
record->ntp_tokens -= ntp_tokens_per_packet;
if (record->tokens[service] >= tokens_per_hit[service]) {
record->tokens[service] -= tokens_per_hit[service];
return 0;
}
drop = limit_response_random(ntp_leak_rate);
drop = limit_response_random(leak_rate[service]);
/* Poorly implemented clients may send new requests at even a higher rate
/* Poorly implemented NTP clients can send requests at a higher rate
when they are not getting replies. If the request rate seems to be more
than twice as much as when replies are sent, give up on rate limiting to
reduce the amount of traffic. Invert the sense of the leak to respond to
most of the requests, but still keep the estimated rate updated. */
if (record->ntp_timeout_rate != INVALID_RATE &&
record->ntp_timeout_rate > record->ntp_rate + RATE_SCALE)
if (service == CLG_NTP && record->ntp_timeout_rate != INVALID_RATE &&
record->ntp_timeout_rate > record->rate[service] + RATE_SCALE)
drop = !drop;
if (!drop) {
record->ntp_tokens = 0;
record->tokens[service] = 0;
return 0;
}
record->flags |= FLAG_NTP_DROPPED;
record->ntp_drops++;
total_ntp_drops++;
record->drop_flags |= 1U << service;
record->drops[service]++;
total_drops[service]++;
return 1;
}
/* ================================================== */
void
CLG_UpdateNtpStats(int auth, NTP_Timestamp_Source rx_ts_src, NTP_Timestamp_Source tx_ts_src)
{
if (auth)
total_ntp_auth_hits++;
if (rx_ts_src >= 0 && rx_ts_src <= MAX_NTP_TS)
total_ntp_rx_timestamps[rx_ts_src]++;
if (tx_ts_src >= 0 && tx_ts_src <= MAX_NTP_TS)
total_ntp_tx_timestamps[tx_ts_src]++;
}
/* ================================================== */
int
CLG_LimitCommandResponseRate(int index)
CLG_GetNtpMinPoll(void)
{
Record *record;
return limit_interval[CLG_NTP];
}
if (!cmd_leak_rate)
return 0;
/* ================================================== */
record = ARR_GetElement(records, index);
static NtpTimestamps *
get_ntp_tss(uint32_t index)
{
return ARR_GetElement(ntp_ts_map.timestamps,
(ntp_ts_map.first + index) & (ntp_ts_map.max_size - 1));
}
if (record->cmd_tokens >= cmd_tokens_per_packet) {
record->cmd_tokens -= cmd_tokens_per_packet;
/* ================================================== */
static int
find_ntp_rx_ts(uint64_t rx_ts, uint32_t *index)
{
uint64_t rx_x, rx_lo, rx_hi, step;
uint32_t i, x, lo, hi;
if (ntp_ts_map.cached_rx_ts == rx_ts && rx_ts != 0ULL) {
*index = ntp_ts_map.cached_index;
return 1;
}
if (ntp_ts_map.size == 0) {
*index = 0;
return 0;
}
if (!limit_response_random(cmd_leak_rate)) {
record->cmd_tokens = 0;
lo = 0;
hi = ntp_ts_map.size - 1;
rx_lo = get_ntp_tss(lo)->rx_ts;
rx_hi = get_ntp_tss(hi)->rx_ts;
/* Check for ts < lo before ts > hi to trim timestamps from "future" later
if both conditions are true to not break the order of the endpoints.
Compare timestamps by their difference to allow adjacent NTP eras. */
if ((int64_t)(rx_ts - rx_lo) < 0) {
*index = 0;
return 0;
} else if ((int64_t)(rx_ts - rx_hi) > 0) {
*index = ntp_ts_map.size;
return 0;
}
record->cmd_drops++;
total_cmd_drops++;
/* Perform a combined linear interpolation and binary search */
for (i = 0; ; i++) {
if (rx_ts == rx_hi) {
*index = ntp_ts_map.cached_index = hi;
ntp_ts_map.cached_rx_ts = rx_ts;
return 1;
} else if (rx_ts == rx_lo) {
*index = ntp_ts_map.cached_index = lo;
ntp_ts_map.cached_rx_ts = rx_ts;
return 1;
} else if (lo + 1 == hi) {
*index = hi;
return 0;
}
if (hi - lo > 3 && i % 2 == 0) {
step = (rx_hi - rx_lo) / (hi - lo);
if (step == 0)
step = 1;
x = lo + (rx_ts - rx_lo) / step;
} else {
x = lo + (hi - lo) / 2;
}
if (x <= lo)
x = lo + 1;
else if (x >= hi)
x = hi - 1;
rx_x = get_ntp_tss(x)->rx_ts;
if ((int64_t)(rx_x - rx_ts) <= 0) {
lo = x;
rx_lo = rx_x;
} else {
hi = x;
rx_hi = rx_x;
}
}
}
/* ================================================== */
static uint64_t
ntp64_to_int64(NTP_int64 *ts)
{
return (uint64_t)ntohl(ts->hi) << 32 | ntohl(ts->lo);
}
/* ================================================== */
static void
int64_to_ntp64(uint64_t ts, NTP_int64 *ntp_ts)
{
ntp_ts->hi = htonl(ts >> 32);
ntp_ts->lo = htonl(ts);
}
/* ================================================== */
static uint32_t
push_ntp_tss(uint32_t index)
{
if (ntp_ts_map.size < ntp_ts_map.max_size) {
ntp_ts_map.size++;
} else {
ntp_ts_map.first = (ntp_ts_map.first + 1) % (ntp_ts_map.max_size);
if (index > 0)
index--;
}
return index;
}
/* ================================================== */
static void
set_ntp_tx(NtpTimestamps *tss, NTP_int64 *rx_ts, struct timespec *tx_ts,
NTP_Timestamp_Source tx_src)
{
struct timespec ts;
if (!tx_ts) {
tss->flags &= ~NTPTS_VALID_TX;
return;
}
UTI_Ntp64ToTimespec(rx_ts, &ts);
UTI_DiffTimespecs(&ts, tx_ts, &ts);
if (ts.tv_sec < -2 || ts.tv_sec > 1) {
tss->flags &= ~NTPTS_VALID_TX;
return;
}
tss->tx_ts_offset = (int32_t)ts.tv_nsec + (int32_t)ts.tv_sec * (int32_t)NSEC_PER_SEC;
tss->flags |= NTPTS_VALID_TX;
tss->tx_ts_source = tx_src;
}
/* ================================================== */
static void
get_ntp_tx(NtpTimestamps *tss, struct timespec *tx_ts, NTP_Timestamp_Source *tx_src)
{
int32_t offset = tss->tx_ts_offset;
NTP_int64 ntp_ts;
if (tss->flags & NTPTS_VALID_TX) {
int64_to_ntp64(tss->rx_ts, &ntp_ts);
UTI_Ntp64ToTimespec(&ntp_ts, tx_ts);
if (offset >= (int32_t)NSEC_PER_SEC) {
offset -= NSEC_PER_SEC;
tx_ts->tv_sec++;
}
tx_ts->tv_nsec += offset;
UTI_NormaliseTimespec(tx_ts);
} else {
UTI_ZeroTimespec(tx_ts);
}
*tx_src = tss->tx_ts_source;
}
/* ================================================== */
void
CLG_SaveNtpTimestamps(NTP_int64 *rx_ts, struct timespec *tx_ts, NTP_Timestamp_Source tx_src)
{
NtpTimestamps *tss;
uint32_t i, index;
uint64_t rx;
if (!active)
return;
/* Allocate the array on first use */
if (!ntp_ts_map.timestamps) {
ntp_ts_map.timestamps = ARR_CreateInstance(sizeof (NtpTimestamps));
ARR_SetSize(ntp_ts_map.timestamps, ntp_ts_map.max_size);
}
rx = ntp64_to_int64(rx_ts);
if (rx == 0ULL)
return;
/* Disable the RX timestamp if it already exists to avoid responding
with a wrong TX timestamp */
if (find_ntp_rx_ts(rx, &index)) {
get_ntp_tss(index)->flags |= NTPTS_DISABLED;
return;
}
assert(index <= ntp_ts_map.size);
if (index == ntp_ts_map.size) {
/* Increase the size or drop the oldest timestamp to make room for
the new timestamp */
index = push_ntp_tss(index);
} else {
/* Trim timestamps in distant future after backward step */
while (index < ntp_ts_map.size &&
get_ntp_tss(ntp_ts_map.size - 1)->rx_ts - rx > NTPTS_FUTURE_LIMIT)
ntp_ts_map.size--;
/* Insert the timestamp if it is close to the latest timestamp.
Otherwise, replace the closest older or the oldest timestamp. */
if (index + NTPTS_INSERT_LIMIT >= ntp_ts_map.size) {
index = push_ntp_tss(index);
for (i = ntp_ts_map.size - 1; i > index; i--)
*get_ntp_tss(i) = *get_ntp_tss(i - 1);
} else {
if (index > 0)
index--;
}
}
ntp_ts_map.cached_index = index;
ntp_ts_map.cached_rx_ts = rx;
tss = get_ntp_tss(index);
tss->rx_ts = rx;
tss->flags = 0;
tss->slew_epoch = ntp_ts_map.slew_epoch;
set_ntp_tx(tss, rx_ts, tx_ts, tx_src);
DEBUG_LOG("Saved RX+TX index=%"PRIu32" first=%"PRIu32" size=%"PRIu32,
index, ntp_ts_map.first, ntp_ts_map.size);
}
/* ================================================== */
static void
handle_slew(struct timespec *raw, struct timespec *cooked, double dfreq,
double doffset, LCL_ChangeType change_type, void *anything)
{
/* Drop all timestamps on unknown step */
if (change_type == LCL_ChangeUnknownStep) {
ntp_ts_map.size = 0;
ntp_ts_map.cached_rx_ts = 0ULL;
}
ntp_ts_map.slew_epoch++;
ntp_ts_map.slew_offset = doffset;
}
/* ================================================== */
void
CLG_UndoNtpTxTimestampSlew(NTP_int64 *rx_ts, struct timespec *tx_ts)
{
uint32_t index;
if (!ntp_ts_map.timestamps)
return;
if (!find_ntp_rx_ts(ntp64_to_int64(rx_ts), &index))
return;
/* If the RX timestamp was captured before the last correction of the clock,
remove the adjustment from the TX timestamp */
if ((uint16_t)(get_ntp_tss(index)->slew_epoch + 1U) == ntp_ts_map.slew_epoch)
UTI_AddDoubleToTimespec(tx_ts, ntp_ts_map.slew_offset, tx_ts);
}
/* ================================================== */
void
CLG_UpdateNtpTxTimestamp(NTP_int64 *rx_ts, struct timespec *tx_ts,
NTP_Timestamp_Source tx_src)
{
uint32_t index;
if (!ntp_ts_map.timestamps)
return;
if (!find_ntp_rx_ts(ntp64_to_int64(rx_ts), &index))
return;
set_ntp_tx(get_ntp_tss(index), rx_ts, tx_ts, tx_src);
}
/* ================================================== */
int
CLG_GetNtpTxTimestamp(NTP_int64 *rx_ts, struct timespec *tx_ts,
NTP_Timestamp_Source *tx_src)
{
NtpTimestamps *tss;
uint32_t index;
if (!ntp_ts_map.timestamps)
return 0;
if (!find_ntp_rx_ts(ntp64_to_int64(rx_ts), &index))
return 0;
tss = get_ntp_tss(index);
if (tss->flags & NTPTS_DISABLED)
return 0;
get_ntp_tx(tss, tx_ts, tx_src);
return 1;
}
/* ================================================== */
void CLG_GetNtpTimestamps(int index, NTP_int64 **rx_ts, NTP_int64 **tx_ts)
void
CLG_DisableNtpTimestamps(NTP_int64 *rx_ts)
{
Record *record;
uint32_t index;
record = ARR_GetElement(records, index);
if (!ntp_ts_map.timestamps)
return;
*rx_ts = &record->ntp_rx_ts;
*tx_ts = &record->ntp_tx_ts;
if (find_ntp_rx_ts(ntp64_to_int64(rx_ts), &index))
get_ntp_tss(index)->flags |= NTPTS_DISABLED;
/* This assumes the function is called only to prevent multiple
interleaved responses to the same timestamp */
total_ntp_interleaved_hits++;
}
/* ================================================== */
@@ -630,10 +1029,12 @@ static uint32_t get_last_ago(uint32_t x, uint32_t y)
/* ================================================== */
int
CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report, struct timespec *now)
CLG_GetClientAccessReportByIndex(int index, int reset, uint32_t min_hits,
RPT_ClientAccessByIndex_Report *report, struct timespec *now)
{
Record *record;
uint32_t now_ts;
int i, r;
if (!active || index < 0 || index >= ARR_GetSize(records))
return 0;
@@ -643,20 +1044,44 @@ CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *repo
if (record->ip_addr.family == IPADDR_UNSPEC)
return 0;
now_ts = get_ts_from_timespec(now);
if (min_hits == 0) {
r = 1;
} else {
for (i = r = 0; i < MAX_SERVICES; i++) {
if (record->hits[i] >= min_hits) {
r = 1;
break;
}
}
}
report->ip_addr = record->ip_addr;
report->ntp_hits = record->ntp_hits;
report->cmd_hits = record->cmd_hits;
report->ntp_drops = record->ntp_drops;
report->cmd_drops = record->cmd_drops;
report->ntp_interval = get_interval(record->ntp_rate);
report->cmd_interval = get_interval(record->cmd_rate);
report->ntp_timeout_interval = get_interval(record->ntp_timeout_rate);
report->last_ntp_hit_ago = get_last_ago(now_ts, record->last_ntp_hit);
report->last_cmd_hit_ago = get_last_ago(now_ts, record->last_cmd_hit);
if (r) {
now_ts = get_ts_from_timespec(now);
return 1;
report->ip_addr = record->ip_addr;
report->ntp_hits = record->hits[CLG_NTP];
report->nke_hits = record->hits[CLG_NTSKE];
report->cmd_hits = record->hits[CLG_CMDMON];
report->ntp_drops = record->drops[CLG_NTP];
report->nke_drops = record->drops[CLG_NTSKE];
report->cmd_drops = record->drops[CLG_CMDMON];
report->ntp_interval = get_interval(record->rate[CLG_NTP]);
report->nke_interval = get_interval(record->rate[CLG_NTSKE]);
report->cmd_interval = get_interval(record->rate[CLG_CMDMON]);
report->ntp_timeout_interval = get_interval(record->ntp_timeout_rate);
report->last_ntp_hit_ago = get_last_ago(now_ts, record->last_hit[CLG_NTP]);
report->last_nke_hit_ago = get_last_ago(now_ts, record->last_hit[CLG_NTSKE]);
report->last_cmd_hit_ago = get_last_ago(now_ts, record->last_hit[CLG_CMDMON]);
}
if (reset) {
for (i = 0; i < MAX_SERVICES; i++) {
record->hits[i] = 0;
record->drops[i] = 0;
}
}
return r;
}
/* ================================================== */
@@ -664,9 +1089,23 @@ CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *repo
void
CLG_GetServerStatsReport(RPT_ServerStatsReport *report)
{
report->ntp_hits = total_ntp_hits;
report->cmd_hits = total_cmd_hits;
report->ntp_drops = total_ntp_drops;
report->cmd_drops = total_cmd_drops;
report->ntp_hits = total_hits[CLG_NTP];
report->nke_hits = total_hits[CLG_NTSKE];
report->cmd_hits = total_hits[CLG_CMDMON];
report->ntp_drops = total_drops[CLG_NTP];
report->nke_drops = total_drops[CLG_NTSKE];
report->cmd_drops = total_drops[CLG_CMDMON];
report->log_drops = total_record_drops;
report->ntp_auth_hits = total_ntp_auth_hits;
report->ntp_interleaved_hits = total_ntp_interleaved_hits;
report->ntp_timestamps = ntp_ts_map.size;
report->ntp_span_seconds = ntp_ts_map.size > 1 ?
(get_ntp_tss(ntp_ts_map.size - 1)->rx_ts -
get_ntp_tss(0)->rx_ts) >> 32 : 0;
report->ntp_daemon_rx_timestamps = total_ntp_rx_timestamps[NTP_TS_DAEMON];
report->ntp_daemon_tx_timestamps = total_ntp_tx_timestamps[NTP_TS_DAEMON];
report->ntp_kernel_rx_timestamps = total_ntp_rx_timestamps[NTP_TS_KERNEL];
report->ntp_kernel_tx_timestamps = total_ntp_tx_timestamps[NTP_TS_KERNEL];
report->ntp_hw_rx_timestamps = total_ntp_rx_timestamps[NTP_TS_HARDWARE];
report->ntp_hw_tx_timestamps = total_ntp_tx_timestamps[NTP_TS_HARDWARE];
}

View File

@@ -31,19 +31,37 @@
#include "sysincl.h"
#include "reports.h"
typedef enum {
CLG_NTP = 0,
CLG_NTSKE,
CLG_CMDMON,
} CLG_Service;
extern void CLG_Initialise(void);
extern void CLG_Finalise(void);
extern int CLG_GetClientIndex(IPAddr *client);
extern int CLG_LogNTPAccess(IPAddr *client, struct timespec *now);
extern int CLG_LogCommandAccess(IPAddr *client, struct timespec *now);
extern int CLG_LimitNTPResponseRate(int index);
extern int CLG_LimitCommandResponseRate(int index);
extern void CLG_GetNtpTimestamps(int index, NTP_int64 **rx_ts, NTP_int64 **tx_ts);
extern int CLG_LogServiceAccess(CLG_Service service, IPAddr *client, struct timespec *now);
extern int CLG_LimitServiceRate(CLG_Service service, int index);
extern void CLG_UpdateNtpStats(int auth, NTP_Timestamp_Source rx_ts_src,
NTP_Timestamp_Source tx_ts_src);
extern int CLG_GetNtpMinPoll(void);
/* Functions to save and retrieve timestamps for server interleaved mode */
extern void CLG_SaveNtpTimestamps(NTP_int64 *rx_ts, struct timespec *tx_ts,
NTP_Timestamp_Source tx_src);
extern void CLG_UndoNtpTxTimestampSlew(NTP_int64 *rx_ts, struct timespec *tx_ts);
extern void CLG_UpdateNtpTxTimestamp(NTP_int64 *rx_ts, struct timespec *tx_ts,
NTP_Timestamp_Source tx_src);
extern int CLG_GetNtpTxTimestamp(NTP_int64 *rx_ts, struct timespec *tx_ts,
NTP_Timestamp_Source *tx_src);
extern void CLG_DisableNtpTimestamps(NTP_int64 *rx_ts);
/* And some reporting functions, for use by chronyc. */
extern int CLG_GetNumberOfIndices(void);
extern int CLG_GetClientAccessReportByIndex(int index, RPT_ClientAccessByIndex_Report *report, struct timespec *now);
extern int CLG_GetClientAccessReportByIndex(int index, int reset, uint32_t min_hits,
RPT_ClientAccessByIndex_Report *report,
struct timespec *now);
extern void CLG_GetServerStatsReport(RPT_ServerStatsReport *report);
#endif /* GOT_CLIENTLOG_H */

48
cmac.h Normal file
View File

@@ -0,0 +1,48 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2019
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Header file for CMAC.
*/
#ifndef GOT_CMAC_H
#define GOT_CMAC_H
/* Avoid overlapping with the hash enumeration */
typedef enum {
CMC_INVALID = 0,
CMC_AES128 = 13,
CMC_AES256 = 14,
} CMC_Algorithm;
typedef struct CMC_Instance_Record *CMC_Instance;
extern int CMC_GetKeyLength(CMC_Algorithm algorithm);
extern CMC_Instance CMC_CreateInstance(CMC_Algorithm algorithm, const unsigned char *key,
int length);
extern int CMC_Hash(CMC_Instance inst, const void *in, int in_len,
unsigned char *out, int out_len);
extern void CMC_DestroyInstance(CMC_Instance inst);
#endif

189
cmac_gnutls.c Normal file
View File

@@ -0,0 +1,189 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2021
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
CMAC using the GnuTLS library
*/
#include "config.h"
#include "sysincl.h"
#include <gnutls/crypto.h>
#include "cmac.h"
#include "hash.h"
#include "logging.h"
#include "memory.h"
struct CMC_Instance_Record {
gnutls_mac_algorithm_t algorithm;
gnutls_hmac_hd_t mac;
};
/* ================================================== */
static int instance_counter = 0;
static int gnutls_initialised = 0;
/* ================================================== */
static void
init_gnutls(void)
{
int r;
if (gnutls_initialised)
return;
r = gnutls_global_init();
if (r < 0)
LOG_FATAL("Could not initialise %s : %s", "gnutls", gnutls_strerror(r));
DEBUG_LOG("Initialised");
gnutls_initialised = 1;
}
/* ================================================== */
static void
deinit_gnutls(void)
{
assert(gnutls_initialised);
gnutls_global_deinit();
gnutls_initialised = 0;
DEBUG_LOG("Deinitialised");
}
/* ================================================== */
static gnutls_mac_algorithm_t
get_mac_algorithm(CMC_Algorithm algorithm)
{
switch (algorithm) {
case CMC_AES128:
return GNUTLS_MAC_AES_CMAC_128;
case CMC_AES256:
return GNUTLS_MAC_AES_CMAC_256;
default:
return GNUTLS_MAC_UNKNOWN;
}
}
/* ================================================== */
int
CMC_GetKeyLength(CMC_Algorithm algorithm)
{
gnutls_mac_algorithm_t malgo = get_mac_algorithm(algorithm);
int len;
if (malgo == GNUTLS_MAC_UNKNOWN)
return 0;
len = gnutls_hmac_get_key_size(malgo);
if (len < 0)
return 0;
return len;
}
/* ================================================== */
CMC_Instance
CMC_CreateInstance(CMC_Algorithm algorithm, const unsigned char *key, int length)
{
gnutls_hmac_hd_t handle;
CMC_Instance inst;
int r;
if (instance_counter == 0)
init_gnutls();
if (length <= 0 || length != CMC_GetKeyLength(algorithm))
goto error;
r = gnutls_hmac_init(&handle, get_mac_algorithm(algorithm), key, length);
if (r < 0) {
DEBUG_LOG("Could not initialise %s : %s", "mac", gnutls_strerror(r));
goto error;
}
inst = MallocNew(struct CMC_Instance_Record);
inst->algorithm = get_mac_algorithm(algorithm);
inst->mac = handle;
instance_counter++;
return inst;
error:
if (instance_counter == 0)
deinit_gnutls();
return NULL;
}
/* ================================================== */
int
CMC_Hash(CMC_Instance inst, const void *in, int in_len, unsigned char *out, int out_len)
{
unsigned char buf[MAX_HASH_LENGTH];
int hash_len;
if (in_len < 0 || out_len < 0)
return 0;
hash_len = gnutls_hmac_get_len(inst->algorithm);
if (out_len > hash_len)
out_len = hash_len;
if (hash_len > sizeof (buf))
return 0;
if (gnutls_hmac(inst->mac, in, in_len) < 0) {
/* Reset the state */
gnutls_hmac_output(inst->mac, buf);
return 0;
}
gnutls_hmac_output(inst->mac, buf);
memcpy(out, buf, out_len);
return out_len;
}
/* ================================================== */
void
CMC_DestroyInstance(CMC_Instance inst)
{
gnutls_hmac_deinit(inst->mac, NULL);
Free(inst);
instance_counter--;
if (instance_counter == 0)
deinit_gnutls();
}

117
cmac_nettle.c Normal file
View File

@@ -0,0 +1,117 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2019
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Support for AES128 and AES256 CMAC in Nettle.
*/
#include "config.h"
#include "sysincl.h"
#include <nettle/cmac.h>
#include "cmac.h"
#include "memory.h"
struct CMC_Instance_Record {
int key_length;
union {
struct cmac_aes128_ctx aes128;
struct cmac_aes256_ctx aes256;
} context;
};
/* ================================================== */
int
CMC_GetKeyLength(CMC_Algorithm algorithm)
{
if (algorithm == CMC_AES128)
return AES128_KEY_SIZE;
else if (algorithm == CMC_AES256)
return AES256_KEY_SIZE;
return 0;
}
/* ================================================== */
CMC_Instance
CMC_CreateInstance(CMC_Algorithm algorithm, const unsigned char *key, int length)
{
CMC_Instance inst;
if (length <= 0 || length != CMC_GetKeyLength(algorithm))
return NULL;
inst = MallocNew(struct CMC_Instance_Record);
inst->key_length = length;
switch (length) {
case AES128_KEY_SIZE:
cmac_aes128_set_key(&inst->context.aes128, key);
break;
case AES256_KEY_SIZE:
cmac_aes256_set_key(&inst->context.aes256, key);
break;
default:
assert(0);
}
return inst;
}
/* ================================================== */
int
CMC_Hash(CMC_Instance inst, const void *in, int in_len, unsigned char *out, int out_len)
{
if (in_len < 0 || out_len < 0)
return 0;
if (out_len > CMAC128_DIGEST_SIZE)
out_len = CMAC128_DIGEST_SIZE;
switch (inst->key_length) {
case AES128_KEY_SIZE:
cmac_aes128_update(&inst->context.aes128, in_len, in);
cmac_aes128_digest(&inst->context.aes128, out_len, out);
break;
case AES256_KEY_SIZE:
cmac_aes256_update(&inst->context.aes256, in_len, in);
cmac_aes256_digest(&inst->context.aes256, out_len, out);
break;
default:
assert(0);
}
return out_len;
}
/* ================================================== */
void
CMC_DestroyInstance(CMC_Instance inst)
{
Free(inst);
}

820
cmdmon.c

File diff suppressed because it is too large Load Diff

View File

@@ -29,7 +29,7 @@
#include "addressing.h"
extern void CAM_Initialise(int family);
extern void CAM_Initialise(void);
extern void CAM_Finalise(void);

View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2013-2014, 2016
* Copyright (C) Miroslav Lichvar 2013-2014, 2016, 2021
*
* 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
@@ -43,14 +43,16 @@ int
CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
{
char *hostname, *cmd;
int n;
uint32_t ef_type;
int n, sel_option;
src->port = SRC_DEFAULT_PORT;
src->params.minpoll = SRC_DEFAULT_MINPOLL;
src->params.maxpoll = SRC_DEFAULT_MAXPOLL;
src->params.online = 1;
src->params.connectivity = SRC_ONLINE;
src->params.auto_offline = 0;
src->params.presend_minpoll = SRC_DEFAULT_PRESEND_MINPOLL;
src->params.burst = 0;
src->params.iburst = 0;
src->params.min_stratum = SRC_DEFAULT_MINSTRATUM;
src->params.poll_target = SRC_DEFAULT_POLLTARGET;
@@ -58,12 +60,21 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
src->params.max_sources = SRC_DEFAULT_MAXSOURCES;
src->params.min_samples = SRC_DEFAULT_MINSAMPLES;
src->params.max_samples = SRC_DEFAULT_MAXSAMPLES;
src->params.filter_length = 0;
src->params.interleaved = 0;
src->params.sel_options = 0;
src->params.nts = 0;
src->params.nts_port = SRC_DEFAULT_NTSPORT;
src->params.copy = 0;
src->params.ext_fields = 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;
src->params.max_delay_quant = 0.0;
src->params.min_delay = 0.0;
src->params.asymmetry = SRC_DEFAULT_ASYMMETRY;
src->params.offset = 0.0;
hostname = line;
@@ -82,22 +93,40 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
if (!strcasecmp(cmd, "auto_offline")) {
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")) {
src->params.online = 0;
} else if (!strcasecmp(cmd, "noselect")) {
src->params.sel_options |= SRC_SELECT_NOSELECT;
} else if (!strcasecmp(cmd, "prefer")) {
src->params.sel_options |= SRC_SELECT_PREFER;
} else if (!strcasecmp(cmd, "require")) {
src->params.sel_options |= SRC_SELECT_REQUIRE;
} else if (!strcasecmp(cmd, "trust")) {
src->params.sel_options |= SRC_SELECT_TRUST;
src->params.connectivity = SRC_OFFLINE;
} 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)
return 0;
} else if (!strcasecmp(cmd, "asymmetry")) {
if (sscanf(line, "%lf%n", &src->params.asymmetry, &n) != 1)
return 0;
} else if (!strcasecmp(cmd, "extfield")) {
if (sscanf(line, "%"SCNx32"%n", &ef_type, &n) != 1)
return 0;
switch (ef_type) {
case NTP_EF_EXP_MONO_ROOT:
src->params.ext_fields |= NTP_EF_FLAG_EXP_MONO_ROOT;
break;
case NTP_EF_EXP_NET_CORRECTION:
src->params.ext_fields |= NTP_EF_FLAG_EXP_NET_CORRECTION;
break;
default:
return 0;
}
} else if (!strcasecmp(cmd, "filter")) {
if (sscanf(line, "%d%n", &src->params.filter_length, &n) != 1)
return 0;
} else if (!strcasecmp(cmd, "maxdelay")) {
if (sscanf(line, "%lf%n", &src->params.max_delay, &n) != 1)
return 0;
@@ -107,6 +136,9 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "maxdelaydevratio")) {
if (sscanf(line, "%lf%n", &src->params.max_delay_dev_ratio, &n) != 1)
return 0;
} else if (!strcasecmp(cmd, "maxdelayquant")) {
if (sscanf(line, "%lf%n", &src->params.max_delay_quant, &n) != 1)
return 0;
} else if (!strcasecmp(cmd, "maxpoll")) {
if (sscanf(line, "%d%n", &src->params.maxpoll, &n) != 1)
return 0;
@@ -116,6 +148,9 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "maxsources")) {
if (sscanf(line, "%d%n", &src->params.max_sources, &n) != 1)
return 0;
} else if (!strcasecmp(cmd, "mindelay")) {
if (sscanf(line, "%lf%n", &src->params.min_delay, &n) != 1)
return 0;
} else if (!strcasecmp(cmd, "minpoll")) {
if (sscanf(line, "%d%n", &src->params.minpoll, &n) != 1)
return 0;
@@ -125,11 +160,16 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
} else if (!strcasecmp(cmd, "minstratum")) {
if (sscanf(line, "%d%n", &src->params.min_stratum, &n) != 1)
return 0;
} else if (!strcasecmp(cmd, "nts")) {
src->params.nts = 1;
} else if (!strcasecmp(cmd, "ntsport")) {
if (sscanf(line, "%d%n", &src->params.nts_port, &n) != 1)
return 0;
} else if (!strcasecmp(cmd, "offset")) {
if (sscanf(line, "%lf%n", &src->params.offset, &n) != 1)
return 0;
} else if (!strcasecmp(cmd, "port")) {
if (sscanf(line, "%hu%n", &src->port, &n) != 1)
if (sscanf(line, "%d%n", &src->port, &n) != 1)
return 0;
} else if (!strcasecmp(cmd, "polltarget")) {
if (sscanf(line, "%d%n", &src->params.poll_target, &n) != 1)
@@ -142,6 +182,8 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
return 0;
} else if (!strcasecmp(cmd, "xleave")) {
src->params.interleaved = 1;
} else if ((sel_option = CPS_GetSelectOption(cmd)) != 0) {
src->params.sel_options |= sel_option;
} else {
return 0;
}
@@ -152,6 +194,102 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src)
/* ================================================== */
int
CPS_GetSelectOption(char *option)
{
if (!strcasecmp(option, "noselect")) {
return SRC_SELECT_NOSELECT;
} else if (!strcasecmp(option, "prefer")) {
return SRC_SELECT_PREFER;
} else if (!strcasecmp(option, "require")) {
return SRC_SELECT_REQUIRE;
} else if (!strcasecmp(option, "trust")) {
return SRC_SELECT_TRUST;
}
return 0;
}
/* ================================================== */
int
CPS_ParseAllowDeny(char *line, int *all, IPAddr *ip, int *subnet_bits)
{
char *p, *net, *slash;
uint32_t a, b, c;
int bits, len, n;
p = CPS_SplitWord(line);
if (strcmp(line, "all") == 0) {
*all = 1;
net = p;
p = CPS_SplitWord(p);
} else {
*all = 0;
net = line;
}
/* Make sure there are no other arguments */
if (*p)
return 0;
/* No specified address or network means all IPv4 and IPv6 addresses */
if (!*net) {
ip->family = IPADDR_UNSPEC;
*subnet_bits = 0;
return 1;
}
slash = strchr(net, '/');
if (slash) {
if (sscanf(slash + 1, "%d%n", &bits, &len) != 1 || slash[len + 1] || bits < 0)
return 0;
*slash = '\0';
} else {
bits = -1;
}
if (UTI_StringToIP(net, ip)) {
if (bits >= 0)
*subnet_bits = bits;
else
*subnet_bits = ip->family == IPADDR_INET6 ? 128 : 32;
return 1;
}
/* Check for a shortened IPv4 network notation using only 1, 2, or 3 decimal
numbers. This is different than the numbers-and-dots notation accepted
by inet_aton()! */
a = b = c = 0;
n = sscanf(net, "%"PRIu32"%n.%"PRIu32"%n.%"PRIu32"%n", &a, &len, &b, &len, &c, &len);
if (n > 0 && !net[len]) {
if (a > 255 || b > 255 || c > 255)
return 0;
ip->family = IPADDR_INET4;
ip->addr.in4 = (a << 24) | (b << 16) | (c << 8);
if (bits >= 0)
*subnet_bits = bits;
else
*subnet_bits = n * 8;
return 1;
}
/* The last possibility is a hostname */
if (bits < 0 && DNS_Name2IPAddress(net, ip, 1) == DNS_Success) {
*subnet_bits = ip->family == IPADDR_INET6 ? 128 : 32;
return 1;
}
return 0;
}
/* ================================================== */
int
CPS_ParseLocal(char *line, int *stratum, int *orphan, double *distance)
{
@@ -246,7 +384,7 @@ CPS_SplitWord(char *line)
/* ================================================== */
int
CPS_ParseKey(char *line, uint32_t *id, const char **hash, char **key)
CPS_ParseKey(char *line, uint32_t *id, const char **type, char **key)
{
char *s1, *s2, *s3, *s4;
@@ -263,12 +401,28 @@ CPS_ParseKey(char *line, uint32_t *id, const char **hash, char **key)
return 0;
if (*s3) {
*hash = s2;
*type = s2;
*key = s3;
} else {
*hash = "MD5";
*type = "MD5";
*key = s2;
}
return 1;
}
/* ================================================== */
int
CPS_ParseRefid(char *line, uint32_t *ref_id)
{
int i;
for (i = *ref_id = 0; line[i] && !isspace((unsigned char)line[i]); i++) {
if (i >= 4)
return 0;
*ref_id |= (uint32_t)line[i] << (24 - i * 8);
}
return i;
}

View File

@@ -32,13 +32,19 @@
typedef struct {
char *name;
unsigned short port;
int port;
SourceParameters params;
} CPS_NTP_Source;
/* Parse a command to add an NTP server or peer */
extern int CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src);
/* Get an NTP/refclock select option */
extern int CPS_GetSelectOption(char *option);
/* Parse a command to allow/deny access */
extern int CPS_ParseAllowDeny(char *line, int *all, IPAddr *ip, int *subnet_bits);
/* Parse a command to enable local reference */
extern int CPS_ParseLocal(char *line, int *stratum, int *orphan, double *distance);
@@ -49,6 +55,9 @@ extern void CPS_NormalizeLine(char *line);
extern char *CPS_SplitWord(char *line);
/* Parse a key from keyfile */
extern int CPS_ParseKey(char *line, uint32_t *id, const char **hash, char **key);
extern int CPS_ParseKey(char *line, uint32_t *id, const char **type, char **key);
/* Parse a refclock reference ID (returns number of characters) */
extern int CPS_ParseRefid(char *line, uint32_t *ref_id);
#endif /* GOT_CMDPARSE_H */

1119
conf.c

File diff suppressed because it is too large Load Diff

65
conf.h
View File

@@ -29,12 +29,14 @@
#define GOT_CONF_H
#include "addressing.h"
#include "array.h"
#include "reference.h"
#include "sources.h"
extern void CNF_Initialise(int restarted);
extern void CNF_Initialise(int restarted, int client_only);
extern void CNF_Finalise(void);
extern void CNF_EnablePrint(void);
extern char *CNF_GetRtcDevice(void);
extern void CNF_ReadFile(const char *filename);
@@ -42,18 +44,23 @@ extern void CNF_ParseLine(const char *filename, int number, char *line);
extern void CNF_CreateDirs(uid_t uid, gid_t gid);
extern void CNF_CheckReadOnlyAccess(void);
extern void CNF_AddInitSources(void);
extern void CNF_AddSources(void);
extern void CNF_AddBroadcasts(void);
extern void CNF_AddRefclocks(void);
extern void CNF_ReloadSources(void);
extern int CNF_GetAcquisitionPort(void);
extern int CNF_GetNTPPort(void);
extern char *CNF_GetDriftFile(void);
extern char *CNF_GetLogDir(void);
extern char *CNF_GetDumpDir(void);
extern int CNF_GetLogBanner(void);
extern int CNF_GetLogMeasurements(void);
extern int CNF_GetLogMeasurements(int *raw);
extern int CNF_GetLogSelection(void);
extern int CNF_GetLogStatistics(void);
extern int CNF_GetLogTracking(void);
extern int CNF_GetLogRtc(void);
@@ -61,7 +68,6 @@ extern int CNF_GetLogRefclocks(void);
extern int CNF_GetLogTempComp(void);
extern char *CNF_GetKeysFile(void);
extern char *CNF_GetRtcFile(void);
extern int CNF_GetDumpOnExit(void);
extern int CNF_GetManualEnabled(void);
extern int CNF_GetCommandPort(void);
extern int CNF_GetRtcOnUtc(void);
@@ -76,7 +82,11 @@ extern void CNF_GetFallbackDrifts(int *min, int *max);
extern void CNF_GetBindAddress(int family, IPAddr *addr);
extern void CNF_GetBindAcquisitionAddress(int family, IPAddr *addr);
extern void CNF_GetBindCommandAddress(int family, IPAddr *addr);
extern char *CNF_GetBindNtpInterface(void);
extern char *CNF_GetBindAcquisitionInterface(void);
extern char *CNF_GetBindCommandInterface(void);
extern char *CNF_GetBindCommandPath(void);
extern int CNF_GetNtpDscp(void);
extern char *CNF_GetNtpSigndSocket(void);
extern char *CNF_GetPidFile(void);
extern REF_LeapMode CNF_GetLeapSecMode(void);
@@ -88,7 +98,9 @@ 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);
extern double CNF_GetMaxJitter(void);
extern double CNF_GetReselectDistance(void);
@@ -102,8 +114,9 @@ extern void CNF_SetupAccessRestrictions(void);
extern int CNF_GetSchedPriority(void);
extern int CNF_GetLockMemory(void);
extern void CNF_GetNTPRateLimit(int *interval, int *burst, int *leak);
extern void CNF_GetCommandRateLimit(int *interval, int *burst, int *leak);
extern int CNF_GetNTPRateLimit(int *interval, int *burst, int *leak);
extern int CNF_GetNtsRateLimit(int *interval, int *burst, int *leak);
extern int CNF_GetCommandRateLimit(int *interval, int *burst, int *leak);
extern void CNF_GetSmooth(double *max_freq, double *max_wander, int *leap_only);
extern void CNF_GetTempComp(char **file, double *interval, char **point_file, double *T0, double *k0, double *k1, double *k2);
@@ -120,6 +133,44 @@ extern char *CNF_GetHwclockFile(void);
extern int CNF_GetInitSources(void);
extern double CNF_GetInitStepThreshold(void);
extern ARR_Instance CNF_GetHwTsInterfaces(void);
typedef enum {
CNF_HWTS_RXFILTER_ANY,
CNF_HWTS_RXFILTER_NONE,
CNF_HWTS_RXFILTER_NTP,
CNF_HWTS_RXFILTER_PTP,
CNF_HWTS_RXFILTER_ALL,
} CNF_HwTs_RxFilter;
typedef struct {
char *name;
int minpoll;
int maxpoll;
int min_samples;
int max_samples;
int nocrossts;
CNF_HwTs_RxFilter rxfilter;
double precision;
double tx_comp;
double rx_comp;
} CNF_HwTsInterface;
extern int CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface);
extern double CNF_GetHwTsTimeout(void);
extern int CNF_GetPtpPort(void);
extern int CNF_GetRefresh(void);
extern char *CNF_GetNtsDumpDir(void);
extern char *CNF_GetNtsNtpServer(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 int CNF_GetNtsTrustedCertsPaths(const char ***paths, uint32_t **ids);
extern int CNF_GetNoSystemCert(void);
extern int CNF_GetNoCertTimeCheck(void);
#endif /* GOT_CONF_H */

479
configure vendored
View File

@@ -4,7 +4,9 @@
# chronyd/chronyc - Programs for keeping computer clocks accurate.
#
# Copyright (C) Richard P. Curnow 1997-2003
# Copyright (C) Miroslav Lichvar 2009, 2012-2015
# Copyright (C) Bryan Christianson 2016
# Copyright (C) Miroslav Lichvar 2009, 2012-2022
# Copyright (C) Stefan R. Filipek 2019
#
# =======================================================================
@@ -31,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 ]
@@ -48,11 +50,39 @@ test_code () {
echo "No"
result=1
fi
rm -f docheck.c docheck
rm -f conftest.c conftest
echo >> config.log
return $result
}
#}}}
#{{{ test_executable
test_executable () {
name=$1
executable=$2
options=$3
printf "%s" "Checking for $name : "
echo $executable $options >> config.log
$executable $options >> config.log 2>&1
if [ $? -eq 0 ]
then
echo "Yes"
result=0
else
echo "No"
result=1
fi
echo >> config.log
return $result
}
#}}}
#{{{ pkg_config
pkg_config () {
$PKG_CONFIG "$@" 2>> config.log
}
#}}}
#{{{ usage
usage () {
cat <<EOF
@@ -78,14 +108,13 @@ 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-gnutls Don't use gnutls even if it is available
--without-nss Don't use NSS even if it is available
--without-tomcrypt Don't use libtomcrypt even if it is available
--disable-nts Disable NTS support
--disable-cmdmon Disable command and monitoring support
--disable-ntp Disable NTP support
--disable-refclock Disable reference clock support
@@ -99,6 +128,7 @@ For better control, use the options below.
--without-seccomp Don't use seccomp even if it is available
--disable-asyncdns Disable asynchronous name resolving
--disable-forcednsretry Don't retry on permanent DNS error
--without-aes-gcm-siv Don't use AES-GCM-SIV for NTS even if it is available
--without-clock-gettime Don't use clock_gettime() even if it is available
--disable-timestamping Disable support for SW/HW timestamping
--enable-ntp-signd Enable support for MS-SNTP authentication in Samba
@@ -106,7 +136,7 @@ For better control, use the options below.
since 1970-01-01 [50*365 days ago]
--with-user=USER Specify default chronyd user [root]
--with-hwclockfile=PATH Specify default path to hwclock(8) adjtime file
--with-pidfile=PATH Specify default pidfile [/var/run/chronyd.pid]
--with-pidfile=PATH Specify default pidfile [/var/run/chrony/chronyd.pid]
--with-rtcdevice=PATH Specify default path to RTC device [/dev/rtc]
--with-sendmail=PATH Path to sendmail binary [/usr/lib/sendmail]
--enable-debug Enable debugging support
@@ -134,6 +164,11 @@ Some influential environment variables:
headers in a nonstandard directory <include dir>
LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
nonstandard directory <lib dir>
PKG_CONFIG path to pkg-config utility
PKG_CONFIG_PATH
directories to add to pkg-config's search path
PKG_CONFIG_LIBDIR
path overriding pkg-config's built-in search path
Use these variables to override the choices made by \`configure' or to help
it to find libraries and programs with nonstandard names/locations.
@@ -151,13 +186,6 @@ add_def () {
fi
}
#}}}
#{{{ pkg_config
pkg_config () {
type pkg-config > /dev/null 2> /dev/null || return 1
pkg-config $@ 2> /dev/null
}
#}}}
#{{{ get_features
get_features () {
ff=1
@@ -183,22 +211,24 @@ OPERATINGSYSTEM=`uname -s`
VERSION=`uname -r`
MACHINE=`uname -m`
LIBS=""
EXTRA_LIBS=""
EXTRA_CLI_LIBS=""
EXTRA_OBJECTS=""
EXTRA_DEFS=""
SYSDEFS=""
EXTRA_CLI_OBJECTS=""
feat_debug=0
feat_cmdmon=1
feat_ntp=1
feat_refclock=1
feat_readline=1
try_readline=1
try_editline=1
feat_sechash=1
try_nettle=1
try_nss=1
try_tomcrypt=1
feat_nts=1
try_gnutls=1
feat_rtc=1
try_rtc=0
feat_droproot=1
@@ -207,9 +237,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
@@ -218,15 +245,18 @@ try_setsched=0
try_lockmem=0
feat_asyncdns=1
feat_forcednsretry=1
try_aes_gcm_siv=1
try_clock_gettime=1
try_arc4random=1
try_recvmmsg=1
feat_timestamping=1
try_timestamping=0
feat_ntp_signd=0
ntp_era_split=""
use_pthread=0
default_user="root"
default_hwclockfile=""
default_pidfile="/var/run/chronyd.pid"
default_pidfile="/var/run/chrony/chronyd.pid"
default_rtcdevice="/dev/rtc"
mail_program="/usr/lib/sendmail"
@@ -239,21 +269,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/[^=]*=//;'`
;;
@@ -329,6 +347,9 @@ do
--disable-forcednsretry)
feat_forcednsretry=0
;;
--without-aes-gcm-siv)
try_aes_gcm_siv=0
;;
--without-clock-gettime)
try_clock_gettime=0
;;
@@ -359,12 +380,21 @@ do
--disable-sechash )
feat_sechash=0
;;
--without-nettle )
try_nettle=0
;;
--without-nss )
try_nss=0
;;
--without-tomcrypt )
try_tomcrypt=0
;;
--disable-nts )
feat_nts=0
;;
--without-gnutls )
try_gnutls=0
;;
--host-system=* )
OPERATINGSYSTEM=`echo $option | sed -e 's/^.*=//;'`
;;
@@ -389,7 +419,7 @@ SYSTEM=${OPERATINGSYSTEM}-${MACHINE}
case $OPERATINGSYSTEM in
Linux)
EXTRA_OBJECTS="sys_generic.o sys_linux.o sys_timex.o"
EXTRA_OBJECTS="sys_generic.o sys_linux.o sys_timex.o sys_posix.o"
[ $try_libcap != "0" ] && try_libcap=1
try_rtc=1
[ $try_seccomp != "0" ] && try_seccomp=1
@@ -397,6 +427,7 @@ case $OPERATINGSYSTEM in
try_setsched=1
try_lockmem=1
try_phc=1
try_arc4random=0
add_def LINUX
echo "Configuring for " $SYSTEM
;;
@@ -404,7 +435,9 @@ case $OPERATINGSYSTEM in
# recvmmsg() seems to be broken on FreeBSD 11.0 and it's just
# a wrapper around recvmsg()
try_recvmmsg=0
EXTRA_OBJECTS="sys_generic.o sys_netbsd.o sys_timex.o"
EXTRA_OBJECTS="sys_generic.o sys_netbsd.o sys_timex.o sys_posix.o"
try_setsched=1
try_lockmem=1
add_def FREEBSD
if [ $feat_droproot = "1" ]; then
add_def FEAT_PRIVDROP
@@ -413,26 +446,37 @@ case $OPERATINGSYSTEM in
echo "Configuring for $SYSTEM"
;;
NetBSD)
EXTRA_OBJECTS="sys_generic.o sys_netbsd.o sys_timex.o"
EXTRA_OBJECTS="sys_generic.o sys_netbsd.o sys_timex.o sys_posix.o"
try_clockctl=1
try_setsched=1
try_lockmem=1
add_def NETBSD
echo "Configuring for $SYSTEM"
;;
Darwin)
EXTRA_OBJECTS="sys_macosx.o"
EXTRA_LIBS="-lresolv"
EXTRA_CLI_LIBS="-lresolv"
LIBS="$LIBS -lresolv"
add_def MACOSX
if [ $feat_droproot = "1" ]; then
add_def FEAT_PRIVDROP
priv_ops="ADJUSTTIME SETTIME BINDSOCKET"
fi
major=`echo $VERSION | cut -d. -f1`
# ntp_adjtime is not available in macOS 10.12 (Darwin 16.x.x) and earlier
if [ $major -gt "16" ]; then
add_def HAVE_MACOS_SYS_TIMEX
EXTRA_OBJECTS="$EXTRA_OBJECTS sys_generic.o sys_netbsd.o sys_timex.o"
if [ $feat_droproot = "1" ]; then
priv_ops="$priv_ops ADJUSTTIMEX"
fi
fi
echo "Configuring for macOS (" $SYSTEM "macOS version" $VERSION ")"
;;
SunOS)
EXTRA_OBJECTS="sys_generic.o sys_solaris.o sys_timex.o"
EXTRA_LIBS="-lsocket -lnsl -lresolv"
EXTRA_CLI_LIBS="-lsocket -lnsl -lresolv"
EXTRA_OBJECTS="sys_generic.o sys_solaris.o sys_timex.o sys_posix.o"
LIBS="$LIBS -lsocket -lnsl -lkvm -lelf -lresolv"
try_setsched=1
try_lockmem=1
add_def SOLARIS
# These are needed to have msg_control in struct msghdr
add_def __EXTENSIONS__
@@ -442,7 +486,7 @@ case $OPERATINGSYSTEM in
add_def FEAT_PRIVDROP
priv_ops="ADJUSTTIMEX SETTIME BINDSOCKET"
fi
echo "Configuring for Solaris (" $SYSTEM "SunOS version" $VERSION ")"
echo "Configuring for illumos (" $SYSTEM "SunOS version" $VERSION ")"
;;
* )
echo "error: $SYSTEM is not supported (yet?)"
@@ -462,7 +506,7 @@ fi
if [ $feat_ntp = "1" ]; then
add_def FEAT_NTP
EXTRA_OBJECTS="$EXTRA_OBJECTS ntp_core.o ntp_io.o ntp_sources.o"
EXTRA_OBJECTS="$EXTRA_OBJECTS ntp_auth.o ntp_core.o ntp_ext.o ntp_io.o ntp_sources.o"
if [ $feat_ntp_signd = "1" ]; then
add_def FEAT_SIGND
EXTRA_OBJECTS="$EXTRA_OBJECTS ntp_signd.o"
@@ -489,14 +533,16 @@ MYCPPFLAGS="$CPPFLAGS"
MYLDFLAGS="$LDFLAGS"
if [ "x$MYCC" = "x" ]; then
MYCC=gcc
if ! test_code "$MYCC" '' '' '' ''; then
MYCC=cc
if ! test_code "$MYCC" '' '' '' ''; then
for cc in gcc clang cc ""; do
if [ "x$cc" = "x" ]; then
echo "error: no C compiler found"
exit 1
fi
fi
MYCC=$cc
if test_code "$MYCC" '' '' '' ''; then
break
fi
done
else
if ! test_code "$MYCC" '' '' '' ''; then
echo "error: C compiler $MYCC cannot create executables"
@@ -506,12 +552,45 @@ fi
if [ "x$MYCFLAGS" = "x" ]; then
MYCFLAGS="-O2 -g"
TESTCFLAGS="-D_FORTIFY_SOURCE=2 -fPIE"
TESTLDFLAGS="-pie -Wl,-z,relro,-z,now"
if test_code 'hardening compiler options' '' "$TESTCFLAGS" "$TESTLDFLAGS" ''; then
MYCFLAGS="$MYCFLAGS $TESTCFLAGS"
MYLDFLAGS="$MYLDFLAGS $TESTLDFLAGS"
fi
TESTCFLAGS="-fstack-protector-strong --param=ssp-buffer-size=4"
if test_code '-fstack-protector-strong' '' "$TESTCFLAGS" '' ''; then
MYCFLAGS="$MYCFLAGS $TESTCFLAGS"
else
TESTCFLAGS="-fstack-protector --param=ssp-buffer-size=4"
if test_code '-fstack-protector' '' "$TESTCFLAGS" '' ''; then
MYCFLAGS="$MYCFLAGS $TESTCFLAGS"
fi
fi
fi
if [ "x$MYCC" = "xgcc" ]; then
TESTCFLAGS="-fwrapv"
if test_code '-fwrapv' '' "$TESTCFLAGS" '' ''; then
GETDATE_CFLAGS="-fwrapv"
else
GETDATE_CFLAGS=""
fi
if [ "x$MYCC" = "xgcc" ] || [ "x$MYCC" = "xclang" ]; then
MYCFLAGS="$MYCFLAGS -Wmissing-prototypes -Wall"
fi
if [ "x$PKG_CONFIG" = "x" ]; then
PKG_CONFIG=pkg-config
fi
if ! test_executable "pkg-config" $PKG_CONFIG --version; then
try_nettle=0
try_nss=0
try_gnutls=0
fi
if test_code '64-bit time_t' 'time.h' '' '' '
char x[sizeof(time_t) > 4 ? 1 : -1] = {0};
return x[0];'
@@ -522,7 +601,11 @@ then
split_seconds=$ntp_era_split
split_days=0
else
split_seconds=`date '+%s'`
if [ "x$SOURCE_DATE_EPOCH" != "x" ]; then
split_seconds=$SOURCE_DATE_EPOCH
else
split_seconds=`date '+%s'`
fi
if [ "x$split_seconds" = "x" ]; then
echo "error: could not get current time, --with-ntp-era option is needed"
exit 1
@@ -547,25 +630,15 @@ then
fi
MATHCODE='return (int) pow(2.0, log(sqrt((double)argc)));'
if test_code 'math' 'math.h' '' '' "$MATHCODE"; then
LIBS=""
else
if ! test_code 'math' 'math.h' '' '' "$MATHCODE"; then
if test_code 'math in -lm' 'math.h' '' '-lm' "$MATHCODE"; then
LIBS="-lm"
LIBS="$LIBS -lm"
else
echo "error: could not compile/link a program which uses sqrt(), log(), pow()"
exit 1
fi
fi
if test_code '<stdint.h>' 'stdint.h' '' '' ''; then
add_def HAVE_STDINT_H
fi
if test_code '<inttypes.h>' 'inttypes.h' '' '' ''; then
add_def HAVE_INTTYPES_H
fi
if test_code 'struct in_pktinfo' 'sys/socket.h netinet/in.h' '' '' '
struct in_pktinfo ipi;
return sizeof (ipi.ipi_spec_dst.s_addr) + IP_PKTINFO;'
@@ -574,10 +647,11 @@ then
fi
if [ $feat_ipv6 = "1" ] && \
test_code 'IPv6 support' 'arpa/inet.h sys/socket.h netinet/in.h' '' "$EXTRA_LIBS" '
test_code 'IPv6 support' 'arpa/inet.h sys/socket.h netinet/in.h' '' "$LIBS" '
struct sockaddr_in6 n;
char p[100];
n.sin6_addr = in6addr_any;
n.sin6_scope_id = 0;
return !inet_ntop(AF_INET6, &n.sin6_addr.s6_addr, p, sizeof(p));'
then
add_def FEAT_IPV6
@@ -595,14 +669,28 @@ 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);'
'clock_gettime(CLOCK_REALTIME, (void *)1);'
then
add_def HAVE_CLOCK_GETTIME
else
if test_code 'clock_gettime() in -lrt' 'time.h' '' '-lrt' \
'clock_gettime(CLOCK_REALTIME, NULL);'
'clock_gettime(CLOCK_REALTIME, (void *)1);'
then
add_def HAVE_CLOCK_GETTIME
EXTRA_LIBS="$EXTRA_LIBS -lrt"
@@ -610,35 +698,45 @@ if [ $try_clock_gettime = "1" ]; then
fi
fi
if test_code 'getaddrinfo()' 'sys/types.h sys/socket.h netdb.h' '' "$EXTRA_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" ] && \
test_code 'pthread' 'pthread.h' '-pthread' '' \
'return pthread_create((void *)1, NULL, (void *)1, NULL);'
test_code 'pthread' 'pthread.h' '-pthread' '' '
pthread_t thread;
return (int)pthread_create(&thread, NULL, (void *)1, NULL);'
then
add_def FEAT_ASYNCDNS
add_def USE_PTHREAD_ASYNCDNS
EXTRA_OBJECTS="$EXTRA_OBJECTS nameserv_async.o"
MYCFLAGS="$MYCFLAGS -pthread"
use_pthread=1
fi
if test_code 'arc4random_buf()' 'stdlib.h' '' '' 'arc4random_buf(NULL, 0);'; then
if [ $try_arc4random = "1" ] && \
test_code 'arc4random_buf()' 'stdlib.h' '' '' \
'arc4random_buf((void *)1, 1);'
then
add_def HAVE_ARC4RANDOM
else
if test_code 'getrandom()' 'stdlib.h sys/random.h' '' '' \
'return getrandom((void *)1, 1, 0);'; then
add_def HAVE_GETRANDOM
fi
fi
RECVMMSG_CODE='
struct mmsghdr hdr;
return !recvmmsg(0, &hdr, 1, MSG_DONTWAIT, 0);'
if [ $try_recvmmsg = "1" ]; then
if test_code 'recvmmsg()' 'sys/socket.h' '' "$EXTRA_LIBS" "$RECVMMSG_CODE"; then
if test_code 'recvmmsg()' 'sys/socket.h' '' "$LIBS" "$RECVMMSG_CODE"; then
add_def HAVE_RECVMMSG
else
if test_code 'recvmmsg() with _GNU_SOURCE' 'sys/socket.h' '-D_GNU_SOURCE' \
"$EXTRA_LIBS" "$RECVMMSG_CODE"
"$LIBS" "$RECVMMSG_CODE"
then
add_def _GNU_SOURCE
add_def HAVE_RECVMMSG
@@ -657,15 +755,27 @@ if [ $feat_timestamping = "1" ] && [ $try_timestamping = "1" ] &&
then
add_def HAVE_LINUX_TIMESTAMPING
EXTRA_OBJECTS="$EXTRA_OBJECTS hwclock.o ntp_io_linux.o"
if test_code 'other timestamping options' \
'sys/types.h sys/socket.h linux/net_tstamp.h' '' '' '
struct scm_ts_pktinfo pktinfo;
pktinfo.if_index = pktinfo.pkt_length = 0;
return pktinfo.if_index + pktinfo.pkt_length + HWTSTAMP_FILTER_NTP_ALL +
SCM_TIMESTAMPING_PKTINFO +
SOF_TIMESTAMPING_OPT_PKTINFO + SOF_TIMESTAMPING_OPT_TX_SWHW;'; then
add_def HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP 1
add_def HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO 1
add_def HAVE_LINUX_TIMESTAMPING_OPT_TX_SWHW 1
fi
fi
timepps_h=""
if [ $feat_refclock = "1" ] && [ $feat_pps = "1" ]; then
if test_code '<sys/timepps.h>' 'sys/timepps.h' '' '' ''; then
if test_code '<sys/timepps.h>' 'inttypes.h time.h sys/timepps.h' '' '' ''; then
timepps_h="sys/timepps.h"
add_def HAVE_SYS_TIMEPPS_H
else
if test_code '<timepps.h>' 'timepps.h' '' '' ''; then
if test_code '<timepps.h>' 'inttypes.h time.h timepps.h' '' '' ''; then
timepps_h="timepps.h"
add_def HAVE_TIMEPPS_H
fi
@@ -673,10 +783,11 @@ if [ $feat_refclock = "1" ] && [ $feat_pps = "1" ]; then
fi
if [ "x$timepps_h" != "x" ] && \
test_code 'PPSAPI' "string.h $timepps_h" '' '' '
test_code 'PPSAPI' "inttypes.h string.h time.h $timepps_h" '' '' '
pps_handle_t h = 0;
pps_info_t i;
struct timespec ts;
ts.tv_sec = ts.tv_nsec = 0;
return time_pps_fetch(h, PPS_TSFMT_TSPEC, &i, &ts);'
then
add_def FEAT_PPS
@@ -705,10 +816,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
priv_ops="NAME2IPADDRESS"
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
@@ -731,32 +844,43 @@ fi
if [ $feat_refclock = "1" ] && [ $feat_phc = "1" ] && [ $try_phc = "1" ] && \
grep '#define HAVE_CLOCK_GETTIME' config.h > /dev/null && \
test_code '<linux/ptp_clock.h>' 'sys/ioctl.h linux/ptp_clock.h' '' '' \
'ioctl(1, PTP_CLOCK_GETCAPS, 0);'
'ioctl(1, PTP_CLOCK_GETCAPS + PTP_SYS_OFFSET, 0);'
then
grep 'HAVE_LINUX_TIMESTAMPING' config.h > /dev/null ||
EXTRA_OBJECTS="$EXTRA_OBJECTS hwclock.o"
add_def FEAT_PHC
fi
if [ $try_setsched = "1" ] && \
test_code \
'sched_setscheduler()' \
'sched.h' '' '' '
'pthread_setschedparam()' \
'pthread.h sched.h' '-pthread' '' '
struct sched_param sched;
sched_get_priority_max(SCHED_FIFO);
sched_setscheduler(0, SCHED_FIFO, &sched);'
pthread_setschedparam(pthread_self(), SCHED_FIFO, &sched);'
then
add_def HAVE_SCHED_SETSCHEDULER
add_def HAVE_PTHREAD_SETSCHEDPARAM
use_pthread=1
fi
if [ $try_lockmem = "1" ] && \
test_code \
'mlockall()' \
'sys/mman.h sys/resource.h' '' '' '
struct rlimit rlim;
setrlimit(RLIMIT_MEMLOCK, &rlim);
'sys/mman.h' '' '' '
mlockall(MCL_CURRENT|MCL_FUTURE);'
then
add_def HAVE_MLOCKALL
fi
if [ $try_lockmem = "1" ] && \
test_code \
'setrlimit(RLIMIT_MEMLOCK, ...)' \
'sys/resource.h' '' '' '
struct rlimit rlim;
rlim.rlim_max = rlim.rlim_cur = RLIM_INFINITY;
setrlimit(RLIMIT_MEMLOCK, &rlim);'
then
add_def HAVE_SETRLIMIT_MEMLOCK
fi
if [ $feat_forcednsretry = "1" ]
then
@@ -766,37 +890,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
@@ -806,16 +904,59 @@ fi
HASH_OBJ="hash_intmd5.o"
HASH_LINK=""
if [ $feat_sechash = "1" ] && [ $try_nss = "1" ]; then
if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_nettle = "1" ]; then
test_cflags="`pkg_config --cflags nettle`"
test_link="`pkg_config --libs nettle`"
if test_code 'nettle' 'nettle/nettle-meta.h nettle/sha2.h' \
"$test_cflags" "$test_link" \
'return nettle_hashes[0]->context_size;'
then
HASH_OBJ="hash_nettle.o"
HASH_LINK="$test_link"
MYCPPFLAGS="$MYCPPFLAGS $test_cflags"
add_def FEAT_SECHASH
if test_code 'CMAC in nettle' 'nettle/cmac.h' "$test_cflags" "$test_link" \
'cmac128_update((void *)1, (void *)2, (void *)3, 1, (void *)4);'
then
add_def HAVE_CMAC
EXTRA_OBJECTS="$EXTRA_OBJECTS cmac_nettle.o"
EXTRA_CLI_OBJECTS="$EXTRA_CLI_OBJECTS cmac_nettle.o"
fi
fi
fi
if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_gnutls = "1" ]; then
test_cflags="`pkg_config --cflags gnutls`"
test_link="`pkg_config --libs gnutls`"
if test_code 'gnutls' 'gnutls/crypto.h' \
"$test_cflags" "$test_link" '
return gnutls_hash((void *)1, (void *)2, 1);'
then
HASH_OBJ="hash_gnutls.o"
HASH_LINK="$test_link"
MYCPPFLAGS="$MYCPPFLAGS $test_cflags"
add_def FEAT_SECHASH
if test_code 'CMAC in gnutls' 'gnutls/crypto.h' "$test_cflags" "$test_link" \
'return gnutls_hmac_init((void *)1, GNUTLS_MAC_AES_CMAC_128, (void *)2, 0);'
then
add_def HAVE_CMAC
EXTRA_OBJECTS="$EXTRA_OBJECTS cmac_gnutls.o"
EXTRA_CLI_OBJECTS="$EXTRA_CLI_OBJECTS cmac_gnutls.o"
fi
fi
fi
if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_nss = "1" ]; then
test_cflags="`pkg_config --cflags nss`"
test_link="`pkg_config --libs-only-L nss` -lfreebl3"
test_link="`pkg_config --libs-only-L nss` -lfreebl3 -lnssutil3"
if test_code 'NSS' 'nss.h hasht.h nsslowhash.h' \
"$test_cflags" "$test_link" \
'NSSLOWHASH_Begin(NSSLOWHASH_NewContext(NSSLOW_Init(), HASH_AlgSHA512));'
then
HASH_OBJ="hash_nss.o"
HASH_LINK="$test_link"
LIBS="$LIBS $HASH_LINK"
MYCPPFLAGS="$MYCPPFLAGS $test_cflags"
add_def FEAT_SECHASH
fi
@@ -823,16 +964,91 @@ fi
if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_tomcrypt = "1" ]; then
if test_code 'tomcrypt' 'tomcrypt.h' '-I/usr/include/tomcrypt' '-ltomcrypt' \
'hash_memory_multi(find_hash("md5"), NULL, NULL, NULL, 0, NULL, 0);'
'hash_memory_multi(find_hash("md5"), (void *)1, (void *)2, (void *)3, 1, (void *)4, 1);'
then
HASH_OBJ="hash_tomcrypt.o"
HASH_LINK="-ltomcrypt"
LIBS="$LIBS $HASH_LINK"
MYCPPFLAGS="$MYCPPFLAGS -I/usr/include/tomcrypt"
add_def FEAT_SECHASH
fi
fi
EXTRA_OBJECTS="$EXTRA_OBJECTS $HASH_OBJ"
EXTRA_CLI_OBJECTS="$EXTRA_CLI_OBJECTS $HASH_OBJ"
LIBS="$LIBS $HASH_LINK"
if [ $feat_ntp = "1" ] && [ $feat_nts = "1" ] && [ $try_gnutls = "1" ]; then
if [ "$HASH_OBJ" = "hash_gnutls.o" ]; then
test_cflags=""
test_link=""
else
test_cflags="`pkg_config --cflags gnutls`"
test_link="`pkg_config --libs gnutls`"
fi
if test_code 'TLS1.3 in gnutls' 'gnutls/gnutls.h' \
"$test_cflags" "$test_link $LIBS" '
return gnutls_init((void *)1, 0) + GNUTLS_TLS1_3 +
gnutls_priority_init2((void *)1, "", NULL, GNUTLS_PRIORITY_INIT_DEF_APPEND) +
gnutls_prf_rfc5705((void *)1, 0, "", 0, "", 16, (void *)2);'
then
if [ $try_nettle = "1" ] && test_code 'AES-SIV-CMAC in nettle' \
'nettle/siv-cmac.h' "" "$LIBS" \
'siv_cmac_aes128_set_key((void *)1, (void *)2);'
then
EXTRA_OBJECTS="$EXTRA_OBJECTS siv_nettle.o"
add_def HAVE_SIV
add_def HAVE_NETTLE_SIV_CMAC
if [ $try_aes_gcm_siv = "1" ] && test_code 'AES-GCM-SIV in nettle' \
'nettle/siv-gcm.h' "" "$LIBS" \
'siv_gcm_aes128_encrypt_message((void *)1, 0, NULL, 0, (void *)2, 16, (void *)3,
(void *)4);'
then
add_def HAVE_NETTLE_SIV_GCM
fi
else
if test_code 'AES-SIV-CMAC in gnutls' 'gnutls/crypto.h' \
"$test_cflags" "$test_link $LIBS" '
return gnutls_aead_cipher_init((void *)1, GNUTLS_CIPHER_AES_128_SIV, (void *)2);'
then
EXTRA_OBJECTS="$EXTRA_OBJECTS siv_gnutls.o"
add_def HAVE_SIV
if [ $try_aes_gcm_siv = "1" ] && test_code 'AES-GCM-SIV in gnutls' \
'gnutls/crypto.h' "$test_cflags" "$test_link $LIBS" '
return gnutls_aead_cipher_init((void *)1, GNUTLS_CIPHER_AES_128_SIV_GCM,
(void *)2);'
then
add_def HAVE_GNUTLS_SIV_GCM
fi
if test_code 'gnutls_aead_cipher_set_key()' 'gnutls/crypto.h' \
"$test_cflags" "$test_link $LIBS" '
return gnutls_aead_cipher_set_key((void *)1, (void *)2);'
then
add_def HAVE_GNUTLS_AEAD_CIPHER_SET_KEY
fi
else
if test_code 'AES128 in nettle' 'nettle/aes.h' '' "$LIBS" \
'aes128_set_encrypt_key((void *)1, (void *)2);'
then
EXTRA_OBJECTS="$EXTRA_OBJECTS siv_nettle.o"
add_def HAVE_SIV
fi
fi
fi
if grep '#define HAVE_SIV' config.h > /dev/null; then
EXTRA_OBJECTS="$EXTRA_OBJECTS nts_ke_client.o nts_ke_server.o nts_ke_session.o"
EXTRA_OBJECTS="$EXTRA_OBJECTS nts_ntp_auth.o nts_ntp_client.o nts_ntp_server.o"
LIBS="$LIBS $test_link"
MYCPPFLAGS="$MYCPPFLAGS $test_cflags"
add_def FEAT_NTS
fi
fi
fi
if [ $use_pthread = "1" ]; then
MYCFLAGS="$MYCFLAGS -pthread"
fi
SYSCONFDIR=/etc
if [ "x$SETSYSCONFDIR" != "x" ]; then
SYSCONFDIR=$SETSYSCONFDIR
@@ -896,9 +1112,9 @@ add_def DEFAULT_USER "\"$default_user\""
add_def DEFAULT_COMMAND_SOCKET "\"$CHRONYRUNDIR/chronyd.sock\""
add_def MAIL_PROGRAM "\"$mail_program\""
common_features="`get_features IPV6 DEBUG`"
common_features="`get_features SECHASH IPV6 DEBUG`"
chronyc_features="`get_features READLINE`"
chronyd_features="`get_features CMDMON NTP REFCLOCK RTC PRIVDROP SCFILTER SECHASH SIGND ASYNCDNS`"
chronyd_features="`get_features CMDMON NTP REFCLOCK RTC PRIVDROP SCFILTER SIGND ASYNCDNS NTS`"
add_def CHRONYC_FEATURES "\"$chronyc_features $common_features\""
add_def CHRONYD_FEATURES "\"$chronyd_features $common_features\""
echo "Features : $chronyd_features $chronyc_features $common_features"
@@ -914,15 +1130,16 @@ add_def CHRONY_VERSION "\"${CHRONY_VERSION}\""
for f in Makefile doc/Makefile test/unit/Makefile
do
echo Creating $f
sed -e "s%@EXTRA_OBJECTS@%${EXTRA_OBJECTS}%;\
sed -e "s%@EXTRA_OBJS@%${EXTRA_OBJECTS}%;\
s%@EXTRA_CLI_OBJS@%${EXTRA_CLI_OBJECTS}%;\
s%@CC@%${MYCC}%;\
s%@CFLAGS@%${MYCFLAGS}%;\
s%@CPPFLAGS@%${MYCPPFLAGS}%;\
s%@LIBS@%${LIBS}%;\
s%@LDFLAGS@%${MYLDFLAGS}%;\
s%@GETDATE_CFLAGS@%${GETDATE_CFLAGS}%;\
s%@LIBS@%${LIBS}%;\
s%@EXTRA_LIBS@%${EXTRA_LIBS}%;\
s%@EXTRA_CLI_LIBS@%${EXTRA_CLI_LIBS}%;\
s%@HASH_OBJ@%${HASH_OBJ}%;\
s%@SYSCONFDIR@%${SYSCONFDIR}%;\
s%@BINDIR@%${BINDIR}%;\
s%@SBINDIR@%${SBINDIR}%;\

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,8 @@
// This file is part of chrony
//
// Copyright (C) Richard P. Curnow 1997-2003
// Copyright (C) Miroslav Lichvar 2009-2016
// Copyright (C) Stephen Wadeley 2016
// Copyright (C) Miroslav Lichvar 2009-2017, 2019-2023
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of version 2 of the GNU General Public License as
@@ -38,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
@@ -50,7 +51,8 @@ running under a non-root user), it will try to connect to 127.0.0.1 and then
Only the following monitoring commands, which do not affect the behaviour of
*chronyd*, are allowed from the network: *activity*, *manual list*,
*rtcdata*, *smoothing*, *sources*, *sourcestats*, *tracking*, *waitsync*. The
*rtcdata*, *smoothing*, *sourcename*, *sources*, *sourcestats*, *tracking*,
*waitsync*. The
set of hosts from which *chronyd* will accept these commands can be configured
with the <<chrony.conf.adoc#cmdallow,*cmdallow*>> directive in the *chronyd*'s
configuration file or the <<cmdallow,*cmdallow*>> command in *chronyc*. By
@@ -58,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.
@@ -77,11 +77,21 @@ With this option hostnames will be resolved only to IPv6 addresses.
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 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)
format. IP addresses will not be resolved to hostnames, time will be printed as
number of seconds since the epoch and values in seconds will not be converted
to other units.
format. Reverse DNS lookups will be disabled, time will be printed as number of
seconds since the epoch, and values in seconds will not be converted to other
units.
*-e*::
With this option each *chronyc* response will end with a line containing a
single dot.
*-d*::
This option enables printing of debugging messages if *chronyc* was compiled
@@ -93,12 +103,15 @@ With this option multiple commands can be specified. Each argument will be
interpreted as a whole command.
*-h* _host_::
This option allows the user to specify which host (or comma-separated list of
addresses) running the *chronyd* program is to be contacted. This allows for
remote monitoring, without having to connect over SSH to the other host first.
This option specifies the host to be contacted by *chronyc*. It can be
specified with a hostname, IP address, or path to the local Unix domain socket.
Multiple values can be specified as a comma-separated list to provide a
fallback.
+
The default is to contact *chronyd* running on the same host where
*chronyc* is being run.
The default value is _@CHRONYRUNDIR@/chronyd.sock,127.0.0.1,::1_, i.e. the host
where *chronyc* is being run. First, it tries to connect to the Unix domain
socket and if that fails (e.g. due to running under a non-root user), it
will try to connect to 127.0.0.1 and then ::1.
*-p* _port_::
This option allows the user to specify the UDP port number which the target
@@ -111,10 +124,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*
@@ -127,17 +144,17 @@ The *tracking* command displays parameters about the system's clock
performance. An example of the output is shown below.
+
----
Reference ID : CB00710F (foo.example.net)
Reference ID : CB00710F (ntp1.example.net)
Stratum : 3
Ref time (UTC) : Fri Feb 3 15:00:29 2012
System time : 0.000001501 seconds slow of NTP time
Last offset : -0.000001632 seconds
RMS offset : 0.000002360 seconds
Frequency : 331.898 ppm fast
Residual freq : 0.004 ppm
Skew : 0.154 ppm
Root delay : 0.373169 seconds
Root dispersion : 0.024780 seconds
Ref time (UTC) : Fri Jan 27 09:49:17 2017
System time : 0.000006523 seconds slow of NTP time
Last offset : -0.000006747 seconds
RMS offset : 0.000035822 seconds
Frequency : 3.225 ppm slow
Residual freq : -0.000 ppm
Skew : 0.129 ppm
Root delay : 0.013639022 seconds
Root dispersion : 0.001100737 seconds
Update interval : 64.2 seconds
Leap status : Normal
----
@@ -161,23 +178,29 @@ with an IPv4 address.
*Stratum*:::
The stratum indicates how many hops away from a computer with an attached
reference clock we are. Such a computer is a stratum-1 computer, so the
computer in the example is two hops away (i.e. _foo.example.net_ is a
computer in the example is two hops away (i.e. _ntp1.example.net_ is a
stratum-2 and is synchronised from a stratum-1).
*Ref time*:::
This is the time (UTC) at which the last measurement from the reference
source was processed.
*System time*:::
In normal operation, *chronyd* by default never steps the system clock, because
any jump in the time can have adverse consequences for certain application
programs. Instead, any error in the system clock is corrected by slightly
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
on this line is the difference due to this effect.
This is the current offset between the NTP clock and system clock. The NTP
clock is a software (virtual) clock maintained by *chronyd*, which is
synchronised to the configured time sources and provides time to NTP clients.
The system clock is synchronised to the NTP clock. To avoid steps in the
system time, which might have adverse consequences for certain applications,
the system clock is normally corrected only by speeding up or slowing down (up
to the rate configured by the <<chrony.conf.adoc#maxslewrate,*maxslewrate*>>
directive). If the offset is too large, this correction will take a very long
time. A step can be forced by the <<makestep,*makestep*>> command, or the
<<chrony.conf.adoc#makestep,*makestep*>> directive in the configuration file.
+
Note that all other offsets reported by *chronyc* and most offsets in the log
files are relative to the NTP clock, not the system clock.
*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*:::
@@ -186,9 +209,6 @@ The '`frequency`' is the rate by which the system's clock would be wrong if
For example, a value of 1 ppm would mean that when the system's clock thinks it
has advanced 1 second, it has actually advanced by 1.000001 seconds relative to
true time.
+
As you can see in the example, the clock in the computer is not a very
good one; it would gain about 30 seconds per day if it was not corrected!
*Residual freq*:::
This shows the '`residual frequency`' for the currently selected reference
source. This reflects any difference between what the measurements from the
@@ -218,7 +238,7 @@ An absolute bound on the computer's clock accuracy (assuming the stratum-1
computer is correct) is given by:
+
----
clock_error <= root_dispersion + (0.5 * |root_delay|)
clock_error <= |system_time_offset| + root_dispersion + (0.5 * root_delay)
----
*Update interval*:::
This is the interval between the last two clock updates.
@@ -286,20 +306,23 @@ milliseconds.
=== Time sources
[[sources]]*sources* [*-v*]::
[[sources]]*sources* [*-a*] [*-v*]::
This command displays information about the current time sources that *chronyd*
is accessing.
+
The optional argument *-v* can be specified, meaning _verbose_. In this case,
If the *-a* option is specified, all sources are displayed, including those that
do not have a known address yet. Such sources have an identifier in the format
_ID#XXXXXXXXXX_, which can be used in other commands expecting a source address.
+
The *-v* option enables a verbose output. In this case,
extra caption lines are shown as a reminder of the meanings of the columns.
+
----
210 Number of sources = 3
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
#* GPS0 0 4 377 11 -479ns[ -621ns] +/- 134ns
^? foo.example.net 2 6 377 23 -923us[ -924us] +/- 43ms
^+ bar.example.net 1 6 377 21 -2629us[-2619us] +/- 86ms
^? ntp1.example.net 2 6 377 23 -923us[ -924us] +/- 43ms
^+ ntp2.example.net 1 6 377 21 -2629us[-2619us] +/- 86ms
----
+
The columns are as follows:
@@ -308,18 +331,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.
@@ -340,8 +368,9 @@ register has 8 bits and is updated on every received or missed packet from
the source. A value of 377 indicates that a valid reply was received for all
from the last eight transmissions.
*LastRx*:::
This column shows how long ago the last sample was received from the source.
This is normally in seconds. The letters _m_, _h_, _d_ or _y_ indicate
This column shows how long ago the last good sample (which is shown in the next
column) was received from the source. Measurements that failed some tests are
ignored. This is normally in seconds. The letters _m_, _h_, _d_ or _y_ indicate
minutes, hours, days, or years.
*Last sample*:::
This column shows the offset between the local clock and the source at the
@@ -350,25 +379,28 @@ offset. This can be suffixed by _ns_ (indicating nanoseconds), _us_
(indicating microseconds), _ms_ (indicating milliseconds), or _s_ (indicating
seconds). The number to the left of the square brackets shows the original
measurement, adjusted to allow for any slews applied to the local clock
since. The number following the _+/-_ indicator shows the margin of error in
the measurement. Positive offsets indicate that the local clock is ahead of
the source.
since. Positive offsets indicate that the local clock is ahead of the source.
The number following the _+/-_ indicator shows the margin of error in the
measurement (NTP root distance).
[[sourcestats]]*sourcestats* [*-v*]::
[[sourcestats]]*sourcestats* [*-a*] [*-v*]::
The *sourcestats* command displays information about the drift rate and offset
estimation process for each of the sources currently being examined by
*chronyd*.
+
The optional argument *-v* can be specified, meaning _verbose_. In this case,
If the *-a* option is specified, all sources are displayed, including those that
do not have a known address yet. Such sources have an identifier in the format
_ID#XXXXXXXXXX_, which can be used in other commands expecting a source address.
+
The *-v* option enables a verbose output. In this case,
extra caption lines are shown as a reminder of the meanings of the columns.
+
An example report is:
+
----
210 Number of sources = 1
Name/IP Address NP NR Span Frequency Freq Skew Offset Std Dev
===============================================================================
foo.example.net 11 5 46m -0.001 0.045 1us 25us
ntp1.example.net 11 5 46m -0.001 0.045 1us 25us
----
+
The columns are as follows:
@@ -401,6 +433,116 @@ This is the estimated offset of the source.
*Std Dev*:::
This is the estimated sample standard deviation.
[[selectdata]]*selectdata* [*-a*] [*-v*]::
The *selectdata* command displays information specific to the selection of time
sources. If the *-a* option is specified, all sources are displayed, including
those that do not have a known address yet. With the *-v* option, extra caption
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 Leap
=======================================================================
D ntp1.example.net Y ----- --TR- 4 1.0 -61ms +62ms N
* ntp2.example.net N ----- ----- 0 1.0 -6846us +7305us N
+ ntp3.example.net N ----- ----- 10 1.0 -7381us +7355us N
----
+
The columns are as follows:
+
*S*:::
This column indicates the state of the source after the last source selection.
It is similar to the state reported by the *sources* command, but more
states are reported.
{blank}:::
The following states indicate the source is not considered selectable for
synchronisation:
* _N_ - has the *noselect* option.
* _s_ - is not synchronised.
* _M_ - does not have enough measurements.
* _d_ - has a root distance larger than the maximum distance (configured by the
<<chrony.conf.adoc#maxdistance,*maxdistance*>> directive).
* _~_ - has a jitter larger than the maximum jitter (configured by the
<<chrony.conf.adoc#maxjitter,*maxjitter*>> directive).
* _w_ - waits for other sources to get out of the _M_ state.
* _S_ - has older measurements than other sources.
* _O_ - has a stratum equal or larger than the orphan stratum (configured by
the <<chrony.conf.adoc#local,*local*>> directive).
* _T_ - does not fully agree with sources that have the *trust* option.
* _x_ - does not agree with other sources (falseticker).
{blank}:::
The following states indicate the source is considered selectable, but it is
not currently used for synchronisation:
* _W_ - waits for other sources to be selectable (required by the
<<chrony.conf.adoc#minsources,*minsources*>> directive, or
the *require* option of another source).
* _P_ - another selectable source is preferred due to the *prefer* option.
* _U_ - waits for a new measurement (after selecting a different best source).
* _D_ - has, or recently had, a root distance which is too large to be combined
with other sources (configured by the
<<chrony.conf.adoc#combinelimit,*combinelimit*>> directive).
{blank}:::
The following states indicate the source is used for synchronisation of the
local clock:
* _+_ - combined with the best source.
* _*_ - selected as the best source to update the reference data (e.g. root
delay, root dispersion).
*Name/IP address*:::
This column shows the name or IP address of the source if it is an NTP server,
or the reference ID if it is a reference clock.
*Auth*:::
This column indicites whether an authentication mechanism is enabled for the
source. _Y_ means yes and _N_ means no.
*COpts*:::
This column displays the configured selection options of the source.
* _N_ indicates the *noselect* option.
* _P_ indicates the *prefer* option.
* _T_ indicates the *trust* option.
* _R_ indicates the *require* option.
*EOpts*:::
This column displays the current effective selection options of the source,
which can be different from the configured options due to the authentication
selection mode (configured by the
<<chrony.conf.adoc#authselectmode,*authselectmode*>> directive). The symbols
are the same as in the *COpts* column.
*Last*:::
This column displays how long ago was the last measurement of the source made
when the selection was performed.
*Score*:::
This column displays the current score against the source in the _*_ state. The
scoring system avoids frequent reselection when multiple sources have a similar
root distance. A value larger than 1 indicates this source was better than the
_*_ source in recent selections. If the score reaches 10, the best source will
be reselected and the scores will be reset to 1.
*Interval*:::
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).
[[selectopts]]*selectopts* _address|refid_ [_+|-option_]...::
The *selectopts* command modifies the configured selection options of an NTP
source specified by IP address (or the _ID#XXXXXXXXXX_ identifier used for
unknown addresses), or a reference clock specified by reference ID as a string.
+
The selection options can be added with the *+* symbol or removed with the *-*
symbol. The *selectdata* command can be used to verify the configuration. The
modified options will be applied in the next source selection, e.g. when a new
measurement is made, or the *reselect* command is executed.
+
An example of using this command is shown below.
+
----
selectopts 1.2.3.4 -noselect +prefer
selectopts GPS +trust
----
[[reselect]]*reselect*::
To avoid excessive switching between sources, *chronyd* can stay synchronised
to a source even when it is not currently the best one among the available
@@ -441,10 +583,83 @@ the offline state.
the name of the server or peer was not resolved to an address yet; this source is
not visible in the *sources* and *sourcestats* reports.
[[authdata]]*authdata* [*-a*]::
The *authdata* command displays information specific to authentication of NTP
sources. If the *-a* option is specified, all sources are displayed, including
those that do not have a known address yet. An example of the output is
shown below.
+
----
Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen
=========================================================================
ntp1.example.net NTS 1 15 256 135m 0 0 8 100
ntp2.example.net SK 30 13 128 - 0 0 0 0
ntp3.example.net - 0 0 0 - 0 0 0 0
----
+
The columns are as follows:
+
*Name/IP address*:::
This column shows the name or the IP address of the source.
*Mode*:::
This column shows which mechanism authenticates NTP packets received from the
source. _NTS_ means Network Time Security, _SK_ means a symmetric key, and _-_
means authentication is disabled.
*KeyID*:::
This column shows an identifier of the key used for authentication. With a
symmetric key, it is the ID from the <<chrony.conf.adoc#keyfile,key file>>.
With NTS, it is a number starting at zero and incremented by one with each
successful key establishment using the NTS-KE protocol, i.e. it shows how many
times the key establishment was performed with this source.
*Type*:::
This columns shows an identifier of the algorithm used for authentication.
With a symmetric key, it is the hash function or cipher specified in the key
file. With NTS, it is an authenticated encryption with associated data (AEAD)
algorithm, which is negotiated in the NTS-KE protocol. The following values can
be reported:
* 1: MD5
* 2: SHA1
* 3: SHA256
* 4: SHA384
* 5: SHA512
* 6: SHA3-224
* 7: SHA3-256
* 8: SHA3-384
* 9: SHA3-512
* 10: TIGER
* 11: WHIRLPOOL
* 13: AES128
* 14: AES256
* 15: AEAD-AES-SIV-CMAC-256
* 30: AEAD-AES-128-GCM-SIV
*KLen*:::
This column shows the length of the key in bits.
*Last*:::
This column shows how long ago the last successful key establishment was
performed. It is in seconds, or letters _m_, _h_, _d_ or _y_ indicate minutes,
hours, days, or years.
*Atmp*:::
This column shows the number of attempts to perform the key establishment since
the last successful key establishment. A number larger than 1 indicates a
problem with the network or server.
*NAK*:::
This column shows whether an NTS NAK was received since the last request.
A NAK indicates that authentication failed on the server side due to
*chronyd* using a cookie which is no longer valid and that it needs to perform
the key establishment again in order to get new cookies.
*Cook*:::
This column shows the number of NTS cookies that *chronyd* currently has. If
the key establishment was successful, a number smaller than 8 indicates a
problem with the network or server.
*CLen*:::
This column shows the length in bytes of the NTS cookie which will be used in
the next request.
[[ntpdata]]*ntpdata* [_address_]::
The *ntpdata* command displays the last valid measurement and other
NTP-specific information about the specified NTP source, or all NTP sources if
no address was specified. An example of the output is shown below.
NTP-specific information about the specified NTP source, or all NTP sources
(with a known address) if no address was specified. An example of the output is
shown below.
+
----
Remote address : 203.0.113.15 (CB00710F)
@@ -458,7 +673,7 @@ Poll interval : 10 (1024 seconds)
Precision : -24 (0.000000060 seconds)
Root delay : 0.000015 seconds
Root dispersion : 0.000015 seconds
Reference ID : 50505331
Reference ID : 47505300 (GPS)
Reference time : Fri Nov 25 15:22:12 2016
Offset : -0.000060878 seconds
Peer delay : 0.000175634 seconds
@@ -473,6 +688,7 @@ RX timestamping : Kernel
Total TX : 24
Total RX : 24
Total valid RX : 24
Total good RX : 22
----
+
The fields are explained as follows:
@@ -510,7 +726,8 @@ packets sent to the source is more variable than the delay of packets sent
from the source back.
*NTP tests*:::
Results of RFC 5905 tests 1 through 3, 5 through 7, and tests for maximum
delay, delay ratio, delay dev ratio, and synchronisation loop.
delay, delay ratio, delay dev ratio (or delay quantile), and synchronisation
loop.
*Interleaved*:::
This shows if the response was in the interleaved mode.
*Authenticated*:::
@@ -525,38 +742,51 @@ The number of packets sent to the source.
*Total RX*:::
The number of all packets received from the source.
*Total valid RX*:::
The number of valid packets received from the source.
The number of packets which passed the first two groups of NTP tests.
*Total good RX*:::
The number of packets which passed all three groups of NTP tests, i.e. the NTP
measurement was accepted.
[[add_peer]]*add peer* _address_ [_option_]...::
[[add_peer]]*add peer* _name_ [_option_]...::
The *add peer* command allows a new NTP peer to be added whilst
*chronyd* is running.
+
Following the words *add peer*, the syntax of the following
parameters and options is similar to that for the
parameters and options is identical to that for the
<<chrony.conf.adoc#peer,*peer*>> directive in the configuration file.
The following peer options can be set in the command: *port*, *minpoll*,
*maxpoll*, *presend*, *maxdelayratio*, *maxdelay*, *key*.
+
An example of using this command is shown below.
+
----
add peer foo.example.net minpoll 6 maxpoll 10 key 25
add peer ntp1.example.net minpoll 6 maxpoll 10 key 25
----
[[add_server]]*add server* _address_ [_option_]...::
The *add server* command allows a new NTP server to be added whilst
[[add_pool]]*add pool* _name_ [_option_]...::
The *add pool* command allows a pool of NTP servers to be added whilst
*chronyd* is running.
+
Following the words *add server*, the syntax of the following parameters and
options is similar to that for the <<chrony.conf.adoc#server,*server*>>
Following the words *add pool*, the syntax of the following parameters and
options is identical to that for the <<chrony.conf.adoc#pool,*pool*>>
directive in the configuration file.
The following server options can be set in the command: *port*, *minpoll*,
*maxpoll*, *presend*, *maxdelayratio*, *maxdelay*, *key*.
+
An example of using this command is shown below:
+
----
add server foo.example.net minpoll 6 maxpoll 10 key 25
add pool ntp1.example.net maxsources 3 iburst
----
[[add_server]]*add server* _name_ [_option_]...::
The *add server* command allows a new NTP server to be added whilst
*chronyd* is running.
+
Following the words *add server*, the syntax of the following parameters and
options is identical to that for the <<chrony.conf.adoc#server,*server*>>
directive in the configuration file.
+
An example of using this command is shown below:
+
----
add server ntp1.example.net minpoll 6 maxpoll 10 key 25
----
[[delete]]*delete* _address_::
@@ -602,7 +832,7 @@ alternative to the form with mask.
_address_:::
This is an IP address or a hostname. The burst command is applied only to
that source.
::
{blank}::
+
If no _mask_ or _masked-address_ arguments are provided, every source will be
matched.
@@ -632,7 +862,7 @@ IPv6 addresses have first 48 bits equal to _2001:db8:789a_.
Example of the three-argument form of the command is:
+
----
burst 2/10 foo.example.net
burst 2/10 ntp1.example.net
----
[[maxdelay]]*maxdelay* _address_ _delay_::
@@ -689,7 +919,8 @@ the loaded periods. The *offline* and *online* commands can be used to achieve
this.
+
There are four forms of the *offline* command. The first form is a wildcard,
meaning all sources. The second form allows an IP address mask and a masked
meaning all sources (including sources that do not have a known address yet).
The second form allows an IP address mask and a masked
address to be specified. The third form uses CIDR notation. The fourth form
uses an IP address or a hostname. These forms are illustrated below.
+
@@ -697,7 +928,7 @@ uses an IP address or a hostname. These forms are illustrated below.
offline
offline 255.255.255.0/1.2.3.0
offline 2001:db8:789a::/48
offline foo.example.net
offline ntp1.example.net
----
+
The second form means that the *offline* command is to be applied to any source
@@ -724,6 +955,14 @@ particular source or sources has been restored.
+
The syntax is identical to that of the <<offline,*offline*>> command.
[[onoffline]]
*onoffline*::
The *onoffline* command tells *chronyd* to switch all sources that have a known
address to the online or
offline status according to the current network configuration. A source is
considered online if it is possible to send requests to it, i.e. a network
route to the source is present.
[[polltarget]]*polltarget* _address_ _polltarget_::
The *polltarget* command is used to modify the poll target for one of the
current set of sources. It is equivalent to the *polltarget* option in the
@@ -731,12 +970,31 @@ current set of sources. It is equivalent to the *polltarget* option in the
[[refresh]]*refresh*::
The *refresh* command can be used to force *chronyd* to resolve the names of
configured sources to IP addresses again, e.g. after suspending and resuming
the machine in a different network.
configured NTP sources to IP addresses again and replace any addresses missing
in the list of resolved addresses.
+
Sources that stop responding will be replaced with newly resolved addresses
automatically after 8 polling intervals, but this command can still be useful
to replace them immediately and not wait until they are marked as unreachable.
Sources that stop responding are replaced with newly resolved addresses
automatically after 8 polling intervals. This command can be used to replace
them immediately, e.g. after suspending and resuming the machine in a different
network.
+
Note that with pools which have more than 16 addresses, or not all IPv4 or IPv6
addresses are included in a single DNS response (e.g. pool.ntp.org), this
command might replace the addresses even if they are still in the pool.
[[reload]]*reload* *sources*::
The *reload sources* command causes *chronyd* to re-read all _*.sources_ files
from the directories specified by the
<<chrony.conf.adoc#sourcedir,*sourcedir*>> directive.
[[sourcename]]*sourcename* _address_::
The *sourcename* command prints the original hostname or address that was
specified for an NTP source in the configuration file, or the *add* command.
This command is an alternative to the *-N* option, which can be useful in
scripts.
+
Note that different NTP sources can share the same name, e.g. servers from a
pool.
=== Manual time input
@@ -774,7 +1032,7 @@ The columns are as as follows:
. The regression residual at this point, in seconds. This allows '`outliers`'
to be easily spotted, so that they can be deleted using the *manual delete*
command.
::
{blank}::
+
The *delete* form of the command deletes a single sample. The parameter is the
index of the sample, as shown in the first column of the output from *manual
@@ -836,7 +1094,7 @@ particular host.
Examples of use, showing a named host and a numeric IP address, are as follows:
+
----
accheck foo.example.net
accheck ntp1.example.net
accheck 1.2.3.4
accheck 2001:db8::1
----
@@ -845,10 +1103,17 @@ This command can be used to examine the effect of a series of *allow*, *allow
all*, *deny*, and *deny all* commands specified either via *chronyc*, or in
*chronyd*'s configuration file.
[[clients]]*clients*::
[[clients]]*clients* [*-p* _packets_] [*-k*] [*-r*]::
This command shows a list of clients that have accessed the server, through
either the NTP or command ports. It does not include accesses over
the Unix domain command socket. There are no arguments.
the NTP, command, or NTS-KE port. It does not include accesses over the Unix
domain command socket.
+
The *-p* option specifies the minimum number of received NTP or command
packets, or accepted NTS-KE connections, needed to include a client in the
list. The default value is 0, i.e. all clients are reported. With the *-k*
option the last four columns will show the NTS-KE accesses instead of command
accesses. If the *-r* option is specified, *chronyd* will reset the counters of
received and dropped packets or connections after reporting the current values.
+
An example of the output is:
+
@@ -856,7 +1121,7 @@ An example of the output is:
Hostname NTP Drop Int IntL Last Cmd Drop Int Last
===============================================================================
localhost 2 0 2 - 133 15 0 -1 7
foo.example.net 12 0 6 - 23 0 0 - -
ntp1.example.net 12 0 6 - 23 0 0 - -
----
+
Each row shows the data for a single host. Only hosts that have passed the host
@@ -873,20 +1138,18 @@ The columns are as follows:
. The average interval between NTP packets.
. The average interval between NTP packets after limiting the response rate.
. Time since the last NTP packet was received
. The number of command packets received from the client.
. The number of command packets dropped to limit the response rate.
. The average interval between command packets.
. Time since the last command packet was received.
. The number of command packets or NTS-KE connections received/accepted from
the client.
. The number of command packets or NTS-KE connections dropped to limit the
response rate.
. The average interval between command packets or NTS-KE connections.
. Time since the last command packet or NTS-KE connection was
received/accepted.
[[serverstats]]*serverstats*::
The *serverstats* command displays how many valid NTP and command requests
*chronyd* as a server received from clients, how many of them were dropped to
limit the response rate as configured by the
<<chrony.conf.adoc#ratelimit,*ratelimit*>> and
<<chrony.conf.adoc#cmdratelimit,*cmdratelimit*>> directives, and how many
client log records were dropped due to the memory limit configured by the
<<chrony.conf.adoc#clientloglimit,*clientloglimit*>> directive. An example of
the output is shown below.
The *serverstats* command displays NTP and command server statistics.
+
An example of the output is shown below.
+
----
NTP packets received : 1598
@@ -894,7 +1157,70 @@ NTP packets dropped : 8
Command packets received : 19
Command packets dropped : 0
Client log records dropped : 0
NTS-KE connections accepted: 3
NTS-KE connections dropped : 0
Authenticated NTP packets : 189
Interleaved NTP packets : 43
NTP timestamps held : 44
NTP timestamp span : 120
NTP daemon RX timestamps : 0
NTP daemon TX timestamps : 1537
NTP kernel RX timestamps : 1590
NTP kernel TX timestamps : 43
NTP hardware RX timestamps : 0
NTP hardware TX timestamps : 0
----
+
The fields have the following meaning:
+
*NTP packets received*:::
The number of valid NTP requests received by the server.
*NTP packets dropped*:::
The number of NTP requests dropped by the server due to rate limiting
(configured by the <<chrony.conf.adoc#ratelimit,*ratelimit*>> directive).
*Command packets received*:::
The number of command requests received by the server.
*Command packets dropped*:::
The number of command requests dropped by the server due to rate limiting
(configured by the <<chrony.conf.adoc#cmdratelimit,*cmdratelimit*>> directive).
*Client log records dropped*:::
The number of client log records dropped by the server to limit the memory use
(configured by the <<chrony.conf.adoc#clientloglimit,*clientloglimit*>>
directive).
*NTS-KE connections accepted*:::
The number of NTS-KE connections accepted by the server.
*NTS-KE connections dropped*:::
The number of NTS-KE connections dropped by the server due to rate limiting
(configured by the <<chrony.conf.adoc#ntsratelimit,*ntsratelimit*>> directive).
*Authenticated NTP packets*:::
The number of received NTP requests that were authenticated (with a symmetric
key or NTS).
*Interleaved NTP packets*:::
The number of received NTP requests that were detected to be in the interleaved
mode.
*NTP timestamps held*:::
The number of pairs of receive and transmit timestamps that the server is
currently holding in memory for clients using the interleaved mode.
*NTP timestamp span*:::
The interval (in seconds) covered by the currently held NTP timestamps.
*NTP daemon RX timestamps*:::
The number of NTP responses which included a receive timestamp captured by the
daemon.
*NTP daemon TX timestamps*:::
The number of NTP responses which included a transmit timestamp captured by the
daemon.
*NTP kernel RX timestamps*:::
The number of NTP responses which included a receive timestamp captured by the
kernel.
*NTP kernel TX timestamps*:::
The number of NTP responses (in the interleaved mode) which included a transmit
timestamp captured by the kernel.
*NTP hardware RX timestamps*:::
The number of NTP responses which included a receive timestamp captured by the
NIC.
*NTP hardware TX timestamps*:::
The number of NTP responses (in the interleaved mode) which included a transmit
timestamp captured by the NIC.
[[allow]]*allow* [*all*] [_subnet_]::
The effect of the allow command is identical to the
@@ -903,11 +1229,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
@@ -922,11 +1245,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
@@ -939,8 +1259,8 @@ deny all
*local* *off*::
The *local* command allows *chronyd* to be told that it is to appear as a
reference source, even if it is not itself properly synchronised to an external
source. (This can be used on isolated networks, to allow one computer to be a
master time server with the other computers slaving to it.)
source. This can be used on isolated networks, to allow a computer to be the
primary time server for other computers.
+
The first form enables the local reference mode on the host. The syntax is
identical to the <<chrony.conf.adoc#local,*local*>> directive in the
@@ -1001,7 +1321,7 @@ used to check whether monitoring access is permitted from a named host.
Examples of use are as follows:
+
----
cmdaccheck foo.example.net
cmdaccheck ntp1.example.net
cmdaccheck 1.2.3.4
cmdaccheck 2001:db8::1
----
@@ -1079,7 +1399,7 @@ more than 1 second away from the system clock):
error).
. Save the RTC parameters to the RTC file (specified with the
<<chrony.conf.adoc#rtcfile,*rtcfile*>> directive in the configuration file).
::
{blank}::
+
The last step is done as a precaution against the computer suffering a power
failure before either the daemon exits or the <<writertc,*writertc*>> command
@@ -1112,25 +1432,38 @@ 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*::
The *dump* command causes *chronyd* to write its current history of
measurements for each of its sources to dump files, either for inspection or to
support the *-r* option when *chronyd* is restarted.
+
The *dump* command is somewhat equivalent to the
<<chrony.conf.adoc#dumponexit,*dumponexit*>> directive in the configuration
file.
+
To use the *dump* command, you might want to configure the name of the
directory into which the dump files will be written. This can only be
done in the configuration file with the <<chrony.conf.adoc#dumpdir,*dumpdir*>>
directive.
measurements for each of its sources to dump files in the directory specified
in the configuration file by the <<chrony.conf.adoc#dumpdir,*dumpdir*>>
directive and also write server NTS keys and client NTS cookies to the
directory specified by the <<chrony.conf.adoc#ntsdumpdir1,*ntsdumpdir*>>
directive. Note that *chronyd* does this automatically when it exits. This
command is mainly useful for inspection whilst *chronyd* is running.
[[rekey]]*rekey*::
The *rekey* command causes *chronyd* to re-read the key file specified in the
configuration file by the <<chrony.conf.adoc#keyfile,*keyfile*>> directive. It
also re-reads the server NTS keys if
<<chrony.conf.adoc#ntsdumpdir2,*ntsdumpdir*>> is specified and
<<chrony.conf.adoc#ntsrotate,automatic rotation>> is disabled in the
configuration file.
[[reset]]*reset* *sources*::
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). *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
the process the SIGTERM signal.
=== Client commands
@@ -1180,10 +1513,10 @@ generated from the _/dev/urandom_ device and it is printed to standard output.
+
The command has three optional arguments. The first argument is the key number
(by default 1), which will be specified with the *key* option of the *server*
or *peer* directives in the configuration file. The second argument is the hash
function (by default SHA1 or MD5 if SHA1 is not available) and the third
argument is the number of bits the key should have, between 80 and 4096 bits
(by default 160 bits).
or *peer* directives in the configuration file. The second argument is the name
of the hash function or cipher (by default SHA1, or MD5 if SHA1 is not
available). The third argument is the length of the key in bits if a hash
function was selected, between 80 and 4096 bits (by default 160 bits).
+
An example is:
+
@@ -1193,7 +1526,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*::
@@ -1209,7 +1548,7 @@ The *help* command displays a summary of the commands and their arguments.
== BUGS
For instructions on how to report bugs, please visit
https://chrony.tuxfamily.org/.
https://chrony-project.org/.
== AUTHORS

View File

@@ -1,7 +1,7 @@
// This file is part of chrony
//
// Copyright (C) Richard P. Curnow 1997-2003
// Copyright (C) Miroslav Lichvar 2009-2016
// Copyright (C) Miroslav Lichvar 2009-2017
//
// 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
@@ -41,7 +41,7 @@ If no configuration directives are specified on the command line, *chronyd*
will read them from a configuration file. The compiled-in default location of
the file is _@SYSCONFDIR@/chrony.conf_.
Information messages and warnings will be logged to syslog.
Informational messages, warnings, and errors will be logged to syslog.
== OPTIONS
@@ -55,35 +55,54 @@ IPv6 sockets will be created.
*-f* _file_::
This option can be used to specify an alternate location for the configuration
file (default _@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.
*-d*::
When run in this mode, the program will not detach itself from the terminal,
and all messages will be sent to the terminal instead of to syslog. When
*chronyd* was compiled with debugging support, this option can be used twice to
print also debugging messages.
and all messages will be written to the terminal instead of syslog. If
*chronyd* was compiled with enabled support for debugging, this option can be
used twice to enable debug messages.
*-l* _file_::
This option enables writing of log messages to a file instead of syslog or the
terminal.
*-L* _level_::
This option specifies the minimum severity level of messages to be written to
the log file, syslog, or terminal. The following levels can be specified: -1
(debug, if compiled with enabled support for debugging), 0 (informational), 1
(warning), 2 (non-fatal error), and 3 (fatal error). The default value is 0.
*-p*::
When run in this mode, *chronyd* will print the configuration and exit. It will
not detach from the terminal. This option can be used to verify the syntax of
the configuration and get the whole configuration, even if it is split into
multiple files and read by the *include* or *confdir* directive.
*-q*::
When run in this mode, *chronyd* will set the system clock once and exit. It
will not detach from the terminal.
*-Q*::
This option is similar to *-q*, but it will only print the offset without any
corrections of the clock.
This option is similar to the *-q* option, except it only prints the offset
without making any corrections of the clock and disables server ports to allow
*chronyd* to be started without root privileges, assuming the configuration
does not have any directives which would require them (e.g. *refclock*,
*hwtimestamp*, *rtcfile*, etc).
*-r*::
This option will try to reload and then delete files containing sample
histories for each of the servers and reference clocks being used. These
histories are created by using the <<chronyc.adoc#dump,*dump*>> command in
*chronyc*, or by setting the <<chrony.conf.adoc#dumponexit,*dumponexit*>>
histories for each of the servers and reference clocks being used. The
files are expected to be in the directory specified by the
<<chrony.conf.adoc#dumpdir,*dumpdir*>>
directive in the configuration file. This option is useful if you want to stop
and restart *chronyd* briefly for any reason, e.g. to install a new version.
However, it should be used only on systems where the kernel can maintain clock
compensation whilst not under *chronyd*'s control (i.e. Linux, FreeBSD, NetBSD
and Solaris).
compensation whilst not under *chronyd*'s control (i.e. Linux, FreeBSD, NetBSD,
illumos, and macOS 10.13 or later).
*-R*::
When this option is used, the <<chrony.conf.adoc#initstepslew,*initstepslew*>>
@@ -120,40 +139,84 @@ 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 (default _@DEFAULT_USER@_).
<<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.
On macOS, FreeBSD, NetBSD and Solaris *chronyd* forks into two processes.
On macOS, FreeBSD, NetBSD, and illumos *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
process is killed when a forbidden system call is made, in level -1 the SYSSIG
signal is thrown instead and in level 0 the filter is disabled (default 0).
This option configures system call filters loaded by *chronyd* processes if it
was compiled with support for the Linux secure computing (seccomp) facility.
Three levels are defined: 0, 1, 2. The filters are disabled at level 0. At
levels 1 and 2, *chronyd* will be killed if it makes a system call which is
blocked by the filters. The level can be specified as a negative number to
trigger the SIGSYS signal instead of SIGKILL, which can be useful for
debugging. The default value is 0.
+
It's recommended to enable the filter only when it's 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. If the filter is missing some system call, *chronyd* could be
killed even in normal operation.
At level 1, the filters allow only selected system calls that are normally
expected to be made by *chronyd*. Other system calls are blocked. This level is
recommended only if it is known to work on the version of the system where
*chrony* is installed. The filters need to allow also system calls made by
libraries that *chronyd* is using (e.g. libc), but different versions or
implementations of the libraries might make different system calls. If the
filters are missing a system call, *chronyd* could be killed even in normal
operation.
+
At level 2, the filters block only a small number of specific system calls
(e.g. fork and exec). This approach should avoid false positives, but the
protection of the system against a compromised *chronyd* process is much more
limited.
+
The filters cannot be enabled with the *mailonchange* directive.
*-P* _priority_::
On Linux, this option will select the SCHED_FIFO real-time scheduler at the
specified priority (which must be between 0 and 100). On macOS, this option
must have either a value of 0 (the default) to disable the thread time
constraint policy or 1 for the policy to be enabled. Other systems do not
support this option.
On Linux, FreeBSD, NetBSD, and illumos this option will select the SCHED_FIFO
real-time scheduler at the specified priority (which must be between 0 and
100). On macOS, this option must have either a value of 0 to disable the thread
time constraint policy or 1 for the policy to be enabled. Other systems do not
support this option. The default value is 0.
*-m*::
This option will lock *chronyd* into RAM so that it will never be paged out.
This mode is only supported on Linux.
This mode is only supported on Linux, FreeBSD, NetBSD, and illumos.
*-v*::
*-x*::
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 be started without the capability to adjust or set
the system clock (e.g. in some containers) to operate as an NTP server.
*-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.
== ENVIRONMENT VARIABLES
*LISTEN_FDS*::
On Linux systems, the systemd service manager may pass file descriptors for
pre-initialised sockets to *chronyd*. The service manager allocates and binds
the file descriptors, and passes a copy to each spawned instance of the
service. This allows for zero-downtime service restarts as the sockets buffer
client requests until the service is able to handle them. The service manager
sets the LISTEN_FDS environment variable to the number of passed file
descriptors.
== FILES
_@SYSCONFDIR@/chrony.conf_
@@ -165,7 +228,7 @@ _@SYSCONFDIR@/chrony.conf_
== BUGS
For instructions on how to report bugs, please visit
https://chrony.tuxfamily.org/.
https://chrony-project.org/.
== AUTHORS

File diff suppressed because it is too large Load Diff

View File

@@ -22,6 +22,26 @@ The software is distributed as source code which has to be compiled. The source
code is supplied in the form of a gzipped tar file, which unpacks to a
subdirectory identifying the name and version of the program.
A C compiler (e.g. `gcc` or `clang`) and GNU Make are needed to build `chrony`.
The following libraries with their development files, and programs, are needed
to enable optional features:
* pkg-config: detection of development libraries
* Nettle, GnuTLS, NSS, or LibTomCrypt: secure hash functions (`SECHASH`)
* libcap: dropping root privileges on Linux (`DROPROOT`)
* libseccomp: system call filter on Linux (`SCFILTER`)
* GnuTLS and Nettle: Network Time Security (`NTS`)
* Editline: line editing in `chronyc` (`READLINE`)
* timepps.h header: PPS reference clock
* Asciidoctor: documentation in HTML format
* Bash: test suite
The following programs are needed when building `chrony` from the git
repository instead of a released tar file:
* Asciidoctor: manual pages
* Bison: parser for chronyc settime command
After unpacking the source code, change directory into it, and type
----
@@ -29,8 +49,8 @@ After unpacking the source code, change directory into it, and type
----
This is a shell script that automatically determines the system type. There is
a single optional parameter, `--prefix` which indicates the directory tree
where the software should be installed. For example,
an optional parameter `--prefix`, which indicates the directory tree where the
software should be installed. For example,
----
./configure --prefix=/opt/free
@@ -40,11 +60,11 @@ will install the `chronyd` daemon into `/opt/free/sbin` and the `chronyc`
control program into `/opt/free/bin`. The default value for the prefix is
`/usr/local`.
The configure script assumes you want to use gcc as your compiler. If you want
to use a different compiler, you can configure this way:
The `configure` script assumes you want to use `gcc` as your compiler. If you
want to use a different compiler, you can configure this way:
----
CC=cc CFLAGS=-O ./configure --prefix=/opt/free
CC=cc ./configure --prefix=/opt/free
----
for Bourne-family shells, or
@@ -63,11 +83,26 @@ shown. Otherwise, `Makefile` will be generated.
On Linux, if development files for the libcap library are available, `chronyd`
will be built with support for dropping root privileges. On other systems no
extra library is needed. The default user which `chronyd` should run as can be
specified with the `--with-user` option of the configure script.
specified with the `--with-user` option of the `configure` script.
If development files for the editline or readline library are available,
If development files for the POSIX threads library are available, `chronyd`
will be built with support for asynchronous resolving of hostnames specified in
the `server`, `peer`, and `pool` directives. This allows `chronyd` operating as
a server to respond to client requests when resolving a hostname. If you don't
want to enable the support, specify the `--disable-asyncdns` flag to
`configure`.
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
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 library are available,
`chronyc` will be built with line editing support. If you don't want this,
specify the `--disable-readline` flag to configure.
specify the `--disable-readline` flag to `configure`.
If a `timepps.h` header is available (e.g. from the
http://linuxpps.org[LinuxPPS project]), `chronyd` will be built with PPS API
@@ -75,6 +110,9 @@ reference clock driver. If the header is installed in a location that isn't
normally searched by the compiler, you can add it to the searched locations by
setting the `CPPFLAGS` variable to `-I/path/to/timepps`.
The `--help` option can be specified to `configure` to print all options
supported by the script.
Now type
----
@@ -122,51 +160,24 @@ unprivileged user for `chronyd` and specify it with the `-u` command-line
option or the `user` directive in the configuration file, or set the default
user with the `--with-user` configure option before building.
== Support for line editing libraries
== Support for system call filtering
`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.
`chronyd` can be built with support for the Linux secure computing (seccomp)
facility. This requires development files for the
https://github.com/seccomp/libseccomp[libseccomp] library and the
`--enable-scfilter` option specified to `configure`. The `-F` option of
`chronyd` will enable a system call filter, which should significantly reduce
the kernel attack surface and possibly prevent kernel exploits from `chronyd`
if it is compromised.
== Extra options for package builders
The configure and make procedures have some extra options that may be useful if
you are building a distribution package for chrony.
The `configure` and `make` procedures have some extra options that may be
useful if you are building a distribution package for `chrony`.
The `--mandir=DIR` option to configure specifies an install directory for the
man pages. This overrides the `man` subdirectory of the argument to the
--prefix option.
The `--mandir=DIR` option to `configure` specifies an installation directory
for the man pages. This overrides the `man` subdirectory of the argument to the
`--prefix` option.
----
./configure --prefix=/usr --mandir=/usr/share/man
@@ -174,8 +185,8 @@ man pages. This overrides the `man` subdirectory of the argument to the
to set both options together.
The final option is the `DESTDIR` option to the make command. For example, you
could use the commands
The final option is the `DESTDIR` option to the `make` command. For example,
you could use the commands
----
./configure --prefix=/usr --mandir=/usr/share/man

View File

@@ -1,5 +1,6 @@
[Unit]
Description=Wait for chrony to synchronize system clock
Documentation=man:chronyc(1)
After=chronyd.service
Requires=chronyd.service
Before=time-sync.target
@@ -7,11 +8,39 @@ 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
CapabilityBoundingSet=
DevicePolicy=closed
DynamicUser=yes
IPAddressAllow=localhost
IPAddressDeny=any
LockPersonality=yes
MemoryDenyWriteExecute=yes
PrivateDevices=yes
PrivateUsers=yes
ProtectClock=yes
ProtectControlGroups=yes
ProtectHome=yes
ProtectHostname=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectProc=invisible
ProtectSystem=strict
RestrictAddressFamilies=AF_INET AF_INET6
RestrictNamespaces=yes
RestrictRealtime=yes
SystemCallArchitectures=native
SystemCallFilter=@system-service
SystemCallFilter=~@privileged @resources
UMask=0777
[Install]
WantedBy=multi-user.target

View File

@@ -4,8 +4,8 @@ pool pool.ntp.org iburst
# Record the rate at which the system clock gains/losses time.
driftfile /var/lib/chrony/drift
# In first three updates step the system clock instead of slew
# if the adjustment is larger than 1 second.
# Allow the system clock to be stepped in the first three updates
# if its offset is larger than 1 second.
makestep 1.0 3
# Enable kernel synchronization of the real-time clock (RTC).

View File

@@ -1,26 +1,45 @@
# 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.
driftfile /var/lib/chrony/drift
# In first three updates step the system clock instead of slew
# if the adjustment is larger than 1 second.
# Allow the system clock to be stepped in the first three updates
# if its offset is larger than 1 second.
makestep 1.0 3
# Enable kernel synchronization of the real-time clock (RTC).
rtcsync
# Allow NTP client access from local network.
#allow 192.168/16
# Enable hardware timestamping on all interfaces that support it.
#hwtimestamp *
# Serve time even if not synchronized to any NTP server.
# Increase the minimum number of selectable sources required to adjust
# the system clock.
#minsources 2
# Allow NTP client access from local network.
#allow 192.168.0.0/16
# Serve time even if not synchronized to a time source.
#local stratum 10
# Require authentication (nts or key option) for all NTP sources.
#authselectmode require
# Specify file containing keys for NTP authentication.
#keyfile /etc/chrony.keys
# Save NTS keys and cookies.
ntsdumpdir /var/lib/chrony
# Insert/delete leap seconds by slewing instead of stepping.
#leapsecmode slew
# Get TAI-UTC offset and leap seconds from the system tz database.
#leapsectz right/UTC
# Specify directory for log files.
logdir /var/log/chrony

View File

@@ -27,48 +27,50 @@
# you can access at http://support.ntp.org/bin/view/Servers/WebHome or
# you can use servers from the pool.ntp.org project.
! server foo.example.net iburst
! server bar.example.net iburst
! server baz.example.net iburst
! server ntp1.example.net iburst
! server ntp2.example.net iburst
! server ntp3.example.net iburst
! pool pool.ntp.org iburst
# However, for dial-up use you probably want these instead. The word
# 'offline' means that the server is not visible at boot time. Use
# chronyc's 'online' command to tell chronyd that these servers have
# become visible after you go on-line.
! server foo.example.net offline
! server bar.example.net offline
! server baz.example.net offline
! pool pool.ntp.org offline
# You may want to specify NTP 'peers' instead. If you run a network
# with a lot of computers and want several computers running chrony to
# have the 'front-line' interface to the public NTP servers, you can
# 'peer' these machines together to increase robustness.
! peer foo.example.net
# There are other options to the 'server' and 'peer' directives that you
# might want to use. For example, you can ignore measurements whose
# round-trip-time is too large (indicating that the measurement is
# probably useless, because you don't know which way the measurement
# message got held up.) Consult the full documentation for details.
#######################################################################
### AVOIDING POTENTIALLY BOGUS CHANGES TO YOUR CLOCK
#
# To avoid changes being made to your computer's gain/loss compensation
# when the measurement history is too erratic, you might want to enable
# one of the following lines. The first seems good for dial-up (or
# other high-latency connections like slow leased lines), the second
# seems OK for a LAN environment.
# one of the following lines. The first seems good with servers on the
# Internet, the second seems OK for a LAN environment.
! maxupdateskew 100
! maxupdateskew 5
# If you want to increase the minimum number of selectable sources
# required to update the system clock in order to make the
# synchronisation more reliable, uncomment (and edit) the following
# line.
! minsources 2
# If your computer has a good stable clock (e.g. it is not a virtual
# machine), you might also want to reduce the maximum assumed drift
# (frequency error) of the clock (the value is specified in ppm).
! maxdrift 100
# By default, chronyd allows synchronisation to an unauthenticated NTP
# source (i.e. specified without the nts and key options) if it agrees with
# a majority of authenticated NTP sources, or if no authenticated source is
# specified. If you don't want chronyd to ever synchronise to an
# unauthenticated NTP source, uncomment the first from the following lines.
# If you don't want to synchronise to an unauthenticated NTP source only
# when an authenticated source is specified, uncomment the second line.
# If you want chronyd to ignore authentication in the source selection,
# uncomment the third line.
! authselectmode require
! authselectmode prefer
! authselectmode ignore
#######################################################################
### FILENAMES ETC
# Chrony likes to keep information about your computer's clock in files.
@@ -84,22 +86,37 @@ driftfile /var/lib/chrony/drift
! keyfile /etc/chrony.keys
# If you specify an NTP server with the nts option to enable authentication
# with the Network Time Security (NTS) mechanism, or enable server NTS with
# the ntsservercert and ntsserverkey directives below, the following line will
# allow the client/server to save the NTS keys and cookies in order to reduce
# the number of key establishments (NTS-KE sessions).
ntsdumpdir /var/lib/chrony
# If chronyd is configured to act as an NTP server and you want to enable NTS
# for its clients, you will need a TLS certificate and private key. Uncomment
# and edit the following lines to specify the locations of the certificate and
# key.
! ntsservercert /etc/.../nts-server.crt
! ntsserverkey /etc/.../nts-server.key
# chronyd can save the measurement history for the servers to files when
# it it exits. This is useful in 2 situations:
# it exits. This is useful in 2 situations:
#
# 1. On Linux, if you stop chronyd and restart it with '-r' (e.g. after
# 1. If you stop chronyd and restart it with the '-r' option (e.g. after
# an upgrade), the old measurements will still be relevant when chronyd
# is restarted. This will reduce the time needed to get accurate
# gain/loss measurements, especially with a dial-up link.
# gain/loss measurements.
#
# 2. Again on Linux, if you use the RTC support and start chronyd with
# 2. On Linux, if you use the RTC support and start chronyd with
# '-r -s' on bootup, measurements from the last boot will still be
# useful (the real time clock is used to 'flywheel' chronyd between
# boots).
#
# Enable these two options to use this.
# Uncomment the following line to use this.
! dumponexit
! dumpdir /var/lib/chrony
# chronyd writes its process ID to a file. If you try to start a second
@@ -107,7 +124,13 @@ driftfile /var/lib/chrony/drift
# still running and bail out. If you want to change the path to the PID
# file, uncomment this line and edit it. The default path is shown.
! pidfile /var/run/chronyd.pid
! pidfile /var/run/chrony/chronyd.pid
# If the system timezone database is kept up to date and includes the
# right/UTC timezone, chronyd can use it to determine the current
# TAI-UTC offset and when will the next leap second occur.
! leapsectz right/UTC
#######################################################################
### INITIAL CLOCK CORRECTION
@@ -122,6 +145,18 @@ driftfile /var/lib/chrony/drift
! makestep 1.0 3
#######################################################################
### LEAP SECONDS
# A leap second is an occasional one-second correction of the UTC
# time scale. By default, chronyd tells the kernel to insert/delete
# the leap second, which makes a backward/forward step to correct the
# clock for it. As with the makestep directive, this jump can upset
# some applications. If you prefer chronyd to make a gradual
# correction, causing the clock to be off for a longer time, uncomment
# the following line.
! leapsecmode slew
#######################################################################
### LOGGING
# If you want to log information about the time measurements chronyd has
@@ -141,8 +176,6 @@ driftfile /var/lib/chrony/drift
#######################################################################
### ACTING AS AN NTP SERVER
# You might want the computer to be an NTP server for other computers.
# e.g. you might be running chronyd on a dial-up machine that has a LAN
# sitting behind it with several 'satellite' computers on it.
#
# By default, chronyd does not allow any clients to access it. You need
# to explicitly enable access using 'allow' and 'deny' directives.
@@ -158,15 +191,6 @@ driftfile /var/lib/chrony/drift
# You can have as many allow and deny directives as you need. The order
# is unimportant.
# If you want chronyd to act as an NTP broadcast server, enable and edit
# (and maybe copy) the following line. This means that a broadcast
# packet is sent to the address 192.168.1.255 every 60 seconds. The
# address MUST correspond to the broadcast address of one of the network
# interfaces on your machine. If you have multiple network interfaces,
# add a broadcast line for each.
! broadcast 60 192.168.1.255
# If you want to present your computer's time for others to synchronise
# with, even if you don't seem to be synchronised to any NTP servers
# yourself, enable the following line. The value 10 may be varied
@@ -181,13 +205,12 @@ driftfile /var/lib/chrony/drift
# machine accesses it. The information can be accessed by the 'clients'
# command of chronyc. You can disable this facility by uncommenting the
# following line. This will save a bit of memory if you have many
# clients.
# clients and it will also disable support for the interleaved mode.
! noclientlog
# The clientlog size is limited to 512KB by default. If you have many
# clients, especially in many different subnets, you might want to
# increase the limit.
# clients, you might want to increase the limit.
! clientloglimit 4194304
@@ -196,7 +219,7 @@ driftfile /var/lib/chrony/drift
# clients that are sending requests too frequently, uncomment and edit
# the following line.
! limitrate interval 3 burst 8
! ratelimit interval 3 burst 8
#######################################################################
### REPORTING BIG CLOCK CHANGES
@@ -215,7 +238,7 @@ driftfile /var/lib/chrony/drift
# several people, you need to set up a mailing list or sendmail alias
# for them and use the address of that.)
! mailonchange wibble@foo.example.net 0.5
! mailonchange wibble@example.net 0.5
#######################################################################
### COMMAND ACCESS
@@ -243,7 +266,17 @@ driftfile /var/lib/chrony/drift
# Rate limiting can be enabled also for command packets. (Note,
# commands from localhost are never limited.)
! cmdratelimit interval 1 burst 16
! cmdratelimit interval -4 burst 16
#######################################################################
### HARDWARE TIMESTAMPING
# On Linux, if the network interface controller and its driver support
# hardware timestamping, it can significantly improve the accuracy of
# synchronisation. It can be enabled on specified interfaces only, or it
# can be enabled on all interfaces that support it.
! hwtimestamp eth0
! hwtimestamp *
#######################################################################
### REAL TIME CLOCK
@@ -274,6 +307,12 @@ driftfile /var/lib/chrony/drift
! rtcdevice /dev/misc/rtc
# Alternatively, if not using the -s option, this directive can be used
# to enable a mode in which the RTC is periodically set to the system
# time, with no tracking of its drift.
! rtcsync
#######################################################################
### REAL TIME SCHEDULER
# This directive tells chronyd to use the real-time FIFO scheduler with the

View File

@@ -1,6 +1,7 @@
# This is an example chrony keys file. It is used for NTP authentication with
# symmetric keys. It should be readable only by root or the user to which
# chronyd is configured to switch to after start.
# This is an example chrony keys file. It enables authentication of NTP
# packets with symmetric keys when its location is specified by the keyfile
# directive in chrony.conf(5). It should be readable only by root and the
# user under which chronyd is running.
#
# Don't use the example keys! It's recommended to generate random keys using
# the chronyc keygen command.
@@ -10,3 +11,5 @@
#1 MD5 AVeryLongAndRandomPassword
#2 MD5 HEX:12114855C7931009B4049EF3EFC48A139C3F989F
#3 SHA1 HEX:B2159C05D6A219673A3B7E896B6DE07F6A440995
#4 AES128 HEX:2DA837C4B6573748CA692B8C828E4891
#5 AES256 HEX:2666B8099BFF2D5BA20876121788ED24D2BE59111B8FFB562F0F56AE6EC7246E

View File

@@ -1,17 +0,0 @@
#!/bin/sh
# This is a NetworkManager dispatcher script for chronyd to set its NTP sources
# online/offline when a default route is configured/removed on the system.
export LC_ALL=C
if [ "$2" = "up" ]; then
/sbin/ip route list dev "$1" | grep -q '^default' &&
/usr/bin/chronyc online > /dev/null 2>&1
fi
if [ "$2" = "down" ]; then
/sbin/ip route list | grep -q '^default' ||
/usr/bin/chronyc offline > /dev/null 2>&1
fi
exit 0

View File

@@ -0,0 +1,49 @@
#!/bin/sh
# This is a NetworkManager dispatcher script for chronyd to update
# its NTP sources with servers from DHCP options passed by NetworkManager
# in the DHCP4_NTP_SERVERS and DHCP6_DHCP6_NTP_SERVERS environment variables.
export LC_ALL=C
interface=$1
action=$2
chronyc=/usr/bin/chronyc
server_options=iburst
server_dir=/var/run/chrony-dhcp
dhcp_server_file=$server_dir/$interface.sources
dhcp_ntp_servers="$DHCP4_NTP_SERVERS $DHCP6_DHCP6_NTP_SERVERS"
add_servers_from_dhcp() {
rm -f "$dhcp_server_file"
for server in $dhcp_ntp_servers; do
# Check for invalid characters (from the DHCPv6 NTP FQDN suboption)
len1=$(printf '%s' "$server" | wc -c)
len2=$(printf '%s' "$server" | tr -d -c 'A-Za-z0-9:.-' | wc -c)
if [ "$len1" -ne "$len2" ] || [ "$len2" -lt 1 ] || [ "$len2" -gt 255 ]; then
continue
fi
printf 'server %s %s\n' "$server" "$server_options" >> "$dhcp_server_file"
done
$chronyc reload sources > /dev/null 2>&1 || :
}
clear_servers_from_dhcp() {
if [ -f "$dhcp_server_file" ]; then
rm -f "$dhcp_server_file"
$chronyc reload sources > /dev/null 2>&1 || :
fi
}
mkdir -p $server_dir
case "$action" in
up|dhcp4-change|dhcp6-change)
add_servers_from_dhcp;;
down)
clear_servers_from_dhcp;;
esac
exit 0

View File

@@ -0,0 +1,29 @@
#!/bin/sh
# This is a NetworkManager dispatcher / networkd-dispatcher script for
# chronyd to set its NTP sources online or offline when a network interface
# is configured or removed
export LC_ALL=C
chronyc=/usr/bin/chronyc
# For NetworkManager consider only selected events
if [ $# -ge 2 ]; then
case "$2" in
up|down|connectivity-change)
;;
dhcp4-change|dhcp6-change)
# Actions "up" and "connectivity-change" in some cases do not
# guarantee that the interface has a route (e.g. a bond).
# dhcp(x)-change handles at least cases that use DHCP.
;;
*)
exit 0;;
esac
fi
# Note: for networkd-dispatcher routable.d ~= on and off.d ~= off
$chronyc onoffline > /dev/null 2>&1
exit 0

View File

@@ -1,46 +0,0 @@
%global chrony_version @@VERSION@@
%if 0%(echo %{chrony_version} | grep -q pre && echo 1)
%global prerelease %(echo %{chrony_version} | sed 's/.*-//')
%endif
Summary: An NTP client/server
Name: chrony
Version: %(echo %{chrony_version} | sed 's/-.*//')
Release: %{!?prerelease:1}%{?prerelease:0.1.%{prerelease}}
Source: chrony-%{version}%{?prerelease:-%{prerelease}}.tar.gz
License: GPLv2
Group: Applications/Utilities
BuildRoot: %{_tmppath}/%{name}-%{version}-root-%(id -u -n)
%description
chrony is a client and server for the Network Time Protocol (NTP).
This program keeps your computer's clock accurate. It was specially
designed to support systems with intermittent Internet connections,
but it also works well in permanently connected environments. It can
also use hardware reference clocks, the system real-time clock, or
manual input as time references.
%prep
%setup -q -n %{name}-%{version}%{?prerelease:-%{prerelease}}
%build
./configure \
--prefix=%{_prefix} \
--bindir=%{_bindir} \
--sbindir=%{_sbindir} \
--mandir=%{_mandir}
make
%install
rm -rf $RPM_BUILD_ROOT
make install DESTDIR=$RPM_BUILD_ROOT
%files
%{_sbindir}/chronyd
%{_bindir}/chronyc
%{_mandir}/man1/chronyc.1.gz
%{_mandir}/man5/chrony.conf.5.gz
%{_mandir}/man8/chronyd.8.gz
%doc README FAQ NEWS COPYING
%doc examples/chrony.conf.example*
%doc examples/chrony.keys.example

View File

@@ -0,0 +1,58 @@
# This is a more restricted version of the chronyd service intended for
# minimal NTP/NTS client configurations. The daemon is started without root
# privileges and is allowed to write only to its own runtime, state, and log
# directories. It cannot bind to privileged ports in order to operate as an
# NTP server, or provide monitoring access over IPv4/IPv6. It cannot use
# reference clocks, HW timestamping, RTC tracking, and other features.
[Unit]
Description=NTP client (restricted)
Documentation=man:chronyd(8) man:chrony.conf(5)
After=chronyd.service ntpdate.service sntp.service ntpd.service
Conflicts=chronyd.service ntpd.service systemd-timesyncd.service
ConditionCapability=CAP_SYS_TIME
[Service]
Type=forking
PIDFile=/run/chrony/chronyd.pid
EnvironmentFile=-/etc/sysconfig/chronyd
ExecStart=/usr/sbin/chronyd -U $OPTIONS
User=chrony
LogsDirectory=chrony
LogsDirectoryMode=0750
RuntimeDirectory=chrony
RuntimeDirectoryMode=0750
RuntimeDirectoryPreserve=restart
StateDirectory=chrony
StateDirectoryMode=0750
AmbientCapabilities=CAP_SYS_TIME
CapabilityBoundingSet=CAP_SYS_TIME
DevicePolicy=closed
LockPersonality=yes
MemoryDenyWriteExecute=yes
NoNewPrivileges=yes
PrivateDevices=yes
PrivateTmp=yes
# This breaks adjtimex()
#PrivateUsers=yes
ProtectControlGroups=yes
ProtectHome=yes
ProtectHostname=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectProc=invisible
ProtectSystem=strict
RemoveIPC=yes
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictNamespaces=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
SystemCallArchitectures=native
SystemCallFilter=~@cpu-emulation @debug @module @mount @obsolete @raw-io
SystemCallFilter=~@reboot @resources @swap
UMask=0077
[Install]
WantedBy=multi-user.target

View File

@@ -1,13 +1,48 @@
[Unit]
Description=NTP client/server
Documentation=man:chronyd(8) man:chrony.conf(5)
After=ntpdate.service sntp.service ntpd.service
Conflicts=ntpd.service systemd-timesyncd.service
ConditionCapability=CAP_SYS_TIME
[Service]
Type=forking
PIDFile=/var/run/chronyd.pid
PIDFile=/run/chrony/chronyd.pid
EnvironmentFile=-/etc/sysconfig/chronyd
ExecStart=/usr/sbin/chronyd $OPTIONS
CapabilityBoundingSet=~CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_AUDIT_WRITE
CapabilityBoundingSet=~CAP_BLOCK_SUSPEND CAP_KILL CAP_LEASE CAP_LINUX_IMMUTABLE
CapabilityBoundingSet=~CAP_MAC_ADMIN CAP_MAC_OVERRIDE CAP_MKNOD CAP_SYS_ADMIN
CapabilityBoundingSet=~CAP_SYS_BOOT CAP_SYS_CHROOT CAP_SYS_MODULE CAP_SYS_PACCT
CapabilityBoundingSet=~CAP_SYS_PTRACE CAP_SYS_RAWIO CAP_SYS_TTY_CONFIG CAP_WAKE_ALARM
DeviceAllow=char-pps rw
DeviceAllow=char-ptp rw
DeviceAllow=char-rtc rw
DevicePolicy=closed
LockPersonality=yes
MemoryDenyWriteExecute=yes
NoNewPrivileges=yes
PrivateTmp=yes
ProtectControlGroups=yes
ProtectHome=yes
ProtectHostname=yes
ProtectKernelLogs=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectProc=invisible
ProtectSystem=strict
ReadWritePaths=/run /var/lib/chrony -/var/log
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictNamespaces=yes
RestrictSUIDSGID=yes
SystemCallArchitectures=native
SystemCallFilter=~@cpu-emulation @debug @module @mount @obsolete @raw-io @reboot @swap
# Adjust restrictions for /usr/sbin/sendmail (mailonchange directive)
NoNewPrivileges=no
ReadWritePaths=-/var/spool
RestrictAddressFamilies=AF_NETLINK
[Install]
WantedBy=multi-user.target

View File

@@ -448,9 +448,9 @@ o_merid : /* NULL */
the same signature as the function definition does. */
#include "getdate.h"
extern struct tm *gmtime ();
extern struct tm *localtime ();
extern time_t mktime ();
extern struct tm *gmtime (const time_t *timep);
extern struct tm *localtime (const time_t *timep);
extern time_t mktime (struct tm *tm);
/* Month and day table. */
static TABLE const MonthDayTable[] = {
@@ -641,16 +641,13 @@ static TABLE const MilitaryTable[] = {
/* ARGSUSED */
static int
yyerror (s)
char *s ATTRIBUTE_UNUSED;
yyerror (char *s ATTRIBUTE_UNUSED)
{
return 0;
}
static int
ToHour (Hours, Meridian)
int Hours;
MERIDIAN Meridian;
ToHour (int Hours, MERIDIAN Meridian)
{
switch (Meridian)
{
@@ -677,8 +674,7 @@ ToHour (Hours, Meridian)
}
static int
ToYear (Year)
int Year;
ToYear (int Year)
{
if (Year < 0)
Year = -Year;
@@ -694,8 +690,7 @@ ToYear (Year)
}
static int
LookupWord (buff)
char *buff;
LookupWord (char *buff)
{
register char *p;
register char *q;

24
hash.h
View File

@@ -31,12 +31,26 @@
/* length of hash values produced by SHA512 */
#define MAX_HASH_LENGTH 64
extern int HSH_GetHashId(const char *name);
typedef enum {
HSH_INVALID = 0,
HSH_MD5 = 1,
HSH_SHA1 = 2,
HSH_SHA256 = 3,
HSH_SHA384 = 4,
HSH_SHA512 = 5,
HSH_SHA3_224 = 6,
HSH_SHA3_256 = 7,
HSH_SHA3_384 = 8,
HSH_SHA3_512 = 9,
HSH_TIGER = 10,
HSH_WHIRLPOOL = 11,
HSH_MD5_NONCRYPTO = 10000, /* For NTPv4 reference ID */
} HSH_Algorithm;
extern unsigned int HSH_Hash(int id,
const unsigned char *in1, unsigned int in1_len,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len);
extern int HSH_GetHashId(HSH_Algorithm algorithm);
extern int HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
unsigned char *out, int out_len);
extern void HSH_Finalise(void);

145
hash_gnutls.c Normal file
View File

@@ -0,0 +1,145 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2021
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Crypto hashing using the GnuTLS library
*/
#include "config.h"
#include "sysincl.h"
#include <gnutls/crypto.h>
#include "hash.h"
#include "logging.h"
struct hash {
const HSH_Algorithm algorithm;
const gnutls_digest_algorithm_t type;
gnutls_hash_hd_t handle;
};
static struct hash hashes[] = {
{ HSH_MD5_NONCRYPTO, GNUTLS_DIG_MD5, NULL },
{ HSH_MD5, GNUTLS_DIG_MD5, NULL },
{ HSH_SHA1, GNUTLS_DIG_SHA1, NULL },
{ HSH_SHA256, GNUTLS_DIG_SHA256, NULL },
{ HSH_SHA384, GNUTLS_DIG_SHA384, NULL },
{ HSH_SHA512, GNUTLS_DIG_SHA512, NULL },
{ HSH_SHA3_224, GNUTLS_DIG_SHA3_224, NULL },
{ HSH_SHA3_256, GNUTLS_DIG_SHA3_256, NULL },
{ HSH_SHA3_384, GNUTLS_DIG_SHA3_384, NULL },
{ HSH_SHA3_512, GNUTLS_DIG_SHA3_512, NULL },
{ 0, 0, NULL }
};
static int gnutls_initialised = 0;
int
HSH_GetHashId(HSH_Algorithm algorithm)
{
int id, r;
if (!gnutls_initialised) {
r = gnutls_global_init();
if (r < 0)
LOG_FATAL("Could not initialise %s : %s", "gnutls", gnutls_strerror(r));
gnutls_initialised = 1;
}
for (id = 0; hashes[id].algorithm != 0; id++) {
if (hashes[id].algorithm == algorithm)
break;
}
if (hashes[id].algorithm == 0)
return -1;
if (hashes[id].handle)
return id;
if (algorithm == HSH_MD5_NONCRYPTO)
GNUTLS_FIPS140_SET_LAX_MODE();
r = gnutls_hash_init(&hashes[id].handle, hashes[id].type);
if (algorithm == HSH_MD5_NONCRYPTO)
GNUTLS_FIPS140_SET_STRICT_MODE();
if (r < 0) {
DEBUG_LOG("Could not initialise %s : %s", "hash", gnutls_strerror(r));
hashes[id].handle = NULL;
return -1;
}
return id;
}
int
HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
unsigned char *out, int out_len)
{
unsigned char buf[MAX_HASH_LENGTH];
gnutls_hash_hd_t handle;
int hash_len;
if (in1_len < 0 || in2_len < 0 || out_len < 0)
return 0;
handle = hashes[id].handle;
hash_len = gnutls_hash_get_len(hashes[id].type);
if (out_len > hash_len)
out_len = hash_len;
if (hash_len > sizeof (buf))
return 0;
if (gnutls_hash(handle, in1, in1_len) < 0 ||
(in2 && gnutls_hash(handle, in2, in2_len) < 0)) {
/* Reset the state */
gnutls_hash_output(handle, buf);
return 0;
}
gnutls_hash_output(handle, buf);
memcpy(out, buf, out_len);
return out_len;
}
void
HSH_Finalise(void)
{
int i;
if (!gnutls_initialised)
return;
for (i = 0; hashes[i].algorithm != 0; i++) {
if (hashes[i].handle)
gnutls_hash_deinit(hashes[i].handle, NULL);
}
gnutls_global_deinit();
}

View File

@@ -29,27 +29,27 @@
#include "sysincl.h"
#include "hash.h"
#include "memory.h"
#include "util.h"
#include "md5.c"
static MD5_CTX ctx;
int
HSH_GetHashId(const char *name)
HSH_GetHashId(HSH_Algorithm algorithm)
{
/* only MD5 is supported */
if (strcmp(name, "MD5"))
if (algorithm != HSH_MD5 && algorithm != HSH_MD5_NONCRYPTO)
return -1;
return 0;
}
unsigned int
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len)
int
HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
unsigned char *out, int out_len)
{
if (out_len < 16)
if (in1_len < 0 || in2_len < 0 || out_len < 0)
return 0;
MD5Init(&ctx);
@@ -58,9 +58,11 @@ HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
MD5Update(&ctx, in2, in2_len);
MD5Final(&ctx);
memcpy(out, ctx.digest, 16);
out_len = MIN(out_len, 16);
return 16;
memcpy(out, ctx.digest, out_len);
return out_len;
}
void

124
hash_nettle.c Normal file
View File

@@ -0,0 +1,124 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2018
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Routines implementing crypto hashing using the nettle library.
*/
#include "config.h"
#include "sysincl.h"
#include <nettle/nettle-meta.h>
#include "hash.h"
#include "memory.h"
struct hash {
const HSH_Algorithm algorithm;
const char *int_name;
const struct nettle_hash *nettle_hash;
void *context;
};
static struct hash hashes[] = {
{ HSH_MD5, "md5", NULL, NULL },
{ HSH_SHA1, "sha1", NULL, NULL },
{ HSH_SHA256, "sha256", NULL, NULL },
{ HSH_SHA384, "sha384", NULL, NULL },
{ HSH_SHA512, "sha512", NULL, NULL },
{ HSH_SHA3_224, "sha3_224", NULL, NULL },
{ HSH_SHA3_256, "sha3_256", NULL, NULL },
{ HSH_SHA3_384, "sha3_384", NULL, NULL },
{ HSH_SHA3_512, "sha3_512", NULL, NULL },
{ 0, NULL, NULL, NULL }
};
int
HSH_GetHashId(HSH_Algorithm algorithm)
{
int id, nid;
if (algorithm == HSH_MD5_NONCRYPTO)
algorithm = HSH_MD5;
for (id = 0; hashes[id].algorithm != 0; id++) {
if (hashes[id].algorithm == algorithm)
break;
}
if (hashes[id].algorithm == 0)
return -1;
if (hashes[id].context)
return id;
for (nid = 0; nettle_hashes[nid]; nid++) {
if (!strcmp(hashes[id].int_name, nettle_hashes[nid]->name))
break;
}
if (!nettle_hashes[nid] || !nettle_hashes[nid]->context_size || !nettle_hashes[nid]->init)
return -1;
hashes[id].nettle_hash = nettle_hashes[nid];
hashes[id].context = Malloc(hashes[id].nettle_hash->context_size);
return id;
}
int
HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
unsigned char *out, int out_len)
{
const struct nettle_hash *hash;
void *context;
if (in1_len < 0 || in2_len < 0 || out_len < 0)
return 0;
hash = hashes[id].nettle_hash;
context = hashes[id].context;
if (out_len > hash->digest_size)
out_len = hash->digest_size;
hash->init(context);
hash->update(context, in1_len, in1);
if (in2)
hash->update(context, in2_len, in2);
hash->digest(context, out_len, out);
return out_len;
}
void
HSH_Finalise(void)
{
int i;
for (i = 0; hashes[i].algorithm != 0; i++) {
if (hashes[i].context)
Free(hashes[i].context);
}
}

View File

@@ -32,35 +32,39 @@
#include <nsslowhash.h>
#include "hash.h"
#include "util.h"
static NSSLOWInitContext *ictx;
struct hash {
HASH_HashType type;
const char *name;
HSH_Algorithm algorithm;
NSSLOWHASHContext *context;
};
static struct hash hashes[] = {
{ HASH_AlgMD5, "MD5", NULL },
{ HASH_AlgSHA1, "SHA1", NULL },
{ HASH_AlgSHA256, "SHA256", NULL },
{ HASH_AlgSHA384, "SHA384", NULL },
{ HASH_AlgSHA512, "SHA512", NULL },
{ 0, NULL, NULL }
{ HASH_AlgMD5, HSH_MD5, NULL },
{ HASH_AlgSHA1, HSH_SHA1, NULL },
{ HASH_AlgSHA256, HSH_SHA256, NULL },
{ HASH_AlgSHA384, HSH_SHA384, NULL },
{ HASH_AlgSHA512, HSH_SHA512, NULL },
{ 0, 0, NULL }
};
int
HSH_GetHashId(const char *name)
HSH_GetHashId(HSH_Algorithm algorithm)
{
int i;
for (i = 0; hashes[i].name; i++) {
if (!strcmp(name, hashes[i].name))
if (algorithm == HSH_MD5_NONCRYPTO)
algorithm = HSH_MD5;
for (i = 0; hashes[i].algorithm != 0; i++) {
if (hashes[i].algorithm == algorithm)
break;
}
if (!hashes[i].name)
if (hashes[i].algorithm == 0)
return -1; /* not found */
if (!ictx && !(ictx = NSSLOW_Init()))
@@ -73,18 +77,24 @@ HSH_GetHashId(const char *name)
return i;
}
unsigned int
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len)
int
HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
unsigned char *out, int out_len)
{
unsigned int ret;
unsigned char buf[MAX_HASH_LENGTH];
unsigned int ret = 0;
if (in1_len < 0 || in2_len < 0 || out_len < 0)
return 0;
NSSLOWHASH_Begin(hashes[id].context);
NSSLOWHASH_Update(hashes[id].context, in1, in1_len);
if (in2)
NSSLOWHASH_Update(hashes[id].context, in2, in2_len);
NSSLOWHASH_End(hashes[id].context, out, &ret, out_len);
NSSLOWHASH_End(hashes[id].context, buf, &ret, sizeof (buf));
ret = MIN(ret, out_len);
memcpy(out, buf, ret);
return ret;
}
@@ -94,7 +104,7 @@ HSH_Finalise(void)
{
int i;
for (i = 0; hashes[i].name; i++) {
for (i = 0; hashes[i].algorithm != 0; i++) {
if (hashes[i].context)
NSSLOWHASH_Destroy(hashes[i].context);
}

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2012
* Copyright (C) Miroslav Lichvar 2012, 2018
*
* 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
@@ -29,59 +29,57 @@
#include "config.h"
#include "hash.h"
#include "util.h"
struct hash {
const char *name;
HSH_Algorithm algorithm;
const char *int_name;
const struct ltc_hash_descriptor *desc;
};
static const struct hash hashes[] = {
{ "MD5", "md5", &md5_desc },
#ifdef LTC_RIPEMD128
{ "RMD128", "rmd128", &rmd128_desc },
#endif
#ifdef LTC_RIPEMD160
{ "RMD160", "rmd160", &rmd160_desc },
#endif
#ifdef LTC_RIPEMD256
{ "RMD256", "rmd256", &rmd256_desc },
#endif
#ifdef LTC_RIPEMD320
{ "RMD320", "rmd320", &rmd320_desc },
#endif
{ HSH_MD5, "md5", &md5_desc },
#ifdef LTC_SHA1
{ "SHA1", "sha1", &sha1_desc },
{ HSH_SHA1, "sha1", &sha1_desc },
#endif
#ifdef LTC_SHA256
{ "SHA256", "sha256", &sha256_desc },
{ HSH_SHA256, "sha256", &sha256_desc },
#endif
#ifdef LTC_SHA384
{ "SHA384", "sha384", &sha384_desc },
{ HSH_SHA384, "sha384", &sha384_desc },
#endif
#ifdef LTC_SHA512
{ "SHA512", "sha512", &sha512_desc },
{ HSH_SHA512, "sha512", &sha512_desc },
#endif
#ifdef LTC_SHA3
{ HSH_SHA3_224, "sha3-224", &sha3_224_desc },
{ HSH_SHA3_256, "sha3-256", &sha3_256_desc },
{ HSH_SHA3_384, "sha3-384", &sha3_384_desc },
{ HSH_SHA3_512, "sha3-512", &sha3_512_desc },
#endif
#ifdef LTC_TIGER
{ "TIGER", "tiger", &tiger_desc },
{ HSH_TIGER, "tiger", &tiger_desc },
#endif
#ifdef LTC_WHIRLPOOL
{ "WHIRLPOOL", "whirlpool", &whirlpool_desc },
{ HSH_WHIRLPOOL, "whirlpool", &whirlpool_desc },
#endif
{ NULL, NULL, NULL }
{ 0, NULL, NULL }
};
int
HSH_GetHashId(const char *name)
HSH_GetHashId(HSH_Algorithm algorithm)
{
int i, h;
for (i = 0; hashes[i].name; i++) {
if (!strcmp(name, hashes[i].name))
if (algorithm == HSH_MD5_NONCRYPTO)
algorithm = HSH_MD5;
for (i = 0; hashes[i].algorithm != 0; i++) {
if (hashes[i].algorithm == algorithm)
break;
}
if (!hashes[i].name)
if (hashes[i].algorithm == 0)
return -1; /* not found */
h = find_hash(hashes[i].int_name);
@@ -94,24 +92,31 @@ HSH_GetHashId(const char *name)
return find_hash(hashes[i].int_name);
}
unsigned int
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len)
int
HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
unsigned char *out, int out_len)
{
unsigned char buf[MAX_HASH_LENGTH];
unsigned long len;
int r;
len = out_len;
if (in1_len < 0 || in2_len < 0 || out_len < 0)
return 0;
len = sizeof (buf);
if (in2)
r = hash_memory_multi(id, out, &len,
in1, (unsigned long)in1_len, in2, (unsigned long)in2_len, NULL, 0);
r = hash_memory_multi(id, buf, &len,
in1, (unsigned long)in1_len,
in2, (unsigned long)in2_len, NULL, 0);
else
r = hash_memory(id, in1, in1_len, out, &len);
r = hash_memory(id, in1, in1_len, buf, &len);
if (r != CRYPT_OK)
return 0;
len = MIN(len, out_len);
memcpy(out, buf, len);
return len;
}

194
hwclock.c
View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2016
* Copyright (C) Miroslav Lichvar 2016-2018, 2022
*
* 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
@@ -33,14 +33,23 @@
#include "local.h"
#include "logging.h"
#include "memory.h"
#include "quantiles.h"
#include "regress.h"
#include "util.h"
/* Maximum number of samples per clock */
#define MAX_SAMPLES 16
/* Minimum and maximum number of samples per clock */
#define MIN_SAMPLES 2
#define MAX_SAMPLES 64
/* Minimum interval between samples (in seconds) */
#define MIN_SAMPLE_SEPARATION 1.0
/* Maximum acceptable frequency offset of the clock */
#define MAX_FREQ_OFFSET (2.0 / 3.0)
/* Quantiles for filtering readings by delay */
#define DELAY_QUANT_MIN_K 1
#define DELAY_QUANT_MAX_K 2
#define DELAY_QUANT_Q 10
#define DELAY_QUANT_REPEAT 7
#define DELAY_QUANT_MIN_STEP 1.0e-9
struct HCL_Instance_Record {
/* HW and local reference timestamp */
@@ -49,18 +58,32 @@ struct HCL_Instance_Record {
/* Samples stored as intervals (uncorrected for frequency error)
relative to local_ref and hw_ref */
double x_data[MAX_SAMPLES];
double y_data[MAX_SAMPLES];
double *x_data;
double *y_data;
/* Number of samples */
/* Minimum, maximum and current number of samples */
int min_samples;
int max_samples;
int n_samples;
/* Maximum error of the last sample */
double last_err;
/* Minimum interval between samples */
double min_separation;
/* Expected precision of readings */
double precision;
/* Flag indicating the offset and frequency values are valid */
int valid_coefs;
/* Estimated offset and frequency of HW clock relative to local clock */
double offset;
double frequency;
/* Estimated quantiles of reading delay */
QNT_Instance delay_quants;
};
/* ================================================== */
@@ -83,15 +106,28 @@ handle_slew(struct timespec *raw, struct timespec *cooked, double dfreq,
/* ================================================== */
HCL_Instance
HCL_CreateInstance(void)
HCL_CreateInstance(int min_samples, int max_samples, double min_separation, double precision)
{
HCL_Instance clock;
min_samples = CLAMP(MIN_SAMPLES, min_samples, MAX_SAMPLES);
max_samples = CLAMP(MIN_SAMPLES, max_samples, MAX_SAMPLES);
max_samples = MAX(min_samples, max_samples);
clock = MallocNew(struct HCL_Instance_Record);
clock->x_data[MAX_SAMPLES - 1] = 0.0;
clock->y_data[MAX_SAMPLES - 1] = 0.0;
clock->x_data = MallocArray(double, max_samples);
clock->y_data = MallocArray(double, max_samples);
clock->x_data[max_samples - 1] = 0.0;
clock->y_data[max_samples - 1] = 0.0;
clock->min_samples = min_samples;
clock->max_samples = max_samples;
clock->n_samples = 0;
clock->valid_coefs = 0;
clock->min_separation = min_separation;
clock->precision = precision;
clock->delay_quants = QNT_CreateInstance(DELAY_QUANT_MIN_K, DELAY_QUANT_MAX_K,
DELAY_QUANT_Q, DELAY_QUANT_REPEAT,
DELAY_QUANT_MIN_STEP);
LCL_AddParameterChangeHandler(handle_slew, clock);
@@ -103,6 +139,9 @@ HCL_CreateInstance(void)
void HCL_DestroyInstance(HCL_Instance clock)
{
LCL_RemoveParameterChangeHandler(handle_slew, clock);
QNT_DestroyInstance(clock->delay_quants);
Free(clock->y_data);
Free(clock->x_data);
Free(clock);
}
@@ -112,7 +151,7 @@ int
HCL_NeedsNewSample(HCL_Instance clock, struct timespec *now)
{
if (!clock->n_samples ||
fabs(UTI_DiffTimespecsToDouble(now, &clock->local_ref)) >= MIN_SAMPLE_SEPARATION)
fabs(UTI_DiffTimespecsToDouble(now, &clock->local_ref)) >= clock->min_separation)
return 1;
return 0;
@@ -120,6 +159,94 @@ HCL_NeedsNewSample(HCL_Instance clock, struct timespec *now)
/* ================================================== */
int
HCL_ProcessReadings(HCL_Instance clock, int n_readings, struct timespec tss[][3],
struct timespec *hw_ts, struct timespec *local_ts, double *err)
{
double delay, raw_delay, min_delay, low_delay, high_delay, e, pred_err;
double delay_sum, hw_sum, local_sum, local_prec, freq;
int i, min_reading, combined;
struct timespec ts1, ts2;
if (n_readings < 1)
return 0;
/* Work out the current correction multiplier needed to get cooked delays */
LCL_CookTime(&tss[0][0], &ts1, NULL);
LCL_CookTime(&tss[n_readings - 1][2], &ts2, NULL);
if (UTI_CompareTimespecs(&tss[0][0], &tss[n_readings - 1][2]) < 0)
freq = UTI_DiffTimespecsToDouble(&ts1, &ts2) /
UTI_DiffTimespecsToDouble(&tss[0][0], &tss[n_readings - 1][2]);
else
freq = 1.0;
for (i = 0; i < n_readings; i++) {
delay = freq * UTI_DiffTimespecsToDouble(&tss[i][2], &tss[i][0]);
if (delay < 0.0) {
/* Step in the middle of a reading? */
DEBUG_LOG("Bad reading delay=%e", delay);
return 0;
}
if (i == 0 || min_delay > delay) {
min_delay = delay;
min_reading = i;
}
QNT_Accumulate(clock->delay_quants, delay);
}
local_prec = LCL_GetSysPrecisionAsQuantum();
low_delay = QNT_GetQuantile(clock->delay_quants, DELAY_QUANT_MIN_K);
high_delay = QNT_GetQuantile(clock->delay_quants, DELAY_QUANT_MAX_K);
low_delay = MIN(low_delay, high_delay);
high_delay = MAX(high_delay, low_delay + local_prec);
/* Combine readings with delay in the expected interval */
for (i = combined = 0, delay_sum = hw_sum = local_sum = 0.0; i < n_readings; i++) {
raw_delay = UTI_DiffTimespecsToDouble(&tss[i][2], &tss[i][0]);
delay = freq * raw_delay;
if (delay < low_delay || delay > high_delay)
continue;
delay_sum += delay;
hw_sum += UTI_DiffTimespecsToDouble(&tss[i][1], &tss[0][1]);
local_sum += UTI_DiffTimespecsToDouble(&tss[i][0], &tss[0][0]) + raw_delay / 2.0;
combined++;
}
DEBUG_LOG("Combined %d readings lo=%e hi=%e", combined, low_delay, high_delay);
if (combined > 0) {
UTI_AddDoubleToTimespec(&tss[0][1], hw_sum / combined, hw_ts);
UTI_AddDoubleToTimespec(&tss[0][0], local_sum / combined, local_ts);
*err = MAX(delay_sum / combined / 2.0, clock->precision);
return 1;
}
/* Accept the reading with minimum delay if its interval does not contain
the current offset predicted from previous samples */
*hw_ts = tss[min_reading][1];
UTI_AddDoubleToTimespec(&tss[min_reading][0], min_delay / freq / 2.0, local_ts);
*err = MAX(min_delay / 2.0, clock->precision);
pred_err = 0.0;
LCL_CookTime(local_ts, &ts1, NULL);
if (!HCL_CookTime(clock, hw_ts, &ts2, &e) ||
((pred_err = UTI_DiffTimespecsToDouble(&ts1, &ts2)) > *err)) {
DEBUG_LOG("Accepted reading err=%e prerr=%e", *err, pred_err);
return 1;
}
return 0;
}
/* ================================================== */
void
HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
struct timespec *local_ts, double err)
@@ -131,18 +258,18 @@ HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
/* Shift old samples */
if (clock->n_samples) {
if (clock->n_samples >= MAX_SAMPLES)
if (clock->n_samples >= clock->max_samples)
clock->n_samples--;
hw_delta = UTI_DiffTimespecsToDouble(hw_ts, &clock->hw_ref);
local_delta = UTI_DiffTimespecsToDouble(local_ts, &clock->local_ref) / local_freq;
if (hw_delta <= 0.0 || local_delta < MIN_SAMPLE_SEPARATION / 2.0) {
if (hw_delta <= 0.0 || local_delta < clock->min_separation / 2.0) {
clock->n_samples = 0;
DEBUG_LOG(LOGF_HwClocks, "HW clock reset interval=%f", local_delta);
DEBUG_LOG("HW clock reset interval=%f", local_delta);
}
for (i = MAX_SAMPLES - clock->n_samples; i < MAX_SAMPLES; i++) {
for (i = clock->max_samples - clock->n_samples; i < clock->max_samples; i++) {
clock->y_data[i - 1] = clock->y_data[i] - hw_delta;
clock->x_data[i - 1] = clock->x_data[i] - local_delta;
}
@@ -151,34 +278,37 @@ HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
clock->n_samples++;
clock->hw_ref = *hw_ts;
clock->local_ref = *local_ts;
clock->last_err = err;
/* Get new coefficients */
clock->valid_coefs =
RGR_FindBestRobustRegression(clock->x_data + MAX_SAMPLES - clock->n_samples,
clock->y_data + MAX_SAMPLES - clock->n_samples,
clock->n_samples, 1.0e-9, &clock->offset, &raw_freq,
RGR_FindBestRobustRegression(clock->x_data + clock->max_samples - clock->n_samples,
clock->y_data + clock->max_samples - clock->n_samples,
clock->n_samples, 1.0e-10, &clock->offset, &raw_freq,
&n_runs, &best_start);
if (!clock->valid_coefs) {
DEBUG_LOG(LOGF_HwClocks, "HW clock needs more samples");
DEBUG_LOG("HW clock needs more samples");
return;
}
clock->frequency = raw_freq / local_freq;
/* Drop unneeded samples */
clock->n_samples -= best_start;
if (clock->n_samples > clock->min_samples)
clock->n_samples -= MIN(best_start, clock->n_samples - clock->min_samples);
/* If the fit doesn't cross the error interval of the last sample, throw away
all previous samples and keep only the frequency estimate */
if (fabs(clock->offset) > err) {
DEBUG_LOG(LOGF_HwClocks, "HW clock reset offset=%e", clock->offset);
clock->offset = 0.0;
clock->n_samples = 1;
/* If the fit doesn't cross the error interval of the last sample,
or the frequency is not sane, drop all samples and start again */
if (fabs(clock->offset) > err ||
fabs(clock->frequency - 1.0) > MAX_FREQ_OFFSET) {
DEBUG_LOG("HW clock reset");
clock->n_samples = 0;
clock->valid_coefs = 0;
}
DEBUG_LOG(LOGF_HwClocks, "HW clock samples=%d offset=%e freq=%.9e raw_freq=%.9e err=%e ref_diff=%e",
clock->n_samples, clock->offset, clock->frequency, raw_freq, err,
DEBUG_LOG("HW clock samples=%d offset=%e freq=%e raw_freq=%e err=%e ref_diff=%e",
clock->n_samples, clock->offset, clock->frequency - 1.0, raw_freq - 1.0, err,
UTI_DiffTimespecsToDouble(&clock->hw_ref, &clock->local_ref));
}
@@ -193,12 +323,12 @@ HCL_CookTime(HCL_Instance clock, struct timespec *raw, struct timespec *cooked,
return 0;
elapsed = UTI_DiffTimespecsToDouble(raw, &clock->hw_ref);
offset = clock->offset + elapsed / clock->frequency;
offset = elapsed / clock->frequency - clock->offset;
UTI_AddDoubleToTimespec(&clock->local_ref, offset, cooked);
/* Estimation of the error is not implemented yet */
/* Fow now, just return the error of the last sample */
if (err)
*err = 0.0;
*err = clock->last_err;
return 1;
}

View File

@@ -29,7 +29,8 @@
typedef struct HCL_Instance_Record *HCL_Instance;
/* Create a new HW clock instance */
extern HCL_Instance HCL_CreateInstance(void);
extern HCL_Instance HCL_CreateInstance(int min_samples, int max_samples,
double min_separation, double precision);
/* Destroy a HW clock instance */
extern void HCL_DestroyInstance(HCL_Instance clock);
@@ -37,6 +38,11 @@ extern void HCL_DestroyInstance(HCL_Instance clock);
/* Check if a new sample should be accumulated at this time */
extern int HCL_NeedsNewSample(HCL_Instance clock, struct timespec *now);
/* Process new readings of the HW clock in form of (sys, hw, sys) triplets and
produce a sample which can be accumulated */
extern int HCL_ProcessReadings(HCL_Instance clock, int n_readings, struct timespec tss[][3],
struct timespec *hw_ts, struct timespec *local_ts, double *err);
/* Accumulate a new sample */
extern void HCL_AccumulateSample(HCL_Instance clock, struct timespec *hw_ts,
struct timespec *local_ts, double err);

276
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
@@ -32,6 +32,7 @@
#include "array.h"
#include "keys.h"
#include "cmac.h"
#include "cmdparse.h"
#include "conf.h"
#include "memory.h"
@@ -42,12 +43,23 @@
/* Consider 80 bits as the absolute minimum for a secure key */
#define MIN_SECURE_KEY_LENGTH 10
typedef enum {
NTP_MAC,
CMAC,
} KeyClass;
typedef struct {
uint32_t id;
char *val;
int len;
int hash_id;
int auth_delay;
int type;
int length;
KeyClass class;
union {
struct {
unsigned char *value;
int hash_id;
} ntp_mac;
CMC_Instance cmac;
} data;
} Key;
static ARR_Instance keys;
@@ -62,9 +74,21 @@ static void
free_keys(void)
{
unsigned int i;
Key *key;
for (i = 0; i < ARR_GetSize(keys); i++)
Free(((Key *)ARR_GetElement(keys, i))->val);
for (i = 0; i < ARR_GetSize(keys); i++) {
key = ARR_GetElement(keys, i);
switch (key->class) {
case NTP_MAC:
Free(key->data.ntp_mac.value);
break;
case CMAC:
CMC_DestroyInstance(key->data.cmac);
break;
default:
assert(0);
}
}
ARR_SetSize(keys, 0);
cache_valid = 0;
@@ -98,60 +122,18 @@ get_key(unsigned int index)
}
/* ================================================== */
/* Decode key encoded in ASCII or HEX */
static int
determine_hash_delay(uint32_t key_id)
decode_key(char *key)
{
NTP_Packet pkt;
struct timespec before, after;
double diff, min_diff;
int i, nsecs;
for (i = 0; i < 10; i++) {
LCL_ReadRawTime(&before);
KEY_GenerateAuth(key_id, (unsigned char *)&pkt, NTP_NORMAL_PACKET_LENGTH,
(unsigned char *)&pkt.auth_data, sizeof (pkt.auth_data));
LCL_ReadRawTime(&after);
diff = UTI_DiffTimespecsToDouble(&after, &before);
if (i == 0 || min_diff > diff)
min_diff = diff;
}
/* Add on a bit extra to allow for copying, conversions etc */
nsecs = 1.0625e9 * min_diff;
DEBUG_LOG(LOGF_Keys, "authentication delay for key %"PRIu32": %d nsecs", key_id, nsecs);
return nsecs;
}
/* ================================================== */
/* Decode password encoded in ASCII or HEX */
static int
decode_password(char *key)
{
int i, j, len = strlen(key);
char buf[3], *p;
int len = strlen(key);
if (!strncmp(key, "ASCII:", 6)) {
memmove(key, key + 6, len - 6);
return len - 6;
} else if (!strncmp(key, "HEX:", 4)) {
if ((len - 4) % 2)
return 0;
for (i = 0, j = 4; j + 1 < len; i++, j += 2) {
buf[0] = key[j], buf[1] = key[j + 1], buf[2] = '\0';
key[i] = strtol(buf, &p, 16);
if (p != buf + 2)
return 0;
}
return i;
return UTI_HexToBytes(key + 4, key, len);
} else {
/* assume ASCII */
return len;
@@ -183,11 +165,13 @@ compare_keys_by_id(const void *a, const void *b)
void
KEY_Reload(void)
{
unsigned int i, line_number;
unsigned int i, line_number, key_length, cmac_key_length;
FILE *in;
uint32_t key_id;
char line[2048], *keyval, *key_file;
const char *hashname;
char line[2048], *key_file, *key_value;
const char *key_type;
HSH_Algorithm hash_algorithm;
CMC_Algorithm cmac_algorithm;
int hash_id;
Key key;
free_keys();
@@ -198,9 +182,12 @@ KEY_Reload(void)
if (!key_file)
return;
in = fopen(key_file, "r");
if (!UTI_CheckFilePermissions(key_file, 0771))
;
in = UTI_OpenFile(NULL, key_file, NULL, 'r', 0);
if (!in) {
LOG(LOGS_WARN, LOGF_Keys, "Could not open keyfile %s", key_file);
LOG(LOGS_WARN, "Could not open keyfile %s", key_file);
return;
}
@@ -211,26 +198,56 @@ KEY_Reload(void)
if (!*line)
continue;
if (!CPS_ParseKey(line, &key_id, &hashname, &keyval)) {
LOG(LOGS_WARN, LOGF_Keys, "Could not parse key at line %d in file %s", line_number, key_file);
memset(&key, 0, sizeof (key));
if (!CPS_ParseKey(line, &key.id, &key_type, &key_value)) {
LOG(LOGS_WARN, "Could not parse key at line %u in file %s", line_number, key_file);
continue;
}
key.hash_id = HSH_GetHashId(hashname);
if (key.hash_id < 0) {
LOG(LOGS_WARN, LOGF_Keys, "Unknown hash function in key %"PRIu32, key_id);
key_length = decode_key(key_value);
if (key_length == 0) {
LOG(LOGS_WARN, "Could not decode key %"PRIu32, key.id);
continue;
}
key.len = decode_password(keyval);
if (!key.len) {
LOG(LOGS_WARN, LOGF_Keys, "Could not decode password in key %"PRIu32, key_id);
hash_algorithm = UTI_HashNameToAlgorithm(key_type);
cmac_algorithm = UTI_CmacNameToAlgorithm(key_type);
if (hash_algorithm != 0) {
hash_id = HSH_GetHashId(hash_algorithm);
if (hash_id < 0) {
LOG(LOGS_WARN, "Unsupported %s in key %"PRIu32, "hash function", key.id);
continue;
}
key.class = NTP_MAC;
key.type = hash_algorithm;
key.length = key_length;
key.data.ntp_mac.value = MallocArray(unsigned char, key_length);
memcpy(key.data.ntp_mac.value, key_value, key_length);
key.data.ntp_mac.hash_id = hash_id;
} else if (cmac_algorithm != 0) {
cmac_key_length = CMC_GetKeyLength(cmac_algorithm);
if (cmac_key_length == 0) {
LOG(LOGS_WARN, "Unsupported %s in key %"PRIu32, "cipher", key.id);
continue;
} else if (cmac_key_length != key_length) {
LOG(LOGS_WARN, "Invalid length of %s key %"PRIu32" (expected %u bits)",
key_type, key.id, 8 * cmac_key_length);
continue;
}
key.class = CMAC;
key.type = cmac_algorithm;
key.length = key_length;
key.data.cmac = CMC_CreateInstance(cmac_algorithm, (unsigned char *)key_value,
key_length);
assert(key.data.cmac);
} else {
LOG(LOGS_WARN, "Invalid type in key %"PRIu32, key.id);
continue;
}
key.id = key_id;
key.val = MallocArray(char, key.len);
memcpy(key.val, keyval, key.len);
ARR_AppendElement(keys, &key);
}
@@ -241,17 +258,16 @@ KEY_Reload(void)
more careful! */
qsort(ARR_GetElements(keys), ARR_GetSize(keys), sizeof (Key), compare_keys_by_id);
LOG(LOGS_INFO, "Loaded %u symmetric keys", ARR_GetSize(keys));
/* Check for duplicates */
for (i = 1; i < ARR_GetSize(keys); i++) {
if (get_key(i - 1)->id == get_key(i)->id)
LOG(LOGS_WARN, LOGF_Keys, "Detected duplicate key %"PRIu32, get_key(i - 1)->id);
LOG(LOGS_WARN, "Detected duplicate key %"PRIu32, get_key(i - 1)->id);
}
/* Erase any passwords from stack */
memset(line, 0, sizeof (line));
for (i = 0; i < ARR_GetSize(keys); i++)
get_key(i)->auth_delay = determine_hash_delay(get_key(i)->id);
}
/* ================================================== */
@@ -307,21 +323,6 @@ KEY_KeyKnown(uint32_t key_id)
/* ================================================== */
int
KEY_GetAuthDelay(uint32_t key_id)
{
Key *key;
key = get_key_by_id(key_id);
if (!key)
return 0;
return key->auth_delay;
}
/* ================================================== */
int
KEY_GetAuthLength(uint32_t key_id)
{
@@ -333,7 +334,15 @@ KEY_GetAuthLength(uint32_t key_id)
if (!key)
return 0;
return HSH_Hash(key->hash_id, buf, 0, buf, 0, buf, sizeof (buf));
switch (key->class) {
case NTP_MAC:
return HSH_Hash(key->data.ntp_mac.hash_id, buf, 0, buf, 0, buf, sizeof (buf));
case CMAC:
return CMC_Hash(key->data.cmac, buf, 0, buf, sizeof (buf));
default:
assert(0);
return 0;
}
}
/* ================================================== */
@@ -348,39 +357,13 @@ KEY_CheckKeyLength(uint32_t key_id)
if (!key)
return 0;
return key->len >= MIN_SECURE_KEY_LENGTH;
}
/* ================================================== */
static int
generate_ntp_auth(int hash_id, const unsigned char *key, int key_len,
const unsigned char *data, int data_len,
unsigned char *auth, int auth_len)
{
return HSH_Hash(hash_id, key, key_len, data, data_len, auth, auth_len);
}
/* ================================================== */
static int
check_ntp_auth(int hash_id, const unsigned char *key, int key_len,
const unsigned char *data, int data_len,
const unsigned char *auth, int auth_len, int trunc_len)
{
unsigned char buf[MAX_HASH_LENGTH];
int hash_len;
hash_len = generate_ntp_auth(hash_id, key, key_len, data, data_len, buf, sizeof (buf));
return MIN(hash_len, trunc_len) == auth_len && !memcmp(buf, auth, auth_len);
return key->length >= MIN_SECURE_KEY_LENGTH;
}
/* ================================================== */
int
KEY_GenerateAuth(uint32_t key_id, const unsigned char *data, int data_len,
unsigned char *auth, int auth_len)
KEY_GetKeyInfo(uint32_t key_id, int *type, int *bits)
{
Key *key;
@@ -389,14 +372,62 @@ KEY_GenerateAuth(uint32_t key_id, const unsigned char *data, int data_len,
if (!key)
return 0;
return generate_ntp_auth(key->hash_id, (unsigned char *)key->val, key->len,
data, data_len, auth, auth_len);
*type = key->type;
*bits = 8 * key->length;
return 1;
}
/* ================================================== */
static int
generate_auth(Key *key, const void *data, int data_len, unsigned char *auth, int auth_len)
{
switch (key->class) {
case NTP_MAC:
return HSH_Hash(key->data.ntp_mac.hash_id, key->data.ntp_mac.value,
key->length, data, data_len, auth, auth_len);
case CMAC:
return CMC_Hash(key->data.cmac, data, data_len, auth, auth_len);
default:
return 0;
}
}
/* ================================================== */
static int
check_auth(Key *key, const void *data, int data_len,
const unsigned char *auth, int auth_len, int trunc_len)
{
unsigned char buf[MAX_HASH_LENGTH];
int hash_len;
hash_len = generate_auth(key, data, data_len, buf, sizeof (buf));
return MIN(hash_len, trunc_len) == auth_len && !memcmp(buf, auth, auth_len);
}
/* ================================================== */
int
KEY_CheckAuth(uint32_t key_id, const unsigned char *data, int data_len,
KEY_GenerateAuth(uint32_t key_id, const void *data, int data_len,
unsigned char *auth, int auth_len)
{
Key *key;
key = get_key_by_id(key_id);
if (!key)
return 0;
return generate_auth(key, data, data_len, auth, auth_len);
}
/* ================================================== */
int
KEY_CheckAuth(uint32_t key_id, const void *data, int data_len,
const unsigned char *auth, int auth_len, int trunc_len)
{
Key *key;
@@ -406,6 +437,5 @@ KEY_CheckAuth(uint32_t key_id, const unsigned char *data, int data_len,
if (!key)
return 0;
return check_ntp_auth(key->hash_id, (unsigned char *)key->val, key->len,
data, data_len, auth, auth_len, trunc_len);
return check_auth(key, data, data_len, auth, auth_len, trunc_len);
}

9
keys.h
View File

@@ -34,15 +34,14 @@ extern void KEY_Finalise(void);
extern void KEY_Reload(void);
extern int KEY_GetKey(uint32_t key_id, char **key, int *len);
extern int KEY_KeyKnown(uint32_t key_id);
extern int KEY_GetAuthDelay(uint32_t key_id);
extern int KEY_GetAuthLength(uint32_t key_id);
extern int KEY_CheckKeyLength(uint32_t key_id);
extern int KEY_GetKeyInfo(uint32_t key_id, int *type, int *bits);
extern int KEY_GenerateAuth(uint32_t key_id, const unsigned char *data,
int data_len, unsigned char *auth, int auth_len);
extern int KEY_CheckAuth(uint32_t key_id, const unsigned char *data, int data_len,
extern int KEY_GenerateAuth(uint32_t key_id, const void *data, int data_len,
unsigned char *auth, int auth_len);
extern int KEY_CheckAuth(uint32_t key_id, const void *data, int data_len,
const unsigned char *auth, int auth_len, int trunc_len);
#endif /* GOT_KEYS_H */

103
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,16 +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;
}
DEBUG_LOG(LOGF_Local, "Clock precision %.9f (%d)", precision_quantum, precision_log);
return 1.0e-9 * best;
}
/* ================================================== */
@@ -168,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 */
@@ -183,13 +183,11 @@ LCL_Initialise(void)
void
LCL_Finalise(void)
{
while (change_list.next != &change_list)
LCL_RemoveParameterChangeHandler(change_list.next->handler,
change_list.next->anything);
while (dispersion_notify_list.next != &dispersion_notify_list)
LCL_RemoveDispersionNotifyHandler(dispersion_notify_list.next->handler,
dispersion_notify_list.next->anything);
/* Make sure all handlers have been removed */
if (change_list.next != &change_list)
assert(0);
if (dispersion_notify_list.next != &dispersion_notify_list)
assert(0);
}
/* ================================================== */
@@ -356,12 +354,12 @@ LCL_ReadRawTime(struct timespec *ts)
{
#if HAVE_CLOCK_GETTIME
if (clock_gettime(CLOCK_REALTIME, ts) < 0)
LOG_FATAL(LOGF_Local, "clock_gettime() failed : %s", strerror(errno));
LOG_FATAL("clock_gettime() failed : %s", strerror(errno));
#else
struct timeval tv;
if (gettimeofday(&tv, NULL) < 0)
LOG_FATAL(LOGF_Local, "gettimeofday() failed : %s", strerror(errno));
LOG_FATAL("gettimeofday() failed : %s", strerror(errno));
UTI_TimevalToTimespec(&tv, ts);
#endif
@@ -424,7 +422,7 @@ clamp_freq(double freq)
if (freq <= max_freq_ppm && freq >= -max_freq_ppm)
return freq;
LOG(LOGS_WARN, LOGF_Local, "Frequency %.1f ppm exceeds allowed maximum", freq);
LOG(LOGS_WARN, "Frequency %.1f ppm exceeds allowed maximum", freq);
return CLAMP(-max_freq_ppm, freq, max_freq_ppm);
}
@@ -438,7 +436,7 @@ check_offset(struct timespec *now, double offset)
if (UTI_IsTimeOffsetSane(now, -offset))
return 1;
LOG(LOGS_WARN, LOGF_Local, "Adjustment of %.1f seconds is invalid", -offset);
LOG(LOGS_WARN, "Adjustment of %.1f seconds is invalid", -offset);
return 0;
}
@@ -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;
}
/* ================================================== */
@@ -544,7 +544,7 @@ LCL_ApplyStepOffset(double offset)
return 0;
if (!(*drv_apply_step_offset)(offset)) {
LOG(LOGS_ERR, LOGF_Local, "Could not step clock");
LOG(LOGS_ERR, "Could not step system clock");
return 0;
}
@@ -563,6 +563,8 @@ void
LCL_NotifyExternalTimeStep(struct timespec *raw, struct timespec *cooked,
double offset, double dispersion)
{
LCL_CancelOffsetCorrection();
/* Dispatch to all handlers */
invoke_parameter_change_handlers(raw, cooked, 0.0, offset, LCL_ChangeUnknownStep);
@@ -588,7 +590,7 @@ LCL_NotifyLeap(int leap)
/* ================================================== */
void
int
LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
{
struct timespec raw, cooked;
@@ -600,7 +602,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;
@@ -611,7 +613,7 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset, double corr_rate)
current_freq_ppm = clamp_freq(current_freq_ppm);
DEBUG_LOG(LOGF_Local, "old_freq=%.3fppm new_freq=%.3fppm offset=%.6fsec",
DEBUG_LOG("old_freq=%.3fppm new_freq=%.3fppm offset=%.6fsec",
old_freq_ppm, current_freq_ppm, doffset);
/* Call the system-specific driver for setting the frequency */
@@ -622,6 +624,26 @@ 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;
}
/* ================================================== */
int
LCL_AccumulateFrequencyAndOffsetNoHandlers(double dfreq, double doffset, double corr_rate)
{
ChangeListEntry *first_handler;
int r;
first_handler = change_list.next;
change_list.next = &change_list;
r = LCL_AccumulateFrequencyAndOffset(dfreq, doffset, corr_rate);
change_list.next = first_handler;
return r;
}
/* ================================================== */
@@ -658,7 +680,7 @@ lcl_RegisterSystemDrivers(lcl_ReadFrequencyDriver read_freq,
current_freq_ppm = (*drv_read_freq)();
DEBUG_LOG(LOGF_Local, "Local freq=%.3fppm", current_freq_ppm);
DEBUG_LOG("Local freq=%.3fppm", current_freq_ppm);
}
/* ================================================== */
@@ -682,13 +704,26 @@ LCL_MakeStep(void)
if (!LCL_ApplyStepOffset(-correction))
return 0;
LOG(LOGS_WARN, LOGF_Local, "System clock was stepped by %.6f seconds", correction);
LOG(LOGS_WARN, "System clock was stepped by %.6f seconds", correction);
return 1;
}
/* ================================================== */
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)
{
@@ -698,10 +733,10 @@ LCL_CanSystemLeap(void)
/* ================================================== */
void
LCL_SetSystemLeap(int leap)
LCL_SetSystemLeap(int leap, int tai_offset)
{
if (drv_set_leap) {
(drv_set_leap)(leap);
(drv_set_leap)(leap, tai_offset);
}
}

21
local.h
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,12 @@ 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);
/* Same as the routine above, except it does not call the registered
parameter change handlers */
extern int LCL_AccumulateFrequencyAndOffsetNoHandlers(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,14 +202,18 @@ 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);
/* Routine to set the system clock to correct itself for a leap second if
supported. Leap second will be inserted at the end of the day if the
argument is positive, deleted if negative, and zero resets the setting. */
extern void LCL_SetSystemLeap(int leap);
/* Routine to set the system clock to correct itself for a leap second and also
set its TAI-UTC offset. If supported, leap second will be inserted at the
end of the day if the argument is positive, deleted if negative, and zero
resets the setting. */
extern void LCL_SetSystemLeap(int leap, int tai_offset);
/* Routine to set a frequency correction (in ppm) that should be applied
to local clock to compensate for temperature changes. A positive

View File

@@ -54,8 +54,8 @@ typedef int (*lcl_ApplyStepOffsetDriver)(double offset);
raw time to get the corrected time */
typedef void (*lcl_OffsetCorrectionDriver)(struct timespec *raw, double *corr, double *err);
/* System driver to schedule leap second */
typedef void (*lcl_SetLeapDriver)(int leap);
/* System driver to schedule leap seconds and set TAI-UTC offset */
typedef void (*lcl_SetLeapDriver)(int leap, int tai_offset);
/* System driver to set the synchronisation status */
typedef void (*lcl_SetSyncStatusDriver)(int synchronised, double est_error, double max_error);

183
logging.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Richard P. Curnow 1997-2003
* Copyright (C) Miroslav Lichvar 2011-2014
* 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
@@ -29,25 +29,28 @@
#include "sysincl.h"
#include <syslog.h>
#include "conf.h"
#include "logging.h"
#include "memory.h"
#include "util.h"
/* This is used by DEBUG_LOG macro */
int log_debug_enabled = 0;
LOG_Severity log_min_severity = LOGS_INFO;
/* Current logging contexts */
static LOG_Context log_contexts;
/* ================================================== */
/* Flag indicating we have initialised */
static int initialised = 0;
static FILE *file_log = NULL;
static int system_log = 0;
static int parent_fd = 0;
#define DEBUG_LEVEL_PRINT_FUNCTION 2
#define DEBUG_LEVEL_PRINT_DEBUG 2
static int debug_level = 0;
struct LogFile {
const char *name;
const char *banner;
@@ -62,13 +65,20 @@ static int n_filelogs = 0;
static struct LogFile logfiles[MAX_FILELOGS];
/* Global prefix for debug messages */
static char *debug_prefix;
/* ================================================== */
/* Init function */
void
LOG_Initialise(void)
{
debug_prefix = Strdup("");
log_contexts = 0;
initialised = 1;
LOG_OpenFileLog(NULL);
}
/* ================================================== */
@@ -77,12 +87,16 @@ LOG_Initialise(void)
void
LOG_Finalise(void)
{
if (system_log) {
if (system_log)
closelog();
}
if (file_log)
fclose(file_log);
LOG_CycleLogFiles();
Free(debug_prefix);
initialised = 0;
}
@@ -112,8 +126,8 @@ static void log_message(int fatal, LOG_Severity severity, const char *message)
assert(0);
}
syslog(priority, fatal ? "Fatal error : %s" : "%s", message);
} else {
fprintf(stderr, fatal ? "Fatal error : %s\n" : "%s\n", message);
} else if (file_log) {
fprintf(file_log, fatal ? "Fatal error : %s\n" : "%s\n", message);
}
}
@@ -121,25 +135,34 @@ static void log_message(int fatal, LOG_Severity severity, const char *message)
void LOG_Message(LOG_Severity severity,
#if DEBUG > 0
LOG_Facility facility, int line_number,
const char *filename, const char *function_name,
int line_number, const char *filename, const char *function_name,
#endif
const char *format, ...)
{
char buf[2048];
va_list other_args;
time_t t;
struct tm stm;
struct tm *tm;
if (!system_log) {
assert(initialised);
severity = CLAMP(LOGS_DEBUG, severity, LOGS_FATAL);
if (!system_log && file_log && severity >= log_min_severity) {
/* Don't clutter up syslog with timestamps and internal debugging info */
time(&t);
stm = *gmtime(&t);
strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", &stm);
fprintf(stderr, "%s ", buf);
tm = gmtime(&t);
if (tm) {
strftime(buf, sizeof (buf), "%Y-%m-%dT%H:%M:%SZ", tm);
fprintf(file_log, "%s ", buf);
}
#if DEBUG > 0
if (debug_level >= DEBUG_LEVEL_PRINT_FUNCTION)
fprintf(stderr, "%s:%d:(%s) ", filename, line_number, function_name);
if (log_min_severity <= LOGS_DEBUG) {
/* Log severity to character mapping (debug, info, warn, err, fatal) */
const char severity_chars[LOGS_FATAL - LOGS_DEBUG + 1] = {'D', 'I', 'W', 'E', 'F'};
fprintf(file_log, "%c:%s%s:%d:(%s) ", severity_chars[severity - LOGS_DEBUG],
debug_prefix, filename, line_number, function_name);
}
#endif
}
@@ -152,28 +175,52 @@ void LOG_Message(LOG_Severity severity,
case LOGS_INFO:
case LOGS_WARN:
case LOGS_ERR:
log_message(0, severity, buf);
if (severity >= log_min_severity)
log_message(0, severity, buf);
break;
case LOGS_FATAL:
log_message(1, severity, buf);
if (severity >= log_min_severity)
log_message(1, severity, buf);
/* With syslog, send the message also to the grandparent
process or write it to stderr if not detached */
if (system_log) {
if (parent_fd > 0) {
if (write(parent_fd, buf, strlen(buf) + 1) < 0)
; /* Not much we can do here */
} else if (parent_fd == 0) {
system_log = 0;
log_message(1, severity, buf);
}
/* Send the message also to the foreground process if it is
still running, or stderr if it is still open */
if (parent_fd > 0) {
if (write(parent_fd, buf, strlen(buf) + 1) < 0)
; /* Not much we can do here */
} else if (system_log && parent_fd == 0) {
system_log = 0;
log_message(1, severity, buf);
}
exit(1);
break;
default:
assert(0);
}
}
/* ================================================== */
void
LOG_OpenFileLog(const char *log_file)
{
FILE *f;
if (log_file) {
f = UTI_OpenFile(NULL, log_file, NULL, 'A', 0640);
} else {
f = stderr;
}
/* Enable line buffering */
setvbuf(f, NULL, _IOLBF, BUFSIZ);
if (file_log && file_log != stderr)
fclose(file_log);
file_log = f;
}
/* ================================================== */
void
@@ -185,12 +232,51 @@ LOG_OpenSystemLog(void)
/* ================================================== */
void LOG_SetDebugLevel(int level)
void LOG_SetMinSeverity(LOG_Severity severity)
{
debug_level = level;
if (level >= DEBUG_LEVEL_PRINT_DEBUG) {
log_debug_enabled = 1;
}
/* Don't print any debug messages in a non-debug build */
log_min_severity = CLAMP(DEBUG > 0 ? LOGS_DEBUG : LOGS_INFO, severity, LOGS_FATAL);
}
/* ================================================== */
LOG_Severity
LOG_GetMinSeverity(void)
{
return log_min_severity;
}
/* ================================================== */
void
LOG_SetContext(LOG_Context context)
{
log_contexts |= context;
}
/* ================================================== */
void
LOG_UnsetContext(LOG_Context context)
{
log_contexts &= ~context;
}
/* ================================================== */
LOG_Severity
LOG_GetContextSeverity(LOG_Context contexts)
{
return log_contexts & contexts ? LOGS_INFO : LOGS_DEBUG;
}
/* ================================================== */
void
LOG_SetDebugPrefix(const char *prefix)
{
Free(debug_prefix);
debug_prefix = Strdup(prefix);
}
/* ================================================== */
@@ -199,6 +285,8 @@ void
LOG_SetParentFd(int fd)
{
parent_fd = fd;
if (file_log == stderr)
file_log = NULL;
}
/* ================================================== */
@@ -216,7 +304,10 @@ LOG_CloseParentFd()
LOG_FileID
LOG_FileOpen(const char *name, const char *banner)
{
assert(n_filelogs < MAX_FILELOGS);
if (n_filelogs >= MAX_FILELOGS) {
assert(0);
return -1;
}
logfiles[n_filelogs].name = name;
logfiles[n_filelogs].banner = banner;
@@ -238,24 +329,20 @@ LOG_FileWrite(LOG_FileID id, const char *format, ...)
return;
if (!logfiles[id].file) {
char filename[512], *logdir = CNF_GetLogDir();
char *logdir = CNF_GetLogDir();
if (logdir[0] == '\0') {
LOG(LOGS_WARN, LOGF_Logging, "logdir not specified");
if (!logdir) {
LOG(LOGS_WARN, "logdir not specified");
logfiles[id].name = NULL;
return;
}
if (snprintf(filename, sizeof(filename), "%s/%s.log",
logdir, logfiles[id].name) >= sizeof (filename) ||
!(logfiles[id].file = fopen(filename, "a"))) {
LOG(LOGS_WARN, LOGF_Logging, "Could not open log file %s", filename);
logfiles[id].file = UTI_OpenFile(logdir, logfiles[id].name, ".log", 'a', 0644);
if (!logfiles[id].file) {
/* Disable the log */
logfiles[id].name = NULL;
return;
}
/* Close on exec */
UTI_FdSetCloexec(fileno(logfiles[id].file));
}
banner = CNF_GetLogBanner();
@@ -263,7 +350,7 @@ LOG_FileWrite(LOG_FileID id, const char *format, ...)
char bannerline[256];
int i, bannerlen;
bannerlen = strlen(logfiles[id].banner);
bannerlen = MIN(strlen(logfiles[id].banner), sizeof (bannerline) - 1);
for (i = 0; i < bannerlen; i++)
bannerline[i] = '=';

110
logging.h
View File

@@ -31,9 +31,6 @@
#include "sysincl.h"
/* Flag indicating whether debug messages are logged */
extern int log_debug_enabled;
/* Line logging macros. If the compiler is GNU C, we take advantage of
being able to get the function name also. */
@@ -46,79 +43,38 @@ extern int log_debug_enabled;
#endif
#if DEBUG > 0
#define LOG_MESSAGE(severity, facility, ...) \
LOG_Message(severity, facility, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__)
#define LOG_MESSAGE(severity, ...) \
LOG_Message(severity, __LINE__, __FILE__, FUNCTION_NAME, __VA_ARGS__)
#else
#define LOG_MESSAGE(severity, facility, ...) \
#define LOG_MESSAGE(severity, ...) \
LOG_Message(severity, __VA_ARGS__)
#endif
#define DEBUG_LOG(facility, ...) \
#define DEBUG_LOG(...) \
do { \
if (DEBUG && log_debug_enabled) \
LOG_MESSAGE(LOGS_DEBUG, facility, __VA_ARGS__); \
if (DEBUG && log_min_severity == LOGS_DEBUG) \
LOG_MESSAGE(LOGS_DEBUG, __VA_ARGS__); \
} while (0)
#define LOG_FATAL(facility, ...) \
#define LOG_FATAL(...) \
do { \
LOG_MESSAGE(LOGS_FATAL, facility, __VA_ARGS__); \
LOG_MESSAGE(LOGS_FATAL, __VA_ARGS__); \
exit(1); \
} while (0)
#define LOG(severity, facility, ...) LOG_MESSAGE(severity, facility, __VA_ARGS__)
#define LOG(severity, ...) LOG_MESSAGE(severity, __VA_ARGS__)
/* Definition of severity */
typedef enum {
LOGS_INFO,
LOGS_DEBUG = -1,
LOGS_INFO = 0,
LOGS_WARN,
LOGS_ERR,
LOGS_FATAL,
LOGS_DEBUG
} LOG_Severity;
/* Definition of facility. Each message is tagged with who generated
it, so that the user can customise what level of reporting he gets
for each area of the software */
typedef enum {
LOGF_Reference,
LOGF_NtpIO,
LOGF_NtpIOLinux,
LOGF_NtpCore,
LOGF_NtpSignd,
LOGF_NtpSources,
LOGF_Scheduler,
LOGF_SourceStats,
LOGF_Sources,
LOGF_Local,
LOGF_Util,
LOGF_Main,
LOGF_Memory,
LOGF_Client,
LOGF_ClientLog,
LOGF_Configure,
LOGF_CmdMon,
LOGF_Acquire,
LOGF_Manual,
LOGF_Keys,
LOGF_Logging,
LOGF_Nameserv,
LOGF_PrivOps,
LOGF_Rtc,
LOGF_Regress,
LOGF_Sys,
LOGF_SysGeneric,
LOGF_SysLinux,
LOGF_SysMacOSX,
LOGF_SysNetBSD,
LOGF_SysSolaris,
LOGF_SysTimex,
LOGF_SysWinnt,
LOGF_TempComp,
LOGF_RtcLinux,
LOGF_Refclock,
LOGF_HwClocks,
LOGF_Smooth,
} LOG_Facility;
/* Minimum severity of messages to be logged */
extern LOG_Severity log_min_severity;
/* Init function */
extern void LOG_Initialise(void);
@@ -128,26 +84,46 @@ extern void LOG_Finalise(void);
/* Line logging function */
#if DEBUG > 0
FORMAT_ATTRIBUTE_PRINTF(6, 7)
extern void LOG_Message(LOG_Severity severity, LOG_Facility facility,
int line_number, const char *filename,
FORMAT_ATTRIBUTE_PRINTF(5, 6)
extern void LOG_Message(LOG_Severity severity, int line_number, const char *filename,
const char *function_name, const char *format, ...);
#else
FORMAT_ATTRIBUTE_PRINTF(2, 3)
extern void LOG_Message(LOG_Severity severity, const char *format, ...);
#endif
/* Set debug level:
0, 1 - only non-debug messages are logged
2 - debug messages are logged too, all messages are prefixed with
filename, line, and function name
*/
extern void LOG_SetDebugLevel(int level);
/* Set the minimum severity of a message to be logged or printed to terminal.
If the severity is LOGS_DEBUG and DEBUG is enabled, all messages will be
prefixed with the filename, line number, and function name. */
extern void LOG_SetMinSeverity(LOG_Severity severity);
/* Get the minimum severity */
extern LOG_Severity LOG_GetMinSeverity(void);
/* Flags for info messages that should be logged only in specific contexts */
typedef enum {
LOGC_Command = 1,
LOGC_SourceFile = 2,
} LOG_Context;
/* Modify current contexts */
extern void LOG_SetContext(LOG_Context context);
extern void LOG_UnsetContext(LOG_Context context);
/* Get severity depending on the current active contexts: INFO if they contain
at least one of the specified contexts, DEBUG otherwise */
extern LOG_Severity LOG_GetContextSeverity(LOG_Context contexts);
/* Set a prefix for debug messages */
extern void LOG_SetDebugPrefix(const char *prefix);
/* Log messages to a file instead of stderr, or stderr again if NULL */
extern void LOG_OpenFileLog(const char *log_file);
/* Log messages to syslog instead of stderr */
extern void LOG_OpenSystemLog(void);
/* Send fatal message also to the foreground process */
/* Stop using stderr and send fatal message to the foreground process */
extern void LOG_SetParentFd(int fd);
/* Close the pipe to the foreground process so it can exit */

438
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-2015
* 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
@@ -38,6 +38,9 @@
#include "ntp_signd.h"
#include "ntp_sources.h"
#include "ntp_core.h"
#include "nts_ke_server.h"
#include "nts_ntp_server.h"
#include "socket.h"
#include "sources.h"
#include "sourcestats.h"
#include "reference.h"
@@ -73,11 +76,18 @@ static REF_Mode ref_mode = REF_ModeNormal;
static void
do_platform_checks(void)
{
struct timespec ts;
/* Require at least 32-bit integers, two's complement representation and
the usual implementation of conversion of unsigned integers */
assert(sizeof (int) >= 4);
assert(-1 == ~0);
assert((int32_t)4294967295U == (int32_t)-1);
/* Require time_t and tv_nsec in timespec to be signed */
ts.tv_sec = -1;
ts.tv_nsec = -1;
assert(ts.tv_sec < 0 && ts.tv_nsec < 0);
}
/* ================================================== */
@@ -86,8 +96,12 @@ static void
delete_pidfile(void)
{
const char *pidfile = CNF_GetPidFile();
/* Don't care if this fails, there's not a lot we can do */
unlink(pidfile);
if (!pidfile)
return;
if (!UTI_RemoveFile(NULL, pidfile, NULL))
;
}
/* ================================================== */
@@ -97,9 +111,8 @@ MAI_CleanupAndExit(void)
{
if (!initialised) exit(exit_status);
if (CNF_GetDumpOnExit()) {
SRC_DumpSources();
}
LCL_CancelOffsetCorrection();
SRC_DumpSources();
/* Don't update clock when removing sources */
REF_SetMode(REF_ModeIgnore);
@@ -108,18 +121,23 @@ MAI_CleanupAndExit(void)
TMC_Finalise();
MNL_Finalise();
CLG_Finalise();
NKS_Finalise();
NNS_Finalise();
NSD_Finalise();
NSR_Finalise();
SST_Finalise();
NCR_Finalise();
NIO_Finalise();
CAM_Finalise();
KEY_Finalise();
RCL_Finalise();
SRC_Finalise();
REF_Finalise();
RTC_Finalise();
SYS_Finalise();
SCK_Finalise();
SCH_Finalise();
LCL_Finalise();
PRV_Finalise();
@@ -127,9 +145,10 @@ MAI_CleanupAndExit(void)
delete_pidfile();
CNF_Finalise();
HSH_Finalise();
LOG_Finalise();
HSH_Finalise();
UTI_ResetGetRandomFunctions();
exit(exit_status);
}
@@ -139,7 +158,6 @@ MAI_CleanupAndExit(void)
static void
signal_cleanup(int x)
{
if (!initialised) exit(0);
SCH_QuitProgram();
}
@@ -148,6 +166,8 @@ signal_cleanup(int x)
static void
quit_timeout(void *arg)
{
LOG(LOGS_INFO, "Timeout reached");
/* Return with non-zero status if the clock is not synchronised */
exit_status = REF_GetOurStratum() >= NTP_MAX_STRATUM;
SCH_QuitProgram();
@@ -175,7 +195,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();
}
@@ -242,63 +262,54 @@ post_init_rtc_hook(void *anything)
}
/* ================================================== */
/* Return 1 if the process exists on the system. */
static int
does_process_exist(int pid)
{
int status;
status = getsid(pid);
if (status >= 0) {
return 1;
} else {
return 0;
}
}
/* ================================================== */
static int
maybe_another_chronyd_running(int *other_pid)
static void
check_pidfile(void)
{
const char *pidfile = CNF_GetPidFile();
FILE *in;
int pid, count;
*other_pid = 0;
if (!pidfile)
return;
in = fopen(pidfile, "r");
if (!in) return 0;
in = UTI_OpenFile(NULL, pidfile, NULL, 'r', 0);
if (!in)
return;
count = fscanf(in, "%d", &pid);
fclose(in);
if (count != 1) return 0;
if (count != 1)
return;
*other_pid = pid;
return does_process_exist(pid);
if (getsid(pid) < 0)
return;
LOG_FATAL("Another chronyd may already be running (pid=%d), check %s",
pid, pidfile);
}
/* ================================================== */
static void
write_lockfile(void)
write_pidfile(void)
{
const char *pidfile = CNF_GetPidFile();
FILE *out;
out = fopen(pidfile, "w");
if (!out) {
LOG_FATAL(LOGF_Main, "could not open lockfile %s for writing", pidfile);
} else {
fprintf(out, "%d\n", (int)getpid());
fclose(out);
}
if (!pidfile)
return;
out = UTI_OpenFile(NULL, pidfile, NULL, 'W', 0644);
fprintf(out, "%d\n", (int)getpid());
fclose(out);
}
/* ================================================== */
#define DEV_NULL "/dev/null"
static void
go_daemon(void)
{
@@ -307,25 +318,29 @@ go_daemon(void)
/* Create pipe which will the daemon use to notify the grandparent
when it's initialised or send an error message */
if (pipe(pipefd)) {
LOG_FATAL(LOGF_Main, "Could not detach, pipe failed : %s", strerror(errno));
LOG_FATAL("pipe() failed : %s", strerror(errno));
}
/* Does this preserve existing signal handlers? */
pid = fork();
if (pid < 0) {
LOG_FATAL(LOGF_Main, "Could not detach, fork failed : %s", strerror(errno));
LOG_FATAL("fork() failed : %s", strerror(errno));
} else if (pid > 0) {
/* In the 'grandparent' */
char message[1024];
int r;
/* Don't exit before the 'parent' */
waitpid(pid, NULL, 0);
close(pipefd[1]);
r = read(pipefd[0], message, sizeof (message));
if (r) {
if (r > 0) {
/* Print the error message from the child */
fprintf(stderr, "%.1024s\n", message);
message[sizeof (message) - 1] = '\0';
fprintf(stderr, "%s\n", message);
}
exit(1);
} else
@@ -339,175 +354,281 @@ go_daemon(void)
pid = fork();
if (pid < 0) {
LOG_FATAL(LOGF_Main, "Could not detach, fork failed : %s", strerror(errno));
LOG_FATAL("fork() failed : %s", strerror(errno));
} else if (pid > 0) {
exit(0); /* In the 'parent' */
/* In the 'parent' */
close(pipefd[1]);
exit(0);
} else {
/* In the child we want to leave running as the daemon */
/* Change current directory to / */
if (chdir("/") < 0) {
LOG_FATAL(LOGF_Main, "Could not chdir to / : %s", strerror(errno));
LOG_FATAL("chdir() failed : %s", strerror(errno));
}
/* Don't keep stdin/out/err from before. But don't close
the parent pipe yet. */
the parent pipe yet, or reusable file descriptors. */
for (fd=0; fd<1024; fd++) {
if (fd != pipefd[1])
if (fd != pipefd[1] && !SCK_IsReusable(fd))
close(fd);
}
LOG_SetParentFd(pipefd[1]);
/* Open /dev/null as new stdin/out/err */
errno = 0;
if (open(DEV_NULL, O_RDONLY) != STDIN_FILENO ||
open(DEV_NULL, O_WRONLY) != STDOUT_FILENO ||
open(DEV_NULL, O_RDWR) != STDERR_FILENO)
LOG_FATAL("Could not open %s : %s", DEV_NULL, strerror(errno));
}
}
}
/* ================================================== */
static void
print_help(const char *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);
}
/* ================================================== */
static void
print_version(void)
{
printf("chronyd (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYD_FEATURES);
}
/* ================================================== */
static int
parse_int_arg(const char *arg)
{
int i;
if (sscanf(arg, "%d", &i) != 1)
LOG_FATAL("Invalid argument %s", arg);
return i;
}
/* ================================================== */
int main
(int argc, char **argv)
{
const char *conf_file = DEFAULT_CONF_FILE;
const char *progname = argv[0];
char *user = NULL;
char *user = NULL, *log_file = NULL;
struct passwd *pw;
int debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
int do_init_rtc = 0, restarted = 0, timeout = 0;
int other_pid;
int opt, debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
int do_init_rtc = 0, restarted = 0, client_only = 0, timeout = -1;
int scfilter_level = 0, lock_memory = 0, sched_priority = 0;
int system_log = 1;
int config_args = 0;
int clock_control = 1, system_log = 1, log_severity = LOGS_INFO;
int user_check = 1, config_args = 0, print_config = 0;
do_platform_checks();
LOG_Initialise();
/* Parse command line options */
while (++argv, (--argc)>0) {
if (!strcmp("-f", *argv)) {
++argv, --argc;
conf_file = *argv;
} else if (!strcmp("-P", *argv)) {
++argv, --argc;
if (argc == 0 || sscanf(*argv, "%d", &sched_priority) != 1) {
LOG_FATAL(LOGF_Main, "Bad scheduler priority");
}
} else if (!strcmp("-m", *argv)) {
lock_memory = 1;
} else if (!strcmp("-r", *argv)) {
reload = 1;
} else if (!strcmp("-R", *argv)) {
restarted = 1;
} else if (!strcmp("-u", *argv)) {
++argv, --argc;
if (argc == 0) {
LOG_FATAL(LOGF_Main, "Missing user name");
} else {
user = *argv;
}
} else if (!strcmp("-F", *argv)) {
++argv, --argc;
if (argc == 0 || sscanf(*argv, "%d", &scfilter_level) != 1)
LOG_FATAL(LOGF_Main, "Bad syscall filter level");
} else if (!strcmp("-s", *argv)) {
do_init_rtc = 1;
} else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
/* This write to the terminal is OK, it comes before we turn into a daemon */
printf("chronyd (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYD_FEATURES);
/* Parse long command-line options */
for (optind = 1; optind < argc; optind++) {
if (!strcmp("--help", argv[optind])) {
print_help(progname);
return 0;
} else if (!strcmp("-n", *argv)) {
nofork = 1;
} else if (!strcmp("-d", *argv)) {
debug++;
nofork = 1;
system_log = 0;
} else if (!strcmp("-q", *argv)) {
ref_mode = REF_ModeUpdateOnce;
nofork = 1;
system_log = 0;
} else if (!strcmp("-Q", *argv)) {
ref_mode = REF_ModePrintOnce;
nofork = 1;
system_log = 0;
} else if (!strcmp("-t", *argv)) {
++argv, --argc;
if (argc == 0 || sscanf(*argv, "%d", &timeout) != 1 || timeout <= 0)
LOG_FATAL(LOGF_Main, "Bad timeout");
} else if (!strcmp("-4", *argv)) {
address_family = IPADDR_INET4;
} else if (!strcmp("-6", *argv)) {
address_family = IPADDR_INET6;
} else if (!strcmp("-h", *argv) || !strcmp("--help", *argv)) {
printf("Usage: %s [-4|-6] [-n|-d] [-q|-Q] [-r] [-R] [-s] [-t TIMEOUT] [-f FILE|COMMAND...]\n",
progname);
} else if (!strcmp("--version", argv[optind])) {
print_version();
return 0;
} else if (*argv[0] == '-') {
LOG_FATAL(LOGF_Main, "Unrecognized command line option [%s]", *argv);
} else {
/* Process remaining arguments and configuration lines */
config_args = argc;
break;
}
}
if (getuid() != 0) {
/* This write to the terminal is OK, it comes before we turn into a daemon */
fprintf(stderr,"Not superuser\n");
return 1;
optind = 1;
/* Parse short command-line options */
while ((opt = getopt(argc, argv, "46df:F:hl:L:mnpP:qQrRst:u:Uvx")) != -1) {
switch (opt) {
case '4':
case '6':
address_family = opt == '4' ? IPADDR_INET4 : IPADDR_INET6;
break;
case 'd':
debug++;
nofork = 1;
system_log = 0;
break;
case 'f':
conf_file = optarg;
break;
case 'F':
scfilter_level = parse_int_arg(optarg);
break;
case 'l':
log_file = optarg;
break;
case 'L':
log_severity = parse_int_arg(optarg);
break;
case 'm':
lock_memory = 1;
break;
case 'n':
nofork = 1;
break;
case 'p':
print_config = 1;
user_check = 0;
nofork = 1;
system_log = 0;
log_severity = LOGS_WARN;
break;
case 'P':
sched_priority = parse_int_arg(optarg);
break;
case 'q':
ref_mode = REF_ModeUpdateOnce;
nofork = 1;
client_only = 0;
system_log = 0;
break;
case 'Q':
ref_mode = REF_ModePrintOnce;
nofork = 1;
client_only = 1;
user_check = 0;
clock_control = 0;
system_log = 0;
break;
case 'r':
reload = 1;
break;
case 'R':
restarted = 1;
break;
case 's':
do_init_rtc = 1;
break;
case 't':
timeout = parse_int_arg(optarg);
break;
case 'u':
user = optarg;
break;
case 'U':
user_check = 0;
break;
case 'v':
print_version();
return 0;
case 'x':
clock_control = 0;
break;
default:
print_help(progname);
return opt != 'h';
}
}
if (user_check && getuid() != 0)
LOG_FATAL("Not superuser");
/* Initialise reusable file descriptors before fork */
SCK_PreInitialise();
/* Turn into a daemon */
if (!nofork) {
go_daemon();
}
if (system_log) {
if (log_file) {
LOG_OpenFileLog(log_file);
} else if (system_log) {
LOG_OpenSystemLog();
}
LOG_SetDebugLevel(debug);
LOG_SetMinSeverity(debug >= 2 ? LOGS_DEBUG : log_severity);
LOG(LOGS_INFO, LOGF_Main, "chronyd version %s starting (%s)",
CHRONY_VERSION, CHRONYD_FEATURES);
LOG(LOGS_INFO, "chronyd version %s starting (%s)", CHRONY_VERSION, CHRONYD_FEATURES);
DNS_SetAddressFamily(address_family);
CNF_Initialise(restarted);
CNF_Initialise(restarted, client_only);
if (print_config)
CNF_EnablePrint();
/* Parse the config file or the remaining command line arguments */
config_args = argc - optind;
if (!config_args) {
CNF_ReadFile(conf_file);
} else {
do {
CNF_ParseLine(NULL, config_args - argc + 1, *argv);
} while (++argv, --argc);
for (; optind < argc; optind++)
CNF_ParseLine(NULL, config_args + optind - argc + 1, argv[optind]);
}
/* Check whether another chronyd may already be running. Do this after
* forking, so that message logging goes to the right place (i.e. syslog), in
* case this chronyd is being run from a boot script. */
if (maybe_another_chronyd_running(&other_pid)) {
LOG_FATAL(LOGF_Main, "Another chronyd may already be running (pid=%d), check lockfile (%s)",
other_pid, CNF_GetPidFile());
}
if (print_config)
return 0;
/* Write our lockfile to prevent other chronyds running. This has *GOT* to
* be done *AFTER* the daemon-creation fork() */
write_lockfile();
/* Check whether another chronyd may already be running */
check_pidfile();
if (!user)
user = CNF_GetUser();
pw = getpwnam(user);
if (!pw)
LOG_FATAL("Could not get user/group ID of %s", user);
/* Create directories for sockets, log files, and dump files */
CNF_CreateDirs(pw->pw_uid, pw->pw_gid);
/* Write our pidfile to prevent other instances from running */
write_pidfile();
PRV_Initialise();
LCL_Initialise();
SCH_Initialise();
SYS_Initialise();
SCK_Initialise(address_family);
/* Start helper processes if needed */
NKS_PreInitialise(pw->pw_uid, pw->pw_gid, scfilter_level);
SYS_Initialise(clock_control);
RTC_Initialise(do_init_rtc);
SRC_Initialise();
RCL_Initialise();
KEY_Initialise();
/* Open privileged ports before dropping root */
CAM_Initialise(address_family);
NIO_Initialise(address_family);
CAM_Initialise();
NIO_Initialise();
NCR_Initialise();
CNF_SetupAccessRestrictions();
@@ -523,24 +644,23 @@ int main
SYS_LockMemory();
}
if (!user) {
user = CNF_GetUser();
/* 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_MAIN_PROCESS);
/* Warn if missing read access or having write access to keys */
CNF_CheckReadOnlyAccess();
}
if ((pw = getpwnam(user)) == NULL)
LOG_FATAL(LOGF_Main, "Could not get %s uid/gid", user);
/* Create all directories before dropping root */
CNF_CreateDirs(pw->pw_uid, pw->pw_gid);
/* Drop root privileges if the user has non-zero uid or gid */
if (pw->pw_uid || pw->pw_gid)
SYS_DropRoot(pw->pw_uid, pw->pw_gid);
if (!geteuid())
LOG(LOGS_WARN, "Running with root privileges");
REF_Initialise();
SST_Initialise();
NSR_Initialise();
NSD_Initialise();
NNS_Initialise();
NKS_Initialise();
CLG_Initialise();
MNL_Initialise();
TMC_Initialise();
@@ -549,12 +669,12 @@ int main
/* From now on, it is safe to do finalisation on exit */
initialised = 1;
UTI_SetQuitSignalsHandler(signal_cleanup);
UTI_SetQuitSignalsHandler(signal_cleanup, 1);
CAM_OpenUnixSocket();
if (scfilter_level)
SYS_EnableSystemCallFilter(scfilter_level);
SYS_EnableSystemCallFilter(scfilter_level, SYS_MAIN_PROCESS);
if (ref_mode == REF_ModeNormal && CNF_GetInitSources() > 0) {
ref_mode = REF_ModeInitStepSlew;
@@ -563,7 +683,7 @@ int main
REF_SetModeEndHandler(reference_mode_end);
REF_SetMode(ref_mode);
if (timeout)
if (timeout >= 0)
SCH_AddTimeoutByDelay(timeout, quit_timeout, NULL);
if (do_init_rtc) {
@@ -576,7 +696,7 @@ int main
the scheduler. */
SCH_MainLoop();
LOG(LOGS_INFO, LOGF_Main, "chronyd exiting");
LOG(LOGS_INFO, "chronyd exiting");
MAI_CleanupAndExit();

View File

@@ -36,8 +36,6 @@ cd RELEASES/$subdir || exit 1
echo $version > version.txt
sed -i -e "s%@@VERSION@@%${version}%" examples/chrony.spec
./configure && make -C doc man txt || exit 1
iconv -f utf-8 -t ascii//TRANSLIT < doc/installation.txt > INSTALL

View File

@@ -92,12 +92,14 @@ MNL_Initialise(void)
void
MNL_Finalise(void)
{
LCL_RemoveParameterChangeHandler(slew_samples, NULL);
}
/* ================================================== */
static void
estimate_and_set_system(struct timespec *now, int offset_provided, double offset, long *offset_cs, double *dfreq_ppm, double *new_afreq_ppm)
estimate_and_set_system(struct timespec *now, int offset_provided, double offset,
double *reg_offset, double *dfreq_ppm, double *new_afreq_ppm)
{
double agos[MAX_SAMPLES], offsets[MAX_SAMPLES];
double b0, b1;
@@ -108,32 +110,26 @@ estimate_and_set_system(struct timespec *now, int offset_provided, double offset
int found_freq;
double slew_by;
b0 = offset_provided ? offset : 0.0;
b1 = freq = 0.0;
found_freq = 0;
if (n_samples > 1) {
for (i=0; i<n_samples; i++) {
agos[i] = UTI_DiffTimespecsToDouble(&samples[n_samples - 1].when, &samples[i].when);
offsets[i] = samples[i].offset;
}
RGR_FindBestRobustRegression(agos, offsets, n_samples,
1.0e-8, /* 0.01ppm easily good enough for this! */
&b0, &b1, &n_runs, &best_start);
/* Ignore b0 from regression; treat offset as being the most
recently entered value. (If the administrator knows he's put
an outlier in, he will rerun the settime operation.) However,
the frequency estimate comes from the regression. */
freq = -b1;
found_freq = 1;
} else {
if (offset_provided) {
b0 = offset;
} else {
b0 = 0.0;
if (RGR_FindBestRobustRegression(agos, offsets, n_samples, 1.0e-8,
&b0, &b1, &n_runs, &best_start)) {
/* Ignore b0 from regression; treat offset as being the most
recently entered value. (If the administrator knows he's put
an outlier in, he will rerun the settime operation.) However,
the frequency estimate comes from the regression. */
freq = -b1;
found_freq = 1;
}
b1 = freq = 0.0;
found_freq = 0;
} else {
agos[0] = 0.0;
offsets[0] = b0;
}
@@ -145,21 +141,20 @@ estimate_and_set_system(struct timespec *now, int offset_provided, double offset
}
if (found_freq) {
LOG(LOGS_INFO, LOGF_Manual,
"Making a frequency change of %.3f ppm and a slew of %.6f",
LOG(LOGS_INFO, "Making a frequency change of %.3f ppm and a slew of %.6f",
1.0e6 * freq, slew_by);
REF_SetManualReference(now,
slew_by,
freq, skew);
} else {
LOG(LOGS_INFO, LOGF_Manual, "Making a slew of %.6f", slew_by);
LOG(LOGS_INFO, "Making a slew of %.6f", slew_by);
REF_SetManualReference(now,
slew_by,
0.0, skew);
}
if (offset_cs) *offset_cs = (long)(0.5 + 100.0 * b0);
if (reg_offset) *reg_offset = b0;
if (dfreq_ppm) *dfreq_ppm = 1.0e6 * freq;
if (new_afreq_ppm) *new_afreq_ppm = LCL_ReadAbsoluteFrequency();
@@ -173,7 +168,7 @@ estimate_and_set_system(struct timespec *now, int offset_provided, double offset
/* ================================================== */
int
MNL_AcceptTimestamp(struct timespec *ts, long *offset_cs, double *dfreq_ppm, double *new_afreq_ppm)
MNL_AcceptTimestamp(struct timespec *ts, double *reg_offset, double *dfreq_ppm, double *new_afreq_ppm)
{
struct timespec now;
double offset, diff;
@@ -210,7 +205,7 @@ MNL_AcceptTimestamp(struct timespec *ts, long *offset_cs, double *dfreq_ppm, dou
samples[n_samples].orig_offset = offset;
++n_samples;
estimate_and_set_system(&now, 1, offset, offset_cs, dfreq_ppm, new_afreq_ppm);
estimate_and_set_system(&now, 1, offset, reg_offset, dfreq_ppm, new_afreq_ppm);
return 1;

View File

@@ -33,7 +33,7 @@
extern void MNL_Initialise(void);
extern void MNL_Finalise(void);
extern int MNL_AcceptTimestamp(struct timespec *ts, long *offset_cs, double *dfreq_ppm, double *new_afreq_ppm);
extern int MNL_AcceptTimestamp(struct timespec *ts, double *reg_offset, double *dfreq_ppm, double *new_afreq_ppm);
extern void MNL_Enable(void);
extern void MNL_Disable(void);

15
md5.c
View File

@@ -117,8 +117,7 @@ inline UINT4 ROTATE_LEFT(UINT4 x, int n)
/* The routine MD5Init initializes the message-digest context
mdContext. All fields are set to zero.
*/
void MD5Init (mdContext)
MD5_CTX *mdContext;
void MD5Init (MD5_CTX *mdContext)
{
mdContext->i[0] = mdContext->i[1] = (UINT4)0;
@@ -134,10 +133,7 @@ MD5_CTX *mdContext;
account for the presence of each of the characters inBuf[0..inLen-1]
in the message whose digest is being computed.
*/
void MD5Update (mdContext, inBuf, inLen)
MD5_CTX *mdContext;
unsigned const char *inBuf;
unsigned int inLen;
void MD5Update (MD5_CTX *mdContext, unsigned const char *inBuf, unsigned int inLen)
{
UINT4 in[16];
int mdi;
@@ -173,8 +169,7 @@ unsigned int inLen;
ends with the desired message digest in mdContext->digest[0...15].
*/
void MD5Final (mdContext)
MD5_CTX *mdContext;
void MD5Final (MD5_CTX *mdContext)
{
UINT4 in[16];
int mdi;
@@ -214,9 +209,7 @@ MD5_CTX *mdContext;
/* Basic MD5 step. Transforms buf based on in.
*/
static void Transform (buf, in)
UINT4 *buf;
UINT4 *in;
static void Transform (UINT4 *buf, UINT4 *in)
{
UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2014
* Copyright (C) Miroslav Lichvar 2014, 2017
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -37,7 +37,7 @@ Malloc(size_t size)
r = malloc(size);
if (!r && size)
LOG_FATAL(LOGF_Memory, "Could not allocate memory");
LOG_FATAL("Could not allocate memory");
return r;
}
@@ -47,13 +47,44 @@ Realloc(void *ptr, size_t size)
{
void *r;
if (size == 0) {
Free(ptr);
return NULL;
}
r = realloc(ptr, size);
if (!r && size)
LOG_FATAL(LOGF_Memory, "Could not allocate memory");
if (!r)
LOG_FATAL("Could not allocate memory");
return r;
}
static size_t
get_array_size(size_t nmemb, size_t size)
{
size_t array_size;
array_size = nmemb * size;
/* Check for overflow */
if (nmemb > 0 && array_size / nmemb != size)
LOG_FATAL("Could not allocate memory");
return array_size;
}
void *
Malloc2(size_t nmemb, size_t size)
{
return Malloc(get_array_size(nmemb, size));
}
void *
Realloc2(void *ptr, size_t nmemb, size_t size)
{
return Realloc(ptr, get_array_size(nmemb, size));
}
char *
Strdup(const char *s)
{
@@ -61,7 +92,7 @@ Strdup(const char *s)
r = strdup(s);
if (!r)
LOG_FATAL(LOGF_Memory, "Could not allocate memory");
LOG_FATAL("Could not allocate memory");
return r;
}

View File

@@ -27,15 +27,19 @@
#ifndef GOT_MEMORY_H
#define GOT_MEMORY_H
#include "sysincl.h"
/* Wrappers checking for errors */
extern void *Malloc(size_t size);
extern void *Realloc(void *ptr, size_t size);
extern void *Malloc2(size_t nmemb, size_t size);
extern void *Realloc2(void *ptr, size_t nmemb, size_t size);
extern char *Strdup(const char *s);
/* Convenient macros */
#define MallocNew(T) ((T *) Malloc(sizeof(T)))
#define MallocArray(T, n) ((T *) Malloc((n) * sizeof(T)))
#define ReallocArray(T,n,x) ((T *) Realloc((void *)(x), (n)*sizeof(T)))
#define MallocArray(T, n) ((T *) Malloc2(n, sizeof(T)))
#define ReallocArray(T, n, x) ((T *) Realloc2((void *)(x), n, sizeof(T)))
#define Free(x) free(x)
#endif /* GOT_MEMORY_H */

View File

@@ -30,7 +30,11 @@
#include "sysincl.h"
#include <netdb.h>
#include <resolv.h>
#include "nameserv.h"
#include "socket.h"
#include "util.h"
/* ================================================== */
@@ -46,15 +50,39 @@ 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));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
switch (address_family) {
case IPADDR_INET4:
hints.ai_family = AF_INET;
break;
#ifdef FEAT_IPV6
case IPADDR_INET6:
hints.ai_family = AF_INET6;
break;
#endif
default:
hints.ai_family = AF_UNSPEC;
}
hints.ai_socktype = SOCK_DGRAM;
result = getaddrinfo(name, NULL, &hints, &res);
@@ -79,6 +107,9 @@ DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
case AF_INET6:
if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET6)
continue;
/* Don't return an address that would lose a scope ID */
if (((struct sockaddr_in6 *)ai->ai_addr)->sin6_scope_id != 0)
continue;
ip_addrs[i].family = IPADDR_INET6;
memcpy(&ip_addrs[i].addr.in6, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr.s6_addr,
sizeof (ip_addrs->addr.in6));
@@ -88,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
}
/* ================================================== */
@@ -138,35 +130,21 @@ 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];
slen = UTI_IPAndPortToSockaddr(ip_addr, 0, (struct sockaddr *)&in6);
if (!getnameinfo((struct sockaddr *)&in6, slen, hbuf, sizeof (hbuf), NULL, 0, 0))
result = hbuf;
#else
struct hostent *host;
uint32_t addr;
ip_saddr.ip_addr = *ip_addr;
ip_saddr.port = 0;
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
slen = SCK_IPSockAddrToSockaddr(&ip_saddr, (struct sockaddr *)&saddr, sizeof (saddr));
if (!getnameinfo((struct sockaddr *)&saddr, slen, hbuf, sizeof (hbuf), NULL, 0, 0))
result = hbuf;
if (result == NULL)
result = UTI_IPToString(ip_addr);

View File

@@ -51,7 +51,7 @@ struct DNS_Async_Instance {
int pipe[2];
};
static int resolving_threads = 0;
static pthread_mutex_t privops_lock = PTHREAD_MUTEX_INITIALIZER;
/* ================================================== */
@@ -60,7 +60,9 @@ start_resolving(void *anything)
{
struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything;
pthread_mutex_lock(&privops_lock);
inst->status = PRV_Name2IPAddress(inst->name, inst->addresses, DNS_MAX_ADDRESSES);
pthread_mutex_unlock(&privops_lock);
/* Notify the main thread that the result is ready */
if (write(inst->pipe[1], "", 1) < 0)
@@ -78,11 +80,9 @@ end_resolving(int fd, int event, void *anything)
int i;
if (pthread_join(inst->thread, NULL)) {
LOG_FATAL(LOGF_Nameserv, "pthread_join() failed");
LOG_FATAL("pthread_join() failed");
}
resolving_threads--;
SCH_RemoveFileHandler(inst->pipe[0]);
close(inst->pipe[0]);
close(inst->pipe[1]);
@@ -110,17 +110,14 @@ DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *
inst->status = DNS_Failure;
if (pipe(inst->pipe)) {
LOG_FATAL(LOGF_Nameserv, "pipe() failed");
LOG_FATAL("pipe() failed");
}
UTI_FdSetCloexec(inst->pipe[0]);
UTI_FdSetCloexec(inst->pipe[1]);
resolving_threads++;
assert(resolving_threads <= 1);
if (pthread_create(&inst->thread, NULL, start_resolving, inst)) {
LOG_FATAL(LOGF_Nameserv, "pthread_create() failed");
LOG_FATAL("pthread_create() failed");
}
SCH_AddFileHandler(inst->pipe[0], SCH_FILE_INPUT, end_resolving, inst);

119
ntp.h
View File

@@ -38,24 +38,30 @@ typedef struct {
typedef uint32_t NTP_int32;
/* The UDP port number used by NTP */
#define NTP_PORT 123
/* The NTP protocol version that we support */
#define NTP_VERSION 4
/* Maximum stratum number (infinity) */
#define NTP_MAX_STRATUM 16
/* The minimum valid length of an extension field */
#define NTP_MIN_EXTENSION_LENGTH 16
/* The maximum assumed length of all extension fields in received
packets (RFC 5905 doesn't specify a limit on length or number of
extension fields in one packet) */
#define NTP_MAX_EXTENSIONS_LENGTH 1024
/* Invalid stratum number */
#define NTP_INVALID_STRATUM 0
/* The minimum and maximum supported length of MAC */
#define NTP_MIN_MAC_LENGTH (4 + 16)
#define NTP_MAX_MAC_LENGTH (4 + MAX_HASH_LENGTH)
/* The minimum valid length of an extension field */
#define NTP_MIN_EF_LENGTH 16
/* The maximum assumed length of all extension fields in an NTP packet,
including a MAC (RFC 5905 doesn't specify a limit on length or number of
extension fields in one packet) */
#define NTP_MAX_EXTENSIONS_LENGTH (1024 + NTP_MAX_MAC_LENGTH)
/* The maximum length of MAC in NTPv4 packets which allows deterministic
parsing of extension fields (RFC 7822) */
#define NTP_MAX_V4_MAC_LENGTH (4 + 20)
@@ -90,21 +96,10 @@ typedef struct {
NTP_int64 receive_ts;
NTP_int64 transmit_ts;
/* Optional extension fields, we don't send packets with them yet */
/* uint8_t extensions[] */
/* Optional message authentication code (MAC) */
NTP_int32 auth_keyid;
uint8_t auth_data[NTP_MAX_MAC_LENGTH - 4];
uint8_t extensions[NTP_MAX_EXTENSIONS_LENGTH];
} NTP_Packet;
#define NTP_NORMAL_PACKET_LENGTH (int)offsetof(NTP_Packet, auth_keyid)
/* The buffer used to hold a datagram read from the network */
typedef struct {
NTP_Packet ntp_pkt;
uint8_t extensions[NTP_MAX_EXTENSIONS_LENGTH];
} NTP_Receive_Buffer;
#define NTP_HEADER_LENGTH (int)offsetof(NTP_Packet, extensions)
/* Macros to work with the lvm field */
#define NTP_LVM_TO_LEAP(lvm) (((lvm) >> 6) & 0x3)
@@ -118,4 +113,88 @@ typedef struct {
#define NTP_REFID_LOCAL 0x7F7F0101UL /* 127.127.1.1 */
#define NTP_REFID_SMOOTH 0x7F7F01FFUL /* 127.127.1.255 */
/* Non-authentication extension fields and corresponding internal flags */
#define NTP_EF_EXP_MONO_ROOT 0xF323
#define NTP_EF_EXP_NET_CORRECTION 0xF324
#define NTP_EF_FLAG_EXP_MONO_ROOT 0x1
#define NTP_EF_FLAG_EXP_NET_CORRECTION 0x2
/* Pre-NTPv5 experimental extension field */
typedef struct {
uint32_t magic;
NTP_int32 root_delay;
NTP_int32 root_dispersion;
NTP_int64 mono_receive_ts;
uint32_t mono_epoch;
} NTP_EFExpMonoRoot;
#define NTP_EF_EXP_MONO_ROOT_MAGIC 0xF5BEDD9AU
/* Experimental extension field to provide PTP corrections */
typedef struct {
uint32_t magic;
NTP_int64 correction;
uint32_t reserved[3];
} NTP_EFExpNetCorrection;
#define NTP_EF_EXP_NET_CORRECTION_MAGIC 0x07AC2CEBU
/* Authentication extension fields */
#define NTP_EF_NTS_UNIQUE_IDENTIFIER 0x0104
#define NTP_EF_NTS_COOKIE 0x0204
#define NTP_EF_NTS_COOKIE_PLACEHOLDER 0x0304
#define NTP_EF_NTS_AUTH_AND_EEF 0x0404
/* Enumeration for authentication modes of NTP packets */
typedef enum {
NTP_AUTH_NONE = 0, /* No authentication */
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 8915) */
} NTP_AuthMode;
/* Structure describing an NTP packet */
typedef struct {
int length;
int version;
NTP_Mode mode;
int ext_fields;
int ext_field_flags;
struct {
NTP_AuthMode mode;
struct {
int start;
int length;
uint32_t key_id;
} mac;
} auth;
} NTP_PacketInfo;
/* Structure used to save NTP measurements. time is the local time at which
the sample is to be considered to have been made and offset is the offset at
the time (positive indicates that the local clock is slow relative to the
source). root_delay/root_dispersion include peer_delay/peer_dispersion. */
typedef struct {
struct timespec time;
double offset;
double peer_delay;
double peer_dispersion;
double root_delay;
double root_dispersion;
} NTP_Sample;
/* Possible sources of timestamps */
typedef enum {
NTP_TS_DAEMON = 0,
NTP_TS_KERNEL,
NTP_TS_HARDWARE
} NTP_Timestamp_Source;
#endif /* GOT_NTP_H */

386
ntp_auth.c Normal file
View File

@@ -0,0 +1,386 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
NTP authentication
*/
#include "config.h"
#include "sysincl.h"
#include "keys.h"
#include "logging.h"
#include "memory.h"
#include "ntp_auth.h"
#include "ntp_signd.h"
#include "nts_ntp.h"
#include "nts_ntp_client.h"
#include "nts_ntp_server.h"
#include "srcparams.h"
#include "util.h"
/* Structure to hold authentication configuration and state */
struct NAU_Instance_Record {
NTP_AuthMode mode; /* Authentication mode of NTP packets */
uint32_t key_id; /* Identifier of a symmetric key */
NNC_Instance nts; /* Client NTS state */
};
/* ================================================== */
static int
generate_symmetric_auth(uint32_t key_id, NTP_Packet *packet, NTP_PacketInfo *info)
{
int auth_len, max_auth_len;
if (info->length + NTP_MIN_MAC_LENGTH > sizeof (*packet)) {
DEBUG_LOG("Packet too long");
return 0;
}
/* Truncate long MACs in NTPv4 packets to allow deterministic parsing
of extension fields (RFC 7822) */
max_auth_len = (info->version == 4 ? NTP_MAX_V4_MAC_LENGTH : NTP_MAX_MAC_LENGTH) - 4;
max_auth_len = MIN(max_auth_len, sizeof (*packet) - info->length - 4);
auth_len = KEY_GenerateAuth(key_id, packet, info->length,
(unsigned char *)packet + info->length + 4, max_auth_len);
if (auth_len < NTP_MIN_MAC_LENGTH - 4) {
DEBUG_LOG("Could not generate auth data with key %"PRIu32, key_id);
return 0;
}
*(uint32_t *)((unsigned char *)packet + info->length) = htonl(key_id);
info->auth.mac.start = info->length;
info->auth.mac.length = 4 + auth_len;
info->auth.mac.key_id = key_id;
info->length += info->auth.mac.length;
return 1;
}
/* ================================================== */
static int
check_symmetric_auth(NTP_Packet *packet, NTP_PacketInfo *info)
{
int trunc_len;
if (info->auth.mac.length < NTP_MIN_MAC_LENGTH)
return 0;
trunc_len = info->version == 4 && info->auth.mac.length <= NTP_MAX_V4_MAC_LENGTH ?
NTP_MAX_V4_MAC_LENGTH : NTP_MAX_MAC_LENGTH;
if (!KEY_CheckAuth(info->auth.mac.key_id, packet, info->auth.mac.start,
(unsigned char *)packet + info->auth.mac.start + 4,
info->auth.mac.length - 4, trunc_len - 4))
return 0;
return 1;
}
/* ================================================== */
static NAU_Instance
create_instance(NTP_AuthMode mode)
{
NAU_Instance instance;
instance = MallocNew(struct NAU_Instance_Record);
instance->mode = mode;
instance->key_id = INACTIVE_AUTHKEY;
instance->nts = NULL;
assert(sizeof (instance->key_id) == 4);
return instance;
}
/* ================================================== */
NAU_Instance
NAU_CreateNoneInstance(void)
{
return create_instance(NTP_AUTH_NONE);
}
/* ================================================== */
NAU_Instance
NAU_CreateSymmetricInstance(uint32_t key_id)
{
NAU_Instance instance = create_instance(NTP_AUTH_SYMMETRIC);
instance->key_id = key_id;
if (!KEY_KeyKnown(key_id))
LOG(LOGS_WARN, "Key %"PRIu32" is %s", key_id, "missing");
else if (!KEY_CheckKeyLength(key_id))
LOG(LOGS_WARN, "Key %"PRIu32" is %s", key_id, "too short");
return instance;
}
/* ================================================== */
NAU_Instance
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, cert_set, ntp_port);
return instance;
}
/* ================================================== */
void
NAU_DestroyInstance(NAU_Instance instance)
{
if (instance->mode == NTP_AUTH_NTS)
NNC_DestroyInstance(instance->nts);
Free(instance);
}
/* ================================================== */
int
NAU_IsAuthEnabled(NAU_Instance instance)
{
return instance->mode != NTP_AUTH_NONE;
}
/* ================================================== */
int
NAU_GetSuggestedNtpVersion(NAU_Instance instance)
{
/* If the MAC in NTPv4 packets would be truncated, prefer NTPv3 for
compatibility with older chronyd servers */
if (instance->mode == NTP_AUTH_SYMMETRIC &&
KEY_GetAuthLength(instance->key_id) + sizeof (instance->key_id) > NTP_MAX_V4_MAC_LENGTH)
return 3;
return NTP_VERSION;
}
/* ================================================== */
int
NAU_PrepareRequestAuth(NAU_Instance instance)
{
switch (instance->mode) {
case NTP_AUTH_NTS:
if (!NNC_PrepareForAuth(instance->nts))
return 0;
break;
default:
break;
}
return 1;
}
/* ================================================== */
int
NAU_GenerateRequestAuth(NAU_Instance instance, NTP_Packet *request, NTP_PacketInfo *info)
{
switch (instance->mode) {
case NTP_AUTH_NONE:
break;
case NTP_AUTH_SYMMETRIC:
if (!generate_symmetric_auth(instance->key_id, request, info))
return 0;
break;
case NTP_AUTH_NTS:
if (!NNC_GenerateRequestAuth(instance->nts, request, info))
return 0;
break;
default:
assert(0);
}
info->auth.mode = instance->mode;
return 1;
}
/* ================================================== */
int
NAU_CheckRequestAuth(NTP_Packet *request, NTP_PacketInfo *info, uint32_t *kod)
{
*kod = 0;
switch (info->auth.mode) {
case NTP_AUTH_NONE:
break;
case NTP_AUTH_SYMMETRIC:
if (!check_symmetric_auth(request, info))
return 0;
break;
case NTP_AUTH_MSSNTP:
/* MS-SNTP requests are not authenticated */
break;
case NTP_AUTH_MSSNTP_EXT:
/* Not supported yet */
return 0;
case NTP_AUTH_NTS:
if (!NNS_CheckRequestAuth(request, info, kod))
return 0;
break;
default:
return 0;
}
return 1;
}
/* ================================================== */
int
NAU_GenerateResponseAuth(NTP_Packet *request, NTP_PacketInfo *request_info,
NTP_Packet *response, NTP_PacketInfo *response_info,
NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
uint32_t kod)
{
switch (request_info->auth.mode) {
case NTP_AUTH_NONE:
break;
case NTP_AUTH_SYMMETRIC:
if (!generate_symmetric_auth(request_info->auth.mac.key_id, response, response_info))
return 0;
break;
case NTP_AUTH_MSSNTP:
/* Sign the packet asynchronously by ntp_signd */
if (!NSD_SignAndSendPacket(request_info->auth.mac.key_id, response, response_info,
remote_addr, local_addr))
return 0;
/* Don't send the original packet */
return 0;
case NTP_AUTH_NTS:
if (!NNS_GenerateResponseAuth(request, request_info, response, response_info, kod))
return 0;
break;
default:
DEBUG_LOG("Could not authenticate response auth_mode=%d", (int)request_info->auth.mode);
return 0;
}
response_info->auth.mode = request_info->auth.mode;
return 1;
}
/* ================================================== */
int
NAU_CheckResponseAuth(NAU_Instance instance, NTP_Packet *response, NTP_PacketInfo *info)
{
/* The authentication must match the expected mode */
if (info->auth.mode != instance->mode)
return 0;
switch (info->auth.mode) {
case NTP_AUTH_NONE:
break;
case NTP_AUTH_SYMMETRIC:
/* Check if it is authenticated with the specified key */
if (info->auth.mac.key_id != instance->key_id)
return 0;
/* and that the MAC is valid */
if (!check_symmetric_auth(response, info))
return 0;
break;
case NTP_AUTH_NTS:
if (!NNC_CheckResponseAuth(instance->nts, response, info))
return 0;
break;
default:
return 0;
}
return 1;
}
/* ================================================== */
void
NAU_ChangeAddress(NAU_Instance instance, IPAddr *address)
{
switch (instance->mode) {
case NTP_AUTH_NONE:
case NTP_AUTH_SYMMETRIC:
break;
case NTP_AUTH_NTS:
NNC_ChangeAddress(instance->nts, address);
break;
default:
assert(0);
}
}
/* ================================================== */
void
NAU_DumpData(NAU_Instance instance)
{
switch (instance->mode) {
case NTP_AUTH_NTS:
NNC_DumpData(instance->nts);
break;
default:
break;
}
}
/* ================================================== */
void
NAU_GetReport(NAU_Instance instance, RPT_AuthReport *report)
{
memset(report, 0, sizeof (*report));
report->mode = instance->mode;
report->last_ke_ago = -1;
switch (instance->mode) {
case NTP_AUTH_NONE:
break;
case NTP_AUTH_SYMMETRIC:
report->key_id = instance->key_id;
KEY_GetKeyInfo(instance->key_id, &report->key_type, &report->key_length);
break;
case NTP_AUTH_NTS:
NNC_GetReport(instance->nts, report);
break;
default:
assert(0);
}
}

84
ntp_auth.h Normal file
View File

@@ -0,0 +1,84 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2019
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Header file for NTP authentication
*/
#ifndef GOT_NTP_AUTH_H
#define GOT_NTP_AUTH_H
#include "addressing.h"
#include "ntp.h"
#include "reports.h"
typedef struct NAU_Instance_Record *NAU_Instance;
/* Create an authenticator instance in a specific mode */
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,
uint32_t cert_set, uint16_t ntp_port);
/* Destroy an instance */
extern void NAU_DestroyInstance(NAU_Instance instance);
/* Check if an instance is not in the None mode */
extern int NAU_IsAuthEnabled(NAU_Instance instance);
/* Get NTP version recommended for better compatibility */
extern int NAU_GetSuggestedNtpVersion(NAU_Instance instance);
/* Perform operations necessary for NAU_GenerateRequestAuth() */
extern int NAU_PrepareRequestAuth(NAU_Instance instance);
/* Extend a request with data required by the authentication mode */
extern int NAU_GenerateRequestAuth(NAU_Instance instance, NTP_Packet *request,
NTP_PacketInfo *info);
/* Verify that a request is authentic. If it is not authentic and a non-zero
kod code is returned, a KoD response should be sent back. */
extern int NAU_CheckRequestAuth(NTP_Packet *request, NTP_PacketInfo *info, uint32_t *kod);
/* Extend a response with data required by the authentication mode. This
function can be called only if the previous call of NAU_CheckRequestAuth()
was on the same request. */
extern int NAU_GenerateResponseAuth(NTP_Packet *request, NTP_PacketInfo *request_info,
NTP_Packet *response, NTP_PacketInfo *response_info,
NTP_Remote_Address *remote_addr,
NTP_Local_Address *local_addr,
uint32_t kod);
/* Verify that a response is authentic */
extern int NAU_CheckResponseAuth(NAU_Instance instance, NTP_Packet *response,
NTP_PacketInfo *info);
/* Change an authentication-specific address (e.g. after replacing a source) */
extern void NAU_ChangeAddress(NAU_Instance instance, IPAddr *address);
/* Save authentication-specific data to speed up the next start */
extern void NAU_DumpData(NAU_Instance instance);
/* Provide a report about the current authentication state */
extern void NAU_GetReport(NAU_Instance instance, RPT_AuthReport *report);
#endif

2229
ntp_core.c

File diff suppressed because it is too large Load Diff

View File

@@ -38,16 +38,12 @@ typedef enum {
NTP_SERVER, NTP_PEER
} NTP_Source_Type;
typedef enum {
NTP_TS_DAEMON = 0,
NTP_TS_KERNEL,
NTP_TS_HARDWARE
} NTP_Timestamp_Source;
typedef struct {
struct timespec ts;
double err;
NTP_Timestamp_Source source;
double rx_duration;
double net_correction;
} NTP_Local_Timestamp;
/* This is a private data type used for storing the instance record for
@@ -59,7 +55,8 @@ extern void NCR_Initialise(void);
extern void NCR_Finalise(void);
/* Get a new instance for a server or peer */
extern NCR_Instance NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params);
extern NCR_Instance NCR_CreateInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type,
SourceParameters *params, const char *name);
/* Destroy an instance */
extern void NCR_DestroyInstance(NCR_Instance instance);
@@ -74,7 +71,8 @@ extern void NCR_ResetInstance(NCR_Instance inst);
extern void NCR_ResetPoll(NCR_Instance instance);
/* Change the remote address of an instance */
extern void NCR_ChangeRemoteAddress(NCR_Instance inst, NTP_Remote_Address *remote_addr);
extern void NCR_ChangeRemoteAddress(NCR_Instance inst, NTP_Remote_Address *remote_addr,
int ntp_only);
/* This routine is called when a new packet arrives off the network,
and it relates to a source we have an ongoing protocol exchange with */
@@ -99,12 +97,9 @@ extern void NCR_ProcessTxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Addr
/* Slew receive and transmit times in instance records */
extern void NCR_SlewTimes(NCR_Instance inst, struct timespec *when, double dfreq, double doffset);
/* Take a particular source online (i.e. start sampling it) */
extern void NCR_TakeSourceOnline(NCR_Instance inst);
/* Take a particular source offline (i.e. stop sampling it, without
marking it unreachable in the source selection stuff) */
extern void NCR_TakeSourceOffline(NCR_Instance inst);
/* Take a particular source online (i.e. start sampling it) or offline
(i.e. stop sampling it) */
extern void NCR_SetConnectivity(NCR_Instance inst, SRC_Connectivity connectivity);
extern void NCR_ModifyMinpoll(NCR_Instance inst, int new_minpoll);
@@ -123,6 +118,7 @@ extern void NCR_ModifyPolltarget(NCR_Instance inst, int new_poll_target);
extern void NCR_InitiateSampleBurst(NCR_Instance inst, int n_good_samples, int n_total_samples);
extern void NCR_ReportSource(NCR_Instance inst, RPT_SourceReport *report, struct timespec *now);
extern void NCR_GetAuthReport(NCR_Instance inst, RPT_AuthReport *report);
extern void NCR_GetNTPReport(NCR_Instance inst, RPT_NTPReport *report);
extern int NCR_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all);
@@ -137,6 +133,8 @@ extern uint32_t NCR_GetLocalRefid(NCR_Instance inst);
extern int NCR_IsSyncPeer(NCR_Instance instance);
extern void NCR_AddBroadcastDestination(IPAddr *addr, unsigned short port, int interval);
extern void NCR_DumpAuthData(NCR_Instance inst);
extern void NCR_AddBroadcastDestination(NTP_Remote_Address *addr, int interval);
#endif /* GOT_NTP_CORE_H */

192
ntp_ext.c Normal file
View File

@@ -0,0 +1,192 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Functions for adding and parsing NTPv4 extension fields
*/
#include "config.h"
#include "sysincl.h"
#include "ntp_ext.h"
struct ExtFieldHeader {
uint16_t type;
uint16_t length;
};
/* ================================================== */
static int
format_field(unsigned char *buffer, int buffer_length, int start,
int type, int body_length, int *length, void **body)
{
struct ExtFieldHeader *header;
if (buffer_length < 0 || start < 0 || buffer_length <= start ||
buffer_length - start < sizeof (*header) || start % 4 != 0)
return 0;
header = (struct ExtFieldHeader *)(buffer + start);
if (body_length < 0 || sizeof (*header) + body_length > 0xffff ||
start + sizeof (*header) + body_length > buffer_length || body_length % 4 != 0)
return 0;
header->type = htons(type);
header->length = htons(sizeof (*header) + body_length);
*length = sizeof (*header) + body_length;
*body = header + 1;
return 1;
}
/* ================================================== */
int
NEF_SetField(unsigned char *buffer, int buffer_length, int start,
int type, void *body, int body_length, int *length)
{
void *ef_body;
if (!format_field(buffer, buffer_length, start, type, body_length, length, &ef_body))
return 0;
memcpy(ef_body, body, body_length);
return 1;
}
/* ================================================== */
int
NEF_AddBlankField(NTP_Packet *packet, NTP_PacketInfo *info, int type, int body_length, void **body)
{
int ef_length, length = info->length;
if (length < NTP_HEADER_LENGTH || length >= sizeof (*packet) || length % 4 != 0)
return 0;
/* Only NTPv4 packets can have extension fields */
if (info->version != 4)
return 0;
if (!format_field((unsigned char *)packet, sizeof (*packet), length,
type, body_length, &ef_length, body))
return 0;
if (ef_length < NTP_MIN_EF_LENGTH)
return 0;
info->length += ef_length;
info->ext_fields++;
return 1;
}
/* ================================================== */
int
NEF_AddField(NTP_Packet *packet, NTP_PacketInfo *info,
int type, void *body, int body_length)
{
void *ef_body;
if (!NEF_AddBlankField(packet, info, type, body_length, &ef_body))
return 0;
memcpy(ef_body, body, body_length);
return 1;
}
/* ================================================== */
int
NEF_ParseSingleField(unsigned char *buffer, int buffer_length, int start,
int *length, int *type, void **body, int *body_length)
{
struct ExtFieldHeader *header;
int ef_length;
if (buffer_length < 0 || start < 0 || buffer_length <= start ||
buffer_length - start < sizeof (*header))
return 0;
header = (struct ExtFieldHeader *)(buffer + start);
assert(sizeof (*header) == 4);
ef_length = ntohs(header->length);
if (ef_length < (int)(sizeof (*header)) || start + ef_length > buffer_length ||
ef_length % 4 != 0)
return 0;
if (length)
*length = ef_length;
if (type)
*type = ntohs(header->type);
if (body)
*body = header + 1;
if (body_length)
*body_length = ef_length - sizeof (*header);
return 1;
}
/* ================================================== */
int
NEF_ParseField(NTP_Packet *packet, int packet_length, int start,
int *length, int *type, void **body, int *body_length)
{
int ef_length;
if (packet_length <= NTP_HEADER_LENGTH || packet_length > sizeof (*packet) ||
packet_length <= start || packet_length % 4 != 0 ||
start < NTP_HEADER_LENGTH || start % 4 != 0)
return 0;
/* Only NTPv4 packets have extension fields */
if (NTP_LVM_TO_VERSION(packet->lvm) != 4)
return 0;
/* Check if the remaining data is a MAC. RFC 7822 specifies the maximum
length of a MAC in NTPv4 packets in order to enable deterministic
parsing. */
if (packet_length - start <= NTP_MAX_V4_MAC_LENGTH)
return 0;
if (!NEF_ParseSingleField((unsigned char *)packet, packet_length, start,
&ef_length, type, body, body_length))
return 0;
if (ef_length < NTP_MIN_EF_LENGTH)
return 0;
if (length)
*length = ef_length;
return 1;
}

43
ntp_ext.h Normal file
View File

@@ -0,0 +1,43 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2019
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Header file for NTP extension fields
*/
#ifndef GOT_NTP_EXT_H
#define GOT_NTP_EXT_H
#include "ntp.h"
extern int NEF_SetField(unsigned char *buffer, int buffer_length, int start,
int type, void *body, int body_length, int *length);
extern int NEF_AddBlankField(NTP_Packet *packet, NTP_PacketInfo *info, int type,
int body_length, void **body);
extern int NEF_AddField(NTP_Packet *packet, NTP_PacketInfo *info,
int type, void *body, int body_length);
extern int NEF_ParseSingleField(unsigned char *buffer, int buffer_length, int start,
int *length, int *type, void **body, int *body_length);
extern int NEF_ParseField(NTP_Packet *packet, int packet_length, int start,
int *length, int *type, void **body, int *body_length);
#endif

831
ntp_io.c

File diff suppressed because it is too large Load Diff

View File

@@ -31,13 +31,17 @@
#include "ntp.h"
#include "addressing.h"
#include "socket.h"
/* Function to initialise the module. */
extern void NIO_Initialise(int family);
extern void NIO_Initialise(void);
/* Function to finalise the module */
extern void NIO_Finalise(void);
/* Function to check if HW timestamping is enabled on any interface */
extern int NIO_IsHwTsEnabled(void);
/* Function to obtain a socket for sending client packets */
extern int NIO_OpenClientSocket(NTP_Remote_Address *remote_addr);
@@ -53,6 +57,15 @@ extern void NIO_CloseServerSocket(int sock_fd);
/* Function to check if socket is a server socket */
extern int NIO_IsServerSocket(int sock_fd);
/* Function to check if a server socket is currently open */
extern int NIO_IsServerSocketOpen(void);
/* Function to check if client packets can be sent to a server */
extern int NIO_IsServerConnectable(NTP_Remote_Address *remote_addr);
/* Function to unwrap an NTP message from non-native transport (e.g. PTP) */
extern int NIO_UnwrapMessage(SCK_Message *message, int sock_fd, double *net_correction);
/* Function to transmit a packet */
extern int NIO_SendPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr,
NTP_Local_Address *local_addr, int length, int process_tx);

View File

@@ -2,7 +2,7 @@
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2016
* Copyright (C) Miroslav Lichvar 2016-2019, 2021-2023
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -29,10 +29,8 @@
#include "sysincl.h"
#include <ifaddrs.h>
#include <linux/errqueue.h>
#include <linux/ethtool.h>
#include <linux/net_tstamp.h>
#include <linux/ptp_clock.h>
#include <linux/sockios.h>
#include <net/if.h>
@@ -41,36 +39,44 @@
#include "hwclock.h"
#include "local.h"
#include "logging.h"
#include "memory.h"
#include "ntp_core.h"
#include "ntp_io.h"
#include "ntp_io_linux.h"
#include "ntp_sources.h"
#include "sched.h"
#include "socket.h"
#include "sys_linux.h"
#include "util.h"
union sockaddr_in46 {
struct sockaddr_in in4;
#ifdef FEAT_IPV6
struct sockaddr_in6 in6;
#endif
struct sockaddr u;
};
struct Interface {
char name[IF_NAMESIZE];
int if_index;
int phc_fd;
int phc_mode;
int phc_nocrossts;
/* Link speed in mbit/s */
int link_speed;
/* Start of UDP data at layer 2 for IPv4 and IPv6 */
int l2_udp4_ntp_start;
int l2_udp6_ntp_start;
/* Compensation of errors in TX and RX timestamping */
double tx_comp;
double rx_comp;
HCL_Instance clock;
int maxpoll;
SCH_TimeoutID poll_timeout_id;
};
/* Number of PHC readings per HW clock sample */
#define PHC_READINGS 10
#define PHC_READINGS 25
/* Minimum and maximum interval between PHC readings */
#define MIN_PHC_POLL -6
#define MAX_PHC_POLL 20
/* Maximum acceptable offset between SW/HW and daemon timestamp */
#define MAX_TS_DELAY 1.0
/* Array of Interfaces */
static ARR_Instance interfaces;
@@ -82,40 +88,52 @@ static int ts_tx_flags;
/* Flag indicating the socket options can't be changed in control messages */
static int permanent_ts_options;
/* Unbound socket keeping the kernel RX timestamping permanently enabled
in order to avoid a race condition between receiving a server response
and the kernel actually starting to timestamp received packets after
enabling the timestamping and sending a request */
static int dummy_rxts_socket;
#define INVALID_SOCK_FD -3
/* ================================================== */
static void poll_phc(struct Interface *iface, struct timespec *now);
/* ================================================== */
static int
add_interface(const char *name)
add_interface(CNF_HwTsInterface *conf_iface)
{
int sock_fd, if_index, minpoll, phc_fd, req_hwts_flags, rx_filter;
struct ethtool_ts_info ts_info;
struct hwtstamp_config ts_config;
struct ifreq req;
int sock_fd, if_index, phc_index, phc_fd;
unsigned int i;
struct Interface *iface;
char phc_path[64];
/* Check if the interface was not already added */
for (i = 0; i < ARR_GetSize(interfaces); i++) {
if (!strcmp(name, ((struct Interface *)ARR_GetElement(interfaces, i))->name))
if (!strcmp(conf_iface->name, ((struct Interface *)ARR_GetElement(interfaces, i))->name))
return 1;
}
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
if (sock_fd < 0)
return 0;
memset(&req, 0, sizeof (req));
memset(&ts_info, 0, sizeof (ts_info));
if (snprintf(req.ifr_name, sizeof (req.ifr_name), "%s", name) >= sizeof (req.ifr_name)) {
close(sock_fd);
if (snprintf(req.ifr_name, sizeof (req.ifr_name), "%s", conf_iface->name) >=
sizeof (req.ifr_name)) {
SCK_CloseSocket(sock_fd);
return 0;
}
if (ioctl(sock_fd, SIOCGIFINDEX, &req)) {
DEBUG_LOG(LOGF_NtpIOLinux, "ioctl(%s) failed : %s", "SIOCGIFINDEX", strerror(errno));
close(sock_fd);
DEBUG_LOG("ioctl(%s) failed : %s", "SIOCGIFINDEX", strerror(errno));
SCK_CloseSocket(sock_fd);
return 0;
}
@@ -125,50 +143,115 @@ add_interface(const char *name)
req.ifr_data = (char *)&ts_info;
if (ioctl(sock_fd, SIOCETHTOOL, &req)) {
DEBUG_LOG(LOGF_NtpIOLinux, "ioctl(%s) failed : %s", "SIOCETHTOOL", strerror(errno));
close(sock_fd);
DEBUG_LOG("ioctl(%s) failed : %s", "SIOCETHTOOL", strerror(errno));
SCK_CloseSocket(sock_fd);
return 0;
}
req_hwts_flags = SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE;
if ((ts_info.so_timestamping & req_hwts_flags) != req_hwts_flags) {
DEBUG_LOG("HW timestamping not supported on %s", req.ifr_name);
SCK_CloseSocket(sock_fd);
return 0;
}
if (ts_info.phc_index < 0) {
DEBUG_LOG("PHC missing on %s", req.ifr_name);
SCK_CloseSocket(sock_fd);
return 0;
}
switch (conf_iface->rxfilter) {
case CNF_HWTS_RXFILTER_ANY:
#ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP
if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_NTP_ALL))
rx_filter = HWTSTAMP_FILTER_NTP_ALL;
else
#endif
if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_ALL))
rx_filter = HWTSTAMP_FILTER_ALL;
else
rx_filter = HWTSTAMP_FILTER_NONE;
break;
case CNF_HWTS_RXFILTER_NONE:
rx_filter = HWTSTAMP_FILTER_NONE;
break;
#ifdef HAVE_LINUX_TIMESTAMPING_RXFILTER_NTP
case CNF_HWTS_RXFILTER_NTP:
rx_filter = HWTSTAMP_FILTER_NTP_ALL;
break;
#endif
case CNF_HWTS_RXFILTER_PTP:
if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT))
rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
else if (ts_info.rx_filters & (1 << HWTSTAMP_FILTER_PTP_V2_EVENT))
rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
else
rx_filter = HWTSTAMP_FILTER_NONE;
break;
default:
rx_filter = HWTSTAMP_FILTER_ALL;
break;
}
ts_config.flags = 0;
ts_config.tx_type = HWTSTAMP_TX_ON;
ts_config.rx_filter = HWTSTAMP_FILTER_ALL;
ts_config.rx_filter = rx_filter;
req.ifr_data = (char *)&ts_config;
if (ioctl(sock_fd, SIOCSHWTSTAMP, &req)) {
DEBUG_LOG(LOGF_NtpIOLinux, "ioctl(%s) failed : %s", "SIOCSHWTSTAMP", strerror(errno));
close(sock_fd);
return 0;
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
as requested */
req.ifr_data = (char *)&ts_config;
#ifdef SIOCGHWTSTAMP
if (ioctl(sock_fd, SIOCGHWTSTAMP, &req) ||
ts_config.tx_type != HWTSTAMP_TX_ON || ts_config.rx_filter != rx_filter)
#endif
{
SCK_CloseSocket(sock_fd);
return 0;
}
}
close(sock_fd);
phc_index = ts_info.phc_index;
SCK_CloseSocket(sock_fd);
if (snprintf(phc_path, sizeof (phc_path), "/dev/ptp%d", phc_index) >= sizeof (phc_path))
phc_fd = SYS_Linux_OpenPHC(NULL, ts_info.phc_index);
if (phc_fd < 0)
return 0;
phc_fd = open(phc_path, O_RDONLY);
if (phc_fd < 0) {
LOG(LOGS_ERR, LOGF_NtpIOLinux, "Could not open %s : %s", phc_path, strerror(errno));
return 0;
}
UTI_FdSetCloexec(phc_fd);
iface = ARR_GetNewElement(interfaces);
snprintf(iface->name, sizeof (iface->name), "%s", name);
snprintf(iface->name, sizeof (iface->name), "%s", conf_iface->name);
iface->if_index = if_index;
iface->phc_fd = phc_fd;
iface->phc_mode = 0;
iface->phc_nocrossts = conf_iface->nocrossts;
/* Start with 1 gbit and no VLANs or IPv4/IPv6 options */
iface->link_speed = 1000;
iface->l2_udp4_ntp_start = 42;
iface->l2_udp6_ntp_start = 62;
iface->clock = HCL_CreateInstance();
iface->tx_comp = conf_iface->tx_comp;
iface->rx_comp = conf_iface->rx_comp;
DEBUG_LOG(LOGF_NtpIOLinux, "Enabled HW timestamping on %s", name);
minpoll = CLAMP(MIN_PHC_POLL, conf_iface->minpoll, MAX_PHC_POLL);
iface->clock = HCL_CreateInstance(conf_iface->min_samples, conf_iface->max_samples,
UTI_Log2ToDouble(minpoll), conf_iface->precision);
iface->maxpoll = CLAMP(minpoll, conf_iface->maxpoll, MAX_PHC_POLL);
/* Do not schedule the first poll timeout here! The argument (interface) can
move until all interfaces are added. Wait for the first HW timestamp. */
iface->poll_timeout_id = 0;
LOG(LOGS_INFO, "Enabled HW timestamping %son %s",
ts_config.rx_filter == HWTSTAMP_FILTER_NONE ? "(TX only) " : "", iface->name);
return 1;
}
@@ -176,18 +259,22 @@ add_interface(const char *name)
/* ================================================== */
static int
add_all_interfaces(void)
add_all_interfaces(CNF_HwTsInterface *conf_iface_all)
{
CNF_HwTsInterface conf_iface;
struct ifaddrs *ifaddr, *ifa;
int r;
conf_iface = *conf_iface_all;
if (getifaddrs(&ifaddr)) {
DEBUG_LOG(LOGF_NtpIOLinux, "getifaddrs() failed : %s", strerror(errno));
DEBUG_LOG("getifaddrs() failed : %s", strerror(errno));
return 0;
}
for (r = 0, ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
if (add_interface(ifa->ifa_name))
conf_iface.name = ifa->ifa_name;
if (add_interface(&conf_iface))
r = 1;
}
@@ -204,9 +291,9 @@ update_interface_speed(struct Interface *iface)
{
struct ethtool_cmd cmd;
struct ifreq req;
int sock_fd;
int sock_fd, link_speed;
sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
if (sock_fd < 0)
return;
@@ -218,14 +305,60 @@ update_interface_speed(struct Interface *iface)
req.ifr_data = (char *)&cmd;
if (ioctl(sock_fd, SIOCETHTOOL, &req)) {
DEBUG_LOG(LOGF_NtpIOLinux, "ioctl(%s) failed : %s", "SIOCETHTOOL", strerror(errno));
close(sock_fd);
DEBUG_LOG("ioctl(%s) failed : %s", "SIOCETHTOOL", strerror(errno));
SCK_CloseSocket(sock_fd);
return;
}
close(sock_fd);
SCK_CloseSocket(sock_fd);
iface->link_speed = ethtool_cmd_speed(&cmd);
link_speed = ethtool_cmd_speed(&cmd);
if (iface->link_speed != link_speed) {
iface->link_speed = link_speed;
DEBUG_LOG("Updated speed of %s to %d Mb/s", iface->name, link_speed);
}
}
/* ================================================== */
#if defined(HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO) || defined(HAVE_LINUX_TIMESTAMPING_OPT_TX_SWHW)
static int
check_timestamping_option(int option)
{
int sock_fd;
sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
if (sock_fd < 0)
return 0;
if (!SCK_SetIntOption(sock_fd, SOL_SOCKET, SO_TIMESTAMPING, option)) {
SCK_CloseSocket(sock_fd);
return 0;
}
SCK_CloseSocket(sock_fd);
return 1;
}
#endif
/* ================================================== */
static int
open_dummy_socket(void)
{
int sock_fd, events = 0;
sock_fd = SCK_OpenUdpSocket(NULL, NULL, NULL, 0);
if (sock_fd < 0)
return INVALID_SOCK_FD;
if (!NIO_Linux_SetTimestampSocketOptions(sock_fd, 1, &events)) {
SCK_CloseSocket(sock_fd);
return INVALID_SOCK_FD;
}
return sock_fd;
}
/* ================================================== */
@@ -233,42 +366,45 @@ update_interface_speed(struct Interface *iface)
void
NIO_Linux_Initialise(void)
{
ARR_Instance config_hwts_ifaces;
char *if_name;
CNF_HwTsInterface *conf_iface;
unsigned int i;
int wildcard, hwts;
int hwts;
interfaces = ARR_CreateInstance(sizeof (struct Interface));
config_hwts_ifaces = CNF_GetHwTsInterfaces();
/* Enable HW timestamping on specified interfaces. If "*" was specified, try
all interfaces. If no interface was specified, enable SW timestamping. */
for (i = wildcard = 0; i < ARR_GetSize(config_hwts_ifaces); i++) {
if (!strcmp("*", *(char **)ARR_GetElement(config_hwts_ifaces, i)))
wildcard = 1;
for (i = hwts = 0; CNF_GetHwTsInterface(i, &conf_iface); i++) {
if (!strcmp("*", conf_iface->name))
continue;
if (!add_interface(conf_iface))
LOG_FATAL("Could not enable HW timestamping on %s", conf_iface->name);
hwts = 1;
}
if (!wildcard && ARR_GetSize(config_hwts_ifaces)) {
for (i = 0; i < ARR_GetSize(config_hwts_ifaces); i++) {
if_name = *(char **)ARR_GetElement(config_hwts_ifaces, i);
if (!add_interface(if_name))
LOG_FATAL(LOGF_NtpIO, "Could not enable HW timestamping on %s", if_name);
}
hwts = 1;
} else if (wildcard && add_all_interfaces()) {
hwts = 1;
} else {
hwts = 0;
for (i = 0; CNF_GetHwTsInterface(i, &conf_iface); i++) {
if (strcmp("*", conf_iface->name))
continue;
if (add_all_interfaces(conf_iface))
hwts = 1;
break;
}
ts_flags = SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_RX_SOFTWARE;
ts_tx_flags = SOF_TIMESTAMPING_TX_SOFTWARE;
if (hwts) {
ts_flags = SOF_TIMESTAMPING_RAW_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE;
ts_tx_flags = SOF_TIMESTAMPING_TX_HARDWARE;
} else {
ts_flags = SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_RX_SOFTWARE;
ts_tx_flags = SOF_TIMESTAMPING_TX_SOFTWARE;
ts_flags |= SOF_TIMESTAMPING_RAW_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE;
ts_tx_flags |= SOF_TIMESTAMPING_TX_HARDWARE;
#ifdef HAVE_LINUX_TIMESTAMPING_OPT_PKTINFO
if (check_timestamping_option(SOF_TIMESTAMPING_OPT_PKTINFO))
ts_flags |= SOF_TIMESTAMPING_OPT_PKTINFO;
#endif
#ifdef HAVE_LINUX_TIMESTAMPING_OPT_TX_SWHW
if (check_timestamping_option(SOF_TIMESTAMPING_OPT_TX_SWHW))
ts_flags |= SOF_TIMESTAMPING_OPT_TX_SWHW;
#endif
}
/* Enable IP_PKTINFO in messages looped back to the error queue */
@@ -276,6 +412,8 @@ NIO_Linux_Initialise(void)
/* Kernels before 4.7 ignore timestamping flags set in control messages */
permanent_ts_options = !SYS_Linux_CheckKernelVersion(4, 7);
dummy_rxts_socket = INVALID_SOCK_FD;
}
/* ================================================== */
@@ -286,8 +424,12 @@ NIO_Linux_Finalise(void)
struct Interface *iface;
unsigned int i;
if (dummy_rxts_socket != INVALID_SOCK_FD)
SCK_CloseSocket(dummy_rxts_socket);
for (i = 0; i < ARR_GetSize(interfaces); i++) {
iface = ARR_GetElement(interfaces, i);
SCH_RemoveTimeout(iface->poll_timeout_id);
HCL_DestroyInstance(iface->clock);
close(iface->phc_fd);
}
@@ -297,6 +439,14 @@ NIO_Linux_Finalise(void)
/* ================================================== */
int
NIO_Linux_IsHwTsEnabled(void)
{
return ARR_GetSize(interfaces) > 0;
}
/* ================================================== */
int
NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events)
{
@@ -314,14 +464,12 @@ NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events)
if (client_only || permanent_ts_options)
flags |= ts_tx_flags;
if (setsockopt(sock_fd, SOL_SOCKET, SO_SELECT_ERR_QUEUE, &val, sizeof (val)) < 0) {
LOG(LOGS_ERR, LOGF_NtpIOLinux, "Could not set %s socket option", "SO_SELECT_ERR_QUEUE");
if (!SCK_SetIntOption(sock_fd, SOL_SOCKET, SO_SELECT_ERR_QUEUE, val)) {
ts_flags = 0;
return 0;
}
if (setsockopt(sock_fd, SOL_SOCKET, SO_TIMESTAMPING, &flags, sizeof (flags)) < 0) {
LOG(LOGS_ERR, LOGF_NtpIOLinux, "Could not set %s socket option", "SO_TIMESTAMPING");
if (!SCK_SetIntOption(sock_fd, SOL_SOCKET, SO_TIMESTAMPING, flags)) {
ts_flags = 0;
return 0;
}
@@ -332,68 +480,6 @@ NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events)
/* ================================================== */
static int
get_phc_sample(int phc_fd, struct timespec *phc_ts, struct timespec *local_ts, double *p_delay)
{
struct ptp_sys_offset sys_off;
struct timespec ts1, ts2, ts3, phc_tss[PHC_READINGS], sys_tss[PHC_READINGS];
double min_delay = 0.0, delays[PHC_READINGS], phc_sum, local_sum, local_prec;
int i, n;
/* Silence valgrind */
memset(&sys_off, 0, sizeof (sys_off));
sys_off.n_samples = PHC_READINGS;
if (ioctl(phc_fd, PTP_SYS_OFFSET, &sys_off)) {
DEBUG_LOG(LOGF_NtpIOLinux, "ioctl(%s) failed : %s", "PTP_SYS_OFFSET", strerror(errno));
return 0;
}
for (i = 0; i < PHC_READINGS; i++) {
ts1.tv_sec = sys_off.ts[i * 2].sec;
ts1.tv_nsec = sys_off.ts[i * 2].nsec;
ts2.tv_sec = sys_off.ts[i * 2 + 1].sec;
ts2.tv_nsec = sys_off.ts[i * 2 + 1].nsec;
ts3.tv_sec = sys_off.ts[i * 2 + 2].sec;
ts3.tv_nsec = sys_off.ts[i * 2 + 2].nsec;
sys_tss[i] = ts1;
phc_tss[i] = ts2;
delays[i] = UTI_DiffTimespecsToDouble(&ts3, &ts1);
if (delays[i] <= 0.0)
/* Step in the middle of a PHC reading? */
return 0;
if (!i || delays[i] < min_delay)
min_delay = delays[i];
}
local_prec = LCL_GetSysPrecisionAsQuantum();
/* Combine best readings */
for (i = n = 0, phc_sum = local_sum = 0.0; i < PHC_READINGS; i++) {
if (delays[i] > min_delay + local_prec)
continue;
phc_sum += UTI_DiffTimespecsToDouble(&phc_tss[i], &phc_tss[0]);
local_sum += UTI_DiffTimespecsToDouble(&sys_tss[i], &sys_tss[0]) + delays[i] / 2.0;
n++;
}
assert(n);
UTI_AddDoubleToTimespec(&phc_tss[0], phc_sum / n, phc_ts);
UTI_AddDoubleToTimespec(&sys_tss[0], local_sum / n, &ts1);
LCL_CookTime(&ts1, local_ts, NULL);
*p_delay = min_delay;
return 1;
}
/* ================================================== */
static struct Interface *
get_interface(int if_index)
{
@@ -414,40 +500,132 @@ get_interface(int if_index)
/* ================================================== */
static void
process_hw_timestamp(struct Interface *iface, struct timespec *hw_ts,
NTP_Local_Timestamp *local_ts, int rx_ntp_length, int family)
poll_timeout(void *arg)
{
struct timespec sample_phc_ts, sample_local_ts;
double sample_delay, rx_correction;
int l2_length;
struct Interface *iface = arg;
struct timespec now;
if (HCL_NeedsNewSample(iface->clock, &local_ts->ts)) {
if (!get_phc_sample(iface->phc_fd, &sample_phc_ts, &sample_local_ts, &sample_delay))
return;
iface->poll_timeout_id = 0;
HCL_AccumulateSample(iface->clock, &sample_phc_ts, &sample_local_ts,
sample_delay / 2.0);
SCH_GetLastEventTime(&now, NULL, NULL);
poll_phc(iface, &now);
}
update_interface_speed(iface);
}
/* ================================================== */
static void
poll_phc(struct Interface *iface, struct timespec *now)
{
struct timespec sample_phc_ts, sample_sys_ts, sample_local_ts;
struct timespec phc_readings[PHC_READINGS][3];
double phc_err, local_err, interval;
int n_readings;
if (!HCL_NeedsNewSample(iface->clock, now))
return;
DEBUG_LOG("Polling PHC on %s%s",
iface->name, iface->poll_timeout_id != 0 ? " before timeout" : "");
n_readings = SYS_Linux_GetPHCReadings(iface->phc_fd, iface->phc_nocrossts,
&iface->phc_mode, PHC_READINGS, phc_readings);
/* Add timeout for the next poll in case no HW timestamp will be captured
between the minpoll and maxpoll. Separate reading of different PHCs to
avoid long intervals between handling I/O events. */
SCH_RemoveTimeout(iface->poll_timeout_id);
interval = UTI_Log2ToDouble(iface->maxpoll);
iface->poll_timeout_id = SCH_AddTimeoutInClass(interval, interval /
ARR_GetSize(interfaces) / 4, 0.1,
SCH_PhcPollClass, poll_timeout, iface);
if (n_readings <= 0)
return;
if (!HCL_ProcessReadings(iface->clock, n_readings, phc_readings,
&sample_phc_ts, &sample_sys_ts, &phc_err))
return;
LCL_CookTime(&sample_sys_ts, &sample_local_ts, &local_err);
HCL_AccumulateSample(iface->clock, &sample_phc_ts, &sample_local_ts, phc_err + local_err);
update_interface_speed(iface);
}
/* ================================================== */
static void
process_hw_timestamp(struct Interface *iface, struct timespec *hw_ts,
NTP_Local_Timestamp *local_ts, int rx_ntp_length, int family,
int l2_length)
{
double rx_correction = 0.0, ts_delay, local_err;
struct timespec ts;
poll_phc(iface, &local_ts->ts);
/* We need to transpose RX timestamps as hardware timestamps are normally
preamble timestamps and RX timestamps in NTP are supposed to be trailer
timestamps. Without raw sockets we don't know the length of the packet
at layer 2, so we make an assumption that UDP data start at the same
position as in the last transmitted packet which had a HW TX timestamp. */
timestamps. If we don't know the length of the packet at layer 2, we
make an assumption that UDP data start at the same position as in the
last transmitted packet which had a HW TX timestamp. */
if (rx_ntp_length && iface->link_speed) {
l2_length = (family == IPADDR_INET4 ? iface->l2_udp4_ntp_start :
iface->l2_udp6_ntp_start) + rx_ntp_length + 4;
if (!l2_length)
l2_length = (family == IPADDR_INET4 ? iface->l2_udp4_ntp_start :
iface->l2_udp6_ntp_start) + rx_ntp_length;
/* Include the frame check sequence (FCS) */
l2_length += 4;
rx_correction = l2_length / (1.0e6 / 8 * iface->link_speed);
UTI_AddDoubleToTimespec(hw_ts, rx_correction, hw_ts);
}
if (!HCL_CookTime(iface->clock, hw_ts, &local_ts->ts, &local_ts->err))
if (!HCL_CookTime(iface->clock, hw_ts, &ts, &local_err))
return;
if (!rx_ntp_length && iface->tx_comp)
UTI_AddDoubleToTimespec(&ts, iface->tx_comp, &ts);
else if (rx_ntp_length && iface->rx_comp)
UTI_AddDoubleToTimespec(&ts, -iface->rx_comp, &ts);
ts_delay = UTI_DiffTimespecsToDouble(&local_ts->ts, &ts);
if (fabs(ts_delay) > MAX_TS_DELAY) {
DEBUG_LOG("Unacceptable timestamp delay %.9f", ts_delay);
return;
}
local_ts->ts = ts;
local_ts->err = local_err;
local_ts->source = NTP_TS_HARDWARE;
local_ts->rx_duration = rx_correction;
/* Network correction needs to include the RX duration to avoid
asymmetric correction with asymmetric link speeds */
local_ts->net_correction = rx_correction;
}
/* ================================================== */
static void
process_sw_timestamp(struct timespec *sw_ts, NTP_Local_Timestamp *local_ts)
{
double ts_delay, local_err;
struct timespec ts;
LCL_CookTime(sw_ts, &ts, &local_err);
ts_delay = UTI_DiffTimespecsToDouble(&local_ts->ts, &ts);
if (fabs(ts_delay) > MAX_TS_DELAY) {
DEBUG_LOG("Unacceptable timestamp delay %.9f", ts_delay);
return;
}
local_ts->ts = ts;
local_ts->err = local_err;
local_ts->source = NTP_TS_KERNEL;
}
/* ================================================== */
@@ -458,7 +636,6 @@ static int
extract_udp_data(unsigned char *msg, NTP_Remote_Address *remote_addr, int len)
{
unsigned char *msg_start = msg;
union sockaddr_in46 addr;
remote_addr->ip_addr.family = IPADDR_UNSPEC;
remote_addr->port = 0;
@@ -481,31 +658,60 @@ extract_udp_data(unsigned char *msg, NTP_Remote_Address *remote_addr, int len)
/* Parse destination address and port from IPv4/IPv6 and UDP headers */
if (len >= 20 && msg[0] >> 4 == 4) {
int ihl = (msg[0] & 0xf) * 4;
uint32_t addr;
if (len < ihl + 8 || msg[9] != 17)
return 0;
memcpy(&addr.in4.sin_addr.s_addr, msg + 16, sizeof (uint32_t));
addr.in4.sin_port = *(uint16_t *)(msg + ihl + 2);
addr.in4.sin_family = AF_INET;
memcpy(&addr, msg + 16, sizeof (addr));
remote_addr->ip_addr.addr.in4 = ntohl(addr);
remote_addr->port = ntohs(*(uint16_t *)(msg + ihl + 2));
remote_addr->ip_addr.family = IPADDR_INET4;
len -= ihl + 8, msg += ihl + 8;
#ifdef FEAT_IPV6
} else if (len >= 48 && msg[0] >> 4 == 6) {
/* IPv6 extension headers are not supported */
if (msg[6] != 17)
return 0;
int eh_len, next_header = msg[6];
memcpy(&addr.in6.sin6_addr.s6_addr, msg + 24, 16);
addr.in6.sin6_port = *(uint16_t *)(msg + 40 + 2);
addr.in6.sin6_family = AF_INET6;
len -= 48, msg += 48;
memcpy(&remote_addr->ip_addr.addr.in6, msg + 24, sizeof (remote_addr->ip_addr.addr.in6));
len -= 40, msg += 40;
/* Skip IPv6 extension headers if present */
while (next_header != 17) {
switch (next_header) {
case 44: /* Fragment Header */
/* Process only the first fragment */
if (ntohs(*(uint16_t *)(msg + 2)) >> 3 != 0)
return 0;
eh_len = 8;
break;
case 0: /* Hop-by-Hop Options */
case 43: /* Routing Header */
case 60: /* Destination Options */
case 135: /* Mobility Header */
eh_len = 8 * (msg[1] + 1);
break;
case 51: /* Authentication Header */
eh_len = 4 * (msg[1] + 2);
break;
default:
return 0;
}
if (eh_len < 8 || len < eh_len + 8)
return 0;
next_header = msg[0];
len -= eh_len, msg += eh_len;
}
remote_addr->port = ntohs(*(uint16_t *)(msg + 2));
remote_addr->ip_addr.family = IPADDR_INET6;
len -= 8, msg += 8;
#endif
} else {
return 0;
}
UTI_SockaddrToIPAndPort(&addr.u, &remote_addr->ip_addr, &remote_addr->port);
/* Move the message to fix alignment of its fields */
if (len > 0)
memmove(msg_start, msg, len);
@@ -516,50 +722,42 @@ extract_udp_data(unsigned char *msg, NTP_Remote_Address *remote_addr, int len)
/* ================================================== */
int
NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
NTP_Local_Timestamp *local_ts, struct msghdr *hdr,
int length, int sock_fd, int if_index)
NIO_Linux_ProcessMessage(SCK_Message *message, NTP_Local_Address *local_addr,
NTP_Local_Timestamp *local_ts, int event)
{
struct Interface *iface;
struct cmsghdr *cmsg;
int is_tx, l2_length;
int is_tx, ts_if_index, l2_length;
double c = 0.0;
is_tx = hdr->msg_flags & MSG_ERRQUEUE;
is_tx = event == SCH_FILE_EXCEPTION;
iface = NULL;
for (cmsg = CMSG_FIRSTHDR(hdr); cmsg; cmsg = CMSG_NXTHDR(hdr, cmsg)) {
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPING) {
struct scm_timestamping ts3;
ts_if_index = message->timestamp.if_index;
if (ts_if_index == INVALID_IF_INDEX)
ts_if_index = message->if_index;
l2_length = message->timestamp.l2_length;
memcpy(&ts3, CMSG_DATA(cmsg), sizeof (ts3));
if (!UTI_IsZeroTimespec(&ts3.ts[0])) {
LCL_CookTime(&ts3.ts[0], &local_ts->ts, &local_ts->err);
local_ts->source = NTP_TS_KERNEL;
} else {
iface = get_interface(if_index);
if (iface) {
process_hw_timestamp(iface, &ts3.ts[2], local_ts, !is_tx ? length : 0,
remote_addr->ip_addr.family);
} else {
DEBUG_LOG(LOGF_NtpIOLinux, "HW clock not found for interface %d", if_index);
}
}
if (!UTI_IsZeroTimespec(&message->timestamp.hw)) {
iface = get_interface(ts_if_index);
if (iface) {
process_hw_timestamp(iface, &message->timestamp.hw, local_ts, !is_tx ? message->length : 0,
message->remote_addr.ip.ip_addr.family, l2_length);
} else {
DEBUG_LOG("HW clock not found for interface %d", ts_if_index);
}
}
if ((cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) ||
(cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_RECVERR)) {
struct sock_extended_err err;
if (local_ts->source == NTP_TS_DAEMON && !UTI_IsZeroTimespec(&message->timestamp.kernel) &&
(!is_tx || UTI_IsZeroTimespec(&message->timestamp.hw))) {
process_sw_timestamp(&message->timestamp.kernel, local_ts);
}
memcpy(&err, CMSG_DATA(cmsg), sizeof (err));
if (err.ee_errno != ENOMSG || err.ee_info != SCM_TSTAMP_SND ||
err.ee_origin != SO_EE_ORIGIN_TIMESTAMPING) {
DEBUG_LOG(LOGF_NtpIOLinux, "Unknown extended error");
/* Drop the message */
return 1;
}
}
/* If the kernel is slow with enabling RX timestamping, open a dummy
socket to keep the kernel RX timestamping permanently enabled */
if (!is_tx && local_ts->source == NTP_TS_DAEMON && ts_flags) {
DEBUG_LOG("Missing kernel RX timestamp");
if (dummy_rxts_socket == INVALID_SOCK_FD)
dummy_rxts_socket = open_dummy_socket();
}
/* Return the message if it's not received from the error queue */
@@ -569,59 +767,49 @@ NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *loc
/* The data from the error queue includes all layers up to UDP. We have to
extract the UDP data and also the destination address with port as there
currently doesn't seem to be a better way to get them both. */
l2_length = length;
length = extract_udp_data(hdr->msg_iov[0].iov_base, remote_addr, length);
l2_length = message->length;
message->length = extract_udp_data(message->data, &message->remote_addr.ip, message->length);
DEBUG_LOG(LOGF_NtpIOLinux, "Received %d (%d) bytes from error queue for %s:%d fd=%d if=%d tss=%d",
l2_length, length, UTI_IPToString(&remote_addr->ip_addr), remote_addr->port,
sock_fd, if_index, local_ts->source);
DEBUG_LOG("Extracted message for %s fd=%d len=%d",
UTI_IPSockAddrToString(&message->remote_addr.ip),
local_addr->sock_fd, message->length);
/* Update assumed position of UDP data at layer 2 for next received packet */
if (iface && length) {
if (remote_addr->ip_addr.family == IPADDR_INET4)
iface->l2_udp4_ntp_start = l2_length - length;
else if (remote_addr->ip_addr.family == IPADDR_INET6)
iface->l2_udp6_ntp_start = l2_length - length;
if (iface && message->length) {
if (message->remote_addr.ip.ip_addr.family == IPADDR_INET4)
iface->l2_udp4_ntp_start = l2_length - message->length;
else if (message->remote_addr.ip.ip_addr.family == IPADDR_INET6)
iface->l2_udp6_ntp_start = l2_length - message->length;
}
/* Drop the message if HW timestamp is missing or its processing failed */
if ((ts_flags & SOF_TIMESTAMPING_RAW_HARDWARE) && local_ts->source != NTP_TS_HARDWARE) {
DEBUG_LOG(LOGF_NtpIOLinux, "Missing HW timestamp");
/* Drop the message if it has no timestamp or its processing failed */
if (local_ts->source == NTP_TS_DAEMON) {
DEBUG_LOG("Missing TX timestamp");
return 1;
}
if (length < NTP_NORMAL_PACKET_LENGTH)
if (!NIO_UnwrapMessage(message, local_addr->sock_fd, &c))
return 1;
NSR_ProcessTx(remote_addr, local_addr, local_ts,
(NTP_Packet *)hdr->msg_iov[0].iov_base, length);
if (message->length < NTP_HEADER_LENGTH || message->length > sizeof (NTP_Packet))
return 1;
NSR_ProcessTx(&message->remote_addr.ip, local_addr, local_ts, message->data, message->length);
return 1;
}
/* ================================================== */
int
NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd)
void
NIO_Linux_RequestTxTimestamp(SCK_Message *message, int sock_fd)
{
struct cmsghdr *cmsg;
if (!ts_flags)
return;
/* Check if TX timestamping is disabled on this socket */
if (permanent_ts_options || !NIO_IsServerSocket(sock_fd))
return cmsglen;
return;
/* Add control message that will enable TX timestamping for this message.
Don't use CMSG_NXTHDR as the one in glibc is buggy for creating new
control messages. */
cmsg = (struct cmsghdr *)((char *)CMSG_FIRSTHDR(msg) + cmsglen);
memset(cmsg, 0, CMSG_SPACE(sizeof (ts_tx_flags)));
cmsglen += CMSG_SPACE(sizeof (ts_tx_flags));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SO_TIMESTAMPING;
cmsg->cmsg_len = CMSG_LEN(sizeof (ts_tx_flags));
memcpy(CMSG_DATA(cmsg), &ts_tx_flags, sizeof (ts_tx_flags));
return cmsglen;
message->timestamp.tx_flags = ts_tx_flags;
}

View File

@@ -24,14 +24,22 @@
This is the header file for the Linux-specific NTP socket I/O bits.
*/
#ifndef GOT_NTP_IO_LINUX_H
#define GOT_NTP_IO_LINUX_H
#include "socket.h"
extern void NIO_Linux_Initialise(void);
extern void NIO_Linux_Finalise(void);
extern int NIO_Linux_IsHwTsEnabled(void);
extern int NIO_Linux_SetTimestampSocketOptions(int sock_fd, int client_only, int *events);
extern int NIO_Linux_ProcessMessage(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
NTP_Local_Timestamp *local_ts, struct msghdr *hdr, int length,
int sock_fd, int if_index);
extern int NIO_Linux_ProcessMessage(SCK_Message *message, NTP_Local_Address *local_addr,
NTP_Local_Timestamp *local_ts, int event);
extern int NIO_Linux_RequestTxTimestamp(struct msghdr *msg, int cmsglen, int sock_fd);
extern void NIO_Linux_RequestTxTimestamp(SCK_Message *message, int sock_fd);
#endif

View File

@@ -34,6 +34,7 @@
#include "ntp_io.h"
#include "ntp_signd.h"
#include "sched.h"
#include "socket.h"
#include "util.h"
/* Declarations per samba/source4/librpc/idl/ntp_signd.idl */
@@ -90,19 +91,11 @@ static ARR_Instance queue;
static unsigned int queue_head;
static unsigned int queue_tail;
#define INVALID_SOCK_FD -1
#define INVALID_SOCK_FD (-6)
/* Unix domain socket connected to ntp_signd */
static int sock_fd;
#define MIN_AUTH_DELAY 1.0e-5
#define MAX_AUTH_DELAY 1.0e-2
/* Average time needed for signing one packet. This is used to adjust the
transmit timestamp in NTP packets. The timestamp won't be very accurate as
the delay is variable, but it should be good enough for MS-SNTP clients. */
static double auth_delay;
/* Flag indicating if the MS-SNTP authentication is enabled */
static int enabled;
@@ -116,7 +109,7 @@ static void
close_socket(void)
{
SCH_RemoveFileHandler(sock_fd);
close(sock_fd);
SCK_CloseSocket(sock_fd);
sock_fd = INVALID_SOCK_FD;
/* Empty the queue */
@@ -128,36 +121,24 @@ close_socket(void)
static int
open_socket(void)
{
struct sockaddr_un s;
char path[PATH_MAX];
if (sock_fd >= 0)
if (sock_fd != INVALID_SOCK_FD)
return 1;
sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (snprintf(path, sizeof (path), "%s/socket", CNF_GetNtpSigndSocket()) >= sizeof (path)) {
DEBUG_LOG("signd socket path too long");
return 0;
}
sock_fd = SCK_OpenUnixStreamSocket(path, NULL, 0);
if (sock_fd < 0) {
DEBUG_LOG(LOGF_NtpSignd, "Could not open signd socket : %s", strerror(errno));
sock_fd = INVALID_SOCK_FD;
return 0;
}
UTI_FdSetCloexec(sock_fd);
SCH_AddFileHandler(sock_fd, SCH_FILE_INPUT, read_write_socket, NULL);
s.sun_family = AF_UNIX;
if (snprintf(s.sun_path, sizeof (s.sun_path), "%s/socket",
CNF_GetNtpSigndSocket()) >= sizeof (s.sun_path)) {
DEBUG_LOG(LOGF_NtpSignd, "signd socket path too long");
close_socket();
return 0;
}
if (connect(sock_fd, (struct sockaddr *)&s, sizeof (s)) < 0) {
DEBUG_LOG(LOGF_NtpSignd, "Could not connect to signd : %s", strerror(errno));
close_socket();
return 0;
}
DEBUG_LOG(LOGF_NtpSignd, "Connected to signd");
return 1;
}
@@ -170,34 +151,30 @@ process_response(SignInstance *inst)
double delay;
if (ntohs(inst->request.packet_id) != ntohl(inst->response.packet_id)) {
DEBUG_LOG(LOGF_NtpSignd, "Invalid response ID");
DEBUG_LOG("Invalid response ID");
return;
}
if (ntohl(inst->response.op) != SIGNING_SUCCESS) {
DEBUG_LOG(LOGF_NtpSignd, "Signing failed");
DEBUG_LOG("Signing failed");
return;
}
/* Check if the file descriptor is still valid */
if (!NIO_IsServerSocket(inst->local_addr.sock_fd)) {
DEBUG_LOG(LOGF_NtpSignd, "Invalid NTP socket");
DEBUG_LOG("Invalid NTP socket");
return;
}
SCH_GetLastEventTime(NULL, NULL, &ts);
delay = UTI_DiffTimespecsToDouble(&ts, &inst->request_ts);
DEBUG_LOG(LOGF_NtpSignd, "Signing succeeded (delay %f)", delay);
DEBUG_LOG("Signing succeeded (delay %f)", delay);
/* Send the signed NTP packet */
NIO_SendPacket(&inst->response.signed_packet, &inst->remote_addr, &inst->local_addr,
ntohl(inst->response.length) + sizeof (inst->response.length) -
offsetof(SigndResponse, signed_packet), 0);
/* Update exponential moving average of the authentication delay */
delay = CLAMP(MIN_AUTH_DELAY, delay, MAX_AUTH_DELAY);
auth_delay += 0.1 * (delay - auth_delay);
}
/* ================================================== */
@@ -218,16 +195,14 @@ read_write_socket(int sock_fd, int event, void *anything)
if (!inst->sent)
SCH_GetLastEventTime(NULL, NULL, &inst->request_ts);
s = send(sock_fd, (char *)&inst->request + inst->sent,
inst->request_length - inst->sent, 0);
s = SCK_Send(sock_fd, (char *)&inst->request + inst->sent,
inst->request_length - inst->sent, 0);
if (s < 0) {
DEBUG_LOG(LOGF_NtpSignd, "signd socket error: %s", strerror(errno));
close_socket();
return;
}
DEBUG_LOG(LOGF_NtpSignd, "Sent %d bytes to signd", s);
inst->sent += s;
/* Try again later if the request is not complete yet */
@@ -235,31 +210,25 @@ read_write_socket(int sock_fd, int event, void *anything)
return;
/* Disable output and wait for a response */
SCH_SetFileHandlerEvents(sock_fd, SCH_FILE_INPUT);
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_OUTPUT, 0);
}
if (event == SCH_FILE_INPUT) {
if (IS_QUEUE_EMPTY()) {
DEBUG_LOG(LOGF_NtpSignd, "Unexpected signd response");
DEBUG_LOG("Unexpected signd response");
close_socket();
return;
}
assert(inst->received < sizeof (inst->response));
s = recv(sock_fd, (char *)&inst->response + inst->received,
sizeof (inst->response) - inst->received, 0);
s = SCK_Receive(sock_fd, (char *)&inst->response + inst->received,
sizeof (inst->response) - inst->received, 0);
if (s <= 0) {
if (s < 0)
DEBUG_LOG(LOGF_NtpSignd, "signd socket error: %s", strerror(errno));
else
DEBUG_LOG(LOGF_NtpSignd, "signd socket closed");
close_socket();
return;
}
DEBUG_LOG(LOGF_NtpSignd, "Received %d bytes from signd", s);
inst->received += s;
if (inst->received < sizeof (inst->response.length))
@@ -269,7 +238,7 @@ read_write_socket(int sock_fd, int event, void *anything)
if (response_length < offsetof(SigndResponse, signed_packet) ||
response_length > sizeof (SigndResponse)) {
DEBUG_LOG(LOGF_NtpSignd, "Invalid response length");
DEBUG_LOG("Invalid response length");
close_socket();
return;
}
@@ -283,7 +252,7 @@ read_write_socket(int sock_fd, int event, void *anything)
/* Move the head and enable output for the next packet */
queue_head = NEXT_QUEUE_INDEX(queue_head);
if (!IS_QUEUE_EMPTY())
SCH_SetFileHandlerEvents(sock_fd, SCH_FILE_INPUT | SCH_FILE_OUTPUT);
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_OUTPUT, 1);
}
}
@@ -293,7 +262,6 @@ void
NSD_Initialise()
{
sock_fd = INVALID_SOCK_FD;
auth_delay = MIN_AUTH_DELAY;
enabled = CNF_GetNtpSigndSocket() && CNF_GetNtpSigndSocket()[0];
if (!enabled)
@@ -303,7 +271,7 @@ NSD_Initialise()
ARR_SetSize(queue, MAX_QUEUE_LENGTH);
queue_head = queue_tail = 0;
LOG(LOGS_INFO, LOGF_NtpSignd, "MS-SNTP authentication enabled");
LOG(LOGS_INFO, "MS-SNTP authentication enabled");
}
/* ================================================== */
@@ -320,30 +288,24 @@ NSD_Finalise()
/* ================================================== */
extern int NSD_GetAuthDelay(uint32_t key_id)
{
return 1.0e9 * auth_delay;
}
/* ================================================== */
int
NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length)
NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_PacketInfo *info,
NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr)
{
SignInstance *inst;
if (!enabled) {
DEBUG_LOG(LOGF_NtpSignd, "signd disabled");
DEBUG_LOG("signd disabled");
return 0;
}
if (queue_head == NEXT_QUEUE_INDEX(queue_tail)) {
DEBUG_LOG(LOGF_NtpSignd, "signd queue full");
DEBUG_LOG("signd queue full");
return 0;
}
if (length != NTP_NORMAL_PACKET_LENGTH) {
DEBUG_LOG(LOGF_NtpSignd, "Invalid packet length");
if (info->length != NTP_HEADER_LENGTH) {
DEBUG_LOG("Invalid packet length");
return 0;
}
@@ -355,7 +317,7 @@ NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_Remote_Address *r
inst->local_addr = *local_addr;
inst->sent = 0;
inst->received = 0;
inst->request_length = offsetof(SigndRequest, packet_to_sign) + length;
inst->request_length = offsetof(SigndRequest, packet_to_sign) + info->length;
/* The length field doesn't include itself */
inst->request.length = htonl(inst->request_length - sizeof (inst->request.length));
@@ -365,16 +327,15 @@ NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_Remote_Address *r
inst->request._pad = 0;
inst->request.key_id = htonl(key_id);
memcpy(&inst->request.packet_to_sign, packet, length);
memcpy(&inst->request.packet_to_sign, packet, info->length);
/* Enable output if there was no pending request */
if (IS_QUEUE_EMPTY())
SCH_SetFileHandlerEvents(sock_fd, SCH_FILE_INPUT | SCH_FILE_OUTPUT);
SCH_SetFileHandlerEvent(sock_fd, SCH_FILE_OUTPUT, 1);
queue_tail = NEXT_QUEUE_INDEX(queue_tail);
DEBUG_LOG(LOGF_NtpSignd, "Packet added to signd queue (%u:%u)",
queue_head, queue_tail);
DEBUG_LOG("Packet added to signd queue (%u:%u)", queue_head, queue_tail);
return 1;
}

View File

@@ -35,10 +35,8 @@ extern void NSD_Initialise(void);
/* Finalisation function */
extern void NSD_Finalise(void);
/* Function to get an estimate of delay due to signing */
extern int NSD_GetAuthDelay(uint32_t key_id);
/* Function to sign an NTP packet and send it */
extern int NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length);
extern int NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_PacketInfo *info,
NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -44,16 +44,23 @@ typedef enum {
NSR_NoSuchSource, /* Remove - attempt to remove a source that is not known */
NSR_AlreadyInUse, /* AddSource - attempt to add a source that is already known */
NSR_TooManySources, /* AddSource - too many sources already present */
NSR_InvalidAF /* AddSource - attempt to add a source with invalid address family */
NSR_InvalidAF, /* AddSource - attempt to add a source with invalid address family */
NSR_InvalidName, /* AddSourceByName - attempt to add a source with invalid name */
NSR_UnresolvedName, /* AddSourceByName - name will be resolved later */
} NSR_Status;
/* Procedure to add a new server or peer source. */
extern NSR_Status NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params);
extern NSR_Status NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type,
SourceParameters *params, uint32_t *conf_id);
/* Procedure to add a new server, peer source, or pool of servers specified by
name instead of address. The name is resolved in exponentially increasing
intervals until it succeeds or fails with a non-temporary error. */
extern void NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, SourceParameters *params);
intervals until it succeeds or fails with a non-temporary error. If the
name is an address, it is equivalent to NSR_AddSource(). */
extern NSR_Status NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type,
SourceParameters *params, uint32_t *conf_id);
extern const char *NSR_StatusToString(NSR_Status status);
/* Function type for handlers to be called back when an attempt
* (possibly unsuccessful) to resolve unresolved sources ends */
@@ -72,7 +79,10 @@ extern void NSR_StartSources(void);
extern void NSR_AutoStartSources(void);
/* Procedure to remove a source */
extern NSR_Status NSR_RemoveSource(NTP_Remote_Address *remote_addr);
extern NSR_Status NSR_RemoveSource(IPAddr *address);
/* Procedure to remove all sources matching a configuration ID */
extern void NSR_RemoveSourcesById(uint32_t conf_id);
/* Procedure to remove all sources */
extern void NSR_RemoveAllSources(void);
@@ -83,9 +93,18 @@ 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. 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 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 */
extern void NSR_ProcessRx(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length);
@@ -102,14 +121,9 @@ extern void NSR_Initialise(void);
extern void NSR_Finalise(void);
/* This routine is used to indicate that sources whose IP addresses
match a particular subnet should be set online again. Returns a
flag indicating whether any hosts matched the address */
extern int NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address);
/* This routine is used to indicate that sources whose IP addresses
match a particular subnet should be set offline. Returns a flag
indicating whether any hosts matched the address */
extern int NSR_TakeSourcesOffline(IPAddr *mask, IPAddr *address);
match a particular subnet should be set online or offline. It returns
a flag indicating whether any hosts matched the address. */
extern int NSR_SetConnectivity(IPAddr *mask, IPAddr *address, SRC_Connectivity connectivity);
extern int NSR_ModifyMinpoll(IPAddr *address, int new_minpoll);
@@ -129,8 +143,12 @@ extern int NSR_InitiateSampleBurst(int n_good_samples, int n_total_samples, IPAd
extern void NSR_ReportSource(RPT_SourceReport *report, struct timespec *now);
extern int NSR_GetAuthReport(IPAddr *address, RPT_AuthReport *report);
extern int NSR_GetNTPReport(RPT_NTPReport *report);
extern void NSR_GetActivityReport(RPT_ActivityReport *report);
extern void NSR_DumpAuthData(void);
#endif /* GOT_NTP_SOURCES_H */

81
nts_ke.h Normal file
View File

@@ -0,0 +1,81 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Header file for the NTS Key Establishment protocol
*/
#ifndef GOT_NTS_KE_H
#define GOT_NTS_KE_H
#include "siv.h"
#define NKE_PORT 4460
#define NKE_RECORD_CRITICAL_BIT (1U << 15)
#define NKE_RECORD_END_OF_MESSAGE 0
#define NKE_RECORD_NEXT_PROTOCOL 1
#define NKE_RECORD_ERROR 2
#define NKE_RECORD_WARNING 3
#define NKE_RECORD_AEAD_ALGORITHM 4
#define NKE_RECORD_COOKIE 5
#define NKE_RECORD_NTPV4_SERVER_NEGOTIATION 6
#define NKE_RECORD_NTPV4_PORT_NEGOTIATION 7
#define NKE_NEXT_PROTOCOL_NTPV4 0
#define NKE_ERROR_UNRECOGNIZED_CRITICAL_RECORD 0
#define NKE_ERROR_BAD_REQUEST 1
#define NKE_ERROR_INTERNAL_SERVER_ERROR 2
#define NKE_ALPN_NAME "ntske/1"
#define NKE_EXPORTER_LABEL "EXPORTER-network-time-security"
#define NKE_EXPORTER_CONTEXT_C2S "\x0\x0\x0\xf\x0"
#define NKE_EXPORTER_CONTEXT_S2C "\x0\x0\x0\xf\x1"
#define NKE_MAX_MESSAGE_LENGTH 16384
#define NKE_MAX_RECORD_BODY_LENGTH 256
#define NKE_MAX_COOKIE_LENGTH 256
#define NKE_MAX_COOKIES 8
#define NKE_MAX_KEY_LENGTH SIV_MAX_KEY_LENGTH
#define NKE_RETRY_FACTOR2_CONNECT 4
#define NKE_RETRY_FACTOR2_TLS 10
#define NKE_MAX_RETRY_INTERVAL2 19
typedef struct {
int length;
unsigned char key[NKE_MAX_KEY_LENGTH];
} NKE_Key;
typedef struct {
SIV_Algorithm algorithm;
NKE_Key c2s;
NKE_Key s2c;
} NKE_Context;
typedef struct {
int length;
unsigned char cookie[NKE_MAX_COOKIE_LENGTH];
} NKE_Cookie;
#endif

457
nts_ke_client.c Normal file
View File

@@ -0,0 +1,457 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2020-2021
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
NTS-KE client
*/
#include "config.h"
#include "sysincl.h"
#include "nts_ke_client.h"
#include "conf.h"
#include "logging.h"
#include "memory.h"
#include "nameserv_async.h"
#include "nts_ke_session.h"
#include "siv.h"
#include "socket.h"
#include "util.h"
#define CLIENT_TIMEOUT 16.0
struct NKC_Instance_Record {
char *name;
IPSockAddr address;
NKSN_Credentials credentials;
NKSN_Instance session;
int destroying;
int got_response;
int resolving_name;
NKE_Context context;
NKE_Cookie cookies[NKE_MAX_COOKIES];
int num_cookies;
char server_name[NKE_MAX_RECORD_BODY_LENGTH + 2];
IPSockAddr ntp_address;
};
/* ================================================== */
static NKSN_Credentials default_credentials = NULL;
static int default_credentials_refs = 0;
/* ================================================== */
static void
name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *arg)
{
NKC_Instance inst = arg;
int i;
inst->resolving_name = 0;
if (inst->destroying) {
Free(inst);
return;
}
if (status != DNS_Success || n_addrs < 1) {
LOG(LOGS_ERR, "Could not resolve NTP server %s from %s", inst->server_name, inst->name);
/* Force restart */
inst->got_response = 0;
return;
}
inst->ntp_address.ip_addr = ip_addrs[0];
/* Prefer an address in the same family as the NTS-KE server */
for (i = 0; i < n_addrs; i++) {
DEBUG_LOG("%s resolved to %s", inst->server_name, UTI_IPToString(&ip_addrs[i]));
if (ip_addrs[i].family == inst->address.ip_addr.family) {
inst->ntp_address.ip_addr = ip_addrs[i];
break;
}
}
}
/* ================================================== */
static int
prepare_request(NKC_Instance inst)
{
NKSN_Instance session = inst->session;
uint16_t data[2];
int length;
NKSN_BeginMessage(session);
data[0] = htons(NKE_NEXT_PROTOCOL_NTPV4);
if (!NKSN_AddRecord(session, 1, NKE_RECORD_NEXT_PROTOCOL, data, sizeof (data[0])))
return 0;
length = 0;
if (SIV_GetKeyLength(AEAD_AES_128_GCM_SIV) > 0)
data[length++] = htons(AEAD_AES_128_GCM_SIV);
if (SIV_GetKeyLength(AEAD_AES_SIV_CMAC_256) > 0)
data[length++] = htons(AEAD_AES_SIV_CMAC_256);
if (!NKSN_AddRecord(session, 1, NKE_RECORD_AEAD_ALGORITHM, data,
length * sizeof (data[0])))
return 0;
if (!NKSN_EndMessage(session))
return 0;
return 1;
}
/* ================================================== */
static int
process_response(NKC_Instance inst)
{
int next_protocol = -1, aead_algorithm = -1, error = 0;
int i, critical, type, length;
uint16_t data[NKE_MAX_RECORD_BODY_LENGTH / sizeof (uint16_t)];
assert(NKE_MAX_COOKIE_LENGTH <= NKE_MAX_RECORD_BODY_LENGTH);
assert(sizeof (data) % sizeof (uint16_t) == 0);
assert(sizeof (uint16_t) == 2);
inst->num_cookies = 0;
inst->ntp_address.ip_addr.family = IPADDR_UNSPEC;
inst->ntp_address.port = 0;
inst->server_name[0] = '\0';
while (!error) {
if (!NKSN_GetRecord(inst->session, &critical, &type, &length, &data, sizeof (data)))
break;
if (length > sizeof (data)) {
DEBUG_LOG("Record too long type=%d length=%d critical=%d", type, length, critical);
if (critical)
error = 1;
continue;
}
switch (type) {
case NKE_RECORD_NEXT_PROTOCOL:
if (!critical || length != 2 || ntohs(data[0]) != NKE_NEXT_PROTOCOL_NTPV4) {
DEBUG_LOG("Unexpected NTS-KE next protocol");
error = 1;
break;
}
next_protocol = NKE_NEXT_PROTOCOL_NTPV4;
break;
case NKE_RECORD_AEAD_ALGORITHM:
if (length != 2 || (ntohs(data[0]) != AEAD_AES_SIV_CMAC_256 &&
ntohs(data[0]) != AEAD_AES_128_GCM_SIV) ||
SIV_GetKeyLength(ntohs(data[0])) <= 0) {
DEBUG_LOG("Unexpected NTS-KE AEAD algorithm");
error = 1;
break;
}
aead_algorithm = ntohs(data[0]);
inst->context.algorithm = aead_algorithm;
break;
case NKE_RECORD_ERROR:
if (length == 2)
DEBUG_LOG("NTS-KE error %d", ntohs(data[0]));
error = 1;
break;
case NKE_RECORD_WARNING:
if (length == 2)
DEBUG_LOG("NTS-KE warning %d", ntohs(data[0]));
error = 1;
break;
case NKE_RECORD_COOKIE:
DEBUG_LOG("Got cookie length=%d", length);
if (length < 1 || length > NKE_MAX_COOKIE_LENGTH || length % 4 != 0 ||
inst->num_cookies >= NKE_MAX_COOKIES) {
DEBUG_LOG("Unexpected length/cookie");
break;
}
assert(NKE_MAX_COOKIE_LENGTH == sizeof (inst->cookies[inst->num_cookies].cookie));
assert(NKE_MAX_COOKIES == sizeof (inst->cookies) /
sizeof (inst->cookies[inst->num_cookies]));
inst->cookies[inst->num_cookies].length = length;
memcpy(inst->cookies[inst->num_cookies].cookie, data, length);
inst->num_cookies++;
break;
case NKE_RECORD_NTPV4_SERVER_NEGOTIATION:
if (length < 1 || length >= sizeof (inst->server_name)) {
DEBUG_LOG("Invalid server name");
error = 1;
break;
}
memcpy(inst->server_name, data, length);
inst->server_name[length] = '\0';
/* Make sure the name is printable and has no spaces */
for (i = 0; i < length && isgraph((unsigned char)inst->server_name[i]); i++)
;
if (i != length) {
DEBUG_LOG("Invalid server name");
error = 1;
break;
}
DEBUG_LOG("Negotiated server %s", inst->server_name);
break;
case NKE_RECORD_NTPV4_PORT_NEGOTIATION:
if (length != 2) {
DEBUG_LOG("Invalid port");
error = 1;
break;
}
inst->ntp_address.port = ntohs(data[0]);
DEBUG_LOG("Negotiated port %d", inst->ntp_address.port);
break;
default:
DEBUG_LOG("Unknown record type=%d length=%d critical=%d", type, length, critical);
if (critical)
error = 1;
}
}
DEBUG_LOG("NTS-KE response: error=%d next=%d aead=%d",
error, next_protocol, aead_algorithm);
if (error || inst->num_cookies == 0 ||
next_protocol != NKE_NEXT_PROTOCOL_NTPV4 ||
aead_algorithm < 0)
return 0;
return 1;
}
/* ================================================== */
static int
handle_message(void *arg)
{
NKC_Instance inst = arg;
if (!process_response(inst)) {
LOG(LOGS_ERR, "Received invalid NTS-KE response from %s", inst->name);
return 0;
}
if (!NKSN_GetKeys(inst->session, inst->context.algorithm,
&inst->context.c2s, &inst->context.s2c))
return 0;
if (inst->server_name[0] != '\0') {
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;
}
}
inst->got_response = 1;
return 1;
}
/* ================================================== */
NKC_Instance
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);
inst->address = *address;
inst->name = Strdup(name);
inst->session = NKSN_CreateInstance(0, inst->name, handle_message, inst);
inst->resolving_name = 0;
inst->destroying = 0;
inst->got_response = 0;
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;
}
/* ================================================== */
void
NKC_DestroyInstance(NKC_Instance inst)
{
NKSN_DestroyInstance(inst->session);
Free(inst->name);
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
the instance later */
if (inst->resolving_name) {
inst->destroying = 1;
return;
}
Free(inst);
}
/* ================================================== */
int
NKC_Start(NKC_Instance inst)
{
IPSockAddr local_addr;
char label[512], *iface;
int sock_fd;
assert(!NKC_IsActive(inst));
inst->got_response = 0;
if (!inst->credentials) {
DEBUG_LOG("Missing client credentials");
return 0;
}
/* Don't try to connect if missing the algorithm which all servers
are required to support */
if (SIV_GetKeyLength(AEAD_AES_SIV_CMAC_256) <= 0) {
LOG(LOGS_ERR, "Missing AES-SIV-CMAC-256");
return 0;
}
/* Follow the bindacqaddress and bindacqdevice settings */
CNF_GetBindAcquisitionAddress(inst->address.ip_addr.family, &local_addr.ip_addr);
local_addr.port = 0;
iface = CNF_GetBindAcquisitionInterface();
/* 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, inst->credentials, CLIENT_TIMEOUT)) {
SCK_CloseSocket(sock_fd);
return 0;
}
/* Send a request */
if (!prepare_request(inst)) {
DEBUG_LOG("Could not prepare NTS-KE request");
NKSN_StopSession(inst->session);
return 0;
}
return 1;
}
/* ================================================== */
int
NKC_IsActive(NKC_Instance inst)
{
return !NKSN_IsStopped(inst->session) || inst->resolving_name;
}
/* ================================================== */
int
NKC_GetNtsData(NKC_Instance inst, NKE_Context *context,
NKE_Cookie *cookies, int *num_cookies, int max_cookies,
IPSockAddr *ntp_address)
{
int i;
if (!inst->got_response || inst->resolving_name)
return 0;
*context = inst->context;
for (i = 0; i < inst->num_cookies && i < max_cookies; i++)
cookies[i] = inst->cookies[i];
*num_cookies = i;
*ntp_address = inst->ntp_address;
return 1;
}
/* ================================================== */
int
NKC_GetRetryFactor(NKC_Instance inst)
{
return NKSN_GetRetryFactor(inst->session);
}

56
nts_ke_client.h Normal file
View File

@@ -0,0 +1,56 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Header file for the NTS-KE client
*/
#ifndef GOT_NTS_KE_CLIENT_H
#define GOT_NTS_KE_CLIENT_H
#include "addressing.h"
#include "nts_ke.h"
typedef struct NKC_Instance_Record *NKC_Instance;
/* Create a client NTS-KE instance */
extern NKC_Instance NKC_CreateInstance(IPSockAddr *address, const char *name, uint32_t cert_set);
/* Destroy an instance */
extern void NKC_DestroyInstance(NKC_Instance inst);
/* Connect to the server, start an NTS-KE session, send an NTS-KE request, and
process the response (asynchronously) */
extern int NKC_Start(NKC_Instance inst);
/* Check if the client is still running */
extern int NKC_IsActive(NKC_Instance inst);
/* Get the NTS data if the session was successful */
extern int NKC_GetNtsData(NKC_Instance inst, NKE_Context *context,
NKE_Cookie *cookies, int *num_cookies, int max_cookies,
IPSockAddr *ntp_address);
/* Get a factor to calculate retry interval (in log2 seconds) */
extern int NKC_GetRetryFactor(NKC_Instance inst);
#endif

1036
nts_ke_server.c Normal file

File diff suppressed because it is too large Load Diff

49
nts_ke_server.h Normal file
View File

@@ -0,0 +1,49 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Header file for the NTS-KE server
*/
#ifndef GOT_NTS_KE_SERVER_H
#define GOT_NTS_KE_SERVER_H
#include "nts_ke.h"
/* Init and fini functions */
extern void NKS_PreInitialise(uid_t uid, gid_t gid, int scfilter_level);
extern void NKS_Initialise(void);
extern void NKS_Finalise(void);
/* Save the current server keys */
extern void NKS_DumpKeys(void);
/* Reload the keys */
extern void NKS_ReloadKeys(void);
/* Generate an NTS cookie with a given context */
extern int NKS_GenerateCookie(NKE_Context *context, NKE_Cookie *cookie);
/* Validate a cookie and decode the context */
extern int NKS_DecodeCookie(NKE_Cookie *cookie, NKE_Context *context);
#endif

929
nts_ke_session.c Normal file
View File

@@ -0,0 +1,929 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2020-2021
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
NTS-KE session used by server and client
*/
#include "config.h"
#include "sysincl.h"
#include "nts_ke_session.h"
#include "conf.h"
#include "local.h"
#include "logging.h"
#include "memory.h"
#include "siv.h"
#include "socket.h"
#include "sched.h"
#include "util.h"
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#define INVALID_SOCK_FD (-8)
struct RecordHeader {
uint16_t type;
uint16_t body_length;
};
struct Message {
int length;
int sent;
int parsed;
int complete;
unsigned char data[NKE_MAX_MESSAGE_LENGTH];
};
typedef enum {
KE_WAIT_CONNECT,
KE_HANDSHAKE,
KE_SEND,
KE_RECEIVE,
KE_SHUTDOWN,
KE_STOPPED,
} KeState;
struct NKSN_Instance_Record {
int server;
char *server_name;
NKSN_MessageHandler handler;
void *handler_arg;
KeState state;
int sock_fd;
char *label;
gnutls_session_t tls_session;
SCH_TimeoutID timeout_id;
int retry_factor;
struct Message message;
int new_message;
};
/* ================================================== */
static gnutls_priority_t priority_cache;
static int credentials_counter = 0;
static int clock_updates = 0;
/* ================================================== */
static void
reset_message(struct Message *message)
{
message->length = 0;
message->sent = 0;
message->parsed = 0;
message->complete = 0;
}
/* ================================================== */
static int
add_record(struct Message *message, int critical, int type, const void *body, int body_length)
{
struct RecordHeader header;
assert(message->length <= sizeof (message->data));
if (body_length < 0 || body_length > 0xffff || type < 0 || type > 0x7fff ||
message->length + sizeof (header) + body_length > sizeof (message->data))
return 0;
header.type = htons(!!critical * NKE_RECORD_CRITICAL_BIT | type);
header.body_length = htons(body_length);
memcpy(&message->data[message->length], &header, sizeof (header));
message->length += sizeof (header);
if (body_length > 0) {
memcpy(&message->data[message->length], body, body_length);
message->length += body_length;
}
return 1;
}
/* ================================================== */
static void
reset_message_parsing(struct Message *message)
{
message->parsed = 0;
}
/* ================================================== */
static int
get_record(struct Message *message, int *critical, int *type, int *body_length,
void *body, int buffer_length)
{
struct RecordHeader header;
int blen, rlen;
if (message->length < message->parsed + sizeof (header) ||
buffer_length < 0)
return 0;
memcpy(&header, &message->data[message->parsed], sizeof (header));
blen = ntohs(header.body_length);
rlen = sizeof (header) + blen;
assert(blen >= 0 && rlen > 0);
if (message->length < message->parsed + rlen)
return 0;
if (critical)
*critical = !!(ntohs(header.type) & NKE_RECORD_CRITICAL_BIT);
if (type)
*type = ntohs(header.type) & ~NKE_RECORD_CRITICAL_BIT;
if (body)
memcpy(body, &message->data[message->parsed + sizeof (header)], MIN(buffer_length, blen));
if (body_length)
*body_length = blen;
message->parsed += rlen;
return 1;
}
/* ================================================== */
static int
check_message_format(struct Message *message, int eof)
{
int critical = 0, type = -1, length = -1, ends = 0;
reset_message_parsing(message);
message->complete = 0;
while (get_record(message, &critical, &type, &length, NULL, 0)) {
if (type == NKE_RECORD_END_OF_MESSAGE) {
if (!critical || length != 0 || ends > 0)
return 0;
ends++;
}
}
/* If the message cannot be fully parsed, but more data may be coming,
consider the format to be ok */
if (message->length == 0 || message->parsed < message->length)
return !eof;
if (type != NKE_RECORD_END_OF_MESSAGE)
return !eof;
message->complete = 1;
return 1;
}
/* ================================================== */
static gnutls_session_t
create_tls_session(int server_mode, int sock_fd, const char *server_name,
gnutls_certificate_credentials_t credentials,
gnutls_priority_t priority)
{
unsigned char alpn_name[sizeof (NKE_ALPN_NAME)];
gnutls_session_t session;
gnutls_datum_t alpn;
unsigned int flags;
int r;
r = gnutls_init(&session, GNUTLS_NONBLOCK | GNUTLS_NO_TICKETS |
(server_mode ? GNUTLS_SERVER : GNUTLS_CLIENT));
if (r < 0) {
LOG(LOGS_ERR, "Could not %s TLS session : %s", "create", gnutls_strerror(r));
return NULL;
}
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;
if (clock_updates < CNF_GetNoCertTimeCheck()) {
flags |= GNUTLS_VERIFY_DISABLE_TIME_CHECKS | GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS;
DEBUG_LOG("Disabled time checks");
}
gnutls_session_set_verify_cert(session, server_name, flags);
}
r = gnutls_priority_set(session, priority);
if (r < 0)
goto error;
r = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, credentials);
if (r < 0)
goto error;
memcpy(alpn_name, NKE_ALPN_NAME, sizeof (alpn_name));
alpn.data = alpn_name;
alpn.size = sizeof (alpn_name) - 1;
r = gnutls_alpn_set_protocols(session, &alpn, 1, 0);
if (r < 0)
goto error;
gnutls_transport_set_int(session, sock_fd);
return session;
error:
LOG(LOGS_ERR, "Could not %s TLS session : %s", "set", gnutls_strerror(r));
gnutls_deinit(session);
return NULL;
}
/* ================================================== */
static void
stop_session(NKSN_Instance inst)
{
if (inst->state == KE_STOPPED)
return;
inst->state = KE_STOPPED;
SCH_RemoveFileHandler(inst->sock_fd);
SCK_CloseSocket(inst->sock_fd);
inst->sock_fd = INVALID_SOCK_FD;
Free(inst->label);
inst->label = NULL;
gnutls_deinit(inst->tls_session);
inst->tls_session = NULL;
SCH_RemoveTimeout(inst->timeout_id);
inst->timeout_id = 0;
}
/* ================================================== */
static void
session_timeout(void *arg)
{
NKSN_Instance inst = arg;
LOG(inst->server ? LOGS_DEBUG : LOGS_ERR, "NTS-KE session with %s timed out", inst->label);
inst->timeout_id = 0;
stop_session(inst);
}
/* ================================================== */
static int
check_alpn(NKSN_Instance inst)
{
gnutls_datum_t alpn;
if (gnutls_alpn_get_selected_protocol(inst->tls_session, &alpn) < 0 ||
alpn.size != sizeof (NKE_ALPN_NAME) - 1 ||
memcmp(alpn.data, NKE_ALPN_NAME, sizeof (NKE_ALPN_NAME) - 1) != 0)
return 0;
return 1;
}
/* ================================================== */
static void
set_input_output(NKSN_Instance inst, int output)
{
SCH_SetFileHandlerEvent(inst->sock_fd, SCH_FILE_INPUT, !output);
SCH_SetFileHandlerEvent(inst->sock_fd, SCH_FILE_OUTPUT, output);
}
/* ================================================== */
static void
change_state(NKSN_Instance inst, KeState state)
{
int output;
switch (state) {
case KE_HANDSHAKE:
output = !inst->server;
break;
case KE_WAIT_CONNECT:
case KE_SEND:
case KE_SHUTDOWN:
output = 1;
break;
case KE_RECEIVE:
output = 0;
break;
default:
assert(0);
}
set_input_output(inst, output);
inst->state = state;
}
/* ================================================== */
static int
handle_event(NKSN_Instance inst, int event)
{
struct Message *message = &inst->message;
int r;
DEBUG_LOG("Session event %d fd=%d state=%d", event, inst->sock_fd, (int)inst->state);
switch (inst->state) {
case KE_WAIT_CONNECT:
/* Check if connect() succeeded */
if (event != SCH_FILE_OUTPUT)
return 0;
/* Get the socket error */
if (!SCK_GetIntOption(inst->sock_fd, SOL_SOCKET, SO_ERROR, &r))
r = EINVAL;
if (r != 0) {
LOG(LOGS_ERR, "Could not connect to %s : %s", inst->label, strerror(r));
stop_session(inst);
return 0;
}
DEBUG_LOG("Connected to %s", inst->label);
change_state(inst, KE_HANDSHAKE);
return 0;
case KE_HANDSHAKE:
r = gnutls_handshake(inst->tls_session);
if (r < 0) {
if (gnutls_error_is_fatal(r)) {
gnutls_datum_t cert_error;
/* Get a description of verification errors */
if (r != GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR ||
gnutls_certificate_verification_status_print(
gnutls_session_get_verify_cert_status(inst->tls_session),
gnutls_certificate_type_get(inst->tls_session), &cert_error, 0) < 0)
cert_error.data = NULL;
LOG(inst->server ? LOGS_DEBUG : LOGS_ERR,
"TLS handshake with %s failed : %s%s%s", inst->label, gnutls_strerror(r),
cert_error.data ? " " : "", cert_error.data ? (const char *)cert_error.data : "");
if (cert_error.data)
gnutls_free(cert_error.data);
stop_session(inst);
/* Increase the retry interval if the handshake did not fail due
to the other end closing the connection */
if (r != GNUTLS_E_PULL_ERROR && r != GNUTLS_E_PREMATURE_TERMINATION)
inst->retry_factor = NKE_RETRY_FACTOR2_TLS;
return 0;
}
/* Disable output when the handshake is trying to receive data */
set_input_output(inst, gnutls_record_get_direction(inst->tls_session));
return 0;
}
inst->retry_factor = NKE_RETRY_FACTOR2_TLS;
if (DEBUG) {
char *description = gnutls_session_get_desc(inst->tls_session);
DEBUG_LOG("Handshake with %s completed %s",
inst->label, description ? description : "");
gnutls_free(description);
}
if (!check_alpn(inst)) {
LOG(inst->server ? LOGS_DEBUG : LOGS_ERR, "NTS-KE not supported by %s", inst->label);
stop_session(inst);
return 0;
}
/* Client will send a request to the server */
change_state(inst, inst->server ? KE_RECEIVE : KE_SEND);
return 0;
case KE_SEND:
assert(inst->new_message && message->complete);
assert(message->length <= sizeof (message->data) && message->length > message->sent);
r = gnutls_record_send(inst->tls_session, &message->data[message->sent],
message->length - message->sent);
if (r < 0) {
if (gnutls_error_is_fatal(r)) {
LOG(inst->server ? LOGS_DEBUG : LOGS_ERR,
"Could not send NTS-KE message to %s : %s", inst->label, gnutls_strerror(r));
stop_session(inst);
}
return 0;
}
DEBUG_LOG("Sent %d bytes to %s", r, inst->label);
message->sent += r;
if (message->sent < message->length)
return 0;
/* Client will receive a response */
change_state(inst, inst->server ? KE_SHUTDOWN : KE_RECEIVE);
reset_message(&inst->message);
inst->new_message = 0;
return 0;
case KE_RECEIVE:
do {
if (message->length >= sizeof (message->data)) {
DEBUG_LOG("Message is too long");
stop_session(inst);
return 0;
}
r = gnutls_record_recv(inst->tls_session, &message->data[message->length],
sizeof (message->data) - message->length);
if (r < 0) {
/* Handle a renegotiation request on both client and server as
a protocol error */
if (gnutls_error_is_fatal(r) || r == GNUTLS_E_REHANDSHAKE) {
LOG(inst->server ? LOGS_DEBUG : LOGS_ERR,
"Could not receive NTS-KE message from %s : %s",
inst->label, gnutls_strerror(r));
stop_session(inst);
}
return 0;
}
DEBUG_LOG("Received %d bytes from %s", r, inst->label);
message->length += r;
} while (gnutls_record_check_pending(inst->tls_session) > 0);
if (!check_message_format(message, r == 0)) {
LOG(inst->server ? LOGS_DEBUG : LOGS_ERR,
"Received invalid NTS-KE message from %s", inst->label);
stop_session(inst);
return 0;
}
/* Wait for more data if the message is not complete yet */
if (!message->complete)
return 0;
/* Server will send a response to the client */
change_state(inst, inst->server ? KE_SEND : KE_SHUTDOWN);
/* Return success to process the received message */
return 1;
case KE_SHUTDOWN:
r = gnutls_bye(inst->tls_session, GNUTLS_SHUT_RDWR);
if (r < 0) {
if (gnutls_error_is_fatal(r)) {
DEBUG_LOG("Shutdown with %s failed : %s", inst->label, gnutls_strerror(r));
stop_session(inst);
return 0;
}
/* Disable output when the TLS shutdown is trying to receive data */
set_input_output(inst, gnutls_record_get_direction(inst->tls_session));
return 0;
}
SCK_ShutdownConnection(inst->sock_fd);
stop_session(inst);
DEBUG_LOG("Shutdown completed");
return 0;
default:
assert(0);
return 0;
}
}
/* ================================================== */
static void
read_write_socket(int fd, int event, void *arg)
{
NKSN_Instance inst = arg;
if (!handle_event(inst, event))
return;
/* A valid message was received. Call the handler to process the message,
and prepare a response if it is a server. */
reset_message_parsing(&inst->message);
if (!(inst->handler)(inst->handler_arg)) {
stop_session(inst);
return;
}
}
/* ================================================== */
static time_t
get_time(time_t *t)
{
struct timespec now;
LCL_ReadCookedTime(&now, NULL);
if (t)
*t = now.tv_sec;
return now.tv_sec;
}
/* ================================================== */
static void
handle_step(struct timespec *raw, struct timespec *cooked, double dfreq,
double doffset, LCL_ChangeType change_type, void *anything)
{
if (change_type != LCL_ChangeUnknownStep && clock_updates < INT_MAX)
clock_updates++;
}
/* ================================================== */
static int gnutls_initialised = 0;
static int
init_gnutls(void)
{
int r;
if (gnutls_initialised)
return 1;
r = gnutls_global_init();
if (r < 0)
LOG_FATAL("Could not initialise %s : %s", "gnutls", gnutls_strerror(r));
/* Prepare a priority cache for server and client NTS-KE sessions
(the NTS specification requires TLS1.3 or later) */
r = gnutls_priority_init2(&priority_cache,
"-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1:-VERS-TLS1.2:-VERS-DTLS-ALL",
NULL, GNUTLS_PRIORITY_INIT_DEF_APPEND);
if (r < 0) {
LOG(LOGS_ERR, "Could not initialise %s : %s",
"priority cache for TLS", gnutls_strerror(r));
gnutls_global_deinit();
return 0;
}
/* Use our clock instead of the system clock in certificate verification */
gnutls_global_set_time_function(get_time);
gnutls_initialised = 1;
DEBUG_LOG("Initialised");
LCL_AddParameterChangeHandler(handle_step, NULL);
return 1;
}
/* ================================================== */
static void
deinit_gnutls(void)
{
if (!gnutls_initialised || credentials_counter > 0)
return;
LCL_RemoveParameterChangeHandler(handle_step, NULL);
gnutls_priority_deinit(priority_cache);
gnutls_global_deinit();
gnutls_initialised = 0;
DEBUG_LOG("Deinitialised");
}
/* ================================================== */
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 i, r;
if (!init_gnutls())
return NULL;
r = gnutls_certificate_allocate_credentials(&credentials);
if (r < 0)
goto error;
if (certs && keys) {
if (trusted_certs || trusted_certs_ids)
assert(0);
for (i = 0; i < n_certs_keys; i++) {
if (!UTI_CheckFilePermissions(keys[i], 0771))
;
r = gnutls_certificate_set_x509_key_file(credentials, certs[i], keys[i],
GNUTLS_X509_FMT_PEM);
if (r < 0)
goto error;
}
} else {
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 && 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 (NKSN_Credentials)credentials;
error:
LOG(LOGS_ERR, "Could not set credentials : %s", gnutls_strerror(r));
if (credentials)
gnutls_certificate_free_credentials(credentials);
deinit_gnutls();
return NULL;
}
/* ================================================== */
NKSN_Credentials
NKSN_CreateServerCertCredentials(const char **certs, const char **keys, int n_certs_keys)
{
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();
}
/* ================================================== */
NKSN_Instance
NKSN_CreateInstance(int server_mode, const char *server_name,
NKSN_MessageHandler handler, void *handler_arg)
{
NKSN_Instance inst;
inst = MallocNew(struct NKSN_Instance_Record);
inst->server = server_mode;
inst->server_name = server_name ? Strdup(server_name) : NULL;
inst->handler = handler;
inst->handler_arg = handler_arg;
/* Replace a NULL argument with the session itself */
if (!inst->handler_arg)
inst->handler_arg = inst;
inst->state = KE_STOPPED;
inst->sock_fd = INVALID_SOCK_FD;
inst->label = NULL;
inst->tls_session = NULL;
inst->timeout_id = 0;
inst->retry_factor = NKE_RETRY_FACTOR2_CONNECT;
return inst;
}
/* ================================================== */
void
NKSN_DestroyInstance(NKSN_Instance inst)
{
stop_session(inst);
Free(inst->server_name);
Free(inst);
}
/* ================================================== */
int
NKSN_StartSession(NKSN_Instance inst, int sock_fd, const char *label,
NKSN_Credentials credentials, double timeout)
{
assert(inst->state == KE_STOPPED);
inst->tls_session = create_tls_session(inst->server, sock_fd, inst->server_name,
(gnutls_certificate_credentials_t)credentials,
priority_cache);
if (!inst->tls_session)
return 0;
inst->sock_fd = sock_fd;
SCH_AddFileHandler(sock_fd, SCH_FILE_INPUT, read_write_socket, inst);
inst->label = Strdup(label);
inst->timeout_id = SCH_AddTimeoutByDelay(timeout, session_timeout, inst);
inst->retry_factor = NKE_RETRY_FACTOR2_CONNECT;
reset_message(&inst->message);
inst->new_message = 0;
change_state(inst, inst->server ? KE_HANDSHAKE : KE_WAIT_CONNECT);
return 1;
}
/* ================================================== */
void
NKSN_BeginMessage(NKSN_Instance inst)
{
reset_message(&inst->message);
inst->new_message = 1;
}
/* ================================================== */
int
NKSN_AddRecord(NKSN_Instance inst, int critical, int type, const void *body, int body_length)
{
assert(inst->new_message && !inst->message.complete);
assert(type != NKE_RECORD_END_OF_MESSAGE);
return add_record(&inst->message, critical, type, body, body_length);
}
/* ================================================== */
int
NKSN_EndMessage(NKSN_Instance inst)
{
assert(!inst->message.complete);
/* Terminate the message */
if (!add_record(&inst->message, 1, NKE_RECORD_END_OF_MESSAGE, NULL, 0))
return 0;
inst->message.complete = 1;
return 1;
}
/* ================================================== */
int
NKSN_GetRecord(NKSN_Instance inst, int *critical, int *type, int *body_length,
void *body, int buffer_length)
{
int type2;
assert(inst->message.complete);
if (body_length)
*body_length = 0;
if (!get_record(&inst->message, critical, &type2, body_length, body, buffer_length))
return 0;
/* Hide the end-of-message record */
if (type2 == NKE_RECORD_END_OF_MESSAGE)
return 0;
if (type)
*type = type2;
return 1;
}
/* ================================================== */
int
NKSN_GetKeys(NKSN_Instance inst, SIV_Algorithm siv, NKE_Key *c2s, NKE_Key *s2c)
{
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,
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,
length, (char *)s2c->key) < 0) {
DEBUG_LOG("Could not export key");
return 0;
}
c2s->length = length;
s2c->length = length;
return 1;
}
/* ================================================== */
int
NKSN_IsStopped(NKSN_Instance inst)
{
return inst->state == KE_STOPPED;
}
/* ================================================== */
void
NKSN_StopSession(NKSN_Instance inst)
{
stop_session(inst);
}
/* ================================================== */
int
NKSN_GetRetryFactor(NKSN_Instance inst)
{
return inst->retry_factor;
}

93
nts_ke_session.h Normal file
View File

@@ -0,0 +1,93 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Header file for the NTS-KE session
*/
#ifndef GOT_NTS_KE_SESSION_H
#define GOT_NTS_KE_SESSION_H
#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 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 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(NKSN_Credentials credentials);
/* Create an instance */
extern NKSN_Instance NKSN_CreateInstance(int server_mode, const char *server_name,
NKSN_MessageHandler handler, void *handler_arg);
/* Destroy an instance */
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,
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. */
extern void NKSN_BeginMessage(NKSN_Instance inst);
/* Add a record to the message */
extern int NKSN_AddRecord(NKSN_Instance inst, int critical, int type,
const void *body, int body_length);
/* Terminate the message */
extern int NKSN_EndMessage(NKSN_Instance inst);
/* Get the next record from the received message. This function should be
called from the message handler. */
extern int NKSN_GetRecord(NKSN_Instance inst, int *critical, int *type, int *body_length,
void *body, int buffer_length);
/* Export NTS keys for a specified algorithm */
extern int NKSN_GetKeys(NKSN_Instance inst, SIV_Algorithm siv, NKE_Key *c2s, NKE_Key *s2c);
/* Check if the session has stopped */
extern int NKSN_IsStopped(NKSN_Instance inst);
/* Stop the session */
extern void NKSN_StopSession(NKSN_Instance inst);
/* Get a factor to calculate retry interval (in log2 seconds)
based on the session state or how it was terminated */
extern int NKSN_GetRetryFactor(NKSN_Instance inst);
#endif

36
nts_ntp.h Normal file
View File

@@ -0,0 +1,36 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Header file for the NTS-NTP protocol
*/
#ifndef GOT_NTS_NTP_H
#define GOT_NTS_NTP_H
#define NTP_KOD_NTS_NAK 0x4e54534e
#define NTS_MIN_UNIQ_ID_LENGTH 32
#define NTS_MIN_UNPADDED_NONCE_LENGTH 16
#define NTS_MAX_COOKIES 8
#endif

187
nts_ntp_auth.c Normal file
View File

@@ -0,0 +1,187 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
NTS Authenticator and Encrypted Extension Fields extension field
*/
#include "config.h"
#include "sysincl.h"
#include "nts_ntp_auth.h"
#include "logging.h"
#include "ntp_ext.h"
#include "nts_ntp.h"
#include "siv.h"
#include "util.h"
struct AuthHeader {
uint16_t nonce_length;
uint16_t ciphertext_length;
};
/* ================================================== */
static int
get_padding_length(int length)
{
return length % 4U ? 4 - length % 4U : 0;
}
/* ================================================== */
static int
get_padded_length(int length)
{
return length + get_padding_length(length);
}
/* ================================================== */
int
NNA_GenerateAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv,
const unsigned char *nonce, int max_nonce_length,
const unsigned char *plaintext, int plaintext_length,
int min_ef_length)
{
int auth_length, ciphertext_length, assoc_length, nonce_length, max_siv_nonce_length;
int nonce_padding, ciphertext_padding, additional_padding;
unsigned char *ciphertext, *body;
struct AuthHeader *header;
assert(sizeof (*header) == 4);
if (max_nonce_length <= 0 || plaintext_length < 0) {
DEBUG_LOG("Invalid nonce/plaintext length");
return 0;
}
assoc_length = info->length;
max_siv_nonce_length = SIV_GetMaxNonceLength(siv);
nonce_length = MIN(max_nonce_length, max_siv_nonce_length);
ciphertext_length = SIV_GetTagLength(siv) + plaintext_length;
nonce_padding = get_padding_length(nonce_length);
ciphertext_padding = get_padding_length(ciphertext_length);
min_ef_length = get_padded_length(min_ef_length);
auth_length = sizeof (*header) + nonce_length + nonce_padding +
ciphertext_length + ciphertext_padding;
additional_padding = MAX(min_ef_length - auth_length - 4, 0);
additional_padding = MAX(MIN(NTS_MIN_UNPADDED_NONCE_LENGTH, max_siv_nonce_length) -
nonce_length - nonce_padding, additional_padding);
auth_length += additional_padding;
if (!NEF_AddBlankField(packet, info, NTP_EF_NTS_AUTH_AND_EEF, auth_length,
(void **)&header)) {
DEBUG_LOG("Could not add EF");
return 0;
}
header->nonce_length = htons(nonce_length);
header->ciphertext_length = htons(ciphertext_length);
body = (unsigned char *)(header + 1);
ciphertext = body + nonce_length + nonce_padding;
if ((unsigned char *)header + auth_length !=
ciphertext + ciphertext_length + ciphertext_padding + additional_padding)
assert(0);
memcpy(body, nonce, nonce_length);
memset(body + nonce_length, 0, nonce_padding);
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;
info->ext_fields--;
return 0;
}
memset(ciphertext + ciphertext_length, 0, ciphertext_padding + additional_padding);
return 1;
}
/* ================================================== */
int
NNA_DecryptAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv, int ef_start,
unsigned char *plaintext, int buffer_length, int *plaintext_length)
{
int siv_tag_length, max_siv_nonce_length, nonce_length, ciphertext_length;
unsigned char *nonce, *ciphertext;
int ef_type, ef_body_length;
void *ef_body;
struct AuthHeader *header;
if (buffer_length < 0)
return 0;
if (!NEF_ParseField(packet, info->length, ef_start,
NULL, &ef_type, &ef_body, &ef_body_length))
return 0;
if (ef_type != NTP_EF_NTS_AUTH_AND_EEF || ef_body_length < sizeof (*header))
return 0;
header = ef_body;
nonce_length = ntohs(header->nonce_length);
ciphertext_length = ntohs(header->ciphertext_length);
if (get_padded_length(nonce_length) +
get_padded_length(ciphertext_length) > ef_body_length)
return 0;
nonce = (unsigned char *)(header + 1);
ciphertext = nonce + get_padded_length(nonce_length);
max_siv_nonce_length = SIV_GetMaxNonceLength(siv);
siv_tag_length = SIV_GetTagLength(siv);
if (nonce_length < 1 ||
ciphertext_length < siv_tag_length ||
ciphertext_length - siv_tag_length > buffer_length) {
DEBUG_LOG("Unexpected nonce/ciphertext length");
return 0;
}
if (sizeof (*header) + MIN(NTS_MIN_UNPADDED_NONCE_LENGTH, max_siv_nonce_length) +
get_padded_length(ciphertext_length) > ef_body_length) {
DEBUG_LOG("Missing padding");
return 0;
}
*plaintext_length = ciphertext_length - siv_tag_length;
assert(*plaintext_length >= 0);
if (!SIV_Decrypt(siv, nonce, nonce_length, packet, ef_start,
ciphertext, ciphertext_length, plaintext, *plaintext_length)) {
DEBUG_LOG("SIV decrypt failed");
return 0;
}
return 1;
}

43
nts_ntp_auth.h Normal file
View File

@@ -0,0 +1,43 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Header for NTS Authenticator and Encrypted Extension Fields
extension field
*/
#ifndef GOT_NTS_NTP_AUTH_H
#define GOT_NTS_NTP_AUTH_H
#include "ntp.h"
#include "siv.h"
extern int NNA_GenerateAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv,
const unsigned char *nonce, int max_nonce_length,
const unsigned char *plaintext, int plaintext_length,
int min_ef_length);
extern int NNA_DecryptAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv,
int ef_start, unsigned char *plaintext, int buffer_length,
int *plaintext_length);
#endif

717
nts_ntp_client.c Normal file
View File

@@ -0,0 +1,717 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Client NTS-NTP authentication
*/
#include "config.h"
#include "sysincl.h"
#include "nts_ntp_client.h"
#include "conf.h"
#include "logging.h"
#include "memory.h"
#include "ntp.h"
#include "ntp_ext.h"
#include "ntp_sources.h"
#include "nts_ke_client.h"
#include "nts_ntp.h"
#include "nts_ntp_auth.h"
#include "sched.h"
#include "siv.h"
#include "util.h"
/* Maximum length of all cookies to avoid IP fragmentation */
#define MAX_TOTAL_COOKIE_LENGTH (8 * 108)
/* Retry interval for NTS-KE start (which doesn't generate network traffic) */
#define RETRY_INTERVAL_KE_START 2.0
/* Magic string of files containing keys and cookies */
#define DUMP_IDENTIFIER "NNC0\n"
struct NNC_Instance_Record {
/* 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 nke_attempts;
double next_nke_attempt;
double last_nke_success;
NKE_Context context;
unsigned int context_id;
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];
unsigned char uniq_id[NTS_MIN_UNIQ_ID_LENGTH];
};
/* ================================================== */
static void save_cookies(NNC_Instance inst);
static void load_cookies(NNC_Instance inst);
/* ================================================== */
static void
reset_instance(NNC_Instance inst)
{
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;
memset(&inst->context, 0, sizeof (inst->context));
inst->context_id = 0;
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));
memset(inst->uniq_id, 0, sizeof (inst->uniq_id));
}
/* ================================================== */
NNC_Instance
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->nts_address = *nts_address;
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;
}
/* ================================================== */
void
NNC_DestroyInstance(NNC_Instance inst)
{
save_cookies(inst);
reset_instance(inst);
Free(inst->name);
Free(inst);
}
/* ================================================== */
static int
check_cookies(NNC_Instance inst)
{
/* Force a new NTS-KE session if a NAK was received without a valid response,
or the keys encrypting the cookies need to be refreshed */
if (inst->num_cookies > 0 &&
((inst->nak_response && !inst->ok_response) ||
SCH_GetLastEventMonoTime() - inst->last_nke_success > CNF_GetNtsRefresh())) {
inst->num_cookies = 0;
DEBUG_LOG("Dropped cookies");
}
return inst->num_cookies > 0;
}
/* ================================================== */
static int
set_ntp_address(NNC_Instance inst, NTP_Remote_Address *negotiated_address)
{
NTP_Remote_Address old_address, new_address;
old_address = inst->ntp_address;
new_address = *negotiated_address;
if (new_address.ip_addr.family == IPADDR_UNSPEC)
new_address.ip_addr = inst->nts_address.ip_addr;
if (new_address.port == 0)
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)
/* Nothing to do */
return 1;
if (NSR_UpdateSourceNtpAddress(&old_address, &new_address) != NSR_Success) {
LOG(LOGS_ERR, "Could not change %s to negotiated address %s",
UTI_IPToString(&old_address.ip_addr), UTI_IPToString(&new_address.ip_addr));
return 0;
}
inst->ntp_address = new_address;
return 1;
}
/* ================================================== */
static void
update_next_nke_attempt(NNC_Instance inst, int failed_start, double now)
{
int factor, interval;
if (failed_start) {
inst->next_nke_attempt = now + RETRY_INTERVAL_KE_START;
return;
}
if (!inst->nke)
return;
factor = NKC_GetRetryFactor(inst->nke);
interval = MIN(factor + inst->nke_attempts - 1, NKE_MAX_RETRY_INTERVAL2);
inst->next_nke_attempt = now + UTI_Log2ToDouble(interval);
}
/* ================================================== */
static int
get_cookies(NNC_Instance inst)
{
NTP_Remote_Address ntp_address;
int got_data, failed_start = 0;
double now;
assert(inst->num_cookies == 0);
now = SCH_GetLastEventMonoTime();
/* Create and start a new NTS-KE session if not already present */
if (!inst->nke) {
if (now < inst->next_nke_attempt) {
DEBUG_LOG("Limiting NTS-KE request rate (%f seconds)",
inst->next_nke_attempt - now);
return 0;
}
inst->nke = NKC_CreateInstance(&inst->nts_address, inst->name, inst->cert_set);
inst->nke_attempts++;
if (!NKC_Start(inst->nke))
failed_start = 1;
}
update_next_nke_attempt(inst, failed_start, now);
/* Wait until the session stops */
if (NKC_IsActive(inst->nke))
return 0;
assert(sizeof (inst->cookies) / sizeof (inst->cookies[0]) == NTS_MAX_COOKIES);
/* Get the new keys, cookies and NTP address if the session was successful */
got_data = NKC_GetNtsData(inst->nke, &inst->context,
inst->cookies, &inst->num_cookies, NTS_MAX_COOKIES,
&ntp_address);
NKC_DestroyInstance(inst->nke);
inst->nke = NULL;
if (!got_data)
return 0;
if (inst->siv)
SIV_DestroyInstance(inst->siv);
inst->siv = NULL;
inst->context_id++;
/* Force a new session if the NTP address is used by another source, with
an expectation that it will eventually get a non-conflicting address */
if (!set_ntp_address(inst, &ntp_address)) {
inst->num_cookies = 0;
return 0;
}
inst->last_nke_success = now;
inst->cookie_index = 0;
return 1;
}
/* ================================================== */
int
NNC_PrepareForAuth(NNC_Instance inst)
{
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)) {
if (!get_cookies(inst))
return 0;
}
inst->nak_response = 0;
if (!inst->siv)
inst->siv = SIV_CreateInstance(inst->context.algorithm);
if (!inst->siv ||
!SIV_SetKey(inst->siv, inst->context.c2s.key, inst->context.c2s.length)) {
DEBUG_LOG("Could not set SIV key");
return 0;
}
inst->auth_ready = 1;
return 1;
}
/* ================================================== */
int
NNC_GenerateRequestAuth(NNC_Instance inst, NTP_Packet *packet,
NTP_PacketInfo *info)
{
NKE_Cookie *cookie;
int i, req_cookies;
void *ef_body;
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];
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,
inst->uniq_id, sizeof (inst->uniq_id)))
return 0;
if (!NEF_AddField(packet, info, NTP_EF_NTS_COOKIE,
cookie->cookie, cookie->length))
return 0;
for (i = 0; i < req_cookies - 1; i++) {
if (!NEF_AddBlankField(packet, info, NTP_EF_NTS_COOKIE_PLACEHOLDER,
cookie->length, &ef_body))
return 0;
memset(ef_body, 0, cookie->length);
}
if (!NNA_GenerateAuthEF(packet, info, inst->siv, inst->nonce, sizeof (inst->nonce),
(const unsigned char *)"", 0, NTP_MAX_V4_MAC_LENGTH + 4))
return 0;
inst->ok_response = 0;
return 1;
}
/* ================================================== */
static int
parse_encrypted_efs(NNC_Instance inst, unsigned char *plaintext, int length)
{
int ef_length, parsed;
for (parsed = 0; parsed < length; parsed += ef_length) {
if (!NEF_ParseSingleField(plaintext, length, parsed, &ef_length, NULL, NULL, NULL)) {
DEBUG_LOG("Could not parse encrypted EF");
return 0;
}
}
return 1;
}
/* ================================================== */
static int
extract_cookies(NNC_Instance inst, unsigned char *plaintext, int length)
{
int ef_type, ef_body_length, ef_length, parsed, index, acceptable, saved;
void *ef_body;
acceptable = saved = 0;
for (parsed = 0; parsed < length; parsed += ef_length) {
if (!NEF_ParseSingleField(plaintext, length, parsed,
&ef_length, &ef_type, &ef_body, &ef_body_length))
return 0;
if (ef_type != NTP_EF_NTS_COOKIE)
continue;
if (ef_length < NTP_MIN_EF_LENGTH || ef_body_length > sizeof (inst->cookies[0].cookie)) {
DEBUG_LOG("Unexpected cookie length %d", ef_body_length);
continue;
}
acceptable++;
if (inst->num_cookies >= NTS_MAX_COOKIES)
continue;
index = (inst->cookie_index + inst->num_cookies) % NTS_MAX_COOKIES;
assert(index >= 0 && index < NTS_MAX_COOKIES);
assert(sizeof (inst->cookies) / sizeof (inst->cookies[0]) == NTS_MAX_COOKIES);
memcpy(inst->cookies[index].cookie, ef_body, ef_body_length);
inst->cookies[index].length = ef_body_length;
inst->num_cookies++;
saved++;
}
DEBUG_LOG("Extracted %d cookies (saved %d)", acceptable, saved);
return acceptable > 0;
}
/* ================================================== */
int
NNC_CheckResponseAuth(NNC_Instance inst, NTP_Packet *packet,
NTP_PacketInfo *info)
{
int ef_type, ef_body_length, ef_length, parsed, plaintext_length;
int has_valid_uniq_id = 0, has_valid_auth = 0;
unsigned char plaintext[NTP_MAX_EXTENSIONS_LENGTH];
void *ef_body;
if (info->ext_fields == 0 || info->mode != MODE_SERVER)
return 0;
/* Accept at most one response per request */
if (inst->ok_response || inst->auth_ready)
return 0;
if (!inst->siv ||
!SIV_SetKey(inst->siv, inst->context.s2c.key, inst->context.s2c.length)) {
DEBUG_LOG("Could not set SIV key");
return 0;
}
for (parsed = NTP_HEADER_LENGTH; parsed < info->length; parsed += ef_length) {
if (!NEF_ParseField(packet, info->length, parsed,
&ef_length, &ef_type, &ef_body, &ef_body_length))
/* This is not expected as the packet already passed parsing */
return 0;
switch (ef_type) {
case NTP_EF_NTS_UNIQUE_IDENTIFIER:
if (ef_body_length != sizeof (inst->uniq_id) ||
memcmp(ef_body, inst->uniq_id, sizeof (inst->uniq_id)) != 0) {
DEBUG_LOG("Invalid uniq id");
return 0;
}
has_valid_uniq_id = 1;
break;
case NTP_EF_NTS_COOKIE:
DEBUG_LOG("Unencrypted cookie");
break;
case NTP_EF_NTS_AUTH_AND_EEF:
if (parsed + ef_length != info->length) {
DEBUG_LOG("Auth not last EF");
return 0;
}
if (!NNA_DecryptAuthEF(packet, info, inst->siv, parsed,
plaintext, sizeof (plaintext), &plaintext_length))
return 0;
if (!parse_encrypted_efs(inst, plaintext, plaintext_length))
return 0;
has_valid_auth = 1;
break;
default:
break;
}
}
if (!has_valid_uniq_id || !has_valid_auth) {
if (has_valid_uniq_id && packet->stratum == NTP_INVALID_STRATUM &&
ntohl(packet->reference_id) == NTP_KOD_NTS_NAK) {
DEBUG_LOG("NTS NAK");
inst->nak_response = 1;
return 0;
}
DEBUG_LOG("Missing NTS EF");
return 0;
}
if (!extract_cookies(inst, plaintext, plaintext_length))
return 0;
inst->ok_response = 1;
/* At this point we know the client interoperates with the server. Allow a
new NTS-KE session to be started as soon as the cookies run out. */
inst->nke_attempts = 0;
inst->next_nke_attempt = 0.0;
return 1;
}
/* ================================================== */
void
NNC_ChangeAddress(NNC_Instance inst, IPAddr *address)
{
save_cookies(inst);
inst->nts_address.ip_addr = *address;
inst->ntp_address.ip_addr = *address;
reset_instance(inst);
DEBUG_LOG("NTS reset");
load_cookies(inst);
}
/* ================================================== */
static void
save_cookies(NNC_Instance inst)
{
char buf[2 * NKE_MAX_COOKIE_LENGTH + 2], *dump_dir, *filename;
struct timespec now;
double context_time;
FILE *f;
int i;
if (inst->num_cookies < 1 || !UTI_IsIPReal(&inst->nts_address.ip_addr))
return;
dump_dir = CNF_GetNtsDumpDir();
if (!dump_dir)
return;
filename = UTI_IPToString(&inst->nts_address.ip_addr);
f = UTI_OpenFile(dump_dir, filename, ".tmp", 'w', 0600);
if (!f)
return;
SCH_GetLastEventTime(&now, NULL, NULL);
context_time = inst->last_nke_success - SCH_GetLastEventMonoTime();
context_time += UTI_TimespecToDouble(&now);
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)) ||
fprintf(f, "%s\n", buf) < 0)
goto error;
for (i = 0; i < inst->num_cookies; i++) {
if (!UTI_BytesToHex(inst->cookies[i].cookie, inst->cookies[i].length, buf, sizeof (buf)) ||
fprintf(f, "%s\n", buf) < 0)
goto error;
}
fclose(f);
if (!UTI_RenameTempFile(dump_dir, filename, ".tmp", ".nts"))
;
return;
error:
DEBUG_LOG("Could not %s cookies for %s", "save", filename);
fclose(f);
if (!UTI_RemoveFile(dump_dir, filename, ".nts"))
;
}
/* ================================================== */
#define MAX_WORDS 4
static void
load_cookies(NNC_Instance inst)
{
char line[2 * NKE_MAX_COOKIE_LENGTH + 2], *dump_dir, *filename, *words[MAX_WORDS];
unsigned int context_id;
int i, algorithm, port;
double context_time;
struct timespec now;
IPSockAddr ntp_addr;
FILE *f;
dump_dir = CNF_GetNtsDumpDir();
if (!dump_dir)
return;
filename = UTI_IPToString(&inst->nts_address.ip_addr);
f = UTI_OpenFile(dump_dir, filename, ".nts", 'r', 0);
if (!f)
return;
/* Don't load this file again */
if (!UTI_RemoveFile(dump_dir, filename, ".nts"))
;
if (inst->siv)
SIV_DestroyInstance(inst->siv);
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 ||
!UTI_StringToIP(words[0], &ntp_addr.ip_addr) || sscanf(words[1], "%d", &port) != 1 ||
!fgets(line, sizeof (line), f) || UTI_SplitString(line, words, MAX_WORDS) != 4 ||
sscanf(words[0], "%u", &context_id) != 1 || sscanf(words[1], "%d", &algorithm) != 1)
goto error;
inst->context.algorithm = algorithm;
inst->context.s2c.length = UTI_HexToBytes(words[2], inst->context.s2c.key,
sizeof (inst->context.s2c.key));
inst->context.c2s.length = UTI_HexToBytes(words[3], inst->context.c2s.key,
sizeof (inst->context.c2s.key));
if (inst->context.s2c.length != SIV_GetKeyLength(algorithm) ||
inst->context.s2c.length <= 0 ||
inst->context.c2s.length != inst->context.s2c.length)
goto error;
for (i = 0; i < NTS_MAX_COOKIES && fgets(line, sizeof (line), f); i++) {
if (UTI_SplitString(line, words, MAX_WORDS) != 1)
goto error;
inst->cookies[i].length = UTI_HexToBytes(words[0], inst->cookies[i].cookie,
sizeof (inst->cookies[i].cookie));
if (inst->cookies[i].length == 0)
goto error;
}
inst->num_cookies = i;
ntp_addr.port = port;
if (!set_ntp_address(inst, &ntp_addr))
goto error;
SCH_GetLastEventTime(&now, NULL, NULL);
context_time -= UTI_TimespecToDouble(&now);
if (context_time > 0)
context_time = 0;
inst->last_nke_success = context_time + SCH_GetLastEventMonoTime();
inst->context_id = context_id;
fclose(f);
DEBUG_LOG("Loaded %d cookies for %s", i, filename);
return;
error:
DEBUG_LOG("Could not %s cookies for %s", "load", filename);
fclose(f);
memset(&inst->context, 0, sizeof (inst->context));
inst->num_cookies = 0;
}
/* ================================================== */
void
NNC_DumpData(NNC_Instance inst)
{
save_cookies(inst);
}
/* ================================================== */
void
NNC_GetReport(NNC_Instance inst, RPT_AuthReport *report)
{
report->key_id = inst->context_id;
report->key_type = inst->context.algorithm;
report->key_length = 8 * inst->context.s2c.length;
report->ke_attempts = inst->nke_attempts;
if (report->key_length > 0)
report->last_ke_ago = SCH_GetLastEventMonoTime() - inst->last_nke_success;
else
report->last_ke_ago = -1;
report->cookies = inst->num_cookies;
report->cookie_length = inst->num_cookies > 0 ? inst->cookies[inst->cookie_index].length : 0;
report->nak = inst->nak_response;
}

51
nts_ntp_client.h Normal file
View File

@@ -0,0 +1,51 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Header file for client NTS-NTP authentication
*/
#ifndef GOT_NTS_NTP_CLIENT_H
#define GOT_NTS_NTP_CLIENT_H
#include "addressing.h"
#include "ntp.h"
#include "reports.h"
typedef struct NNC_Instance_Record *NNC_Instance;
extern NNC_Instance NNC_CreateInstance(IPSockAddr *nts_address, const char *name,
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,
NTP_PacketInfo *info);
extern int NNC_CheckResponseAuth(NNC_Instance inst, NTP_Packet *packet,
NTP_PacketInfo *info);
extern void NNC_ChangeAddress(NNC_Instance inst, IPAddr *address);
extern void NNC_DumpData(NNC_Instance inst);
extern void NNC_GetReport(NNC_Instance inst, RPT_AuthReport *report);
#endif

309
nts_ntp_server.c Normal file
View File

@@ -0,0 +1,309 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2020, 2022
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Server NTS-NTP authentication
*/
#include "config.h"
#include "sysincl.h"
#include "nts_ntp_server.h"
#include "conf.h"
#include "logging.h"
#include "memory.h"
#include "ntp.h"
#include "ntp_ext.h"
#include "nts_ke_server.h"
#include "nts_ntp.h"
#include "nts_ntp_auth.h"
#include "siv.h"
#include "util.h"
#define MAX_SERVER_SIVS 2
struct NtsServer {
SIV_Instance sivs[MAX_SERVER_SIVS];
SIV_Algorithm siv_algorithms[MAX_SERVER_SIVS];
unsigned char nonce[NTS_MIN_UNPADDED_NONCE_LENGTH];
NKE_Cookie cookies[NTS_MAX_COOKIES];
int num_cookies;
int siv_index;
NTP_int64 req_tx;
};
/* The server instance handling all requests */
struct NtsServer *server;
/* ================================================== */
void
NNS_Initialise(void)
{
const char **certs, **keys;
int i;
/* Create an NTS-NTP server instance only if NTS-KE server is enabled */
if (CNF_GetNtsServerCertAndKeyFiles(&certs, &keys) <= 0) {
server = NULL;
return;
}
server = Malloc(sizeof (struct NtsServer));
server->siv_algorithms[0] = AEAD_AES_SIV_CMAC_256;
server->siv_algorithms[1] = AEAD_AES_128_GCM_SIV;
assert(MAX_SERVER_SIVS == 2);
for (i = 0; i < 2; i++)
server->sivs[i] = SIV_CreateInstance(server->siv_algorithms[i]);
/* AES-SIV-CMAC-256 is required on servers */
if (!server->sivs[0])
LOG_FATAL("Missing AES-SIV-CMAC-256");
}
/* ================================================== */
void
NNS_Finalise(void)
{
int i;
if (!server)
return;
for (i = 0; i < MAX_SERVER_SIVS; i++) {
if (server->sivs[i])
SIV_DestroyInstance(server->sivs[i]);
}
Free(server);
server = NULL;
}
/* ================================================== */
int
NNS_CheckRequestAuth(NTP_Packet *packet, NTP_PacketInfo *info, uint32_t *kod)
{
int ef_type, ef_body_length, ef_length, has_uniq_id = 0, has_auth = 0, has_cookie = 0;
int i, plaintext_length, parsed, requested_cookies, cookie_length = -1, auth_start = 0;
unsigned char plaintext[NTP_MAX_EXTENSIONS_LENGTH];
NKE_Context context;
NKE_Cookie cookie;
SIV_Instance siv;
void *ef_body;
*kod = 0;
if (!server)
return 0;
server->num_cookies = 0;
server->siv_index = -1;
server->req_tx = packet->transmit_ts;
if (info->ext_fields == 0 || info->mode != MODE_CLIENT)
return 0;
requested_cookies = 0;
for (parsed = NTP_HEADER_LENGTH; parsed < info->length; parsed += ef_length) {
if (!NEF_ParseField(packet, info->length, parsed,
&ef_length, &ef_type, &ef_body, &ef_body_length))
/* This is not expected as the packet already passed NAU_ParsePacket() */
return 0;
switch (ef_type) {
case NTP_EF_NTS_UNIQUE_IDENTIFIER:
has_uniq_id = 1;
break;
case NTP_EF_NTS_COOKIE:
if (has_cookie || ef_body_length > sizeof (cookie.cookie)) {
DEBUG_LOG("Unexpected cookie/length");
return 0;
}
cookie.length = ef_body_length;
memcpy(cookie.cookie, ef_body, ef_body_length);
has_cookie = 1;
/* Fall through */
case NTP_EF_NTS_COOKIE_PLACEHOLDER:
requested_cookies++;
if (cookie_length >= 0 && cookie_length != ef_body_length) {
DEBUG_LOG("Invalid cookie/placeholder length");
return 0;
}
cookie_length = ef_body_length;
break;
case NTP_EF_NTS_AUTH_AND_EEF:
if (parsed + ef_length != info->length) {
DEBUG_LOG("Auth not last EF");
return 0;
}
auth_start = parsed;
has_auth = 1;
break;
default:
break;
}
}
if (!has_uniq_id || !has_cookie || !has_auth) {
DEBUG_LOG("Missing an NTS EF");
return 0;
}
if (!NKS_DecodeCookie(&cookie, &context)) {
*kod = NTP_KOD_NTS_NAK;
return 0;
}
/* Find the SIV instance needed for authentication */
for (i = 0; i < MAX_SERVER_SIVS && context.algorithm != server->siv_algorithms[i]; i++)
;
if (i == MAX_SERVER_SIVS || !server->sivs[i]) {
DEBUG_LOG("Unexpected SIV");
return 0;
}
server->siv_index = i;
siv = server->sivs[i];
if (!SIV_SetKey(siv, context.c2s.key, context.c2s.length)) {
DEBUG_LOG("Could not set C2S key");
return 0;
}
if (!NNA_DecryptAuthEF(packet, info, siv, auth_start,
plaintext, sizeof (plaintext), &plaintext_length)) {
*kod = NTP_KOD_NTS_NAK;
return 0;
}
for (parsed = 0; parsed < plaintext_length; parsed += ef_length) {
if (!NEF_ParseSingleField(plaintext, plaintext_length, parsed,
&ef_length, &ef_type, &ef_body, &ef_body_length)) {
DEBUG_LOG("Could not parse encrypted EF");
return 0;
}
switch (ef_type) {
case NTP_EF_NTS_COOKIE_PLACEHOLDER:
if (cookie_length != ef_body_length) {
DEBUG_LOG("Invalid cookie/placeholder length");
return 0;
}
requested_cookies++;
break;
default:
break;
}
}
if (!SIV_SetKey(siv, context.s2c.key, context.s2c.length)) {
DEBUG_LOG("Could not set S2C key");
return 0;
}
/* Prepare data for NNS_GenerateResponseAuth() to minimise the time spent
there (when the TX timestamp is already set) */
UTI_GetRandomBytes(server->nonce, sizeof (server->nonce));
assert(sizeof (server->cookies) / sizeof (server->cookies[0]) == NTS_MAX_COOKIES);
for (i = 0; i < NTS_MAX_COOKIES && i < requested_cookies; i++)
if (!NKS_GenerateCookie(&context, &server->cookies[i]))
return 0;
server->num_cookies = i;
return 1;
}
/* ================================================== */
int
NNS_GenerateResponseAuth(NTP_Packet *request, NTP_PacketInfo *req_info,
NTP_Packet *response, NTP_PacketInfo *res_info,
uint32_t kod)
{
int i, ef_type, ef_body_length, ef_length, parsed;
void *ef_body;
unsigned char plaintext[NTP_MAX_EXTENSIONS_LENGTH];
int plaintext_length;
if (!server || req_info->mode != MODE_CLIENT || res_info->mode != MODE_SERVER)
return 0;
/* Make sure this is a response to the request from the last call
of NNS_CheckRequestAuth() */
if (UTI_CompareNtp64(&server->req_tx, &request->transmit_ts) != 0)
assert(0);
for (parsed = NTP_HEADER_LENGTH; parsed < req_info->length; parsed += ef_length) {
if (!NEF_ParseField(request, req_info->length, parsed,
&ef_length, &ef_type, &ef_body, &ef_body_length))
/* This is not expected as the packet already passed parsing */
return 0;
switch (ef_type) {
case NTP_EF_NTS_UNIQUE_IDENTIFIER:
/* Copy the ID from the request */
if (!NEF_AddField(response, res_info, ef_type, ef_body, ef_body_length))
return 0;
default:
break;
}
}
/* NTS NAK response does not have any other fields */
if (kod)
return 1;
for (i = 0, plaintext_length = 0; i < server->num_cookies; i++) {
if (!NEF_SetField(plaintext, sizeof (plaintext), plaintext_length,
NTP_EF_NTS_COOKIE, server->cookies[i].cookie,
server->cookies[i].length, &ef_length))
return 0;
plaintext_length += ef_length;
assert(plaintext_length <= sizeof (plaintext));
}
server->num_cookies = 0;
if (server->siv_index < 0)
return 0;
/* Generate an authenticator field which will make the length
of the response equal to the length of the request */
if (!NNA_GenerateAuthEF(response, res_info, server->sivs[server->siv_index],
server->nonce, sizeof (server->nonce),
plaintext, plaintext_length,
req_info->length - res_info->length))
return 0;
return 1;
}

40
nts_ntp_server.h Normal file
View File

@@ -0,0 +1,40 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 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
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Header file for server NTS-NTP authentication
*/
#ifndef GOT_NTS_NTP_SERVER_H
#define GOT_NTS_NTP_SERVER_H
#include "ntp.h"
extern void NNS_Initialise(void);
extern void NNS_Finalise(void);
extern int NNS_CheckRequestAuth(NTP_Packet *packet, NTP_PacketInfo *info, uint32_t *kod);
extern int NNS_GenerateResponseAuth(NTP_Packet *request, NTP_PacketInfo *req_info,
NTP_Packet *response, NTP_PacketInfo *res_info,
uint32_t kod);
#endif

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 */
@@ -110,12 +110,26 @@ static const struct request_length request_lengths[] = {
REQ_LENGTH_ENTRY(smoothtime, null), /* SMOOTHTIME */
REQ_LENGTH_ENTRY(null, null), /* REFRESH */
REQ_LENGTH_ENTRY(null, server_stats), /* SERVER_STATS */
REQ_LENGTH_ENTRY(client_accesses_by_index,
client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX2 */
{ 0, 0 }, /* CLIENT_ACCESSES_BY_INDEX2 - not supported */
REQ_LENGTH_ENTRY(local, null), /* LOCAL2 */
REQ_LENGTH_ENTRY(ntp_data, ntp_data), /* NTP_DATA */
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_SERVER2 */
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_PEER2 */
{ 0, 0 }, /* ADD_SERVER2 */
{ 0, 0 }, /* ADD_PEER2 */
{ 0, 0 }, /* ADD_SERVER3 */
{ 0, 0 }, /* ADD_PEER3 */
REQ_LENGTH_ENTRY(null, null), /* SHUTDOWN */
REQ_LENGTH_ENTRY(null, null), /* ONOFFLINE */
REQ_LENGTH_ENTRY(ntp_source, null), /* ADD_SOURCE */
REQ_LENGTH_ENTRY(ntp_source_name,
ntp_source_name), /* NTP_SOURCE_NAME */
REQ_LENGTH_ENTRY(null, null), /* RESET_SOURCES */
REQ_LENGTH_ENTRY(auth_data, auth_data), /* AUTH_DATA */
REQ_LENGTH_ENTRY(client_accesses_by_index,
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 */
REQ_LENGTH_ENTRY(modify_select_opts, null), /* MODIFY_SELECTOPTS */
};
static const uint16_t reply_lengths[] = {
@@ -123,19 +137,28 @@ static const uint16_t reply_lengths[] = {
RPY_LENGTH_ENTRY(null), /* NULL */
RPY_LENGTH_ENTRY(n_sources), /* N_SOURCES */
RPY_LENGTH_ENTRY(source_data), /* SOURCE_DATA */
RPY_LENGTH_ENTRY(manual_timestamp), /* MANUAL_TIMESTAMP */
0, /* MANUAL_TIMESTAMP */
RPY_LENGTH_ENTRY(tracking), /* TRACKING */
RPY_LENGTH_ENTRY(sourcestats), /* SOURCESTATS */
RPY_LENGTH_ENTRY(rtc), /* RTC */
0, /* SUBNETS_ACCESSED - not supported */
0, /* CLIENT_ACCESSES - not supported */
0, /* CLIENT_ACCESSES_BY_INDEX - not supported */
0, /* MANUAL_LIST - variable length */
0, /* MANUAL_LIST - not supported */
RPY_LENGTH_ENTRY(activity), /* ACTIVITY */
RPY_LENGTH_ENTRY(smoothing), /* SMOOTHING */
RPY_LENGTH_ENTRY(server_stats), /* SERVER_STATS */
RPY_LENGTH_ENTRY(client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX2 */
0, /* SERVER_STATS - not supported */
0, /* CLIENT_ACCESSES_BY_INDEX2 - not supported */
RPY_LENGTH_ENTRY(ntp_data), /* NTP_DATA */
RPY_LENGTH_ENTRY(manual_timestamp), /* MANUAL_TIMESTAMP2 */
RPY_LENGTH_ENTRY(manual_list), /* MANUAL_LIST2 */
RPY_LENGTH_ENTRY(ntp_source_name), /* NTP_SOURCE_NAME */
RPY_LENGTH_ENTRY(auth_data), /* AUTH_DATA */
RPY_LENGTH_ENTRY(client_accesses_by_index), /* CLIENT_ACCESSES_BY_INDEX3 */
0, /* SERVER_STATS2 - not supported */
RPY_LENGTH_ENTRY(select_data), /* SELECT_DATA */
0, /* SERVER_STATS3 - not supported */
RPY_LENGTH_ENTRY(server_stats), /* SERVER_STATS4 */
};
/* ================================================== */
@@ -192,21 +215,6 @@ PKL_ReplyLength(CMD_Reply *r)
if (type < 1 || type >= N_REPLY_TYPES)
return 0;
/* Length of MANUAL_LIST depends on number of samples stored in it */
if (type == RPY_MANUAL_LIST) {
uint32_t ns;
if (r->status != htons(STT_SUCCESS))
return offsetof(CMD_Reply, data);
ns = ntohl(r->data.manual_list.n_samples);
if (ns > MAX_MANUAL_LIST_SAMPLES)
return 0;
return offsetof(CMD_Reply, data.manual_list.samples) +
ns * sizeof (RPY_ManualListSample);
}
return reply_lengths[type];
}

199
privops.c
View File

@@ -3,7 +3,7 @@
**********************************************************************
* Copyright (C) Bryan Christianson 2015
* Copyright (C) Miroslav Lichvar 2016
* Copyright (C) Miroslav Lichvar 2017
*
* 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
@@ -33,6 +33,7 @@
#include "nameserv.h"
#include "logging.h"
#include "privops.h"
#include "socket.h"
#include "util.h"
#define OP_ADJUSTTIME 1024
@@ -40,6 +41,7 @@
#define OP_SETTIME 1026
#define OP_BINDSOCKET 1027
#define OP_NAME2IPADDRESS 1028
#define OP_RELOADDNS 1029
#define OP_QUIT 1099
union sockaddr_in46 {
@@ -157,7 +159,7 @@ res_fatal(PrvResponse *res, const char *fmt, ...)
static int
send_response(int fd, const PrvResponse *res)
{
if (send(fd, res, sizeof (*res), 0) != sizeof (*res))
if (SCK_Send(fd, res, sizeof (*res), 0) != sizeof (*res))
return 0;
return 1;
@@ -169,37 +171,23 @@ send_response(int fd, const PrvResponse *res)
static int
receive_from_daemon(int fd, PrvRequest *req)
{
struct msghdr msg;
struct cmsghdr *cmsg;
struct iovec iov;
char cmsgbuf[256];
SCK_Message *message;
iov.iov_base = req;
iov.iov_len = sizeof (*req);
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = (void *)cmsgbuf;
msg.msg_controllen = sizeof (cmsgbuf);
msg.msg_flags = MSG_WAITALL;
/* read the data */
if (recvmsg(fd, &msg, 0) != sizeof (*req))
message = SCK_ReceiveMessage(fd, SCK_FLAG_MSG_DESCRIPTOR);
if (!message || message->length != sizeof (*req))
return 0;
memcpy(req, message->data, sizeof (*req));
if (req->op == OP_BINDSOCKET) {
/* extract transferred descriptor */
req->data.bind_socket.sock = -1;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
memcpy(&req->data.bind_socket.sock, CMSG_DATA(cmsg), sizeof (int));
}
req->data.bind_socket.sock = message->descriptor;
/* return error if valid descriptor not found */
if (req->data.bind_socket.sock < 0)
return 0;
} else if (message->descriptor >= 0) {
SCK_CloseSocket(message->descriptor);
return 0;
}
return 1;
@@ -256,8 +244,7 @@ do_set_time(const ReqSetTime *req, PrvResponse *res)
static void
do_bind_socket(ReqBindSocket *req, PrvResponse *res)
{
unsigned short port;
IPAddr ip;
IPSockAddr ip_saddr;
int sock_fd;
struct sockaddr *sa;
socklen_t sa_len;
@@ -266,10 +253,11 @@ do_bind_socket(ReqBindSocket *req, PrvResponse *res)
sa_len = req->sa_len;
sock_fd = req->sock;
UTI_SockaddrToIPAndPort(sa, &ip, &port);
if (port && port != CNF_GetNTPPort()) {
close(sock_fd);
res_fatal(res, "Invalid port %d", port);
SCK_SockaddrToIPSockAddr(sa, sa_len, &ip_saddr);
if (ip_saddr.port != 0 && ip_saddr.port != CNF_GetNTPPort() &&
ip_saddr.port != CNF_GetAcquisitionPort() && ip_saddr.port != CNF_GetPtpPort()) {
SCK_CloseSocket(sock_fd);
res_fatal(res, "Invalid port %d", ip_saddr.port);
return;
}
@@ -278,7 +266,7 @@ do_bind_socket(ReqBindSocket *req, PrvResponse *res)
res->res_errno = errno;
/* sock is still open on daemon side, but we're done with it in the helper */
close(sock_fd);
SCK_CloseSocket(sock_fd);
}
#endif
@@ -293,8 +281,6 @@ do_name_to_ipaddress(ReqName2IPAddress *req, PrvResponse *res)
/* make sure the string is terminated */
req->name[sizeof (req->name) - 1] = '\0';
DNS_Reload();
res->rc = DNS_Name2IPAddress(req->name, res->data.name_to_ipaddress.addresses,
DNS_MAX_ADDRESSES);
}
@@ -302,6 +288,19 @@ do_name_to_ipaddress(ReqName2IPAddress *req, PrvResponse *res)
/* ======================================================================= */
/* HELPER - perform DNS_Reload() */
#ifdef PRIVOPS_RELOADDNS
static void
do_reload_dns(PrvResponse *res)
{
DNS_Reload();
res->rc = 0;
}
#endif
/* ======================================================================= */
/* HELPER - main loop - action requests from the daemon */
static void
@@ -343,6 +342,11 @@ helper_main(int fd)
case OP_NAME2IPADDRESS:
do_name_to_ipaddress(&req.data.name_to_ipaddress, &res);
break;
#endif
#ifdef PRIVOPS_RELOADDNS
case OP_RELOADDNS:
do_reload_dns(&res);
break;
#endif
case OP_QUIT:
quit = 1;
@@ -356,7 +360,7 @@ helper_main(int fd)
send_response(fd, &res);
}
close(fd);
SCK_CloseSocket(fd);
exit(0);
}
@@ -369,16 +373,16 @@ receive_response(PrvResponse *res)
{
int resp_len;
resp_len = recv(helper_fd, res, sizeof (*res), 0);
resp_len = SCK_Receive(helper_fd, res, sizeof (*res), 0);
if (resp_len < 0)
LOG_FATAL(LOGF_PrivOps, "Could not read from helper : %s", strerror(errno));
LOG_FATAL("Could not read from helper : %s", strerror(errno));
if (resp_len != sizeof (*res))
LOG_FATAL(LOGF_PrivOps, "Invalid helper response");
LOG_FATAL("Invalid helper response");
if (res->fatal_error)
LOG_FATAL(LOGF_PrivOps, "Error in helper : %s", res->data.fatal_msg.msg);
LOG_FATAL("Error in helper : %s", res->data.fatal_msg.msg);
DEBUG_LOG(LOGF_PrivOps, "Received response rc=%d", res->rc);
DEBUG_LOG("Received response rc=%d", res->rc);
/* if operation failed in the helper, set errno so daemon can print log message */
if (res->res_errno)
@@ -392,47 +396,28 @@ receive_response(PrvResponse *res)
static void
send_request(PrvRequest *req)
{
struct msghdr msg;
struct iovec iov;
char cmsgbuf[256];
SCK_Message message;
int flags;
iov.iov_base = req;
iov.iov_len = sizeof (*req);
SCK_InitMessage(&message, SCK_ADDR_UNSPEC);
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
message.data = req;
message.length = sizeof (*req);
flags = 0;
if (req->op == OP_BINDSOCKET) {
/* send file descriptor as a control message */
struct cmsghdr *cmsg;
int *ptr_send_fd;
msg.msg_control = cmsgbuf;
msg.msg_controllen = CMSG_SPACE(sizeof (int));
cmsg = CMSG_FIRSTHDR(&msg);
memset(cmsg, 0, CMSG_SPACE(sizeof (int)));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof (int));
ptr_send_fd = (int *)CMSG_DATA(cmsg);
*ptr_send_fd = req->data.bind_socket.sock;
message.descriptor = req->data.bind_socket.sock;
flags |= SCK_FLAG_MSG_DESCRIPTOR;
}
if (sendmsg(helper_fd, &msg, 0) < 0) {
if (!SCK_SendMessage(helper_fd, &message, flags)) {
/* don't try to send another request from exit() */
helper_fd = -1;
LOG_FATAL(LOGF_PrivOps, "Could not send to helper : %s", strerror(errno));
LOG_FATAL("Could not send to helper : %s", strerror(errno));
}
DEBUG_LOG(LOGF_PrivOps, "Sent request op=%d", req->op);
DEBUG_LOG("Sent request op=%d", req->op);
}
/* ======================================================================= */
@@ -556,13 +541,14 @@ PRV_SetTime(const struct timeval *tp, const struct timezone *tzp)
int
PRV_BindSocket(int sock, struct sockaddr *address, socklen_t address_len)
{
IPSockAddr ip_saddr;
PrvRequest req;
PrvResponse res;
IPAddr ip;
unsigned short port;
UTI_SockaddrToIPAndPort(address, &ip, &port);
assert(!port || port == CNF_GetNTPPort());
SCK_SockaddrToIPSockAddr(address, address_len, &ip_saddr);
if (ip_saddr.port != 0 && ip_saddr.port != CNF_GetNTPPort() &&
ip_saddr.port != CNF_GetAcquisitionPort() && ip_saddr.port != CNF_GetPtpPort())
assert(0);
if (!have_helper())
return bind(sock, address, address_len);
@@ -571,6 +557,7 @@ PRV_BindSocket(int sock, struct sockaddr *address, socklen_t address_len)
req.op = OP_BINDSOCKET;
req.data.bind_socket.sock = sock;
req.data.bind_socket.sa_len = address_len;
assert(address_len <= sizeof (req.data.bind_socket.sa));
memcpy(&req.data.bind_socket.sa.u, address, address_len);
submit_request(&req, &res);
@@ -598,7 +585,6 @@ PRV_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
req.op = OP_NAME2IPADDRESS;
if (snprintf(req.data.name_to_ipaddress.name, sizeof (req.data.name_to_ipaddress.name),
"%s", name) >= sizeof (req.data.name_to_ipaddress.name)) {
DEBUG_LOG(LOGF_PrivOps, "Name too long");
return DNS_Failure;
}
@@ -613,6 +599,30 @@ PRV_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
/* ======================================================================= */
/* DAEMON - request res_init() */
#ifdef PRIVOPS_RELOADDNS
void
PRV_ReloadDNS(void)
{
PrvRequest req;
PrvResponse res;
if (!have_helper()) {
DNS_Reload();
return;
}
memset(&req, 0, sizeof (req));
req.op = OP_RELOADDNS;
submit_request(&req, &res);
assert(!res.rc);
}
#endif
/* ======================================================================= */
void
PRV_Initialise(void)
{
@@ -628,44 +638,41 @@ void
PRV_StartHelper(void)
{
pid_t pid;
int fd, sock_pair[2];
int fd, sock_fd1, sock_fd2;
if (have_helper())
LOG_FATAL(LOGF_PrivOps, "Helper already running");
LOG_FATAL("Helper already running");
if (
#ifdef SOCK_SEQPACKET
socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sock_pair) &&
#endif
socketpair(AF_UNIX, SOCK_DGRAM, 0, sock_pair))
LOG_FATAL(LOGF_PrivOps, "socketpair() failed : %s", strerror(errno));
UTI_FdSetCloexec(sock_pair[0]);
UTI_FdSetCloexec(sock_pair[1]);
sock_fd1 = SCK_OpenUnixSocketPair(SCK_FLAG_BLOCK, &sock_fd2);
if (sock_fd1 < 0)
LOG_FATAL("Could not open socket pair");
pid = fork();
if (pid < 0)
LOG_FATAL(LOGF_PrivOps, "fork() failed : %s", strerror(errno));
LOG_FATAL("fork() failed : %s", strerror(errno));
if (pid == 0) {
/* child process */
close(sock_pair[0]);
SCK_CloseSocket(sock_fd1);
/* close other descriptors inherited from the parent process */
for (fd = 0; fd < 1024; fd++) {
if (fd != sock_pair[1])
/* close other descriptors inherited from the parent process, except
stdin, stdout, and stderr */
for (fd = STDERR_FILENO + 1; fd < 1024; fd++) {
if (fd != sock_fd2)
close(fd);
}
/* ignore signals, the process will exit on OP_QUIT request */
UTI_SetQuitSignalsHandler(SIG_IGN);
UTI_ResetGetRandomFunctions();
helper_main(sock_pair[1]);
/* ignore signals, the process will exit on OP_QUIT request */
UTI_SetQuitSignalsHandler(SIG_IGN, 1);
helper_main(sock_fd2);
} else {
/* parent process */
close(sock_pair[1]);
helper_fd = sock_pair[0];
SCK_CloseSocket(sock_fd2);
helper_fd = sock_fd1;
helper_pid = pid;
/* stop the helper even when not exiting cleanly from the main function */

View File

@@ -58,6 +58,12 @@ int PRV_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs);
#define PRV_Name2IPAddress DNS_Name2IPAddress
#endif
#ifdef PRIVOPS_RELOADDNS
void PRV_ReloadDNS(void);
#else
#define PRV_ReloadDNS DNS_Reload
#endif
#ifdef PRIVOPS_HELPER
void PRV_Initialise(void);
void PRV_StartHelper(void);

69
ptp.h Normal file
View File

@@ -0,0 +1,69 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2021
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
This is the header file for the Precision Time Protocol (PTP).
*/
#ifndef GOT_PTP_H
#define GOT_PTP_H
#include "sysincl.h"
#include "ntp.h"
#define PTP_VERSION 2
#define PTP_TYPE_DELAY_REQ 1
#define PTP_DOMAIN_NTP 123
#define PTP_FLAG_UNICAST (1 << (2 + 8))
#define PTP_TLV_NTP 0x2023
typedef struct {
uint8_t type;
uint8_t version;
uint16_t length;
uint8_t domain;
uint8_t min_sdoid;
uint16_t flags;
uint8_t correction[8];
uint8_t msg_specific[4];
uint8_t port_id[10];
uint16_t sequence_id;
uint8_t control;
int8_t interval;
} PTP_Header;
typedef struct {
uint16_t type;
uint16_t length;
} PTP_TlvHeader;
typedef struct {
PTP_Header header;
uint8_t origin_ts[10];
PTP_TlvHeader tlv_header;
NTP_Packet ntp_msg;
} PTP_NtpMessage;
#define PTP_NTP_PREFIX_LENGTH (int)offsetof(PTP_NtpMessage, ntp_msg)
#endif

209
quantiles.c Normal file
View File

@@ -0,0 +1,209 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2022
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
**********************************************************************
=======================================================================
Estimation of quantiles using the Frugal-2U streaming algorithm
(https://arxiv.org/pdf/1407.1121v1.pdf)
*/
#include "config.h"
#include "logging.h"
#include "memory.h"
#include "quantiles.h"
#include "regress.h"
#include "util.h"
/* Maximum number of repeated estimates for stabilisation */
#define MAX_REPEAT 64
struct Quantile {
double est;
double step;
int sign;
};
struct QNT_Instance_Record {
struct Quantile *quants;
int n_quants;
int repeat;
int q;
int min_k;
double min_step;
int n_set;
};
/* ================================================== */
QNT_Instance
QNT_CreateInstance(int min_k, int max_k, int q, int repeat, double min_step)
{
QNT_Instance inst;
long seed;
if (q < 2 || min_k > max_k || min_k < 1 || max_k >= q ||
repeat < 1 || repeat > MAX_REPEAT || min_step <= 0.0)
assert(0);
inst = MallocNew(struct QNT_Instance_Record);
inst->n_quants = (max_k - min_k + 1) * repeat;
inst->quants = MallocArray(struct Quantile, inst->n_quants);
inst->repeat = repeat;
inst->q = q;
inst->min_k = min_k;
inst->min_step = min_step;
QNT_Reset(inst);
/* Seed the random number generator, which will not be isolated from
other instances and other random() users */
UTI_GetRandomBytes(&seed, sizeof (seed));
srandom(seed);
return inst;
}
/* ================================================== */
void
QNT_DestroyInstance(QNT_Instance inst)
{
Free(inst->quants);
Free(inst);
}
/* ================================================== */
void
QNT_Reset(QNT_Instance inst)
{
int i;
inst->n_set = 0;
for (i = 0; i < inst->n_quants; i++) {
inst->quants[i].est = 0.0;
inst->quants[i].step = inst->min_step;
inst->quants[i].sign = 1;
}
}
/* ================================================== */
static void
insert_initial_value(QNT_Instance inst, double value)
{
int i, j, r = inst->repeat;
if (inst->n_set * r >= inst->n_quants)
assert(0);
/* Keep the initial estimates repeated and ordered */
for (i = inst->n_set; i > 0 && inst->quants[(i - 1) * r].est > value; i--) {
for (j = 0; j < r; j++)
inst->quants[i * r + j].est = inst->quants[(i - 1) * r].est;
}
for (j = 0; j < r; j++)
inst->quants[i * r + j].est = value;
inst->n_set++;
/* Duplicate the largest value in unset quantiles */
for (i = inst->n_set * r; i < inst->n_quants; i++)
inst->quants[i].est = inst->quants[i - 1].est;
}
/* ================================================== */
static void
update_estimate(struct Quantile *quantile, double value, double p, double rand,
double min_step)
{
if (value > quantile->est && rand > (1.0 - p)) {
quantile->step += quantile->sign > 0 ? min_step : -min_step;
quantile->est += quantile->step > 0.0 ? fabs(quantile->step) : min_step;
if (quantile->est > value) {
quantile->step += value - quantile->est;
quantile->est = value;
}
if (quantile->sign < 0 && quantile->step > min_step)
quantile->step = min_step;
quantile->sign = 1;
} else if (value < quantile->est && rand > p) {
quantile->step += quantile->sign < 0 ? min_step : -min_step;
quantile->est -= quantile->step > 0.0 ? fabs(quantile->step) : min_step;
if (quantile->est < value) {
quantile->step += quantile->est - value;
quantile->est = value;
}
if (quantile->sign > 0 && quantile->step > min_step)
quantile->step = min_step;
quantile->sign = -1;
}
}
/* ================================================== */
void
QNT_Accumulate(QNT_Instance inst, double value)
{
double p, rand;
int i;
/* Initialise the estimates with first received values */
if (inst->n_set * inst->repeat < inst->n_quants) {
insert_initial_value(inst, value);
return;
}
for (i = 0; i < inst->n_quants; i++) {
p = (double)(i / inst->repeat + inst->min_k) / inst->q;
rand = (double)random() / ((1U << 31) - 1);
update_estimate(&inst->quants[i], value, p, rand, inst->min_step);
}
}
/* ================================================== */
int
QNT_GetMinK(QNT_Instance inst)
{
return inst->min_k;
}
/* ================================================== */
double
QNT_GetQuantile(QNT_Instance inst, int k)
{
double estimates[MAX_REPEAT];
int i;
if (k < inst->min_k || k - inst->min_k >= inst->n_quants)
assert(0);
for (i = 0; i < inst->repeat; i++)
estimates[i] = inst->quants[(k - inst->min_k) * inst->repeat + i].est;
return RGR_FindMedian(estimates, inst->repeat);
}

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