From: Otto Moerbeek Date: Mon, 24 Jan 2022 15:27:22 +0000 (+0100) Subject: Improved storage of nsec3 info and a few tweaks X-Git-Tag: auth-4.7.0-alpha1~42^2~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2088c7b8a678ba3e7a94f2120194c387f63ee7d4;p=thirdparty%2Fpdns.git Improved storage of nsec3 info and a few tweaks --- diff --git a/pdns/pdnsutil.cc b/pdns/pdnsutil.cc index 594a854a3e..6b99588d50 100644 --- a/pdns/pdnsutil.cc +++ b/pdns/pdnsutil.cc @@ -44,6 +44,7 @@ StatBag S; AuthPacketCache PC; AuthQueryCache QC; AuthZoneCache g_zoneCache; +uint16_t g_maxNSEC3Iterations{0}; namespace po = boost::program_options; po::variables_map g_vm; diff --git a/pdns/recursordist/rec-zonetocache.cc b/pdns/recursordist/rec-zonetocache.cc index 4ee5c6ec26..7347b61321 100644 --- a/pdns/recursordist/rec-zonetocache.cc +++ b/pdns/recursordist/rec-zonetocache.cc @@ -87,6 +87,9 @@ bool ZoneData::isRRSetAuth(const DNSName& qname, QType qtype) const void ZoneData::parseDRForCache(DNSRecord& dr) { + if (dr.d_class != QClass::IN) { + return; + } const auto key = pair(dr.d_name, dr.d_type); dr.d_ttl += d_now; @@ -283,11 +286,24 @@ vState ZoneData::dnssecValidate(pdns::ZoneMD& zonemd, size_t& zonemdCount) const cspmap_t csp; vState nsecValidationStatus; + if (nsecs.records.size() > 0 && nsecs.signatures.size() > 0) { + // Valdidate the NSEC nsecValidationStatus = validateWithKeySet(d_now, d_zone, nsecs.records, nsecs.signatures, validKeys); csp.emplace(std::make_pair(d_zone, QType::NSEC), nsecs); } - else if (nsec3s.records.size() > 0 && nsec3s.signatures.size() > 0 && !zonemd.getNSEC3Label().empty()) { + else if (nsec3s.records.size() > 0 && nsec3s.signatures.size() > 0) { + // Validate NSEC3PARAMS + records.clear(); + for (const auto& rec : zonemd.getNSEC3Params()) { + records.emplace(rec); + } + nsecValidationStatus = validateWithKeySet(d_now, d_zone, records, zonemd.getRRSIGs(), validKeys); + if (nsecValidationStatus != vState::Secure) { + d_log->info("NSEC3PARAMS records did not validate"); + return nsecValidationStatus; + } + // Valdidate the NSEC3 nsecValidationStatus = validateWithKeySet(d_now, zonemd.getNSEC3Label(), nsec3s.records, nsec3s.signatures, validKeys); csp.emplace(std::make_pair(zonemd.getNSEC3Label(), QType::NSEC3), nsec3s); } @@ -297,7 +313,7 @@ vState ZoneData::dnssecValidate(pdns::ZoneMD& zonemd, size_t& zonemdCount) const } if (nsecValidationStatus != vState::Secure) { - d_log->info("zone NSEC(3) record does no validate"); + d_log->info("zone NSEC(3) record does not validate"); return nsecValidationStatus; } auto denial = getDenial(csp, d_zone, QType::ZONEMD, false, false, true); diff --git a/pdns/testrunner.cc b/pdns/testrunner.cc index 7adf7bb1b8..4f24cb4d65 100644 --- a/pdns/testrunner.cc +++ b/pdns/testrunner.cc @@ -13,6 +13,7 @@ StatBag S; AuthPacketCache PC; AuthQueryCache QC; AuthZoneCache g_zoneCache; +uint16_t g_maxNSEC3Iterations{0}; ArgvMap &arg() { diff --git a/pdns/zonemd.cc b/pdns/zonemd.cc index 843a68cc77..1ee0b58b9c 100644 --- a/pdns/zonemd.cc +++ b/pdns/zonemd.cc @@ -46,11 +46,11 @@ void pdns::ZoneMD::readRecord(const DNSRecord& record) if (!record.d_name.isPartOf(d_zone) && record.d_name != d_zone) { return; } - if (record.d_type == QType::SOA && d_soaRecordContent) { + if (record.d_class == QClass::IN && record.d_type == QType::SOA && d_soaRecordContent) { return; } - if (record.d_name == d_zone) { + if (record.d_class == QClass::IN && record.d_name == d_zone) { switch (record.d_type) { case QType::SOA: { d_soaRecordContent = std::dynamic_pointer_cast(record.d_content); @@ -84,13 +84,11 @@ void pdns::ZoneMD::readRecord(const DNSRecord& record) if (rrsig == nullptr) { throw PDNSException("Invalid RRSIG record"); } + d_rrsigs.emplace_back(rrsig); if (rrsig->d_type == QType::NSEC) { d_nsecs.signatures.emplace_back(rrsig); } - else if (rrsig->d_type == QType::NSEC3) { - d_nsecs3.signatures.emplace_back(rrsig); - } - d_rrsigs.emplace_back(rrsig); + // RRSIG on NEC3 handled below break; } case QType::NSEC: { @@ -112,21 +110,31 @@ void pdns::ZoneMD::readRecord(const DNSRecord& record) if (g_maxNSEC3Iterations && param->d_iterations > g_maxNSEC3Iterations) { return; } + d_nsec3params.emplace_back(param); d_nsec3label = d_zone; d_nsec3label.prependRawLabel(toBase32Hex(hashQNameWithSalt(param->d_salt, param->d_iterations, d_zone))); - // XXX We could filter the collected NSEC3 and their RRSIGs in d_nsecs3 at this point as we now know the right label + // Zap the NSEC3 at labels that we now know are not relevant + for (auto it = d_nsec3s.begin(); it != d_nsec3s.end();) { + if (it->first != d_nsec3label) { + it = d_nsec3s.erase(it); + } + else { + ++it; + } + } break; } } } - if (d_nsec3label.empty() || record.d_name == d_nsec3label) { + // Until we have seen the NSEC3PARAM record, we save all of them, as we do not know the label for the zone yet + if (record.d_class == QClass::IN && (d_nsec3label.empty() || record.d_name == d_nsec3label)) { switch (record.d_type) { case QType::NSEC3: { auto nsec3 = std::dynamic_pointer_cast(record.d_content); if (nsec3 == nullptr) { throw PDNSException("Invalid NSEC3 record"); } - d_nsecs3.records.emplace(nsec3); + d_nsec3s[record.d_name].records.emplace(nsec3); break; } case QType::RRSIG: { @@ -135,7 +143,7 @@ void pdns::ZoneMD::readRecord(const DNSRecord& record) throw PDNSException("Invalid RRSIG record"); } if (rrsig->d_type == QType::NSEC3) { - d_nsecs3.signatures.emplace_back(rrsig); + d_nsec3s[record.d_name].signatures.emplace_back(rrsig); } break; } diff --git a/pdns/zonemd.hh b/pdns/zonemd.hh index df834130c1..63551fec3e 100644 --- a/pdns/zonemd.hh +++ b/pdns/zonemd.hh @@ -89,13 +89,20 @@ public: // Return the zone's apex NSEC3s with signatures const ContentSigPair& getNSEC3s() const { - return d_nsecs3; + const auto it = d_nsec3s.find(d_nsec3label); + return it == d_nsec3s.end() ? empty : d_nsec3s.at(d_nsec3label); } - const DNSName& getNSEC3Label() const { + const DNSName& getNSEC3Label() const + { return d_nsec3label; } + const std::vector>& getNSEC3Params() const + { + return d_nsec3params; + } + private: typedef std::pair RRSetKey_t; typedef std::vector> RRVector_t; @@ -132,10 +139,12 @@ private: std::shared_ptr d_soaRecordContent; std::set> d_dnskeys; std::vector> d_rrsigs; + std::vector> d_nsec3params; ContentSigPair d_nsecs; - ContentSigPair d_nsecs3; + map d_nsec3s; DNSName d_nsec3label; const DNSName d_zone; + const ContentSigPair empty; }; }