./pdns/distributor.hh
./pdns/dns.cc
./pdns/dns.hh
-./pdns/dns_random.cc
-./pdns/dns_random.hh
./pdns/dnsbackend.cc
./pdns/dnsbackend.hh
./pdns/dnsbulktest.cc
./pdns/test-common.hh
./pdns/test-digests_hh.cc
./pdns/test-distributor_hh.cc
-./pdns/test-dns_random_hh.cc
./pdns/test-dnscrypt_cc.cc
./pdns/test-dnsdist_cc.cc
./pdns/test-dnsdistpacketcache_cc.cc
RNG_ARC4RANDOM,
RNG_URANDOM,
RNG_KISS,
-} chosen_rng = RNG_UNINITIALIZED;
+} chosen_rng
+ = RNG_UNINITIALIZED;
static int urandom_fd = -1;
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_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;
+ 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(bool force=false)
+static void dns_random_setup(bool force = false)
{
string rdev;
string rng;
rng = ::arg()["rng"];
rdev = ::arg()["entropy-source"];
if (rng == "auto") {
-# if defined(HAVE_GETRANDOM)
+#if defined(HAVE_GETRANDOM)
chosen_rng = RNG_GETRANDOM;
-# elif defined(HAVE_ARC4RANDOM)
+#elif defined(HAVE_ARC4RANDOM)
chosen_rng = RNG_ARC4RANDOM;
-# elif defined(HAVE_RANDOMBYTES_STIR)
+#elif defined(HAVE_RANDOMBYTES_STIR)
chosen_rng = RNG_SODIUM;
-# elif defined(HAVE_RAND_BYTES)
+#elif defined(HAVE_RAND_BYTES)
chosen_rng = RNG_OPENSSL;
-# else
+#else
chosen_rng = RNG_URANDOM;
-# endif
-# if defined(HAVE_RANDOMBYTES_STIR)
- } else if (rng == "sodium") {
+#endif
+#if defined(HAVE_RANDOMBYTES_STIR)
+ }
+ else if (rng == "sodium") {
chosen_rng = RNG_SODIUM;
-# endif
-# if defined(HAVE_RAND_BYTES)
- } else if (rng == "openssl") {
+#endif
+#if defined(HAVE_RAND_BYTES)
+ }
+ else if (rng == "openssl") {
chosen_rng = RNG_OPENSSL;
-# endif
-# if defined(HAVE_GETRANDOM)
- } else if (rng == "getrandom") {
+#endif
+#if defined(HAVE_GETRANDOM)
+ }
+ else if (rng == "getrandom") {
chosen_rng = RNG_GETRANDOM;
-# endif
-# if defined(HAVE_ARC4RANDOM)
- } else if (rng == "arc4random") {
+#endif
+#if defined(HAVE_ARC4RANDOM)
+ }
+ else if (rng == "arc4random") {
chosen_rng = RNG_ARC4RANDOM;
-# endif
- } else if (rng == "urandom") {
+#endif
+ }
+ else if (rng == "urandom") {
chosen_rng = RNG_URANDOM;
#if defined(HAVE_KISS_RNG)
- } else if (rng == "kiss") {
+ }
+ else if (rng == "kiss") {
chosen_rng = RNG_KISS;
- g_log<<Logger::Warning<<"kiss rng should not be used in production environment"<<std::endl;
+ g_log << Logger::Warning << "kiss rng should not be used in production environment" << std::endl;
#endif
- } else {
+ }
+ else {
throw std::runtime_error("Unsupported rng '" + rng + "'");
}
-# if defined(HAVE_RANDOMBYTES_STIR)
+#if defined(HAVE_RANDOMBYTES_STIR)
if (chosen_rng == RNG_SODIUM) {
if (sodium_init() == -1)
throw std::runtime_error("Unable to initialize sodium crypto library");
/* make sure it's set up */
randombytes_stir();
}
-# endif
+#endif
-# if defined(HAVE_GETRANDOM)
+#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 && errno != EINTR) {
- g_log<<Logger::Warning<<"getrandom() failed: "<<stringerror()<<", falling back to " + rdev<<std::endl;
- chosen_rng = RNG_URANDOM;
+ g_log << Logger::Warning << "getrandom() failed: " << stringerror() << ", falling back to " + rdev << std::endl;
+ chosen_rng = RNG_URANDOM;
}
}
-# endif
+#endif
-# if defined(HAVE_RAND_BYTES)
+#if defined(HAVE_RAND_BYTES)
if (chosen_rng == RNG_OPENSSL) {
int ret;
unsigned char buf[1];
if (ret == 0)
throw std::runtime_error("Openssl RNG was not seeded");
}
-# endif
+#endif
#endif /* USE_URANDOM_ONLY */
if (chosen_rng == RNG_URANDOM) {
urandom_fd = open(rdev.c_str(), O_RDONLY);
#endif
}
-void dns_random_init(const string& data __attribute__((unused)), bool force) {
+void dns_random_init(const string& data __attribute__((unused)), bool force)
+{
dns_random_setup(force);
(void)dns_random(1);
// init should occur already in dns_random_setup
return;
if (data.size() != 16)
throw std::runtime_error("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));
+ 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
}
-uint32_t dns_random(uint32_t upper_bound) {
+uint32_t dns_random(uint32_t upper_bound)
+{
if (chosen_rng == RNG_UNINITIALIZED)
dns_random_setup();
unsigned int min = pdns::random_minimum_acceptable_value(upper_bound);
- switch(chosen_rng) {
+ switch (chosen_rng) {
case RNG_UNINITIALIZED:
throw std::runtime_error("Unreachable at " __FILE__ ":" + boost::lexical_cast<std::string>(__LINE__)); // cannot be reached
case RNG_SODIUM:
#endif /* RND_SODIUM */
case RNG_OPENSSL: {
#if defined(HAVE_RAND_BYTES) && !defined(USE_URANDOM_ONLY)
- uint32_t num = 0;
- do {
- if (RAND_bytes(reinterpret_cast<unsigned char*>(&num), sizeof(num)) < 1)
- throw std::runtime_error("Openssl RNG was not seeded");
- }
- while(num < min);
+ uint32_t num = 0;
+ do {
+ if (RAND_bytes(reinterpret_cast<unsigned char*>(&num), sizeof(num)) < 1)
+ throw std::runtime_error("Openssl RNG was not seeded");
+ } while (num < min);
- return num % upper_bound;
+ return num % upper_bound;
#else
- throw std::runtime_error("Unreachable at " __FILE__ ":" + boost::lexical_cast<std::string>(__LINE__)); // cannot be reached
+ throw std::runtime_error("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)
- 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());
- }
+ 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(num < min);
+ } while (num < min);
- return num % upper_bound;
+ return num % upper_bound;
#else
- throw std::runtime_error("Unreachable at " __FILE__ ":" + boost::lexical_cast<std::string>(__LINE__)); // cannot be reached
+ throw std::runtime_error("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 arc4random_uniform(upper_bound);
throw std::runtime_error("Unreachable at " __FILE__ ":" + boost::lexical_cast<std::string>(__LINE__)); // cannot be reached
#endif
case RNG_URANDOM: {
- uint32_t num = 0;
- size_t attempts = 5;
- do {
- ssize_t got = read(urandom_fd, &num, sizeof(num));
- if (got < 0) {
- if (errno == EINTR) {
- continue;
- }
-
- (void)close(urandom_fd);
- throw std::runtime_error("Cannot read random device");
- }
- else if (static_cast<size_t>(got) != sizeof(num)) {
- /* short read, let's retry */
- if (attempts == 0) {
- throw std::runtime_error("Too many short reads on random device");
- }
- attempts--;
+ uint32_t num = 0;
+ size_t attempts = 5;
+ do {
+ ssize_t got = read(urandom_fd, &num, sizeof(num));
+ if (got < 0) {
+ if (errno == EINTR) {
continue;
}
+
+ (void)close(urandom_fd);
+ throw std::runtime_error("Cannot read random device");
+ }
+ else if (static_cast<size_t>(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(num < min);
+ } while (num < min);
- return num % upper_bound;
- }
+ return num % upper_bound;
+ }
#if defined(HAVE_KISS_RNG)
case RNG_KISS: {
- uint32_t num = 0;
- do {
- num = kiss_rand();
- }
- while(num < min);
+ uint32_t num = 0;
+ do {
+ num = kiss_rand();
+ } while (num < min);
- return num % upper_bound;
- }
+ return num % upper_bound;
+ }
#endif
default:
throw std::runtime_error("Unreachable at " __FILE__ ":" + boost::lexical_cast<std::string>(__LINE__)); // cannot be reached
uint32_t dns_random(uint32_t n);
uint16_t dns_random_uint16();
-namespace pdns {
- struct dns_random_engine {
+namespace pdns
+{
+struct dns_random_engine
+{
- typedef uint32_t result_type;
+ typedef uint32_t result_type;
- static constexpr result_type min()
- {
- return 0;
- }
-
- static constexpr result_type max()
- {
- return std::numeric_limits<result_type>::max() - 1;
- }
+ static constexpr result_type min()
+ {
+ return 0;
+ }
- result_type operator()()
- {
- return dns_random(std::numeric_limits<result_type>::max());
- }
- };
+ static constexpr result_type max()
+ {
+ return std::numeric_limits<result_type>::max() - 1;
+ }
- /* minimum value that a PRNG should return for this upper bound to avoid a modulo bias */
- inline unsigned int random_minimum_acceptable_value(uint32_t upper_bound)
+ result_type operator()()
{
- /* Parts of this code come from arc4random_uniform */
- /* To avoid "modulo bias" for some methods, calculate
- minimum acceptable value for random number to improve
- uniformity.
+ return dns_random(std::numeric_limits<result_type>::max());
+ }
+};
+
+/* minimum value that a PRNG should return for this upper bound to avoid a modulo bias */
+inline unsigned int random_minimum_acceptable_value(uint32_t upper_bound)
+{
+ /* Parts of this code come from arc4random_uniform */
+ /* 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.
- */
- unsigned int min;
+ On applicable rngs, we loop until the rng spews out
+ value larger than min, and then take modulo out of that.
+ */
+ unsigned int min;
#if (ULONG_MAX > 0xffffffffUL)
- min = 0x100000000UL % upper_bound;
+ 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
- return min;
+ /* 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
+ return min;
+}
}
#include "dns_random.hh"
#include "namespaces.hh"
-
using namespace boost;
using namespace boost::accumulators;
typedef accumulator_set<
- double
- , stats<boost::accumulators::tag::median(with_p_square_quantile),
- boost::accumulators::tag::mean(immediate)
- >
- > acc_t;
-
-
+ double, stats<boost::accumulators::tag::median(with_p_square_quantile), boost::accumulators::tag::mean(immediate)>>
+ acc_t;
BOOST_AUTO_TEST_SUITE(test_dns_random_hh)
-BOOST_AUTO_TEST_CASE(test_dns_random_auto_average) {
+BOOST_AUTO_TEST_CASE(test_dns_random_auto_average)
+{
- ::arg().set("rng")="auto";
- ::arg().set("entropy-source")="/dev/urandom";
+ ::arg().set("rng") = "auto";
+ ::arg().set("entropy-source") = "/dev/urandom";
dns_random_init("", true);
acc_t acc;
- for(unsigned int n=0; n < 100000; ++n) {
- acc(dns_random(100000)/100000.0);
+ for (unsigned int n = 0; n < 100000; ++n) {
+ acc(dns_random(100000) / 100000.0);
}
BOOST_CHECK_CLOSE(0.5, median(acc), 2.0); // within 2%
BOOST_CHECK_CLOSE(0.5, mean(acc), 2.0);
// please add covariance tests, chi-square, Kolmogorov-Smirnov
}
-BOOST_AUTO_TEST_CASE(test_dns_random_urandom_average) {
+BOOST_AUTO_TEST_CASE(test_dns_random_urandom_average)
+{
- ::arg().set("rng")="urandom";
- ::arg().set("entropy-source")="/dev/urandom";
+ ::arg().set("rng") = "urandom";
+ ::arg().set("entropy-source") = "/dev/urandom";
dns_random_init("", true);
acc_t acc;
- for(unsigned int n=0; n < 100000; ++n) {
- acc(dns_random(100000)/100000.0);
+ for (unsigned int n = 0; n < 100000; ++n) {
+ acc(dns_random(100000) / 100000.0);
}
BOOST_CHECK_CLOSE(0.5, median(acc), 2.0); // within 2%
BOOST_CHECK_CLOSE(0.5, mean(acc), 2.0);
// please add covariance tests, chi-square, Kolmogorov-Smirnov
}
-BOOST_AUTO_TEST_CASE(test_dns_random_garbage) {
+BOOST_AUTO_TEST_CASE(test_dns_random_garbage)
+{
- ::arg().set("rng")="garbage";
- ::arg().set("entropy-source")="/dev/urandom";
+ ::arg().set("rng") = "garbage";
+ ::arg().set("entropy-source") = "/dev/urandom";
BOOST_CHECK_THROW(dns_random_init("", true), std::runtime_error);
}
-BOOST_AUTO_TEST_CASE(test_dns_random_upper_bound) {
- ::arg().set("rng")="auto";
- ::arg().set("entropy-source")="/dev/urandom";
+BOOST_AUTO_TEST_CASE(test_dns_random_upper_bound)
+{
+ ::arg().set("rng") = "auto";
+ ::arg().set("entropy-source") = "/dev/urandom";
dns_random_init("", true);
map<int, bool> seen;
- for(unsigned int n=0; n < 100000; ++n) {
+ for (unsigned int n = 0; n < 100000; ++n) {
seen[dns_random(10)] = true;
}
}
#if defined(HAVE_GETRANDOM)
-BOOST_AUTO_TEST_CASE(test_dns_random_getrandom_average) {
+BOOST_AUTO_TEST_CASE(test_dns_random_getrandom_average)
+{
- ::arg().set("rng")="getrandom";
- ::arg().set("entropy-source")="/dev/urandom";
+ ::arg().set("rng") = "getrandom";
+ ::arg().set("entropy-source") = "/dev/urandom";
dns_random_init("", true);
acc_t acc;
- for(unsigned int n=0; n < 100000; ++n) {
- acc(dns_random(100000)/100000.0);
+ for (unsigned int n = 0; n < 100000; ++n) {
+ acc(dns_random(100000) / 100000.0);
}
BOOST_CHECK_CLOSE(0.5, median(acc), 2.0); // within 2%
BOOST_CHECK_CLOSE(0.5, mean(acc), 2.0);
#endif
#if defined(HAVE_ARC4RANDOM)
-BOOST_AUTO_TEST_CASE(test_dns_random_arc4random_average) {
+BOOST_AUTO_TEST_CASE(test_dns_random_arc4random_average)
+{
- ::arg().set("rng")="arc4random";
- ::arg().set("entropy-source")="/dev/urandom";
+ ::arg().set("rng") = "arc4random";
+ ::arg().set("entropy-source") = "/dev/urandom";
dns_random_init("", true);
acc_t acc;
- for(unsigned int n=0; n < 100000; ++n) {
- acc(dns_random(100000)/100000.0);
+ for (unsigned int n = 0; n < 100000; ++n) {
+ acc(dns_random(100000) / 100000.0);
}
BOOST_CHECK_CLOSE(0.5, median(acc), 2.0); // within 2%
BOOST_CHECK_CLOSE(0.5, mean(acc), 2.0);
#endif
#if defined(HAVE_RANDOMBYTES_STIR)
-BOOST_AUTO_TEST_CASE(test_dns_random_sodium_average) {
+BOOST_AUTO_TEST_CASE(test_dns_random_sodium_average)
+{
- ::arg().set("rng")="sodium";
- ::arg().set("entropy-source")="/dev/urandom";
+ ::arg().set("rng") = "sodium";
+ ::arg().set("entropy-source") = "/dev/urandom";
dns_random_init("", true);
acc_t acc;
- for(unsigned int n=0; n < 100000; ++n) {
- acc(dns_random(100000)/100000.0);
+ for (unsigned int n = 0; n < 100000; ++n) {
+ acc(dns_random(100000) / 100000.0);
}
BOOST_CHECK_CLOSE(0.5, median(acc), 2.0); // within 2%
BOOST_CHECK_CLOSE(0.5, mean(acc), 2.0);
#endif
#if defined(HAVE_RAND_BYTES)
-BOOST_AUTO_TEST_CASE(test_dns_random_openssl_average) {
+BOOST_AUTO_TEST_CASE(test_dns_random_openssl_average)
+{
- ::arg().set("rng")="openssl";
- ::arg().set("entropy-source")="/dev/urandom";
+ ::arg().set("rng") = "openssl";
+ ::arg().set("entropy-source") = "/dev/urandom";
dns_random_init("", true);
acc_t acc;
- for(unsigned int n=0; n < 100000; ++n) {
- acc(dns_random(100000)/100000.0);
+ for (unsigned int n = 0; n < 100000; ++n) {
+ acc(dns_random(100000) / 100000.0);
}
BOOST_CHECK_CLOSE(0.5, median(acc), 2.0); // within 2%
BOOST_CHECK_CLOSE(0.5, mean(acc), 2.0);
#endif
#if defined(HAVE_KISS_RNG)
-BOOST_AUTO_TEST_CASE(test_dns_random_kiss_average) {
+BOOST_AUTO_TEST_CASE(test_dns_random_kiss_average)
+{
- ::arg().set("rng")="kiss";
- ::arg().set("entropy-source")="/dev/urandom";
+ ::arg().set("rng") = "kiss";
+ ::arg().set("entropy-source") = "/dev/urandom";
dns_random_init("", true);
acc_t acc;
- for(unsigned int n=0; n < 100000; ++n) {
- acc(dns_random(100000)/100000.0);
+ for (unsigned int n = 0; n < 100000; ++n) {
+ acc(dns_random(100000) / 100000.0);
}
BOOST_CHECK_CLOSE(0.5, median(acc), 2.0); // within 2%
BOOST_CHECK_CLOSE(0.5, mean(acc), 2.0);
}
#endif
-
BOOST_AUTO_TEST_SUITE_END()
#endif