#include "logging.hh"
#include "threadname.hh"
#include "rec-lua-conf.hh"
+#include "zonemd.hh"
#ifdef HAVE_LIBCURL
#include "minicurl.hh"
bool isRRSetAuth(const DNSName& qname, QType qtype) const;
void parseDRForCache(DNSRecord& dr);
- void getByAXFR(const RecZoneToCache::Config&);
+ pdns::ZoneMD::Result getByAXFR(const RecZoneToCache::Config&);
void ZoneToCache(const RecZoneToCache::Config& config, uint64_t gen);
};
}
}
-void ZoneData::getByAXFR(const RecZoneToCache::Config& config)
+pdns::ZoneMD::Result ZoneData::getByAXFR(const RecZoneToCache::Config& config)
{
ComboAddress primary = ComboAddress(config.d_sources.at(0), 53);
uint16_t axfrTimeout = config.d_timeout;
time_t axfrStart = time(nullptr);
time_t axfrNow = time(nullptr);
+ vector<DNSRecord> v;
while (axfr.getChunk(nop, &chunk, (axfrStart + axfrTimeout - axfrNow))) {
for (auto& dr : chunk) {
+ if (config.d_zonemd != pdns::ZoneMD::Config::Ignore) {
+ v.push_back(dr);
+ }
parseDRForCache(dr);
}
axfrNow = time(nullptr);
throw std::runtime_error("Total AXFR time for zoneToCache exceeded!");
}
}
+ if (config.d_zonemd != pdns::ZoneMD::Config::Ignore) {
+ auto zonemd = pdns::ZoneMD(d_zone);
+ zonemd.readRecords(v);
+ bool validationDone, validationSuccess;
+ zonemd.verify(validationDone, validationSuccess);
+ if (!validationDone) {
+ return pdns::ZoneMD::Result::NoValidationDone;
+ }
+ if (!validationSuccess) {
+ return pdns::ZoneMD::Result::ValidationFailure;
+ }
+ }
+ return pdns::ZoneMD::Result::OK;
}
static std::vector<std::string> getLinesFromFile(const std::string& file)
// A this moment, we ignore NSEC and NSEC3 records. It is not clear to me yet under which conditions
// they could be entered in into the (neg)cache.
+ pdns::ZoneMD::Result result = pdns::ZoneMD::Result::OK;
if (config.d_method == "axfr") {
d_log->info("Getting zone by AXFR");
- getByAXFR(config);
+ result = getByAXFR(config);
}
else {
vector<string> lines;
DNSRecord dr(drr);
parseDRForCache(dr);
}
+ // XXX ZONEMD processing
+ }
+
+ if (config.d_zonemd == pdns::ZoneMD::Config::Required && result != pdns::ZoneMD::Result::OK) {
+ // We do not accept NoValidationDone in this case
+ throw PDNSException("ZoneMD validation failure");
+ return;
+ }
+ if (config.d_zonemd == pdns::ZoneMD::Config::Process && result == pdns::ZoneMD::Result::ValidationFailure) {
+ throw PDNSException("ZoneMD validation failure");
+ return;
+ }
+ if (config.d_zonemd == pdns::ZoneMD::Config::LogOnly) {
+ switch (result) {
+ case pdns::ZoneMD::Result::ValidationFailure:
+ d_log->info("ZoneMD failure (ignored)");
+ break;
+ case pdns::ZoneMD::Result::NoValidationDone:
+ d_log->info("No ZoneMD validation done");
+ break;
+ case pdns::ZoneMD::Result::OK:
+ d_log->info("ZoneMD validation succeeded");
+ break;
+ }
}
// Extra check before we are touching the cache
}
}
+void pdns::ZoneMD::readRecords(const vector<DNSRecord>& records)
+{
+ for (auto& record : records) {
+ if (!record.d_name.isPartOf(d_zone) && record.d_name != d_zone) {
+ continue;
+ }
+ if (record.d_type == QType::SOA && d_soaRecordContent) {
+ continue;
+ }
+
+ if (record.d_type == QType::SOA && record.d_name == d_zone) {
+ d_soaRecordContent = std::dynamic_pointer_cast<SOARecordContent>(record.d_content);
+ }
+ if (record.d_type == QType::ZONEMD && record.d_name == d_zone) {
+ auto zonemd = std::dynamic_pointer_cast<ZONEMDRecordContent>(record.d_content);
+ auto inserted = d_zonemdRecords.insert({pair(zonemd->d_scheme, zonemd->d_hashalgo), {zonemd, false}});
+ if (!inserted.second) {
+ // Mark as duplicate
+ inserted.first->second.duplicate = true;
+ }
+ }
+ RRSetKey_t key = std::pair(record.d_name, record.d_type);
+ d_resourceRecordSets[key].push_back(record.d_content);
+ d_resourceRecordSetTTLs[key] = record.d_ttl;
+ }
+}
+
void pdns::ZoneMD::verify(bool& validationDone, bool& validationOK)
{
validationDone = false;
class ZoneMD
{
public:
+ enum class Config: uint8_t { Ignore, Process, LogOnly, Required };
+ enum class Result: uint8_t { OK, NoValidationDone, ValidationFailure };
+
ZoneMD(const DNSName& zone) :
d_zone(zone)
{}
void readRecords(ZoneParserTNG& zpt);
+ void readRecords(const std::vector<DNSRecord>& records);
void verify(bool& validationDone, bool& validationOK);
private: