Compare commits

...

No commits in common. "c10s" and "c8" have entirely different histories.
c10s ... c8

28 changed files with 1587 additions and 1706 deletions

2
.chrony.metadata Normal file
View File

@ -0,0 +1,2 @@
4661e5df181a9761b73caeaef2f2ab755bbe086a SOURCES/chrony-4.5.tar.gz
e021461c23fe4e5c46fd53c449587d8f6cc217ae SOURCES/clknetsim-5d1dc0.tar.gz

View File

@ -1 +0,0 @@
1

5
.gitignore vendored
View File

@ -1,3 +1,2 @@
/chrony-4.6.1.tar.gz SOURCES/chrony-4.5.tar.gz
/chrony-4.6.1-tar-gz-asc.txt SOURCES/clknetsim-5d1dc0.tar.gz
/clknetsim-cdd694.tar.gz

56
SOURCES/chrony-cmac.patch Normal file
View File

@ -0,0 +1,56 @@
commit 8eb5dd54efd13aa0209aea38dbad2a7904377f75
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Tue Sep 17 13:00:43 2024 +0200
configure: enable AES-CMAC using gnutls
Allow gnutls to be used for AES-CMAC when nettle doesn't support it
without switching also hashing.
diff --git a/configure b/configure
index eefe5de8..0fb3aa38 100755
--- a/configure
+++ b/configure
@@ -937,14 +937,26 @@ if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_gnutls = "1" ];
HASH_LINK="$test_link"
MYCPPFLAGS="$MYCPPFLAGS $test_cflags"
add_def FEAT_SECHASH
+ fi
+fi
- 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
+if [ $feat_sechash = "1" ] && [ $try_gnutls = "1" ] &&
+ ! grep '#define HAVE_CMAC' config.h > /dev/null; 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 '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"
+ LIBS="$LIBS $test_link"
+ MYCPPFLAGS="$MYCPPFLAGS $test_cflags"
fi
fi
@@ -978,7 +990,7 @@ 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
+ if echo "$HASH_OBJ $EXTRA_OBJECTS" | grep "_gnutls\.o" > /dev/null; then
test_cflags=""
test_link=""
else

View File

@ -0,0 +1,38 @@
diff -up chrony-4.1/examples/chrony.conf.example2.defconfig chrony-4.1/examples/chrony.conf.example2
--- chrony-4.1/examples/chrony.conf.example2.defconfig 2021-05-12 13:06:15.000000000 +0200
+++ chrony-4.1/examples/chrony.conf.example2 2019-05-10 12:22:57.000000000 +0200
@@ -1,5 +1,5 @@
# Use public servers from the pool.ntp.org project.
-# Please consider joining the pool (https://www.pool.ntp.org/join.html).
+# Please consider joining the pool (http://www.pool.ntp.org/join.html).
pool pool.ntp.org iburst
# Record the rate at which the system clock gains/losses time.
@@ -25,18 +25,9 @@ rtcsync
# 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
diff -up chrony-4.5/examples/chrony.keys.example.keys chrony-4.5/examples/chrony.keys.example
--- chrony-4.5/examples/chrony.keys.example.keys 2023-12-05 14:22:10.000000000 +0100
+++ chrony-4.5/examples/chrony.keys.example 2023-12-06 09:59:26.089508934 +0100
@@ -11,5 +11,3 @@
#1 MD5 AVeryLongAndRandomPassword
#2 MD5 HEX:12114855C7931009B4049EF3EFC48A139C3F989F
#3 SHA1 HEX:B2159C05D6A219673A3B7E896B6DE07F6A440995
-#4 AES128 HEX:2DA837C4B6573748CA692B8C828E4891
-#5 AES256 HEX:2666B8099BFF2D5BA20876121788ED24D2BE59111B8FFB562F0F56AE6EC7246E

View File

@ -0,0 +1,8 @@
[Unit]
Description=DNS SRV lookup of %I for chrony
After=chronyd.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/libexec/chrony-helper update-dnssrv-servers %I

View File

@ -0,0 +1,9 @@
[Unit]
Description=Periodic DNS SRV lookup of %I for chrony
[Timer]
OnActiveSec=0
OnUnitInactiveSec=1h
[Install]
WantedBy=timers.target

View File

@ -0,0 +1,164 @@
First, revert upstream changes since 4.2
diff --git a/examples/chrony.nm-dispatcher.dhcp b/examples/chrony.nm-dispatcher.dhcp
index 547ce83f..6ea4c370 100644
--- a/examples/chrony.nm-dispatcher.dhcp
+++ b/examples/chrony.nm-dispatcher.dhcp
@@ -1,7 +1,8 @@
#!/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.
+# its NTP sources passed from DHCP options. Note that this script is
+# specific to NetworkManager-dispatcher due to use of the
+# DHCP4_NTP_SERVERS environment variable.
export LC_ALL=C
@@ -9,23 +10,17 @@ interface=$1
action=$2
chronyc=/usr/bin/chronyc
-server_options=iburst
+default_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"
+# DHCP4_NTP_SERVERS is passed from DHCP options by NetworkManager.
+nm_dhcp_servers=$DHCP4_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"
+ for server in $nm_dhcp_servers; do
+ echo "server $server $default_server_options" >> "$dhcp_server_file"
done
$chronyc reload sources > /dev/null 2>&1 || :
}
@@ -39,11 +34,10 @@ clear_servers_from_dhcp() {
mkdir -p $server_dir
-case "$action" in
- up|dhcp4-change|dhcp6-change)
- add_servers_from_dhcp;;
- down)
- clear_servers_from_dhcp;;
-esac
+if [ "$action" = "up" ] || [ "$action" = "dhcp4-change" ]; then
+ add_servers_from_dhcp
+elif [ "$action" = "down" ]; then
+ clear_servers_from_dhcp
+fi
exit 0
From: Robert Fairley <rfairley@redhat.com>
Date: Wed, 17 Jun 2020 10:14:19 -0400
Subject: [PATCH] examples/nm-dispatcher.dhcp: use sysconfig
Use the PEERNTP and NTPSERVERARGS environment variables from
/etc/sysconfig/network{-scripts}.
Co-Authored-By: Christian Glombek <cglombek@redhat.com>
diff --git a/examples/chrony.nm-dispatcher.dhcp b/examples/chrony.nm-dispatcher.dhcp
index 6ea4c37..a6ad35a 100644
--- a/examples/chrony.nm-dispatcher.dhcp
+++ b/examples/chrony.nm-dispatcher.dhcp
@@ -6,16 +6,24 @@
chronyc=/usr/bin/chronyc
default_server_options=iburst
-server_dir=/var/run/chrony-dhcp
+server_dir=/run/chrony-dhcp
dhcp_server_file=$server_dir/$interface.sources
# DHCP4_NTP_SERVERS is passed from DHCP options by NetworkManager.
nm_dhcp_servers=$DHCP4_NTP_SERVERS
+[ -f /etc/sysconfig/network ] && . /etc/sysconfig/network
+[ -f /etc/sysconfig/network-scripts/ifcfg-"${interface}" ] && \
+ . /etc/sysconfig/network-scripts/ifcfg-"${interface}"
+
add_servers_from_dhcp() {
rm -f "$dhcp_server_file"
+
+ # Don't add NTP servers if PEERNTP=no specified; return early.
+ [ "$PEERNTP" = "no" ] && return
+
for server in $nm_dhcp_servers; do
- echo "server $server $default_server_options" >> "$dhcp_server_file"
+ echo "server $server ${NTPSERVERARGS:-$default_server_options}" >> "$dhcp_server_file"
done
$chronyc reload sources > /dev/null 2>&1 || :
}
--
2.29.2
Use chrony-helper instead of chronyc to avoid changes in default chrony.conf
diff -up chrony-4.1/examples/chrony.nm-dispatcher.dhcp.nm-dispatcher-dhcp chrony-4.1/examples/chrony.nm-dispatcher.dhcp
--- chrony-4.1/examples/chrony.nm-dispatcher.dhcp.nm-dispatcher-dhcp 2021-06-09 11:10:30.997416152 +0200
+++ chrony-4.1/examples/chrony.nm-dispatcher.dhcp 2021-06-09 11:16:23.598381336 +0200
@@ -9,11 +9,12 @@ export LC_ALL=C
interface=$1
action=$2
-chronyc=/usr/bin/chronyc
+helper=/usr/libexec/chrony-helper
default_server_options=iburst
-server_dir=/run/chrony-dhcp
+server_dir=/run/chrony-helper
-dhcp_server_file=$server_dir/$interface.sources
+dhcp_server_tmpfile=$server_dir/tmp-nm-dhcp.$interface
+dhcp_server_file=$server_dir/nm-dhcp.$interface
# DHCP4_NTP_SERVERS is passed from DHCP options by NetworkManager.
nm_dhcp_servers=$DHCP4_NTP_SERVERS
@@ -24,24 +24,30 @@ nm_dhcp_servers=$DHCP4_NTP_SERVERS
add_servers_from_dhcp() {
rm -f "$dhcp_server_file"
+ # Remove servers saved by the dhclient script before it detected NM.
+ rm -f "/var/lib/dhclient/chrony.servers.$interface"
+
# Don't add NTP servers if PEERNTP=no specified; return early.
[ "$PEERNTP" = "no" ] && return
+ # Create the directory with correct SELinux context.
+ $helper create-helper-directory > /dev/null 2>&1
+
for server in $nm_dhcp_servers; do
- echo "server $server ${NTPSERVERARGS:-$default_server_options}" >> "$dhcp_server_file"
+ echo "$server ${NTPSERVERARGS:-$default_server_options}" >> "$dhcp_server_tmpfile"
done
+ [ -e "$dhcp_server_tmpfile" ] && mv "$dhcp_server_tmpfile" "$dhcp_server_file"
- $chronyc reload sources > /dev/null 2>&1 || :
+
+ $helper update-daemon > /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 || :
+ $helper update-daemon > /dev/null 2>&1 || :
fi
}
-mkdir -p $server_dir
-
if [ "$action" = "up" ] || [ "$action" = "dhcp4-change" ]; then
add_servers_from_dhcp
elif [ "$action" = "down" ]; then

View File

@ -0,0 +1,86 @@
commit f49be7f06343ee27fff2950937d7f6742f53976f
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Tue Mar 12 14:30:27 2024 +0100
conf: don't load sourcedir during initstepslew and RTC init
If the reload sources command was received in the chronyd start-up
sequence with initstepslew and/or RTC init (-s option), the sources
loaded from sourcedirs caused a crash due to failed assertion after
adding sources specified in the config.
Ignore the reload sources command until chronyd enters the normal
operation mode.
Fixes: 519796de3756 ("conf: add sourcedirs directive")
diff --git a/conf.c b/conf.c
index 6eae11c9..8849bdce 100644
--- a/conf.c
+++ b/conf.c
@@ -298,6 +298,8 @@ static ARR_Instance ntp_sources;
static ARR_Instance ntp_source_dirs;
/* Array of uint32_t corresponding to ntp_sources (for sourcedirs reload) */
static ARR_Instance ntp_source_ids;
+/* Flag indicating ntp_sources and ntp_source_ids are used for sourcedirs */
+static int conf_ntp_sources_added = 0;
/* Array of RefclockParameters */
static ARR_Instance refclock_sources;
@@ -1689,8 +1691,12 @@ reload_source_dirs(void)
NSR_Status s;
int d, pass;
+ /* Ignore reload command before adding configured sources */
+ if (!conf_ntp_sources_added)
+ return;
+
prev_size = ARR_GetSize(ntp_source_ids);
- if (prev_size > 0 && ARR_GetSize(ntp_sources) != prev_size)
+ if (ARR_GetSize(ntp_sources) != prev_size)
assert(0);
/* Save the current sources and their configuration IDs */
@@ -1859,7 +1865,10 @@ CNF_AddSources(void)
Free(source->params.name);
}
+ /* The arrays will be used for sourcedir (re)loading */
ARR_SetSize(ntp_sources, 0);
+ ARR_SetSize(ntp_source_ids, 0);
+ conf_ntp_sources_added = 1;
reload_source_dirs();
}
diff --git a/test/simulation/203-initreload b/test/simulation/203-initreload
new file mode 100755
index 00000000..cf7924b8
--- /dev/null
+++ b/test/simulation/203-initreload
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+
+. ./test.common
+
+check_config_h 'FEAT_CMDMON 1' || test_skip
+
+# Test fix "conf: don't load sourcedir during initstepslew and RTC init"
+
+test_start "reload during initstepslew"
+
+client_conf="initstepslew 5 192.168.123.1
+sourcedir tmp"
+client_server_conf="#"
+chronyc_conf="reload sources"
+chronyc_start=4
+
+echo 'server 192.168.123.1' > tmp/sources.sources
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+
+check_log_messages "Added source 192\.168\.123\.1" 1 1 || test_fail
+
+test_pass

View File

