From: Otto Moerbeek Date: Tue, 13 Jun 2023 09:08:50 +0000 (+0200) Subject: Introduce dns_random_uint32() X-Git-Tag: rec-5.0.0-alpha1~170^2~6 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=43159bf142d429a3458fa0ea07282a24db12a4f5;p=thirdparty%2Fpdns.git Introduce dns_random_uint32() To be used when a full 32 bits of randomness are needed, also avoiding the modulo dance --- diff --git a/pdns/dns_random.cc b/pdns/dns_random.cc index 4461de6413..9d3e34edc4 100644 --- a/pdns/dns_random.cc +++ b/pdns/dns_random.cc @@ -219,6 +219,90 @@ void dns_random_init(const string& data __attribute__((unused)), bool force) #endif } +uint32_t dns_random_uint32() +{ + if (chosen_rng == RNG_UNINITIALIZED) { + dns_random_setup(); + } + + switch (chosen_rng) { + case RNG_UNINITIALIZED: + throw std::runtime_error("Unreachable at " __FILE__ ":" + std::to_string(__LINE__)); // cannot be reached + case RNG_SODIUM: +#if defined(HAVE_RANDOMBYTES_STIR) && !defined(USE_URANDOM_ONLY) + return randombytes_random(); +#else + throw std::runtime_error("Unreachable at " __FILE__ ":" + std::to_string(__LINE__)); // cannot be reached +#endif /* RND_SODIUM */ + case RNG_OPENSSL: { +#if defined(HAVE_RAND_BYTES) && !defined(USE_URANDOM_ONLY) + uint32_t num = 0; + if (RAND_bytes(reinterpret_cast(&num), sizeof(num)) < 1) { // NOLINT: API + throw std::runtime_error("Openssl RNG was not seeded"); + } + return num; +#else + throw std::runtime_error("Unreachable at " __FILE__ ":" + std::to_string(__LINE__)); // cannot be reached +#endif /* RNG_OPENSSL */ + } + case RNG_GETRANDOM: { +#if defined(HAVE_GETRANDOM) && !defined(USE_URANDOM_ONLY) + uint32_t num = 0; + do { + auto got = getrandom(&num, sizeof(num), 0); + if (got == -1 && errno == EINTR) { + continue; + } + if (got != sizeof(num)) { + throw std::runtime_error("getrandom() failed: " + stringerror()); + } + } while (true); + return num; +#else + throw std::runtime_error("Unreachable at " __FILE__ ":" + std::to_string(__LINE__)); // cannot be reached +#endif + } + case RNG_ARC4RANDOM: +#if defined(HAVE_ARC4RANDOM) && !defined(USE_URANDOM_ONLY) + return arc4random(); +#else + throw std::runtime_error("Unreachable at " __FILE__ ":" + std::to_string(__LINE__)); // cannot be reached +#endif + case RNG_URANDOM: { + uint32_t num = 0; + size_t attempts = 5; + ssize_t got = read(urandom_fd, &num, sizeof(num)); + do { + if (got < 0) { + if (errno == EINTR) { + continue; + } + + (void)close(urandom_fd); + throw std::runtime_error("Cannot read random device"); + } + if (static_cast(got) != sizeof(num)) { + /* short read, let's retry */ + if (attempts == 0) { + throw std::runtime_error("Too many short reads on random device"); + } + attempts--; + continue; + } + } while (true); + return num; + } +#if defined(HAVE_KISS_RNG) + case RNG_KISS: { + uint32_t num = kiss_rand(); + return num; + } +#endif + default: + throw std::runtime_error("Unreachable at " __FILE__ ":" + std::to_string(__LINE__)); // cannot be reached + }; +} + uint32_t dns_random(uint32_t upper_bound) { if (chosen_rng == RNG_UNINITIALIZED) { @@ -320,5 +404,5 @@ uint32_t dns_random(uint32_t upper_bound) uint16_t dns_random_uint16() { - return dns_random(0x10000); + return dns_random_uint32() & 0xffff; } diff --git a/pdns/dns_random.hh b/pdns/dns_random.hh index be93e68bcb..634d233c1c 100644 --- a/pdns/dns_random.hh +++ b/pdns/dns_random.hh @@ -26,6 +26,7 @@ void dns_random_init(const std::string& data = "", bool force_reinit = false); uint32_t dns_random(uint32_t upper_bound); +uint32_t dns_random_uint32(); uint16_t dns_random_uint16(); namespace pdns @@ -42,12 +43,12 @@ struct dns_random_engine static constexpr result_type max() { - return std::numeric_limits::max() - 1; + return std::numeric_limits::max(); } result_type operator()() { - return dns_random(std::numeric_limits::max()); + return dns_random_uint32(); } };