]> granicus.if.org Git - pdns/commitdiff
pdns: Implement new dns_random
authorAki Tuomi <cmouse@cmouse.fi>
Mon, 5 Feb 2018 07:32:13 +0000 (09:32 +0200)
committerAki Tuomi <cmouse@cmouse.fi>
Wed, 11 Apr 2018 17:37:56 +0000 (20:37 +0300)
Adds new setting rng, which can be set to choose particular rng

25 files changed:
configure.ac
docs/settings.rst
m4/pdns_enable_kiss.m4 [new file with mode: 0644]
modules/remotebackend/Makefile.am
pdns/Makefile.am
pdns/common_startup.cc
pdns/dns_random.cc
pdns/dns_random.hh
pdns/dns_random_urandom.cc [new file with mode: 0644]
pdns/ixplore.cc
pdns/misc.hh
pdns/pdns_recursor.cc
pdns/pdnsutil.cc
pdns/randomhelper.cc [deleted file]
pdns/receiver.cc
pdns/recursordist/Makefile.am
pdns/recursordist/configure.ac
pdns/recursordist/dns_random_urandom.cc [new symlink]
pdns/recursordist/docs/settings.rst
pdns/recursordist/randomhelper.cc [deleted symlink]
pdns/recursordist/test-syncres_cc.cc
pdns/saxfr.cc
pdns/stubquery.cc
pdns/test-dns_random_hh.cc
pdns/tsig-tests.cc

index 778ddbf5d8b802256705bcf84c710a70e61590f7..f28e57d62c4c88991008d0a751525b2d55ad5e95 100644 (file)
@@ -64,6 +64,8 @@ AS_IF([test "x$enable_hardening" != "xno"], [
   AC_LD_RELRO
 ])
 
+PDNS_ENABLE_KISS
+
 PDNS_CHECK_NETWORK_LIBS
 
 LT_PREREQ([2.2.2])
index 6b26758d366a5d441cf4e377ca8e7b2764815ddb..6fb06cd24e00081329da2fc2893f48bc59298fa8 100644 (file)
@@ -1005,6 +1005,25 @@ or may not be a good idea. You could use this to enable transparent
 restarts, but it may also mask configuration issues and for this reason
 it is disabled by default.
 
+.. _setting-rng:
+``rng``
+-------
+
+- String
+- Default: auto
+
+Specify which random number generator to use. Permissible choises are
+ - auto - choose automatically
+ - sodium - Use libsodium ``randombytes_uniform``
+ - openssl - Use libcrypto ``RAND_bytes``
+ - getrandom - Use libc getrandom, falls back to urandom if it does not really work
+ - arc4random - Use BSD ``arc4random_uniform``
+ - urandom - Use ``/dev/urandom``
+ - kiss - Use simple settable deterministic RNG. **FOR TESTING PURPOSES ONLY!**
+
+.. note::
+  Not all choises are available on all systems.
+
 .. _setting-security-poll-suffix:
 
 ``security-poll-suffix``
diff --git a/m4/pdns_enable_kiss.m4 b/m4/pdns_enable_kiss.m4
new file mode 100644 (file)
index 0000000..1f882d9
--- /dev/null
@@ -0,0 +1,7 @@
+AC_DEFUN([PDNS_ENABLE_KISS], [
+  AC_ARG_ENABLE([unsafe-rng-kiss],
+    AS_HELP_STRING([--enable-unsafe-rng-kiss],
+      [Enable unsafe rng KISS]), [
+        AC_DEFINE([HAVE_KISS_RNG], [1], [Define to 1 to enable unsafe rng KISS])
+  ])
+])
index cfbf6f164031fcb8139ac2fe76327e6b03d209e2..e106047624b284c494cf94acea7b3ae4ccfb7bad 100644 (file)
@@ -118,7 +118,7 @@ libtestremotebackend_la_SOURCES = \
        ../../pdns/statbag.cc \
        ../../pdns/ueberbackend.hh ../../pdns/ueberbackend.cc \
        ../../pdns/dns.hh ../../pdns/dns.cc \
-       ../../pdns/dns_random.cc \
+       ../../pdns/dns_random_urandom.cc \
        ../../pdns/dnswriter.cc \
        ../../pdns/nameserver.cc \
        ../../pdns/rcpgenerator.cc \
index ab2f39874f499890b304898601df068e2e7efe95..97f47901b9d28b915b351ca9b6df65c5f4de8c46 100644 (file)
@@ -195,7 +195,6 @@ pdns_server_SOURCES = \
        packethandler.cc packethandler.hh \
        pdnsexception.hh \
        qtype.cc qtype.hh \
