From 35ff15d320a7b7b3ab63ca5eac081a633099c83c Mon Sep 17 00:00:00 2001 From: snek Date: Thu, 11 Jun 2026 18:07:27 +0200 Subject: [PATCH] pdns: emit rrsig on alias responses Signed-off-by: snek --- docs/dnssec/modes-of-operation.rst | 3 - docs/guides/alias.rst | 9 +- pdns/dnsproxy.cc | 45 ++++++- pdns/dnsproxy.hh | 12 +- pdns/packethandler.cc | 2 +- regression-tests.auth-py/authtests.py | 2 +- regression-tests.auth-py/requirements.in | 1 + regression-tests.auth-py/requirements.txt | 143 +++++++++++++++++++++- regression-tests.auth-py/test_ALIAS.py | 60 +++++++++ 9 files changed, 265 insertions(+), 12 deletions(-) diff --git a/docs/dnssec/modes-of-operation.rst b/docs/dnssec/modes-of-operation.rst index 72aae06e3f10..09a472b094cb 100644 --- a/docs/dnssec/modes-of-operation.rst +++ b/docs/dnssec/modes-of-operation.rst @@ -32,9 +32,6 @@ DNSSEC data using the original keys. Such a single replicated database requires no further attention beyond monitoring already required during non-DNSSEC operations. -Please note that the ALIAS record type is -:ref:`not supported ` in this mode. - Records, Keys, signatures, hashes within PowerDNS in online signing mode ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/guides/alias.rst b/docs/guides/alias.rst index b528f80d83c3..0297981acf70 100644 --- a/docs/guides/alias.rst +++ b/docs/guides/alias.rst @@ -84,7 +84,8 @@ When set to 'ignore-errors', an unresolvable ALIAS target will be omitted from t ALIAS and DNSSEC ---------------- -Starting with the PowerDNS Authoritative Server 4.0.0, DNSSEC 'washing' -of ALIAS records is supported on AXFR (**not** on live-signing). Set -``outgoing-axfr-expand-alias`` to 'yes' and enable DNSSEC for the zone -on the primary. PowerDNS will sign the A/AAAA records during the AXFR. +Starting with the PowerDNS Authoritative Server 4.0.0, DNSSEC 'washing' of +ALIAS records is supported on AXFR. Set ``outgoing-axfr-expand-alias`` to +'yes' and enable DNSSEC for the zone on the primary. PowerDNS will sign the +A/AAAA records during the AXFR. Starting with PowerDNS Authoritative Server +?.?.?, live-signing is also supported. diff --git a/pdns/dnsproxy.cc b/pdns/dnsproxy.cc index 3c34ce5d9ec8..a53ce3352e52 100644 --- a/pdns/dnsproxy.cc +++ b/pdns/dnsproxy.cc @@ -39,6 +39,9 @@ #include "ednsoptions.hh" #include "ednssubnet.hh" #include "dnsproxy.hh" +#include "dnsseckeeper.hh" +#include "dnssecinfra.hh" +#include "ueberbackend.hh" #include @@ -111,7 +114,7 @@ void DNSProxy::go() } //! look up qname 'target' with reply->qtype, plonk it in the answer section of 'reply' with name 'aname' -bool DNSProxy::completePacket(std::unique_ptr& reply, const DNSName& target, const DNSName& aname, const uint8_t scopeMask) +bool DNSProxy::completePacket(std::unique_ptr& reply, const DNSName& target, const DNSName& aname, const uint8_t scopeMask, const bool doSign, const std::set& authSet, DNSSECKeeper& dnssecKeeper, UeberBackend& backend) { string ECSOptionStr; @@ -157,6 +160,23 @@ bool DNSProxy::completePacket(std::unique_ptr& reply, const DNSName& ip.dr.d_name = aname; reply->addRecord(std::move(ip)); } + if (doSign) { + try { + addRRSigs(dnssecKeeper, backend, authSet, reply->getRRS(), reply.get()); + } + catch (const std::exception& e) { + SLOG(g_log << Logger::Error << "Error signing ALIAS answer for " << aname << " over TCP: " << e.what() << ", returning SERVFAIL" << endl, + d_slog->error(Logr::Error, e.what(), "Error signing ALIAS answer over TCP, returning SERVFAIL", "alias", Logging::Loggable(aname))); + reply->clearRecords(); + reply->setRcode(RCode::ServFail); + } + catch (const PDNSException& e) { + SLOG(g_log << Logger::Error << "Error signing ALIAS answer for " << aname << " over TCP: " << e.reason << ", returning SERVFAIL" << endl, + d_slog->error(Logr::Error, e.reason, "Error signing ALIAS answer over TCP, returning SERVFAIL", "alias", Logging::Loggable(aname))); + reply->clearRecords(); + reply->setRcode(RCode::ServFail); + } + } } uint16_t len = htons(reply->getString().length()); @@ -184,6 +204,8 @@ bool DNSProxy::completePacket(std::unique_ptr& reply, const DNSName& ce.complete = std::move(reply); ce.aname = aname; ce.anameScopeMask = scopeMask; + ce.doSign = doSign; + ce.authSet = authSet; (*conntrack)[id] = std::move(ce); } @@ -234,6 +256,9 @@ void DNSProxy::mainloop() { setThreadName("pdns/dnsproxy"); try { + UeberBackend db; + DNSSECKeeper dk(d_slog, &db); + char buffer[1500]; ssize_t len; @@ -324,6 +349,24 @@ void DNSProxy::mainloop() } iter->second.complete->setRcode(mdp.d_header.rcode); + + if (iter->second.doSign) { + try { + addRRSigs(dk, db, iter->second.authSet, iter->second.complete->getRRS(), iter->second.complete.get()); + } + catch (const std::exception& e) { + SLOG(g_log << Logger::Error << "Error signing ALIAS answer for " << iter->second.aname << ": " << e.what() << ", returning SERVFAIL" << endl, + d_slog->error(Logr::Error, e.what(), "Error signing ALIAS answer, returning SERVFAIL", "alias", Logging::Loggable(iter->second.aname))); + iter->second.complete->clearRecords(); + iter->second.complete->setRcode(RCode::ServFail); + } + catch (const PDNSException& e) { + SLOG(g_log << Logger::Error << "Error signing ALIAS answer for " << iter->second.aname << ": " << e.reason << ", returning SERVFAIL" << endl, + d_slog->error(Logr::Error, e.reason, "Error signing ALIAS answer, returning SERVFAIL", "alias", Logging::Loggable(iter->second.aname))); + iter->second.complete->clearRecords(); + iter->second.complete->setRcode(RCode::ServFail); + } + } } else { SLOG(g_log << Logger::Error << "Error resolving for " << iter->second.aname << " ALIAS " << iter->second.qname << " over UDP, " << QType(iter->second.qtype).toString() << "-record query returned " << RCode::to_s(mdp.d_header.rcode) << ", returning SERVFAIL" << endl, diff --git a/pdns/dnsproxy.hh b/pdns/dnsproxy.hh index 975ecd28ff9b..218e963f296a 100644 --- a/pdns/dnsproxy.hh +++ b/pdns/dnsproxy.hh @@ -21,6 +21,7 @@ */ #pragma once #include +#include #include #include #include @@ -29,6 +30,7 @@ #include "dnspacket.hh" #include "lock.hh" #include "iputils.hh" +#include "dnsname.hh" #include "namespaces.hh" @@ -48,13 +50,19 @@ to make sure outside parties can't spoof us. To fix: how to remove the stale entries that will surely accumulate */ +class DNSSECKeeper; +class UeberBackend; + class DNSProxy { public: DNSProxy(Logr::log_t slog, const string& remote, const string& udpPortRange); //!< creates socket ~DNSProxy(); //& reply, const DNSName& target, const DNSName& aname, uint8_t scopeMask); + // dnssecKeeper and backend are only used for the TCP path, where signing + // happens synchronously in the caller's thread; the UDP path signs later in + // mainloop() using its own thread-local backend. + bool completePacket(std::unique_ptr& reply, const DNSName& target, const DNSName& aname, uint8_t scopeMask, bool doSign, const std::set& authSet, DNSSECKeeper& dnssecKeeper, UeberBackend& backend); void mainloop(); //!< this is the main loop that receives reply packets and sends them out again private: @@ -65,7 +73,9 @@ private: DNSName qname; std::unique_ptr complete; DNSName aname; + std::set authSet; uint8_t anameScopeMask; + bool doSign{false}; ComboAddress remote; uint16_t id; uint16_t qtype; diff --git a/pdns/packethandler.cc b/pdns/packethandler.cc index cd7a70520144..339b8c417fb9 100644 --- a/pdns/packethandler.cc +++ b/pdns/packethandler.cc @@ -1998,7 +1998,7 @@ bool PacketHandler::opcodeQueryInner2(DNSPacket& pkt, queryState &state, bool re if(!haveAlias.empty() && (!weDone || pkt.qtype.getCode() == QType::ANY)) { DLOG(SLOG(g_log<info(Logr::Warning, "Found nothing that matched, but got alias, referring", "query", Logging::Loggable(state.target), "alias", Logging::Loggable(haveAlias)))); - DP->completePacket(state.r, haveAlias, state.target, aliasScopeMask); + DP->completePacket(state.r, haveAlias, state.target, aliasScopeMask, d_dnssec, state.authSet, d_dk, B); state.r = nullptr; return false; } diff --git a/regression-tests.auth-py/authtests.py b/regression-tests.auth-py/authtests.py index b3db557b4292..32760194e966 100644 --- a/regression-tests.auth-py/authtests.py +++ b/regression-tests.auth-py/authtests.py @@ -638,7 +638,7 @@ def assertMatchingRRSIGInAnswer(self, msg, coveredRRset, keys=None): if keys: try: - dns.dnssec.validate(msgRRSet, msgRRsigRRSet.to_rdataset(), keys) + dns.dnssec.validate(msgRRSet, msgRRsigRRSet, keys) except dns.dnssec.ValidationFailure as e: raise AssertionError("Signature validation failed for %s:\n%s" % (msg.question[0].to_text(), e)) diff --git a/regression-tests.auth-py/requirements.in b/regression-tests.auth-py/requirements.in index 8aaa42d3f08e..a7ca14a8bffe 100644 --- a/regression-tests.auth-py/requirements.in +++ b/regression-tests.auth-py/requirements.in @@ -3,6 +3,7 @@ wheel==0.46.3 dnspython +cryptography>=43 pytest Twisted>0.15.0 requests>=2.18.4 diff --git a/regression-tests.auth-py/requirements.txt b/regression-tests.auth-py/requirements.txt index 28dfc0d0acad..ec8c649e893b 100644 --- a/regression-tests.auth-py/requirements.txt +++ b/regression-tests.auth-py/requirements.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.13 +# This file is autogenerated by pip-compile with Python 3.14 # by the following command: # # pip-compile --allow-unsafe --generate-hashes requirements.in @@ -16,6 +16,92 @@ certifi==2026.5.20 \ --hash=sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897 \ --hash=sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d # via requests +cffi==2.0.0 \ + --hash=sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb \ + --hash=sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b \ + --hash=sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f \ + --hash=sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9 \ + --hash=sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44 \ + --hash=sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2 \ + --hash=sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c \ + --hash=sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75 \ + --hash=sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65 \ + --hash=sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e \ + --hash=sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a \ + --hash=sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e \ + --hash=sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25 \ + --hash=sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a \ + --hash=sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe \ + --hash=sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b \ + --hash=sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91 \ + --hash=sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592 \ + --hash=sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187 \ + --hash=sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c \ + --hash=sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1 \ + --hash=sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94 \ + --hash=sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba \ + --hash=sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb \ + --hash=sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165 \ + --hash=sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529 \ + --hash=sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca \ + --hash=sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c \ + --hash=sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6 \ + --hash=sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c \ + --hash=sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0 \ + --hash=sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743 \ + --hash=sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63 \ + --hash=sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5 \ + --hash=sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5 \ + --hash=sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4 \ + --hash=sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d \ + --hash=sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b \ + --hash=sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93 \ + --hash=sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205 \ + --hash=sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27 \ + --hash=sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512 \ + --hash=sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d \ + --hash=sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c \ + --hash=sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037 \ + --hash=sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26 \ + --hash=sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322 \ + --hash=sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb \ + --hash=sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c \ + --hash=sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8 \ + --hash=sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4 \ + --hash=sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414 \ + --hash=sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9 \ + --hash=sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664 \ + --hash=sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9 \ + --hash=sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775 \ + --hash=sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739 \ + --hash=sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc \ + --hash=sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062 \ + --hash=sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe \ + --hash=sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9 \ + --hash=sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92 \ + --hash=sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5 \ + --hash=sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13 \ + --hash=sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d \ + --hash=sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26 \ + --hash=sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f \ + --hash=sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495 \ + --hash=sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b \ + --hash=sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6 \ + --hash=sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c \ + --hash=sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef \ + --hash=sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5 \ + --hash=sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18 \ + --hash=sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad \ + --hash=sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3 \ + --hash=sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7 \ + --hash=sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5 \ + --hash=sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534 \ + --hash=sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49 \ + --hash=sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2 \ + --hash=sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5 \ + --hash=sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453 \ + --hash=sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf + # via cryptography charset-normalizer==3.4.7 \ --hash=sha256:007d05ec7321d12a40227aae9e2bc6dca73f3cb21058999a1df9e193555a9dcc \ --hash=sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c \ @@ -151,6 +237,57 @@ constantly==23.10.4 \ --hash=sha256:3fd9b4d1c3dc1ec9757f3c52aef7e53ad9323dbe39f51dfd4c43853b68dfa3f9 \ --hash=sha256:aa92b70a33e2ac0bb33cd745eb61776594dc48764b06c35e0efd050b7f1c7cbd # via twisted +cryptography==48.0.1 \ + --hash=sha256:08a597acce1ff37f347400087776599e2348a3a8bc53b44120e463cd274efe4a \ + --hash=sha256:09f73a725d582cef64b91281a322cd798d14a33b2b6f2b7ad9531dc336d84c02 \ + --hash=sha256:0df56b056bc17c1b7d6821dfa65216e62bd232d8ab05eb3db44e71d235651471 \ + --hash=sha256:0ee6ea481db1ab889cba043ec1eda17bb9c1ea79db6722f779c3667f9f70322f \ + --hash=sha256:15254441469dd6bf027039453288e2072124f8b6603563f5d759e1c9b69273fa \ + --hash=sha256:266f4ee051abb2f725b74ef8072b521ce1feacf685a3364fa6a6b45548db791a \ + --hash=sha256:2c37f2461406063b417837f5f3daab668652acd82423efcd7f0a9f04be972de1 \ + --hash=sha256:32143b24adb918f078134e1e230f1eb8cc04886b92c28b5f0041aaf3e5699225 \ + --hash=sha256:33842cf0888951cef5bc7ac724ab844a42044c1727b967b7f8997289a0464f92 \ + --hash=sha256:3752f2dbc8f07a30aad2932c986cea495b03bb554887828225da104f732852b6 \ + --hash=sha256:39489bfca54c7a1f6b297efcd8bc608ab92d16c4ca631b0cad4da46724588b24 \ + --hash=sha256:3e4a1a3232eef2e6c732827d5722db29a0cc8b27af2a4d865b094cf954be9ca1 \ + --hash=sha256:3fd2ca57062b241c856670b073487d2e86c4637937ca5601e48f97bf8e11fc8f \ + --hash=sha256:42fcd8e26fe555d9b3577a135f5091fefa0aa4e99129c23fb56787a1bd4ada72 \ + --hash=sha256:43c5835e2cb98c8733d86f57d6fc879b613f5c3478607281c3e36daffc6dd8a6 \ + --hash=sha256:48fe40804d4caa2288f24e70ca8c64c42dd826da0ad7e4f1b41b2128d679e6c8 \ + --hash=sha256:4ab0a343c807bbcd90c971cd1ecf072937cd01847a9e002bef88fb47ac6be577 \ + --hash=sha256:4fdc69f8e4316bcf0c8c8ec1f26f285d12e8142d88d96c876a59a03be3f6ae67 \ + --hash=sha256:6184ca7b174f28d7c703f1290d4b297217c45355f77a98f67e9b7f14549ac54a \ + --hash=sha256:66fd0771e7b9c6dcd44cf1120690d2338d16d72795cf40cae2786a39eba65429 \ + --hash=sha256:6b2c0c3e6ccf3ade7750f836ef3ee36eea250cc467d45c256895573ac08cc6f1 \ + --hash=sha256:735824ec41b7f74a7c45fb1591349333e4c696cb6c044e5f46356e560143e4cd \ + --hash=sha256:7e234ac052af99f2700826a5c29ea99d9c1b1f80341cde62d11c8154dc8e0bd9 \ + --hash=sha256:869c3b8a53bfe27147832df48b32adadf558249d50e76cb3769d40e986b13265 \ + --hash=sha256:86be3b1b0b6bf09482fb50a979c508d2950ed95f5621ec77f4e385962006b83a \ + --hash=sha256:86fe77abb1bd87afb251d4d02ada7ecf53a32cee9b67d976abb2e45a13297475 \ + --hash=sha256:88c852a0ae366e262e5a1744b685e6a433dc8788dd2a277e418bf4904203609d \ + --hash=sha256:8ace4507d1e6533c125f4fac754f8bb8b6a74c08e92179dabd7e16571a3efbf3 \ + --hash=sha256:92a46e1d638daa264ba2971c0b0489c9409787943efae4d60ffda3d091ef832c \ + --hash=sha256:9621de99d2da096006b629979efd8ae7eb2d8b822488d0c89ee4000c306c59b1 \ + --hash=sha256:9a49ca6c81417f6a5edb50375a60cccdd70fa0a91a5211829dbea74eba94d2ac \ + --hash=sha256:9bd3f92d76217892b15df84ca256c2c113d386fdda7a7d8691aeeced976507c6 \ + --hash=sha256:9de21387aa95e2a895823d0745b430bed4f33503ba9ab5e0b5311f33e37d66d2 \ + --hash=sha256:b024e784ad6c077ee0147b35ea9cbfc1e34e1fd4c1dcca214c2794d73a12df08 \ + --hash=sha256:b4e391975f038e66432328639620a4aff2d307513b004f1ca06d6225bced815c \ + --hash=sha256:b74ca3b8e5ecdd833bf6a002ca41b4793bb27fb8f1c06ffaf2643c9e9140e31b \ + --hash=sha256:b7a2d1a937a738a881737cec135a38bb61470589b17515b9f73f571d0ae10401 \ + --hash=sha256:b9a32b876490d66c8bcc9963ef220199569748434ab01a9d6aaeabf88e7f5158 \ + --hash=sha256:bd81490cd5801d755cf97bb68ac191f14b708470b1c7cf4580f669b9c9264cd8 \ + --hash=sha256:c1400da5e32a43253392277eac7490a60e497d810a63dd5608d71bbd7af507c9 \ + --hash=sha256:d069066deead00ac7f090be101be875a06855908f7ec004c27b8fefb4acfb411 \ + --hash=sha256:d5d30989c6917b478b5817902e85fddaea2261efa8648383d965381ccb9e1ac4 \ + --hash=sha256:df637c05205ea7c1d7fbcbe54bbfea648a52951155f997af13d895d0ecc96991 \ + --hash=sha256:e361afba8918070d376df76f408a4f67fec0ee9cff81a99e48fe9a233ef59e17 \ + --hash=sha256:eb86ce1af36fe65041b6db9a8bb064ee621a7e5fded0f80d475ec243477cd242 \ + --hash=sha256:f0d27a5696721ef7a672b8c810f6aded391058e0b9486e63e6d93baf765da691 \ + --hash=sha256:f2ceef93cb096aa3c4cc4b5c94ca6131f9196d28c64d6111533402a9b2054d41 \ + --hash=sha256:f817adc181390bd54f2f700107a7419040fb7c1bdf2fc26f36551a06a68c3345 \ + --hash=sha256:fe0180af5bf9236518a087e35bf2d9a347d5f5f51e63c579d683ddff424e3d46 + # via -r requirements.in dnspython==2.8.0 \ --hash=sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af \ --hash=sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f @@ -196,6 +333,10 @@ protobuf==7.35.0 \ --hash=sha256:f05bcadf9a2a6b8dda047007075135fb7d08c73d9177aabc067e1be46881a201 \ --hash=sha256:fcbe42a4ac09d3ec9c987ddfcd956afd0b15f1ff613bd8371bde9405ffd5c8e5 # via -r requirements.in +pycparser==3.0 \ + --hash=sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29 \ + --hash=sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992 + # via cffi pygments==2.20.0 \ --hash=sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f \ --hash=sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176 diff --git a/regression-tests.auth-py/test_ALIAS.py b/regression-tests.auth-py/test_ALIAS.py index 6c899188d4f4..414c524af4d8 100644 --- a/regression-tests.auth-py/test_ALIAS.py +++ b/regression-tests.auth-py/test_ALIAS.py @@ -6,6 +6,7 @@ import clientsubnetoption import dns +import dns.dnssec from twisted.internet.protocol import DatagramProtocol from twisted.internet import reactor @@ -227,6 +228,65 @@ def testECSNone(self): self.assertAnyRRsetInAnswer(res, expected_aaaa) self.assertEqual(res.options[0], ecso2) + def getDNSKEYs(self): + query = dns.message.make_query("example.org", "DNSKEY", use_edns=True, want_dnssec=True) + res = self.sendUDPQuery(query) + self.assertRcodeEqual(res, dns.rcode.NOERROR) + for rrset in res.answer: + if rrset.rdtype == dns.rdatatype.DNSKEY: + return {dns.name.from_text("example.org."): rrset} + raise AssertionError("No DNSKEY found for example.org") + + def testDNSSEC(self): + keys = self.getDNSKEYs() + expected_a = dns.rrset.from_text("noerror.example.org.", 0, dns.rdataclass.IN, "A", "192.0.2.1") + expected_aaaa = dns.rrset.from_text("noerror.example.org.", 0, dns.rdataclass.IN, "AAAA", "2001:DB8::1") + + query = dns.message.make_query("noerror.example.org", "A", use_edns=True, want_dnssec=True) + res = self.sendUDPQuery(query) + self.assertRcodeEqual(res, dns.rcode.NOERROR) + self.assertMatchingRRSIGInAnswer(res, expected_a, keys) + + query = dns.message.make_query("noerror.example.org", "AAAA", use_edns=True, want_dnssec=True) + res = self.sendUDPQuery(query) + self.assertRcodeEqual(res, dns.rcode.NOERROR) + self.assertMatchingRRSIGInAnswer(res, expected_aaaa, keys) + + query = dns.message.make_query("noerror.example.org", "ANY", use_edns=True, want_dnssec=True) + res = self.sendUDPQuery(query) + self.assertRcodeEqual(res, dns.rcode.NOERROR) + self.assertMatchingRRSIGInAnswer(res, expected_a, keys) + self.assertMatchingRRSIGInAnswer(res, expected_aaaa, keys) + + def testDNSSECTCP(self): + keys = self.getDNSKEYs() + expected_a = dns.rrset.from_text("noerror.example.org.", 0, dns.rdataclass.IN, "A", "192.0.2.1") + expected_aaaa = dns.rrset.from_text("noerror.example.org.", 0, dns.rdataclass.IN, "AAAA", "2001:DB8::1") + + query = dns.message.make_query("noerror.example.org", "A", use_edns=True, want_dnssec=True) + res = self.sendTCPQuery(query) + self.assertRcodeEqual(res, dns.rcode.NOERROR) + self.assertMatchingRRSIGInAnswer(res, expected_a, keys) + + query = dns.message.make_query("noerror.example.org", "AAAA", use_edns=True, want_dnssec=True) + res = self.sendTCPQuery(query) + self.assertRcodeEqual(res, dns.rcode.NOERROR) + self.assertMatchingRRSIGInAnswer(res, expected_aaaa, keys) + + query = dns.message.make_query("noerror.example.org", "ANY", use_edns=True, want_dnssec=True) + res = self.sendTCPQuery(query) + self.assertRcodeEqual(res, dns.rcode.NOERROR) + self.assertMatchingRRSIGInAnswer(res, expected_a, keys) + self.assertMatchingRRSIGInAnswer(res, expected_aaaa, keys) + + def testDNSSECServFail(self): + query = dns.message.make_query("servfail.example.org", "A", use_edns=True, want_dnssec=True) + res = self.sendUDPQuery(query) + self.assertRcodeEqual(res, dns.rcode.SERVFAIL) + + res = self.sendTCPQuery(query) + self.assertRcodeEqual(res, dns.rcode.SERVFAIL) + class AliasUDPResponder(DatagramProtocol): def datagramReceived(self, datagram, address):