/* Name of the user to which will be dropped root privileges. */
static char *user;
+/* Address refresh interval */
+static int refresh = 1209600; /* 2 weeks */
+
/* NTS server and client configuration */
static char *nts_dump_dir = NULL;
static char *nts_ntp_server = NULL;
&ntp_ratelimit_burst, &ntp_ratelimit_leak);
} else if (!strcasecmp(command, "refclock")) {
parse_refclock(p);
+ } else if (!strcasecmp(command, "refresh")) {
+ parse_int(p, &refresh);
} else if (!strcasecmp(command, "reselectdist")) {
parse_double(p, &reselect_distance);
} else if (!strcasecmp(command, "rtcautotrim")) {
/* ================================================== */
+int
+CNF_GetRefresh(void)
+{
+ return refresh;
+}
+
+/* ================================================== */
+
char *
CNF_GetNtsDumpDir(void)
{
extern int CNF_GetPtpPort(void);
+extern int CNF_GetRefresh(void);
+
extern char *CNF_GetNtsDumpDir(void);
extern char *CNF_GetNtsNtpServer(void);
extern int CNF_GetNtsServerCertAndKeyFiles(const char ***certs, const char ***keys);
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
+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.
++
+The <<chronyc.adoc#refresh,*refresh*>> command can be used to refresh all
+sources immediately.
+
=== Source selection
[[authselectmode]]*authselectmode* _mode_::
#include "sysincl.h"
#include "array.h"
+#include "conf.h"
#include "ntp_sources.h"
#include "ntp_core.h"
#include "ntp_io.h"
received from the source yet */
uint32_t conf_id; /* Configuration ID, which can be shared with
different sources in case of a pool */
+ double last_resolving; /* Time of last name resolving (monotonic) */
} SourceRecord;
/* Hash table of SourceRecord, its size is a power of two and it's never
record->pool_id = pool_id;
record->tentative = 1;
record->conf_id = conf_id;
+ record->last_resolving = SCH_GetLastEventMonoTime();
record_lock = 0;
{
struct UnresolvedSource *us;
- DEBUG_LOG("trying to replace %s (%s)",
+ DEBUG_LOG("%s %s (%s)", refreshment ? "refreshing" : "trying to replace",
UTI_IPToString(&record->remote_addr->ip_addr), record->name);
+ record->last_resolving = SCH_GetLastEventMonoTime();
+
us = MallocNew(struct UnresolvedSource);
us->name = Strdup(record->name);
/* Ignore the order of addresses from the resolver to not get
/* ================================================== */
+static void
+maybe_refresh_source(void)
+{
+ static double last_refreshment = 0.0;
+ SourceRecord *record, *oldest_record;
+ int i, min_interval;
+ double now;
+
+ min_interval = CNF_GetRefresh();
+
+ now = SCH_GetLastEventMonoTime();
+ if (min_interval <= 0 || now < last_refreshment + min_interval)
+ return;
+
+ last_refreshment = now;
+
+ for (i = 0, oldest_record = NULL; i < ARR_GetSize(records); i++) {
+ record = get_record(i);
+ if (!record->remote_addr || UTI_IsStringIP(record->name))
+ continue;
+
+ if (!oldest_record || oldest_record->last_resolving > record->last_resolving)
+ oldest_record = record;
+ }
+
+ if (!oldest_record)
+ return;
+
+ /* Check if the name wasn't already resolved in the last interval */
+ if (now < oldest_record->last_resolving + min_interval) {
+ last_refreshment = oldest_record->last_resolving;
+ return;
+ }
+
+ resolve_source_replacement(oldest_record, 1);
+}
+
+/* ================================================== */
+
void
NSR_RefreshAddresses(void)
{
remove_pool_sources(record->pool_id, 1, 0);
}
}
+
+ maybe_refresh_source();
} else {
NCR_ProcessRxUnknown(remote_addr, local_addr, rx_ts, message, length);
}
check_file_messages "20.*192.168.123.[345]" 31 33 measurements.log || test_fail
rm -f tmp/measurements.log
if check_config_h 'FEAT_DEBUG 1'; then
+ check_log_messages "refreshing 192.168.123" 3 3 || test_fail
check_log_messages "resolved_name.*still fresh" 3 3 || test_fail
fi
+limit=1100
+client_server_conf="
+server nodes-1-2.net1.clk maxpoll 6
+pool nodes-3-4-5.net1.clk maxpoll 6 maxsources 3"
+client_conf+="
+refresh 128"
+chronyc_conf=""
+
+run_test || test_fail
+check_chronyd_exit || test_fail
+check_source_selection || test_fail
+check_packet_interval || test_fail
+check_sync || test_fail
+
+check_file_messages "20.*192.168.123.1" 0 0 measurements.log || test_fail
+check_file_messages "20.*192.168.123.2" 16 18 measurements.log || test_fail
+check_file_messages "20.*192.168.123.[345]" 50 55 measurements.log || test_fail
+rm -f tmp/measurements.log
+if check_config_h 'FEAT_DEBUG 1'; then
+ check_log_messages "refreshing 192.168.123" 8 8 || test_fail
+ check_log_messages "resolved_name.*still fresh" 8 8 || test_fail
+ check_log_messages "refreshing 192.168.123.2" 2 2 || test_fail
+ check_log_messages "refreshing 192.168.123.3" 2 2 || test_fail
+ check_log_messages "refreshing 192.168.123.4" 2 2 || test_fail
+ check_log_messages "refreshing 192.168.123.5" 2 2 || test_fail
+fi
+
test_pass