summaryrefslogtreecommitdiffstats
path: root/contrib/ntp/ntpd/ntp_intres.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ntp/ntpd/ntp_intres.c')
-rw-r--r--contrib/ntp/ntpd/ntp_intres.c288
1 files changed, 181 insertions, 107 deletions
diff --git a/contrib/ntp/ntpd/ntp_intres.c b/contrib/ntp/ntpd/ntp_intres.c
index 7f27f21..2a4b51f 100644
--- a/contrib/ntp/ntpd/ntp_intres.c
+++ b/contrib/ntp/ntpd/ntp_intres.c
@@ -15,6 +15,11 @@
* might go about autoconfiguring an NTP distribution network.
*
*/
+ /*
+ * For special situations define the FORCE_DNSRETRY Macro
+ * to force retries even if it fails the lookup.
+ * Use with extreme caution since it will then retry forever.
+ */
#ifdef HAVE_CONFIG_H
# include <config.h>
@@ -29,7 +34,6 @@
#include <stdio.h>
#include <ctype.h>
-#include <netdb.h>
#include <signal.h>
/**/
@@ -40,6 +44,9 @@
# include <sys/param.h> /* MAXHOSTNAMELEN (often) */
#endif
+#include <isc/net.h>
+#include <isc/result.h>
+
#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
/*
@@ -135,7 +142,6 @@ char *req_file; /* name of the file with configuration info */
/* end stuff to be filled in */
-static RETSIGTYPE bong P((int));
static void checkparent P((void));
static void removeentry P((struct conf_entry *));
static void addentry P((char *, int, int, int, int, u_int,
@@ -167,6 +173,23 @@ struct ntp_res_c_pkt { /* Control packet: */
};
+static void resolver_exit P((int));
+
+/*
+ * Call here instead of just exiting
+ */
+
+static void resolver_exit (int code)
+{
+#ifdef SYS_WINNT
+ CloseHandle(ResolverEventHandle);
+ ResolverEventHandle = NULL;
+ ExitThread(code); /* Just to kill the thread not the process */
+#else
+ exit(code); /* kill the forked process */
+#endif
+}
+
/*
* ntp_res_recv: Process an answer from the resolver
*/
@@ -193,11 +216,13 @@ void
ntp_intres(void)
{
FILE *in;
-#ifdef HAVE_SIGSUSPEND
- sigset_t set;
-
- sigemptyset(&set);
-#endif /* HAVE_SIGSUSPEND */
+ struct timeval tv;
+ fd_set fdset;
+#ifdef SYS_WINNT
+ DWORD rc;
+#else
+ int rc;
+#endif
#ifdef DEBUG
if (debug > 1) {
@@ -210,7 +235,7 @@ ntp_intres(void)
if (!authistrusted(req_keyid)) {
msyslog(LOG_ERR, "invalid request keyid %08x",
req_keyid );
- exit(1);
+ resolver_exit(1);
}
}
@@ -222,106 +247,93 @@ ntp_intres(void)
if ((in = fopen(req_file, "r")) == NULL) {
msyslog(LOG_ERR, "can't open configuration file %s: %m",
req_file);
- exit(1);
+ resolver_exit(1);
}
readconf(in, req_file);
(void) fclose(in);
+#ifdef DEBUG
if (!debug )
+#endif
(void) unlink(req_file);
/*
- * Sleep a little to make sure the server is completely up
- */
-
- sleep(SLEEPTIME);
-
- /*
- * Make a first cut at resolving the bunch
- */
- doconfigure(1);
- if (confentries == NULL) {
-#if defined SYS_WINNT
- ExitThread(0); /* Don't want to kill whole NT process */
-#else
- exit(0); /* done that quick */
-#endif
- }
-
- /*
- * Here we've got some problem children. Set up the timer
- * and wait for it.
+ * Set up the timers to do first shot immediately.
*/
- resolve_value = resolve_timer = MINRESOLVE;
+ resolve_timer = 0;
+ resolve_value = MINRESOLVE;
config_timer = CONFIG_TIME;
-#ifndef SYS_WINNT
- (void) signal_no_reset(SIGALRM, bong);
- alarm(ALARM_TIME);
-#endif /* SYS_WINNT */
for (;;) {
- if (confentries == NULL)
- exit(0);
-
checkparent();
if (resolve_timer == 0) {
- if (resolve_value < MAXRESOLVE)
- resolve_value <<= 1;
+ /*
+ * Sleep a little to make sure the network is completely up
+ */
+ sleep(SLEEPTIME);
+ doconfigure(1);
+
+ /* prepare retry, in case there's more work to do */
resolve_timer = resolve_value;
#ifdef DEBUG
if (debug > 2)
msyslog(LOG_INFO, "resolve_timer: 0->%d", resolve_timer);
#endif
+ if (resolve_value < MAXRESOLVE)
+ resolve_value <<= 1;
+
config_timer = CONFIG_TIME;
- doconfigure(1);
- continue;
- } else if (config_timer == 0) {
+ } else if (config_timer == 0) { /* MB: in which case would this be required ? */
+ doconfigure(0);
+ /* MB: should we check now if we could exit, similar to the code above? */
config_timer = CONFIG_TIME;
#ifdef DEBUG
if (debug > 2)
msyslog(LOG_INFO, "config_timer: 0->%d", config_timer);
#endif
- doconfigure(0);
+ }
+
+ if (confentries == NULL)
+ resolver_exit(0); /* done */
+
+#ifdef SYS_WINNT
+ rc = WaitForSingleObject(ResolverEventHandle, 1000 * ALARM_TIME); /* in milliseconds */
+
+ if ( rc == WAIT_OBJECT_0 ) { /* signaled by the main thread */
+ resolve_timer = 0; /* retry resolving immediately */
continue;
}
-#ifndef SYS_WINNT
- /*
- * There is a race in here. Is okay, though, since
- * all it does is delay things by 30 seconds.
- */
-# ifdef HAVE_SIGSUSPEND
- sigsuspend(&set);
-# else
- sigpause(0);
-# endif /* HAVE_SIGSUSPEND */
-#else
+
+ if ( rc != WAIT_TIMEOUT ) /* not timeout: error */
+ resolver_exit(1);
+
+#else /* not SYS_WINNT */
+ tv.tv_sec = ALARM_TIME;
+ tv.tv_usec = 0;
+ FD_ZERO(&fdset);
+ FD_SET(resolver_pipe_fd[0], &fdset);
+ rc = select(resolver_pipe_fd[0] + 1, &fdset, (fd_set *)0, (fd_set *)0, &tv);
+
+ if (rc > 0) { /* parent process has written to the pipe */
+ read(resolver_pipe_fd[0], (char *)&rc, sizeof(rc)); /* make pipe empty */
+ resolve_timer = 0; /* retry resolving immediately */
+ continue;
+ }
+
+ if ( rc < 0 ) /* select() returned error */
+ resolver_exit(1);
+#endif
+
+ /* normal timeout, keep on waiting */
if (config_timer > 0)
- config_timer--;
+ config_timer--;
if (resolve_timer > 0)
- resolve_timer--;
- sleep(ALARM_TIME);
-#endif /* SYS_WINNT */
+ resolve_timer--;
}
}
-#ifndef SYS_WINNT
-/*
- * bong - service and reschedule an alarm() interrupt
- */
-static RETSIGTYPE
-bong(
- int sig
- )
-{
- if (config_timer > 0)
- config_timer--;
- if (resolve_timer > 0)
- resolve_timer--;
- alarm(ALARM_TIME);
-}
-#endif /* SYS_WINNT */
/*
* checkparent - see if our parent process is still running
@@ -344,7 +356,7 @@ checkparent(void)
*/
if (getppid() == 1) {
msyslog(LOG_INFO, "parent died before we finished, exiting");
- exit(0);
+ resolver_exit(0);
}
#endif /* SYS_WINNT && SYS_VXWORKS*/
}
@@ -411,7 +423,9 @@ addentry(
ce = (struct conf_entry *)emalloc(sizeof(struct conf_entry));
ce->ce_name = cp;
ce->ce_peeraddr = 0;
+#ifdef ISC_PLATFORM_HAVEIPV6
ce->ce_peeraddr6 = in6addr_any;
+#endif
ANYSOCK(&ce->peer_store);
ce->ce_hmode = (u_char)mode;
ce->ce_version = (u_char)version;
@@ -450,17 +464,18 @@ findhostaddr(
)
{
struct addrinfo *addr;
+ struct addrinfo hints;
int error;
checkparent(); /* make sure our guy is still running */
- if (entry->ce_name != NULL && SOCKNUL(&entry->peer_store)) {
+ if (entry->ce_name != NULL && !SOCKNUL(&entry->peer_store)) {
/* HMS: Squawk? */
msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are defined...");
return 1;
}
- if (entry->ce_name == NULL && !SOCKNUL(&entry->peer_store)) {
+ if (entry->ce_name == NULL && SOCKNUL(&entry->peer_store)) {
msyslog(LOG_ERR, "findhostaddr: both ce_name and ce_peeraddr are undefined!");
return 0;
}
@@ -471,7 +486,16 @@ findhostaddr(
msyslog(LOG_INFO, "findhostaddr: Resolving <%s>",
entry->ce_name);
#endif /* DEBUG */
- error = getaddrinfo(entry->ce_name, NULL, NULL, &addr);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ /*
+ * If the IPv6 stack is not available look only for IPv4 addresses
+ */
+ if (isc_net_probeipv6() != ISC_R_SUCCESS)
+ hints.ai_family = AF_INET;
+
+ error = getaddrinfo(entry->ce_name, NULL, &hints, &addr);
if (error == 0) {
entry->peer_store = *((struct sockaddr_storage*)(addr->ai_addr));
if (entry->peer_store.ss_family == AF_INET) {
@@ -484,6 +508,10 @@ findhostaddr(
entry->ce_config.v6_flag = 1;
}
}
+ else if (error == EAI_NONAME)
+ {
+ msyslog(LOG_ERR, "host name not found: %s", entry->ce_name);
+ }
} else {
#ifdef DEBUG
if (debug > 2)
@@ -496,15 +524,37 @@ findhostaddr(
(char *)&entry->ce_name, MAXHOSTNAMELEN,
NULL, 0, 0);
}
+#ifdef DEBUG
+ if (debug > 2)
+ printf("intres: got error status of: %d\n", error);
+#endif
+ /*
+ * If the resolver failed, see if the failure is
+ * temporary. If so, return success.
+ */
if (error != 0) {
- /*
- * If the resolver is in use, see if the failure is
- * temporary. If so, return success.
- */
- if (h_errno == TRY_AGAIN)
- return (1);
- return (0);
+ switch (error)
+ {
+ case EAI_AGAIN:
+ return (1);
+ case EAI_NONAME:
+#ifndef FORCE_DNSRETRY
+ return (0);
+#else
+ return (1);
+#endif
+#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
+ case EAI_NODATA:
+#endif
+ case EAI_FAIL:
+#ifdef EAI_SYSTEM
+ case EAI_SYSTEM:
+ return (1);
+#endif
+ default:
+ return (0);
+ }
}
if (entry->ce_name) {
@@ -531,22 +581,28 @@ openntp(void)
{
struct addrinfo hints;
struct addrinfo *addrResult;
+ const char *localhost = "127.0.0.1"; /* Use IPv6 loopback */
- if (sockfd >= 0)
+ if (sockfd != INVALID_SOCKET)
return;
memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_UNSPEC;
+
+ /*
+ * For now only bother with IPv4
+ */
+ hints.ai_family = AF_INET;
+
hints.ai_socktype = SOCK_DGRAM;
- if (getaddrinfo(NULL, "ntp", &hints, &addrResult)!=0) {
+ if (getaddrinfo(localhost, "ntp", &hints, &addrResult)!=0) {
msyslog(LOG_ERR, "getaddrinfo failed: %m");
- exit(1);
+ resolver_exit(1);
}
sockfd = socket(addrResult->ai_family, addrResult->ai_socktype, 0);
if (sockfd == -1) {
msyslog(LOG_ERR, "socket() failed: %m");
- exit(1);
+ resolver_exit(1);
}
/*
@@ -556,13 +612,13 @@ openntp(void)
#if defined(O_NONBLOCK)
if (fcntl(sockfd, F_SETFL, O_NONBLOCK) == -1) {
msyslog(LOG_ERR, "fcntl(O_NONBLOCK) failed: %m");
- exit(1);
+ resolver_exit(1);
}
#else
#if defined(FNDELAY)
if (fcntl(sockfd, F_SETFL, FNDELAY) == -1) {
msyslog(LOG_ERR, "fcntl(FNDELAY) failed: %m");
- exit(1);
+ resolver_exit(1);
}
#else
# include "Bletch: NEED NON BLOCKING IO"
@@ -573,13 +629,13 @@ openntp(void)
int on = 1;
if (ioctlsocket(sockfd,FIONBIO,(u_long *) &on) == SOCKET_ERROR) {
msyslog(LOG_ERR, "ioctlsocket(FIONBIO) fails: %m");
- exit(1); /* Windows NT - set socket in non-blocking mode */
+ resolver_exit(1); /* Windows NT - set socket in non-blocking mode */
}
}
#endif /* SYS_WINNT */
if (connect(sockfd, addrResult->ai_addr, addrResult->ai_addrlen) == -1) {
msyslog(LOG_ERR, "openntp: connect() failed: %m");
- exit(1);
+ resolver_exit(1);
}
freeaddrinfo(addrResult);
}
@@ -607,7 +663,7 @@ request(
checkparent(); /* make sure our guy is still running */
- if (sockfd < 0)
+ if (sockfd == INVALID_SOCKET)
openntp();
#ifdef SYS_WINNT
@@ -643,7 +699,7 @@ request(
/* Make sure mbz_itemsize <= sizeof reqpkt.data */
if (sizeof(struct conf_peer) > sizeof (reqpkt.data)) {
msyslog(LOG_ERR, "Bletch: conf_peer is too big for reqpkt.data!");
- exit(1);
+ resolver_exit(1);
}
memmove(reqpkt.data, (char *)conf, sizeof(struct conf_peer));
reqpkt.keyid = htonl(req_keyid);
@@ -678,7 +734,7 @@ request(
overlap.Offset = overlap.OffsetHigh = (DWORD)0;
overlap.hEvent = hReadWriteEvent;
ret = WriteFile((HANDLE)sockfd, (char *)&reqpkt, REQ_LEN_NOMAC + n,
- (LPDWORD)&NumberOfBytesWritten, (LPOVERLAPPED)&overlap);
+ NULL, (LPOVERLAPPED)&overlap);
if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) {
msyslog(LOG_ERR, "send to NTP server failed: %m");
return 0;
@@ -689,6 +745,11 @@ request(
msyslog(LOG_ERR, "WaitForSingleObject failed: %m");
return 0;
}
+ if (!GetOverlappedResult((HANDLE)sockfd, (LPOVERLAPPED)&overlap,
+ (LPDWORD)&NumberOfBytesWritten, FALSE)) {
+ msyslog(LOG_ERR, "GetOverlappedResult for WriteFile fails: %m");
+ return 0;
+ }
#endif /* SYS_WINNT */
@@ -718,8 +779,10 @@ request(
}
else if (n == 0)
{
+#ifdef DEBUG
if (debug)
msyslog(LOG_INFO, "select() returned 0.");
+#endif
return 0;
}
@@ -734,7 +797,7 @@ request(
}
#else /* Overlapped I/O used on non-blocking sockets on Windows NT */
ret = ReadFile((HANDLE)sockfd, (char *)&reqpkt, (DWORD)REQ_LEN_MAC,
- (LPDWORD)&NumberOfBytesRead, (LPOVERLAPPED)&overlap);
+ NULL, (LPOVERLAPPED)&overlap);
if ((ret == FALSE) && (GetLastError() != ERROR_IO_PENDING)) {
msyslog(LOG_ERR, "ReadFile() fails: %m");
return 0;
@@ -742,11 +805,16 @@ request(
dwWait = WaitForSingleObject(hReadWriteEvent, (DWORD) TIMEOUT_SEC * 1000);
if ((dwWait == WAIT_FAILED) || (dwWait == WAIT_TIMEOUT)) {
if (dwWait == WAIT_FAILED) {
- msyslog(LOG_ERR, "WaitForSingleObject fails: %m");
+ msyslog(LOG_ERR, "WaitForSingleObject for ReadFile fails: %m");
return 0;
}
continue;
}
+ if (!GetOverlappedResult((HANDLE)sockfd, (LPOVERLAPPED)&overlap,
+ (LPDWORD)&NumberOfBytesRead, FALSE)) {
+ msyslog(LOG_ERR, "GetOverlappedResult fails: %m");
+ return 0;
+ }
n = NumberOfBytesRead;
#endif /* SYS_WINNT */
@@ -941,7 +1009,7 @@ readconf(
msyslog(LOG_ERR,
"tokenizing error in file `%s', quitting",
name);
- exit(1);
+ resolver_exit(1);
}
}
@@ -950,7 +1018,7 @@ readconf(
msyslog(LOG_ERR,
"format error for integer token `%s', file `%s', quitting",
token[i], name);
- exit(1);
+ resolver_exit(1);
}
}
@@ -959,27 +1027,27 @@ readconf(
intval[TOK_HMODE] != MODE_BROADCAST) {
msyslog(LOG_ERR, "invalid mode (%ld) in file %s",
intval[TOK_HMODE], name);
- exit(1);
+ resolver_exit(1);
}
if (intval[TOK_VERSION] > NTP_VERSION ||
intval[TOK_VERSION] < NTP_OLDVERSION) {
msyslog(LOG_ERR, "invalid version (%ld) in file %s",
intval[TOK_VERSION], name);
- exit(1);
+ resolver_exit(1);
}
if (intval[TOK_MINPOLL] < NTP_MINPOLL ||
intval[TOK_MINPOLL] > NTP_MAXPOLL) {
msyslog(LOG_ERR, "invalid MINPOLL value (%ld) in file %s",
intval[TOK_MINPOLL], name);
- exit(1);
+ resolver_exit(1);
}
if (intval[TOK_MAXPOLL] < NTP_MINPOLL ||
intval[TOK_MAXPOLL] > NTP_MAXPOLL) {
msyslog(LOG_ERR, "invalid MAXPOLL value (%ld) in file %s",
intval[TOK_MAXPOLL], name);
- exit(1);
+ resolver_exit(1);
}
if ((intval[TOK_FLAGS] & ~(FLAG_AUTHENABLE | FLAG_PREFER |
@@ -987,7 +1055,7 @@ readconf(
!= 0) {
msyslog(LOG_ERR, "invalid flags (%ld) in file %s",
intval[TOK_FLAGS], name);
- exit(1);
+ resolver_exit(1);
}
flags = 0;
@@ -1026,6 +1094,12 @@ doconfigure(
register struct conf_entry *ce;
register struct conf_entry *ceremove;
+#ifdef DEBUG
+ if (debug > 1)
+ msyslog(LOG_INFO, "Running doconfigure %s DNS",
+ dores ? "with" : "without" );
+#endif
+
ce = confentries;
while (ce != NULL) {
#ifdef DEBUG
@@ -1034,7 +1108,7 @@ doconfigure(
"doconfigure: <%s> has peeraddr %s",
ce->ce_name, stoa(&ce->peer_store));
#endif
- if (dores && !SOCKNUL(&(ce->peer_store))) {
+ if (dores && SOCKNUL(&(ce->peer_store))) {
if (!findhostaddr(ce)) {
msyslog(LOG_ERR,
"couldn't resolve `%s', giving up on it",
OpenPOWER on IntegriCloud