-       randomhelper.cc \
        rcpgenerator.cc \
        receiver.cc \
        resolver.cc resolver.hh \
@@ -312,7 +311,6 @@ pdnsutil_SOURCES = \
        opensslsigners.cc opensslsigners.hh \
        pdnsutil.cc \
        qtype.cc \
-       randomhelper.cc \
        rcpgenerator.cc rcpgenerator.hh \
        serialtweaker.cc \
        signingpipe.cc \
@@ -386,7 +384,7 @@ zone2sql_SOURCES = \
        bindparser.yy \
        bindparserclasses.hh \
        dns.cc \
-       dns_random.cc \
+       dns_random_urandom.cc \
        dnsname.cc dnsname.hh \
        dnslabeltext.cc \
        dnsparser.cc \
@@ -450,7 +448,7 @@ zone2ldap_SOURCES = \
        bindlexer.l \
        bindparser.yy \
        bindparserclasses.hh \
-       dns_random.cc \
+       dns_random_urandom.cc \
        dnsname.cc dnsname.hh \
        dnslabeltext.cc \
        dnsparser.cc \
@@ -498,7 +496,7 @@ calidns_SOURCES = \
        base32.cc \
        base64.cc base64.hh \
        calidns.cc \
-       dns_random.cc dns_random.hh \
+       dns_random_urandom.cc dns_random.hh \
        dnslabeltext.cc \
        dnsname.cc dnsname.hh \
        dnsparser.cc dnsparser.hh \
@@ -545,7 +543,7 @@ stubquery_SOURCES = \
        arguments.cc arguments.hh \
        base32.cc \
        base64.cc \
-       dns_random.cc \
+       dns_random_urandom.cc \
        dnslabeltext.cc \
        dnsname.cc \
        dnsparser.cc \
@@ -568,7 +566,7 @@ stubquery_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS)
 saxfr_SOURCES = \
        base32.cc \
        base64.cc base64.hh \
-       dns_random.cc dns_random.hh \
+       dns_random_urandom.cc dns_random.hh \
        dnslabeltext.cc \
        dnsname.cc dnsname.hh \
        dnsparser.cc dnsparser.hh \
@@ -604,7 +602,7 @@ ixfrdist_SOURCES = \
        base32.cc \
        base64.cc base64.hh \
        dns.cc \
-       dns_random.cc dns_random.hh \
+       dns_random_urandom.cc dns_random.hh \
        dnslabeltext.cc \
        dnsname.cc dnsname.hh \
        dnsparser.cc dnsparser.hh \
@@ -654,7 +652,7 @@ ixplore_SOURCES = \
        base32.cc \
        base64.cc base64.hh \
        dns.cc \
-       dns_random.cc dns_random.hh \
+       dns_random_urandom.cc dns_random.hh \
        dnslabeltext.cc \
        dnsname.cc dnsname.hh \
        dnsparser.cc dnsparser.hh \
@@ -754,7 +752,7 @@ endif
 toysdig_SOURCES = \
        base32.cc \
        base64.cc base64.hh \
-       dns_random.cc \
+       dns_random_urandom.cc \
        dnsname.cc dnsname.hh \
        dnslabeltext.cc \
        dnsparser.cc dnsparser.hh \
@@ -770,7 +768,6 @@ toysdig_SOURCES = \
        nsecrecords.cc \
        opensslsigners.cc opensslsigners.hh \
        qtype.cc \
-       randomhelper.cc \
        root-dnssec.hh \
        rcpgenerator.cc rcpgenerator.hh \
        rec-lua-conf.hh \
@@ -808,7 +805,7 @@ tsig_tests_SOURCES = \
        base32.cc \
        base64.cc base64.hh \
        dns.cc \
-       dns_random.cc dns_random.hh \
+       dns_random_urandom.cc dns_random.hh \
        dnslabeltext.cc \
        dnsname.cc dnsname.hh \
        dnsparser.cc dnsparser.hh \
@@ -820,7 +817,6 @@ tsig_tests_SOURCES = \
        misc.cc misc.hh \
        nsecrecords.cc \
        qtype.cc \
-       randomhelper.cc \
        rcpgenerator.cc rcpgenerator.hh \
        resolver.cc \
        sillyrecords.cc \
index 63309857ced31d4d43e589414e505411f2cf6321..9a52ed45cd0be0585a542a1be9a39397555b0afd 100644 (file)
@@ -204,6 +204,8 @@ void declareArguments()
   ::arg().set("xfr-max-received-mbytes", "Maximum number of megabytes received from an incoming XFR")="100";
 
   ::arg().set("tcp-fast-open", "Enable TCP Fast Open support on the listening sockets, using the supplied numerical value as the queue size")="0";
