From 141ded72f4da92408bad7df2b08c81a76e9fd624 Mon Sep 17 00:00:00 2001 From: d-wibowo Date: Fri, 23 Aug 2024 13:30:23 +0700 Subject: [PATCH 1/8] auth: added a new config for direct queries of dnskey signature --- pdns/auth-main.cc | 1 + pdns/dnssecsigner.cc | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pdns/auth-main.cc b/pdns/auth-main.cc index 691242143f2e..722ae7e86051 100644 --- a/pdns/auth-main.cc +++ b/pdns/auth-main.cc @@ -295,6 +295,7 @@ static void declareArguments() ::arg().setSwitch("traceback-handler", "Enable the traceback handler (Linux only)") = "yes"; ::arg().setSwitch("direct-dnskey", "Fetch DNSKEY, CDS and CDNSKEY RRs from backend during DNSKEY or CDS/CDNSKEY synthesis") = "no"; + ::arg().setSwitch("direct-dnskey-signature", "Fetch signature of DNSKEY RRs from backend directly") = "no"; ::arg().set("default-ksk-algorithm", "Default KSK algorithm") = "ecdsa256"; ::arg().set("default-ksk-size", "Default KSK size (0 means default)") = "0"; ::arg().set("default-zsk-algorithm", "Default ZSK algorithm") = ""; diff --git a/pdns/dnssecsigner.cc b/pdns/dnssecsigner.cc index 0e122c11a319..041a642a503b 100644 --- a/pdns/dnssecsigner.cc +++ b/pdns/dnssecsigner.cc @@ -151,7 +151,7 @@ static void addSignature(DNSSECKeeper& dk, UeberBackend& db, const DNSName& sign if(toSign.empty()) return; vector rrcs; - if(dk.isPresigned(signer)) { + if(dk.isPresigned(signer) || (::arg().mustDo("direct-dnskey-signature") && signQType == QType::DNSKEY)) { //cerr<<"Doing presignatures"< Date: Wed, 8 Jan 2025 10:54:00 +0700 Subject: [PATCH 2/8] updated settings.rst for direct-dnskey-signature --- docs/settings.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/settings.rst b/docs/settings.rst index 506b24845651..66e242d59c15 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -572,6 +572,17 @@ Configure a delay to send out notifications, no delay by default. Read additional DNSKEY, CDS and CDNSKEY records from the records table/your BIND zonefile. If not set, DNSKEY, CDS and CDNSKEY records in the zonefiles are ignored. +.. _setting-direct-dnskey-signature: + +``direct-dnskey-signature`` +----------------- + +- Boolean +- Default: no + +Read signatures of DNSKEY records directly from the backend. If not set and the record is not presigned, +DNSKEY records will be signed directly by PDNS Authoritative. + .. _setting-disable-axfr: ``disable-axfr`` From 7c30df1e688e2662119e1d5a5c614d37ee99e6c8 Mon Sep 17 00:00:00 2001 From: d-wibowo Date: Thu, 9 Jan 2025 11:23:05 +0700 Subject: [PATCH 3/8] added regression test for direct dnskey signature --- .../test_DirectDNSKEYSignature.py | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 regression-tests.auth-py/test_DirectDNSKEYSignature.py diff --git a/regression-tests.auth-py/test_DirectDNSKEYSignature.py b/regression-tests.auth-py/test_DirectDNSKEYSignature.py new file mode 100644 index 000000000000..014ca10dd1f0 --- /dev/null +++ b/regression-tests.auth-py/test_DirectDNSKEYSignature.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python + +import dns +import os +import socket +from authtests import AuthTest + +class TestDirectDNSKEYSignature(AuthTest): + _config_template = """ + launch=bind + direct-dnskey=yes + direct-dnskey-signature=yes + """ + + _zones = { + 'example.org': """ +example.org. 3600 IN SOA {soa} +example.org. 3600 IN NS ns1.example.org. +example.org. 3600 IN NS ns2.example.org. +ns1.example.org. 3600 IN A 192.0.2.1 +ns2.example.org. 3600 IN A 192.0.2.2 +example.org. 3600 IN DNSKEY 257 3 13 kRMX25/TJovOrsWq9Hv6QEFpzYsxItaOWPduFEwPz+5FM97SEHyCx+fc /XUN9gtktpXx45LAZpg/sFFEQH89og== +example.org. 3600 IN DNSKEY 256 3 13 Fy1p5/TTniw9Ukwca3Fnjo4tQk9ZK5zSwX9HZhHC2Tta/+3OZ9+y/Noz G51m/vs/I3oo9OqF+znxOi69yuGZaQ== +example.org. 3600 IN RRSIG DNSKEY 13 2 3600 20250118211239 20241228221941 22273 example.org. 8HNifVnXhm5u+YDL8wWuJou5BWPzRYainXaP45qn2/yoPqBXSwhGFA2a kmh2Lqpj2D7qcs3KJ/QAR1QZ9CUAjw== + """ + } + + @classmethod + def setUpClass(cls): + cls.setUpSockets() + cls.startResponders() + confdir = os.path.join('configs', cls._confdir) + cls.createConfigDir(confdir) + cls.generateAllAuthConfig(confdir) + cls.startAuth(confdir, "0.0.0.0") + print("Launching tests...") + + @classmethod + def setUpSockets(cls): + print("Setting up UDP socket...") + cls._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + cls._sock.settimeout(2.0) + cls._sock.connect((cls._PREFIX + ".2", cls._authPort)) + + def testDNSKEYQuery(self): + """Test to verify DNSKEY and RRSIG records are served correctly""" + query = dns.message.make_query('example.org', 'DNSKEY', use_edns=True, want_dnssec=True) + res = self.sendUDPQuery(query) + + # Ensure no error in response + self.assertRcodeEqual(res, dns.rcode.NOERROR) + + # Validate DNSKEY record + dnskey_found = any(rrset.rdtype == dns.rdatatype.DNSKEY for rrset in res.answer) + self.assertTrue(dnskey_found, "DNSKEY record not found in the answer section") + + # Validate RRSIG record for DNSKEY + rrsig_found = any(rrset.rdtype == dns.rdatatype.RRSIG and rrset.covers == dns.rdatatype.DNSKEY for rrset in res.answer) + self.assertTrue(rrsig_found, "RRSIG for DNSKEY not found in the answer section") + + def testDNSKEYQueryWithoutDNSSEC(self): + """Test to ensure no RRSIG records are returned without the DNSSEC flag""" + query = dns.message.make_query('example.org', 'DNSKEY', use_edns=True, want_dnssec=False) + res = self.sendUDPQuery(query) + + # Ensure no error in response + self.assertRcodeEqual(res, dns.rcode.NOERROR) + + # Ensure DNSKEY is present but no RRSIG + dnskey_found = any(rrset.rdtype == dns.rdatatype.DNSKEY for rrset in res.answer) + self.assertTrue(dnskey_found, "DNSKEY record not found in the answer section") + + rrsig_found = any(rrset.rdtype == dns.rdatatype.RRSIG for rrset in res.answer) + self.assertFalse(rrsig_found, "RRSIG records found unexpectedly without DNSSEC flag") \ No newline at end of file From 7446800f7c71b7e81feb6f47a34d836ec73fa717 Mon Sep 17 00:00:00 2001 From: d-wibowo Date: Tue, 14 Jan 2025 08:14:27 +0700 Subject: [PATCH 4/8] ended regression test file in newline --- regression-tests.auth-py/test_DirectDNSKEYSignature.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regression-tests.auth-py/test_DirectDNSKEYSignature.py b/regression-tests.auth-py/test_DirectDNSKEYSignature.py index 014ca10dd1f0..fe5929ba7ba7 100644 --- a/regression-tests.auth-py/test_DirectDNSKEYSignature.py +++ b/regression-tests.auth-py/test_DirectDNSKEYSignature.py @@ -71,4 +71,4 @@ def testDNSKEYQueryWithoutDNSSEC(self): self.assertTrue(dnskey_found, "DNSKEY record not found in the answer section") rrsig_found = any(rrset.rdtype == dns.rdatatype.RRSIG for rrset in res.answer) - self.assertFalse(rrsig_found, "RRSIG records found unexpectedly without DNSSEC flag") \ No newline at end of file + self.assertFalse(rrsig_found, "RRSIG records found unexpectedly without DNSSEC flag") From 73cb7edc6af01947c1fb9161cb64dc4e5cc0e6ec Mon Sep 17 00:00:00 2001 From: d-wibowo Date: Tue, 14 Jan 2025 08:19:15 +0700 Subject: [PATCH 5/8] updated docs for 'direct-dnskey-signature' --- docs/settings.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/settings.rst b/docs/settings.rst index 66e242d59c15..97edfd14cc35 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -580,8 +580,9 @@ set, DNSKEY, CDS and CDNSKEY records in the zonefiles are ignored. - Boolean - Default: no -Read signatures of DNSKEY records directly from the backend. If not set and the record is not presigned, -DNSKEY records will be signed directly by PDNS Authoritative. +Read signatures of DNSKEY records directly from the backend. +If not set and the record is not presigned, DNSKEY records will be signed directly by PDNS Authoritative. +Please only use this if you are sure that you need it. .. _setting-disable-axfr: From 1d5c4ea5ac55bd75adb4fefbf81d2f452af50f3e Mon Sep 17 00:00:00 2001 From: Dyno Wibowo <102284364+d-wibowo@users.noreply.github.com> Date: Wed, 15 Jan 2025 07:56:52 +0700 Subject: [PATCH 6/8] Update docs/settings.rst Co-authored-by: Peter van Dijk --- docs/settings.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/settings.rst b/docs/settings.rst index 97edfd14cc35..0181b2894913 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -580,6 +580,8 @@ set, DNSKEY, CDS and CDNSKEY records in the zonefiles are ignored. - Boolean - Default: no +.. versionadded:: 5.0.0 + Read signatures of DNSKEY records directly from the backend. If not set and the record is not presigned, DNSKEY records will be signed directly by PDNS Authoritative. Please only use this if you are sure that you need it. From 18f17eb9e5300bb122f4353dc23223be065767ca Mon Sep 17 00:00:00 2001 From: Peter van Dijk Date: Fri, 17 Jan 2025 11:29:03 +0100 Subject: [PATCH 7/8] assert key_tag too --- regression-tests.auth-py/test_DirectDNSKEYSignature.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regression-tests.auth-py/test_DirectDNSKEYSignature.py b/regression-tests.auth-py/test_DirectDNSKEYSignature.py index fe5929ba7ba7..bb63eda2a604 100644 --- a/regression-tests.auth-py/test_DirectDNSKEYSignature.py +++ b/regression-tests.auth-py/test_DirectDNSKEYSignature.py @@ -55,7 +55,7 @@ def testDNSKEYQuery(self): self.assertTrue(dnskey_found, "DNSKEY record not found in the answer section") # Validate RRSIG record for DNSKEY - rrsig_found = any(rrset.rdtype == dns.rdatatype.RRSIG and rrset.covers == dns.rdatatype.DNSKEY for rrset in res.answer) + rrsig_found = any(rrset.rdtype == dns.rdatatype.RRSIG and rrset.covers == dns.rdatatype.DNSKEY and rrset[0].key_tag == 22273 for rrset in res.answer) self.assertTrue(rrsig_found, "RRSIG for DNSKEY not found in the answer section") def testDNSKEYQueryWithoutDNSSEC(self): From 8aa9a8409f807690e6c5ea927fac3eb7f9d7f844 Mon Sep 17 00:00:00 2001 From: Peter van Dijk Date: Fri, 17 Jan 2025 11:31:35 +0100 Subject: [PATCH 8/8] only look up direct-dnskey-signature in the config once --- pdns/dnssecsigner.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pdns/dnssecsigner.cc b/pdns/dnssecsigner.cc index 041a642a503b..4a9ab1e7dadf 100644 --- a/pdns/dnssecsigner.cc +++ b/pdns/dnssecsigner.cc @@ -147,11 +147,13 @@ static void addSignature(DNSSECKeeper& dk, UeberBackend& db, const DNSName& sign uint32_t signTTL, DNSResourceRecord::Place signPlace, sortedRecords_t& toSign, vector& outsigned, uint32_t origTTL, DNSPacket* packet) { + static bool directDNSKEYSignature = ::arg().mustDo("direct-dnskey-signature"); + //cerr<<"Asked to sign '"< rrcs; - if(dk.isPresigned(signer) || (::arg().mustDo("direct-dnskey-signature") && signQType == QType::DNSKEY)) { + if(dk.isPresigned(signer) || (directDNSKEYSignature && signQType == QType::DNSKEY)) { //cerr<<"Doing presignatures"<