thread_local std::unique_ptr<MT_t> MT; // the big MTasker
std::unique_ptr<MemRecursorCache> g_recCache;
std::unique_ptr<NegCache> g_negCache;
-std::map<std::string, std::string> g_zones_to_cache;
thread_local std::unique_ptr<RecursorPacketCache> t_packetCache;
thread_local FDMultiplexer* t_fdm{nullptr};
g_log<<Logger::Error<<"Exception while priming the root NS zones"<<endl;
}
}
- // Redo zones-to-cache if the min TTL of those zones time is 90% up.
- if (!g_zones_to_cache.empty() && now.tv_sec - last_zone_to_cache > 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);
}
}
exit(1);
}
}
- {
- std::vector<std::string> 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");
::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";
rpzPrimary(lci, delayedThreads, primaries_, zoneName, options);
});
+ typedef std::unordered_map<std::string, boost::variant<uint32_t, std::string>> zoneToCacheOptions_t;
+
+ Lua.writeFunction("zoneToCache", [&lci](const string& zoneName, const string& method, const boost::variant<string, std::vector<std::pair<int, string>>>& primaries, boost::optional<zoneToCacheOptions_t> 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<std::string>(primaries));
+ }
+ else {
+ for (const auto& primary : boost::get<std::vector<std::pair<int, std::string>>>(primaries)) {
+ conf.d_sources.push_back(primary.second);
+ }
+ }
+ if (options) {
+ auto& have = *options;
+ if (have.count("timeout")) {
+ conf.d_timeout = boost::get<uint32_t>(have["timeout"]);
+ }
+ if (have.count("tsigname")) {
+ conf.d_tt.name = DNSName(toLower(boost::get<string>(have["tsigname"])));
+ conf.d_tt.algo = DNSName(toLower(boost::get<string>(have[ "tsigalgo"])));
+ if (B64Decode(boost::get<string>(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<size_t>(boost::get<uint32_t>(have["maxReceivedMBytes"]));
+ conf.d_maxReceivedBytes *= 1024 * 1024;
+ }
+ if (have.count("localAddress")) {
+ conf.d_local = ComboAddress(boost::get<string>(have["localAddress"]));
+ }
+ }
+
+ lci.zonesToCacheConfig.push_back(conf);
+ }
+ catch (const std::exception&e ) {
+ g_log<<Logger::Error<<"Problem configuring zoneToCache: "<<e.what()<<endl;
+ }
+ });
+
typedef vector<pair<int,boost::variant<string, vector<pair<int, string> > > > > argvec_t;
Lua.writeFunction("addSortList",
[&lci](const std::string& formask_,
#include "sortlist.hh"
#include "filterpo.hh"
#include "validate.hh"
+#include "rec-zonetocache.hh"
struct ProtobufExportConfig
{
ProtobufExportConfig protobufExportConfig;
ProtobufExportConfig outgoingProtobufExportConfig;
FrameStreamExportConfig frameStreamExportConfig;
-
+ vector<RecZoneToCache::Config> zonesToCacheConfig;
/* we need to increment this every time the configuration
is reloaded, so we know if we need to reload the protobuf
remote loggers */
#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<std::string, std::string>& map)
+#ifdef HAVE_LIBCURL
+#include "minicurl.hh"
+#endif
+
+time_t RecZoneToCache::ZonesToCache(const std::vector<Config>& cfgs)
{
// By default and max once per 24 hours
time_t refresh = 24 * 3600;
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;
}
// We do not want to refresh more than once per hour
- refresh = max(refresh, 3600LL);
+ refresh = std::max(refresh, 3600LL);
}
return refresh;
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)
}
}
-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);
}
}
}
-static std::vector<std::string> getLinesFromFile(const std::string& url)
+static std::vector<std::string> getLinesFromFile(const RecZoneToCache::Config& config)
{
+
std::vector<std::string> 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);
return lines;
}
-static std::vector<std::string> getURL(const std::string& url)
+static std::vector<std::string> getURL(const RecZoneToCache::Config& config)
{
std::vector<std::string> 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)) {
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<time_t>::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
// 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<string> 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);
#pragma once
#include "namespaces.hh"
+#include "dns.hh"
+#include "iputils.hh"
class RecZoneToCache
{
public:
- static time_t ZonesToCache(const std::map<std::string, std::string>& map);
+ struct Config
+ {
+ std::string d_zone; // Zone name
+ std::string d_method; // axfr, http, https, file
+ vector<std::string> 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<Config>&);
private:
- static time_t ZoneToCache(const string& name, const string& url, bool dnssec);
+ static time_t ZoneToCache(const Config& config, bool dnssec);
};