From e98f76e084a70e48b9378b50e62b71cf872e0865 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Thu, 7 Jan 2016 16:17:17 +0100 Subject: [PATCH] sources: add require option Require that at least one of the sources specified with this option is selectable (i.e. recently reachable and not a falseticker) before updating the clock. Together with the trust option this may be useful to allow a trusted, but not very precise, reference clock or a trusted authenticated NTP source to be safely combined with unauthenticated NTP sources in order to improve the accuracy of the clock. They can be selected and used for synchronization only if they agree with the trusted and required source. --- candm.h | 2 ++ chrony.texi.in | 16 ++++++++++++++++ client.c | 3 ++- cmdmon.c | 6 ++++-- cmdparse.c | 3 +++ conf.c | 3 +++ sources.c | 16 +++++++++++++--- srcparams.h | 1 + 8 files changed, 44 insertions(+), 6 deletions(-) diff --git a/candm.h b/candm.h index 5b7c8d2..cf7c317 100644 --- a/candm.h +++ b/candm.h @@ -244,6 +244,7 @@ typedef struct { #define REQ_ADDSRC_PREFER 0x8 #define REQ_ADDSRC_NOSELECT 0x10 #define REQ_ADDSRC_TRUST 0x20 +#define REQ_ADDSRC_REQUIRE 0x40 typedef struct { IPAddr ip_addr; @@ -480,6 +481,7 @@ typedef struct { #define RPY_SD_FLAG_NOSELECT 0x1 #define RPY_SD_FLAG_PREFER 0x2 #define RPY_SD_FLAG_TRUST 0x4 +#define RPY_SD_FLAG_REQUIRE 0x8 typedef struct { IPAddr ip_addr; diff --git a/chrony.texi.in b/chrony.texi.in index 73f9023..dc8f817 100644 --- a/chrony.texi.in +++ b/chrony.texi.in @@ -2724,6 +2724,14 @@ which are not very accurate, but are locked with a PPS refclock. Assume time from this source is always true. It can't be rejected as a falseticker in the source selection if sources that are specified without this option don't agree with it. +@item require +Require that at least one of the sources specified with this option is +selectable (i.e. recently reachable and not a falseticker) before updating the +clock. Together with the @code{trust} option this may be useful to allow a +trusted, but not very precise, reference clock to be safely combined with +unauthenticated NTP sources in order to improve the accuracy of the clock. +They can be selected and used for synchronisation only if they agree with +the trusted and required source. @item minsamples Set the minimum number of samples kept for this source. This overrides the @code{minsamples} directive (@pxref{minsamples directive}). @@ -3033,6 +3041,14 @@ Assume time from this source is always true. It can't be rejected as a falseticker in the source selection if sources that are specified without this option don't agree with it. +@item require +Require that at least one of the sources specified with this option is +selectable (i.e. recently reachable and not a falseticker) before updating the +clock. Together with the @code{trust} option this may be useful to allow a +trusted authenticated source to be safely combined with unauthenticated sources +in order to improve the accuracy of the clock. They can be selected and used +for synchronisation only if they agree with the trusted and required source. + @item minsamples Set the minimum number of samples kept for this source. This overrides the @code{minsamples} directive (@pxref{minsamples directive}). diff --git a/client.c b/client.c index aa7271a..728f14e 100644 --- a/client.c +++ b/client.c @@ -1119,7 +1119,8 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line) (data.params.iburst ? REQ_ADDSRC_IBURST : 0) | (data.params.sel_options & SRC_SELECT_PREFER ? REQ_ADDSRC_PREFER : 0) | (data.params.sel_options & SRC_SELECT_NOSELECT ? REQ_ADDSRC_NOSELECT : 0) | - (data.params.sel_options & SRC_SELECT_TRUST ? REQ_ADDSRC_TRUST : 0)); + (data.params.sel_options & SRC_SELECT_TRUST ? REQ_ADDSRC_TRUST : 0) | + (data.params.sel_options & SRC_SELECT_REQUIRE ? REQ_ADDSRC_REQUIRE : 0)); result = 1; break; diff --git a/cmdmon.c b/cmdmon.c index ae2a10c..3322cb7 100644 --- a/cmdmon.c +++ b/cmdmon.c @@ -664,7 +664,8 @@ handle_source_data(CMD_Request *rx_message, CMD_Reply *tx_message) tx_message->data.source_data.flags = htons((report.sel_options & SRC_SELECT_PREFER ? RPY_SD_FLAG_PREFER : 0) | (report.sel_options & SRC_SELECT_NOSELECT ? RPY_SD_FLAG_NOSELECT : 0) | - (report.sel_options & SRC_SELECT_TRUST ? RPY_SD_FLAG_TRUST : 0)); + (report.sel_options & SRC_SELECT_TRUST ? RPY_SD_FLAG_TRUST : 0) | + (report.sel_options & SRC_SELECT_REQUIRE ? RPY_SD_FLAG_REQUIRE : 0)); tx_message->data.source_data.reachability = htons(report.reachability); tx_message->data.source_data.since_sample = htonl(report.latest_meas_ago); tx_message->data.source_data.orig_latest_meas = UTI_FloatHostToNetwork(report.orig_latest_meas); @@ -760,7 +761,8 @@ handle_add_source(NTP_Source_Type type, CMD_Request *rx_message, CMD_Reply *tx_m params.sel_options = (ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_PREFER ? SRC_SELECT_PREFER : 0) | (ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_NOSELECT ? SRC_SELECT_NOSELECT : 0) | - (ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_TRUST ? SRC_SELECT_TRUST : 0); + (ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_TRUST ? SRC_SELECT_TRUST : 0) | + (ntohl(rx_message->data.ntp_source.flags) & REQ_ADDSRC_REQUIRE ? SRC_SELECT_REQUIRE : 0); params.max_delay = UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay); params.max_delay_ratio = UTI_FloatNetworkToHost(rx_message->data.ntp_source.max_delay_ratio); diff --git a/cmdparse.c b/cmdparse.c index 976e696..591e2e4 100644 --- a/cmdparse.c +++ b/cmdparse.c @@ -173,6 +173,9 @@ CPS_ParseNTPSourceAdd(char *line, CPS_NTP_Source *src) } else if (!strcasecmp(cmd, "trust")) { src->params.sel_options |= SRC_SELECT_TRUST; + } else if (!strcasecmp(cmd, "require")) { + src->params.sel_options |= SRC_SELECT_REQUIRE; + } else if (!strcasecmp(cmd, "version")) { if (sscanf(line, "%d%n", &src->params.version, &n) != 1) { result = CPS_BadVersion; diff --git a/conf.c b/conf.c index 8260de6..df3d080 100644 --- a/conf.c +++ b/conf.c @@ -746,6 +746,9 @@ parse_refclock(char *line) } else if (!strcasecmp(cmd, "trust")) { n = 0; sel_options |= SRC_SELECT_TRUST; + } else if (!strcasecmp(cmd, "require")) { + n = 0; + sel_options |= SRC_SELECT_REQUIRE; } else { other_parse_error("Invalid refclock option"); return; diff --git a/sources.c b/sources.c index 2e48c5f..cee2cbf 100644 --- a/sources.c +++ b/sources.c @@ -602,7 +602,7 @@ SRC_SelectSource(SRC_Instance updated_inst) struct SelectInfo *si; struct timeval now, ref_time; int i, j, j1, j2, index, sel_prefer, n_endpoints, n_sel_sources; - int n_badstats_sources, max_sel_reach, max_badstat_reach; + int n_badstats_sources, max_sel_reach, max_badstat_reach, sel_req_source; int depth, best_depth, trust_depth, best_trust_depth; int combined, stratum, min_stratum, max_score_index; double src_offset, src_offset_sd, src_frequency, src_skew; @@ -631,12 +631,18 @@ SRC_SelectSource(SRC_Instance updated_inst) n_endpoints = 0; n_sel_sources = 0; n_badstats_sources = 0; + sel_req_source = 0; max_sel_reach = max_badstat_reach = 0; max_reach_sample_ago = 0.0; for (i = 0; i < n_sources; i++) { assert(sources[i]->status != SRC_OK); + /* If some sources are specified with the require option, at least one + of them will have to be selectable in order to update the clock */ + if (sources[i]->sel_options & SRC_SELECT_REQUIRE) + sel_req_source = 1; + /* Ignore sources which were added with the noselect option */ if (sources[i]->sel_options & SRC_SELECT_NOSELECT) { sources[i]->status = SRC_UNSELECTABLE; @@ -825,15 +831,19 @@ SRC_SelectSource(SRC_Instance updated_inst) sources[i]->sel_info.hi_limit <= best_hi)) { sel_sources[n_sel_sources++] = i; + + if (sources[i]->sel_options & SRC_SELECT_REQUIRE) + sel_req_source = 0; } else { sources[i]->status = SRC_FALSETICKER; } } - if (n_sel_sources == 0 || n_sel_sources < CNF_GetMinSources()) { + if (!n_sel_sources || sel_req_source || n_sel_sources < CNF_GetMinSources()) { if (selected_source_index != INVALID_SOURCE) { log_selection_message("Can't synchronise: %s selectable sources", - n_sel_sources ? "not enough" : "no"); + !n_sel_sources ? "no" : + sel_req_source ? "no required source in" : "not enough"); selected_source_index = INVALID_SOURCE; } mark_ok_sources(SRC_WAITS_SOURCES); diff --git a/srcparams.h b/srcparams.h index 15fb6f2..42a1555 100644 --- a/srcparams.h +++ b/srcparams.h @@ -67,5 +67,6 @@ typedef struct { #define SRC_SELECT_NOSELECT 0x1 #define SRC_SELECT_PREFER 0x2 #define SRC_SELECT_TRUST 0x4 +#define SRC_SELECT_REQUIRE 0x8 #endif /* GOT_SRCPARAMS_H */