From: Otto Date: Wed, 29 Sep 2021 13:51:51 +0000 (+0200) Subject: Scaffolding for config via Lua X-Git-Tag: auth-4.6.0-alpha1~5^2~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e807cd1ee9d4b16579c7f941297de7b684022bce;p=thirdparty%2Fpdns.git Scaffolding for config via Lua --- diff --git a/pdns/pdns_recursor.cc b/pdns/pdns_recursor.cc index ceb32001a4..1eef4713dc 100644 --- a/pdns/pdns_recursor.cc +++ b/pdns/pdns_recursor.cc @@ -136,7 +136,6 @@ static thread_local uint64_t t_frameStreamServersGeneration; thread_local std::unique_ptr MT; // the big MTasker std::unique_ptr g_recCache; std::unique_ptr g_negCache; -std::map g_zones_to_cache; thread_local std::unique_ptr t_packetCache; thread_local FDMultiplexer* t_fdm{nullptr}; @@ -3776,10 +3775,10 @@ static void houseKeeping(void *) g_log< zones_to_cache_interval * 9 / 10) { + // Redo zones-to-cache if the min TTL of those zones time is 90% passed. + if (!luaconfsLocal->zonesToCacheConfig.empty() && now.tv_sec - last_zone_to_cache > zones_to_cache_interval * 9 / 10) { last_zone_to_cache = now.tv_sec; - zones_to_cache_interval = RecZoneToCache::ZonesToCache(g_zones_to_cache); + zones_to_cache_interval = RecZoneToCache::ZonesToCache(luaconfsLocal->zonesToCacheConfig); } } @@ -5027,19 +5026,6 @@ static int serviceMain(int argc, char*argv[]) exit(1); } } - { - std::vector parts; - stringtok(parts, ::arg()["zones-to-cache"], " ,\t\n\r"); - for (const auto& p : parts) { - if (p.find('=') == string::npos) { - throw PDNSException("Error parsing '" + p + "', missing ="); - } - auto [zone, url] = splitField(p, '='); - boost::trim(zone); - boost::trim(url); - g_zones_to_cache[zone] = url; - } - } g_networkTimeoutMsec = ::arg().asNum("network-timeout"); @@ -5963,7 +5949,6 @@ int main(int argc, char **argv) ::arg().setSwitch("dot-to-port-853", "Force DoT connection to target port 853 if DoT compiled in")="yes"; ::arg().set("dot-to-auth-names", "Use DoT to authoritative servers with these names or suffixes")=""; - ::arg().set("zones-to-cache", "Zones to prefill the cache with, comma separated domain=url pairs")=""; ::arg().set("tcp-out-max-idle-ms", "Time TCP/DoT connections are left idle in milliseconds or 0 if no limit") = "10000"; ::arg().set("tcp-out-max-idle-per-auth", "Maximum number of idle TCP/DoT connections to a specific IP per thread, 0 means do not keep idle connections open") = "10"; diff --git a/pdns/rec-lua-conf.cc b/pdns/rec-lua-conf.cc index 3f86fcd0be..6bcd0b897b 100644 --- a/pdns/rec-lua-conf.cc +++ b/pdns/rec-lua-conf.cc @@ -398,6 +398,49 @@ void loadRecursorLuaConfig(const std::string& fname, luaConfigDelayedThreads& de rpzPrimary(lci, delayedThreads, primaries_, zoneName, options); }); + typedef std::unordered_map> zoneToCacheOptions_t; + + Lua.writeFunction("zoneToCache", [&lci](const string& zoneName, const string& method, const boost::variant>>& primaries, boost::optional options) { + try { + RecZoneToCache::Config conf; + conf.d_zone = zoneName; + conf.d_method = method; + if (primaries.type() == typeid(string)) { + conf.d_sources.push_back(boost::get(primaries)); + } + else { + for (const auto& primary : boost::get>>(primaries)) { + conf.d_sources.push_back(primary.second); + } + } + if (options) { + auto& have = *options; + if (have.count("timeout")) { + conf.d_timeout = boost::get(have["timeout"]); + } + if (have.count("tsigname")) { + conf.d_tt.name = DNSName(toLower(boost::get(have["tsigname"]))); + conf.d_tt.algo = DNSName(toLower(boost::get(have[ "tsigalgo"]))); + if (B64Decode(boost::get(have[ "tsigsecret"]), conf.d_tt.secret)) { + throw std::runtime_error("TSIG secret is not valid Base-64 encoded"); + } + } + if (have.count("maxReceivedMBytes")) { + conf.d_maxReceivedBytes = static_cast(boost::get(have["maxReceivedMBytes"])); + conf.d_maxReceivedBytes *= 1024 * 1024; + } + if (have.count("localAddress")) { + conf.d_local = ComboAddress(boost::get(have["localAddress"])); + } + } + + lci.zonesToCacheConfig.push_back(conf); + } + catch (const std::exception&e ) { + g_log< > > > > argvec_t; Lua.writeFunction("addSortList", [&lci](const std::string& formask_, diff --git a/pdns/rec-lua-conf.hh b/pdns/rec-lua-conf.hh index cc03bf99a2..c9317f1088 100644 --- a/pdns/rec-lua-conf.hh +++ b/pdns/rec-lua-conf.hh @@ -26,6 +26,7 @@ #include "sortlist.hh" #include "filterpo.hh" #include "validate.hh" +#include "rec-zonetocache.hh" struct ProtobufExportConfig { @@ -72,7 +73,7 @@ public: ProtobufExportConfig protobufExportConfig; ProtobufExportConfig outgoingProtobufExportConfig; FrameStreamExportConfig frameStreamExportConfig; - + vector zonesToCacheConfig; /* we need to increment this every time the configuration is reloaded, so we know if we need to reload the protobuf remote loggers */ diff --git a/pdns/recursordist/rec-zonetocache.cc b/pdns/recursordist/rec-zonetocache.cc index 1835e89cbf..9e4a4899be 100644 --- a/pdns/recursordist/rec-zonetocache.cc +++ b/pdns/recursordist/rec-zonetocache.cc @@ -23,13 +23,16 @@ #include "rec-zonetocache.hh" #include "syncres.hh" -#include "minicurl.hh" #include "zoneparser-tng.hh" #include "query-local-address.hh" #include "axfr-retriever.hh" #include "validate-recursor.hh" -time_t RecZoneToCache::ZonesToCache(const std::map& map) +#ifdef HAVE_LIBCURL +#include "minicurl.hh" +#endif + +time_t RecZoneToCache::ZonesToCache(const std::vector& cfgs) { // By default and max once per 24 hours time_t refresh = 24 * 3600; @@ -41,10 +44,10 @@ time_t RecZoneToCache::ZonesToCache(const std::map& ma sr.setDoDNSSEC(dnssec); sr.setDNSSECValidationRequested(g_dnssecmode != DNSSECMode::Off && g_dnssecmode != DNSSECMode::ProcessNoValidate); - for (const auto& [zone, url] : map) { - const string msg = "zones-to-cache error while loading " + zone + " from " + url + ": "; + for (const auto& config : cfgs) { + const string msg = "zones-to-cache error while loading " + config.d_zone + ": "; try { - refresh = min(refresh, ZoneToCache(zone, url, dnssec)); + refresh = min(refresh, ZoneToCache(config, dnssec)); } catch (const PDNSException& e) { g_log << Logger::Error << msg << e.reason << endl; @@ -57,7 +60,7 @@ time_t RecZoneToCache::ZonesToCache(const std::map& ma } // We do not want to refresh more than once per hour - refresh = max(refresh, 3600LL); + refresh = std::max(refresh, 3600LL); } return refresh; @@ -74,7 +77,7 @@ struct ZoneData bool isRRSetAuth(const DNSName& qname, QType qtype); void parseDRForCache(DNSRecord& dr); - void getByAXFR(const std::string& url); + void getByAXFR(const RecZoneToCache::Config&); }; bool ZoneData::isRRSetAuth(const DNSName& qname, QType qtype) @@ -141,13 +144,13 @@ void ZoneData::parseDRForCache(DNSRecord& dr) } } -void ZoneData::getByAXFR(const std::string& url) +void ZoneData::getByAXFR(const RecZoneToCache::Config& config) { - ComboAddress primary = ComboAddress(url.substr(7), 53); - uint16_t axfrTimeout = 20; - size_t maxReceivedBytes = 0; - const TSIGTriplet tt; - ComboAddress local; //(localAddress); + ComboAddress primary = ComboAddress(config.d_sources.at(0), 53); + uint16_t axfrTimeout = config.d_timeout; + size_t maxReceivedBytes = config.d_maxReceivedBytes; + const TSIGTriplet tt = config.d_tt; + ComboAddress local = config.d_local; if (local == ComboAddress()) { local = pdns::getQueryLocalAddress(primary.sin4.sin_family, 0); } @@ -168,10 +171,14 @@ void ZoneData::getByAXFR(const std::string& url) } } -static std::vector getLinesFromFile(const std::string& url) +static std::vector getLinesFromFile(const RecZoneToCache::Config& config) { + std::vector lines; - std::ifstream stream(url); + std::ifstream stream(config.d_sources.at(0)); + if (!stream) { + throw PDNSException("Cannot read file: " + config.d_sources.at(0)); + } std::string line; while (std::getline(stream, line)) { lines.push_back(line); @@ -179,12 +186,13 @@ static std::vector getLinesFromFile(const std::string& url) return lines; } -static std::vector getURL(const std::string& url) +static std::vector getURL(const RecZoneToCache::Config& config) { std::vector lines; #ifdef HAVE_LIBCURL MiniCurl mc; - std::string reply = mc.getURL(url, nullptr, nullptr, 10, false, true); + ComboAddress local = config.d_local; + std::string reply = mc.getURL(config.d_sources.at(0), nullptr, local == ComboAddress() ? nullptr : &local, config.d_timeout, false, true); std::istringstream stream(reply); string line; while (std::getline(stream, line)) { @@ -194,11 +202,14 @@ static std::vector getURL(const std::string& url) return lines; } -time_t RecZoneToCache::ZoneToCache(const string& name, const string& url, bool dnssec) +time_t RecZoneToCache::ZoneToCache(const Config& config, bool dnssec) { + if (config.d_sources.size() > 1) { + // XXX Warning + } ZoneData data; data.d_refresh = std::numeric_limits::max(); - data.d_zone = DNSName(name); + data.d_zone = DNSName(config.d_zone); data.d_now = time(nullptr); // We do not do validation, it will happen on-demand if an Indeterminate record is encountered when the caches are queried @@ -206,16 +217,16 @@ time_t RecZoneToCache::ZoneToCache(const string& name, const string& url, bool d // 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. - if (url.substr(0, 7) == "axfr://") { - data.getByAXFR(url); + if (config.d_method == "axfr") { + data.getByAXFR(config); } else { vector lines; - if (url.substr(0, 8) != "https://" && url.substr(0, 7) != "http://") { - lines = getLinesFromFile(url); + if (config.d_method == "url") { + lines = getURL(config); } - else { - lines = getURL(url); + else if (config.d_method == "file") { + lines = getLinesFromFile(config); } DNSResourceRecord drr; ZoneParserTNG zpt(lines, data.d_zone); diff --git a/pdns/recursordist/rec-zonetocache.hh b/pdns/recursordist/rec-zonetocache.hh index 7f777dcf9f..d95891e955 100644 --- a/pdns/recursordist/rec-zonetocache.hh +++ b/pdns/recursordist/rec-zonetocache.hh @@ -23,12 +23,24 @@ #pragma once #include "namespaces.hh" +#include "dns.hh" +#include "iputils.hh" class RecZoneToCache { public: - static time_t ZonesToCache(const std::map& map); + struct Config + { + std::string d_zone; // Zone name + std::string d_method; // axfr, http, https, file + vector d_sources; // IPs or URLs + uint32_t d_timeout{20}; // timeout in seconds + ComboAddress d_local; // local address + size_t d_maxReceivedBytes{0}; // Maximum size + TSIGTriplet d_tt; // Authentication data + }; + static time_t ZonesToCache(const std::vector&); private: - static time_t ZoneToCache(const string& name, const string& url, bool dnssec); + static time_t ZoneToCache(const Config& config, bool dnssec); };