]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Use getrandom() if available 11723/head
authorRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 24 Jun 2022 13:14:12 +0000 (15:14 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 24 Jun 2022 15:41:51 +0000 (17:41 +0200)
It turns out to use much less CPU than RANDOM_bytes() from libcrypto.

pdns/dnsdistdist/configure.ac
pdns/dnsdistdist/dnsdist-random.cc

index 476f6d807a0fe2970e3873d1a28e66df641ce1df..7641fa2c74427a28526e8e0bfc9a017fcc631610 100644 (file)
@@ -48,7 +48,7 @@ PDNS_WITH_SERVICE_USER([dnsdist])
 
 dnl the *_r functions are in posix so we can use them unconditionally, but the ext/yahttp code is
 dnl using the defines.
-AC_CHECK_FUNCS_ONCE([localtime_r gmtime_r])
+AC_CHECK_FUNCS_ONCE([localtime_r gmtime_r getrandom])
 AC_SUBST([YAHTTP_CFLAGS], ['-I$(top_srcdir)/ext/yahttp'])
 AC_SUBST([YAHTTP_LIBS], ['$(top_builddir)/ext/yahttp/yahttp/libyahttp.la'])
 AC_SUBST([IPCRYPT_CFLAGS], ['-I$(top_srcdir)/ext/ipcrypt'])
index d06abcd0e6d55fc222153bc0eb01b1b2857f3477..01e3ba4d9c2f98fe0c40428dd1d47c3f4dc48e04 100644 (file)
 #include <openssl/rand.h>
 #endif /* HAVE_RAND_BYTES */
 
+#if defined(HAVE_GETRANDOM)
+#include <sys/random.h>
+#endif
+
 #include "dnsdist-random.hh"
 #include "dns_random.hh"
+#include "dolog.hh"
+#include "misc.hh"
 
 namespace dnsdist
 {
+#if !defined(HAVE_LIBSODIUM) && defined(HAVE_GETRANDOM)
+static bool s_useGetRandom{true};
+#endif
+
 void initRandom()
 {
 #ifdef HAVE_LIBSODIUM
@@ -43,6 +53,15 @@ void initRandom()
 #else
   {
     auto getSeed = []() {
+#if defined(HAVE_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 && errno != EINTR) {
+        warnlog("getrandom() failed %s", stringerror());
+        s_useGetRandom = false;
+      }
+#endif /* HAVE_GETRANDOM */
 #ifdef HAVE_RAND_BYTES
       unsigned int seed;
       if (RAND_bytes(reinterpret_cast<unsigned char*>(&seed), sizeof(seed)) == 1) {
@@ -64,8 +83,24 @@ uint32_t getRandomValue(uint32_t upperBound)
 #ifdef HAVE_LIBSODIUM
   return randombytes_uniform(upperBound);
 #else /* HAVE_LIBSODIUM */
-  uint32_t result;
+  uint32_t result = 0;
   unsigned int min = pdns::random_minimum_acceptable_value(upperBound);
+
+#if defined(HAVE_GETRANDOM)
+  if (s_useGetRandom) {
+    do {
+      auto got = getrandom(&result, sizeof(result), 0);
+      if (got == -1 && errno == EINTR) {
+        continue;
+      }
+      if (got != sizeof(result)) {
+        throw std::runtime_error("Error getting a random value via getrandom(): " + stringerror());
+      }
+    } while (result < min);
+
+    return result % upperBound;
+  }
+#endif /* HAVE_GETRANDOM */
 #ifdef HAVE_RAND_BYTES
   do {
     if (RAND_bytes(reinterpret_cast<unsigned char*>(&result), sizeof(result)) != 1) {