From d7c2b1d2f356da16fccc4b069db154764dc0fc4e Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Mon, 5 Feb 2024 14:06:52 +0100 Subject: [PATCH] ntp: support per-source IP family restriction Add a new parameter to the NSR_AddSourceByName() function to allow individual sources to be limited to IPv4 or IPv6 addresses. This doesn't change the options passed to the resolver. It's just an additional filter in the processing of resolved addresses following the -4/-6 command-line option of chronyd. --- cmdmon.c | 2 +- conf.c | 9 +++++---- ntp_sources.c | 23 ++++++++++++++++++----- ntp_sources.h | 9 ++++++--- stubs.c | 2 +- test/unit/ntp_sources.c | 10 +++++++--- 6 files changed, 38 insertions(+), 17 deletions(-) diff --git a/cmdmon.c b/cmdmon.c index 9adc9d6..d2199a7 100644 --- a/cmdmon.c +++ b/cmdmon.c @@ -789,7 +789,7 @@ handle_add_source(CMD_Request *rx_message, CMD_Reply *tx_message) NTP_EF_FLAG_EXP_NET_CORRECTION : 0); params.sel_options = convert_addsrc_select_options(ntohl(rx_message->data.ntp_source.flags)); - status = NSR_AddSourceByName(name, port, pool, type, ¶ms, NULL); + status = NSR_AddSourceByName(name, IPADDR_UNSPEC, port, pool, type, ¶ms, NULL); switch (status) { case NSR_Success: break; diff --git a/conf.c b/conf.c index fa74459..9bae265 100644 --- a/conf.c +++ b/conf.c @@ -1728,8 +1728,9 @@ reload_source_dirs(void) /* Add new sources */ if (pass == 1 && d > 0) { source = &new_sources[j]; - s = NSR_AddSourceByName(source->params.name, source->params.port, source->pool, - source->type, &source->params.params, &new_ids[j]); + s = NSR_AddSourceByName(source->params.name, IPADDR_UNSPEC, source->params.port, + source->pool, source->type, &source->params.params, + &new_ids[j]); if (s == NSR_UnresolvedName) { unresolved++; @@ -1842,8 +1843,8 @@ CNF_AddSources(void) for (i = 0; i < ARR_GetSize(ntp_sources); i++) { source = (NTP_Source *)ARR_GetElement(ntp_sources, i); - s = NSR_AddSourceByName(source->params.name, source->params.port, source->pool, - source->type, &source->params.params, NULL); + s = NSR_AddSourceByName(source->params.name, IPADDR_UNSPEC, source->params.port, + source->pool, source->type, &source->params.params, NULL); if (s != NSR_Success && s != NSR_UnresolvedName) LOG(LOGS_ERR, "Could not add source %s", source->params.name); diff --git a/ntp_sources.c b/ntp_sources.c index d8bd2d8..590e5e0 100644 --- a/ntp_sources.c +++ b/ntp_sources.c @@ -61,6 +61,8 @@ typedef struct { (may be an IP address) */ IPAddr resolved_addr; /* Address resolved from the name, which can be different from remote_addr (e.g. NTS-KE) */ + int family; /* IP family of acceptable resolved addresses + (IPADDR_UNSPEC if any) */ int pool_id; /* ID of the pool from which was this source added or INVALID_POOL */ int tentative; /* Flag indicating there was no valid response @@ -98,6 +100,8 @@ struct UnresolvedSource { int pool_id; /* Name to be resolved */ char *name; + /* Address family to filter resolved addresses */ + int family; /* Flag indicating addresses should be used in a random order */ int random_order; /* Flag indicating current address should be replaced only if it is @@ -353,7 +357,7 @@ log_source(SourceRecord *record, int addition, int once_per_pool) /* Procedure to add a new source */ static NSR_Status -add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type, +add_source(NTP_Remote_Address *remote_addr, char *name, int family, NTP_Source_Type type, SourceParameters *params, int pool_id, uint32_t conf_id) { SourceRecord *record; @@ -391,6 +395,7 @@ add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type, record->data = NCR_CreateInstance(remote_addr, type, params, record->name); record->remote_addr = NCR_GetRemoteAddress(record->data); record->resolved_addr = remote_addr->ip_addr; + record->family = family; record->pool_id = pool_id; record->tentative = 1; record->conf_id = conf_id; @@ -552,6 +557,10 @@ process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs DEBUG_LOG("(%d) %s", i + 1, UTI_IPToString(&new_addr.ip_addr)); + /* Skip addresses not from the requested family */ + if (us->family != IPADDR_UNSPEC && us->family != new_addr.ip_addr.family) + continue; + if (us->pool_id != INVALID_POOL) { /* In the pool resolving mode, try to replace a source from the pool which does not have a real address yet */ @@ -768,14 +777,14 @@ NSR_Status NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params, uint32_t *conf_id) { - return add_source(remote_addr, NULL, type, params, INVALID_POOL, + return add_source(remote_addr, NULL, IPADDR_UNSPEC, type, params, INVALID_POOL, get_next_conf_id(conf_id)); } /* ================================================== */ NSR_Status -NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, +NSR_AddSourceByName(char *name, int family, int port, int pool, NTP_Source_Type type, SourceParameters *params, uint32_t *conf_id) { struct UnresolvedSource *us; @@ -787,7 +796,9 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, /* If the name is an IP address, add the source with the address directly */ if (UTI_StringToIP(name, &remote_addr.ip_addr)) { remote_addr.port = port; - return add_source(&remote_addr, name, type, params, INVALID_POOL, + if (family != IPADDR_UNSPEC && family != remote_addr.ip_addr.family) + return NSR_InvalidAF; + return add_source(&remote_addr, name, IPADDR_UNSPEC, type, params, INVALID_POOL, get_next_conf_id(conf_id)); } @@ -799,6 +810,7 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, us = MallocNew(struct UnresolvedSource); us->name = Strdup(name); + us->family = family; us->random_order = 0; us->refreshment = 0; @@ -835,7 +847,7 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, for (i = 0; i < new_sources; i++) { if (i > 0) remote_addr.ip_addr.addr.id = ++last_address_id; - if (add_source(&remote_addr, name, type, params, us->pool_id, cid) != NSR_Success) + if (add_source(&remote_addr, name, family, type, params, us->pool_id, cid) != NSR_Success) return NSR_TooManySources; } @@ -1026,6 +1038,7 @@ resolve_source_replacement(SourceRecord *record, int refreshment) us = MallocNew(struct UnresolvedSource); us->name = Strdup(record->name); + us->family = record->family; /* Ignore the order of addresses from the resolver to not get stuck with a pair of unreachable or otherwise unusable servers (e.g. falsetickers) in case the order doesn't change, or a group diff --git a/ntp_sources.h b/ntp_sources.h index 5aeb1a3..79daf1d 100644 --- a/ntp_sources.h +++ b/ntp_sources.h @@ -55,9 +55,12 @@ extern NSR_Status NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type /* Procedure to add a new server, peer source, or pool of servers specified by name instead of address. The name is resolved in exponentially increasing - intervals until it succeeds or fails with a non-temporary error. If the - name is an address, it is equivalent to NSR_AddSource(). */ -extern NSR_Status NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, + intervals until it succeeds or fails with a non-temporary error. The + specified family filters resolved addresses. If the name is an address + and its family does not conflict with the specified family, it is equivalent + to NSR_AddSource(). */ +extern NSR_Status NSR_AddSourceByName(char *name, int family, int port, int pool, + NTP_Source_Type type, SourceParameters *params, uint32_t *conf_id); extern const char *NSR_StatusToString(NSR_Status status); diff --git a/stubs.c b/stubs.c index b729c2f..044d17e 100644 --- a/stubs.c +++ b/stubs.c @@ -201,7 +201,7 @@ NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, } NSR_Status -NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, +NSR_AddSourceByName(char *name, int family, int port, int pool, NTP_Source_Type type, SourceParameters *params, uint32_t *conf_id) { return NSR_TooManySources; diff --git a/test/unit/ntp_sources.c b/test/unit/ntp_sources.c index e3d7c4d..a9bdbad 100644 --- a/test/unit/ntp_sources.c +++ b/test/unit/ntp_sources.c @@ -125,7 +125,7 @@ void test_unit(void) { char source_line[] = "127.0.0.1 offline", conf[] = "port 0", name[64]; - int i, j, k, slot, found, pool, prev_n; + int i, j, k, family, slot, found, pool, prev_n; uint32_t hash = 0, conf_id; NTP_Remote_Address addrs[256], addr; NTP_Local_Address local_addr; @@ -216,7 +216,7 @@ test_unit(void) TEST_CHECK(n_sources == 0); - status = NSR_AddSourceByName("a b", 0, 0, 0, &source.params, &conf_id); + status = NSR_AddSourceByName("a b", IPADDR_UNSPEC, 0, 0, 0, &source.params, &conf_id); TEST_CHECK(status == NSR_InvalidName); local_addr.ip_addr.family = IPADDR_INET4; @@ -228,11 +228,13 @@ test_unit(void) for (i = 0; i < 500; i++) { for (j = 0; j < 20; j++) { snprintf(name, sizeof (name), "ntp%d.example.net", (int)(random() % 10)); + family = random() % 2 ? IPADDR_UNSPEC : random() % 2 ? IPADDR_INET4 : IPADDR_INET6; pool = random() % 2; prev_n = n_sources; DEBUG_LOG("%d/%d adding source %s pool=%d", i, j, name, pool); - status = NSR_AddSourceByName(name, 0, pool, random() % 2 ? NTP_SERVER : NTP_PEER, + status = NSR_AddSourceByName(name, family, 0, pool, + random() % 2 ? NTP_SERVER : NTP_PEER, &source.params, &conf_id); TEST_CHECK(status == NSR_UnresolvedName); @@ -242,11 +244,13 @@ test_unit(void) for (us = unresolved_sources; us->next; us = us->next) ; TEST_CHECK(strcmp(us->name, name) == 0); + TEST_CHECK(us->family == family); if (pool) { TEST_CHECK(us->address.ip_addr.family == IPADDR_UNSPEC && us->pool_id >= 0); } else { TEST_CHECK(strcmp(NSR_GetName(&us->address.ip_addr), name) == 0); TEST_CHECK(find_slot2(&us->address, &slot) == 2); + TEST_CHECK(get_record(slot)->family == family); } if (random() % 2) {