diff --git a/client.c b/client.c index c2af79c..899732f 100644 --- a/client.c +++ b/client.c @@ -902,6 +902,13 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line) status = CPS_ParseNTPSourceAdd(line, &data); switch (status) { case CPS_Success: + /* Don't retry name resolving */ + if (data.ip_addr.family == IPADDR_UNSPEC) { + Free(data.name); + fprintf(stderr, "Invalid host/IP address\n"); + break; + } + msg->data.ntp_source.port = htonl((unsigned long) data.port); UTI_IPHostToNetwork(&data.ip_addr, &msg->data.ntp_source.ip_addr); msg->data.ntp_source.minpoll = htonl(data.params.minpoll); diff --git a/cmdparse.c b/cmdparse.c index 668e08d..5dad262 100644 --- a/cmdparse.c +++ b/cmdparse.c @@ -33,6 +33,7 @@ #include "sysincl.h" #include "cmdparse.h" +#include "memory.h" #include "nameserv.h" #define MAXLEN 2047 @@ -66,6 +67,10 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src) s = DNS_Name2IPAddress(hostname, &src->ip_addr); if (s == DNS_Success) { ok = 1; + src->name = NULL; + } else if (s == DNS_TryAgain) { + ok = 1; + src->ip_addr.family = IPADDR_UNSPEC; } } @@ -160,6 +165,13 @@ CPS_ParseNTPSourceAdd(const char *line, CPS_NTP_Source *src) } while (!done); } + if (ok && src->ip_addr.family == IPADDR_UNSPEC) { + n = strlen(hostname); + src->name = MallocArray(char, n + 1); + strncpy(src->name, hostname, n); + src->name[n] = '\0'; + } + return result; } diff --git a/cmdparse.h b/cmdparse.h index 30fea49..7523d8e 100644 --- a/cmdparse.h +++ b/cmdparse.h @@ -49,6 +49,7 @@ typedef enum { typedef struct { IPAddr ip_addr; + char *name; unsigned short port; SourceParameters params; } CPS_NTP_Source; diff --git a/conf.c b/conf.c index 0f049b5..1556c2f 100644 --- a/conf.c +++ b/conf.c @@ -262,9 +262,7 @@ static int line_number; typedef struct { NTP_Source_Type type; - IPAddr ip_addr; - unsigned short port; - SourceParameters params; + CPS_NTP_Source params; } NTP_Source; #define MAX_NTP_SOURCES 64 @@ -355,23 +353,14 @@ CNF_ReadFile(const char *filename) static void parse_source(const char *line, NTP_Source_Type type) { - int i; - NTP_Source s; CPS_Status status; - CPS_NTP_Source params; - s.type = type; - status = CPS_ParseNTPSourceAdd(line, ¶ms); + ntp_sources[n_ntp_sources].type = type; + status = CPS_ParseNTPSourceAdd(line, &ntp_sources[n_ntp_sources].params); switch (status) { case CPS_Success: - s.port = params.port; - s.ip_addr = params.ip_addr; - s.params = params.params; - - i = n_ntp_sources++; - ntp_sources[i] = s; - + n_ntp_sources++; break; case CPS_BadOption: LOG(LOGS_WARN, LOGF_Configure, "Unrecognized subcommand at line %d", line_number); @@ -1191,11 +1180,16 @@ CNF_AddSources(void) { int i; for (i=0; iname, &address.ip_addr); + if (s == DNS_TryAgain) { + i = &(*i)->next; + continue; + } else if (s == DNS_Success) { + address.port = us->port; + NSR_AddSource(&address, us->type, &us->params); + } else { + LOG(LOGS_WARN, LOGF_NtpSources, "Invalid host %s", us->name); + } + + *i = us->next; + + Free(us->name); + Free(us); + } + + if (unresolved_sources) { + /* Try again later */ + if (resolving_interval < 9) + resolving_interval++; + resolving_id = SCH_AddTimeoutByDelay(7 * (1 << resolving_interval), resolve_sources, NULL); + } else { + resolving_interval = 0; + } +} + +/* ================================================== */ + +/* Procedure to add a new server or peer source, but instead of an IP address + only a name is provided */ +void +NSR_AddUnresolvedSource(char *name, int port, NTP_Source_Type type, SourceParameters *params) +{ + struct UnresolvedSource *us, **i; + + us = MallocNew(struct UnresolvedSource); + + us->name = name; + us->port = port; + us->type = type; + us->params = *params; + us->next = NULL; + + for (i = &unresolved_sources; *i; i = &(*i)->next) + ; + *i = us; + + if (!resolving_interval) { + resolving_interval = 2; + resolving_id = SCH_AddTimeoutByDelay(7 * (1 << resolving_interval), resolve_sources, NULL); + } +} + +/* ================================================== */ + /* Procedure to remove a source. We don't bother whether the port address is matched - we're only interested in removing a record for the right IP address. Thus the caller can specify the port number @@ -311,6 +396,13 @@ NSR_TakeSourcesOnline(IPAddr *mask, IPAddr *address) } } + if (resolving_interval) { + /* Try to resolve any unresolved sources now */ + SCH_RemoveTimeout(resolving_id); + resolving_interval--; + resolve_sources(NULL); + } + return any; } @@ -472,6 +564,7 @@ void NSR_GetActivityReport(RPT_ActivityReport *report) { int i; + struct UnresolvedSource *us; report->online = 0; report->offline = 0; @@ -484,6 +577,12 @@ NSR_GetActivityReport(RPT_ActivityReport *report) &report->burst_online, &report->burst_offline); } } + + /* Add unresolved sources to offline count */ + for (us = unresolved_sources; us; us = us->next) { + report->offline++; + } + return; } diff --git a/ntp_sources.h b/ntp_sources.h index eaef8a8..d69ee0d 100644 --- a/ntp_sources.h +++ b/ntp_sources.h @@ -53,6 +53,11 @@ typedef enum { /* Procedure to add a new server or peer source. */ extern NSR_Status NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params); +/* Procedure to add a new server or peer source with currently unknown address. + The name will be periodically resolved in exponentially increasing intervals + until it succeeds or fails with a non-temporary error. */ +extern void NSR_AddUnresolvedSource(char *name, int port, NTP_Source_Type type, SourceParameters *params); + /* Procedure to remove a source */ extern NSR_Status NSR_RemoveSource(NTP_Remote_Address *remote_addr);