---
 src/dnsmasq.c        | 10 +++++++---
 src/dnsmasq.h        |  1 +
 src/hash-questions.c |  2 ++
 src/util.c           | 47 +++++++++++++++++++++++++++++++++++---------
 4 files changed, 48 insertions(+), 12 deletions(-)

diff --git src/dnsmasq.c src/dnsmasq.c
index d15177f8..68c290a3 100644
--- src/dnsmasq.c
+++ src/dnsmasq.c
@@ -41,7 +41,7 @@ static void tcp_init(void);
 
 int main (int argc, char **argv)
 {
-  time_t now;
+  time_t now = dnsmasq_time(), reseed_hshqs = 0, reseed_rand = 0;
   struct sigaction sigact;
   struct iname *if_tmp;
   int piperead, pipefd[2], err_pipe[2];
@@ -101,7 +101,7 @@ int main (int argc, char **argv)
 
   umask(022); /* known umask, create leases and pid files as 0644 */
 
-  rand_init(); /* Must precede read_opts() */
+  rand_init(), reseed_rand = now; /* Must precede read_opts() */
   
   read_opts(argc, argv, compile_opts);
  
@@ -410,7 +410,7 @@ int main (int argc, char **argv)
     {
       cache_init();
       blockdata_init();
-      hash_questions_init();
+      hash_questions_init(), reseed_hshqs = now;
 
       /* Scale random socket pool by ftabsize, but
         limit it based on available fds. */
@@ -1169,6 +1169,10 @@ int main (int argc, char **argv)
 
 #endif
 
+      if (should_reseed(reseed_rand, now))
+       rand_init(), reseed_rand = now;
+      if (daemon->port != 0 && !daemon->frec_list && 
should_reseed(reseed_hshqs, now))
+       hash_questions_init(), reseed_hshqs = now;
    
       /* must do this just before do_poll(), when we know no
         more calls to my_syslog() can occur */
diff --git src/dnsmasq.h src/dnsmasq.h
index ff926bf8..65c458e9 100644
--- src/dnsmasq.h
+++ src/dnsmasq.h
@@ -1455,6 +1455,7 @@ void rand_init(void);
 unsigned short rand16(void);
 u32 rand32(void);
 u64 rand64(void);
+unsigned int should_reseed(time_t last, time_t now);
 int rr_on_list(struct rrlist *list, unsigned short rr);
 int legal_hostname(char *name);
 char *canonicalise(char *in, int *nomem);
diff --git src/hash-questions.c src/hash-questions.c
index e6304ac8..b7731c06 100644
--- src/hash-questions.c
+++ src/hash-questions.c
@@ -36,6 +36,8 @@ static unsigned char *digest;
 
 void hash_questions_init(void)
 {
+  if (ctx)
+    return;
   if (!(hash = hash_find("sha256")))
     die(_("Failed to create SHA-256 hash object"), NULL, EC_MISC);
 
diff --git src/util.c src/util.c
index 28b9c6d2..1631328c 100644
--- src/util.c
+++ src/util.c
@@ -19,6 +19,7 @@
 
 
 #include "dnsmasq.h"
+#include <stdbool.h>
 
 #ifdef HAVE_BROKEN_RTC
 #include <sys/times.h>
@@ -53,27 +54,42 @@ static int getentropy_fallback(void *buffer, size_t length)
 
 /* SURF random number generator */
 
-static u32 seed[32];
-static u32 in[12];
+static struct surf_state {
+  u32 seed[32];
+  u32 in[12];
+} surfst;
 static u32 out[8];
 static int outleft = 0;
 
 void rand_init()
 {
-  if (getentropy(&seed, sizeof(seed)) + getentropy(&in, sizeof(in)) < 0)
-    die(_("failed to seed the random number generator: %s"), NULL, EC_MISC);
+  const u32 * const in = surfst.in;
+  const bool reseed = in[0] || in[1] || in[2] || in[3] || in[4] || in[5] ||
+                      in[6] || in[7] || in[8] || in[9] || in[10] || in[11];
+  struct surf_state next;
+  const unsigned bytes = reseed ? sizeof(next.seed) : sizeof(next);
+  if (getentropy(&next, bytes) != 0)
+    {
+      if (!reseed)
+       die(_("failed to seed the random number generator: %s"), NULL, EC_MISC);
+      else
+       my_syslog(LOG_ERR, _("failed to reseed the random number generator: 
%s"), strerror(errno));
+    }
+  _Static_assert(surfst.in == surfst.seed + countof(surfst.seed)); // No weird 
alignment gaps.
+  for (unsigned int i = 0; i < bytes / sizeof(next.seed[0]); i++)
+    surfst.seed[i] ^= next.seed[i];
 }
 
 static void rand_atfork(pid_t fpid)
 {
-  u32 next[countof(seed)];
-  for (unsigned int i = 0; i < countof(seed); i++)
-    next[i] = rand32();
+  struct surf_state next;
+  for (unsigned int i = 0; i < countof(next.seed); i++)
+    next.seed[i] = rand32();
   // Child reseeds the state with generated values.  Parent skips those values 
explicitly as they
   // might be exposed to an external observer and used to guess something 
about PRNG of the child.
   if (fpid == 0)
-    for (unsigned int i = 0; i < countof(seed); i++)
-      seed[i] ^= next[i];
+    for (unsigned int i = 0; i < countof(next.seed); i++)
+      surfst.seed[i] ^= next.seed[i];
 }
 
 #define ROTATE(x,b) (((x) << (b)) | ((x) >> (32 - (b))))
@@ -81,6 +97,8 @@ static void rand_atfork(pid_t fpid)
 
 static void surf(void)
 {
+  u32 * const in = surfst.in;
+  const u32 * const seed = surfst.seed;
   u32 t[12]; u32 x; u32 sum = 0;
   int r; int i; int loop;
 
@@ -124,6 +142,17 @@ u64 rand64(void)
   return (u64)out[outleft+1] + (((u64)out[outleft]) << 32);
 }
 
+// Reseeding hourly to avoid low-entropy condition right after boot that is 
somewhat possible
+// in the embedded world. dnsmasq boxes often lack of RTC clocks and/or 
observe clock jumps
+// due to NTP during boot. So, "hourly" is an approximated as "once in 4096 
seconds".
+unsigned int should_reseed(time_t last, time_t now)
+{
+  static u16 offset;
+  if (!offset)
+    offset = 1 + (rand16() & 4095);
+  return ((last + offset) >> 12) != ((now + offset) >> 12);
+}
+
 int rr_on_list(struct rrlist *list, unsigned short rr)
 {
   while (list)
-- 
2.34.1


_______________________________________________
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss

Reply via email to