From: Pieter Lexis Date: Mon, 15 Oct 2018 10:24:59 +0000 (+0200) Subject: rec: automatically reload trust anchors from file X-Git-Tag: dnsdist-1.3.3~23^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e4ae55e5d9ea28f99dfbbe93975e592686b45dd5;p=thirdparty%2Fpdns.git rec: automatically reload trust anchors from file This allows external processec to update TA's without having to restart the recursor. --- diff --git a/pdns/pdns_recursor.cc b/pdns/pdns_recursor.cc index 3c7ec0ee31..3b765c304b 100644 --- a/pdns/pdns_recursor.cc +++ b/pdns/pdns_recursor.cc @@ -2516,9 +2516,16 @@ static void doStats(void) 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; @@ -2571,8 +2578,24 @@ static void houseKeeping(void *) g_log<trustAnchorFileInfo.fname.empty() && luaconfsLocal->trustAnchorFileInfo.interval != 0 && + g_now.tv_sec - last_trustAnchorUpdate >= (luaconfsLocal->trustAnchorFileInfo.interval * 3600)) { + g_log< 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< g_luaconfs; @@ -411,37 +408,15 @@ void loadRecursorLuaConfig(const std::string& fname, luaConfigDelayedThreads& de 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(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(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 interval) { + uint32_t realInterval = 24; + if (interval) { + realInterval = static_cast(*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 diff --git a/pdns/rec-lua-conf.hh b/pdns/rec-lua-conf.hh index fad49ddd19..a47077a280 100644 --- a/pdns/rec-lua-conf.hh +++ b/pdns/rec-lua-conf.hh @@ -41,12 +41,18 @@ struct ProtobufExportConfig 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 dsAnchors; map negAnchors; ProtobufExportConfig protobufExportConfig; diff --git a/pdns/recursordist/docs/dnssec.rst b/pdns/recursordist/docs/dnssec.rst index b5bd5b9a41..7c54102c64 100644 --- a/pdns/recursordist/docs/dnssec.rst +++ b/pdns/recursordist/docs/dnssec.rst @@ -105,6 +105,7 @@ Reading trust anchors from files 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`: diff --git a/pdns/recursordist/docs/lua-config/dnssec.rst b/pdns/recursordist/docs/lua-config/dnssec.rst index 17b189d339..f278c9af6c 100644 --- a/pdns/recursordist/docs/lua-config/dnssec.rst +++ b/pdns/recursordist/docs/lua-config/dnssec.rst @@ -57,7 +57,7 @@ This page only documents the Lua functions for DNSSEC configuration :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 @@ -65,3 +65,4 @@ This page only documents the Lua functions for DNSSEC configuration 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. diff --git a/pdns/validate-recursor.cc b/pdns/validate-recursor.cc index 3299631318..6b62e1b8b2 100644 --- a/pdns/validate-recursor.cc +++ b/pdns/validate-recursor.cc @@ -2,6 +2,10 @@ #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; @@ -24,3 +28,44 @@ vState increaseDNSSECStateCounter(const vState& state) g_stats.dnssecResults[state]++; return state; } + +// Returns true if dsAnchors were modified +bool updateTrustAnchorsFromFile(const std::string &fname, map &dsAnchors) { + map 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(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(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< &dsAnchors); diff --git a/regression-tests.recursor-dnssec/test_ReadTrustAnchorsFromFile.py b/regression-tests.recursor-dnssec/test_ReadTrustAnchorsFromFile.py index c150703ee9..913aa3ca6f 100644 --- a/regression-tests.recursor-dnssec/test_ReadTrustAnchorsFromFile.py +++ b/regression-tests.recursor-dnssec/test_ReadTrustAnchorsFromFile.py @@ -1,3 +1,4 @@ +from __future__ import print_function import os import subprocess from recursortests import RecursorTest @@ -25,6 +26,6 @@ readTrustAnchorsFromFile('root.keys')""" self.assertEqual(ret, expected) except subprocess.CalledProcessError as e: - print e.output + print(e.output) raise