[PATCH] ntpd: improve postponed hostname resolution

Natanael Copa ncopa at alpinelinux.org
Fri Jan 6 11:13:23 UTC 2017


Run the namelookup from the main loop so a misspelled first ntp server
name does not block everything forever.

This fixes the following situation which would block forever:
  $ sudo ./busybox ntpd -dn -p foobar  -p pool.ntp.org
  ntpd: bad address 'foobar'
  ntpd: bad address 'foobar'
  ntpd: bad address 'foobar'
  ...

This patch is based on Kaarle Ritvanens work.
http://lists.busybox.net/pipermail/busybox/2016-May/084197.html

function                                             old     new   delta
static.set_next                                        -      23     +23
step_time                                            426     422      -4
recv_and_process_peer_pkt                           2342    2338      -4
ntpd_main                                           1178    1171      -7
add_peers                                            229     217     -12
resolve_peer_hostname                                102      88     -14
.rodata                                           125081  125065     -16
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 0/6 up/down: 23/-57)            Total: -34
bytes
   text	   data	    bss	    dec	    hex	filename
 802129	  15459	   2192	 819780	  c8244	busybox_old
 802095	  15459	   2192	 819746	  c8222	busybox_unstripped

Signed-off-by: Kaarle Ritvanen <kaarle.ritvanen at datakunkku.fi>
Signed-off-by: Natanael Copa <ncopa at alpinelinux.org>
---
 networking/ntpd.c | 71 ++++++++++++++++++++++++++-----------------------------
 1 file changed, 33 insertions(+), 38 deletions(-)

diff --git a/networking/ntpd.c b/networking/ntpd.c
index b7fa5dce9..97e3919fb 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -155,6 +155,7 @@
 #define RETRY_INTERVAL    32    /* on send/recv error, retry in N secs (need to be power of 2) */
 #define NOREPLY_INTERVAL 512    /* sent, but got no reply: cap next query by this many seconds */
 #define RESPONSE_INTERVAL 16    /* wait for reply up to N secs */
+#define HOSTNAME_INTERVAL  4    /* hostname lookup failed. Wait N secs for next try */
 
 /* Step threshold (sec). std ntpd uses 0.128.
  */
@@ -293,6 +294,7 @@ typedef struct {
 
 typedef struct {
 	len_and_sockaddr *p_lsa;
+	char             *p_hostname;
 	char             *p_dotted;
 	int              p_fd;
 	int              datapoint_idx;
@@ -318,7 +320,6 @@ typedef struct {
 	datapoint_t      filter_datapoint[NUM_DATAPOINTS];
 	/* last sent packet: */
 	msg_t            p_xmt_msg;
-	char             p_hostname[1];
 } peer_t;
 
 
@@ -791,27 +792,17 @@ reset_peer_stats(peer_t *p, double offset)
 }
 
 static void
-resolve_peer_hostname(peer_t *p, int loop_on_fail)
-{
-	len_and_sockaddr *lsa;
-
- again:
-	lsa = host2sockaddr(p->p_hostname, 123);
-	if (!lsa) {
-		/* error message already emitted by host2sockaddr() */
-		if (!loop_on_fail)
-			return;
-//FIXME: do this to avoid infinite looping on typo in a hostname?
-//well... in which case, what is a good value for loop_on_fail?
-		//if (--loop_on_fail == 0)
-		//	xfunc_die();
-		sleep(5);
-		goto again;
+resolve_peer_hostname(peer_t *p) {
+	len_and_sockaddr *lsa = host2sockaddr(p->p_hostname, 123);
+	if (lsa) {
+		if (p->p_lsa) {
+			free(p->p_lsa);
+			free(p->p_dotted);
+		}
+		p->p_lsa = lsa;
+		p->p_dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
 	}
-	free(p->p_lsa);
-	free(p->p_dotted);
-	p->p_lsa = lsa;
-	p->p_dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
+	set_next(p, lsa ? 0 : HOSTNAME_INTERVAL);
 }
 
 static void
@@ -820,28 +811,29 @@ add_peers(const char *s)
 	llist_t *item;
 	peer_t *p;
 
-	p = xzalloc(sizeof(*p) + strlen(s));
-	strcpy(p->p_hostname, s);
-	resolve_peer_hostname(p, /*loop_on_fail=*/ 1);
+	p = xzalloc(sizeof(*p));
+	p->p_hostname = xstrdup(s);
+	resolve_peer_hostname(p);
 
 	/* Names like N.<country2chars>.pool.ntp.org are randomly resolved
 	 * to a pool of machines. Sometimes different N's resolve to the same IP.
 	 * It is not useful to have two peers with same IP. We skip duplicates.
 	 */
-	for (item = G.ntp_peers; item != NULL; item = item->link) {
-		peer_t *pp = (peer_t *) item->data;
-		if (strcmp(p->p_dotted, pp->p_dotted) == 0) {
-			bb_error_msg("duplicate peer %s (%s)", s, p->p_dotted);
-			free(p->p_lsa);
-			free(p->p_dotted);
-			free(p);
-			return;
+	if (p->p_lsa)
+		for (item = G.ntp_peers; item != NULL; item = item->link) {
+			peer_t *pp = (peer_t *) item->data;
+			if (pp->p_lsa && strcmp(p->p_dotted, pp->p_dotted) == 0) {
+				bb_error_msg("duplicate peer %s (%s)", s, p->p_dotted);
+				free(p->p_hostname);
+				free(p->p_lsa);
+				free(p->p_dotted);
+				free(p);
+				return;
+			}
 		}
-	}
 
 	p->p_fd = -1;
 	p->p_xmt_msg.m_status = MODE_CLIENT | (NTP_VERSION << 3);
-	p->next_action_time = G.cur_time; /* = set_next(p, 0); */
 	reset_peer_stats(p, STEP_THRESHOLD);
 
 	llist_add_to(&G.ntp_peers, p);
@@ -2263,8 +2255,8 @@ static NOINLINE void ntp_init(char **argv)
 	if (opts & OPT_N)
 		setpriority(PRIO_PROCESS, 0, -15);
 
-	/* add_peers() calls can retry DNS resolution (possibly forever).
-	 * Daemonize before them, or else boot can stall forever.
+	/* add_peers() calls can retry DNS resolution.
+	 * Daemonize before them, or else boot can stall.
 	 */
 	if (!(opts & OPT_n)) {
 		bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO, argv);
@@ -2378,7 +2370,10 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
 		for (item = G.ntp_peers; item != NULL; item = item->link) {
 			peer_t *p = (peer_t *) item->data;
 
-			if (p->next_action_time <= G.cur_time) {
+			if (!p->p_lsa) {
+				resolve_peer_hostname(p);
+
+			} else if (p->next_action_time <= G.cur_time) {
 				if (p->p_fd == -1) {
 					/* Time to send new req */
 					if (--cnt == 0) {
@@ -2400,7 +2395,7 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv)
 
 					/* What if don't see it because it changed its IP? */
 					if (p->reachable_bits == 0)
-						resolve_peer_hostname(p, /*loop_on_fail=*/ 0);
+						resolve_peer_hostname(p);
 
 					set_next(p, timeout);
 				}
-- 
2.11.0



More information about the busybox mailing list