+
+  ::arg().set("rng", "Specify the random number generator to use. Valid values are auto,sodium,openssl,getrandom,arc4random,urandom.")="auto";
 }
 
 static time_t s_start=time(0);
index 873de38622e438221ecc6df664e19c1dda5ae171..08378311ebbc38dfba963cae342ace201940c51b 100644 (file)
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
-#include <openssl/aes.h>
-#include <openssl/opensslv.h>
-#if OPENSSL_VERSION_NUMBER > 0x1010000fL && !defined LIBRESSL_VERSION_NUMBER
-// Older OpenSSL does not have CRYPTO_ctr128_encrypt. Before 1.1.0 the header
-// file did not have the necessary extern "C" wrapper. In 1.1.0, AES_ctr128_encrypt
-// was removed.
-#include <openssl/modes.h>
-#endif
-#include <iostream>
-#include <cstdlib>
-#include <cstring>
 #include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 #include <unistd.h>
-#include <sys/time.h>
-#include <limits>
-#include <stdexcept>
-#include <stdint.h>
+#include <stdlib.h>
+#include <string>
 #include "dns_random.hh"
+#include "arguments.hh"
+#include "logger.hh"
+#include "boost/lexical_cast.hpp"
+
+#if defined(HAVE_RANDOMBYTES_STIR)
+#include <sodium.h>
+#endif
+#if defined(HAVE_RAND_BYTES)
+#include <openssl/rand.h>
+#endif
+#if defined(HAVE_GETRANDOM)
+#include <linux/random.h>
+#endif
 
-using namespace std;
+static enum DNS_RNG {
+  RNG_UNINITIALIZED = 0,
+  RNG_SODIUM,
+  RNG_OPENSSL,
+  RNG_GETRANDOM,
+  RNG_ARC4RANDOM,
+  RNG_URANDOM,
+  RNG_KISS,
+} chosen_rng = RNG_UNINITIALIZED;
 
-static AES_KEY aes_key;
-static unsigned int g_offset;
-static unsigned char g_counter[16], g_stream[16];
-static uint32_t g_in;
+static int urandom_fd = -1;
 
-static bool g_initialized;
+#if defined(HAVE_KISS_RNG)
+/* KISS is intended for development use only */
+static unsigned int kiss_seed;
+static uint32_t kiss_z, kiss_w, kiss_jsr, kiss_jcong;
 