@ -0,0 +1,39 @@
commit e11b518a1ffa704986fb1f1835c425844ba248ef
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Mon Jan 8 11:35:56 2024 +0100
ntp: fix authenticated requests in serverstats
Fix the CLG_UpdateNtpStats() call to count requests passing the
authentication check instead of requests triggering a KoD response
(i.e. NTS NAK).
diff --git a/ntp_core.c b/ntp_core.c
index 023e60b2..35801744 100644
--- a/ntp_core.c
+++ b/ntp_core.c
@@ -2736,7 +2736,7 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
CLG_DisableNtpTimestamps(&ntp_rx);
}
- CLG_UpdateNtpStats(kod != 0 && info.auth.mode != NTP_AUTH_NONE &&
+ CLG_UpdateNtpStats(kod == 0 && info.auth.mode != NTP_AUTH_NONE &&
info.auth.mode != NTP_AUTH_MSSNTP,
rx_ts->source, interleaved ? tx_ts->source : NTP_TS_DAEMON);
diff --git a/test/system/010-nts b/test/system/010-nts
index 8d92bbc8..b215efa3 100755
--- a/test/system/010-nts
+++ b/test/system/010-nts
@@ -45,6 +45,11 @@ check_chronyc_output "^Name/IP address Mode KeyID Type KLen Last Atm
=========================================================================
127\.0\.0\.1 NTS 1 (30|15) (128|256) [0-9] 0 0 [78] ( 64|100)$" || test_fail
+run_chronyc "serverstats" || test_fail
+check_chronyc_output "NTS-KE connections accepted: 1
+NTS-KE connections dropped : 0
+Authenticated NTP packets : [1-9][0-9]*" || test_fail
+
stop_chronyd || test_fail
check_chronyd_messages || test_fail
check_chronyd_files || test_fail

View File

@ -0,0 +1,12 @@
diff -up chrony-4.1/examples/chronyd.service.service-helper chrony-4.1/examples/chronyd.service
--- chrony-4.1/examples/chronyd.service.service-helper 2021-05-12 13:06:15.000000000 +0200
+++ chrony-4.1/examples/chronyd.service 2021-06-15 09:01:56.948968576 +0200
@@ -10,6 +10,8 @@ Type=forking
PIDFile=/run/chrony/chronyd.pid
EnvironmentFile=-/etc/sysconfig/chronyd
ExecStart=/usr/sbin/chronyd $OPTIONS
+ExecStartPost=/usr/libexec/chrony-helper update-daemon
+ExecStopPost=/usr/libexec/chrony-helper remove-daemon-state
PrivateTmp=yes
ProtectHome=yes
ProtectSystem=full

View File

@ -0,0 +1,81 @@
diff --git a/examples/chrony-wait.service b/examples/chrony-wait.service
index 72b028f2..b3aa7aa2 100644
--- a/examples/chrony-wait.service
+++ b/examples/chrony-wait.service
@@ -16,31 +16,5 @@ 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
diff --git a/examples/chronyd.service b/examples/chronyd.service
index 4fb930ef..289548cb 100644
--- a/examples/chronyd.service
+++ b/examples/chronyd.service
@@ -10,39 +10,9 @@ Type=forking
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
+ProtectSystem=full
[Install]
WantedBy=multi-user.target

View File

@ -1,7 +1,6 @@
#!/bin/bash #!/bin/bash
CHRONY_SOURCEDIR=/run/chrony-dhcp SERVERFILE=$SAVEDIR/chrony.servers.$interface
SERVERFILE=$CHRONY_SOURCEDIR/$interface.sources
chrony_config() { chrony_config() {
# Disable modifications if called from a NM dispatcher script # Disable modifications if called from a NM dispatcher script
@ -9,11 +8,10 @@ chrony_config() {
rm -f "$SERVERFILE" rm -f "$SERVERFILE"
if [ "$PEERNTP" != "no" ]; then if [ "$PEERNTP" != "no" ]; then
mkdir -p $CHRONY_SOURCEDIR
for server in $new_ntp_servers; do for server in $new_ntp_servers; do
echo "server $server ${NTPSERVERARGS:-iburst}" >> "$SERVERFILE" echo "$server ${NTPSERVERARGS:-iburst}" >> "$SERVERFILE"
done done
/usr/bin/chronyc reload sources > /dev/null 2>&1 || : /usr/libexec/chrony-helper update-daemon || :
fi fi
} }
@ -22,6 +20,6 @@ chrony_restore() {
if [ -f "$SERVERFILE" ]; then if [ -f "$SERVERFILE" ]; then
rm -f "$SERVERFILE" rm -f "$SERVERFILE"
/usr/bin/chronyc reload sources > /dev/null 2>&1 || : /usr/libexec/chrony-helper update-daemon || :
fi fi
} }

285
SOURCES/chrony.helper Normal file
View File

@ -0,0 +1,285 @@
#!/bin/bash
# This script configures running chronyd to use NTP servers obtained from
# DHCP and _ntp._udp DNS SRV records. Files with servers from DHCP are managed
# externally (e.g. by a dhclient script). Files with servers from DNS SRV
# records are updated here using the dig utility. The script can also list
# and set static sources in the chronyd configuration file.
chronyc=/usr/bin/chronyc
chrony_conf=/etc/chrony.conf
chrony_service=chronyd.service
helper_dir=/run/chrony-helper
added_servers_file=$helper_dir/added_servers
network_sysconfig_file=/etc/sysconfig/network
nm_servers_files="$helper_dir/nm-dhcp.*"
dhclient_servers_files="/var/lib/dhclient/chrony.servers.*"
dnssrv_servers_files="$helper_dir/dnssrv@*"
dnssrv_timer_prefix=chrony-dnssrv@
. $network_sysconfig_file &> /dev/null
chrony_command() {
$chronyc -n -m "$@"
}
is_running() {
chrony_command "tracking" &> /dev/null
}
get_servers_files() {
[ "$PEERNTP" != "no" ] && echo "$nm_servers_files"
[ "$PEERNTP" != "no" ] && echo "$dhclient_servers_files"
echo "$dnssrv_servers_files"
}
is_update_needed() {
for file in $(get_servers_files) $added_servers_file; do
[ -e "$file" ] && return 0
done
return 1
}
remove_daemon_state() {
rm -f $added_servers_file
}
update_daemon() {
local all_servers_with_args all_servers added_servers
if ! is_running; then
remove_daemon_state
return 0
fi
all_servers_with_args=$(cat $(get_servers_files) 2> /dev/null)
all_servers=$(
echo "$all_servers_with_args" |
while read -r server serverargs; do
echo "$server"
done | sort -u)
added_servers=$( (
cat $added_servers_file 2> /dev/null
echo "$all_servers_with_args" |
while read -r server serverargs; do
[ -z "$server" ] && continue
chrony_command "add server $server $serverargs" &> /dev/null &&
echo "$server"
done) | sort -u)
comm -23 <(echo -n "$added_servers") <(echo -n "$all_servers") |
while read -r server; do
chrony_command -c sources -a 2>/dev/null |
while IFS=, read -r type _ address _; do
[ "$type" = "^" ] || continue
[ "$(chrony_command "sourcename $address")" = "$server" ] || continue
chrony_command "delete $address" &> /dev/null
break
done
done
added_servers=$(comm -12 <(echo -n "$added_servers") <(echo -n "$all_servers"))
if [ -n "$added_servers" ]; then
echo "$added_servers" > $added_servers_file
else
rm -f $added_servers_file
fi
}
get_dnssrv_servers() {
local name=$1 output
if ! command -v dig &> /dev/null; then
echo "Missing dig (DNS lookup utility)" >&2
return 1
fi
output=$(dig "$name" srv +short +ndots=2 +search 2> /dev/null) || return 0
echo "$output" | while read -r _ _ port target; do
server=${target%.}
[ -z "$server" ] && continue
echo "$server port $port ${NTPSERVERARGS:-iburst}"
done
}
check_dnssrv_name() {
local name=$1
if [ -z "$name" ]; then
echo "No DNS SRV name specified" >&2
return 1
fi
if [ "${name:0:9}" != _ntp._udp ]; then
echo "DNS SRV name $name doesn't start with _ntp._udp" >&2
return 1
fi
}
update_dnssrv_servers() {
local name=$1
local srv_file=$helper_dir/dnssrv@$name servers
check_dnssrv_name "$name" || return 1
servers=$(get_dnssrv_servers "$name")
if [ -n "$servers" ]; then
echo "$servers" > "$srv_file"
else
rm -f "$srv_file"
fi
}
set_dnssrv_timer() {
local state=$1 name=$2
local srv_file=$helper_dir/dnssrv@$name servers
local timer
timer=$dnssrv_timer_prefix$(systemd-escape "$name").timer || return 1
check_dnssrv_name "$name" || return 1
if [ "$state" = enable ]; then
systemctl enable "$timer"
systemctl start "$timer"
elif [ "$state" = disable ]; then
systemctl stop "$timer"
systemctl disable "$timer"
rm -f "$srv_file"
fi
}
list_dnssrv_timers() {
systemctl --all --full -t timer list-units | grep "^$dnssrv_timer_prefix" | \
sed "s|^$dnssrv_timer_prefix\(.*\)\.timer.*|\1|" |
while read -r name; do
systemd-escape --unescape "$name"
done
}
prepare_helper_dir() {
mkdir -p $helper_dir
exec 100> $helper_dir/lock
if ! flock -w 20 100; then
echo "Failed to lock $helper_dir" >&2
return 1
fi
}
is_source_line() {
local pattern="^[ \t]*(server|pool|peer|refclock)[ \t]+[^ \t]+"
[[ "$1" =~ $pattern ]]
}
list_static_sources() {
while read -r line; do
if is_source_line "$line"; then
echo "$line"
fi
done < $chrony_conf
}
set_static_sources() {
local new_config tmp_conf
new_config=$(
sources=$(
while read -r line; do
is_source_line "$line" && echo "$line"
done)
while read -r line; do
if ! is_source_line "$line"; then
echo "$line"
continue
fi
tmp_sources=$(
local removed=0
echo "$sources" | while read -r line2; do
if [ "$removed" -ne 0 ] || [ "$line" != "$line2" ]; then
echo "$line2"
else
removed=1
fi
done)
[ "$sources" == "$tmp_sources" ] && continue
sources=$tmp_sources
echo "$line"
done < $chrony_conf
echo "$sources"
)
tmp_conf=${chrony_conf}.tmp
cp -a $chrony_conf $tmp_conf &&
echo "$new_config" > $tmp_conf &&
mv $tmp_conf $chrony_conf || return 1
systemctl try-restart $chrony_service
}
print_help() {
echo "Usage: $0 COMMAND"
echo
echo "Commands:"
echo " create-helper-directory"
echo " update-daemon"
echo " remove-daemon-state"
echo " update-dnssrv-servers NAME"
echo " enable-dnssrv NAME"
echo " disable-dnssrv NAME"
echo " list-dnssrv"
echo " list-static-sources"
echo " set-static-sources < sources.list"
echo " is-running"
echo " command CHRONYC-COMMAND"
}
case "$1" in
create-helper-directory)
prepare_helper_dir
;;
update-daemon|add-dhclient-servers|remove-dhclient-servers)
is_update_needed || exit 0
prepare_helper_dir && update_daemon
;;
remove-daemon-state)
remove_daemon_state
;;
update-dnssrv-servers)
prepare_helper_dir && update_dnssrv_servers "$2" && update_daemon
;;
enable-dnssrv)
set_dnssrv_timer enable "$2"
;;
disable-dnssrv)
set_dnssrv_timer disable "$2" && prepare_helper_dir && update_daemon
;;
list-dnssrv)
list_dnssrv_timers
;;
list-static-sources)
list_static_sources
;;
set-static-sources)
set_static_sources
;;
is-running)
is_running
;;
command|forced-command)
chrony_command "$2"
;;
*)
print_help
exit 2
esac
exit $?

680
SOURCES/ntp2chrony.py Normal file
View File

