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.
This commit is contained in:
Miroslav Lichvar 2020-02-18 10:41:37 +01:00
parent 84902d0e00
commit d7e3ad17ff

View file

@ -48,7 +48,9 @@
particular sources */ particular sources */
typedef struct { typedef struct {
NTP_Remote_Address *remote_addr; /* The address of this source, non-NULL 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 */ NCR_Instance data; /* Data for the protocol engine for this source */
char *name; /* Name of the source, may be NULL */ char *name; /* Name of the source, may be NULL */
int pool; /* Number of the pool from which was this source 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 */ /* Flag indicating new sources will be started automatically when added */
static int auto_start_sources = 0; 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 { struct UnresolvedSource {
char *name; /* Current address of the source (IDADDR_ID is used for a single source
int port; with unknown address and IPADDR_UNSPEC for a pool of sources */
int random_order; NTP_Remote_Address address;
int replacement; /* ID of the pool if not a single source */
union {
struct {
NTP_Source_Type type;
SourceParameters params;
int pool; int pool;
int max_new_sources; /* Name to be resolved */
} new_source; char *name;
NTP_Remote_Address replace_source; /* Flag indicating addresses should be used in a random order */
}; int random_order;
/* Next unresolved source in the list */
struct UnresolvedSource *next; struct UnresolvedSource *next;
}; };
@ -101,7 +103,7 @@ static NSR_SourceResolvingEndHandler resolving_end_handler = NULL;
/* Pool of sources with the same name */ /* Pool of sources with the same name */
struct SourcePool { struct SourcePool {
/* Number of sources added from this pool (ignoring tentative sources) */ /* Number of non-tentative sources with known address */
int sources; int sources;
/* Maximum number of sources */ /* Maximum number of sources */
int max_sources; int max_sources;
@ -116,6 +118,7 @@ static ARR_Instance pools;
static void resolve_sources(void *arg); static void resolve_sources(void *arg);
static void rehash_records(void); static void rehash_records(void);
static void clean_source_record(SourceRecord *record); static void clean_source_record(SourceRecord *record);
static void remove_pool_sources(int pool, int tentative, int unresolved);
static void static void
slew_sources(struct timespec *raw, slew_sources(struct timespec *raw,
@ -211,7 +214,8 @@ find_slot(NTP_Remote_Address *remote_addr, int *slot, int *found)
*found = 0; *found = 0;
if (remote_addr->ip_addr.family != IPADDR_INET4 && 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; return;
hash = UTI_IPToHash(&remote_addr->ip_addr); 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; return NSR_AlreadyInUse;
} else { } else {
if (remote_addr->ip_addr.family != IPADDR_INET4 && 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; return NSR_InvalidAF;
} else { } else {
n_sources++; n_sources++;
@ -313,7 +318,7 @@ add_source(NTP_Remote_Address *remote_addr, char *name, NTP_Source_Type type, So
record->pool = pool; record->pool = pool;
record->tentative = 1; record->tentative = 1;
if (auto_start_sources) if (auto_start_sources && UTI_IsIPReal(&remote_addr->ip_addr))
NCR_StartInstance(record->data); NCR_StartInstance(record->data);
return NSR_Success; return NSR_Success;
@ -329,6 +334,7 @@ replace_source(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr)
int slot1, slot2, found; int slot1, slot2, found;
SourceRecord *record; SourceRecord *record;
struct SourcePool *pool; struct SourcePool *pool;
LOG_Severity severity;
char *name; char *name;
find_slot(old_addr, &slot1, &found); 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); record = get_record(slot1);
NCR_ChangeRemoteAddress(record->data, new_addr); NCR_ChangeRemoteAddress(record->data, new_addr);
record->remote_addr = NCR_GetRemoteAddress(record->data); 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) { if (!record->tentative) {
record->tentative = 1; 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 */ /* The hash table must be rebuilt for the new address */
rehash_records(); 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 : ""); UTI_IPToString(&new_addr->ip_addr), name ? name : "");
return NSR_Success; return NSR_Success;
@ -368,31 +379,42 @@ replace_source(NTP_Remote_Address *old_addr, NTP_Remote_Address *new_addr)
static void static void
process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs) process_resolved_name(struct UnresolvedSource *us, IPAddr *ip_addrs, int n_addrs)
{ {
NTP_Remote_Address address; NTP_Remote_Address old_addr, new_addr;
int i, added; SourceRecord *record;
unsigned short first = 0; unsigned short first = 0;
int i, j;
if (us->random_order) if (us->random_order)
UTI_GetRandomBytes(&first, sizeof (first)); UTI_GetRandomBytes(&first, sizeof (first));
for (i = added = 0; i < n_addrs; i++) { for (i = 0; i < n_addrs; i++) {
address.ip_addr = ip_addrs[((unsigned int)i + first) % n_addrs]; new_addr.ip_addr = ip_addrs[((unsigned int)i + first) % n_addrs];
address.port = us->port;
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 (us->pool != INVALID_POOL) {
if (replace_source(&us->replace_source, &address) != NSR_AlreadyInUse) /* 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; break;
}
} else { } else {
if (add_source(&address, us->name, us->new_source.type, &us->new_source.params, new_addr.port = us->address.port;
us->new_source.pool) == NSR_Success) if (replace_source(&us->address, &new_addr) != NSR_AlreadyInUse)
added++;
if (added >= us->new_source.max_new_sources)
break; 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; next = us->next;
/* Remove the source from the list on success or failure, replacements /* Remove the source from the list on success or failure, replacements
are removed on any status */ of known addresses are removed on any status */
if (us->replacement || status != DNS_TryAgain) { if (status != DNS_TryAgain || UTI_IsIPReal(&us->address.ip_addr)) {
for (i = &unresolved_sources; *i; i = &(*i)->next) { for (i = &unresolved_sources; *i; i = &(*i)->next) {
if (*i == us) { if (*i == us) {
*i = us->next; *i = us->next;
@ -511,7 +533,7 @@ NSR_AddSourceByName(char *name, int port, int pool, NTP_Source_Type type, Source
struct UnresolvedSource *us; struct UnresolvedSource *us;
struct SourcePool *sp; struct SourcePool *sp;
NTP_Remote_Address remote_addr; 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 /* If the name is an IP address, don't bother with full resolving now
or later when trying to replace the source */ 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 = MallocNew(struct UnresolvedSource);
us->name = Strdup(name); us->name = Strdup(name);
us->port = port;
us->random_order = 0; us->random_order = 0;
us->replacement = 0;
us->new_source.type = type; remote_addr.ip_addr.family = IPADDR_ID;
us->new_source.params = *params; remote_addr.ip_addr.addr.id = ++last_address_id;
remote_addr.port = port;
if (!pool) { if (!pool) {
us->new_source.pool = INVALID_POOL; us->pool = INVALID_POOL;
us->new_source.max_new_sources = 1; us->address = remote_addr;
new_sources = 1;
} else { } else {
sp = (struct SourcePool *)ARR_GetNewElement(pools); sp = (struct SourcePool *)ARR_GetNewElement(pools);
sp->sources = 0; sp->sources = 0;
sp->max_sources = params->max_sources; sp->max_sources = CLAMP(1, params->max_sources, MAX_POOL_SOURCES);
us->new_source.pool = ARR_GetSize(pools) - 1; us->pool = ARR_GetSize(pools) - 1;
us->new_source.max_new_sources = MAX_POOL_SOURCES; us->address.ip_addr.family = IPADDR_UNSPEC;
new_sources = MIN(2 * sp->max_sources, MAX_POOL_SOURCES);
} }
append_unresolved_source(us); 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; return NSR_UnresolvedName;
} }
@ -584,10 +615,12 @@ NSR_ResolveSources(void)
void NSR_StartSources(void) void NSR_StartSources(void)
{ {
NTP_Remote_Address *addr;
unsigned int i; unsigned int i;
for (i = 0; i < ARR_GetSize(records); 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; continue;
NCR_StartInstance(get_record(i)->data); NCR_StartInstance(get_record(i)->data);
} }
@ -671,14 +704,13 @@ resolve_source_replacement(SourceRecord *record)
us = MallocNew(struct UnresolvedSource); us = MallocNew(struct UnresolvedSource);
us->name = Strdup(record->name); 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 /* 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 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 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 */ IPv4/IPv6 addresses if the resolver prefers inaccessible IP family */
us->random_order = record->tentative; us->random_order = record->tentative;
us->replacement = 1; us->pool = INVALID_POOL;
us->replace_source = *record->remote_addr; us->address = *record->remote_addr;
append_unresolved_source(us); append_unresolved_source(us);
NSR_ResolveSources(); 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; SourceRecord *record;
unsigned int i, removed; 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++) { for (i = removed = 0; i < ARR_GetSize(records); i++) {
record = get_record(i); record = get_record(i);
if (!record->remote_addr || record->pool != pool || !record->tentative) if (!record->remote_addr || record->pool != pool)
continue; 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)); UTI_IPToString(&record->remote_addr->ip_addr));
clean_source_record(record); 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 /* If the number of sources from the pool reached the configured
maximum, remove the remaining tentative sources */ maximum, remove the remaining tentative sources */
if (pool->sources >= pool->max_sources) if (pool->sources >= pool->max_sources)
remove_tentative_pool_sources(record->pool); remove_pool_sources(record->pool, 1, 0);
} }
} }
} else { } else {
@ -922,17 +958,6 @@ NSR_SetConnectivity(IPAddr *mask, IPAddr *address, SRC_Connectivity connectivity
if (syncpeer) if (syncpeer)
NCR_SetConnectivity(syncpeer->data, connectivity); 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; return any;
} }
@ -1143,26 +1168,25 @@ NSR_GetActivityReport(RPT_ActivityReport *report)
{ {
SourceRecord *record; SourceRecord *record;
unsigned int i; unsigned int i;
struct UnresolvedSource *us;
report->online = 0; report->online = 0;
report->offline = 0; report->offline = 0;
report->burst_online = 0; report->burst_online = 0;
report->burst_offline = 0; report->burst_offline = 0;
report->unresolved = 0;
for (i = 0; i < ARR_GetSize(records); i++) { for (i = 0; i < ARR_GetSize(records); i++) {
record = get_record(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, NCR_IncrementActivityCounters(record->data, &report->online, &report->offline,
&report->burst_online, &report->burst_offline); &report->burst_online, &report->burst_offline);
} }
} }
report->unresolved = 0;
for (us = unresolved_sources; us; us = us->next) {
report->unresolved++;
}
} }