-void dns_random_init(const char data[16])
+static void
+kiss_init(unsigned int seed)
 {
-  g_offset = 0;
-  memset(&g_stream, 0, sizeof(g_stream));
-  if (AES_set_encrypt_key((const unsigned char*)data, 128, &aes_key) < 0) {
-    throw std::runtime_error("AES_set_encrypt_key failed");
+  kiss_seed = seed;
+  kiss_jsr = 0x5eed5eed; /* simply musn't be 0 */
+  kiss_z = 1 ^ (kiss_w = kiss_jcong = seed); /* w=z=0 is bad, see Rose */
+}
+
+static unsigned int
+kiss_rand(void)
+{
+  kiss_z = 36969 * (kiss_z&65535) + (kiss_z>>16);
+  kiss_w = 18000 * (kiss_w&65535) + (kiss_w>>16);
+  kiss_jcong = 69069 * kiss_jcong + 1234567;
+  kiss_jsr^=(kiss_jsr<<13); /* <<17, >>13 gives cycle length 2^28.2 max */
+  kiss_jsr^=(kiss_jsr>>17); /* <<13, >>17 gives maximal cycle length */
+  kiss_jsr^=(kiss_jsr<<5);
+  return (((kiss_z<<16) + kiss_w) ^ kiss_jcong) + kiss_jsr;
+}
+#endif
+
+static void dns_random_setup(void)
+{
+  string rdev;
+  string rng;
+  /* check if selection has been done */
+  if (chosen_rng > RNG_UNINITIALIZED)
+    return;
+
+/* XXX: A horrible hack to allow using dns_random in places where arguments are not available.
+        Forces /dev/urandom usage
+*/
+#if defined(USE_URANDOM_ONLY)
+  chosen_rng = RNG_URANDOM;
+  rdev = "/dev/urandom";
+#else
+  rng = ::arg()["rng"];
+  rdev = ::arg()["entropy-source"];
+  if (rng == "auto") {
+# if defined(HAVE_GETRANDOM)
+    chosen_rng = RNG_GETRANDOM;
+# elif defined(HAVE_ARC4RANDOM)
+    chosen_rng = RNG_ARC4RANDOM;
+# elif defined(HAVE_RANDOMBYTES_STIR)
+    chosen_rng = RNG_SODIUM;
+# elif defined(HAVE_RAND_BYTES)
+    chosen_rng = RNG_OPENSSL;
+# else
+    chosen_rng = RNG_URANDOM;
+# endif
+# if defined(HAVE_RANDOMBYTES_STIR)
+  } else if (rng == "sodium") {
+    chosen_rng = RNG_SODIUM;
+# endif
+# if defined(HAVE_RAND_BYTES)
+  } else if (rng == "openssl") {
+    chosen_rng = RNG_OPENSSL;
+# endif
+# if defined(HAVE_GETRANDOM)
+  } else if (rng == "getrandom") {
+    chosen_rng = RNG_GETRANDOM;
+# endif
+# if defined(HAVE_ARC4RANDOM)
+  } else if (rng == "arc4random") {
+    chosen_rng = RNG_ARC4RANDOM;
+# endif
+  } else if (rng == "urandom") {
+    chosen_rng = RNG_URANDOM;
+#if defined(HAVE_KISS_RNG)
+  } else if (rng == "kiss") {
+    chosen_rng = RNG_KISS;
+    L<<Logger::Warning<<"kiss rng should not be used in production environment"<<std::endl;
+#endif
+  } else {
+    throw PDNSException("Unsupported rng '" + rng + "'");
   }
 
-  struct timeval now;
-  gettimeofday(&now, 0);
+# if defined(HAVE_RANDOMBYTES_STIR)
+  if (chosen_rng == RNG_SODIUM) {
+    if (sodium_init() == -1)
+      throw PDNSException("Unable to initialize sodium crypto library");
+    /*  make sure it's set up */
+    randombytes_stir();
+  }
+# endif
 
-  static_assert(sizeof(g_counter) >= (sizeof(now.tv_usec) + sizeof(now.tv_sec)), "g_counter must be large enough to get tv_sec + tv_usec");
-  memcpy(g_counter, &now.tv_usec, sizeof(now.tv_usec));
-  memcpy(g_counter+sizeof(now.tv_usec), &now.tv_sec, sizeof(now.tv_sec));
-  g_in = getpid() | (getppid()<<16);
+# if defined(HAVE_GETRANDOM)
+  if (chosen_rng == RNG_GETRANDOM) {
+    char buf[1];
+    // some systems define getrandom but it does not really work, e.g. because it's
+    // not present in kernel.
+    if (getrandom(buf, sizeof(buf), 0) == -1) {
+       L<<Logger::Warning<<"getrandom() failed: "<<strerror(errno)<<", falling back to " + rdev<<std::endl;
+       chosen_rng = RNG_URANDOM;
+    }
+  }
+# endif
 
-  g_initialized = true;
-  srandom(dns_random(numeric_limits<uint32_t>::max()));
+# if defined(HAVE_RAND_BYTES)
+  if (chosen_rng == RNG_OPENSSL) {
+    int ret;
+    unsigned char buf[1];
+    if ((ret = RAND_bytes(buf, sizeof(buf))) == -1)
+      throw PDNSException("RAND_bytes not supported by current SSL engine");
+    if (ret == 0)
+      throw PDNSException("Openssl RNG was not seeded");
+  }
+# endif
+#endif /* USE_URANDOM_ONLY */
+  if (chosen_rng == RNG_URANDOM) {
+    urandom_fd = open(rdev.c_str(), O_RDONLY);
+    if (urandom_fd == -1)
+      throw PDNSException("Cannot open " + rdev + ": " + std::string(strerror(errno)));
+  }
+#if defined(HAVE_KISS_RNG)
+  if (chosen_rng == RNG_KISS) {
+    unsigned int seed;
+    urandom_fd = open(rdev.c_str(), O_RDONLY);
+    if (urandom_fd == -1)
+      throw PDNSException("Cannot open " + rdev + ": " + std::string(strerror(errno)));
+    if (read(urandom_fd, &seed, sizeof(seed)) < 0) {
+      (void)close(urandom_fd);
+      throw PDNSException("Cannot read random device");
+    }
+    kiss_init(seed);
+    (void)close(urandom_fd);
+  }
+#endif
 }
 
-unsigned int dns_random(unsigned int n)
-{
-  if(!g_initialized)
-    abort();
-  uint32_t out;
-#if OPENSSL_VERSION_NUMBER > 0x1010000fL && !defined LIBRESSL_VERSION_NUMBER
-  CRYPTO_ctr128_encrypt((const unsigned char*)&g_in, (unsigned char*) &out, sizeof(g_in), &aes_key, g_counter, g_stream, &g_offset, (block128_f) AES_encrypt);
-#else
-  AES_ctr128_encrypt((const unsigned char*)&g_in, (unsigned char*) &out, sizeof(g_in), &aes_key, g_counter, g_stream, &g_offset);
+void dns_random_init(const string& data __attribute__((unused))) {
+  dns_random_setup();
+  (void)dns_random(1);
+  // init should occur already in dns_random_setup
+  // this interface is only for KISS
+#if defined(HAVE_KISS_RNG)
+  unsigned int seed;
+  if (chosen_rng != RNG_KISS)
+    return;
+  if (data.size() != 16)
+    throw PDNSException("invalid seed");
+  seed = (data[0] + (data[1]<<8) + (data[2]<<16) + (data[3]<<24)) ^
+         (data[4] + (data[5]<<8) + (data[6]<<16) + (data[7]<<24)) ^
+         (data[8] + (data[9]<<8) + (data[10]<<16) + (data[11]<<24)) ^
+         (data[12] + (data[13]<<8) + (data[14]<<16) + (data[15]<<24));
+  kiss_init(seed);
 #endif
-  return out % n;
 }
 
-#if 0
-int main()
-{
-  dns_random_init("0123456789abcdef");
+/* Parts of this code come from arc4random_uniform */
+unsigned int dns_random(unsigned int upper_bound) {
+  if (chosen_rng == RNG_UNINITIALIZED)
+    dns_random_setup();
 
-  for(int n = 0; n < 16; n++)
-    cerr<<dns_random(16384)<<endl;
-}
+  unsigned int min;
+  if (upper_bound < 2)
+    return 0;
+  /* To avoid "modulo bias" for some methods, calculate
+     minimum acceptable value for random number to improve
+     uniformity.
+
+     On applicable rngs, we loop until the rng spews out
+     value larger than min, and then take modulo out of that.
+  */
+#if (ULONG_MAX > 0xffffffffUL)
+  min = 0x100000000UL % upper_bound;
+#else
+  /* Calculate (2**32 % upper_bound) avoiding 64-bit math */
+  if (upper_bound > 0x80000000)
+    min = 1 + ~upper_bound; /* 2**32 - upper_bound */
+  else {
+    /* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
+    min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound;
+  }
 #endif
+
+  switch(chosen_rng) {
+  case RNG_UNINITIALIZED:
+    throw PDNSException("Unreachable at " __FILE__ ":" + boost::lexical_cast<std::string>(__LINE__)); // cannot be reached
+  case RNG_SODIUM:
+#if defined(HAVE_RANDOMBYTES_STIR) && !defined(USE_URANDOM_ONLY)
+    return static_cast<unsigned int>(randombytes_uniform(static_cast<uint32_t>(upper_bound)));
+#else
+    throw PDNSException("Unreachable at " __FILE__ ":" + boost::lexical_cast<std::string>(__LINE__)); // cannot be reached
+#endif /* RND_SODIUM */
+  case RNG_OPENSSL: {
+#if defined(HAVE_RAND_BYTES) && !defined(USE_URANDOM_ONLY)
+      unsigned int num=0;
+      while(num < min) {
+        if (RAND_bytes(reinterpret_cast<unsigned char*>(&num), sizeof(num)) < 1)
+          throw PDNSException("Openssl RNG was not seeded");
+      }
+      return num % upper_bound;
+#else
+      throw PDNSException("Unreachable at " __FILE__ ":" + boost::lexical_cast<std::string>(__LINE__)); // cannot be reached
+#endif /* RNG_OPENSSL */
+     }
+  case RNG_GETRANDOM: {
+#if defined(HAVE_GETRANDOM) && !defined(USE_URANDOM_ONLY)
+      unsigned int num=0;
+      while(num < min) {
+        if (getrandom(&num, sizeof(num), 0) != 0)
+          throw PDNSException("getrandom() failed: " + std::string(strerror(errno)));
+      }
+      return num % upper_bound;
+#else
+      throw PDNSException("Unreachable at " __FILE__ ":" + boost::lexical_cast<std::string>(__LINE__)); // cannot be reached
+#endif
+      }
+  case RNG_ARC4RANDOM:
+#if defined(HAVE_ARC4RANDOM) && !defined(USE_URANDOM_ONLY)
+    return static_cast<unsigned int>(arc4random_uniform(static_cast<uint32_t>(upper_bound)));
+#else
+    throw PDNSException("Unreachable at " __FILE__ ":" + boost::lexical_cast<std::string>(__LINE__)); // cannot be reached
+#endif
+  case RNG_URANDOM: {
+      unsigned int num = 0;
+      while(num < min) {
+        if (read(urandom_fd, &num, sizeof(num)) < 0) {
+          (void)close(urandom_fd);
+          throw PDNSException("Cannot read random device");
+        }
+      }
+      return num % upper_bound;
+    }
+#if defined(HAVE_KISS_RNG)
+  case RNG_KISS: {
+      unsigned int num = 0;
+      while(num < min)
+        num = kiss_rand();
+      return num % upper_bound;
+    }
+#endif
+  default:
+    throw PDNSException("Unreachable at " __FILE__ ":" + boost::lexical_cast<std::string>(__LINE__)); // cannot be reached
+  };
+}
index 55b68a93f4884fd311a5519fd9a9344cdba90d87..d4a869a09bd83a29a2b905bc2e3596e3c5f162ab 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef PDNS_DNS_RANDOM
 #define PDNS_DNS_RANDOM
 
-void dns_random_init(const char data[16]);
+void dns_random_init(const std::string& data = "");
 unsigned int dns_random(unsigned int n);
 
 #endif
diff --git a/pdns/dns_random_urandom.cc b/pdns/dns_random_urandom.cc
new file mode 100644 (file)
index 0000000..708d3df
--- /dev/null
@@ -0,0 +1,2 @@
+#define USE_URANDOM_ONLY
+#include "dns_random.cc"
index b06eaf0f3d89c5fab33a1bbbc76359457d672d61..85536b3b28e6f5f568ba4d5c6a0352e8ff6753b9 100644 (file)
@@ -103,7 +103,6 @@ int main(int argc, char** argv) {
        Store result in memory, read that best zone in memory, apply deltas, write it out.
 
        Next up, loop this every REFRESH seconds */
-    dns_random_init("0123456789abcdef");
 
     DNSName zone(argv[4]);
     ComboAddress master(argv[2], atoi(argv[3]));
index bdc535b3aea27ca0f8ff61415005107b0beaf7b0..0f17a3a60987c07211632d2af45cbd95a03f8ab2 100644 (file)
@@ -428,7 +428,6 @@ inline DNSName toCanonic(const DNSName& zone, const string& qname)
 
 string stripDot(const string& dom);
 
-void seedRandom(const string& source);
 int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret);
 int makeIPv4sockaddr(const std::string& str, struct sockaddr_in* ret);
 int makeUNsockaddr(const std::string& path, struct sockaddr_un* ret);
index a868ed4b5816191b0da59b78fe4547ff18d6efb0..c3969996434a7ec4e27e631c5bc15677b45cefdf 100644 (file)
@@ -3037,7 +3037,6 @@ static int serviceMain(int argc, char*argv[])
   }
 
   showProductVersion();
-  seedRandom(::arg()["entropy-source"]);
 
   g_disthashseed=dns_random(0xffffffff);
 
@@ -3267,6 +3266,8 @@ static int serviceMain(int argc, char*argv[])
 
   openssl_thread_setup();
   openssl_seed();
+  /* setup rng before chroot */
+  dns_random_init();
 
   int newgid=0;
   if(!::arg()["setgid"].empty())
@@ -3665,6 +3666,7 @@ int main(int argc, char **argv)
     ::arg().set("udp-source-port-min", "Minimum UDP port to bind on")="1024";
     ::arg().set("udp-source-port-max", "Maximum UDP port to bind on")="65535";
     ::arg().set("udp-source-port-avoid", "List of comma separated UDP port number to avoid")="11211";
+    ::arg().set("rng", "Specify random number generator to use. Valid values are auto,sodium,openssl,getrandom,arc4random,urandom.")="auto";
 
     ::arg().setCmd("help","Provide a helpful message");
     ::arg().setCmd("version","Print version string");
index 83cf5f85eaa7207fb5d6a51b6ceaa3b480613637..fedc0521bc67d84a52608392dfda1b4f83b6eb08 100644 (file)
@@ -95,6 +95,7 @@ void loadMainConfig(const std::string& configdir)
   ::arg().setSwitch("direct-dnskey","Fetch DNSKEY RRs from backend during DNSKEY synthesis")="no";
   ::arg().set("max-nsec3-iterations","Limit the number of NSEC3 hash iterations")="500"; // RFC5155 10.3
   ::arg().set("max-signature-cache-entries", "Maximum number of signatures cache entries")="";
+  ::arg().set("rng", "Specify random number generator to use. Valid values are auto,sodium,openssl,getrandom,arc4random,urandom.")="auto";
   ::arg().laxFile(configname.c_str());
 
   g_log.toConsole(Logger::Error);   // so we print any errors
@@ -124,16 +125,15 @@ void loadMainConfig(const std::string& configdir)
   if (! ::arg().laxFile(configname.c_str()))
     cerr<<"Warning: unable to read configuration file '"<<configname<<"': "<<strerror(errno)<<endl;
 
-  seedRandom(::arg()["entropy-source"]);
-
 #ifdef HAVE_LIBSODIUM
   if (sodium_init() == -1) {
     cerr<<"Unable to initialize sodium crypto library"<<endl;
     exit(99);
   }
 #endif
-
   openssl_seed();
+  /* init rng before chroot */
+  dns_random_init();
 
   if (!::arg()["chroot"].empty()) {
     if (chroot(::arg()["chroot"].c_str())<0 || chdir("/") < 0) {
diff --git a/pdns/randomhelper.cc b/pdns/randomhelper.cc
deleted file mode 100644 (file)
index 97f0911..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include "misc.hh"
-#include "logger.hh"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include "dns_random.hh"                     
-
-void seedRandom(const string& source)
-{
-  g_log<<Logger::Warning<<"Reading random entropy from '"<<source<<"'"<<endl;
-
-  int fd=open(source.c_str(), O_RDONLY);
-  if(fd < 0) {
-    g_log<<Logger::Error<<"Unable to open source of random '"<<source<<"': "<<stringerror()<<endl;
-    exit(EXIT_FAILURE);
-  }
-  char seed[16];
-  int ret;
-  int pos=0;
-  while(pos!=sizeof(seed)) {
-    ret = read(fd, seed+pos, sizeof(seed)-pos);
-    if(ret < 0) { 
-      g_log<<Logger::Error<<"Unable to read random seed from "<<source<<": "<<stringerror()<<endl;
-      close(fd);
-      exit(EXIT_FAILURE);
-    }
-    if(!ret) {
-      g_log<<Logger::Error<<"Unable to read random seed from "<<source<<": end of file"<<endl;
-      close(fd);
-      exit(EXIT_FAILURE);
-    }
-    pos+=ret;
-  }
-  close(fd);
-  dns_random_init(seed);
-}
index c20abdc6fe2325c03eb429e2100cc3a9d80cfa0a..ac27940c80085b7d492138091ccf99402ac470e6 100644 (file)
@@ -494,8 +494,6 @@ int main(int argc, char **argv)
     }
 #endif
 
-    seedRandom(::arg()["entropy-source"]);
-
 #ifdef HAVE_LIBSODIUM
       if (sodium_init() == -1) {
         cerr<<"Unable to initialize sodium crypto library"<<endl;
@@ -505,6 +503,8 @@ int main(int argc, char **argv)
 
     openssl_thread_setup();
     openssl_seed();
+    /* setup rng */
+    dns_random_init();
 
     loadModules();
     BackendMakers().launch(::arg()["launch"]); // vrooooom!
index 387e3cd809dde348d97b279d2181a6c0294a5a7c..a8580377c1e74ea667be8712acaa0dc4ac110da4 100644 (file)
@@ -130,7 +130,6 @@ pdns_recursor_SOURCES = \
        protobuf.cc protobuf.hh \
        pubsuffix.hh pubsuffix.cc \
        qtype.hh qtype.cc \
-       randomhelper.cc \
        rcpgenerator.cc rcpgenerator.hh \
        rec-carbon.cc \
        rec-lua-conf.hh rec-lua-conf.cc \
@@ -191,7 +190,7 @@ testrunner_SOURCES = \
        base32.cc \
        base64.cc base64.hh \
        dns.cc dns.hh \
-       dns_random.cc dns_random.hh \
+       dns_random_urandom.cc dns_random.hh \
        dnslabeltext.cc \
        dnsname.cc dnsname.hh \
        dnsparser.hh dnsparser.cc \
@@ -217,7 +216,6 @@ testrunner_SOURCES = \
        opensslsigners.cc opensslsigners.hh \
        protobuf.cc protobuf.hh \
        qtype.cc qtype.hh \
-       randomhelper.cc \
        rcpgenerator.cc \
        rec-protobuf.cc rec-protobuf.hh \
        recpacketcache.cc recpacketcache.hh \
index dc681520ec4dfc4a01b73263baf285c97da45c14..ed1e388fe44d1a3f84aa14f7399f324735983995 100644 (file)
@@ -121,7 +121,7 @@ PDNS_WITH_NET_SNMP
 PDNS_CHECK_RAGEL([pdns/dnslabeltext.cc], [www.powerdns.com])
 PDNS_CHECK_CURL
 
-AC_CHECK_FUNCS_ONCE([strcasestr localtime_r recvmmsg getrandom arc4random])
+AC_CHECK_FUNCS_ONCE([strcasestr getrandom arc4random])
 
 PDNS_CHECK_PTHREAD_NP
 
diff --git a/pdns/recursordist/dns_random_urandom.cc b/pdns/recursordist/dns_random_urandom.cc
new file mode 120000 (symlink)
index 0000000..a412aea
--- /dev/null
@@ -0,0 +1 @@
+../dns_random_urandom.cc
\ No newline at end of file
index dbcb127a563cae852976c9ea87bee09be4554cce..ca19519dfb4cb4e3a11ba5a79364e5390fbd6bde 100644 (file)
@@ -871,6 +871,25 @@ If ``SO_REUSEPORT`` support is available, allows multiple processes to open a li
 
 Since 4.1.0, when ``pdns-distributes-queries`` is set to false and ``reuseport`` is enabled, every thread will open a separate listening socket to let the kernel distribute the incoming queries, avoiding any thundering herd issue as well as the distributor thread being a bottleneck, thus leading to much higher performance on multi-core boxes.
 
+.. _setting-rng:
+``rng``
+-------
+
+- String
+- Default: auto
+
+Specify which random number generator to use. Permissible choises are
+ - auto - choose automatically
+ - sodium - Use libsodium ``randombytes_uniform``
+ - openssl - Use libcrypto ``RAND_bytes``
+ - getrandom - Use libc getrandom, falls back to urandom if it does not really work
+ - arc4random - Use BSD ``arc4random_uniform``
+ - urandom - Use ``/dev/urandom``
+ - kiss - Use simple settable deterministic RNG. **FOR TESTING PURPOSES ONLY!**
+
+.. note::
+  Not all choises are available on all systems.
+
 .. _setting-root-nx-trust:
 
 ``root-nx-trust``
diff --git a/pdns/recursordist/randomhelper.cc b/pdns/recursordist/randomhelper.cc
deleted file mode 120000 (symlink)
index 9f7ac16..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../randomhelper.cc
\ No newline at end of file
index c8879a7b9cf81ec670e94177f41dffd87ca9c697..3a157279e29b19e6c0832c32e72207668f6d3b93 100644 (file)
@@ -113,7 +113,6 @@ static void init(bool debug=false)
     g_log.toConsole(Logger::Error);
   }
 
-  seedRandom("/dev/urandom");
   reportAllTypes();
 
   t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
index 9b18d422e7fffb8e50092d8c179776a08fae8106..a6d4ec84d34e92dfb156b2096866b09c98a4a877 100644 (file)
@@ -83,7 +83,6 @@ try
   }
 
   reportAllTypes();
-  dns_random_init("0123456789abcdef");
 
   vector<uint8_t> packet;
   uint16_t len;
index 140da8bba9007f864adfab55b4d6a54ac9116b4d..afffa27b432e8bcc75ec3029cef86aba12cd66cf 100644 (file)
@@ -46,7 +46,6 @@ try
   ::arg().set("resolver","Use this resolver for ALIAS and the internal stub resolver")="no"; 
 
   reportAllTypes();
-  dns_random_init("0123456789abcdef");
   stubParseResolveConf();
 
   vector<DNSZoneRecord> ret;
index 1dda1ade7d26f34384912f5f9174c8414de3603a..aadb8864f0ac5f049ccf95ec93c7dcfac59249e7 100644 (file)
@@ -37,7 +37,6 @@ BOOST_AUTO_TEST_SUITE(test_dns_random_hh)
 
 BOOST_AUTO_TEST_CASE(test_dns_random_average) {
 
-  dns_random_init("loremipsumdolorx");
   acc_t acc;
 
   for(unsigned int n=0; n < 100000; ++n)  {
index 22563d0a48d183357b39b5c0d3d2d76de5215f96..93900fb258c6641f33c568a55e1749f3a3acf226 100644 (file)
@@ -59,7 +59,6 @@ try
 
   Socket sock(AF_INET, SOCK_DGRAM);
   ComboAddress dest(argv[1] + (*argv[1]=='@'), atoi(argv[2]));
-  seedRandom("/dev/urandom");
   cerr<<"Keyname: '"<<keyname<<"', algo: '"<<trc.d_algoName<<"', key: '"<<Base64Encode(key)<<"'\n";
   TSIGTriplet tt;
   tt.name=keyname;