static void houseKeeping(void *)
{
- static thread_local time_t last_rootupdate, last_prune, last_secpoll;
+ static thread_local time_t last_rootupdate, last_prune, last_secpoll, last_trustAnchorUpdate{0};
static thread_local int cleanCounter=0;
static thread_local bool s_running; // houseKeeping can get suspended in secpoll, and be restarted, which makes us do duplicate work
+ auto luaconfsLocal = g_luaconfs.getLocal();
+
+ if (last_trustAnchorUpdate == 0 && !luaconfsLocal->trustAnchorFileInfo.fname.empty() && luaconfsLocal->trustAnchorFileInfo.interval != 0) {
+ // Loading the Lua config file already "refreshed" the TAs
+ last_trustAnchorUpdate = g_now.tv_sec + luaconfsLocal->trustAnchorFileInfo.interval * 3600;
+ }
+
try {
if(s_running)
return;
g_log<<Logger::Error<<"Exception while performing security poll"<<endl;
}
}
+
+ if (!luaconfsLocal->trustAnchorFileInfo.fname.empty() && luaconfsLocal->trustAnchorFileInfo.interval != 0 &&
+ g_now.tv_sec - last_trustAnchorUpdate >= (luaconfsLocal->trustAnchorFileInfo.interval * 3600)) {
+ g_log<<Logger::Debug<<"Refreshing Trust Anchors from file"<<endl;
+ try {
+ map<DNSName, dsmap_t> dsAnchors;
+ if (updateTrustAnchorsFromFile(luaconfsLocal->trustAnchorFileInfo.fname, dsAnchors)) {
+ g_luaconfs.modify([&dsAnchors](LuaConfigItems& lci) {
+ lci.dsAnchors = dsAnchors;
+ });
+ }
+ last_trustAnchorUpdate = now.tv_sec;
+ } catch (const PDNSException &pe) {
+ g_log<<Logger::Error<<"Unable to update Trust Anchors: "<<pe.reason<<endl;
+ }
+ }
+ s_running=false;
}
- s_running=false;
}
catch(PDNSException& ae)
{
#include "validate.hh"
#include "validate-recursor.hh"
#include "root-dnssec.hh"
-#include "dnssecinfra.hh"
-#include "dnsseckeeper.hh"
-#include "zoneparser-tng.hh"
GlobalStateHolder<LuaConfigItems> g_luaconfs;
lci.negAnchors.clear();
});
- Lua.writeFunction("readTrustAnchorsFromFile", [&lci](const std::string& fname) {
- warnIfDNSSECDisabled("Warning: reading Trust Anchors from file (readTrustAnchorsFromFile), but dnssec is set to 'off'!");
- auto zp = ZoneParserTNG(fname);
- DNSResourceRecord rr;
- DNSRecord dr;
- try {
- while(zp.get(rr)) {
- dr = DNSRecord(rr);
- if (rr.qtype == QType::DS) {
- auto dsr = getRR<DSRecordContent>(dr);
- if (dsr == nullptr) {
- throw PDNSException("Unable to parse DS record '" + rr.qname.toString() + " " + rr.getZoneRepresentation() + "'");
- }
- lci.dsAnchors[rr.qname].insert(*dsr);
- }
- if (rr.qtype == QType::DNSKEY) {
- auto dnskeyr = getRR<DNSKEYRecordContent>(dr);
- if (dnskeyr == nullptr) {
- throw PDNSException("Unable to parse DNSKEY record '" + rr.qname.toString() + " " + rr.getZoneRepresentation() +"'");
- }
- auto dsr = makeDSFromDNSKey(rr.qname, *dnskeyr, DNSSECKeeper::SHA256);
- lci.dsAnchors[rr.qname].insert(dsr);
- }
- }
- }
- catch (const std::exception &e) {
- throw PDNSException("Error while reading Trust Anchors from file (readTrustAnchorsFromFile) '" + fname + "': " + e.what());
- }
- catch (...) {
- throw PDNSException("Error while reading Trust Anchors from file (readTrustAnchorsFromFile) '" + fname + "'");
+ Lua.writeFunction("readTrustAnchorsFromFile", [&lci](const std::string& fname, const boost::optional<uint32_t> interval) {
+ uint32_t realInterval = 24;
+ if (interval) {
+ realInterval = static_cast<uint32_t>(*interval);
}
+ warnIfDNSSECDisabled("Warning: reading Trust Anchors from file (readTrustAnchorsFromFile), but dnssec is set to 'off'!");
+ lci.trustAnchorFileInfo.fname = fname;
+ lci.trustAnchorFileInfo.interval = realInterval;
+ updateTrustAnchorsFromFile(fname, lci.dsAnchors);
});
#if HAVE_PROTOBUF
bool taggedOnly{false};
};
+struct TrustAnchorFileInfo {
+ uint32_t interval{24};
+ std::string fname;
+};
+
class LuaConfigItems
{
public:
LuaConfigItems();
SortList sortlist;
DNSFilterEngine dfe;
+ TrustAnchorFileInfo trustAnchorFileInfo; // Used to update the Trust Anchors from file periodically
map<DNSName,dsmap_t> dsAnchors;
map<DNSName,std::string> negAnchors;
ProtobufExportConfig protobufExportConfig;
Since version 4.2.0 of the PowerDNS Recursor, it is also possible to read the Trust Anchors from a BIND-style zonefile.
Only the DS and DNSKEY records from this file are read.
+This file is (by default) re-read every 24 hours for updates.
Debian and its derivatives ship the ``dns-root-data`` package that contains the DNSSEC root trust anchors in ``/usr/share/dns/root.key``.
To only use the distribution-provided Trust Anchors, add the following to the :ref:`setting-lua-config-file`:
:param str name: The name in the DNS tree from where this NTA should be removed
-.. function:: readTrustAnchorsFromFile(fname)
+.. function:: readTrustAnchorsFromFile(fname[, interval])
.. versionadded:: 4.2.0
This function can be used to read distribution provided trust anchors, as for instance ``/usr/share/dns/root.key`` from Debian's ``dns-root-data`` package.
:param str fname: Path to a zone file with Trust Anchors
+ :param int interval: Re-read this file every ``interval`` hours. By default this is set to 24. Set to 0 to disable automatic re-reads.
#include "validate-recursor.hh"
#include "syncres.hh"
#include "logger.hh"
+#include "rec-lua-conf.hh"
+#include "dnssecinfra.hh"
+#include "dnsseckeeper.hh"
+#include "zoneparser-tng.hh"
DNSSECMode g_dnssecmode{DNSSECMode::ProcessNoValidate};
bool g_dnssecLogBogus;
g_stats.dnssecResults[state]++;
return state;
}
+
+// Returns true if dsAnchors were modified
+bool updateTrustAnchorsFromFile(const std::string &fname, map<DNSName, dsmap_t> &dsAnchors) {
+ map<DNSName,dsmap_t> newDSAnchors;
+ try {
+ auto zp = ZoneParserTNG(fname);
+ DNSResourceRecord rr;
+ DNSRecord dr;
+ while(zp.get(rr)) {
+ dr = DNSRecord(rr);
+ if (rr.qtype == QType::DS) {
+ auto dsr = getRR<DSRecordContent>(dr);
+ if (dsr == nullptr) {
+ throw PDNSException("Unable to parse DS record '" + rr.qname.toString() + " " + rr.getZoneRepresentation() + "'");
+ }
+ newDSAnchors[rr.qname].insert(*dsr);
+ }
+ if (rr.qtype == QType::DNSKEY) {
+ auto dnskeyr = getRR<DNSKEYRecordContent>(dr);
+ if (dnskeyr == nullptr) {
+ throw PDNSException("Unable to parse DNSKEY record '" + rr.qname.toString() + " " + rr.getZoneRepresentation() +"'");
+ }
+ auto dsr = makeDSFromDNSKey(rr.qname, *dnskeyr, DNSSECKeeper::SHA256);
+ newDSAnchors[rr.qname].insert(dsr);
+ }
+ }
+ if (dsAnchors == newDSAnchors) {
+ g_log<<Logger::Debug<<"Read Trust Anchors from file, no changes detected"<<endl;
+ return false;
+ }
+ g_log<<Logger::Info<<"Read changed Trust Anchors from file, updating"<<endl;
+ dsAnchors = newDSAnchors;
+ return true;
+ }
+ catch (const std::exception &e) {
+ throw PDNSException("Error while reading Trust Anchors from file '" + fname + "': " + e.what());
+ }
+ catch (...) {
+ throw PDNSException("Error while reading Trust Anchors from file '" + fname + "'");
+ }
+}
bool checkDNSSECDisabled();
bool warnIfDNSSECDisabled(const string& msg);
vState increaseDNSSECStateCounter(const vState& state);
+bool updateTrustAnchorsFromFile(const std::string &fname, map<DNSName, dsmap_t> &dsAnchors);
+from __future__ import print_function
import os
import subprocess
from recursortests import RecursorTest
self.assertEqual(ret, expected)
except subprocess.CalledProcessError as e:
- print e.output
+ print(e.output)
raise