@ -0,0 +1,680 @@
#!/usr/bin/python3
#
# Convert ntp configuration to chrony
#
# Copyright (C) 2018-2019 Miroslav Lichvar <mlichvar@redhat.com>
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import argparse
import ipaddress
import logging
import os
import re
import subprocess
import sys
# python2 compatibility hacks
if sys.version_info[0] < 3:
from io import open
reload(sys)
sys.setdefaultencoding("utf-8")
class NtpConfiguration(object):
def __init__(self, root_dir, ntp_conf, step_tickers):
self.root_dir = root_dir if root_dir != "/" else ""
self.ntp_conf_path = ntp_conf
self.step_tickers_path = step_tickers
# Read and write files using an 8-bit transparent encoding
self.file_encoding = "latin-1"
self.enabled_services = set()
self.step_tickers = []
self.time_sources = []
self.fudges = {}
self.restrictions = {
# Built-in defaults
ipaddress.ip_network(u"0.0.0.0/0"): set(),
ipaddress.ip_network(u"::/0"): set(),
}
self.keyfile = ""
self.keys = []
self.trusted_keys = []
self.driftfile = ""
self.statistics = []
self.leapfile = ""
self.tos_options = {}
self.ignored_directives = set()
self.ignored_lines = []
# self.detect_enabled_services()
self.parse_step_tickers()
self.parse_ntp_conf()
def detect_enabled_services(self):
for service in ["ntpdate", "ntpd", "ntp-wait"]:
service_path = os.path.join(self.root_dir,
"etc/systemd/system/multi-user.target.wants/{}.service".format(service))
if os.path.islink(service_path):
self.enabled_services.add(service)
logging.info("Enabled services found in /etc/systemd/system: %s",
" ".join(self.enabled_services))
def parse_step_tickers(self):
if not self.step_tickers_path:
return
path = os.path.join(self.root_dir, self.step_tickers_path)
if not os.path.isfile(path):
logging.info("Missing %s", path)
return
with open(path, encoding=self.file_encoding) as f:
for line in f:
line = line[:line.find('#')]
words = line.split()
if not words:
continue
self.step_tickers.extend(words)
def parse_ntp_conf(self, path=None):
if path is None:
path = os.path.join(self.root_dir, self.ntp_conf_path)
with open(path, encoding=self.file_encoding) as f:
logging.info("Reading %s", path)
for line in f:
line = line[:line.find('#')]
words = line.split()
if not words:
continue
if not self.parse_directive(words):
self.ignored_lines.append(line)
def parse_directive(self, words):
name = words.pop(0)
if name.startswith("logconfig"):
name = "logconfig"
if words:
if name in ["server", "peer", "pool"]:
return self.parse_source(name, words)
elif name == "fudge":
return self.parse_fudge(words)
elif name == "restrict":
return self.parse_restrict(words)
elif name == "tos":
return self.parse_tos(words)
elif name == "includefile":
return self.parse_includefile(words)
elif name == "keys":
return self.parse_keys(words)
elif name == "trustedkey":
return self.parse_trustedkey(words)
elif name == "driftfile":
self.driftfile = words[0]
elif name == "statistics":
self.statistics = words
elif name == "leapfile":
self.leapfile = words[0]
else:
self.ignored_directives.add(name)
return False
else:
self.ignored_directives.add(name)
return False
return True
def parse_source(self, source_type, words):
ipv4_only = False
ipv6_only = False
source = {
"type": source_type,
"options": []
}
if words[0] == "-4":
ipv4_only = True
words.pop(0)
elif words[0] == "-6":
ipv6_only = True
words.pop(0)
if not words:
return False
source["address"] = words.pop(0)
# Check if -4/-6 corresponds to the address and ignore hostnames
if ipv4_only or ipv6_only:
try:
version = ipaddress.ip_address(source["address"]).version
if (ipv4_only and version != 4) or (ipv6_only and version != 6):
return False
except ValueError:
return False
if source["address"].startswith("127.127."):
if not source["address"].startswith("127.127.1."):
# Ignore non-LOCAL refclocks
return False
while words:
if len(words) >= 2 and words[0] in ["minpoll", "maxpoll", "version", "key"]:
source["options"].append((words[0], words[1]))
words = words[2:]
elif words[0] in ["burst", "iburst", "noselect", "prefer", "true", "xleave"]:
source["options"].append((words[0],))
words.pop(0)
else:
return False
self.time_sources.append(source)
return True
def parse_fudge(self, words):
address = words.pop(0)
options = {}
while words:
if len(words) >= 2 and words[0] in ["stratum"]:
if not words[1].isdigit():
return False
options[words[0]] = int(words[1])
words = words[2:]
elif len(words) >= 2:
words = words[2:]
else:
return False
self.fudges[address] = options
return True
def parse_restrict(self, words):
ipv4_only = False
ipv6_only = False
flags = set()
mask = ""
if words[0] == "-4":
ipv4_only = True
words.pop(0)
elif words[0] == "-6":
ipv6_only = True
words.pop(0)
if not words:
return False
address = words.pop(0)
while words:
if len(words) >= 2 and words[0] == "mask":
mask = words[1]
words = words[2:]
else:
if words[0] not in ["kod", "nomodify", "notrap", "nopeer", "noquery",
"limited", "ignore", "noserve"]:
return False
flags.add(words[0])
words.pop(0)
# Convert to IP network(s), ignoring restrictions with hostnames
networks = []
if address == "default" and not mask:
if not ipv6_only:
networks.append(ipaddress.ip_network(u"0.0.0.0/0"))
if not ipv4_only:
networks.append(ipaddress.ip_network(u"::/0"))
else:
try:
if mask:
# Count bits in the mask (ipaddress does not support
# expanded IPv6 netmasks)
mask_ip = ipaddress.ip_address(mask)
mask_str = "{0:0{1}b}".format(int(mask_ip), mask_ip.max_prefixlen)
networks.append(ipaddress.ip_network(
u"{}/{}".format(address, len(mask_str.rstrip('0')))))
else:
networks.append(ipaddress.ip_network(address))
except ValueError:
return False
if (ipv4_only and networks[-1].version != 4) or \
(ipv6_only and networks[-1].version != 6):
return False
for network in networks:
self.restrictions[network] = flags
return True
def parse_tos(self, words):
options = {}
while words:
if len(words) >= 2 and words[0] in ["minsane", "orphan"]:
if not words[1].isdigit():
return False
options[words[0]] = int(words[1])
words = words[2:]
elif len(words) >= 2 and words[0] in ["maxdist"]:
# Check if it is a float value
if not words[1].replace('.', '', 1).isdigit():
return False
options[words[0]] = float(words[1])
words = words[2:]
else:
return False
self.tos_options.update(options)
return True
def parse_includefile(self, words):
path = os.path.join(self.root_dir, words[0])
if not os.path.isfile(path):
return False
self.parse_ntp_conf(path)
return True
def parse_keys(self, words):
keyfile = words[0]
path = os.path.join(self.root_dir, keyfile)
if not os.path.isfile(path):
logging.info("Missing %s", path)
return False
with open(path, encoding=self.file_encoding) as f:
logging.info("Reading %s", path)
keys = []
for line in f:
words = line.split()
if len(words) < 3 or not words[0].isdigit():
continue
keys.append((int(words[0]), words[1], words[2]))
self.keyfile = keyfile
self.keys = keys
return True
def parse_trustedkey(self, words):
key_ranges = []
for word in words:
if word.isdigit():
key_ranges.append((int(word), int(word)))
elif re.match("^[0-9]+-[0-9]+$", word):
first, last = word.split("-")
key_ranges.append((int(first), int(last)))
else:
return False
self.trusted_keys = key_ranges
return True
def write_chrony_configuration(self, chrony_conf_path, chrony_keys_path,
dry_run=False, backup=False):
chrony_conf = self.get_chrony_conf(chrony_keys_path)
logging.debug("Generated %s:\n%s", chrony_conf_path, chrony_conf)
if not dry_run:
self.write_file(chrony_conf_path, 0o644, chrony_conf, backup)
chrony_keys = self.get_chrony_keys()
if chrony_keys:
logging.debug("Generated %s:\n%s", chrony_keys_path, chrony_keys)
if not dry_run:
self.write_file(chrony_keys_path, 0o640, chrony_keys, backup)
def get_processed_time_sources(self):
# Convert {0,1,2,3}.*pool.ntp.org servers to 2.*pool.ntp.org pools
# Make shallow copies of all sources (only type will be modified)
time_sources = [s.copy() for s in self.time_sources]
pools = {}
for source in time_sources:
if source["type"] != "server":
continue
m = re.match("^([0123])(\\.\\w+)?\\.pool\\.ntp\\.org$", source["address"])
if m is None:
continue
number = m.group(1)
zone = m.group(2)
if zone not in pools:
pools[zone] = []
pools[zone].append((int(number), source))
remove_servers = set()
for zone, pool in pools.items():
# sort and skip all pools not in [0, 3] range
pool.sort()
if [number for number, source in pool] != [0, 1, 2, 3]:
# only exact group of 4 servers can be converted, nothing to do here
continue
# verify that parameters are the same for all servers in the pool
if not all([p[1]["options"] == pool[0][1]["options"] for p in pool]):
break
remove_servers.update([pool[i][1]["address"] for i in [0, 1, 3]])
pool[2][1]["type"] = "pool"
processed_sources = []
for source in time_sources:
if source["type"] == "server" and source["address"] in remove_servers:
continue
processed_sources.append(source)
return processed_sources
def get_chrony_conf_sources(self):
conf = ""
if self.step_tickers:
conf += "# Specify NTP servers used for initial correction.\n"
conf += "initstepslew 0.1 {}\n".format(" ".join(self.step_tickers))
conf += "\n"
conf += "# Specify time sources.\n"
for source in self.get_processed_time_sources():
address = source["address"]
if address.startswith("127.127."):
if address.startswith("127.127.1."):
continue
# No other refclocks are expected from the parser
assert False
else:
conf += "{} {}".format(source["type"], address)
for option in source["options"]:
if option[0] in ["minpoll", "maxpoll", "version", "key",
"iburst", "noselect", "prefer", "xleave"]:
conf += " {}".format(" ".join(option))
elif option[0] == "burst":
conf += " presend 6"
elif option[0] == "true":
conf += " trust"
else:
# No other options are expected from the parser
assert False
conf += "\n"
conf += "\n"
return conf
def get_chrony_conf_allows(self):
allowed_networks = filter(lambda n: "ignore" not in self.restrictions[n] and
"noserve" not in self.restrictions[n],
self.restrictions.keys())
conf = ""
for network in sorted(allowed_networks, key=lambda n: (n.version, n)):
if network.num_addresses > 1:
conf += "allow {}\n".format(network)
else:
conf += "allow {}\n".format(network.network_address)
if conf:
conf = "# Allow NTP client access.\n" + conf
conf += "\n"
return conf
def get_chrony_conf_cmdallows(self):
allowed_networks = filter(lambda n: "ignore" not in self.restrictions[n] and
"noquery" not in self.restrictions[n] and
n != ipaddress.ip_network(u"127.0.0.1/32") and
n != ipaddress.ip_network(u"::1/128"),
self.restrictions.keys())
ip_versions = set()
conf = ""
for network in sorted(allowed_networks, key=lambda n: (n.version, n)):
ip_versions.add(network.version)
if network.num_addresses > 1:
conf += "cmdallow {}\n".format(network)
else:
conf += "cmdallow {}\n".format(network.network_address)
if conf:
conf = "# Allow remote monitoring.\n" + conf
if 4 in ip_versions:
conf += "bindcmdaddress 0.0.0.0\n"
if 6 in ip_versions:
conf += "bindcmdaddress ::\n"
conf += "\n"
return conf
def get_chrony_conf(self, chrony_keys_path):
local_stratum = 0
maxdistance = 0.0
minsources = 1
orphan_stratum = 0
logs = []
for source in self.time_sources:
address = source["address"]
if address.startswith("127.127.1."):
if address in self.fudges and "stratum" in self.fudges[address]:
local_stratum = self.fudges[address]["stratum"]
else:
local_stratum = 5
if "maxdist" in self.tos_options:
maxdistance = self.tos_options["maxdist"]
if "minsane" in self.tos_options:
minsources = self.tos_options["minsane"]
if "orphan" in self.tos_options:
orphan_stratum = self.tos_options["orphan"]
if "clockstats" in self.statistics:
logs.append("refclocks")
if "loopstats" in self.statistics:
logs.append("tracking")
if "peerstats" in self.statistics:
logs.append("statistics")
if "rawstats" in self.statistics:
logs.append("measurements")
conf = "# This file was converted from {}{}.\n".format(
self.ntp_conf_path,
" and " + self.step_tickers_path if self.step_tickers_path else "")
conf += "\n"
if self.ignored_lines:
conf += "# The following directives were ignored in the conversion:\n"
for line in self.ignored_lines:
# Remove sensitive information
line = re.sub(r"\s+pw\s+\S+", " pw XXX", line.rstrip())
conf += "# " + line + "\n"
conf += "\n"
conf += self.get_chrony_conf_sources()
conf += "# Record the rate at which the system clock gains/losses time.\n"
if not self.driftfile:
conf += "#"
conf += "driftfile /var/lib/chrony/drift\n"
conf += "\n"
conf += "# Allow the system clock to be stepped in the first three updates\n"
conf += "# if its offset is larger than 1 second.\n"
conf += "makestep 1.0 3\n"
conf += "\n"
conf += "# Enable kernel synchronization of the real-time clock (RTC).\n"
conf += "rtcsync\n"
conf += "\n"
conf += "# Enable hardware timestamping on all interfaces that support it.\n"
conf += "#hwtimestamp *\n"
conf += "\n"
if maxdistance > 0.0:
conf += "# Specify the maximum distance of sources to be selectable.\n"
conf += "maxdistance {}\n".format(maxdistance)
conf += "\n"
conf += "# Increase the minimum number of selectable sources required to adjust\n"
conf += "# the system clock.\n"
if minsources > 1:
conf += "minsources {}\n".format(minsources)
else:
conf += "#minsources 2\n"
conf += "\n"
conf += self.get_chrony_conf_allows()
conf += self.get_chrony_conf_cmdallows()
conf += "# Serve time even if not synchronized to a time source.\n"
if orphan_stratum > 0 and orphan_stratum < 16:
conf += "local stratum {} orphan\n".format(orphan_stratum)
elif local_stratum > 0 and local_stratum < 16:
conf += "local stratum {}\n".format(local_stratum)
else:
conf += "#local stratum 10\n"
conf += "\n"
conf += "# Specify file containing keys for NTP authentication.\n"
conf += "keyfile {}\n".format(chrony_keys_path)
conf += "\n"
conf += "# Get TAI-UTC offset and leap seconds from the system tz database.\n"
conf += "leapsectz right/UTC\n"
conf += "\n"
conf += "# Specify directory for log files.\n"
conf += "logdir /var/log/chrony\n"
conf += "\n"
conf += "# Select which information is logged.\n"
if logs:
conf += "log {}\n".format(" ".join(logs))
else:
conf += "#log measurements statistics tracking\n"
return conf
def get_chrony_keys(self):
if not self.keyfile:
return ""
keys = "# This file was converted from {}.\n".format(self.keyfile)
keys += "\n"
for key in self.keys:
key_id = key[0]
key_type = key[1]
password = key[2]
if key_type in ["m", "M"]:
key_type = "MD5"
elif key_type == "AES128CMAC":
key_type = "AES128"
elif key_type not in ["MD5", "SHA1", "SHA256", "SHA384", "SHA512"]:
continue
prefix = "ASCII" if len(password) <= 20 else "HEX"
for first, last in self.trusted_keys:
if first <= key_id <= last:
trusted = True
break
else:
trusted = False
# Disable keys that were not marked as trusted
if not trusted:
keys += "#"
keys += "{} {} {}:{}\n".format(key_id, key_type, prefix, password)
return keys
def write_file(self, path, mode, content, backup):
path = self.root_dir + path
if backup and os.path.isfile(path):
os.rename(path, path + ".old")
with open(os.open(path, os.O_CREAT | os.O_WRONLY | os.O_EXCL, mode), "w",
encoding=self.file_encoding) as f:
logging.info("Writing %s", path)
f.write(u"" + content)
# Fix SELinux context if restorecon is installed
try:
subprocess.call(["restorecon", path])
except OSError:
pass
def main():
parser = argparse.ArgumentParser(description="Convert ntp configuration to chrony.")
parser.add_argument("-r", "--root", dest="roots", default=["/"], nargs="+",
metavar="DIR", help="specify root directory (default /)")
parser.add_argument("--ntp-conf", action="store", default="/etc/ntp.conf",
metavar="FILE", help="specify ntp config (default /etc/ntp.conf)")
parser.add_argument("--step-tickers", action="store", default="",
metavar="FILE", help="specify ntpdate step-tickers config (no default)")
parser.add_argument("--chrony-conf", action="store", default="/etc/chrony.conf",
metavar="FILE", help="specify chrony config (default /etc/chrony.conf)")
parser.add_argument("--chrony-keys", action="store", default="/etc/chrony.keys",
metavar="FILE", help="specify chrony keyfile (default /etc/chrony.keys)")
parser.add_argument("-b", "--backup", action="store_true", help="backup existing configs before writing")
parser.add_argument("-L", "--ignored-lines", action="store_true", help="print ignored lines")
parser.add_argument("-D", "--ignored-directives", action="store_true",
help="print names of ignored directives")
parser.add_argument("-n", "--dry-run", action="store_true", help="don't make any changes")
parser.add_argument("-v", "--verbose", action="count", default=0, help="increase verbosity")
args = parser.parse_args()
logging.basicConfig(format="%(message)s",
level=[logging.ERROR, logging.INFO, logging.DEBUG][min(args.verbose, 2)])
for root in args.roots:
conf = NtpConfiguration(root, args.ntp_conf, args.step_tickers)
if args.ignored_lines:
for line in conf.ignored_lines:
print(line)
if args.ignored_directives:
for directive in conf.ignored_directives:
print(directive)
conf.write_chrony_configuration(args.chrony_conf, args.chrony_keys, args.dry_run, args.backup)
if __name__ == "__main__":
main()

View File

