From: Remi Gacogne Date: Wed, 13 Sep 2017 09:10:52 +0000 (+0200) Subject: rec: Detect zone cuts by asking for DS instead of NS X-Git-Tag: rec-4.1.0-rc1~18^2~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5374b03b252b953075e37863e1567b63aa8c6829;p=thirdparty%2Fpdns.git rec: Detect zone cuts by asking for DS instead of NS --- diff --git a/pdns/recursordist/test-syncres_cc.cc b/pdns/recursordist/test-syncres_cc.cc index 36f5d34c40..554986240a 100644 --- a/pdns/recursordist/test-syncres_cc.cc +++ b/pdns/recursordist/test-syncres_cc.cc @@ -248,10 +248,10 @@ static void computeRRSIG(const DNSSECPrivateKey& dpk, const DNSName& signer, con typedef std::unordered_map > testkeysset_t; -static void addRRSIG(const testkeysset_t& keys, std::vector& records, const DNSName& signer, uint32_t sigValidity, bool broken=false, boost::optional algo=boost::none, boost::optional wildcard=boost::none) +static bool addRRSIG(const testkeysset_t& keys, std::vector& records, const DNSName& signer, uint32_t sigValidity, bool broken=false, boost::optional algo=boost::none, boost::optional wildcard=boost::none) { if (records.empty()) { - return; + return false; } const auto it = keys.find(signer); @@ -284,6 +284,8 @@ static void addRRSIG(const testkeysset_t& keys, std::vector& records, rec.d_content = std::make_shared(rrc); records.push_back(rec); + + return true; } static void addDNSKEY(const testkeysset_t& keys, const DNSName& signer, uint32_t ttl, std::vector& records) @@ -303,11 +305,11 @@ static void addDNSKEY(const testkeysset_t& keys, const DNSName& signer, uint32_t records.push_back(rec); } -static void addDS(const DNSName& domain, uint32_t ttl, std::vector& records, const testkeysset_t& keys, DNSResourceRecord::Place place=DNSResourceRecord::AUTHORITY) +static bool addDS(const DNSName& domain, uint32_t ttl, std::vector& records, const testkeysset_t& keys, DNSResourceRecord::Place place=DNSResourceRecord::AUTHORITY) { const auto it = keys.find(domain); if (it == keys.cend()) { - return; + return false; } DNSRecord rec; @@ -318,6 +320,7 @@ static void addDS(const DNSName& domain, uint32_t ttl, std::vector& r rec.d_content = std::make_shared(it->second.second); records.push_back(rec); + return true; } static void addNSECRecordToLW(const DNSName& domain, const DNSName& next, const std::set& types, uint32_t ttl, std::vector& records) @@ -353,6 +356,43 @@ static void generateKeyMaterial(const DNSName& name, unsigned int algo, uint8_t dsAnchors[name].insert(keys[name].second); } +static int genericDSAndDNSKEYHandler(LWResult* res, const DNSName& domain, DNSName auth, int type, const testkeysset_t& keys) +{ + if (type == QType::DS) { + auth.chopOff(); + + setLWResult(res, 0, true, false, true); + + if (addDS(domain, 300, res->d_records, keys, DNSResourceRecord::ANSWER)) { + addRRSIG(keys, res->d_records, auth, 300); + } + else { + addRecordToLW(res, auth, QType::SOA, "foo. bar. 2017032800 1800 900 604800 86400", DNSResourceRecord::AUTHORITY, 86400); + + /* if the auth zone is signed, we need to provide a secure denial */ + const auto it = keys.find(auth); + if (it != keys.cend()) { + /* sign the SOA */ + addRRSIG(keys, res->d_records, auth, 300); + /* add a NSEC denying the DS */ + addNSECRecordToLW(domain, DNSName("z") + domain, { QType::NS, QType::NSEC }, 600, res->d_records); + addRRSIG(keys, res->d_records, auth, 300); + } + } + + return 1; + } + + if (type == QType::DNSKEY) { + setLWResult(res, 0, true, false, true); + addDNSKEY(keys, auth, 300, res->d_records); + addRRSIG(keys, res->d_records, auth, 300); + return 1; + } + + return 0; +} + /* Real tests */ BOOST_AUTO_TEST_SUITE(syncres_cc) @@ -3975,56 +4015,52 @@ BOOST_AUTO_TEST_CASE(test_dnssec_secure_various_algos) { if (domain == target) { auth = DNSName("powerdns.com."); } - if (type == QType::DS) { - return 0; + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); } - else if (type == QType::DNSKEY) { - setLWResult(res, 0, true, false, true); - addDNSKEY(keys, auth, 300, res->d_records); - addRRSIG(keys, res->d_records, auth, 300); + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); return 1; } - else { - if (isRootServer(ip)) { - setLWResult(res, 0, false, false, true); - addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); - addDS(DNSName("com."), 300, res->d_records, keys); - addRRSIG(keys, res->d_records, DNSName("."), 300); + + if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, domain, 300); addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); - return 1; + addRRSIG(keys, res->d_records, domain, 300); } - else if (ip == ComboAddress("192.0.2.1:53")) { - if (domain == DNSName("com.")) { - setLWResult(res, 0, true, false, true); - addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); - addRRSIG(keys, res->d_records, domain, 300); - addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); - addRRSIG(keys, res->d_records, domain, 300); - } - else { - setLWResult(res, 0, false, false, true); - addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); - addDS(auth, 300, res->d_records, keys); - addRRSIG(keys, res->d_records, DNSName("com."), 300); - addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); - } - return 1; + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(auth, 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); } - else if (ip == ComboAddress("192.0.2.2:53")) { - if (type == QType::NS) { - setLWResult(res, 0, true, false, true); - addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); - addRRSIG(keys, res->d_records, auth, 300); - addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); - addRRSIG(keys, res->d_records, auth, 300); - } - else { - setLWResult(res, RCode::NoError, true, false, true); - addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); - addRRSIG(keys, res->d_records, auth, 300); - } - return 1; + return 1; + } + + if (ip == ComboAddress("192.0.2.2:53")) { + if (type == QType::NS) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, auth, 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, auth, 300); } + else { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); + addRRSIG(keys, res->d_records, auth, 300); + } + return 1; } return 0; @@ -4073,56 +4109,52 @@ BOOST_AUTO_TEST_CASE(test_dnssec_secure_a_then_ns) { if (domain == target) { auth = DNSName("powerdns.com."); } - if (type == QType::DS) { - return 0; + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); } - else if (type == QType::DNSKEY) { - setLWResult(res, 0, true, false, true); - addDNSKEY(keys, auth, 300, res->d_records); - addRRSIG(keys, res->d_records, auth, 300); + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); return 1; } - else { - if (isRootServer(ip)) { - setLWResult(res, 0, false, false, true); - addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); - addDS(DNSName("com."), 300, res->d_records, keys); - addRRSIG(keys, res->d_records, DNSName("."), 300); + + if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, domain, 300); addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); - return 1; + addRRSIG(keys, res->d_records, domain, 300); } - else if (ip == ComboAddress("192.0.2.1:53")) { - if (domain == DNSName("com.")) { - setLWResult(res, 0, true, false, true); - addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); - addRRSIG(keys, res->d_records, domain, 300); - addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); - addRRSIG(keys, res->d_records, domain, 300); - } - else { - setLWResult(res, 0, false, false, true); - addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); - addDS(auth, 300, res->d_records, keys); - addRRSIG(keys, res->d_records, DNSName("com."), 300); - addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); - } - return 1; + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(auth, 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); } - else if (ip == ComboAddress("192.0.2.2:53")) { - if (type == QType::NS) { - setLWResult(res, 0, true, false, true); - addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); - addRRSIG(keys, res->d_records, auth, 300); - addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); - addRRSIG(keys, res->d_records, auth, 300); - } - else { - setLWResult(res, RCode::NoError, true, false, true); - addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); - addRRSIG(keys, res->d_records, auth, 300); - } - return 1; + return 1; + } + + if (ip == ComboAddress("192.0.2.2:53")) { + if (type == QType::NS) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, auth, 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, auth, 300); + } + else { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); + addRRSIG(keys, res->d_records, auth, 300); } + return 1; } return 0; @@ -4150,7 +4182,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_secure_a_then_ns) { BOOST_CHECK_EQUAL(res, RCode::NoError); BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); BOOST_REQUIRE_EQUAL(ret.size(), 2); - BOOST_CHECK_EQUAL(queriesCount, 8); + BOOST_CHECK_EQUAL(queriesCount, 9); } @@ -4180,54 +4212,50 @@ BOOST_AUTO_TEST_CASE(test_dnssec_insecure_a_then_ns) { if (domain == target) { auth = DNSName("powerdns.com."); } - if (type == QType::DS) { - return 0; + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); } - else if (type == QType::DNSKEY) { - setLWResult(res, 0, true, false, true); - addDNSKEY(keys, auth, 300, res->d_records); - addRRSIG(keys, res->d_records, auth, 300); + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); return 1; } - else { - if (isRootServer(ip)) { - setLWResult(res, 0, false, false, true); - addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); - addDS(DNSName("com."), 300, res->d_records, keys); - addRRSIG(keys, res->d_records, DNSName("."), 300); + + if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, domain, 300); addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); - return 1; + addRRSIG(keys, res->d_records, domain, 300); } - else if (ip == ComboAddress("192.0.2.1:53")) { - if (domain == DNSName("com.")) { - setLWResult(res, 0, true, false, true); - addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); - addRRSIG(keys, res->d_records, domain, 300); - addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); - addRRSIG(keys, res->d_records, domain, 300); - } - else { - setLWResult(res, 0, false, false, true); - addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); - /* no DS */ - addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records); - addRRSIG(keys, res->d_records, DNSName("com."), 300); - addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); - } - return 1; + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + /* no DS */ + addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); } - else if (ip == ComboAddress("192.0.2.2:53")) { - if (type == QType::NS) { - setLWResult(res, 0, true, false, true); - addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); - addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); - } - else { - setLWResult(res, RCode::NoError, true, false, true); - addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); - } - return 1; + return 1; + } + + if (ip == ComboAddress("192.0.2.2:53")) { + if (type == QType::NS) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); } + else { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); + } + return 1; } return 0; @@ -4255,7 +4283,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_insecure_a_then_ns) { BOOST_CHECK_EQUAL(res, RCode::NoError); BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); BOOST_REQUIRE_EQUAL(ret.size(), 1); - BOOST_CHECK_EQUAL(queriesCount, 7); + BOOST_CHECK_EQUAL(queriesCount, 8); } BOOST_AUTO_TEST_CASE(test_dnssec_secure_with_nta) { @@ -4289,56 +4317,52 @@ BOOST_AUTO_TEST_CASE(test_dnssec_secure_with_nta) { if (domain == target) { auth = DNSName("powerdns.com."); } - if (type == QType::DS) { - return 0; + + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); } - else if (type == QType::DNSKEY) { - setLWResult(res, 0, true, false, true); - addDNSKEY(keys, auth, 300, res->d_records); - addRRSIG(keys, res->d_records, auth, 300); + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); return 1; } - else { - if (isRootServer(ip)) { - setLWResult(res, 0, false, false, true); - addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); - addDS(DNSName("com."), 300, res->d_records, keys); - addRRSIG(keys, res->d_records, DNSName("."), 300); + + if (ip == ComboAddress("192.0.2.1:53")) { + if (domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, domain, 300); addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); - return 1; + addRRSIG(keys, res->d_records, domain, 300); } - else if (ip == ComboAddress("192.0.2.1:53")) { - if (domain == DNSName("com.")) { - setLWResult(res, 0, true, false, true); - addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); - addRRSIG(keys, res->d_records, domain, 300); - addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); - addRRSIG(keys, res->d_records, domain, 300); - } - else { - setLWResult(res, 0, false, false, true); - addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); - addDS(auth, 300, res->d_records, keys); - addRRSIG(keys, res->d_records, DNSName("com."), 300); - addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); - } - return 1; + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, auth, QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(auth, 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); } - else if (ip == ComboAddress("192.0.2.2:53")) { - if (type == QType::NS) { - setLWResult(res, 0, true, false, true); - addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); - addRRSIG(keys, res->d_records, auth, 300); - addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); - addRRSIG(keys, res->d_records, auth, 300); - } - else { - setLWResult(res, RCode::NoError, true, false, true); - addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); - addRRSIG(keys, res->d_records, auth, 300); - } - return 1; + return 1; + } + + if (ip == ComboAddress("192.0.2.2:53")) { + if (type == QType::NS) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::NS, "ns1.powerdns.com."); + addRRSIG(keys, res->d_records, auth, 300); + addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, auth, 300); + } + else { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, domain, QType::A, targetAddr.toString(), DNSResourceRecord::ANSWER, 3600); + addRRSIG(keys, res->d_records, auth, 300); } + return 1; } return 0; @@ -4350,7 +4374,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_secure_with_nta) { /* Should be insecure because of the NTA */ BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); BOOST_REQUIRE_EQUAL(ret.size(), 2); - BOOST_CHECK_EQUAL(queriesCount, 7); + BOOST_CHECK_EQUAL(queriesCount, 5); /* again, to test the cache */ ret.clear(); @@ -4359,7 +4383,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_secure_with_nta) { /* Should be insecure because of the NTA */ BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); BOOST_REQUIRE_EQUAL(ret.size(), 2); - BOOST_CHECK_EQUAL(queriesCount, 7); + BOOST_CHECK_EQUAL(queriesCount, 5); } BOOST_AUTO_TEST_CASE(test_dnssec_bogus_with_nta) { @@ -4438,8 +4462,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_bogus_with_nta) { /* Should be insecure because of the NTA */ BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); BOOST_REQUIRE_EQUAL(ret.size(), 1); - /* and a such, no query for the DNSKEYs */ - BOOST_CHECK_EQUAL(queriesCount, 6); + BOOST_CHECK_EQUAL(queriesCount, 4); /* again, to test the cache */ ret.clear(); @@ -4447,7 +4470,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_bogus_with_nta) { BOOST_CHECK_EQUAL(res, RCode::NoError); BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); BOOST_REQUIRE_EQUAL(ret.size(), 1); - BOOST_CHECK_EQUAL(queriesCount, 6); + BOOST_CHECK_EQUAL(queriesCount, 4); } BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec) { @@ -4473,14 +4496,8 @@ BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec) { sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res) { queriesCount++; - if (type == QType::DS) { - return 0; - } - else if (type == QType::DNSKEY) { - setLWResult(res, 0, true, false, true); - addDNSKEY(keys, domain, 300, res->d_records); - addRRSIG(keys, res->d_records, domain, 300); - return 1; + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); } else { if (isRootServer(ip)) { @@ -4573,14 +4590,18 @@ BOOST_AUTO_TEST_CASE(test_dnssec_validation_nxdomain_nsec) { if (domain == target) { auth = DNSName("powerdns.com."); } - if (type == QType::DS) { - return 0; - } - else if (type == QType::DNSKEY) { - setLWResult(res, 0, true, false, true); - addDNSKEY(keys, auth, 300, res->d_records); - addRRSIG(keys, res->d_records, auth, 300); - return 1; + if (type == QType::DS || type == QType::DNSKEY) { + if (type == QType::DS && domain == target) { + setLWResult(res, RCode::NXDomain, true, false, true); + addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, auth, 300); + addNSECRecordToLW(DNSName("nw.powerdns.com."), DNSName("ny.powerdns.com."), { QType::RRSIG, QType::NSEC }, 600, res->d_records); + addRRSIG(keys, res->d_records, auth, 300); + return 1; + } + else { + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } } else { if (isRootServer(ip)) { @@ -4677,14 +4698,18 @@ BOOST_AUTO_TEST_CASE(test_dnssec_validation_nsec_wildcard) { sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res) { queriesCount++; - if (type == QType::DS) { - return 0; - } - else if (type == QType::DNSKEY) { - setLWResult(res, 0, true, false, true); - addDNSKEY(keys, domain, 300, res->d_records); - addRRSIG(keys, res->d_records, domain, 300); - return 1; + if (type == QType::DS || type == QType::DNSKEY) { + if (type == QType::DS && domain == target) { + setLWResult(res, RCode::NoError, true, false, true); + addRecordToLW(res, DNSName("powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + addRRSIG(keys, res->d_records, DNSName("powerdns.com."), 300); + addNSECRecordToLW(DNSName("www.powerdns.com."), DNSName("wwz.powerdns.com."), { QType::A, QType::NSEC, QType::RRSIG }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("powerdns.com"), 300); + return 1; + } + else { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } } else { if (isRootServer(ip)) { @@ -4854,8 +4879,8 @@ BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_secure) { BOOST_CHECK_EQUAL(res, RCode::NoError); BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); BOOST_REQUIRE_EQUAL(ret.size(), 2); - BOOST_CHECK_EQUAL(queriesCount, 11); - BOOST_CHECK_EQUAL(dsQueriesCount, 2); + BOOST_CHECK_EQUAL(queriesCount, 9); + BOOST_CHECK_EQUAL(dsQueriesCount, 3); /* again, to test the cache */ ret.clear(); @@ -4863,8 +4888,8 @@ BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_secure) { BOOST_CHECK_EQUAL(res, RCode::NoError); BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); BOOST_REQUIRE_EQUAL(ret.size(), 2); - BOOST_CHECK_EQUAL(queriesCount, 11); - BOOST_CHECK_EQUAL(dsQueriesCount, 2); + BOOST_CHECK_EQUAL(queriesCount, 9); + BOOST_CHECK_EQUAL(dsQueriesCount, 3); } BOOST_AUTO_TEST_CASE(test_dnssec_ds_sign_loop) { @@ -5076,7 +5101,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_insecure) { BOOST_CHECK_EQUAL(res, RCode::NoError); BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); BOOST_REQUIRE_EQUAL(ret.size(), 1); - BOOST_CHECK_EQUAL(queriesCount, 10); + BOOST_CHECK_EQUAL(queriesCount, 7); BOOST_CHECK_EQUAL(dsQueriesCount, 2); /* again, to test the cache */ @@ -5085,7 +5110,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_no_ds_on_referral_insecure) { BOOST_CHECK_EQUAL(res, RCode::NoError); BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); BOOST_REQUIRE_EQUAL(ret.size(), 1); - BOOST_CHECK_EQUAL(queriesCount, 10); + BOOST_CHECK_EQUAL(queriesCount, 7); BOOST_CHECK_EQUAL(dsQueriesCount, 2); } @@ -5112,14 +5137,8 @@ BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_unsigned_nsec) { sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res) { queriesCount++; - if (type == QType::DS) { - return 0; - } - else if (type == QType::DNSKEY) { - setLWResult(res, 0, true, false, true); - addDNSKEY(keys, domain, 300, res->d_records); - addRRSIG(keys, res->d_records, domain, 300); - return 1; + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); } else { if (isRootServer(ip)) { @@ -5205,14 +5224,8 @@ BOOST_AUTO_TEST_CASE(test_dnssec_validation_bogus_no_nsec) { sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res) { queriesCount++; - if (type == QType::DS) { - return 0; - } - else if (type == QType::DNSKEY) { - setLWResult(res, 0, true, false, true); - addDNSKEY(keys, domain, 300, res->d_records); - addRRSIG(keys, res->d_records, domain, 300); - return 1; + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); } else { if (isRootServer(ip)) { @@ -5305,6 +5318,8 @@ BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure) { addNSECRecordToLW(domain, DNSName("z.powerdns.com."), { QType::NS }, 600, res->d_records); addRRSIG(keys, res->d_records, DNSName("com."), 300); return 1; + } else { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); } } else if (type == QType::DNSKEY) { @@ -5420,6 +5435,9 @@ BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_skipped_cut) { addRecordToLW(res, DNSName("sub.powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); return 1; } + else { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } } else if (type == QType::DNSKEY) { if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) { @@ -5488,7 +5506,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_skipped_cut) { BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); BOOST_REQUIRE_EQUAL(ret.size(), 1); BOOST_CHECK(ret[0].d_type == QType::A); - BOOST_CHECK_EQUAL(queriesCount, 11); + BOOST_CHECK_EQUAL(queriesCount, 9); /* again, to test the cache */ ret.clear(); @@ -5497,7 +5515,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_skipped_cut) { BOOST_CHECK_EQUAL(sr->getValidationState(), Insecure); BOOST_REQUIRE_EQUAL(ret.size(), 1); BOOST_CHECK(ret[0].d_type == QType::A); - BOOST_CHECK_EQUAL(queriesCount, 11); + BOOST_CHECK_EQUAL(queriesCount, 9); } BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_ta_skipped_cut) { @@ -5535,7 +5553,17 @@ BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_ta_skipped_cut) { } else { setLWResult(res, 0, false, false, true); - addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + + if (domain == DNSName("com.")) { + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + /* no DS */ + addNSECRecordToLW(DNSName("com."), DNSName("dom."), { QType::NS }, 600, res->d_records); + addRRSIG(keys, res->d_records, DNSName("."), 300); + } + else { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + } } return 1; } @@ -5563,7 +5591,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_ta_skipped_cut) { addRecordToLW(res, DNSName("com."), QType::NS, "a.gtld-servers.com."); addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); } - else if (domain == DNSName("powerdns.com.")) { + else if (domain.isPartOf(DNSName("powerdns.com."))) { setLWResult(res, 0, false, false, true); addRecordToLW(res, DNSName("powerdns.com."), QType::NS, "ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 3600); addRecordToLW(res, "ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 3600); @@ -5604,7 +5632,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_ta_skipped_cut) { BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); BOOST_REQUIRE_EQUAL(ret.size(), 2); BOOST_CHECK(ret[0].d_type == QType::A); - BOOST_CHECK_EQUAL(queriesCount, 9); + BOOST_CHECK_EQUAL(queriesCount, 7); /* again, to test the cache */ ret.clear(); @@ -5613,7 +5641,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_ta_skipped_cut) { BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); BOOST_REQUIRE_EQUAL(ret.size(), 2); BOOST_CHECK(ret[0].d_type == QType::A); - BOOST_CHECK_EQUAL(queriesCount, 9); + BOOST_CHECK_EQUAL(queriesCount, 7); } BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_nodata) { @@ -5646,6 +5674,9 @@ BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_nodata) { addRRSIG(keys, res->d_records, DNSName("com."), 300); return 1; } + else { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } } else if (type == QType::DNSKEY) { if (domain == g_rootdnsname || domain == DNSName("com.")) { @@ -5749,13 +5780,16 @@ BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cname) { queriesCount++; if (type == QType::DS) { - if (domain == target) { + if (domain == targetCName) { setLWResult(res, 0, false, false, true); addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); addNSECRecordToLW(domain, DNSName("z.power-dns.com."), { QType::NS }, 600, res->d_records); addRRSIG(keys, res->d_records, DNSName("com."), 300); return 1; } + else { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } } else if (type == QType::DNSKEY) { if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) { @@ -5880,6 +5914,9 @@ BOOST_AUTO_TEST_CASE(test_dnssec_insecure_to_secure_cname) { addRRSIG(keys, res->d_records, DNSName("com."), 300); return 1; } + else { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } } else if (type == QType::DNSKEY) { if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) { @@ -5994,14 +6031,8 @@ BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_secure_cname) { sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res) { queriesCount++; - if (type == QType::DS) { - return 0; - } - else if (type == QType::DNSKEY) { - setLWResult(res, 0, true, false, true); - addDNSKEY(keys, domain, 300, res->d_records); - addRRSIG(keys, res->d_records, domain, 300); - return 1; + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); } else { if (isRootServer(ip)) { @@ -6095,14 +6126,8 @@ BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_bogus_cname) { sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res) { queriesCount++; - if (type == QType::DS) { - return 0; - } - else if (type == QType::DNSKEY) { - setLWResult(res, 0, true, false, true); - addDNSKEY(keys, domain, 300, res->d_records); - addRRSIG(keys, res->d_records, domain, 300); - return 1; + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); } else { if (isRootServer(ip)) { @@ -6196,14 +6221,8 @@ BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_secure_cname) { sr->setAsyncCallback([target,targetCName,targetCNameAddr,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res) { queriesCount++; - if (type == QType::DS) { - return 0; - } - else if (type == QType::DNSKEY) { - setLWResult(res, 0, true, false, true); - addDNSKEY(keys, domain, 300, res->d_records); - addRRSIG(keys, res->d_records, domain, 300); - return 1; + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); } else { if (isRootServer(ip)) { @@ -6305,6 +6324,9 @@ BOOST_AUTO_TEST_CASE(test_dnssec_bogus_to_insecure_cname) { addRRSIG(keys, res->d_records, DNSName("com."), 300); return 1; } + else { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } } else if (type == QType::DNSKEY) { if (domain == g_rootdnsname || domain == DNSName("com.") || domain == DNSName("powerdns.com.")) { @@ -6472,12 +6494,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta) { /* We got a RRSIG */ BOOST_REQUIRE_EQUAL(ret.size(), 2); BOOST_CHECK(ret[0].d_type == QType::A); - /* - NS com. (at . and com.) - - NS powerdns.com (com. and powerdns.com.) - - DNSKEY (. and powerdns.com.) - - A powerdns.com - */ - BOOST_CHECK_EQUAL(queriesCount, 7); + BOOST_CHECK_EQUAL(queriesCount, 5); /* again, to test the cache */ ret.clear(); @@ -6486,7 +6503,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta) { BOOST_CHECK_EQUAL(sr->getValidationState(), Secure); BOOST_REQUIRE_EQUAL(ret.size(), 2); BOOST_CHECK(ret[0].d_type == QType::A); - BOOST_CHECK_EQUAL(queriesCount, 7); + BOOST_CHECK_EQUAL(queriesCount, 5); } BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta_norrsig) { @@ -6572,12 +6589,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta_norrsig) { /* No RRSIG */ BOOST_REQUIRE_EQUAL(ret.size(), 1); BOOST_CHECK(ret[0].d_type == QType::A); - /* - NS com. (at . and com.) - - NS powerdns.com (com. and powerdns.com.) - - DNSKEY (.) - - A powerdns.com (no DNSKEY because no RRSIG) - */ - BOOST_CHECK_EQUAL(queriesCount, 6); + BOOST_CHECK_EQUAL(queriesCount, 4); /* again, to test the cache */ ret.clear(); @@ -6586,7 +6598,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_insecure_ta_norrsig) { BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); BOOST_REQUIRE_EQUAL(ret.size(), 1); BOOST_CHECK(ret[0].d_type == QType::A); - BOOST_CHECK_EQUAL(queriesCount, 6); + BOOST_CHECK_EQUAL(queriesCount, 4); } BOOST_AUTO_TEST_CASE(test_dnssec_nta) { @@ -6723,6 +6735,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_bogus_nodata) { auto luaconfsCopy = g_luaconfs.getCopy(); luaconfsCopy.dsAnchors.clear(); generateKeyMaterial(DNSName("."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); g_luaconfs.setState(luaconfsCopy); @@ -6731,14 +6744,8 @@ BOOST_AUTO_TEST_CASE(test_dnssec_bogus_nodata) { sr->setAsyncCallback([target,&queriesCount,keys](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res) { queriesCount++; - if (type == QType::DS) { - return 0; - } - else if (type == QType::DNSKEY) { - setLWResult(res, 0, true, false, true); - addDNSKEY(keys, domain, 300, res->d_records); - addRRSIG(keys, res->d_records, domain, 300); - return 1; + if (type == QType::DS || type == QType::DNSKEY) { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); } else { @@ -6764,7 +6771,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_bogus_nodata) { BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus); BOOST_REQUIRE_EQUAL(ret.size(), 0); /* we don't store empty results */ - BOOST_CHECK_EQUAL(queriesCount, 6); + BOOST_CHECK_EQUAL(queriesCount, 4); } BOOST_AUTO_TEST_CASE(test_nsec_denial_nowrap) { diff --git a/pdns/syncres.cc b/pdns/syncres.cc index 05ecb7dc3f..455e329b09 100644 --- a/pdns/syncres.cc +++ b/pdns/syncres.cc @@ -577,9 +577,9 @@ int SyncRes::doResolve(const DNSName &qname, const QType &qtype, vectorsecond]<<" for name "<second; + if (allowIndeterminate || it->second != Indeterminate) { + LOG(d_prefix<<": got status "<second]<<" for name "<second; + } } } while (name.chopOff()); @@ -1434,31 +1454,19 @@ vState SyncRes::getValidationStatus(const DNSName& subdomain) bool SyncRes::lookForCut(const DNSName& qname, unsigned int depth, const vState existingState, vState& newState) { bool foundCut = false; - std::set beenthere; - std::vector nsrecords; + dsmap_t ds; + vState dsState = getDSRecords(qname, ds, newState == Bogus || existingState == Insecure || existingState == Bogus, depth, false, &foundCut); - int rcode = doResolve(qname, QType(QType::NS), nsrecords, depth, beenthere, newState); + if (dsState != Indeterminate) { + newState = dsState; + } - if (rcode == RCode::NoError && !nsrecords.empty()) { - for (const auto& record : nsrecords) { - if(record.d_type != QType::NS || record.d_name != qname) - continue; - foundCut = true; - break; + if (foundCut) { + if (newState == TA) { + newState = Secure; } - - if (foundCut) { - dsmap_t ds; - vState dsState = getDSRecords(qname, ds, newState == Bogus || existingState == Insecure || existingState == Bogus, depth); - if (dsState != Indeterminate) { - newState = dsState; - } - if (newState == TA) { - newState = Secure; - } - else if (newState == NTA) { - newState = Insecure; - } + else if (newState == NTA) { + newState = Insecure; } } @@ -1822,10 +1830,12 @@ RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, LWResult& lwr isAA = false; } - vState recordState = getValidationStatus(auth); + vState recordState = getValidationStatus(i->first.name, false); LOG(d_prefix<<": got initial zone status "<first.name<first.place != DNSResourceRecord::ADDITIONAL) { /* the additional entries can be insecure, @@ -1854,7 +1864,9 @@ RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, LWResult& lwr } } - updateValidationState(state, recordState); + if (initialState == Secure && state != recordState) { + updateValidationState(state, recordState); + } } else { if (d_DNSSECValidationRequested) { @@ -1880,9 +1892,8 @@ void SyncRes::getDenialValidationState(NegCache::NegCacheEntry& ne, vState& stat dState res = getDenial(csp, ne.d_name, ne.d_qtype.getCode()); if (res != expectedState) { if (res == OPTOUT && allowOptOut) { - LOG(d_prefix<<"OPT-out denial found for "<second == Indeterminate) { - cut->second = state; + cut->second = Insecure; } } else { - LOG(prefix< beenthere2; - vState cnameState = Indeterminate; - *rcode = doResolve(newtarget, qtype, ret, depth + 1, beenthere2, cnameState); - LOG(prefix< beenthere2; + vState cnameState = Indeterminate; + *rcode = doResolve(newtarget, qtype, ret, depth + 1, beenthere2, cnameState); + LOG(prefix<& records, const std::vector >& signatures); vState validateDNSKeys(const DNSName& zone, const std::vector& dnskeys, const std::vector >& signatures, unsigned int depth); - vState getDSRecords(const DNSName& zone, dsmap_t& ds, bool onlyTA, unsigned int depth, bool bogusOnNXD=true); + vState getDSRecords(const DNSName& zone, dsmap_t& ds, bool onlyTA, unsigned int depth, bool bogusOnNXD=true, bool* foundCut=nullptr); vState getDNSKeys(const DNSName& signer, skeyset_t& keys, unsigned int depth); void getDenialValidationState(NegCache::NegCacheEntry& ne, vState& state, const dState expectedState, bool allowOptOut); vState getTA(const DNSName& zone, dsmap_t& ds); bool haveExactValidationStatus(const DNSName& domain); - vState getValidationStatus(const DNSName& subdomain); + vState getValidationStatus(const DNSName& subdomain, bool allowIndeterminate=true); bool lookForCut(const DNSName& qname, unsigned int depth, const vState existingState, vState& newState); void computeZoneCuts(const DNSName& begin, const DNSName& end, unsigned int depth); diff --git a/pdns/validate.cc b/pdns/validate.cc index 176af6d44a..148a320eda 100644 --- a/pdns/validate.cc +++ b/pdns/validate.cc @@ -42,6 +42,59 @@ static bool isCoveredByNSEC(const DNSName& name, const DNSName& begin, const DNS (begin == next && name != begin)); // "we have only 1 NSEC record, LOL!" } +static std::string getHashFromNSEC3(const DNSName& qname, const std::shared_ptr nsec3) +{ + std::string result; + + if (g_maxNSEC3Iterations && nsec3->d_iterations > g_maxNSEC3Iterations) { + return result; + } + + return hashQNameWithSalt(nsec3->d_salt, nsec3->d_iterations, qname); +} + +bool denialProvesNoDelegation(const DNSName& zone, const std::vector& dsrecords) +{ + for (const auto& record : dsrecords) { + if (record.d_type == QType::NSEC) { + const auto nsec = getRR(record); + if (!nsec) { + continue; + } + + if (record.d_name == zone) { + return !nsec->d_set.count(QType::NS); + } + + if (isCoveredByNSEC(zone, record.d_name, nsec->d_next)) { + return true; + } + } + else if (record.d_type == QType::NSEC3) { + const auto nsec3 = getRR(record); + if (!nsec3) { + continue; + } + + const string h = getHashFromNSEC3(zone, nsec3); + if (h.empty()) { + return false; + } + + const string beginHash = fromBase32Hex(record.d_name.getRawLabels()[0]); + if (beginHash == h) { + return !nsec3->d_set.count(QType::NS); + } + + if (isCoveredByNSEC3Hash(h, beginHash, nsec3->d_nexthash)) { + return !(nsec3->d_flags & 1); + } + } + } + + return false; +} + // FIXME: needs a zone argument, to avoid things like 6840 4.1 // FIXME: Add ENT support // FIXME: Make usable for non-DS records and hook up to validateRecords (or another place) @@ -99,11 +152,11 @@ dState getDenial(const cspmap_t &validrrsets, const DNSName& qname, const uint16 if(!nsec3) continue; - if (g_maxNSEC3Iterations && nsec3->d_iterations > g_maxNSEC3Iterations) { + string h = getHashFromNSEC3(qname, nsec3); + if (h.empty()) { return INSECURE; } - string h = hashQNameWithSalt(nsec3->d_salt, nsec3->d_iterations, qname); // cerr<<"Salt length: "<d_salt.length()<<", iterations: "<d_iterations<<", hashed: "< >& signatures); +bool denialProvesNoDelegation(const DNSName& zone, const std::vector& dsrecords);