}
g_maxCacheEntries = ::arg().asNum("max-cache-entries");
- luaconfig(false);
- // try {
- // ProxyMapping proxyMapping;
- // LuaConfigItems lci;
- // loadRecursorLuaConfig(::arg()["lua-config-file"], proxyMapping, lci);
- // // Initial proxy mapping
- // g_proxyMapping = proxyMapping.empty() ? nullptr : std::make_unique<ProxyMapping>(proxyMapping);
- // activateLuaConfig(lci);
- // }
- // catch (PDNSException& e) {
- // SLOG(g_log << Logger::Error << "Cannot load Lua configuration: " << e.reason << endl,
- // log->error(Logr::Error, e.reason, "Cannot load Lua configuration"));
- // return 1;
- // }
+ auto luaResult = luaconfig(false);
+ if (luaResult.d_ret != 0) {
+ SLOG(g_log << Logger::Error << "Cannot load Lua or equivalent YAML configuration: " << luaResult.d_str << endl,
+ log->error(Logr::Error, luaResult.d_str, "Cannot load Lua or equivalent YAML configuration"));
+ return 1;
+ }
parseACLs();
initPublicSuffixList(::arg()["public-suffix-list-file"]);
}
}
-static pair<int, bool> doYamlConfig(Logr::log_t startupLog, int argc, char* argv[], const pdns::rust::settings::rec::Recursorsettings& settings) // NOLINT: Posix API
+static pair<int, bool> doYamlConfig(int argc, char* argv[], const pdns::rust::settings::rec::Recursorsettings& settings) // NOLINT: Posix API
{
if (!::arg().mustDo("config")) {
return {0, false};
const string config = ::arg()["config"];
if (config == "diff" || config.empty()) {
::arg().parse(argc, argv);
- //pdns::rust::settings::rec::Recursorsettings settings;
- //pdns::settings::rec::oldStyleSettingsToBridgeStruct(settings);
ProxyMapping proxyMapping;
LuaConfigItems lci;
pdns::settings::rec::fromBridgeStructToLuaConfig(settings, lci, proxyMapping);
- cerr << "LCI " << lci.trustAnchorFileInfo.fname << endl;
-
- //pdns::settings::rec::fromLuaConfigToBridgeStruct(lci, proxyMapping, settings);
auto yaml = settings.to_yaml_string();
cout << yaml << endl;
}
if (g_yamlSettings) {
bool mustExit = false;
- std::tie(ret, mustExit) = doYamlConfig(startupLog, argc, argv, settings);
+ std::tie(ret, mustExit) = doYamlConfig(argc, argv, settings);
if (ret != 0 || mustExit) {
return ret;
}
void startLuaConfigDelayedThreads(const vector<RPZTrackerParams>& rpzs, uint64_t generation)
{
- cerr << "slcdt: " << rpzs.size() << endl;
for (const auto& rpzPrimary : rpzs) {
if (rpzPrimary.primaries.empty()) {
continue;
}
try {
- cerr << "STARTING" << endl;
// The get calls all return a value object here. That is essential, since we want copies so that RPZIXFRTracker gets values
// with the proper lifetime.
std::thread theThread(RPZIXFRTracker, rpzPrimary, generation);
if (lci.dsAnchors.size() > rootDSs.size()) {
warnIfDNSSECDisabled("Warning: adding Trust Anchor for DNSSEC, but dnssec is set to 'off'!");
}
+ for (auto x : lci.dsAnchors) {
+ cerr << "TA: " << x.first << endl;
+ for (auto ds : x.second) {
+ cerr << " DS: " << ds.getZoneRepresentation() << endl;
+ }
+ }
if (!lci.negAnchors.empty()) {
warnIfDNSSECDisabled("Warning: adding Negative Trust Anchor for DNSSEC, but dnssec is set to 'off'!");
}
// Initial proxy mapping
g_proxyMapping = proxyMapping.empty() ? nullptr : std::make_unique<ProxyMapping>(proxyMapping);
}
- SLOG(g_log << Logger::Notice << "Reloaded Lua configuration file '" << ::arg()["lua-config-file"] << "', requested via control channel" << endl,
- g_slog->withName("config")->info(Logr::Info, "Reloaded"));
+ if (broadcast) {
+ SLOG(g_log << Logger::Notice << "Reloaded Lua configuration file '" << ::arg()["lua-config-file"] << "', requested via control channel" << endl,
+ g_slog->withName("config")->info(Logr::Info, "Reloaded"));
+ }
return {0, "Reloaded Lua configuration file '" + ::arg()["lua-config-file"] + "'\n"};
}
catch (std::exception& e) {
pdns::rust::settings::rec::Recursorsettings settings;
auto yamlstat = pdns::settings::rec::tryReadYAML(configname + ".yml", false, dummy1, dummy2, settings, g_slog);
if (yamlstat != pdns::settings::rec::YamlSettingsStatus::OK) {
- // HANDLE
+ return {1, "Not reloading dynamic part of YAML configuration\n"};
}
auto generation = g_luaconfs.getLocal()->generation;
lci.generation = generation + 1;
std::atomic<bool> stop{false};
};
-static void preloadRPZFIle(RPZTrackerParams& params, const DNSName& zoneName, std::shared_ptr<DNSFilterEngine::Zone>& oldZone, uint32_t& refresh, const string& polName, RPZWaiter& rpzwaiter, Logr::log_t logger)
+static void preloadRPZFIle(RPZTrackerParams& params, const DNSName& zoneName, std::shared_ptr<DNSFilterEngine::Zone>& oldZone, uint32_t& refresh, const string& polName, uint64_t configGeneration, RPZWaiter& rpzwaiter, Logr::log_t logger)
{
while (!params.soaRecordContent) {
/* if we received an empty sr, the zone was not really preloaded */
[&stop = rpzwaiter.stop] { return stop.load(); });
}
rpzwaiter.stop = false;
+ auto luaconfsLocal = g_luaconfs.getLocal();
+
+ if (luaconfsLocal->generation != configGeneration) {
+ /* the configuration has been reloaded, meaning that a new thread
+ has been started to handle that zone and we are now obsolete.
+ */
+ return;
+ }
}
}
auto lock = condVars.lock();
lock->emplace(zoneName, waiter);
}
- preloadRPZFIle(params, zoneName, oldZone, refresh, polName, waiter, logger);
+ preloadRPZFIle(params, zoneName, oldZone, refresh, polName, configGeneration, waiter, logger);
bool skipRefreshDelay = isPreloaded;
{
dnssec.trustanchorfile = luaConfig.trustAnchorFileInfo.fname;
dnssec.trustanchorfile_interval = luaConfig.trustAnchorFileInfo.interval;
+ dnssec.trustanchors.clear();
for (const auto& anchors : luaConfig.dsAnchors) {
::rust::Vec<::rust::String> dsRecords;
for (const auto& dsRecord : anchors.second) {
void fromRustToLuaConfig(const pdns::rust::settings::rec::Dnssec& dnssec, LuaConfigItems& luaConfig)
{
for (const auto& trustAnchor : dnssec.trustanchors) {
- // Do not inser the default root DS records
- if (trustAnchor.name == ".") {
- for (const auto& dsRecord : trustAnchor.dsrecords) {
- const std::string dsString = std::string(dsRecord);
- if (std::find(rootDSs.begin(), rootDSs.end(), dsString) == rootDSs.end()) {
- auto dsRecContent = std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(dsString));
- luaConfig.dsAnchors[DNSName(std::string(trustAnchor.name))].emplace(*dsRecContent);
- }
- }
- }
- else {
- for (const auto& dsRecord : trustAnchor.dsrecords) {
- auto dsRecContent = std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(std::string(dsRecord)));
- luaConfig.dsAnchors[DNSName(std::string(trustAnchor.name))].emplace(*dsRecContent);
- }
+ auto name = DNSName(std::string(trustAnchor.name));
+ luaConfig.dsAnchors.erase(name);
+ }
+ for (const auto& trustAnchor : dnssec.trustanchors) {
+ auto name = DNSName(std::string(trustAnchor.name));
+ for (const auto& dsRecord : trustAnchor.dsrecords) {
+ auto dsRecContent = std::dynamic_pointer_cast<DSRecordContent>(DSRecordContent::make(std::string(dsRecord)));
+ luaConfig.dsAnchors[name].emplace(*dsRecContent);
}
}
for (const auto& nta : dnssec.negative_trustanchors) {
for (const auto& rpz : rpzs) {
RPZTrackerParams params;
for (const auto& address : rpz.addresses) {
- params.primaries.emplace_back(std::string(address));
+ ComboAddress combo = ComboAddress(std::string(address), 53);
+ params.primaries.emplace_back(combo.toStringWithPort());
}
params.name = std::string(rpz.name);
params.polName = std::string(rpz.policyName);
bool pdns::settings::rec::luaItemSet(const pdns::rust::settings::rec::Recursorsettings& settings)
{
bool alldefault = true;
- alldefault = alldefault && settings.dnssec.trustanchors.empty();
+ for (const auto& trustanchor : settings.dnssec.trustanchors) {
+ if (trustanchor.name == ".") {
+ if (trustanchor.dsrecords.size() != rootDSs.size()) {
+ alldefault = false;
+ break;
+ for (const auto& dsRecord : trustanchor.dsrecords) {
+ if (std::find(rootDSs.begin(), rootDSs.end(), std::string(dsRecord)) == rootDSs.end()) {
+ alldefault = false;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ alldefault = false;
+ break;
+ }
+ }
alldefault = alldefault && settings.dnssec.negative_trustanchors.empty();
alldefault = alldefault && settings.dnssec.trustanchorfile.empty();
alldefault = alldefault && settings.dnssec.trustanchorfile_interval == 24;
startupLog->info(Logr::Notice, "YAML config found and processed", "configname", Logging::Loggable(yamlconfigname)));
pdns::settings::rec::processAPIDir(arg()["include-dir"], settings, startupLog);
luaSettingsInYAML = pdns::settings::rec::luaItemSet(settings);
- cerr << "XXXX " << luaSettingsInYAML << ' ' << settings.recursor.lua_config_file.empty() << endl;
if (luaSettingsInYAML && !settings.recursor.lua_config_file.empty()) {
const std::string err = "YAML settings include values originally in Lua but also sets `recursor.lua_config_file`. This is unsupported";
SLOG(g_log << Logger::Error << err << endl,
return value == ''
return False
-def gen_rust_vec_default_functions(name, typeName):
+def gen_rust_vec_default_functions(name, typeName, defvalue):
"""Generate Rust code for the default handling of a vector for typeName"""
ret = f'// DEFAULT HANDLING for {name}\n'
ret += f'fn default_value_{name}() -> Vec<recsettings::{typeName}> {{\n'
- ret += ' Vec::new()\n'
+ ret += f' let deserialized: Vec<recsettings::{typeName}> = serde_yaml::from_str({quote(defvalue)}).unwrap();\n'
+ ret += f' deserialized\n'
ret += '}\n'
ret += f'fn default_value_equal_{name}(value: &Vec<recsettings::{typeName}>)'
ret += '-> bool {\n'
def gen_rust_default_functions(entry, name, rust_type):
"""Generate Rust code for the default handling"""
+ defvalue = entry['default']
if entry['type'] in listOfStringTypes:
return gen_rust_stringvec_default_functions(entry, name)
if entry['type'] in listOfStructuredTypes:
baseName = list_to_base_type(entry['type'])
- return gen_rust_vec_default_functions(name, baseName)
+ return gen_rust_vec_default_functions(name, baseName, defvalue)
ret = f'// DEFAULT HANDLING for {name}\n'
ret += f'fn default_value_{name}() -> {rust_type} {{\n'
- defvalue = entry['default']
rustdef = f'env!("{defvalue}")' if isEnvVar(defvalue) else quote(defvalue)
ret += f" String::from({rustdef})\n"
ret += '}\n'
fn parse_yaml_string_to_forward_zones(str: &str) -> Result<Vec<ForwardZone>>;
// Allow notify for sequence
fn parse_yaml_string_to_allow_notify_for(str: &str) -> Result<Vec<String>>;
- // REST APIU zones
+ // REST API zones
fn parse_yaml_string_to_api_zones(str: &str) -> Result<ApiZones>;
- // Prdoduce a YAML formatted sting given a data structure known to Serde
+ // Prdoduce a YAML formatted string given a data structure known to Serde
fn to_yaml_string(self: &Recursorsettings) -> Result<String>;
// When doing a conversion of old-style to YAML style we use a vector of OldStyle structs
fn map_to_yaml_string(map: &Vec<OldStyle>) -> Result<String>;
'name' : 'trustanchors',
'section' : 'dnssec',
'type' : LType.ListTrustAnchors,
- 'default' : '',
+ 'default' : '[{name: ., dsrecords: [\'20326 8 2 e06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d\']}]',
'help' : 'XXX',
'doc' : ''',
XXX
BOOST_AUTO_TEST_CASE(test_yaml_defaults_ta)
{
// Two entries: one all default, one all overrides
- const std::string yaml = R"EOT(dnssec:
+ const std::string yaml1 = R"EOT(dnssec:
+
+)EOT";
+ auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml1);
+ settings.validate();
+ BOOST_CHECK_EQUAL(settings.dnssec.trustanchors.size(), 1U);
+ BOOST_CHECK_EQUAL(std::string(settings.dnssec.trustanchors[0].name), ".");
+ BOOST_CHECK_EQUAL(std::string(settings.dnssec.trustanchors[0].dsrecords[0]), "20326 8 2 e06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d");
+ BOOST_CHECK_EQUAL(settings.dnssec.negative_trustanchors.size(), 0U);
+ BOOST_CHECK_EQUAL(std::string(settings.dnssec.trustanchorfile), "");
+ BOOST_CHECK_EQUAL(settings.dnssec.trustanchorfile_interval, 24U);
+
+ const std::string yaml2 = R"EOT(dnssec:
trustanchors:
- name: a
- dsrecords: [b]
+ dsrecords: [b]
+ - name: a
+ dsrecords: [c]
negative_trustanchors:
- name: c
reason: d
trustanchorfile: e
trustanchorfile_interval: 99
)EOT";
- auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml);
+ settings = pdns::rust::settings::rec::parse_yaml_string(yaml2);
settings.validate();
+ BOOST_CHECK_EQUAL(settings.dnssec.trustanchors.size(), 2U);
BOOST_CHECK_EQUAL(std::string(settings.dnssec.trustanchors[0].name), "a");
BOOST_CHECK_EQUAL(std::string(settings.dnssec.trustanchors[0].dsrecords[0]), "b");
+ BOOST_CHECK_EQUAL(std::string(settings.dnssec.trustanchors[1].dsrecords[0]), "c");
BOOST_CHECK_EQUAL(std::string(settings.dnssec.negative_trustanchors[0].name), "c");
BOOST_CHECK_EQUAL(std::string(settings.dnssec.negative_trustanchors[0].reason), "d");
BOOST_CHECK_EQUAL(std::string(settings.dnssec.trustanchorfile), "e");
BOOST_CHECK_EQUAL(settings.dnssec.trustanchorfile_interval, 99U);
}
+BOOST_AUTO_TEST_CASE(test_yaml_ta_merge)
+{
+ // If the YAML sets a root zone DS, the default one(s) are thrown away
+ const std::string yaml1 = R"EOT(dnssec:
+ trustanchors:
+ - name: .
+ dsrecords: ['19718 13 2 8ACBB0CD28F41250A80A491389424D341522D946B0DA0C0291F2D3D7 71D7805A']
+ - name: a
+ dsrecords: ['37331 13 2 2F0BEC2D6F79DFBD1D08FD21A3AF92D0E39A4B9EF1E3F4111FFF2824 90DA453B']
+)EOT";
+
+ auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml1);
+ settings.validate();
+ LuaConfigItems lua1;
+ ProxyMapping proxyMapping;
+ pdns::settings::rec::fromBridgeStructToLuaConfig(settings, lua1, proxyMapping);
+ BOOST_CHECK_EQUAL(lua1.dsAnchors.size(), 2U);
+ BOOST_CHECK_EQUAL(lua1.dsAnchors[DNSName(".")].size(), 1U);
+ BOOST_CHECK_EQUAL(lua1.dsAnchors[DNSName(".")].begin()->getZoneRepresentation(), "19718 13 2 8acbb0cd28f41250a80a491389424d341522d946b0da0c0291f2d3d771d7805a");
+ BOOST_CHECK_EQUAL(lua1.dsAnchors[DNSName("a")].size(), 1U);
+
+ // Not adding a root DS should leave the default intact
+ const std::string yaml2 = R"EOT(dnssec:
+ trustanchors:
+ - name: a
+ dsrecords: ['19718 13 2 8ACBB0CD28F41250A80A491389424D341522D946B0DA0C0291F2D3D7 71D7805A']
+ - name: a
+ dsrecords: ['37331 13 2 2F0BEC2D6F79DFBD1D08FD21A3AF92D0E39A4B9EF1E3F4111FFF2824 90DA453B']
+)EOT";
+
+ settings = pdns::rust::settings::rec::parse_yaml_string(yaml2);
+ settings.validate();
+ LuaConfigItems lua2;
+ pdns::settings::rec::fromBridgeStructToLuaConfig(settings, lua2, proxyMapping);
+ BOOST_CHECK_EQUAL(lua2.dsAnchors.size(), 2U);
+ BOOST_CHECK_EQUAL(lua2.dsAnchors[DNSName(".")].size(), 1U);
+ BOOST_CHECK_EQUAL(lua2.dsAnchors[DNSName("a")].size(), 2U);
+}
+
BOOST_AUTO_TEST_CASE(test_yaml_defaults_protobuf)
{
// Two entries: one all default, one all overrides
// Create YAML, given a Lua config
auto newsettings = pdns::rust::settings::rec::parse_yaml_string("");
- // GlobalStateHolder<LuaConfigItems> gsluaConfig;
- // gsluaConfig.setState(luaConfig);
- // LuaConfigItems local; // = gsluaConfig.getCopy();
try {
pdns::settings::rec::fromLuaConfigToBridgeStruct(luaConfig, proxyMapping, newsettings);
}
// They should be the same
auto newyaml = newsettings.to_yaml_string();
+#if 0
std::ofstream aaa("a");
std::ofstream bbb("b");
aaa << "===" << endl
bbb << "===" << endl
<< newyaml << endl
<< "===" << endl;
+#endif
BOOST_CHECK_EQUAL(yaml, std::string(newyaml));
}
if e.errno != errno.ENOENT:
raise
os.mkdir(confdir, 0o755)
+ os.mkdir(confdir + '/include', 0o755)
@classmethod
def generateAuthZone(cls, confdir, zonename, zonecontent):
conf.write("hint-file=%s\n" % roothintspath)
@classmethod
- def generateRecursorYamlConfig(cls, confdir):
+ def generateRecursorYamlConfig(cls, confdir, luaConfig=True):
params = tuple([getattr(cls, param) for param in cls._config_params])
if len(params):
print(params)
with open(recursorconf, 'w') as conf:
conf.write("# Autogenerated by recursortests.py\n")
- conf.write(cls._config_template_yaml_default % confdir)
- recursorconf = os.path.join(confdir, 'recursor01.yml')
+ conf.write(cls._config_template_yaml_default % os.path.join(confdir, 'include'))
+ recursorconf = os.path.join(confdir, 'include', 'recursor01.yml')
with open(recursorconf, 'w') as conf:
conf.write(cls._config_template % params)
conf.write("\n")
- recursorconf = os.path.join(confdir, 'recursor02.yml')
+ recursorconf = os.path.join(confdir, 'include', 'recursor02.yml')
with open(recursorconf, 'w') as conf:
conf.write("recursor:\n")
conf.write(" socket_dir: %s\n" % confdir)
- if cls._lua_config_file or cls._root_DS:
+ if luaConfig and (cls._lua_config_file or cls._root_DS):
luaconfpath = os.path.join(confdir, 'conffile.lua')
with open(luaconfpath, 'w') as luaconf:
if cls._root_DS:
#!/bin/sh
+if pgrep pdns_server; then
+ echo 'There are (stray?) pdns_servers running that might interfere with these tests!'
+fi
+
export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python
if [ ! -d .venv ]; then
import dns
from recursortests import RecursorTest
-class testSimple(RecursorTest):
+class testNTA(RecursorTest):
_confdir = 'NTA'
_config_template = """dnssec=validate"""
--- /dev/null
+import dns
+from recursortests import RecursorTest
+
+class testNoDSYAML(RecursorTest):
+ _confdir = 'NoDSYAML'
+
+ _config_template = """
+dnssec:
+ validation: validate
+ trustanchors: [{name: .}]
+"""
+ @classmethod
+ def generateRecursorConfig(cls, confdir):
+ super(testNoDSYAML, cls).generateRecursorYamlConfig(confdir, False)
+
+ def testNoDSInsecure(self):
+ """#4430 When the root DS is removed, the result must be Insecure"""
+
+ msg = dns.message.make_query("ted.bogus.example.", dns.rdatatype.A)
+ msg.flags = dns.flags.from_text('AD RD')
+ msg.use_edns(edns=0, ednsflags=dns.flags.edns_from_text('DO'))
+
+ res = self.sendUDPQuery(msg)
+
+ self.assertMessageHasFlags(res, ['QR', 'RA', 'RD'], ['DO'])
+ self.assertRcodeEqual(res, dns.rcode.NOERROR)
import os
from recursortests import RecursorTest
-class testSimple(RecursorTest):
- _confdir = 'Simple'
+class testSimpleYAML(RecursorTest):
+ _confdir = 'SimpleYAML'
_config_template = """
recursor:
@ 3600 IN SOA {soa}
@ 3600 IN A 192.0.2.88
""".format(soa=cls._SOA))
- super(testSimple, cls).generateRecursorYamlConfig(confdir)
+ super(testSimpleYAML, cls).generateRecursorYamlConfig(confdir)
def testSOAs(self):
for zone in ['.', 'example.', 'secure.example.']: