From d7e3ad17ff7a80732e1edf27dd294e3ab8d9a293 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Tue, 18 Feb 2020 10:41:37 +0100 Subject: [PATCH] ntp: create sources for unresolved addresses Rework the ntp_sources code to create sources for addresses that are not resolved yet using the new identifiers. --- ntp_sources.c | 166 +++++++++++++++++++++++++++++--------------------- 1 file changed, 95 insertions(+), 71 deletions(-) diff --git a/ntp_sources.c b/ntp_sources.c index 6a05bdd..33e3633 100644 --- a/ntp_sources.c +++ b/ntp_sources.c @@ -48,7 +48,9 @@ particular sources */ typedef struct { NTP_Remote_Address *remote_addr; /* The address of this source, non-NULL - means this slot in table is in use */ + means this slot in table is in use + (an IPADDR_ID address means the address + is not resolved yet) */ NCR_Instance data; /* Data for the protocol engine for this source */ char *name; /* Name of the source, may be NULL */ int pool; /* Number of the pool from which was this source @@ -67,21 +69,21 @@ static int n_sources; /* Flag indicating new sources will be started automatically when added */ static int auto_start_sources = 0; -/* Source with unknown address (which may be resolved later) */ +/* Last assigned address ID */ +static uint32_t last_address_id = 0; + +/* Source scheduled for name resolving (first resolving or replacement) */ struct UnresolvedSource { + /* Current address of the source (IDADDR_ID is used for a single source + with unknown address and IPADDR_UNSPEC for a pool of sources */ + NTP_Remote_Address address; + /* ID of the pool if not a single source */ + int pool; + /* Name to be resolved */ char *name; - int port; + /* Flag indicating addresses should be used in a random order */ int random_order; - int replacement; - union { - struct { - NTP_Source_Type type; - SourceParameters params; - int pool; - int max_new_sources; - } new_source; - NTP_Remote_Address replace_source; - }; + /* Next unresolved source in the list */ struct UnresolvedSource *next; }; @@ -101,7 +103,7 @@ static NSR_SourceResolvingEndHandler resolving_end_handler = NULL; /* Pool of sources with the same name */ struct SourcePool { - /* Number of sources added from this pool (ignoring tentative sources) */ + /* Number of non-tentative sources with known address */ int sources; /* Maximum number of sources */ int max_sources; @@ -116,6 +118,7 @@ static ARR_Instance pools; static void resolve_sources(void *arg); static void rehash_records(void); static void clean_source_record(SourceRecord *record); +static void remove_pool_sources(int pool, int tentative, int unresolved); static void slew_sources(struct timespec *raw, @@ -211,7 +214,8 @@ find_slot(NTP_Remote_Address *remote_addr, int *slot, int *found) *found = 0; if (remote_addr->ip_addr.family != IPADDR_INET4 && - remote_addr->ip_addr.family != IPADDR_INET6) + remote_addr->ip_addr.family != IPADDR_INET6 && + remote_addr->ip_addr.family != IPADDR_ID) return; hash = UTI_IPToHash(&remote_addr->ip_addr); @@ -295,7 +299,8 @@ add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type, So return NSR_AlreadyInUse; } else { if (remote_addr->ip_addr.family != IPADDR_INET4 && - remote_addr->ip_addr.family != IPADDR_INET6) { + remote_addr->ip_addr.family != IPADDR_INET6 && + remote_addr->ip_addr.family != IPADDR_ID) { return NSR_InvalidAF; } else { n_sources++; @@ -313,7 +318,7 @@ add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type, So record->pool = pool; record->tentative = 1; - if (auto_start_sources) + if (auto_start_sources && UTI_IsIPReal(&remote_addr->ip_addr)) NCR_StartInstance(record->data); return NSR_Success; @@ -329,6 +334,7 @@ replace_source(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr) int slot1, slot2, found; SourceRecord *record; struct SourcePool *pool; + LOG_Severity severity; char *name; find_slot(old_addr, &slot1, &found); @@ -342,6 +348,9 @@ replace_source(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr) record = get_record(slot1); NCR_ChangeRemoteAddress(record->data, new_addr); record->remote_addr = NCR_GetRemoteAddress(record->data); + if (!UTI_IsIPReal(&old_addr->ip_addr) && UTI_IsIPReal(&new_addr->ip_addr) && + auto_start_sources) + NCR_StartInstance(record->data); if (!record->tentative) { record->tentative = 1; @@ -357,7 +366,9 @@ replace_source(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr) /* The hash table must be rebuilt for the new address */ rehash_records(); - LOG(LOGS_INFO, "Source %s replaced with %s (%s)", UTI_IPToString(&old_addr->ip_addr), + severity = UTI_IsIPReal(&old_addr->ip_addr) ? LOGS_INFO : LOGS_DEBUG; + + LOG(severity, "Source %s replaced with %s (%s)", UTI_IPToString(&old_addr->ip_addr), UTI_IPToString(&new_addr->ip_addr), name ? name : ""); return NSR_Success; @@ -368,31 +379,42 @@ replace_source(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr) static void process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs) { - NTP_Remote_Address address; - int i, added; + NTP_Remote_Address old_addr, new_addr; + SourceRecord *record; unsigned short first = 0; + int i, j; if (us->random_order) UTI_GetRandomBytes(&first, sizeof (first)); - for (i = added = 0; i < n_addrs; i++) { - address.ip_addr = ip_addrs[((unsigned int)i + first) % n_addrs]; - address.port = us->port; + for (i = 0; i < n_addrs; i++) { + new_addr.ip_addr = ip_addrs[((unsigned int)i + first) % n_addrs]; - DEBUG_LOG("(%d) %s", i + 1, UTI_IPToString(&address.ip_addr)); + DEBUG_LOG("(%d) %s", i + 1, UTI_IPToString(&new_addr.ip_addr)); - if (us->replacement) { - if (replace_source(&us->replace_source, &address) != NSR_AlreadyInUse) - break; + if (us->pool != INVALID_POOL) { + /* In the pool resolving mode, try to replace all sources from + the pool which don't have a real address yet */ + for (j = 0; j < ARR_GetSize(records); j++) { + record = get_record(j); + if (!record->remote_addr || record->pool != us->pool || + UTI_IsIPReal(&record->remote_addr->ip_addr)) + continue; + old_addr = *record->remote_addr; + new_addr.port = old_addr.port; + if (replace_source(&old_addr, &new_addr) != NSR_AlreadyInUse) + break; + } } else { - if (add_source(&address, us->name, us->new_source.type, &us->new_source.params, - us->new_source.pool) == NSR_Success) - added++; - - if (added >= us->new_source.max_new_sources) + new_addr.port = us->address.port; + if (replace_source(&us->address, &new_addr) != NSR_AlreadyInUse) break; } } + + /* Remove pool sources that didn't get an address */ + if (us->pool != INVALID_POOL) + remove_pool_sources(us->pool, 0, 1); } /* ================================================== */ @@ -424,8 +446,8 @@ name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *any next = us->next; /* Remove the source from the list on success or failure, replacements - are removed on any status */ - if (us->replacement || status != DNS_TryAgain) { + of known addresses are removed on any status */ + if (status != DNS_TryAgain || UTI_IsIPReal(&us->address.ip_addr)) { for (i = &unresolved_sources; *i; i = &(*i)->next) { if (*i == us) { *i = us->next; @@ -511,7 +533,7 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, Source struct UnresolvedSource *us; struct SourcePool *sp; NTP_Remote_Address remote_addr; - int i; + int i, new_sources; /* If the name is an IP address, don't bother with full resolving now or later when trying to replace the source */ @@ -528,25 +550,34 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, Source us = MallocNew(struct UnresolvedSource); us->name = Strdup(name); - us->port = port; us->random_order = 0; - us->replacement = 0; - us->new_source.type = type; - us->new_source.params = *params; + + remote_addr.ip_addr.family = IPADDR_ID; + remote_addr.ip_addr.addr.id = ++last_address_id; + remote_addr.port = port; if (!pool) { - us->new_source.pool = INVALID_POOL; - us->new_source.max_new_sources = 1; + us->pool = INVALID_POOL; + us->address = remote_addr; + new_sources = 1; } else { sp = (struct SourcePool *)ARR_GetNewElement(pools); sp->sources = 0; - sp->max_sources = params->max_sources; - us->new_source.pool = ARR_GetSize(pools) - 1; - us->new_source.max_new_sources = MAX_POOL_SOURCES; + sp->max_sources = CLAMP(1, params->max_sources, MAX_POOL_SOURCES); + us->pool = ARR_GetSize(pools) - 1; + us->address.ip_addr.family = IPADDR_UNSPEC; + new_sources = MIN(2 * sp->max_sources, MAX_POOL_SOURCES); } append_unresolved_source(us); + 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) != NSR_Success) + return NSR_TooManySources; + } + return NSR_UnresolvedName; } @@ -584,10 +615,12 @@ NSR_ResolveSources(void) void NSR_StartSources(void) { + NTP_Remote_Address *addr; unsigned int i; for (i = 0; i < ARR_GetSize(records); i++) { - if (!get_record(i)->remote_addr) + addr = get_record(i)->remote_addr; + if (!addr || !UTI_IsIPReal(&addr->ip_addr)) continue; NCR_StartInstance(get_record(i)->data); } @@ -671,14 +704,13 @@ resolve_source_replacement(SourceRecord *record) us = MallocNew(struct UnresolvedSource); us->name = Strdup(record->name); - us->port = record->remote_addr->port; /* If there never was a valid reply from this source (e.g. it was a bad replacement), ignore the order of addresses from the resolver to not get stuck to a pair of addresses if the order doesn't change, or a group of IPv4/IPv6 addresses if the resolver prefers inaccessible IP family */ us->random_order = record->tentative; - us->replacement = 1; - us->replace_source = *record->remote_addr; + us->pool = INVALID_POOL; + us->address = *record->remote_addr; append_unresolved_source(us); NSR_ResolveSources(); @@ -740,7 +772,7 @@ NSR_RefreshAddresses(void) /* ================================================== */ -static void remove_tentative_pool_sources(int pool) +static void remove_pool_sources(int pool, int tentative, int unresolved) { SourceRecord *record; unsigned int i, removed; @@ -748,10 +780,14 @@ static void remove_tentative_pool_sources(int pool) for (i = removed = 0; i < ARR_GetSize(records); i++) { record = get_record(i); - if (!record->remote_addr || record->pool != pool || !record->tentative) + if (!record->remote_addr || record->pool != pool) continue; - DEBUG_LOG("removing tentative source %s", + if ((tentative && !record->tentative) || + (unresolved && UTI_IsIPReal(&record->remote_addr->ip_addr))) + continue; + + DEBUG_LOG("removing %ssource %s", tentative ? "tentative " : "", UTI_IPToString(&record->remote_addr->ip_addr)); clean_source_record(record); @@ -837,7 +873,7 @@ NSR_ProcessRx(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, /* If the number of sources from the pool reached the configured maximum, remove the remaining tentative sources */ if (pool->sources >= pool->max_sources) - remove_tentative_pool_sources(record->pool); + remove_pool_sources(record->pool, 1, 0); } } } else { @@ -922,17 +958,6 @@ NSR_SetConnectivity(IPAddr *mask, IPAddr *address, SRC_Connectivity connectivity if (syncpeer) NCR_SetConnectivity(syncpeer->data, connectivity); - if (address->family == IPADDR_UNSPEC) { - struct UnresolvedSource *us; - - for (us = unresolved_sources; us; us = us->next) { - if (us->replacement) - continue; - any = 1; - us->new_source.params.connectivity = connectivity; - } - } - return any; } @@ -1143,26 +1168,25 @@ NSR_GetActivityReport(RPT_ActivityReport *report) { SourceRecord *record; unsigned int i; - struct UnresolvedSource *us; report->online = 0; report->offline = 0; report->burst_online = 0; report->burst_offline = 0; + report->unresolved = 0; for (i = 0; i < ARR_GetSize(records); i++) { record = get_record(i); - if (record->remote_addr) { + if (!record->remote_addr) + continue; + + if (!UTI_IsIPReal(&record->remote_addr->ip_addr)) { + report->unresolved++; + } else { NCR_IncrementActivityCounters(record->data, &report->online, &report->offline, &report->burst_online, &report->burst_offline); } } - - report->unresolved = 0; - - for (us = unresolved_sources; us; us = us->next) { - report->unresolved++; - } }