Rec: add feature to allow names (resolved by system resolver) in forwarding config
rec-protozero.cc rec-protozero.hh \
rec-responsestats.hh rec-responsestats.cc \
rec-snmp.hh rec-snmp.cc \
+ rec-system-resolve.hh rec-system-resolve.cc \
rec-taskqueue.cc rec-taskqueue.hh \
rec-tcounters.cc rec-tcounters.hh \
rec-tcp.cc \
rcpgenerator.cc \
rec-eventtrace.cc rec-eventtrace.hh \
rec-responsestats.hh rec-responsestats.cc \
+ rec-system-resolve.hh rec-system-resolve.cc \
rec-taskqueue.cc rec-taskqueue.hh \
rec-tcounters.cc rec-tcounters.hh \
rec-zonetocache.cc rec-zonetocache.hh \
test-negcache_cc.cc \
test-packetcache_hh.cc \
test-rcpgenerator_cc.cc \
+ test-rec-system-resolve.cc \
test-rec-taskqueue.cc \
test-rec-tcounters_cc.cc \
test-rec-zonetocache.cc \
PDNS_CHECK_OS
PDNS_CHECK_NETWORK_LIBS
+AC_SEARCH_LIBS([res_query], [resolv])
+# macOS uses an alternative name internally
+AC_SEARCH_LIBS([res_9_query], [resolv])
PTHREAD_SET_NAME
AC_FUNC_STRERROR_R
#include "dnsseckeeper.hh"
#include "settings/cxxsettings.hh"
#include "json.hh"
-
+#include "rec-system-resolve.hh"
#ifdef NOD_ENABLED
#include "nod.hh"
#endif /* NOD_ENABLED */
handleRuntimeDefaults(startupLog);
+ if (auto ttl = ::arg().asNum("system-resolver-ttl"); ttl != 0) {
+ time_t interval = ttl;
+ if (::arg().asNum("system-resolver-interval") != 0) {
+ interval = ::arg().asNum("system-resolver-interval");
+ }
+ bool selfResolveCheck = ::arg().mustDo("system-resolver-self-resolve-check");
+ // Cannot use SyncRes::s_serverID, it is not set yet
+ pdns::RecResolve::setInstanceParameters(arg()["server-id"], ttl, interval, selfResolveCheck, []() { reloadZoneConfiguration(g_yamlSettings); });
+ }
+
g_recCache = std::make_unique<MemRecursorCache>(::arg().asNum("record-cache-shards"));
g_negCache = std::make_unique<NegCache>(::arg().asNum("record-cache-shards") / 8);
if (!::arg().mustDo("disable-packetcache")) {
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include "dnsparser.hh"
+#include "dnsrecords.hh"
+#include "rec-system-resolve.hh"
+#include "logging.hh"
+#include "noinitvector.hh"
+#include "threadname.hh"
+
+namespace
+{
+ComboAddress resolve(const std::string& name)
+{
+ struct addrinfo hints = {};
+ hints.ai_flags = AI_ADDRCONFIG;
+ hints.ai_family = 0;
+
+ struct addrinfo* res0 = nullptr;
+ auto ret = getaddrinfo(name.c_str(), nullptr, &hints, &res0);
+ // We pick the first address after sorting for now, no handling of multiple addresses or AF selection.
+ vector<ComboAddress> vec;
+ if (ret != 0) {
+ return {};
+ }
+ auto* res = res0;
+ while (res != nullptr) {
+ try {
+ auto address = ComboAddress{res->ai_addr, res->ai_addrlen};
+ vec.emplace_back(address);
+ }
+ catch (...) {
+ }
+ res = res->ai_next;
+ }
+ freeaddrinfo(res0);
+ if (!vec.empty()) {
+ std::sort(vec.begin(), vec.end());
+ return vec.at(0);
+ }
+ return {};
+}
+
+PacketBuffer resolve(const string& name, QClass cls, QType type)
+{
+ PacketBuffer answer(512);
+ auto ret = res_query(name.c_str(), cls, type, answer.data(), static_cast<int>(answer.size()));
+ if (ret == -1) {
+ answer.resize(0);
+ }
+ else {
+ answer.resize(ret);
+ }
+ return answer;
+}
+
+// do a id.server/CH/TXT query
+std::string serverID()
+{
+ auto buffer = resolve("id.server", QClass::CHAOS, QType::TXT);
+ if (buffer.empty()) {
+ return {};
+ }
+
+ MOADNSParser parser(false, static_cast<const char*>(static_cast<void*>(buffer.data())), buffer.size());
+ if (parser.d_header.rcode != RCode::NoError || parser.d_answers.size() != 1) {
+ return {};
+ }
+ const auto& dnsrecord = parser.d_answers.at(0).first;
+ if (dnsrecord.d_type == QType::TXT) {
+ if (auto txt = getRR<TXTRecordContent>(dnsrecord); txt != nullptr) {
+ const auto& text = txt->d_text;
+ if (text.size() >= 2 && text.at(0) == '"' && text.at(text.size() - 1) == '"') {
+ // remove quotes around text
+ return txt->d_text.substr(1, txt->d_text.size() - 2);
+ }
+ return txt->d_text;
+ }
+ }
+ return {};
+}
+} // anonymous namespace
+
+// RecResolve class members.
+std::string pdns::RecResolve::s_serverID;
+time_t pdns::RecResolve::s_ttl{0};
+time_t pdns::RecResolve::s_interval{0};
+std::function<void()> pdns::RecResolve::s_callback;
+bool pdns::RecResolve::s_selfResolveCheck{false};
+
+void pdns::RecResolve::setInstanceParameters(std::string serverID, time_t ttl, time_t interval, bool selfResolveCheck, const std::function<void()>& callback)
+{
+ pdns::RecResolve::s_serverID = std::move(serverID);
+ pdns::RecResolve::s_ttl = ttl;
+ pdns::RecResolve::s_interval = interval;
+ pdns::RecResolve::s_selfResolveCheck = selfResolveCheck;
+ pdns::RecResolve::s_callback = callback;
+}
+
+pdns::RecResolve& pdns::RecResolve::getInstance()
+{
+ static unique_ptr<RecResolve> res = make_unique<pdns::RecResolve>(s_ttl, s_interval, s_selfResolveCheck, s_callback);
+ return *res;
+}
+
+pdns::RecResolve::RecResolve(time_t ttl, time_t interval, bool selfResolveCheck, const std::function<void()>& callback) :
+ d_ttl(ttl), d_refresher(interval, callback, selfResolveCheck, *this)
+{
+}
+
+pdns::RecResolve::~RecResolve() = default;
+
+void pdns::RecResolve::stopRefresher()
+{
+ d_refresher.finish();
+}
+
+void pdns::RecResolve::startRefresher()
+{
+ d_refresher.start();
+}
+
+ComboAddress pdns::RecResolve::lookupAndRegister(const std::string& name, time_t now)
+{
+ if (s_ttl == 0) {
+ throw PDNSException("config tried to resolve `" + name + "' but system resolver feature not enabled");
+ }
+ auto data = d_data.lock();
+ if (auto iter = data->d_map.find(name); iter != data->d_map.end()) {
+ if (iter->second.d_ttd < now) {
+ return iter->second.d_address;
+ }
+ // If it's stale, re-resolve below
+ }
+ // We keep the lock while resolving, even though this might take a while...
+ auto address = resolve(name);
+
+ time_t ttd = now + d_ttl;
+ auto iter = data->d_map.emplace(name, AddressData{address, ttd}).first;
+ return iter->second.d_address;
+}
+
+ComboAddress pdns::RecResolve::lookup(const std::string& name)
+{
+ auto data = d_data.lock();
+ if (auto iter = data->d_map.find(name); iter != data->d_map.end()) {
+ // always return it, even if it's stale
+ return iter->second.d_address;
+ }
+ throw PDNSException("system resolve of unregistered name: " + name);
+}
+
+void pdns::RecResolve::wipe(const string& name)
+{
+ auto data = d_data.lock();
+ if (name.empty()) {
+ data->d_map.clear();
+ }
+ else {
+ data->d_map.erase(name);
+ }
+}
+
+bool pdns::RecResolve::refresh(time_t now)
+{
+ // The refresh task should not take the lock for a long time, so we're working on a copy
+ ResolveData copy;
+ {
+ auto data = d_data.lock();
+ copy = *data;
+ }
+ std::map<std::string, AddressData> newData;
+
+ auto log = g_slog->withName("system-resolver");
+
+ bool updated = false;
+ for (const auto& entry : copy.d_map) {
+ if (entry.second.d_ttd <= now) {
+ auto newAddress = resolve(entry.first);
+ time_t ttd = now;
+ if (newAddress != ComboAddress()) {
+ // positive resolve, good for ttl
+ ttd += d_ttl;
+ }
+ else {
+ log->error(Logr::Error, "Name did not resolve", "name", Logging::Loggable(entry.first));
+ }
+ if (newAddress != entry.second.d_address) {
+ log->info(Logr::Debug, "Name resolved to new address",
+ "name", Logging::Loggable(entry.first),
+ "address", Logging::Loggable(newAddress.toString()));
+ // An address changed
+ updated = true;
+ }
+ newData.emplace(entry.first, AddressData{newAddress, ttd});
+ }
+ }
+
+ if (!newData.empty()) {
+ auto data = d_data.lock();
+ for (const auto& entry : newData) {
+ data->d_map.insert_or_assign(entry.first, entry.second);
+ }
+ }
+ if (updated) {
+ log->info(Logr::Info, "Changes in names detected");
+ }
+ return updated;
+}
+
+pdns::RecResolve::Refresher::Refresher(time_t interval, const std::function<void()>& callback, bool selfResolveCheck, pdns::RecResolve& res) :
+ d_resolver(res), d_callback(callback), d_interval(std::max(static_cast<time_t>(1), interval)), d_selfResolveCheck(selfResolveCheck)
+{
+ start();
+}
+
+pdns::RecResolve::Refresher::~Refresher()
+{
+ finish();
+}
+
+void pdns::RecResolve::Refresher::refreshLoop()
+{
+ setThreadName("rec/sysres");
+ time_t lastSelfCheck = 0;
+
+ while (!stop) {
+ const time_t startTime = time(nullptr);
+ time_t wakeTime = startTime;
+ // The expresion wakeTime - startTime is equal to the total amount of time slept
+ while (wakeTime - startTime < d_interval) {
+ std::unique_lock lock(mutex);
+ time_t remaining = d_interval - (wakeTime - startTime);
+ if (remaining <= 0) {
+ break;
+ }
+ condVar.wait_for(lock, std::chrono::seconds(remaining),
+ [&doWakeup = wakeup] { return doWakeup.load(); });
+ wakeup = false;
+ if (stop) {
+ break;
+ }
+ if (d_selfResolveCheck && lastSelfCheck < time(nullptr) - 3600) {
+ lastSelfCheck = time(nullptr);
+ auto resolvedServerID = serverID();
+ if (resolvedServerID == s_serverID) {
+ auto log = g_slog->withName("system-resolver");
+ log->info(Logr::Error, "id.server/CH/TXT resolves to my own server identity", "id.server", Logging::Loggable(resolvedServerID));
+ }
+ }
+ bool changes = d_resolver.refresh(time(nullptr));
+ wakeTime = time(nullptr);
+ if (changes) {
+ d_callback();
+ }
+ }
+ }
+}
+
+void pdns::RecResolve::Refresher::finish()
+{
+ stop = true;
+ wakeup = true;
+ condVar.notify_one();
+ d_thread.join();
+}
+
+void pdns::RecResolve::Refresher::start()
+{
+ stop = false;
+ wakeup = false;
+ d_thread = std::thread([this]() { refreshLoop(); });
+}
+
+void pdns::RecResolve::Refresher::trigger()
+{
+ stop = true;
+ wakeup = true;
+ condVar.notify_one();
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#pragma once
+
+#include "config.h"
+
+#include <condition_variable>
+#include <functional>
+#include <thread>
+
+#include "namespaces.hh"
+#include "iputils.hh"
+#include "lock.hh"
+
+/************************************************************************************************
+The pdns::RecResolve class implements a facility to use the system configured resolver. At the moment
+of writing, this can only be used to configure forwarding by name instead of IP.
+ ************************************************************************************************/
+
+/************************************************************************************************
+DESIGN CONSIDERATIONS
+
+- all names looked up with lookupAndRegister() will be entered into a table.
+
+- the names in the table will ber periodically checked by a refresh thread. Set the period (before
+ starting to use the system resolver) by calling pdns::RecResolve::setInstanceParameters().
+
+- if *a* name resolves to a different result than stored, we will call the callback. Currently this is
+ used to call the equivalent of rec_control reload-zones
+
+- A manual rec_control reload-zones will *also* flush the existing table before doing the reload, so
+ we force a re-resolve all names. See
+ rec_channel_rec.cc:reloadZoneConfigurationWithSysResolveReset()
+
+**************************************************************************************************/
+
+/************************************************************************************************
+PRACTICAL CONSIDERATIONS/IMPLEMENTATION LIMITS
+
+- Currently the facility is *only* used by the forwarding code
+
+- We resolve with AI_ADDRCONFIG, the address families enabled will depend on the network config
+ of the machine
+
+- We pick the first address that getaddrinfo() produced. Currently no handling of multiple addresses
+ and/or multiple address families.
+
+- There is a check to detect *some* cases of self-resolve. This is done by resolving
+ id.server/CH/TXT and comparing the result to the system-id set. Both false positives and false
+ negatives can occur.
+
+**************************************************************************************************/
+namespace pdns
+{
+class RecResolve
+{
+public:
+ // Should be called before any getInstance() call is done
+ static void setInstanceParameters(std::string serverID, time_t ttl, time_t interval, bool selfResolveCheck, const std::function<void()>& callback);
+ // Get "the" instance of the system resolver.
+ static RecResolve& getInstance();
+
+ RecResolve(time_t ttl, time_t interval, bool selfResolveCheck, const std::function<void()>& callback = nullptr);
+ ~RecResolve();
+ // Lookup a name and register it in the names to be checked if not already there
+ ComboAddress lookupAndRegister(const std::string& name, time_t now);
+ // Lookup a name which must be already registered
+ ComboAddress lookup(const std::string& name);
+
+ // When an instance is created, it will run a refresh thread, stop it with this method
+ void stopRefresher();
+ // And restart it again
+ void startRefresher();
+ // Wipe one or all names
+ void wipe(const std::string& name = "");
+
+private:
+ bool refresh(time_t now);
+ struct AddressData
+ {
+ ComboAddress d_address;
+ time_t d_ttd{0};
+ };
+ struct ResolveData
+ {
+ std::map<std::string, AddressData> d_map;
+ };
+ LockGuarded<ResolveData> d_data;
+ const time_t d_ttl;
+
+ // This private class implements the refresher thread
+ class Refresher
+ {
+ public:
+ Refresher(time_t interval, const std::function<void()>& callback, bool selfResolveCheck, pdns::RecResolve& res);
+ Refresher(const Refresher&) = delete;
+ Refresher(Refresher&&) = delete;
+ Refresher& operator=(const Refresher&) = delete;
+ Refresher& operator=(Refresher&&) = delete;
+ ~Refresher();
+
+ void start();
+ void finish();
+ void trigger();
+
+ private:
+ void refreshLoop();
+
+ pdns::RecResolve& d_resolver;
+ std::function<void()> d_callback;
+ const time_t d_interval;
+ std::thread d_thread;
+ std::mutex mutex;
+ std::condition_variable condVar;
+ std::atomic<bool> wakeup{false};
+ std::atomic<bool> stop{false};
+ const bool d_selfResolveCheck;
+ };
+
+ Refresher d_refresher;
+
+ static std::string s_serverID;
+ static std::function<void()> s_callback;
+ static time_t s_ttl;
+ static time_t s_interval;
+ static bool s_selfResolveCheck;
+};
+
+}
#include "rec-taskqueue.hh"
#include "rec-tcpout.hh"
#include "rec-main.hh"
+#include "rec-system-resolve.hh"
#include "settings/cxxsettings.hh"
return {0, "ok\n"};
}
+static std::string reloadZoneConfigurationWithSysResolveReset()
+{
+ auto& sysResolver = pdns::RecResolve::getInstance();
+ sysResolver.stopRefresher();
+ sysResolver.wipe();
+ auto ret = reloadZoneConfiguration(g_yamlSettings);
+ sysResolver.startRefresher();
+ return ret;
+}
+
RecursorControlChannel::Answer RecursorControlParser::getAnswer(int socket, const string& question, RecursorControlParser::func_t** command)
{
*command = nop;
g_log << Logger::Error << "Unable to reload zones and forwards when chroot()'ed, requested via control channel" << endl;
return {1, "Unable to reload zones and forwards when chroot()'ed, please restart\n"};
}
- return {0, reloadZoneConfiguration(g_yamlSettings)};
+ return {0, reloadZoneConfigurationWithSysResolveReset()};
}
if (cmd == "set-ecs-minimum-ttl") {
return {0, setMinimumECSTTL(begin, end)};
#include "syncres.hh"
#include "zoneparser-tng.hh"
#include "settings/cxxsettings.hh"
+#include "rec-system-resolve.hh"
extern int g_argc;
extern char** g_argv;
return ret;
}
+static ComboAddress fromNameOrIP(const string& str, uint16_t defPort, Logr::log_t log)
+{
+ try {
+ ComboAddress addr = parseIPAndPort(str, defPort);
+ return addr;
+ }
+ catch (const PDNSException&) {
+ uint16_t port = defPort;
+ string::size_type pos = str.rfind(':');
+ if (pos != string::npos) {
+ port = pdns::checked_stoi<uint16_t>(str.substr(pos + 1));
+ }
+ auto& res = pdns::RecResolve::getInstance();
+ ComboAddress address = res.lookupAndRegister(str.substr(0, pos), time(nullptr));
+ if (address != ComboAddress()) {
+ address.setPort(port);
+ return address;
+ }
+ log->error(Logr::Error, "Could not resolve name", "name", Logging::Loggable(str));
+ throw PDNSException("Could not resolve " + str);
+ }
+}
+
static void convertServersForAD(const std::string& zone, const std::string& input, SyncRes::AuthDomain& authDomain, const char* sepa, Logr::log_t log, bool verbose = true)
{
vector<string> servers;
vector<string> addresses;
for (auto& server : servers) {
- ComboAddress addr = parseIPAndPort(server, 53);
+ ComboAddress addr = fromNameOrIP(server, 53, log);
authDomain.d_servers.push_back(addr);
if (verbose) {
addresses.push_back(addr.toStringWithPort());
recurse: true
notify_allowed: true
+Starting with version 5.1.0, names can be used if
+:ref:`setting-yaml-recursor.system_resolver_ttl` is set.
+The names will be resolved using the system resolver and an automatic refresh of the forwarding zones will happen if a name starts resolving to a new address.
+The refresh is done by performing the equivalent of ``rec_control reload-zones``.
+
Auth Zone
^^^^^^^^^
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
+[[package]]
+name = "hostname-validator"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f558a64ac9af88b5ba400d99b579451af0d39c6d360980045b91aac966d705e2"
+
[[package]]
name = "indexmap"
version = "2.1.0"
dependencies = [
"cxx",
"cxx-build",
+ "hostname-validator",
"ipnet",
"once_cell",
"serde",
serde_yaml = "0.9"
ipnet = "2.8"
once_cell = "1.18.0"
+hostname-validator = "1.1.1" # This is temporary. PR 13819 has the infra to call C++ from, so we can arrange for DNSName::ishostname() to be called instead of importing another crate after that one is merged.
[build-dependencies]
cxx-build = "1.0"
Ok(())
}
+fn is_port_number(str: &str) -> bool {
+ str.parse::<u16>().is_ok()
+}
+
+pub fn validate_socket_address_or_name(field: &str, val: &String) -> Result<(), ValidationError> {
+ let sa = validate_socket_address(field, val);
+ if sa.is_err() {
+ if !hostname_validator::is_valid(val) {
+ let parts: Vec<&str> = val.split(':').collect();
+ if parts.len() != 2
+ || !hostname_validator::is_valid(parts[0])
+ || !is_port_number(parts[1])
+ {
+ let msg = format!(
+ "{}: value `{}' is not an IP, IP:port, name or name:port combination",
+ field, val
+ );
+ return Err(ValidationError { msg });
+ }
+ }
+ }
+ Ok(())
+}
+
fn validate_name(field: &str, val: &String) -> Result<(), ValidationError> {
if val.is_empty() {
let msg = format!("{}: value may not be empty", field);
serde_yaml::from_str(str)
}
-pub fn parse_yaml_string_to_allow_notify_for(
- str: &str,
-) -> Result<Vec<String>, serde_yaml::Error> {
+pub fn parse_yaml_string_to_allow_notify_for(str: &str) -> Result<Vec<String>, serde_yaml::Error> {
serde_yaml::from_str(str)
}
validate_vec(
&(field.to_owned() + ".forwarders"),
&self.forwarders,
- validate_socket_address,
+ validate_socket_address_or_name,
)
}
}
#[allow(clippy::ptr_arg)] //# Avoids creating a rust::Slice object on the C++ side.
-pub fn validate_forward_zones(
- field: &str,
- vec: &Vec<ForwardZone>,
-) -> Result<(), ValidationError> {
+pub fn validate_forward_zones(field: &str, vec: &Vec<ForwardZone>) -> Result<(), ValidationError> {
validate_vec(field, vec, |field, element| element.validate(field))
}
}
serde_yaml::Value::Sequence(seq)
}
- other => serde_yaml::Value::String("map_to_yaml_string: Unknown type: ".to_owned() + other),
+ other => serde_yaml::Value::String(
+ "map_to_yaml_string: Unknown type: ".to_owned() + other,
+ ),
};
if entry.overriding {
let tagged_value = Box::new(serde_yaml::value::TaggedValue {
}
// This function is called from C++, it needs to acquire the lock
-pub fn api_add_forward_zones(path: &str, forwardzones: &mut Vec<ForwardZone>) -> Result<(), std::io::Error> {
+pub fn api_add_forward_zones(
+ path: &str,
+ forwardzones: &mut Vec<ForwardZone>,
+) -> Result<(), std::io::Error> {
let _lock = LOCK.lock().unwrap();
let mut zones = api_read_zones_locked(path, true)?;
zones.forward_zones.append(forwardzones);
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-use std::{error::Error, fmt};
use crate::ValidationError;
+use std::{error::Error, fmt};
/* Helper code for validation */
impl Error for ValidationError {}
pub const OVERRIDE_TAG: &str = "!override";
-pub fn is_overriding(m: &serde_yaml::Mapping, key: &str) -> bool{
+pub fn is_overriding(m: &serde_yaml::Mapping, key: &str) -> bool {
if let Some(serde_yaml::Value::Tagged(vvv)) = m.get(key) {
return vvv.tag == OVERRIDE_TAG;
}
false
}
-
'section' : 'recursor',
'type' : LType.ListStrings,
'default' : 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128',
- 'docdefault': 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\*, ecs-v6-response-bits-\*',
+ 'docdefault': 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\\*, ecs-v6-response-bits-\\*',
'help' : 'List of statistics that are disabled when retrieving the complete list of statistics via the API',
'doc' : '''
A list of comma-separated statistic names, that are disabled when retrieving the complete list of statistics via the API for performance reasons.
'section' : 'recursor',
'type' : LType.ListStrings,
'default' : 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count',
- 'docdefault': 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\*, ecs-v6-response-bits-\*, cumul-answers-\*, cumul-auth4answers-\*, cumul-auth6answers-\*',
+ 'docdefault': 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\\*, ecs-v6-response-bits-\\*, cumul-answers-\\*, cumul-auth4answers-\\*, cumul-auth6answers-\\*',
'help' : 'List of statistics that are prevented from being exported via Carbon',
'doc' : '''
A list of comma-separated statistic names, that are prevented from being exported via carbon for performance reasons.
'section' : 'recursor',
'type' : LType.ListStrings,
'default' : 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count',
- 'docdefault': 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\*, ecs-v6-response-bits-\*, cumul-answers-\*, cumul-auth4answers-\*, cumul-auth6answers-\*',
+ 'docdefault': 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\\*, ecs-v6-response-bits-\\*, cumul-answers-\\*, cumul-auth4answers-\\*, cumul-auth6answers-\\*',
'help' : 'List of statistics that are prevented from being exported via rec_control get-all',
'doc' : '''
A list of comma-separated statistic names, that are disabled when retrieving the complete list of statistics via `rec_control get-all`, for performance reasons.
'section' : 'recursor',
'type' : LType.ListStrings,
'default' : 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-1, ecs-v4-response-bits-2, ecs-v4-response-bits-3, ecs-v4-response-bits-4, ecs-v4-response-bits-5, ecs-v4-response-bits-6, ecs-v4-response-bits-7, ecs-v4-response-bits-8, ecs-v4-response-bits-9, ecs-v4-response-bits-10, ecs-v4-response-bits-11, ecs-v4-response-bits-12, ecs-v4-response-bits-13, ecs-v4-response-bits-14, ecs-v4-response-bits-15, ecs-v4-response-bits-16, ecs-v4-response-bits-17, ecs-v4-response-bits-18, ecs-v4-response-bits-19, ecs-v4-response-bits-20, ecs-v4-response-bits-21, ecs-v4-response-bits-22, ecs-v4-response-bits-23, ecs-v4-response-bits-24, ecs-v4-response-bits-25, ecs-v4-response-bits-26, ecs-v4-response-bits-27, ecs-v4-response-bits-28, ecs-v4-response-bits-29, ecs-v4-response-bits-30, ecs-v4-response-bits-31, ecs-v4-response-bits-32, ecs-v6-response-bits-1, ecs-v6-response-bits-2, ecs-v6-response-bits-3, ecs-v6-response-bits-4, ecs-v6-response-bits-5, ecs-v6-response-bits-6, ecs-v6-response-bits-7, ecs-v6-response-bits-8, ecs-v6-response-bits-9, ecs-v6-response-bits-10, ecs-v6-response-bits-11, ecs-v6-response-bits-12, ecs-v6-response-bits-13, ecs-v6-response-bits-14, ecs-v6-response-bits-15, ecs-v6-response-bits-16, ecs-v6-response-bits-17, ecs-v6-response-bits-18, ecs-v6-response-bits-19, ecs-v6-response-bits-20, ecs-v6-response-bits-21, ecs-v6-response-bits-22, ecs-v6-response-bits-23, ecs-v6-response-bits-24, ecs-v6-response-bits-25, ecs-v6-response-bits-26, ecs-v6-response-bits-27, ecs-v6-response-bits-28, ecs-v6-response-bits-29, ecs-v6-response-bits-30, ecs-v6-response-bits-31, ecs-v6-response-bits-32, ecs-v6-response-bits-33, ecs-v6-response-bits-34, ecs-v6-response-bits-35, ecs-v6-response-bits-36, ecs-v6-response-bits-37, ecs-v6-response-bits-38, ecs-v6-response-bits-39, ecs-v6-response-bits-40, ecs-v6-response-bits-41, ecs-v6-response-bits-42, ecs-v6-response-bits-43, ecs-v6-response-bits-44, ecs-v6-response-bits-45, ecs-v6-response-bits-46, ecs-v6-response-bits-47, ecs-v6-response-bits-48, ecs-v6-response-bits-49, ecs-v6-response-bits-50, ecs-v6-response-bits-51, ecs-v6-response-bits-52, ecs-v6-response-bits-53, ecs-v6-response-bits-54, ecs-v6-response-bits-55, ecs-v6-response-bits-56, ecs-v6-response-bits-57, ecs-v6-response-bits-58, ecs-v6-response-bits-59, ecs-v6-response-bits-60, ecs-v6-response-bits-61, ecs-v6-response-bits-62, ecs-v6-response-bits-63, ecs-v6-response-bits-64, ecs-v6-response-bits-65, ecs-v6-response-bits-66, ecs-v6-response-bits-67, ecs-v6-response-bits-68, ecs-v6-response-bits-69, ecs-v6-response-bits-70, ecs-v6-response-bits-71, ecs-v6-response-bits-72, ecs-v6-response-bits-73, ecs-v6-response-bits-74, ecs-v6-response-bits-75, ecs-v6-response-bits-76, ecs-v6-response-bits-77, ecs-v6-response-bits-78, ecs-v6-response-bits-79, ecs-v6-response-bits-80, ecs-v6-response-bits-81, ecs-v6-response-bits-82, ecs-v6-response-bits-83, ecs-v6-response-bits-84, ecs-v6-response-bits-85, ecs-v6-response-bits-86, ecs-v6-response-bits-87, ecs-v6-response-bits-88, ecs-v6-response-bits-89, ecs-v6-response-bits-90, ecs-v6-response-bits-91, ecs-v6-response-bits-92, ecs-v6-response-bits-93, ecs-v6-response-bits-94, ecs-v6-response-bits-95, ecs-v6-response-bits-96, ecs-v6-response-bits-97, ecs-v6-response-bits-98, ecs-v6-response-bits-99, ecs-v6-response-bits-100, ecs-v6-response-bits-101, ecs-v6-response-bits-102, ecs-v6-response-bits-103, ecs-v6-response-bits-104, ecs-v6-response-bits-105, ecs-v6-response-bits-106, ecs-v6-response-bits-107, ecs-v6-response-bits-108, ecs-v6-response-bits-109, ecs-v6-response-bits-110, ecs-v6-response-bits-111, ecs-v6-response-bits-112, ecs-v6-response-bits-113, ecs-v6-response-bits-114, ecs-v6-response-bits-115, ecs-v6-response-bits-116, ecs-v6-response-bits-117, ecs-v6-response-bits-118, ecs-v6-response-bits-119, ecs-v6-response-bits-120, ecs-v6-response-bits-121, ecs-v6-response-bits-122, ecs-v6-response-bits-123, ecs-v6-response-bits-124, ecs-v6-response-bits-125, ecs-v6-response-bits-126, ecs-v6-response-bits-127, ecs-v6-response-bits-128, cumul-clientanswers, cumul-authanswers, policy-hits, proxy-mapping-total, remote-logger-count',
- 'docdefault': 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\*, ecs-v6-response-bits-\*',
+ 'docdefault': 'cache-bytes, packetcache-bytes, special-memory-usage, ecs-v4-response-bits-\\*, ecs-v6-response-bits-\\*',
'help' : 'List of statistics that are prevented from being exported via SNMP',
'doc' : '''
A list of comma-separated statistic names, that are prevented from being exported via SNMP, for performance reasons.
''',
'versionadded': '4.5.0'
},
+ {
+ 'name' : 'system_resolver_ttl',
+ 'section' : 'recursor',
+ 'type' : LType.Uint64,
+ 'default' : '0',
+ 'help' : 'Set TTL of system resolver feature, 0 (default) is disabled',
+ 'doc' : '''
+Sets TTL in seconds of the system resolver feature.
+If not equal to zero names can be used for forwarding targets.
+The names will be resolved by the system resolver configured in the OS.
+
+The TTL is used as a time to live to see if the names used in forwarding resolve to a different address than before.
+If the TTL is expired, a re-resolve will be done by the next iteration of the check function;
+if a change is detected, the recursor performs an equivalent of ``rec_control reload-zones``.
+
+Make sure the recursor itself is not used by the system resolver! Default is 0 (not enabled).
+A suggested value is 60.
+''',
+ 'versionadded': '5.1.0'
+ },
+ {
+ 'name' : 'system_resolver_interval',
+ 'section' : 'recursor',
+ 'type' : LType.Uint64,
+ 'default' : '0',
+ 'help' : 'Set interval (in seconds) of the re-resolve checks of system resolver subsystem.',
+ 'doc' : '''
+Sets the check interval (in seconds) of the system resolver feature.
+All names known by the system resolver subsystem are periodically checked for changing values.
+
+If the TTL of a name has expired, it is checked by re-resolving it.
+if a change is detected, the recursor performs an equivalent of ``rec_control reload-zones``.
+
+This settings sets the interval between the checks.
+If set to zero (the default), the value :ref:`setting-system-resolver-ttl` is used.
+''',
+ 'versionadded': '5.1.0'
+ },
+ {
+ 'name' : 'system_resolver_self_resolve_check',
+ 'section' : 'recursor',
+ 'type' : LType.Bool,
+ 'default' : 'true',
+ 'help' : 'Check for potential self-resolve, default enabled.',
+ 'doc' : '''
+Warn on potential self-resolve.
+If this check draws the wrong conclusion, you can disable it.
+''',
+ 'versionadded': '5.1.0'
+ },
]
--- /dev/null
+#ifndef BOOST_TEST_DYN_LINK
+#define BOOST_TEST_DYN_LINK
+#endif
+
+#include <boost/test/unit_test.hpp>
+
+#include "rec-system-resolve.hh"
+
+BOOST_AUTO_TEST_SUITE(rec_system_resolve)
+
+BOOST_AUTO_TEST_CASE(test_basic_resolve)
+{
+
+ pdns::RecResolve::setInstanceParameters("foo", 60, 10, false, nullptr);
+ auto& sysResolve = pdns::RecResolve::getInstance();
+
+ auto address = sysResolve.lookupAndRegister("localhost", time(nullptr));
+ BOOST_CHECK(address.toString() == "127.0.0.1" || address.toString() == "::1");
+ address = sysResolve.lookup("localhost");
+ BOOST_CHECK(address.toString() == "127.0.0.1" || address.toString() == "::1");
+ sysResolve.wipe("localhost");
+ BOOST_CHECK_THROW(sysResolve.lookup("localhost"), PDNSException);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
- zone: "example.com"
forwarders:
- 1.2.3.4
- - a.b
+ - '-a.b'
)EOT";
auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml);
--- /dev/null
+import dns
+import os
+import unittest
+import subprocess
+import time
+from recursortests import RecursorTest
+
+class testNamedForward(RecursorTest):
+ """
+ This is forwarding test using a name as target
+ """
+
+ _confdir = 'NamedForward'
+ _config_template = """
+dnssec=validate
+forward-zones-recurse=.=dns.quad9.net
+system-resolver-ttl=10
+ """
+
+ @classmethod
+ def setUpClass(cls):
+
+ # we don't need all the auth stuff
+ cls.setUpSockets()
+
+ confdir = os.path.join('configs', cls._confdir)
+ cls.createConfigDir(confdir)
+
+ cls.generateRecursorConfig(confdir)
+ cls.startRecursor(confdir, cls._recursorPort)
+
+ def testA(self):
+ expected = dns.rrset.from_text('dns.google.', 0, dns.rdataclass.IN, 'A', '8.8.8.8', '8.8.4.4')
+ query = dns.message.make_query('dns.google', 'A', want_dnssec=True)
+ query.flags |= dns.flags.AD
+
+ res = self.sendUDPQuery(query)
+
+ self.assertMessageIsAuthenticated(res)
+ self.assertRRsetInAnswer(res, expected)
+ self.assertMatchingRRSIGInAnswer(res, expected)
+
+@unittest.skipUnless('ENABLE_SUDO_TESTS' in os.environ, "sudo is not available")
+class testNamedForwardWithChange(RecursorTest):
+ """
+ This is forwarding test using a name as target and a changing resolve
+ """
+
+ _confdir = 'NamedForwardWithChange'
+ _config_template = """
+dnssec=off
+forward-zones-recurse=.=namedforwardtest
+devonly-regression-test-mode
+system-resolver-ttl=1
+ """
+
+ @classmethod
+ def generateRecursorConfig(cls, confdir):
+ subprocess.run(['sudo', 'sed', '-i', '-e', '/namedforwardtest/d', '/etc/hosts'])
+ subprocess.run(['sudo', 'sh', '-c', 'echo ' + cls._PREFIX + '.10 namedforwardtest >> /etc/hosts'])
+ super(testNamedForwardWithChange, cls).generateRecursorConfig(confdir)
+
+ def testExampleNSQuery(self):
+ query = dns.message.make_query('example', 'NS', want_dnssec=False)
+
+ expectedNS = dns.rrset.from_text('example.', 0, 'IN', 'NS', 'ns1.example.', 'ns2.example.')
+
+ res = self.sendUDPQuery(query)
+
+ self.assertRcodeEqual(res, dns.rcode.NOERROR)
+ self.assertRRsetInAnswer(res, expectedNS)
+
+ subprocess.run(['sudo', 'sed', '-i', '-e', '/namedforwardtest/d', '/etc/hosts'])
+ subprocess.run(['sudo', 'sh', '-c', 'echo ' + self._PREFIX + '.12 namedforwardtest >> /etc/hosts'])
+
+ # the change should get picked up by the systemn resolver update thread and the reload flushes the caches
+ time.sleep(2)
+ res = self.sendUDPQuery(query)
+ subprocess.run(['sudo', 'sed', '-i', '-e', '/namedforwardtest/d', '/etc/hosts'])
+ self.assertRcodeEqual(res, dns.rcode.SERVFAIL)