From 94328c3c1c321669711a0cd4398618f40b8d56dd Mon Sep 17 00:00:00 2001 From: Miod Vallat Date: Wed, 30 Jul 2025 14:40:11 +0200 Subject: [PATCH] Allow edns-cookie-secret to be set to "random". Signed-off-by: Miod Vallat --- docs/settings.rst | 3 +++ pdns/auth-main.cc | 24 ++++++++++++++++-------- regression-tests.auth-py/test_Cookies.py | 7 ++++++- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/docs/settings.rst b/docs/settings.rst index 4545d623e8..482ec473e2 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -744,6 +744,9 @@ PowerDNS will also respond with BADCOOKIE to clients that have sent only a clien This setting MUST be 32 hexadecimal characters, as the siphash algorithm's key used to create the cookie requires a 128-bit key. +Alternatively, starting with version 5.0.0, this parameter can be set to +`random`, in which case a random cookie value will be generated upon startup. + .. _setting-edns-subnet-processing: ``edns-subnet-processing`` diff --git a/pdns/auth-main.cc b/pdns/auth-main.cc index 017285ec8f..0a28e3faf3 100644 --- a/pdns/auth-main.cc +++ b/pdns/auth-main.cc @@ -744,15 +744,23 @@ static void mainthread() // User wants cookie processing #ifdef HAVE_CRYPTO_SHORTHASH // we can do siphash-based cookies DNSPacket::s_doEDNSCookieProcessing = true; - try { - if (::arg()["edns-cookie-secret"].size() != EDNSCookiesOpt::EDNSCookieSecretSize) { - throw std::range_error("wrong size (" + std::to_string(::arg()["edns-cookie-secret"].size()) + "), must be " + std::to_string(EDNSCookiesOpt::EDNSCookieSecretSize)); - } - DNSPacket::s_EDNSCookieKey = makeBytesFromHex(::arg()["edns-cookie-secret"]); + const std::string& secret = ::arg()["edns-cookie-secret"]; + if (secret == "random") { + std::array key{}; + dns_random(key.data(), key.size()); + DNSPacket::s_EDNSCookieKey = std::string(key.data(), key.size()); } - catch (const std::range_error& e) { - g_log << Logger::Error << "edns-cookie-secret invalid: " << e.what() << endl; - exit(1); + else { + try { + if (secret.size() != EDNSCookiesOpt::EDNSCookieSecretSize) { + throw std::range_error("wrong size (" + std::to_string(secret.size()) + "), must be " + std::to_string(EDNSCookiesOpt::EDNSCookieSecretSize)); + } + DNSPacket::s_EDNSCookieKey = makeBytesFromHex(secret); + } + catch (const std::range_error& e) { + g_log << Logger::Error << "edns-cookie-secret invalid: " << e.what() << endl; + exit(1); // NOLINT(concurrency-mt-unsafe) we're single threaded at this point + } } #else g_log << Logger::Error << "Support for EDNS Cookies is not available because of missing cryptographic functions (libsodium support should be enabled, with the crypto_shorthash() function available)" << endl; diff --git a/regression-tests.auth-py/test_Cookies.py b/regression-tests.auth-py/test_Cookies.py index ac85c3312b..e063b48c6d 100644 --- a/regression-tests.auth-py/test_Cookies.py +++ b/regression-tests.auth-py/test_Cookies.py @@ -3,7 +3,6 @@ import dns from authtests import AuthTest - class TestEdnsCookies(AuthTest): _config_template = """ launch={backend} @@ -108,3 +107,9 @@ www.example.org. 3600 IN A 192.0.2.5 self.assertNotEqual(opt.data, opts[0].data) return self.fail() + +class TestEdnsRandomCookies(TestEdnsCookies): + _config_template = """ +launch={backend} +edns-cookie-secret=random +""" -- 2.47.2