From f78b8ab629110559afd3dfe178a3ad508c9800f4 Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Fri, 24 Jun 2022 15:14:12 +0200 Subject: [PATCH] dnsdist: Use getrandom() if available It turns out to use much less CPU than RANDOM_bytes() from libcrypto. --- pdns/dnsdistdist/configure.ac | 2 +- pdns/dnsdistdist/dnsdist-random.cc | 37 +++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/pdns/dnsdistdist/configure.ac b/pdns/dnsdistdist/configure.ac index 476f6d807a..7641fa2c74 100644 --- a/pdns/dnsdistdist/configure.ac +++ b/pdns/dnsdistdist/configure.ac @@ -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']) diff --git a/pdns/dnsdistdist/dnsdist-random.cc b/pdns/dnsdistdist/dnsdist-random.cc index d06abcd0e6..01e3ba4d9c 100644 --- a/pdns/dnsdistdist/dnsdist-random.cc +++ b/pdns/dnsdistdist/dnsdist-random.cc @@ -31,11 +31,21 @@ #include #endif /* HAVE_RAND_BYTES */ +#if defined(HAVE_GETRANDOM) +#include +#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(&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(&result), sizeof(result)) != 1) { -- 2.47.2