AuthPacketCache PC;
AuthQueryCache QC;
AuthZoneCache g_zoneCache;
+uint16_t g_maxNSEC3Iterations{0};
namespace po = boost::program_options;
po::variables_map g_vm;
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;
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);
}
}
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);
AuthPacketCache PC;
AuthQueryCache QC;
AuthZoneCache g_zoneCache;
+uint16_t g_maxNSEC3Iterations{0};
ArgvMap &arg()
{
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<SOARecordContent>(record.d_content);
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: {
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<NSEC3RecordContent>(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: {
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;
}
// 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<shared_ptr<NSEC3PARAMRecordContent>>& getNSEC3Params() const
+ {
+ return d_nsec3params;
+ }
+
private:
typedef std::pair<DNSName, QType> RRSetKey_t;
typedef std::vector<std::shared_ptr<DNSRecordContent>> RRVector_t;
std::shared_ptr<SOARecordContent> d_soaRecordContent;
std::set<shared_ptr<DNSKEYRecordContent>> d_dnskeys;
std::vector<shared_ptr<RRSIGRecordContent>> d_rrsigs;
+ std::vector<shared_ptr<NSEC3PARAMRecordContent>> d_nsec3params;
ContentSigPair d_nsecs;
- ContentSigPair d_nsecs3;
+ map<DNSName, ContentSigPair> d_nsec3s;
DNSName d_nsec3label;
const DNSName d_zone;
+ const ContentSigPair empty;
};
}