@ -1,55 +1,57 @@
%global _hardened_build 1 %global _hardened_build 1
%global clknetsim_ver cdd694 %global clknetsim_ver 5d1dc0
%global ntp2chrony_ver 233b75
%bcond_without debug %bcond_without debug
%bcond_without nts %bcond_without nts
%ifarch %{ix86} x86_64 %{arm} aarch64 mipsel mips64el ppc64 ppc64le s390 s390x
%bcond_without seccomp
%endif
Name: chrony Name: chrony
Version: 4.6.1 Version: 4.5
Release: 2%{?dist} Release: 2%{?dist}
Summary: An NTP client/server Summary: An NTP client/server
License: GPL-2.0-only Group: System Environment/Daemons
License: GPLv2
URL: https://chrony-project.org URL: https://chrony-project.org
Source0: https://chrony-project.org/releases/chrony-%{version}%{?prerelease}.tar.gz Source0: https://chrony-project.org/releases/chrony-%{version}%{?prerelease}.tar.gz
Source1: https://chrony-project.org/releases/chrony-%{version}%{?prerelease}-tar-gz-asc.txt Source1: chrony.dhclient
Source2: https://chrony-project.org/gpgkey-8F375C7E8D0EE125A3D3BD51537E2B76F7680DAC.asc Source2: chrony.helper
Source3: chrony.dhclient Source3: chrony-dnssrv@.service
Source4: chrony.sysusers Source4: chrony-dnssrv@.timer
# simulator for test suite # simulator for test suite
Source10: https://gitlab.com/chrony/clknetsim/-/archive/master/clknetsim-%{clknetsim_ver}.tar.gz Source10: https://gitlab.com/chrony/clknetsim/-/archive/master/clknetsim-%{clknetsim_ver}.tar.gz
# script for converting ntp configuration to chrony
Source11: https://github.com/mlichvar/ntp2chrony/raw/%{ntp2chrony_ver}/ntp2chrony/ntp2chrony.py
%{?gitpatch:Patch0: chrony-%{version}%{?prerelease}-%{gitpatch}.patch.gz} %{?gitpatch:Patch0: chrony-%{version}%{?prerelease}-%{gitpatch}.patch.gz}
# add distribution-specific bits to DHCP dispatcher # revert upstream changes in packaged service files
Patch0: chrony-services.patch
# modify NetworkManager DHCP dispatcher to work with chrony-helper and
# follow distribution-specific configuration
Patch1: chrony-nm-dispatcher-dhcp.patch Patch1: chrony-nm-dispatcher-dhcp.patch
# keep PHC refclock reachable when dropping samples due to high delay # add NTP servers from DHCP when starting service
Patch2: chrony-refclkreach.patch Patch2: chrony-service-helper.patch
# improve description of refresh directive # revert upstream changes in packaged configuration examples
Patch3: chrony-docrefresh.patch Patch3: chrony-defconfig.patch
# improve logging of selection failures # fix serverstats to correctly count authenticated packets
Patch4: chrony-logselect.patch Patch4: chrony-serverstats.patch
# fix sourcedir reloading to not multiply sources # fix crash on reload command during start
Patch5: chrony-sourcedir.patch Patch5: chrony-reload.patch
# enable AES-CMAC support using gnutls (but keep nettle for hashing)
Patch6: chrony-cmac.patch
# revert clknetsim changes in PHC breaking old refclock tests BuildRequires: libcap-devel libedit-devel nettle-devel pps-tools-devel
Patch20: clknetsim-revert-phc.patch %ifarch %{ix86} x86_64 %{arm} aarch64 mipsel mips64el ppc64 ppc64le s390 s390x
BuildRequires: libseccomp-devel
BuildRequires: gnutls-devel libcap-devel libedit-devel pps-tools-devel %endif
BuildRequires: gcc gcc-c++ make bison systemd gnupg2 BuildRequires: gcc gcc-c++ make bison systemd
%{?with_nts:BuildRequires: gnutls-utils} BuildRequires: kernel-headers > 4.18.0-87
%{?with_seccomp:BuildRequires: libseccomp-devel} %{?with_nts:BuildRequires: gnutls-devel gnutls-utils}
Requires(pre): shadow-utils
%{?systemd_requires} %{?systemd_requires}
%{?sysusers_requires_compat}
# Needed by the leapsectz directive in default chrony.conf # install timedated implementation that can control chronyd service
Requires: tzdata Recommends: timedatex
# Old NetworkManager expects the dispatcher scripts in a different place
Conflicts: NetworkManager < 1.20
# suggest drivers for hardware reference clocks # suggest drivers for hardware reference clocks
Suggests: ntp-refclock Suggests: ntp-refclock
@ -66,30 +68,27 @@ service to other computers in the network.
%endif %endif
%prep %prep
%{gpgverify} --keyring=%{SOURCE2} --signature=%{SOURCE1} --data=%{SOURCE0}
%setup -q -n %{name}-%{version}%{?prerelease} -a 10 %setup -q -n %{name}-%{version}%{?prerelease} -a 10
%{?gitpatch:%patch -P 0 -p1} %{?gitpatch:%patch0 -p1}
%patch -P 1 -p1 -b .nm-dispatcher-dhcp %patch0 -p1 -b .services
%patch -P 2 -p1 %patch1 -p1 -b .nm-dispatcher-dhcp
%patch -P 3 -p1 -b .docrefresh %patch2 -p1 -b .service-helper
%patch -P 4 -p1 %patch3 -p1 -b .defconfig
%patch -P 5 -p1 %patch4 -p1 -b .serverstats
%patch5 -p1
pushd clknetsim-*-%{clknetsim_ver}* %patch6 -p1 -b .cmac
%patch -P 20 -R -p1
popd
%{?gitpatch: echo %{version}-%{gitpatch} > version.txt} %{?gitpatch: echo %{version}-%{gitpatch} > version.txt}
# review changes in packaged configuration files and scripts # review changes in packaged configuration files and scripts
md5sum -c <<-EOF | (! grep -v 'OK$') md5sum -c <<-EOF | (! grep -v 'OK$')
5530d6e60f84b76c27495485d2510bac examples/chrony-wait.service bc563c1bcf67b2da774bd8c2aef55a06 examples/chrony-wait.service
826354a2d467d6147e412d43bfe07484 examples/chrony.conf.example2 e473a9fab7fe200cacce3dca8b66290b examples/chrony.conf.example2
96999221eeef476bd49fe97b97503126 examples/chrony.keys.example
6a3178c4670de7de393d9365e2793740 examples/chrony.logrotate 6a3178c4670de7de393d9365e2793740 examples/chrony.logrotate
c3992e2f985550739cd1cd95f98c9548 examples/chrony.nm-dispatcher.dhcp fabb5b3f127b802c27c82837feff0fe6 examples/chrony.nm-dispatcher.dhcp
4e85d36595727318535af3387411070c examples/chrony.nm-dispatcher.onoffline 4e85d36595727318535af3387411070c examples/chrony.nm-dispatcher.onoffline
c11159b78b89684eca773db6236a9855 examples/chronyd.service 56d221eba8ce8a2e03d3e0dd87999a81 examples/chronyd.service
46fa3e2d42c8eb9c42e71095686c90ed examples/chronyd-restricted.service
EOF EOF
# don't allow packaging without vendor zone # don't allow packaging without vendor zone
@ -98,28 +97,26 @@ test -n "%{vendorzone}"
# use example chrony.conf as the default config with some modifications: # use example chrony.conf as the default config with some modifications:
# - use our vendor zone (2.*pool.ntp.org names include IPv6 addresses) # - use our vendor zone (2.*pool.ntp.org names include IPv6 addresses)
# - enable leapsectz to get TAI-UTC offset and leap seconds from tzdata # - enable leapsectz to get TAI-UTC offset and leap seconds from tzdata
# - use NTP servers from DHCP # - enable keyfile
sed -e 's|^\(pool \)\(pool.ntp.org\)|\12.%{vendorzone}\2|' \ sed -e 's|^\(pool \)\(pool.ntp.org\)|\12.%{vendorzone}\2|' \
-e 's|#\(leapsectz\)|\1|' \ -e 's|#\(leapsectz\)|\1|' \
-e 's|^pool.*pool.ntp.org.*|&\n\n# Use NTP servers from DHCP.\nsourcedir /run/chrony-dhcp|' \ -e 's|#\(keyfile\)|\1|' \
< examples/chrony.conf.example2 > chrony.conf < examples/chrony.conf.example2 > chrony.conf
touch -r examples/chrony.conf.example2 chrony.conf touch -r examples/chrony.conf.example2 chrony.conf
# set selinux context in chronyd-restricted service
sed -i '/^ExecStart/a SELinuxContext=system_u:system_r:chronyd_restricted_t:s0' \
examples/chronyd-restricted.service
# regenerate the file from getdate.y # regenerate the file from getdate.y
rm -f getdate.c rm -f getdate.c
mv clknetsim-*-%{clknetsim_ver}* test/simulation/clknetsim mv clknetsim-*-%{clknetsim_ver}* test/simulation/clknetsim
install -m 644 -p %{SOURCE11} ntp2chrony.py
%build %build
%configure \ %configure \
%{?with_debug: --enable-debug} \ %{?with_debug: --enable-debug} \
--enable-ntp-signd \ --enable-ntp-signd \
%{?with_seccomp: --enable-scfilter} \ --enable-scfilter \
%{!?with_nts: --disable-nts} \ %{!?with_nts: --disable-nts} \
--chronyrundir=/run/chrony \ --chronyrundir=/run/chrony \
--docdir=%{_docdir} \ --docdir=%{_docdir} \
@ -127,49 +124,48 @@ mv clknetsim-*-%{clknetsim_ver}* test/simulation/clknetsim
--with-user=chrony \ --with-user=chrony \
--with-hwclockfile=%{_sysconfdir}/adjtime \ --with-hwclockfile=%{_sysconfdir}/adjtime \
--with-pidfile=/run/chrony/chronyd.pid \ --with-pidfile=/run/chrony/chronyd.pid \
--with-sendmail=%{_sbindir}/sendmail \ --with-sendmail=%{_sbindir}/sendmail
--without-nettle make %{?_smp_mflags}
%make_build
%install %install
%make_install make install DESTDIR=$RPM_BUILD_ROOT
rm -rf $RPM_BUILD_ROOT%{_docdir} rm -rf $RPM_BUILD_ROOT%{_docdir}
mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/{sysconfig,logrotate.d} mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/{sysconfig,logrotate.d}
mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/{lib,log}/chrony mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/{lib,log}/chrony
mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/NetworkManager/dispatcher.d
mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/dhcp/dhclient.d mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/dhcp/dhclient.d
mkdir -p $RPM_BUILD_ROOT%{_libexecdir} mkdir -p $RPM_BUILD_ROOT%{_libexecdir}
mkdir -p $RPM_BUILD_ROOT%{_sysusersdir}
mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/NetworkManager/dispatcher.d
mkdir -p $RPM_BUILD_ROOT{%{_unitdir},%{_prefix}/lib/systemd/ntp-units.d} mkdir -p $RPM_BUILD_ROOT{%{_unitdir},%{_prefix}/lib/systemd/ntp-units.d}
install -m 644 -p chrony.conf $RPM_BUILD_ROOT%{_sysconfdir}/chrony.conf install -m 644 -p chrony.conf $RPM_BUILD_ROOT%{_sysconfdir}/chrony.conf
install -m 755 -p %{SOURCE3} \ install -m 640 -p examples/chrony.keys.example \
$RPM_BUILD_ROOT%{_sysconfdir}/chrony.keys
install -m 755 -p examples/chrony.nm-dispatcher.onoffline \
$RPM_BUILD_ROOT%{_sysconfdir}/NetworkManager/dispatcher.d/20-chrony-onoffline
install -m 755 -p examples/chrony.nm-dispatcher.dhcp \
$RPM_BUILD_ROOT%{_sysconfdir}/NetworkManager/dispatcher.d/20-chrony-dhcp
install -m 755 -p %{SOURCE1} \
$RPM_BUILD_ROOT%{_sysconfdir}/dhcp/dhclient.d/chrony.sh $RPM_BUILD_ROOT%{_sysconfdir}/dhcp/dhclient.d/chrony.sh
install -m 644 -p examples/chrony.logrotate \ install -m 644 -p examples/chrony.logrotate \
$RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/chrony $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/chrony
install -m 644 -p examples/chronyd.service \ install -m 644 -p examples/chronyd.service \
$RPM_BUILD_ROOT%{_unitdir}/chronyd.service $RPM_BUILD_ROOT%{_unitdir}/chronyd.service
install -m 644 -p examples/chronyd-restricted.service \
$RPM_BUILD_ROOT%{_unitdir}/chronyd-restricted.service
install -m 755 -p examples/chrony.nm-dispatcher.onoffline \
$RPM_BUILD_ROOT%{_prefix}/lib/NetworkManager/dispatcher.d/20-chrony-onoffline
install -m 755 -p examples/chrony.nm-dispatcher.dhcp \
$RPM_BUILD_ROOT%{_prefix}/lib/NetworkManager/dispatcher.d/20-chrony-dhcp
install -m 644 -p examples/chrony-wait.service \ install -m 644 -p examples/chrony-wait.service \
$RPM_BUILD_ROOT%{_unitdir}/chrony-wait.service $RPM_BUILD_ROOT%{_unitdir}/chrony-wait.service
install -m 644 -p %{SOURCE4} \ install -m 644 -p %{SOURCE3} $RPM_BUILD_ROOT%{_unitdir}/chrony-dnssrv@.service
$RPM_BUILD_ROOT%{_sysusersdir}/chrony.conf install -m 644 -p %{SOURCE4} $RPM_BUILD_ROOT%{_unitdir}/chrony-dnssrv@.timer
install -m 755 -p %{SOURCE2} $RPM_BUILD_ROOT%{_libexecdir}/chrony-helper
cat > $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/chronyd <<EOF cat > $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/chronyd <<EOF
# Command-line options for chronyd # Command-line options for chronyd
OPTIONS="%{?with_seccomp:-F 2}" OPTIONS=""
EOF EOF
touch $RPM_BUILD_ROOT%{_sysconfdir}/chrony.keys
touch $RPM_BUILD_ROOT%{_localstatedir}/lib/chrony/{drift,rtc} touch $RPM_BUILD_ROOT%{_localstatedir}/lib/chrony/{drift,rtc}
echo 'chronyd.service' > \ echo 'chronyd.service' > \
@ -177,47 +173,51 @@ echo 'chronyd.service' > \
%check %check
# set random seed to get deterministic results # set random seed to get deterministic results
export CLKNETSIM_RANDOM_SEED=24508 export CLKNETSIM_RANDOM_SEED=24502
%make_build -C test/simulation/clknetsim make %{?_smp_mflags} -C test/simulation/clknetsim
make quickcheck make quickcheck
%pre %pre
%sysusers_create_compat %{SOURCE4} getent group chrony > /dev/null || /usr/sbin/groupadd -r chrony
getent passwd chrony > /dev/null || /usr/sbin/useradd -r -g chrony \
-d %{_localstatedir}/lib/chrony -s /sbin/nologin chrony
:
%post %post
# migrate from chrony-helper to sourcedir directive # fix PIDFile in local chronyd.service on upgrades from chrony < 3.3-2
if test -a %{_libexecdir}/chrony-helper; then if grep -q 'PIDFile=%{_localstatedir}/run/chronyd.pid' \
grep -qi 'sourcedir /run/chrony-dhcp$' %{_sysconfdir}/chrony.conf 2> /dev/null || \ %{_sysconfdir}/systemd/system/chronyd.service 2> /dev/null && \
echo -e '\n# Use NTP servers from DHCP.\nsourcedir /run/chrony-dhcp' >> \ ! grep -qi '^[ '$'\t'']*pidfile' %{_sysconfdir}/chrony.conf 2> /dev/null
%{_sysconfdir}/chrony.conf then
mkdir -p /run/chrony-dhcp sed -i '/PIDFile=/s|/run/|/run/chrony/|' \
for f in %{_localstatedir}/lib/dhclient/chrony.servers.*; do %{_sysconfdir}/systemd/system/chronyd.service
sed 's|.*|server &|' < $f > /run/chrony-dhcp/"${f##*servers.}.sources"
done 2> /dev/null
fi fi
%systemd_post chronyd.service chronyd-restricted.service chrony-wait.service # workaround for late reload of unit file (#1614751)
%{_bindir}/systemctl daemon-reload
%systemd_post chronyd.service chrony-wait.service
%preun %preun
%systemd_preun chronyd.service chronyd-restricted.service chrony-wait.service %systemd_preun chronyd.service chrony-wait.service
%postun %postun
%systemd_postun_with_restart chronyd.service chronyd-restricted.service %systemd_postun_with_restart chronyd.service
%files %files
%{!?_licensedir:%global license %%doc} %{!?_licensedir:%global license %%doc}
%license COPYING %license COPYING
%doc FAQ NEWS README examples/chrony.keys.example %doc FAQ NEWS README ntp2chrony.py
%config(noreplace) %{_sysconfdir}/chrony.conf %config(noreplace) %{_sysconfdir}/chrony.conf
%ghost %config %attr(640,root,chrony) %{_sysconfdir}/chrony.keys %config(noreplace) %verify(not md5 size mtime) %attr(640,root,chrony) %{_sysconfdir}/chrony.keys
%config(noreplace) %{_sysconfdir}/logrotate.d/chrony %config(noreplace) %{_sysconfdir}/logrotate.d/chrony
%config(noreplace) %{_sysconfdir}/sysconfig/chronyd %config(noreplace) %{_sysconfdir}/sysconfig/chronyd
%{_sysconfdir}/NetworkManager/dispatcher.d/20-chrony*
%{_sysconfdir}/dhcp/dhclient.d/chrony.sh %{_sysconfdir}/dhcp/dhclient.d/chrony.sh
%{_bindir}/chronyc %{_bindir}/chronyc
%{_sbindir}/chronyd %{_sbindir}/chronyd
%{_prefix}/lib/NetworkManager %{_libexecdir}/chrony-helper
%{_prefix}/lib/systemd/ntp-units.d/*.list %{_prefix}/lib/systemd/ntp-units.d/*.list
%{_unitdir}/chrony*.service %{_unitdir}/chrony*.service
%{_sysusersdir}/chrony.conf %{_unitdir}/chrony*.timer
%{_mandir}/man[158]/%{name}*.[158]* %{_mandir}/man[158]/%{name}*.[158]*
%dir %attr(750,chrony,chrony) %{_localstatedir}/lib/chrony %dir %attr(750,chrony,chrony) %{_localstatedir}/lib/chrony
%ghost %attr(-,chrony,chrony) %{_localstatedir}/lib/chrony/drift %ghost %attr(-,chrony,chrony) %{_localstatedir}/lib/chrony/drift
@ -225,228 +225,49 @@ fi
%dir %attr(750,chrony,chrony) %{_localstatedir}/log/chrony %dir %attr(750,chrony,chrony) %{_localstatedir}/log/chrony
%changelog %changelog
* Wed Jun 04 2025 Miroslav Lichvar <mlichvar@redhat.com> 4.6.1-2 * Wed Sep 18 2024 Miroslav Lichvar <mlichvar@redhat.com> 4.5-2.el8_10
- improve description of refresh directive (RHEL-91788) - fix crash on reload command during start (RHEL-59112)
- improve logging of selection failures (RHEL-91787 RHEL-91789 RHEL-91791) - enable AES-CMAC support using gnutls (RHEL-59032)
- fix sourcedir reloading to not multiply sources (RHEL-95017)
* Wed Nov 06 2024 Miroslav Lichvar <mlichvar@redhat.com> 4.6.1-1 * Wed Jan 10 2024 Miroslav Lichvar <mlichvar@redhat.com> 4.5-1
- update to 4.6.1 (RHEL-61876) - update to 4.5 (RHEL-21069 RHEL-10701)
- keep PHC refclock reachable when dropping samples due to high delay
(RHEL-65843)
* Tue Oct 29 2024 Troy Dawson <tdawson@redhat.com> - 4.6-2 * Thu Jul 14 2022 Miroslav Lichvar <mlichvar@redhat.com> 4.2-1
- Bump release for October 2024 mass rebuild: - update to 4.2 (#2062356)
Resolves: RHEL-64018 - fix chrony-helper to delete sources by their original name (#2061660)
- update ntp2chrony script (#2018045 #2063766)
* Tue Sep 03 2024 Miroslav Lichvar <mlichvar@redhat.com> 4.6-1 * Tue Jun 15 2021 Miroslav Lichvar <mlichvar@redhat.com> 4.1-1
- update to 4.6 (RHEL-55735) - update to 4.1 (#1895003 #1847853 #1929157)
- add NetworkManager dispatcher script to add servers from DHCP even without
* Tue Jul 02 2024 Miroslav Lichvar <mlichvar@redhat.com> 4.5-6 dhclient (#1933139)
- fix gnutls build requirement - restrict permissions of /var/lib/chrony and /var/log/chrony (#1939295)
- fix crash on reload command during start (RHEL-45854) - reset chrony-helper state after stopping chronyd (#1971697)
- add gcc-c++ and make to build requirements
* Mon Jun 24 2024 Troy Dawson <tdawson@redhat.com> - 4.5-5
- Bump release for June 2024 mass rebuild
* Tue May 28 2024 Miroslav Lichvar <mlichvar@redhat.com> 4.5-4
- disable nettle support in favor of gnutls (RHEL-38924)
* Tue Jan 23 2024 Fedora Release Engineering <releng@fedoraproject.org> - 4.5-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* Fri Jan 19 2024 Fedora Release Engineering <releng@fedoraproject.org> - 4.5-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* Tue Dec 05 2023 Miroslav Lichvar <mlichvar@redhat.com> 4.5-1
- update to 4.5
* Wed Nov 22 2023 Miroslav Lichvar <mlichvar@redhat.com> 4.5-0.1.pre1
- update to 4.5-pre1
* Wed Aug 09 2023 Miroslav Lichvar <mlichvar@redhat.com> 4.4-1
- update to 4.4
- require tzdata (#2218368)
* Wed Jul 19 2023 Fedora Release Engineering <releng@fedoraproject.org> - 4.4-0.4.pre2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
* Wed Jun 21 2023 Miroslav Lichvar <mlichvar@redhat.com> 4.4-0.3.pre2
- update to 4.4-pre2
- set selinux context in chronyd-restricted service (#2169949)
* Tue Jun 06 2023 Miroslav Lichvar <mlichvar@redhat.com> 4.4-0.2.pre1
- rebuild for AES-GCM-SIV in new nettle
* Wed May 10 2023 Miroslav Lichvar <mlichvar@redhat.com> 4.4-0.1.pre1
- update to 4.4-pre1
- switch from patchX to patch -P X
* Wed Jan 25 2023 Miroslav Lichvar <mlichvar@redhat.com> 4.3-3
- drop default chrony.keys config (#2104918)
- add chronyd-restricted service for minimal NTP client configurations
- convert license tag to SPDX
* Wed Jan 18 2023 Fedora Release Engineering <releng@fedoraproject.org> - 4.3-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild
* Wed Aug 31 2022 Miroslav Lichvar <mlichvar@redhat.com> 4.3-1
- update to 4.3
* Thu Aug 11 2022 Miroslav Lichvar <mlichvar@redhat.com> 4.3-0.1.pre1
- update to 4.3-pre1
* Wed Jul 20 2022 Fedora Release Engineering <releng@fedoraproject.org> - 4.2-7
- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild
* Tue May 24 2022 Luca BRUNO <lucab@lucabruno.net> - 4.2-6
- Add a sysusers.d fragment for chrony user/group
* Wed Feb 16 2022 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> - 4.2-5
- Drop obsolete workaround in scriptlet
* Wed Feb 09 2022 Miroslav Lichvar <mlichvar@redhat.com> 4.2-4
- update seccomp filter for latest glibc
* Tue Feb 08 2022 Miroslav Lichvar <mlichvar@redhat.com> 4.2-3
- use NTP servers passed by NetworkManager from DHCPv6 NTP server option
* Wed Jan 19 2022 Fedora Release Engineering <releng@fedoraproject.org> - 4.2-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild
* Thu Dec 16 2021 Miroslav Lichvar <mlichvar@redhat.com> 4.2-1
- update to 4.2
* Thu Dec 02 2021 Miroslav Lichvar <mlichvar@redhat.com> 4.2-0.1.pre1
- update to 4.2-pre1
* Tue Nov 16 2021 Miroslav Lichvar <mlichvar@redhat.com> 4.1-5
- fix hardened chronyd service to allow writing log files
* Wed Sep 29 2021 Miroslav Lichvar <mlichvar@redhat.com> 4.1-4
- harden chronyd and chrony-wait services
* Mon Aug 09 2021 Miroslav Lichvar <mlichvar@redhat.com> 4.1-3
- update seccomp filter for new glibc
- remove unnecessary build requirement
* Wed Jul 21 2021 Fedora Release Engineering <releng@fedoraproject.org> - 4.1-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild
* Thu May 13 2021 Miroslav Lichvar <mlichvar@redhat.com> 4.1-1
- update to 4.1
- enable seccomp filter by default (incompatible with mailonchange directive)
* Thu Apr 22 2021 Miroslav Lichvar <mlichvar@redhat.com> 4.1-0.1.pre1
- update to 4.1-pre1
- rework NM-dispatcher/dhclient detection
- enable LTO on s390x
* Tue Mar 02 2021 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> - 4.0-4
- Rebuilt for updated systemd-rpm-macros
See https://pagure.io/fesco/issue/2583.
* Tue Feb 02 2021 Miroslav Lichvar <mlichvar@redhat.com> 4.0-3
- update NM DHCP dispatcher script
* Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 4.0-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
- Add BuildRequires: make
- drop dnssrv service and timer
* Wed Oct 07 2020 Miroslav Lichvar <mlichvar@redhat.com> 4.0-1
- update to 4.0
- update directory permissions to follow upstream
* Wed Sep 16 2020 Miroslav Lichvar <mlichvar@redhat.com> 4.0-0.9.pre4
- update to 4.0-pre4
* Wed Aug 26 2020 Miroslav Lichvar <mlichvar@redhat.com> 4.0-0.8.pre3
- update to 4.0-pre3
- switch to sourcedir directive for loading servers from DHCP
- add NetworkManager dispatcher script to save servers from DHCP when
dhclient is not installed (Robert Fairley)
- drop old migration code from scriptlet
- move default paths in /var/run to /run - move default paths in /var/run to /run
* Mon Aug 10 2020 Jeff Law <law@redhat.com> - 4.0-0.7.pre2 * Tue May 21 2019 Miroslav Lichvar <mlichvar@redhat.com> 3.5-1
- Disable LTO on s390x - update to 3.5 (#1685469 #1677218)
- fix shellcheck warnings in helper scripts (#1711948)
- update ntp2chrony script
* Sat Aug 01 2020 Fedora Release Engineering <releng@fedoraproject.org> - 4.0-0.6.pre2 * Mon Aug 13 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-3
- Second attempt - Rebuilt for
https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Mon Jul 27 2020 Fedora Release Engineering <releng@fedoraproject.org> - 4.0-0.5.pre2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Mon Jul 13 2020 Tom Stellard <tstellar@redhat.com> 4.0-0.4.pre2
- use make macros
* Mon May 04 2020 Miroslav Lichvar <mlichvar@redhat.com> 4.0-0.3.pre2
- rebuild for new nettle
* Mon Apr 20 2020 Miroslav Lichvar <mlichvar@redhat.com> 4.0-0.2.pre2
- update to 4.0-pre2
* Tue Mar 17 2020 Miroslav Lichvar <mlichvar@redhat.com> 4.0-0.1.pre1
- update to 4.0-pre1
- add net-tools to build requirements for testing
- add missing dependency on coreutils
* Tue Jan 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 3.5-8
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
* Mon Jan 20 2020 Miroslav Lichvar <mlichvar@redhat.com> 3.5-7
- fix testing with new glibc (#1792854)
* Wed Oct 09 2019 Miroslav Lichvar <mlichvar@redhat.com> 3.5-6
- drop timedatex recommendation
- verify upstream signatures
* Thu Aug 22 2019 Lubomir Rintel <lkundrak@v3.sk> - 3.5-5
- Move the NetworkManager dispatcher script out of /etc
* Wed Jul 24 2019 Fedora Release Engineering <releng@fedoraproject.org> - 3.5-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
* Tue Jul 16 2019 Miroslav Lichvar <mlichvar@redhat.com> 3.5-3
- rebuild for new nettle
* Thu May 23 2019 Miroslav Lichvar <mlichvar@redhat.com> 3.5-2
- fix shellcheck warnings in helper scripts
* Tue May 14 2019 Miroslav Lichvar <mlichvar@redhat.com> 3.5-1
- update to 3.5
* Thu May 02 2019 Miroslav Lichvar <mlichvar@redhat.com> 3.5-0.1.pre1
- update to 3.5-pre1
* Thu Jan 31 2019 Fedora Release Engineering <releng@fedoraproject.org> - 3.4-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
* Wed Sep 19 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.4-1
- update to 3.4
* Fri Aug 31 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.4-0.1.pre1
- update to 3.4-pre1
* Mon Aug 13 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-5
- fix PIDFile in local chronyd.service on upgrades from chrony < 3.3-2 - fix PIDFile in local chronyd.service on upgrades from chrony < 3.3-2
(#1614800)
- add workaround for late reload of unit file (#1614751) - add workaround for late reload of unit file (#1614751)
* Mon Jul 16 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-4
- add gcc-c++ to build requirements
* Thu Jul 12 2018 Fedora Release Engineering <releng@fedoraproject.org> - 3.3-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
* Mon Jun 18 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-2 * Mon Jun 18 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-2
- move pidfile to /var/run/chrony to allow chronyd to remove it on exit - move pidfile to /var/run/chrony to allow chronyd to remove it on exit
- avoid blocking in getrandom system call (#1584585)
- avoid blocking in getrandom system call (#1592425)
* Wed Apr 04 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-1 * Thu Apr 05 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-1
- update to 3.3 - update to 3.3
- enable keyfile by default again - enable keyfile by default again
- update ntp2chrony script
* Mon Mar 19 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-0.2.pre1
- include ntp2chrony script in documentation (#1530987)
* Thu Mar 15 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-0.1.pre1 * Thu Mar 15 2018 Miroslav Lichvar <mlichvar@redhat.com> 3.3-0.1.pre1
- update to 3.3-pre1 - update to 3.3-pre1

View File

@ -1,55 +0,0 @@
commit b889627998ba584528d1c1145a212fb2b97e5289
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Thu Feb 27 10:04:41 2025 +0100
doc: improve description of refresh directive
diff --git a/doc/chrony.conf.adoc b/doc/chrony.conf.adoc
index 7ccdd20c..eb00e029 100644
--- a/doc/chrony.conf.adoc
+++ b/doc/chrony.conf.adoc
@@ -941,14 +941,15 @@ time, assuming the first update corrects the clock and later checks can work
with correct time.
[[refresh]]*refresh* _interval_::
-This directive specifies the interval (in seconds) between refreshing IP
-addresses of NTP sources specified by hostname. If the hostname no longer
+This directive specifies the minimum interval (in seconds) between refreshing
+IP addresses of NTP sources specified by hostname. If the hostname no longer
resolves to the currently used address, it will be replaced with one of the new
addresses to avoid using a server which is no longer intended for service, even
if it is still responding correctly and would not be replaced as unreachable.
-Only one source is refreshed at a time. The default value is 1209600 (2 weeks)
-and the maximum value is 2^31-1 (68 years). A value of 0 disables the periodic
-refreshment.
+Only one source is refreshed at a time and only when a valid response is
+received (unreachable sources are replaced independently). The default value is
+1209600 (2 weeks) and the maximum value is 2^31-1 (68 years). A value of 0
+disables the periodic refreshment.
+
The <<chronyc.adoc#refresh,*refresh*>> command can be used to refresh all
sources immediately.
diff -up chrony-4.6.1/doc/chrony.conf.man.in.docrefresh chrony-4.6.1/doc/chrony.conf.man.in
--- chrony-4.6.1/doc/chrony.conf.man.in.docrefresh 2025-05-15 17:04:33.824077026 +0200
+++ chrony-4.6.1/doc/chrony.conf.man.in 2025-05-15 17:04:53.308070453 +0200
@@ -1270,14 +1270,15 @@ with correct time.
.sp
\fBrefresh\fP \fIinterval\fP
.RS 4
-This directive specifies the interval (in seconds) between refreshing IP
-addresses of NTP sources specified by hostname. If the hostname no longer
+This directive specifies the minimum interval (in seconds) between refreshing
+IP addresses of NTP sources specified by hostname. If the hostname no longer
resolves to the currently used address, it will be replaced with one of the new
addresses to avoid using a server which is no longer intended for service, even
if it is still responding correctly and would not be replaced as unreachable.
-Only one source is refreshed at a time. The default value is 1209600 (2 weeks)
-and the maximum value is 2^31\-1 (68 years). A value of 0 disables the periodic
-refreshment.
+Only one source is refreshed at a time and only when a valid response is
+received (unreachable sources are replaced independently). The default value is
+1209600 (2 weeks) and the maximum value is 2^31\-1 (68 years). A value of 0
+disables the periodic refreshment.
.sp
The \fBrefresh\fP command can be used to refresh all
sources immediately.

View File

@ -1,612 +0,0 @@
commit 620210218c4d2e9634035b3c3d01b0a329708111
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Mon Mar 3 15:48:37 2025 +0100
sources: refactor logging of source-specific selection status
Move logging of falsetickers and system peers to the mark_source()
function. Use an array to flag already logged messages in preparation
for logging of other status. Support variable number of arguments in the
logging functions.
diff --git a/sources.c b/sources.c
index e292e4d6..bfb1c45b 100644
--- a/sources.c
+++ b/sources.c
@@ -66,7 +66,7 @@ struct SelectInfo {
/* This enum contains the flag values that are used to label
each source */
typedef enum {
- SRC_OK, /* OK so far, not a final status! */
+ SRC_OK = 0, /* OK so far, not a final status! */
SRC_UNSELECTABLE, /* Has noselect option set */
SRC_BAD_STATS, /* Doesn't have valid stats data */
SRC_UNSYNCHRONISED, /* Provides samples, but not synchronised */
@@ -144,9 +144,9 @@ struct SRC_Instance_Record {
/* Flag indicating the source has a leap second vote */
int leap_vote;
- /* Flag indicating the source was already reported as
- a falseticker since the last selection change */
- int reported_falseticker;
+ /* Flags indicating which status was already reported for
+ the source since the last change of the system peer */
+ char reported_status[SRC_SELECTED + 1];
};
/* ================================================== */
@@ -360,8 +360,8 @@ SRC_ResetInstance(SRC_Instance instance)
instance->stratum = 0;
instance->leap = LEAP_Unsynchronised;
instance->leap_vote = 0;
- instance->reported_falseticker = 0;
+ memset(instance->reported_status, 0, sizeof (instance->reported_status));
memset(&instance->sel_info, 0, sizeof (instance->sel_info));
SST_ResetInstance(instance->stats);
@@ -620,20 +620,45 @@ update_sel_options(void)
/* ================================================== */
+FORMAT_ATTRIBUTE_PRINTF(2, 3)
static void
-log_selection_message(LOG_Severity severity, const char *format, const char *arg)
+log_selection_message(LOG_Severity severity, const char *format, ...)
{
+ char buf[256];
+ va_list ap;
+
if (REF_GetMode() != REF_ModeNormal)
return;
- LOG(severity, format, arg);
+
+ va_start(ap, format);
+ vsnprintf(buf, sizeof (buf), format, ap);
+ va_end(ap);
+
+ LOG(severity, "%s", buf);
}
/* ================================================== */
+FORMAT_ATTRIBUTE_PRINTF(3, 4)
static void
-log_selection_source(LOG_Severity severity, const char *format, SRC_Instance inst)
+log_selection_source(LOG_Severity severity, SRC_Instance inst, const char *format, ...)
{
- char buf[320], *name, *ntp_name;
+ char buf[320], buf2[256], *name, *ntp_name, *s;
+ va_list ap;
+
+ if (REF_GetMode() != REF_ModeNormal)
+ return;
+
+ va_start(ap, format);
+ vsnprintf(buf2, sizeof (buf2), format, ap);
+ va_end(ap);
+
+ /* Replace ## with %s in the formatted string to be the source name */
+ s = strstr(buf2, "##");
+ if (!s || strchr(buf2, '%'))
+ return;
+ s[0] = '%';
+ s[1] = 's';
name = source_to_string(inst);
ntp_name = inst->type == SRC_NTP ? NSR_GetName(inst->ip_addr) : NULL;
@@ -643,7 +668,9 @@ log_selection_source(LOG_Severity severity, const char *format, SRC_Instance ins
else
snprintf(buf, sizeof (buf), "%s", name);
- log_selection_message(severity, format, buf);
+ LOG(severity, buf2, buf);
+
+ inst->reported_status[inst->status] = 1;
}
/* ================================================== */
@@ -686,7 +713,7 @@ source_to_string(SRC_Instance inst)
/* ================================================== */
static void
-mark_source(SRC_Instance inst, SRC_Status status)
+set_source_status(SRC_Instance inst, SRC_Status status)
{
struct timespec now;
@@ -731,6 +758,30 @@ mark_source(SRC_Instance inst, SRC_Status status)
/* ================================================== */
+static void
+mark_source(SRC_Instance inst, SRC_Status status)
+{
+ set_source_status(inst, status);
+
+ if (status < SRC_OK || status >= sizeof (inst->reported_status))
+ assert(0);
+
+ if (!inst->reported_status[status]) {
+ switch (status) {
+ case SRC_FALSETICKER:
+ log_selection_source(LOGS_WARN, inst, "Detected falseticker ##");
+ break;
+ case SRC_SELECTED:
+ log_selection_source(LOGS_INFO, inst, "Selected source ##");
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/* ================================================== */
+
static void
mark_ok_sources(SRC_Status status)
{
@@ -739,7 +790,8 @@ mark_ok_sources(SRC_Status status)
for (i = 0; i < n_sources; i++) {
if (sources[i]->status != SRC_OK)
continue;
- mark_source(sources[i], status);
+ /* Don't log the status in this case (multiple sources at once) */
+ set_source_status(sources[i], status);
}
}
@@ -1161,7 +1213,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
/* Could not even get half the reachable (trusted) sources to agree */
if (!reported_no_majority) {
- log_selection_message(LOGS_WARN, "Can't synchronise: no majority", NULL);
+ log_selection_message(LOGS_WARN, "Can't synchronise: no majority");
reported_no_majority = 1;
report_selection_loss = 0;
}
@@ -1212,10 +1264,6 @@ SRC_SelectSource(SRC_Instance updated_inst)
sel_req_source = 0;
} else {
mark_source(sources[i], SRC_FALSETICKER);
- if (!sources[i]->reported_falseticker) {
- log_selection_source(LOGS_WARN, "Detected falseticker %s", sources[i]);
- sources[i]->reported_falseticker = 1;
- }
}
}
@@ -1335,13 +1383,12 @@ SRC_SelectSource(SRC_Instance updated_inst)
}
selected_source_index = max_score_index;
- log_selection_source(LOGS_INFO, "Selected source %s", sources[selected_source_index]);
/* New source has been selected, reset all scores */
for (i = 0; i < n_sources; i++) {
sources[i]->sel_score = 1.0;
sources[i]->distant = 0;
- sources[i]->reported_falseticker = 0;
+ memset(sources[i]->reported_status, 0, sizeof (sources[i]->reported_status));
}
reported_no_majority = 0;
commit 52237b7d0da75fcd750c5d5ee80e87b97474f7fd
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Wed Mar 5 10:45:20 2025 +0100
sources: warn about sources exceeding maxdistance or maxjitter
Log a warning message if a source is rejected in the source selecting
due to exceeding the maxdistance or maxjitter limit to make it more
obvious when synchronization is failing for this reason. Delay the
message until the reachability register is full (8 updates), or a
replacement of the source is attempted.
diff --git a/sources.c b/sources.c
index bfb1c45b..2ba595b5 100644
--- a/sources.c
+++ b/sources.c
@@ -768,6 +768,20 @@ mark_source(SRC_Instance inst, SRC_Status status)
if (!inst->reported_status[status]) {
switch (status) {
+ case SRC_BAD_DISTANCE:
+ if (inst->reachability_size < SOURCE_REACH_BITS && inst->bad < BAD_HANDLE_THRESHOLD)
+ break;
+ log_selection_source(LOGS_WARN, inst,
+ "Root distance of ## exceeds maxdistance of %.3f seconds",
+ max_distance);
+ break;
+ case SRC_JITTERY:
+ if (inst->reachability_size < SOURCE_REACH_BITS && inst->bad < BAD_HANDLE_THRESHOLD)
+ break;
+ log_selection_source(LOGS_WARN, inst,
+ "Jitter of ## exceeds maxjitter of %.3f seconds",
+ max_jitter);
+ break;
case SRC_FALSETICKER:
log_selection_source(LOGS_WARN, inst, "Detected falseticker ##");
break;
commit 1c06925d439d8699cc52df71a7a4e809b5b7348f
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Thu Mar 6 12:46:09 2025 +0100
sources: improve no majority log message
Add the number of sources that form an agreement (overlapping
intervals), if at least two agree with each other, and number of
reachable sources to the "Can't synchronize: no majority" log message to
better explain why synchronization is failing and hint that adding more
sources might help.
diff --git a/sources.c b/sources.c
index 2ba595b5..3b1766be 100644
--- a/sources.c
+++ b/sources.c
@@ -1222,12 +1222,23 @@ SRC_SelectSource(SRC_Instance updated_inst)
assert(depth == 0 && trust_depth == 0);
assert(2 * n_sel_sources == n_endpoints);
- if ((best_trust_depth == 0 && best_depth <= n_sel_sources / 2) ||
- (best_trust_depth > 0 && best_trust_depth <= n_sel_trust_sources / 2)) {
+ if (best_trust_depth > 0) {
+ best_depth = best_trust_depth;
+ n_sel_sources = n_sel_trust_sources;
+ }
+
+ if (best_depth <= n_sel_sources / 2) {
/* Could not even get half the reachable (trusted) sources to agree */
if (!reported_no_majority) {
- log_selection_message(LOGS_WARN, "Can't synchronise: no majority");
+ if (best_depth < 2)
+ log_selection_message(LOGS_WARN, "%s (no agreement among %d %ssources)",
+ "Can't synchronise: no majority", n_sel_sources,
+ best_trust_depth > 0 ? "trusted " : "");
+ else
+ log_selection_message(LOGS_WARN, "%s (only %d of %d %ssources agree)",
+ "Can't synchronise: no majority", best_depth,
+ n_sel_sources, best_trust_depth > 0 ? "trusted " : "");
reported_no_majority = 1;
report_selection_loss = 0;
}
diff --git a/test/simulation/009-sourceselection b/test/simulation/009-sourceselection
index 547c376c..139b6aa2 100755
--- a/test/simulation/009-sourceselection
+++ b/test/simulation/009-sourceselection
@@ -24,6 +24,12 @@ for falsetickers in 3 4; do
# These check are expected to fail
check_source_selection && test_fail
check_sync && test_fail
+
+ if [ $falsetickers = 3 ]; then
+ check_log_messages "Can't synchronise: no majority (only 2 of 5 sources agree)" 1 1 || test_fail
+ else
+ check_log_messages "Can't synchronise: no majority (no agreement among 5 sources)" 1 1 || test_fail
+ fi
done
# Sources with large asymmetric delay should be excluded
diff --git a/test/simulation/148-replacement b/test/simulation/148-replacement
index d09fba6e..ee8b2e23 100755
--- a/test/simulation/148-replacement
+++ b/test/simulation/148-replacement
@@ -68,7 +68,7 @@ check_source_selection && test_fail
check_packet_interval || test_fail
check_sync || test_fail
-check_log_messages "Can't synchronise: no majority" 1 1 || test_fail
+check_log_messages "Can't synchronise: no majority (no agreement among 2 sources)" 1 1 || test_fail
check_log_messages "Detected falseticker" 0 2 || test_fail
check_log_messages "Source 192.168.123.. replaced with" 3 60 || test_fail
check_log_messages "Source 192.168.123.1 replaced with" 1 25 || test_fail
commit 2fc7fc2e227f85dcde0953d47e1815432a4a2bf7
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Wed Mar 12 15:21:18 2025 +0100
sources: delay maxjitter/maxdistance warning messages
Avoid logging the new warning messages about exceeded maxjitter or
maxdistance when only a small number of samples is collected after the
source becomes reachable and the values are unstable. Log the messages
only when a replacement attempt is made.
diff --git a/sources.c b/sources.c
index 3b1766be..c8d96af4 100644
--- a/sources.c
+++ b/sources.c
@@ -769,14 +769,14 @@ mark_source(SRC_Instance inst, SRC_Status status)
if (!inst->reported_status[status]) {
switch (status) {
case SRC_BAD_DISTANCE:
- if (inst->reachability_size < SOURCE_REACH_BITS && inst->bad < BAD_HANDLE_THRESHOLD)
+ if (inst->bad < BAD_HANDLE_THRESHOLD)
break;
log_selection_source(LOGS_WARN, inst,
"Root distance of ## exceeds maxdistance of %.3f seconds",
max_distance);
break;
case SRC_JITTERY:
- if (inst->reachability_size < SOURCE_REACH_BITS && inst->bad < BAD_HANDLE_THRESHOLD)
+ if (inst->bad < BAD_HANDLE_THRESHOLD)
break;
log_selection_source(LOGS_WARN, inst,
"Jitter of ## exceeds maxjitter of %.3f seconds",
commit 0c7e72304aac05020cbaeb4ccab73ce0c441e1ca
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Thu Mar 13 15:40:47 2025 +0100
sources: switch unselect_selected_source() to variable arguments
Switch the function to the full printf style, which will be needed to
log an integer.
diff --git a/sources.c b/sources.c
index c8d96af4..b43ef8dc 100644
--- a/sources.c
+++ b/sources.c
@@ -206,8 +206,7 @@ static LOG_FileID logfileid;
/* Forward prototype */
static void update_sel_options(void);
-static void unselect_selected_source(LOG_Severity severity, const char *format,
- const char *arg);
+static void unselect_selected_source(LOG_Severity severity, const char *format, ...);
static void slew_sources(struct timespec *raw, struct timespec *cooked, double dfreq,
double doffset, LCL_ChangeType change_type, void *anything);
static void add_dispersion(double dispersion, void *anything);
@@ -340,7 +339,7 @@ void SRC_DestroyInstance(SRC_Instance instance)
if (selected_source_index > dead_index)
--selected_source_index;
else if (selected_source_index == dead_index)
- unselect_selected_source(LOGS_INFO, NULL, NULL);
+ unselect_selected_source(LOGS_INFO, NULL);
SRC_SelectSource(NULL);
}
@@ -815,16 +814,24 @@ mark_ok_sources(SRC_Status status)
call providing a message or selection of another source, which resets the
report_selection_loss flag. */
+FORMAT_ATTRIBUTE_PRINTF(2, 3)
static void
-unselect_selected_source(LOG_Severity severity, const char *format, const char *arg)
+unselect_selected_source(LOG_Severity severity, const char *format, ...)
{
+ char buf[256];
+ va_list ap;
+
if (selected_source_index != INVALID_SOURCE) {
selected_source_index = INVALID_SOURCE;
report_selection_loss = 1;
}
if (report_selection_loss && format) {
- log_selection_message(severity, format, arg);
+ va_start(ap, format);
+ vsnprintf(buf, sizeof (buf), format, ap);
+ va_end(ap);
+
+ log_selection_message(severity, "%s", buf);
report_selection_loss = 0;
}
}
@@ -947,7 +954,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
}
if (n_sources == 0) {
- unselect_selected_source(LOGS_INFO, "Can't synchronise: no sources", NULL);
+ unselect_selected_source(LOGS_INFO, "Can't synchronise: no sources");
return;
}
@@ -1134,7 +1141,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
if (n_badstats_sources && n_sel_sources && selected_source_index == INVALID_SOURCE &&
max_sel_reach_size < SOURCE_REACH_BITS && max_sel_reach >> 1 == max_badstat_reach) {
mark_ok_sources(SRC_WAITS_STATS);
- unselect_selected_source(LOGS_INFO, NULL, NULL);
+ unselect_selected_source(LOGS_INFO, NULL);
return;
}
@@ -1148,7 +1155,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
if (n_endpoints == 0) {
/* No sources provided valid endpoints */
- unselect_selected_source(LOGS_INFO, "Can't synchronise: no selectable sources", NULL);
+ unselect_selected_source(LOGS_INFO, "Can't synchronise: no selectable sources");
return;
}
@@ -1402,7 +1409,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
/* Before selecting the new synchronisation source wait until the reference
can be updated */
if (sources[max_score_index]->updates == 0) {
- unselect_selected_source(LOGS_INFO, NULL, NULL);
+ unselect_selected_source(LOGS_INFO, NULL);
mark_ok_sources(SRC_WAITS_UPDATE);
return;
}
commit a8094716b0c21a037e3f21d2f3c2e45f14060b07
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Thu Nov 14 13:41:41 2024 +0100
test: add 014-intermittent test
diff --git a/test/simulation/014-intermittent b/test/simulation/014-intermittent
new file mode 100755
index 00000000..2f018ed0
--- /dev/null
+++ b/test/simulation/014-intermittent
@@ -0,0 +1,49 @@
+#!/usr/bin/env bash
+
+. ./test.common
+
+test_start "intermittent connection"
+
+# Pass packets only for 1200 seconds every 10000 seconds
+base_delay=$(cat <<-EOF | tr -d '\n'
+ (+ 1e-4
+ (* -1
+ (equal 0.1 (min (% time 10000) 1200) 1200)))
+EOF
+)
+
+time_max_limit=1e-1
+freq_max_limit=1e-2
+time_rms_limit=2e-3
+freq_rms_limit=2e-5
+limit=100000
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_sync || test_fail
+
+check_log_messages "Can't.*no selectable sources" 9 10 || test_fail
+check_log_messages "Selected source 192.168.123.1" 9 10 || test_fail
+
+# Pass every 20th request
+base_delay=$(cat <<-EOF | tr -d '\n'
+ (+ 1e-4
+ (* -1
+ (equal 0.1 from 2)
+ (equal 0.1 (min (% (sum 1) 20) 1) 1)))
+EOF
+)
+
+time_max_limit=1e-2
+freq_max_limit=1e-4
+time_rms_limit=5e-3
+max_sync_time=22000
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_sync || test_fail
+
+check_log_messages "Can't.*no selectable sources" 5 15 || test_fail
+check_log_messages "Selected source 192.168.123.1" 5 15 || test_fail
+
+test_pass
commit aa3660256a83768aa3fb640f6032780000c7a4fb
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Thu Mar 13 15:55:32 2025 +0100
sources: improve no-selectable-sources log message
Include the number of unreachable sources in the "Can't synchronise: no
selectable sources" log message to provide a hint whether it might be a
networking issue.
diff --git a/sources.c b/sources.c
index b43ef8dc..406c2f86 100644
--- a/sources.c
+++ b/sources.c
@@ -937,7 +937,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
struct timespec now, ref_time;
int i, j, j1, j2, index, sel_prefer, n_endpoints, n_sel_sources, sel_req_source;
int max_badstat_reach, max_badstat_reach_size, n_badstats_sources;
- int max_sel_reach, max_sel_reach_size;
+ int max_sel_reach, max_sel_reach_size, n_unreach_sources;
int depth, best_depth, trust_depth, best_trust_depth, n_sel_trust_sources;
int combined, stratum, min_stratum, max_score_index;
int orphan_stratum, orphan_source;
@@ -966,6 +966,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
n_endpoints = 0;
n_sel_sources = n_sel_trust_sources = 0;
n_badstats_sources = 0;
+ n_unreach_sources = 0;
sel_req_source = 0;
max_sel_reach = max_badstat_reach = 0;
max_sel_reach_size = max_badstat_reach_size = 0;
@@ -988,6 +989,10 @@ SRC_SelectSource(SRC_Instance updated_inst)
continue;
}
+ /* Count unreachable sources for a warning message */
+ if (sources[i]->reachability == 0)
+ n_unreach_sources++;
+
si = &sources[i]->sel_info;
SST_GetSelectionData(sources[i]->stats, &now,
&si->lo_limit, &si->hi_limit, &si->root_distance,
@@ -1155,7 +1160,8 @@ SRC_SelectSource(SRC_Instance updated_inst)
if (n_endpoints == 0) {
/* No sources provided valid endpoints */
- unselect_selected_source(LOGS_INFO, "Can't synchronise: no selectable sources");
+ unselect_selected_source(LOGS_INFO, "Can't synchronise: no selectable sources"
+ " (%d unreachable sources)", n_unreach_sources);
return;
}
diff --git a/test/simulation/014-intermittent b/test/simulation/014-intermittent
index 2f018ed0..4af574b7 100755
--- a/test/simulation/014-intermittent
+++ b/test/simulation/014-intermittent
@@ -22,7 +22,7 @@ run_test || test_fail
check_chronyd_exit || test_fail
check_sync || test_fail
-check_log_messages "Can't.*no selectable sources" 9 10 || test_fail
+check_log_messages "Can't.*no selectable sources (1 unreachable" 9 10 || test_fail
check_log_messages "Selected source 192.168.123.1" 9 10 || test_fail
# Pass every 20th request
@@ -43,7 +43,7 @@ run_test || test_fail
check_chronyd_exit || test_fail
check_sync || test_fail
-check_log_messages "Can't.*no selectable sources" 5 15 || test_fail
+check_log_messages "Can't.*no selectable sources (1 unreachable" 5 15 || test_fail
check_log_messages "Selected source 192.168.123.1" 5 15 || test_fail
test_pass
commit 402d5d9eb5767797e3af150119b63a08adf43813
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Thu Mar 13 16:03:59 2025 +0100
sources: increase severity of can't-synchronise log messages
Switch the info-level "Can't synchronise" selection messages to
warnings.
diff --git a/sources.c b/sources.c
index 406c2f86..cfe7f260 100644
--- a/sources.c
+++ b/sources.c
@@ -954,7 +954,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
}
if (n_sources == 0) {
- unselect_selected_source(LOGS_INFO, "Can't synchronise: no sources");
+ unselect_selected_source(LOGS_WARN, "Can't synchronise: no sources");
return;
}
@@ -1160,7 +1160,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
if (n_endpoints == 0) {
/* No sources provided valid endpoints */
- unselect_selected_source(LOGS_INFO, "Can't synchronise: no selectable sources"
+ unselect_selected_source(LOGS_WARN, "Can't synchronise: no selectable sources"
" (%d unreachable sources)", n_unreach_sources);
return;
}
@@ -1306,7 +1306,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
}
if (!n_sel_sources || sel_req_source || n_sel_sources < CNF_GetMinSources()) {
- unselect_selected_source(LOGS_INFO, "Can't synchronise: %s selectable sources",
+ unselect_selected_source(LOGS_WARN, "Can't synchronise: %s selectable sources",
!n_sel_sources ? "no" :
sel_req_source ? "no required source in" : "not enough");
mark_ok_sources(SRC_WAITS_SOURCES);

View File

@ -1,39 +0,0 @@
From: Robert Fairley <rfairley@redhat.com>
Date: Wed, 17 Jun 2020 10:14:19 -0400
Subject: [PATCH] examples/nm-dispatcher.dhcp: use sysconfig
Use the PEERNTP and NTPSERVERARGS environment variables from
/etc/sysconfig/network{-scripts}.
Co-Authored-By: Christian Glombek <cglombek@redhat.com>
diff --git a/examples/chrony.nm-dispatcher.dhcp b/examples/chrony.nm-dispatcher.dhcp
index 6ea4c37..a6ad35a 100644
--- a/examples/chrony.nm-dispatcher.dhcp
+++ b/examples/chrony.nm-dispatcher.dhcp
@@ -8,15 +8,23 @@ export LC_ALL=C
interface=$1
action=$2
+[ -f /etc/sysconfig/network ] && . /etc/sysconfig/network
+[ -f /etc/sysconfig/network-scripts/ifcfg-"${interface}" ] && \
+ . /etc/sysconfig/network-scripts/ifcfg-"${interface}"
+
chronyc=/usr/bin/chronyc
-server_options=iburst
-server_dir=/var/run/chrony-dhcp
+server_options=${NTPSERVERARGS:-iburst}
+server_dir=/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"
+
+ # Don't add NTP servers if PEERNTP=no specified; return early.
+ [ "$PEERNTP" = "no" ] && return
+
for server in $dhcp_ntp_servers; do
# Check for invalid characters (from the DHCPv6 NTP FQDN suboption)
len1=$(printf '%s' "$server" | wc -c)

View File

@ -1,226 +0,0 @@
commit b9b338a8df23927d8104f41ecb21baa3558de0cd
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Thu Oct 31 14:41:19 2024 +0100
refclock: rework update of reachability
Update the reachability register of a refclock source by 1 if a valid
measurement is received by the drivers between source polls, and not
only when it is accumulated to sourcestats, similarly to how
reachability works with NTP sources.
This avoids drops in the reported reachability when a PHC refclock is
dropping samples due to significant changes in the measured delay (e.g.
due to high PCIe load), or a PPS refclock dropping samples due to failed
lock.
diff --git a/doc/chronyc.adoc b/doc/chronyc.adoc
index 935f1da9..dea93c9f 100644
--- a/doc/chronyc.adoc
+++ b/doc/chronyc.adoc
@@ -364,9 +364,12 @@ a measurement is being made every 64 seconds. *chronyd* automatically varies
the polling rate in response to prevailing conditions.
*Reach*:::
This shows the source's reachability register printed as an octal number. The
-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.
+register has 8 bits. It is shifted to left by one bit with each poll and it is
+updated by 1 when a valid NTP response, or just a sample in case of a reference
+clock, is received from the source. A value of 377 indicates that a valid
+response or sample was received for all of the last 8 polls. Note that samples
+can be dropped if they are not considered good enough for synchronisation, but
+the reachability register will still have 1s for their polls.
*LastRx*:::
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
diff --git a/refclock.c b/refclock.c
index 22d775a5..d14560fa 100644
--- a/refclock.c
+++ b/refclock.c
@@ -63,6 +63,7 @@ struct RCL_Instance_Record {
int driver_poll;
int driver_polled;
int poll;
+ int reached;
int leap_status;
int local;
int pps_forced;
@@ -175,6 +176,7 @@ RCL_AddRefclock(RefclockParameters *params)
inst->driver_poll = params->driver_poll;
inst->poll = params->poll;
inst->driver_polled = 0;
+ inst->reached = 0;
inst->leap_status = LEAP_Normal;
inst->local = params->local;
inst->pps_forced = params->pps_forced;
@@ -665,6 +667,12 @@ RCL_AddCookedPulse(RCL_Instance instance, struct timespec *cooked_time,
return 1;
}
+void
+RCL_UpdateReachability(RCL_Instance instance)
+{
+ instance->reached++;
+}
+
double
RCL_GetPrecision(RCL_Instance instance)
{
@@ -792,6 +800,9 @@ poll_timeout(void *arg)
if (!(inst->driver->poll && inst->driver_polled < (1 << (inst->poll - inst->driver_poll)))) {
inst->driver_polled = 0;
+ SRC_UpdateReachability(inst->source, inst->reached > 0);
+ inst->reached = 0;
+
if (SPF_GetFilteredSample(inst->filter, &sample)) {
double local_freq, local_offset;
struct timespec local_ref_time;
@@ -807,7 +818,6 @@ poll_timeout(void *arg)
inst->leap_status = LEAP_Unsynchronised;
}
- SRC_UpdateReachability(inst->source, 1);
SRC_UpdateStatus(inst->source, stratum, inst->leap_status);
SRC_AccumulateSample(inst->source, &sample);
SRC_SelectSource(inst->source);
@@ -816,8 +826,6 @@ poll_timeout(void *arg)
follow_local(inst, &local_ref_time, local_freq, local_offset);
log_sample(inst, &sample.time, 1, 0, 0.0, sample.offset, sample.peer_dispersion);
- } else {
- SRC_UpdateReachability(inst->source, 0);
}
}
diff --git a/refclock.h b/refclock.h
index 40c852de..5fdbf9c7 100644
--- a/refclock.h
+++ b/refclock.h
@@ -81,6 +81,7 @@ extern int RCL_AddSample(RCL_Instance instance, struct timespec *sample_time,
extern int RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second);
extern int RCL_AddCookedPulse(RCL_Instance instance, struct timespec *cooked_time,
double second, double dispersion, double raw_correction);
+extern void RCL_UpdateReachability(RCL_Instance instance);
extern double RCL_GetPrecision(RCL_Instance instance);
extern int RCL_GetDriverPoll(RCL_Instance instance);
diff --git a/refclock_phc.c b/refclock_phc.c
index e12f2258..6c0914f6 100644
--- a/refclock_phc.c
+++ b/refclock_phc.c
@@ -154,6 +154,8 @@ static void process_ext_pulse(RCL_Instance instance, struct timespec *phc_ts)
}
phc->last_extts = *phc_ts;
+ RCL_UpdateReachability(instance);
+
if (!HCL_CookTime(phc->clock, phc_ts, &local_ts, &local_err))
return;
@@ -204,6 +206,9 @@ static int phc_poll(RCL_Instance instance)
if (n_readings < 1)
return 0;
+ if (!phc->extpps)
+ RCL_UpdateReachability(instance);
+
if (!HCL_ProcessReadings(phc->clock, n_readings, readings, &phc_ts, &sys_ts, &phc_err))
return 0;
diff --git a/refclock_pps.c b/refclock_pps.c
index 880c13fc..f00b7ccb 100644
--- a/refclock_pps.c
+++ b/refclock_pps.c
@@ -143,6 +143,8 @@ static int pps_poll(RCL_Instance instance)
pps->last_seq = seq;
+ RCL_UpdateReachability(instance);
+
return RCL_AddPulse(instance, &ts, 1.0e-9 * ts.tv_nsec);
}
diff --git a/refclock_shm.c b/refclock_shm.c
index ee13e871..22e51820 100644
--- a/refclock_shm.c
+++ b/refclock_shm.c
@@ -109,6 +109,8 @@ static int shm_poll(RCL_Instance instance)
shm->valid = 0;
+ RCL_UpdateReachability(instance);
+
receive_ts.tv_sec = t.receiveTimeStampSec;
clock_ts.tv_sec = t.clockTimeStampSec;
diff --git a/refclock_sock.c b/refclock_sock.c
index 2da57ef5..49cf3559 100644
--- a/refclock_sock.c
+++ b/refclock_sock.c
@@ -129,6 +129,8 @@ static void read_sample(int sockfd, int event, void *anything)
UTI_TimevalToTimespec(&sample.tv, &sys_ts);
UTI_NormaliseTimespec(&sys_ts);
+ RCL_UpdateReachability(instance);
+
if (!UTI_IsTimeOffsetSane(&sys_ts, sample.offset))
return;
diff --git a/test/simulation/106-refclock b/test/simulation/106-refclock
index dedab9b8..3793bd86 100755
--- a/test/simulation/106-refclock
+++ b/test/simulation/106-refclock
@@ -114,6 +114,32 @@ Root delay : 0\.000000001 seconds
rm -f tmp/refclocks.log
fi
+export CLKNETSIM_PHC_JITTER_OFF=$[2 * 25 * 492]
+export CLKNETSIM_PHC_JITTER_ON=$[2 * 25 * 8]
+export CLKNETSIM_PHC_JITTER=1e-6
+refclock_offset=0.0
+refclock_jitter=1e-9
+min_sync_time=5
+max_sync_time=7
+time_max_limit=1e-7
+time_rms_limit=1e-8
+client_conf="refclock PHC /dev/ptp0:nocrossts poll 0
+logdir tmp
+log refclocks"
+chronyc_start=500
+chronyc_conf="sources"
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_sync || test_fail
+check_chronyc_output "^MS.*
+=*
+#\* PHC0 0 0 377 8 .*$" || test_fail
+
+unset CLKNETSIM_PHC_JITTER_OFF
+unset CLKNETSIM_PHC_JITTER_ON
+export CLKNETSIM_PHC_JITTER=1e-7
refclock_offset="(+ 0.399 (sum 1e-3))"
refclock_jitter=1e-6
servers=1
diff -up chrony/doc/chronyc.man.orig chrony/doc/chronyc.man
--- chrony/doc/chronyc.man.in.orig 2024-11-06 12:07:50.555216174 +0100
+++ chrony/doc/chronyc.man.in 2024-11-06 12:07:58.131217759 +0100
@@ -535,9 +535,12 @@ the polling rate in response to prevaili
\fBReach\fP
.RS 4
This shows the source\(cqs reachability register printed as an octal number. The
-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.
+register has 8 bits. It is shifted to left by one bit with each poll and it is
+updated by 1 when a valid NTP response, or just a sample in case of a reference
+clock, is received from the source. A value of 377 indicates that a valid
+response or sample was received for all of the last 8 polls. Note that samples
+can be dropped if they are not considered good enough for synchronisation, but
+the reachability register will still have 1s for their polls.
.RE
.sp
\fBLastRx\fP

View File

@ -1,279 +0,0 @@
commit d6aab8da1533b169385c749f8d1320c2b568a149
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Mon Jun 2 10:53:47 2025 +0200
conf: fix sourcedir reloading to not multiply sources
The sourcedir reload triggered by the chronyc "reload sources"
command incorrectly assumed that NSR_AddSourceByName() can return
only the NSR_Success status when a source is added. It ignored the
NSR_UnresolvedName status returned for a source whose name needs to
be resolved after the call (i.e. not specified with an IP address)
and added the source again, effectively multiplying it if the name
can be resolved to a different IP address.
Fix the code to check for the NSR_UnresolvedName status to correctly
determine whether the source was already added before and should not be
added again.
Reported-by: MichaelR <MichaelR42@runbox.com>
Fixes: 916ed70c4a81 ("conf: save source status in sourcedir reload")
diff --git a/conf.c b/conf.c
index cbb11304..59a2e5c9 100644
--- a/conf.c
+++ b/conf.c
@@ -1742,8 +1742,8 @@ reload_source_dirs(void)
NTP_Source *prev_sources, *new_sources, *source;
unsigned int i, j, prev_size, new_size, unresolved;
char buf[MAX_LINE_LENGTH];
+ int d, pass, was_added;
NSR_Status s;
- int d, pass;
/* Ignore reload command before adding configured sources */
if (!conf_ntp_sources_added)
@@ -1782,13 +1782,16 @@ reload_source_dirs(void)
else
d = i < prev_size ? -1 : 1;
+ was_added = d <= 0 && (prev_sources[i].status == NSR_Success ||
+ prev_sources[i].status == NSR_UnresolvedName);
+
/* Remove missing sources before adding others to avoid conflicts */
- if (pass == 0 && d < 0 && prev_sources[i].status == NSR_Success) {
+ if (pass == 0 && d < 0 && was_added) {
NSR_RemoveSourcesById(prev_sources[i].conf_id);
}
/* Add new sources and sources that could not be added before */
- if (pass == 1 && (d > 0 || (d == 0 && prev_sources[i].status != NSR_Success))) {
+ if (pass == 1 && (d > 0 || (d == 0 && !was_added))) {
source = &new_sources[j];
s = NSR_AddSourceByName(source->params.name, source->params.family, source->params.port,
source->pool, source->type, &source->params.params,
commit 778331092436c2f2077a7d0b6253ca1771fb8e27
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Tue Jun 3 10:58:00 2025 +0200
test: add 149-sourcedir test
diff --git a/test/simulation/149-sourcedir b/test/simulation/149-sourcedir
new file mode 100755
index 00000000..77b8499f
--- /dev/null
+++ b/test/simulation/149-sourcedir
@@ -0,0 +1,189 @@
+#!/usr/bin/env bash
+
+. ./test.common
+
+test_start "sourcedir directive"
+
+check_config_h 'FEAT_CMDMON 1' || test_skip
+
+servers=4
+limit=191
+update_executable="tmp/update-sourcedir"
+client_server_conf="sourcedir tmp"
+base_delay="(+ 1e-4 (* 5 (equal 0.1 from $[servers + 2])))"
+chronyc_start=1
+chronyc_conf="timeout 6000
+activity
+$(for i in $(seq 1 18); do echo "reload sources"; echo activity; done)"
+
+cat > tmp/sources.sources <<EOF
+pool nodes-1-2-3-4.net1.clk iburst
+EOF
+
+cat > tmp/update-sourcedir <<EOF
+#!/usr/bin/env bash
+case "\$1" in
+ 19) s="pool nodes-1-2-3-4.net1.clk";;
+ 39) s="pool nodes-1-2-3-4.net1.clk maxsources 3";;
+ 59) s="pool nodes-1-2-3.net1.clk";;
+ 79) s="pool nodes-1-2-3.net1.clk
+ server nodes-3-4.net1.clk";;
+ 99) s="server nodes-3-4.net1.clk";;
+ 119) s="server nodes-1-2-3.net1.clk";;
+ 139) s="server 192.168.123.2";;
+ 159) s="server 192.168.123.2 maxdelay 0.1";;
+ 179) s="";;
+ *) exit 0;;
+esac
+echo "\$s" > tmp/sources.sources
+EOF
+chmod 755 tmp/update-sourcedir
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+
+check_log_messages "T00:0.:[135].Z \(Added\|Removed\)" 0 0 || test_fail
+check_log_messages "T00:0.:..Z Added pool nodes-1-2-3-4\." 3 3 || test_fail
+check_log_messages "T00:0.:..Z Removed pool nodes-1-2-3-4\." 3 3 || test_fail
+check_log_messages "T00:0.:..Z Added pool nodes-1-2-3\." 1 1 || test_fail
+check_log_messages "T00:0.:..Z Removed pool nodes-1-2-3\." 1 1 || test_fail
+check_log_messages "T00:0.:..Z Added source ID#" 2 2 || test_fail
+check_log_messages "T00:0.:..Z Added source 192.168.123.[1234]" 2 2 || test_fail
+check_log_messages "T00:0.:..Z Removed source 192.168.123.[1234]" 4 4 || test_fail
+
+check_chronyc_output "^200 OK
+0 sources online
+0 sources offline
+4 sources doing burst \(return to online\)
+0 sources doing burst \(return to offline\)
+0 sources with unknown address
+200 OK
+200 OK
+4 sources online
+0 sources offline
+0 sources doing burst \(return to online\)
+0 sources doing burst \(return to offline\)
+0 sources with unknown address
+200 OK
+200 OK
+4 sources online
+0 sources offline
+0 sources doing burst \(return to online\)
+0 sources doing burst \(return to offline\)
+0 sources with unknown address
+200 OK
+200 OK
+4 sources online
+0 sources offline
+0 sources doing burst \(return to online\)
+0 sources doing burst \(return to offline\)
+0 sources with unknown address
+200 OK
+200 OK
+3 sources online
+0 sources offline
+0 sources doing burst \(return to online\)
+0 sources doing burst \(return to offline\)
+0 sources with unknown address
+200 OK
+200 OK
+3 sources online
+0 sources offline
+0 sources doing burst \(return to online\)
+0 sources doing burst \(return to offline\)
+0 sources with unknown address
+200 OK
+200 OK
+3 sources online
+0 sources offline
+0 sources doing burst \(return to online\)
+0 sources doing burst \(return to offline\)
+5 sources with unknown address
+200 OK
+200 OK
+3 sources online
+0 sources offline
+0 sources doing burst \(return to online\)
+0 sources doing burst \(return to offline\)
+5 sources with unknown address
+200 OK
+200 OK
+4 sources online
+0 sources offline
+0 sources doing burst \(return to online\)
+0 sources doing burst \(return to offline\)
+5 sources with unknown address
+200 OK
+200 OK
+4 sources online
+0 sources offline
+0 sources doing burst \(return to online\)
+0 sources doing burst \(return to offline\)
+5 sources with unknown address
+200 OK
+200 OK
+1 sources online
+0 sources offline
+0 sources doing burst \(return to online\)
+0 sources doing burst \(return to offline\)
+0 sources with unknown address
+200 OK
+200 OK
+1 sources online
+0 sources offline
+0 sources doing burst \(return to online\)
+0 sources doing burst \(return to offline\)
+0 sources with unknown address
+200 OK
+200 OK
+1 sources online
+0 sources offline
+0 sources doing burst \(return to online\)
+0 sources doing burst \(return to offline\)
+0 sources with unknown address
+200 OK
+200 OK
+1 sources online
+0 sources offline
+0 sources doing burst \(return to online\)
+0 sources doing burst \(return to offline\)
+0 sources with unknown address
+200 OK
+200 OK
+1 sources online
+0 sources offline
+0 sources doing burst \(return to online\)
+0 sources doing burst \(return to offline\)
+0 sources with unknown address
+200 OK
+200 OK
+1 sources online
+0 sources offline
+0 sources doing burst \(return to online\)
+0 sources doing burst \(return to offline\)
+0 sources with unknown address
+200 OK
+200 OK
+1 sources online
+0 sources offline
+0 sources doing burst \(return to online\)
+0 sources doing burst \(return to offline\)
+0 sources with unknown address
+200 OK
+200 OK
+1 sources online
+0 sources offline
+0 sources doing burst \(return to online\)
+0 sources doing burst \(return to offline\)
+0 sources with unknown address
+200 OK
+200 OK
+0 sources online
+0 sources offline
+0 sources doing burst \(return to online\)
+0 sources doing burst \(return to offline\)
+0 sources with unknown address$" || test_fail
+
+check_packet_interval || test_fail
+
+test_pass
diff --git a/test/simulation/test.common b/test/simulation/test.common
index 42a2917b..7eb348e3 100644
--- a/test/simulation/test.common
+++ b/test/simulation/test.common
@@ -39,6 +39,7 @@ default_refclock_jitter=""
default_refclock_offset=0.0
default_update_interval=0
+default_update_executable=""
default_shift_pll=2
default_server_strata=1
@@ -442,7 +443,9 @@ run_simulation() {
-o tmp/log.offset -f tmp/log.freq -p tmp/log.packets \
-R $(awk "BEGIN {print $update_interval < 0 ? 2^-($update_interval) : 1}") \
-r $(awk "BEGIN {print $max_sync_time * 2^$update_interval}") \
- -l $(awk "BEGIN {print $limit * 2^$update_interval}") && test_ok || test_error
+ -l $(awk "BEGIN {print $limit * 2^$update_interval}") \
+ $([ "$update_executable" != "" ] && printf "%s" "-e $update_executable") && \
+ test_ok || test_error
}
run_test() {

View File

@ -1,2 +0,0 @@
#Type Name ID GECOS Home directory Shell
u chrony - "chrony system user" /var/lib/chrony /sbin/nologin

1
ci.fmf
View File

@ -1 +0,0 @@
resultsdb-testcase: separate

View File

@ -1,64 +0,0 @@
commit 1205197f2e15166a47fa1817feaf3587738fb37a
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Wed Nov 27 16:03:19 2024 +0100
avoid timestamps from future in PTP_SYS_OFFSET_EXTENDED
diff --git a/client.c b/client.c
index 065eddf..32796e0 100644
--- a/client.c
+++ b/client.c
@@ -2065,24 +2065,24 @@ int ioctl(int fd, unsigned long request, ...) {
} else if (request == PTP_SYS_OFFSET_EXTENDED && fd == REFCLK_FD) {
struct ptp_sys_offset_extended *sys_off = va_arg(ap, struct ptp_sys_offset_extended *);
struct timespec ts, ts1, ts2;
+ double delay;
int i;
if (sys_off->n_samples > PTP_MAX_SAMPLES)
sys_off->n_samples = PTP_MAX_SAMPLES;
for (i = 0; i < sys_off->n_samples; i++) {
+ clock_gettime(CLOCK_REALTIME, &ts2);
clock_gettime(REFCLK_ID, &ts);
- sys_off->ts[i][1].sec = ts.tv_sec;
- sys_off->ts[i][1].nsec = ts.tv_nsec;
- }
-
- clock_gettime(CLOCK_REALTIME, &ts);
- for (i = 0; i < sys_off->n_samples; i++) {
- ts1 = ts, ts2 = ts;
- add_to_timespec(&ts1, -get_phc_delay(-1));
- add_to_timespec(&ts2, get_phc_delay(1));
+ delay = get_phc_delay(1);
+ add_to_timespec(&ts, -delay);
+ delay += get_phc_delay(-1);
+ ts1 = ts2;
+ add_to_timespec(&ts1, -delay);
sys_off->ts[i][0].sec = ts1.tv_sec;
sys_off->ts[i][0].nsec = ts1.tv_nsec;
+ sys_off->ts[i][1].sec = ts.tv_sec;
+ sys_off->ts[i][1].nsec = ts.tv_nsec;
sys_off->ts[i][2].sec = ts2.tv_sec;
sys_off->ts[i][2].nsec = ts2.tv_nsec;
}
commit 8b8831d98df1fca21288a9bc18c6a8fbfe6874a6
Author: Miroslav Lichvar <mlichvar@redhat.com>
Date: Wed Nov 27 16:06:40 2024 +0100
round nanoseconds in PTP_SYS_OFFSET* delay adjustments
diff --git a/client.c b/client.c
index 32796e0..0e235a6 100644
--- a/client.c
+++ b/client.c
@@ -794,7 +794,7 @@ static void normalize_timespec(struct timespec *tp) {
static void add_to_timespec(struct timespec *tp, double offset) {
tp->tv_sec += floor(offset);
- tp->tv_nsec += (offset - floor(offset)) * 1e9;
+ tp->tv_nsec += round((offset - floor(offset)) * 1e9);
normalize_timespec(tp);
}

View File

@ -1,25 +0,0 @@
--- !Policy
product_versions:
- fedora-*
decision_context: bodhi_update_push_testing
subject_type: koji_build
rules:
- !PassingTestCaseRule {test_case_name: fedora-ci.koji-build./plans/tier1-public.functional}
#Rawhide
--- !Policy
product_versions:
- fedora-*
decision_context: bodhi_update_push_stable
subject_type: koji_build
rules:
- !PassingTestCaseRule {test_case_name: fedora-ci.koji-build./plans/tier1-public.functional}
#gating rhel
--- !Policy
product_versions:
- rhel-*
decision_context: osci_compose_gate
rules:
- !PassingTestCaseRule {test_case_name: osci.brew-build./plans/tier1-public.functional}
- !PassingTestCaseRule {test_case_name: osci.brew-build./plans/tier1-internal.functional}

View File

@ -1,54 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBGCc9dwBEADLydyZIqgarshQeCtIlWAgP3coy0mdJwxet1CvXwF1xpq18Qi1
Tt9RZL64SkbQ8sKryBqnPjKZdOfVT5FwUucjp9L+/j7Bhk0tqv30EIQ57rnDLJ9T
c4LG1leO+Tc5Ym/0tvv4uMjkxr4KAKHPYrweHk6EAw06bbJ02mfy9xhlITSfyyFl
QRoRTEjy8N2IDutA4QzbZm0T5kvI7k7s/ILG5vyNo53X5PI/rWrSqmPZ5qs0lvDv
tA+rxOJp+FvlvOyBuv3ftIX0kAwRU+x/ET2Yd9qQWnXRx9d9D2UpFXm9DHfCDJYR
F56D0O3hf+rrCa/uSutIqmR33j5Wz4bYjWdmg4wbRQaoVxJl5AUrWuYEFwcCuY2B
FFgttLPb0qHpeBwuWaWJ9U6HM7qY3WEI2C/OWM0XFM8ERezedNEf7O2GTsoVVcm+
LRg31R3eJzipKMAGZWScSDSRAXhh6oZhflMRjYKGvwRfgeos/Sl2bdYL80hqyjGV
jMhEYDC9sfLXRyLU+9FexruIzSLR8Vornma3zjzu9pRkbfTHb8FfBMt9MZEWraF2
7riRq/zJE9QPWnBL/C8rdaXXxflBmGctn7RDKGOvxZ7SxPzzHbl5tV/Fizhkeph/
v8YLVuCOk0pIpX65mFun3Xw5IF01x1GMzU1xYezExti9yBNiv9HVqf1DWwARAQAB
tCZNaXJvc2xhdiBMaWNodmFyIDxtbGljaHZhckByZWRoYXQuY29tPokCVAQTAQgA
PhYhBI83XH6NDuElo9O9UVN+K3b3aA2sBQJgnPXcAhsDBQkSzAMABQsJCAcCBhUK
CQgLAgQWAgMBAh4BAheAAAoJEFN+K3b3aA2sl8IQAJ9AMppV6cdxzt8g2Ypz0hw1
6+9T5DjbYE/s0lozFQhCoYfo+SZyc3+yyKzlxI3ryHwFk9NjXGZZ8QjzT7FLj7/s
nKDjv5hUCOAi9Q+k217xwlBueeMyheeVaGGGa+Hv5CF1fZx/MtxiShUqu8oSqUyP
nW8lPGz73MfGAPT7kijVnz73pbht0vrZ9I+r8dnQGiweGBohexfCvmncrTyhjM8r
nvecycYBNnXhupzpmSMZgIA1s2v7oVmTnV0bntxE/gr7+SPk7KozhD12K8OU8deJ
cDD8F7NKa9Oe5NtuGVN4IPqp5cgj7GAyIj0sYss9Jknu4jX0imR5kwH6GbgFa7c/
kU+fKTz57Rs1OGr3glYpMnNftXSWbC2V/OJxHVEcMk8HwKLgnQjtmKLVGeCo5iS6
LFQuWaxpfjvxVjGSpnNu19cHVUhDM9cTP1DhUd4LdnltHQ+/xjwgzTgE4GJ1ZB0W
vhvxcdb69Sf50bGd4/WuURRoYSE7M6UKRwfXmMpyTiNhZz+3XjAoScA9AS7q9xfS
y3OddQEle/+qNFdABB12WmCgRhWemHzTZDXydIJuw+ucLO7U5RrDdqdaHkRVXJ9G
4mdk+3FgUlYgB9GY4pHQdqGdE60838R2zY9x0gK8cHU+FaRPAiTU8SJL0wb/Rko7
qbZUY/6bgrDoXp4otAP2iF0EExECAB0WIQSLH0qa2nPUAeMIWgtf8G8puh4BOwUC
YJ0C3AAKCRBf8G8puh4BO9k2AJ4ohgz/p49IBfjf22sEL1FvYM/DhwCfTyCkbogO
uagIg5qwuEGwHMgn19G5Ag0EYJz13AEQAMrLXgl5u6vAakSF9n+xCP2WOiMHzzrR
OxHnWzsX6PTXpJt14LSZOZ5wjdyR3gLJWGLdkfHoxHpQYp7PLgNS29SuAc4HQ+Br
O5F4g9EmwDJ0ueUYxU1FcySRXfXR+gLabpQCc2s9bW6RaMwLuQNxZwkfXClkPQms
ImTFA0KntWpHc+uEr1J2i6LQS7D/BK6m72l9x8z9k9gqAabXw+xHsis+ffPMG5Jm
HOqeHYtsq+2JW1VvBnA4Qh3DKH9OQaD9hZbEiUC3nMmlLkPF/r29tWTPa7luBHBn
X556JTXVm+vDUDwZ2srLfaKyQCxbNLwvQ2Pn5SOyyCnuIWR2xZs/+KPDMhtKUBAV
HcboVu6iPCTU42CVMPaJvYD2iUEncZNeUGJOSuG240LSLNGEFFsD7YgXb1XHjQD5
ci3Ki7P/hHi3AG53IsQTiaE5VgBdDje3zYCf5WaZ6c3DQQB9lab2RMz+5Fdr7Z6Y
mFRUbmxSnsMe0mwwcqVe3ofV0fKvE7Ep0T8bBg53dCqyU8hIbD5wUe99JmhMFnzs
5elwkv/Hb3Eg92dgu1zWb5kMzuvGEHtCIukIy1B+pzQOfT+iOC+lbmRHhPslJ9S0
1vENJE+nEEsGxPy9pRHrmWSKI4Zh+ysjb/vW/vOwAd1RsvxTfgBeOOawmlz+n0pJ
T018ZnUgmc35ABEBAAGJAjwEGAEIACYWIQSPN1x+jQ7hJaPTvVFTfit292gNrAUC
YJz13AIbDAUJEswDAAAKCRBTfit292gNrPuRD/43kM0P71gxfJQj6PBpPtjIVVfm
4TIPWKmV+F4/9eCwAPC/o44Yw+nxGr77Rk2DsaSn0V51j2egRCXKuZBZx/v6JXP7
qpDk3Uecml7IfxTd+N+gkI3viUsrt4ykUgyUH/wy/edMG3h9qhBQP0RxiDge18P6
YUpQSnq3uP72ycTPLBJlqp/Y9+GXUapvcyDqBFnvs96ieDmSbjSf6tris1cuLv6f
eld4HNUY/LmI5MlYbywbgWGpSOyKUlTtyF33LqPnWd7UuTN7QNsYyjGnlJbkkGi/
KwuNbIo5Gs4avaUSTc7SBLdCYneEIt7mt7hg0StKHQC6s/ak/w8yl1yFy5gRusO4
QCFT2ZMQ6jZUAuaQGx0rhWQr9akNNJEDsHTBQR8pxpFp3LcDXcUXSSeySRSFZLt+
hExvDQxXuhdbZHYGL1E6g5gtJQKnobNu2jMOziBcDivhAsqNw2Poq6fJVLavjBI5
BI1xAqmymIExJFSlHdLuZq09cVzY3EOj3x23YTzPKNOI/qu4jTUT4Byi8Oy3PN1B
B0n5SqORWJ0KfAyVEewshSAqJ7zrZ5sJXWnKeVQqBOg5EwkOB8rz/M3mqgrnBRiq
hLiiiG5tKETA1YIQGXIbP8t1vqoQrpvYaJfkk3kQlktxfFkDRt8dKIxpFk8uPiNb
bcAu2uXfRrQxpaqcOg==
=/wbD
-----END PGP PUBLIC KEY BLOCK-----

View File

@ -1,36 +0,0 @@
/tier1-internal:
plan:
import:
url: https://gitlab.com/redhat/centos-stream/tests/chrony.git
name: /plans/tier1/internal
/tier1-public:
plan:
import:
url: https://gitlab.com/redhat/centos-stream/tests/chrony.git
name: /plans/tier1/public
/tier2-tier3-internal:
plan:
import:
url: https://gitlab.com/redhat/centos-stream/tests/chrony.git
name: /plans/tier2-tier3/internal
/tier2-tier3-public:
plan:
import:
url: https://gitlab.com/redhat/centos-stream/tests/chrony.git
name: /plans/tier2-tier3/public
/others-internal:
plan:
import:
url: https://gitlab.com/redhat/centos-stream/tests/chrony.git
name: /plans/others/internal
/others-public:
plan:
import:
url: https://gitlab.com/redhat/centos-stream/tests/chrony.git
name: /plans/others/public

View File

@ -1,3 +0,0 @@
SHA512 (chrony-4.6.1.tar.gz) = 646ae08f2587366236796f2399d8ab3eb570979e0d82f5d13f5cec49939054c876cc93dc20c8d38e105fd3500e1720d05a223a15076783cd882d0de43afd9c7e
SHA512 (chrony-4.6.1-tar-gz-asc.txt) = 992b706636bf3a7eb6d502562a4990c9d8e20e5f3011d2cdb2ceb32220e9a1c2bfa6eca767212cee49b811823872602dc33f9e7201a7f9a93cc9c90e81b1db49
SHA512 (clknetsim-cdd694.tar.gz) = 289641461bd8c7227547478ba8cd51b7a114da3e34c994fe652382b0fb4df386c8734585bbcfa3ee5b99891cc6eef305997c5a7d92ea06b2cc6e94480aea5e75