From: Otto Moerbeek Date: Fri, 16 Feb 2024 14:28:34 +0000 (+0100) Subject: Add --config support and validation of a few fields X-Git-Tag: rec-5.1.0-alpha1~9^2~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4792eae8e0563a175fa503a2ea7342fc2d421bf6;p=thirdparty%2Fpdns.git Add --config support and validation of a few fields --- diff --git a/pdns/recursordist/Makefile.am b/pdns/recursordist/Makefile.am index fbec4c82b1..63b821d4eb 100644 --- a/pdns/recursordist/Makefile.am +++ b/pdns/recursordist/Makefile.am @@ -14,6 +14,7 @@ AM_CPPFLAGS += \ -I$(top_srcdir)/ext/protozero/include \ -I$(top_srcdir)/settings \ -I$(top_builddir)/settings \ + -I$(top_srcdir)/settings/rust/src \ $(YAHTTP_CFLAGS) \ $(LIBCRYPTO_INCLUDES) \ -DBOOST_CONTAINER_USE_STD_EXCEPTIONS diff --git a/pdns/recursordist/rec-main.cc b/pdns/recursordist/rec-main.cc index bf22554044..06c0ec3cdc 100644 --- a/pdns/recursordist/rec-main.cc +++ b/pdns/recursordist/rec-main.cc @@ -2901,7 +2901,7 @@ static void recursorThread() } } -static pair doYamlConfig(Logr::log_t startupLog, int argc, char* argv[]) // NOLINT: Posix API +static pair doYamlConfig(Logr::log_t startupLog, int argc, char* argv[], const pdns::rust::settings::rec::Recursorsettings& settings) // NOLINT: Posix API { if (!::arg().mustDo("config")) { return {0, false}; @@ -2909,18 +2909,14 @@ static pair doYamlConfig(Logr::log_t startupLog, int argc, char* argv 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); + //pdns::rust::settings::rec::Recursorsettings settings; + //pdns::settings::rec::oldStyleSettingsToBridgeStruct(settings); ProxyMapping proxyMapping; LuaConfigItems lci; - try { - loadRecursorLuaConfig(::arg()["lua-config-file"], proxyMapping, lci); - } - catch (PDNSException& e) { - SLOG(g_log << Logger::Error << "Cannot load Lua configuration: " << e.reason << endl, - startupLog->error(Logr::Error, e.reason, "Cannot load Lua configuration")); - } - pdns::settings::rec::fromLuaConfigToBridgeStruct(lci, proxyMapping, settings); + 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; } @@ -2928,6 +2924,9 @@ static pair doYamlConfig(Logr::log_t startupLog, int argc, char* argv auto yaml = pdns::settings::rec::defaultsToYaml(); cout << yaml << endl; } + else if (config == "check") { + // Kinda redundant, if we came here we already read and checked the config....x + } return {0, true}; } @@ -3152,7 +3151,7 @@ int main(int argc, char** argv) if (g_yamlSettings) { bool mustExit = false; - std::tie(ret, mustExit) = doYamlConfig(startupLog, argc, argv); + std::tie(ret, mustExit) = doYamlConfig(startupLog, argc, argv, settings); if (ret != 0 || mustExit) { return ret; } diff --git a/pdns/recursordist/rec_channel_rec.cc b/pdns/recursordist/rec_channel_rec.cc index dd45c5e5f8..75b5bc862c 100644 --- a/pdns/recursordist/rec_channel_rec.cc +++ b/pdns/recursordist/rec_channel_rec.cc @@ -2133,49 +2133,13 @@ static RecursorControlChannel::Answer help() RecursorControlChannel::Answer luaconfig(bool broadcast) { - ProxyMapping proxyMapping; - LuaConfigItems lci; - lci.d_slog = g_slog; - extern std::unique_ptr g_proxyMapping; - if (!g_luaSettingsInYAML) { - try { - loadRecursorLuaConfig(::arg()["lua-config-file"], proxyMapping, lci); - activateLuaConfig(lci); - lci = g_luaconfs.getCopy(); - if (broadcast) { - startLuaConfigDelayedThreads(lci.rpzs, lci.generation); - broadcastFunction([=] { return pleaseSupplantProxyMapping(proxyMapping); }); - } - else { - // Initial proxy mapping - g_proxyMapping = proxyMapping.empty() ? nullptr : std::make_unique(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")); - return {0, "Reloaded Lua configuration file '" + ::arg()["lua-config-file"] + "'\n"}; - } - catch (std::exception& e) { - return {1, "Unable to load Lua script from '" + ::arg()["lua-config-file"] + "': " + e.what() + "\n"}; - } - catch (const PDNSException& e) { - return {1, "Unable to load Lua script from '" + ::arg()["lua-config-file"] + "': " + e.reason + "\n"}; - } - } + ProxyMapping proxyMapping; + LuaConfigItems lci; + lci.d_slog = g_slog; + extern std::unique_ptr g_proxyMapping; + if (!g_luaSettingsInYAML) { try { - string configname = ::arg()["config-dir"] + "/recursor"; - if (!::arg()["config-name"].empty()) { - configname = ::arg()["config-dir"] + "/recursor-" + ::arg()["config-name"]; - } - bool dummy1{}; - bool dummy2{}; - 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 - } - auto generation = g_luaconfs.getLocal()->generation; - lci.generation = generation + 1; - pdns::settings::rec::fromBridgeStructToLuaConfig(settings, lci, proxyMapping); + loadRecursorLuaConfig(::arg()["lua-config-file"], proxyMapping, lci); activateLuaConfig(lci); lci = g_luaconfs.getCopy(); if (broadcast) { @@ -2186,15 +2150,51 @@ RecursorControlChannel::Answer luaconfig(bool broadcast) // Initial proxy mapping g_proxyMapping = proxyMapping.empty() ? nullptr : std::make_unique(proxyMapping); } - - return {0, "Reloaded dynamic part of YAML configuration\n"}; + 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) { - return {1, "Unable to reload dynamic YAML changes: " + std::string(e.what()) + "\n"}; + return {1, "Unable to load Lua script from '" + ::arg()["lua-config-file"] + "': " + e.what() + "\n"}; } catch (const PDNSException& e) { - return {1, "Unable to reload dynamic YAML changes: " + e.reason + "\n"}; + return {1, "Unable to load Lua script from '" + ::arg()["lua-config-file"] + "': " + e.reason + "\n"}; } + } + try { + string configname = ::arg()["config-dir"] + "/recursor"; + if (!::arg()["config-name"].empty()) { + configname = ::arg()["config-dir"] + "/recursor-" + ::arg()["config-name"]; + } + bool dummy1{}; + bool dummy2{}; + 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 + } + auto generation = g_luaconfs.getLocal()->generation; + lci.generation = generation + 1; + pdns::settings::rec::fromBridgeStructToLuaConfig(settings, lci, proxyMapping); + activateLuaConfig(lci); + lci = g_luaconfs.getCopy(); + if (broadcast) { + startLuaConfigDelayedThreads(lci.rpzs, lci.generation); + broadcastFunction([=] { return pleaseSupplantProxyMapping(proxyMapping); }); + } + else { + // Initial proxy mapping + g_proxyMapping = proxyMapping.empty() ? nullptr : std::make_unique(proxyMapping); + } + + return {0, "Reloaded dynamic part of YAML configuration\n"}; + } + catch (std::exception& e) { + return {1, "Unable to reload dynamic YAML changes: " + std::string(e.what()) + "\n"}; + } + catch (const PDNSException& e) { + return {1, "Unable to reload dynamic YAML changes: " + e.reason + "\n"}; + } } template diff --git a/pdns/recursordist/settings/Makefile.am b/pdns/recursordist/settings/Makefile.am index f7eca1cbe8..e9293a4eba 100644 --- a/pdns/recursordist/settings/Makefile.am +++ b/pdns/recursordist/settings/Makefile.am @@ -10,6 +10,7 @@ EXTRA_DIST = \ rust-bridge-in.rs \ rust-preamble-in.rs \ table.py \ + rust/src/bridge.hh \ rust/src/lib.rs all: cxxsettings-generated.cc rust/src/lib.rs diff --git a/pdns/recursordist/settings/cxxsupport.cc b/pdns/recursordist/settings/cxxsupport.cc index feaeafa5d6..66fffff371 100644 --- a/pdns/recursordist/settings/cxxsupport.cc +++ b/pdns/recursordist/settings/cxxsupport.cc @@ -1359,3 +1359,9 @@ pdns::settings::rec::YamlSettingsStatus pdns::settings::rec::tryReadYAML(const s } return yamlstatus; } + +uint16_t pdns::rust::settings::rec::qTypeStringToCode(::rust::Str str) +{ + std::string tmp(str.data(), str.length()); + return QType::chartocode(tmp.c_str()); +} diff --git a/pdns/recursordist/settings/generate.py b/pdns/recursordist/settings/generate.py index 8515ec2a02..84db15513f 100644 --- a/pdns/recursordist/settings/generate.py +++ b/pdns/recursordist/settings/generate.py @@ -525,7 +525,7 @@ def write_validator(file, section, entries): continue file.write(f' let fieldname = "{section.lower()}.{name}".to_string();\n') file.write(f' validate_vec(&fieldname, &self.{name}, {validator})?;\n') - file.write(' Ok(())\n') + file.write(f' validate_{section.lower()}(self)\n') file.write(' }\n') file.write('}\n\n') diff --git a/pdns/recursordist/settings/rust-bridge-in.rs b/pdns/recursordist/settings/rust-bridge-in.rs index 5807bd6de7..2328385443 100644 --- a/pdns/recursordist/settings/rust-bridge-in.rs +++ b/pdns/recursordist/settings/rust-bridge-in.rs @@ -343,3 +343,8 @@ extern "Rust" { fn validate_negativetrustanchors(field: &str, vec: &Vec) -> Result<()>; fn api_delete_zone(file: &str, zone: &str) -> Result<()>; } + +unsafe extern "C++" { + include!("bridge.hh"); + fn qTypeStringToCode(name: &str) -> u16; +} diff --git a/pdns/recursordist/settings/rust/Cargo.lock b/pdns/recursordist/settings/rust/Cargo.lock index 6c09825964..48d4f54571 100644 --- a/pdns/recursordist/settings/rust/Cargo.lock +++ b/pdns/recursordist/settings/rust/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "cc" version = "1.0.83" @@ -193,6 +199,7 @@ dependencies = [ name = "settings" version = "0.1.0" dependencies = [ + "base64", "cxx", "cxx-build", "hostname-validator", diff --git a/pdns/recursordist/settings/rust/Cargo.toml b/pdns/recursordist/settings/rust/Cargo.toml index c14e85d6e0..3dd157c50d 100644 --- a/pdns/recursordist/settings/rust/Cargo.toml +++ b/pdns/recursordist/settings/rust/Cargo.toml @@ -14,6 +14,7 @@ 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. +base64 = "0.21" [build-dependencies] cxx-build = "1.0" diff --git a/pdns/recursordist/settings/rust/build.rs b/pdns/recursordist/settings/rust/build.rs index 3bf2cbca45..256f9981bf 100644 --- a/pdns/recursordist/settings/rust/build.rs +++ b/pdns/recursordist/settings/rust/build.rs @@ -2,5 +2,6 @@ fn main() { cxx_build::bridge("src/lib.rs") // .file("src/source.cc") at the moment no C++ code callable from Rust .flag_if_supported("-std=c++17") + .flag("-Isrc") .compile("settings"); } diff --git a/pdns/recursordist/settings/rust/src/bridge.hh b/pdns/recursordist/settings/rust/src/bridge.hh new file mode 100644 index 0000000000..02f8beb733 --- /dev/null +++ b/pdns/recursordist/settings/rust/src/bridge.hh @@ -0,0 +1,29 @@ +/* + * 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 "rust/cxx.h" + +namespace pdns::rust::settings::rec +{ +uint16_t qTypeStringToCode(::rust::Str str); +} diff --git a/pdns/recursordist/settings/rust/src/bridge.rs b/pdns/recursordist/settings/rust/src/bridge.rs index fd8d04107e..cbb9ef04ee 100644 --- a/pdns/recursordist/settings/rust/src/bridge.rs +++ b/pdns/recursordist/settings/rust/src/bridge.rs @@ -20,6 +20,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +use base64::prelude::*; use once_cell::sync::Lazy; use std::fs::File; use std::io::{BufReader, BufWriter, ErrorKind, Write}; @@ -28,7 +29,7 @@ use std::str::FromStr; use std::sync::Mutex; use crate::helpers::OVERRIDE_TAG; -use crate::recsettings::*; +use crate::recsettings::{self, *}; use crate::{Merge, ValidationError}; impl Default for ForwardZone { @@ -105,6 +106,15 @@ pub fn validate_socket_address_or_name(field: &str, val: &String) -> Result<(), Ok(()) } +fn validate_qtype(field: &str, val: &String) -> Result<(), ValidationError> { + let code = qTypeStringToCode(val); + if code == 0 { + let msg = format!("{}: value `{}' is not a qtype", 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); @@ -152,6 +162,44 @@ pub fn validate_subnet(field: &str, val: &String) -> Result<(), ValidationError> Ok(()) } +fn validate_address_family(addrfield: &str, localfield: &str, vec: &[String], local_address: &String) -> Result<(), ValidationError> { + if vec.len() == 0 { + let msg = format!("{}: cannot be empty", addrfield); + return Err(ValidationError { msg }); + } + validate_vec(addrfield, vec, validate_socket_address)?; + if local_address.is_empty() { + return Ok(()); + } + let local = IpAddr::from_str(local_address); + if local.is_err() { + let msg = format!("{}: value `{}' is not an IP", localfield, local_address); + return Err(ValidationError { msg }); + } + let local = local.unwrap(); + for addr_str in vec { + let mut wrong = false; + let sa = SocketAddr::from_str(addr_str); + if sa.is_err() { + let ip = IpAddr::from_str(addr_str).unwrap(); + if local.is_ipv4() != ip.is_ipv4() || local.is_ipv6() != ip.is_ipv6() { + wrong = true; + } + } + else { + let sa = sa.unwrap(); + if local.is_ipv4() != sa.is_ipv4() || local.is_ipv6() != sa.is_ipv6() { + wrong = true; + } + } + if wrong { + let msg = format!("{}: value `{}' and `{}' differ in address family", localfield, local_address, addr_str); + return Err(ValidationError { msg }); + } + } + Ok(()) +} + pub fn validate_vec(field: &str, vec: &[T], func: F) -> Result<(), ValidationError> where F: Fn(&str, &T) -> Result<(), ValidationError>, @@ -300,7 +348,17 @@ impl NegativeTrustAnchor { } impl ProtobufServer { - pub fn validate(&self, _field: &str) -> Result<(), ValidationError> { + pub fn validate(&self, field: &str) -> Result<(), ValidationError> { + validate_vec( + &(field.to_owned() + ".servers"), + &self.servers, + validate_socket_address, + )?; + validate_vec( + &(field.to_owned() + ".exportTypes"), + &self.exportTypes, + validate_qtype, + )?; Ok(()) } @@ -397,7 +455,18 @@ impl SortList { } impl RPZ { - pub fn validate(&self, _field: &str) -> Result<(), ValidationError> { + pub fn validate(&self, field: &str) -> Result<(), ValidationError> { + if self.extendedErrorCode > u16::MAX as u32 && self.extendedErrorCode != u32::MAX { + let msg = format!( + "{}: value `{}' is no a valid extendedErrorCode", + field, self.extendedErrorCode + ); + return Err(ValidationError { msg }); + } + self.tsig.validate(&(field.to_owned() + ".tsig"))?; + if !self.addresses.is_empty() { + validate_address_family(&(field.to_owned() + ".addresses"), &(field.to_owned() + ".localAddress"), &self.addresses, &self.localAddress)?; + } Ok(()) } @@ -450,7 +519,33 @@ impl RPZ { } impl ZoneToCache { - pub fn validate(&self, _field: &str) -> Result<(), ValidationError> { + pub fn validate(&self, field: &str) -> Result<(), ValidationError> { + match self.method.as_str() { + "axfr" | "url" | "file" => {} + _ => { + let msg = format!( + "{}: must be one of axfr, url, file", + &(field.to_string() + ".method") + ); + return Err(ValidationError { msg }); + } + } + if self.sources.is_empty() { + let msg = format!( + "{}: at least one source required", + &(field.to_string() + ".sources") + ); + return Err(ValidationError { msg }); + } + if self.method == "axfr" { + validate_vec( + &(field.to_string() + ".sources"), + &self.sources, + validate_socket_address, + )?; + validate_address_family(&(field.to_string() + ".sources"), &(field.to_string() + ".localAddress"), &self.sources, &self.localAddress)?; + } + self.tsig.validate(&(field.to_owned() + ".tsig"))?; Ok(()) } @@ -521,6 +616,26 @@ impl ProxyMapping { } } +impl TSIGTriplet { + pub fn validate(&self, field: &str) -> Result<(), ValidationError> { + let namelen = self.name.len(); + let algolen = self.algo.len(); + let secretlen = self.secret.len(); + if namelen == 0 && algolen == 0 && secretlen == 0 { + return Ok(()); + } + if namelen == 0 || algolen == 0 || secretlen == 0 { + let msg = format!("{}: a field value is missing", field); + return Err(ValidationError { msg }); + } + if BASE64_STANDARD.decode(&self.secret).is_err() { + let msg = format!("{}.secret: `{}' is not a Base64 string", field, self.secret); + return Err(ValidationError { msg }); + } + Ok(()) + } +} + #[allow(clippy::ptr_arg)] //# Avoids creating a rust::Slice object on the C++ side. pub fn validate_auth_zones(field: &str, vec: &Vec) -> Result<(), ValidationError> { validate_vec(field, vec, |field, element| element.validate(field)) @@ -907,3 +1022,83 @@ pub fn def_additional_mode() -> String { pub fn default_value_equals_additional_mode(value: &String) -> bool { &def_additional_mode() == value } + +pub fn validate_dnssec(dnssec: &recsettings::Dnssec) -> Result<(), ValidationError> { + let val = dnssec.validation.as_str(); + match val { + "off" | "process-no-validate" | "process" | "log-fail" | "validate" => {} + _ => { + let msg = format!("dnssec.validation: value `{}' is unknown", val); + return Err(ValidationError { msg }); + } + }; + Ok(()) +} + +pub fn validate_incoming(_incoming: &recsettings::Incoming) -> Result<(), ValidationError> { + Ok(()) +} + +pub fn validate_recursor(_recursor: &recsettings::Recursor) -> Result<(), ValidationError> { + Ok(()) +} + +pub fn validate_webservice(_webservice: &recsettings::Webservice) -> Result<(), ValidationError> { + Ok(()) +} + +pub fn validate_carbon(_carbon: &recsettings::Carbon) -> Result<(), ValidationError> { + Ok(()) +} + +pub fn validate_outgoing(_outgoing: &recsettings::Outgoing) -> Result<(), ValidationError> { + Ok(()) +} + +pub fn validate_packetcache( + _packetcache: &recsettings::Packetcache, +) -> Result<(), ValidationError> { + Ok(()) +} + +pub fn validate_logging(logging: &recsettings::Logging) -> Result<(), ValidationError> { + if logging.protobuf_servers.len() > 1 { + return Err(ValidationError { + msg: String::from("number of protobuf_servers must be <= 1"), + }); + } + if logging.outgoing_protobuf_servers.len() > 1 { + return Err(ValidationError { + msg: String::from("number of outgoing_protobuf_servers must be <= 1"), + }); + } + if logging.dnstap_framestream_servers.len() > 1 { + return Err(ValidationError { + msg: String::from("number of dnstap_framestream_servers must be <= 1"), + }); + } + if logging.dnstap_nod_framestream_servers.len() > 1 { + return Err(ValidationError { + msg: String::from("number of dnstap_nod_framestream_servers must be <= 1"), + }); + } + Ok(()) +} + +pub fn validate_ecs(_ecs: &recsettings::Ecs) -> Result<(), ValidationError> { + Ok(()) +} + +pub fn validate_nod(_nod: &recsettings::Nod) -> Result<(), ValidationError> { + Ok(()) +} + +pub fn validate_recordcache( + _recordcache: &recsettings::Recordcache, +) -> Result<(), ValidationError> { + Ok(()) +} + +pub fn validate_snmp(_snmp: &recsettings::Snmp) -> Result<(), ValidationError> { + Ok(()) +} diff --git a/pdns/recursordist/settings/table.py b/pdns/recursordist/settings/table.py index 63d59ca00f..96ddd43441 100644 --- a/pdns/recursordist/settings/table.py +++ b/pdns/recursordist/settings/table.py @@ -1941,7 +1941,7 @@ Maximum estimated NSEC3 cost for a given query to consider aggressive use of the 'default' : '8', 'help' : 'Maximum number of DS records to consider per zone', 'doc' : ''' -Maximum number of DS records to consider when validating records inside a zone.. +Maximum number of DS records to consider when validating records inside a zone. ''', 'versionadded': ['5.0.2', '4.9.3', '4.8.6'], }, diff --git a/pdns/recursordist/test-settings.cc b/pdns/recursordist/test-settings.cc index 6fbdde7ec8..f469e6f03c 100644 --- a/pdns/recursordist/test-settings.cc +++ b/pdns/recursordist/test-settings.cc @@ -449,21 +449,12 @@ BOOST_AUTO_TEST_CASE(test_yaml_defaults_ta) BOOST_AUTO_TEST_CASE(test_yaml_defaults_protobuf) { // Two entries: one all default, one all overrides - const std::string yaml = R"EOT(logging: + const std::string yaml1 = R"EOT(logging: protobuf_servers: - - servers: [a] - - servers: [b] - timeout: 100 - maxQueuedEntries: 101 - reconnectWaitTime: 102 - taggedOnly: true - asyncConnect: true - logQueries: false - logResponses: false - logMappedFrom: true + - servers: [1.2.3.4] )EOT"; - auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml); + auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml1); settings.validate(); BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[0].timeout, 2U); BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[0].maxQueuedEntries, 100U); @@ -477,23 +468,9 @@ BOOST_AUTO_TEST_CASE(test_yaml_defaults_protobuf) // BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[0].exportTypes, testv); BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[0].logMappedFrom, false); - BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[1].timeout, 100U); - BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[1].maxQueuedEntries, 101U); - BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[1].reconnectWaitTime, 102U); - BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[1].taggedOnly, true); - BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[1].asyncConnect, true); - BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[1].logQueries, false); - BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[1].logResponses, false); - BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[1].logMappedFrom, true); -} - -BOOST_AUTO_TEST_CASE(test_yaml_defaults_outgoing_protobuf) -{ - // Two entries: one all default, one all overrides - const std::string yaml = R"EOT(logging: - outgoing_protobuf_servers: - - servers: [a] - - servers: [b] + const std::string yaml2 = R"EOT(logging: + protobuf_servers: + - servers: [6.7.8.9] timeout: 100 maxQueuedEntries: 101 reconnectWaitTime: 102 @@ -503,8 +480,27 @@ BOOST_AUTO_TEST_CASE(test_yaml_defaults_outgoing_protobuf) logResponses: false logMappedFrom: true )EOT"; + settings = pdns::rust::settings::rec::parse_yaml_string(yaml2); + settings.validate(); + BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[0].timeout, 100U); + BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[0].maxQueuedEntries, 101U); + BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[0].reconnectWaitTime, 102U); + BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[0].taggedOnly, true); + BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[0].asyncConnect, true); + BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[0].logQueries, false); + BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[0].logResponses, false); + BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[0].logMappedFrom, true); +} - auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml); +BOOST_AUTO_TEST_CASE(test_yaml_defaults_outgoing_protobuf) +{ + // Two entries: one all default, one all overrides + const std::string yaml1 = R"EOT(logging: + outgoing_protobuf_servers: + - servers: ['::1'] +)EOT"; + + auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml1); settings.validate(); BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[0].timeout, 2U); BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[0].maxQueuedEntries, 100U); @@ -518,34 +514,39 @@ BOOST_AUTO_TEST_CASE(test_yaml_defaults_outgoing_protobuf) // BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[0].exportTypes, testv); BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[0].logMappedFrom, false); - BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[1].timeout, 100U); - BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[1].maxQueuedEntries, 101U); - BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[1].reconnectWaitTime, 102U); - BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[1].taggedOnly, true); - BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[1].asyncConnect, true); - BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[1].logQueries, false); - BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[1].logResponses, false); - BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[1].logMappedFrom, true); + const std::string yaml2 = R"EOT(logging: + outgoing_protobuf_servers: + - servers: [123.123.123.123] + timeout: 100 + maxQueuedEntries: 101 + reconnectWaitTime: 102 + taggedOnly: true + asyncConnect: true + logQueries: false + logResponses: false + logMappedFrom: true +)EOT"; + settings = pdns::rust::settings::rec::parse_yaml_string(yaml2); + settings.validate(); + BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[0].timeout, 100U); + BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[0].maxQueuedEntries, 101U); + BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[0].reconnectWaitTime, 102U); + BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[0].taggedOnly, true); + BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[0].asyncConnect, true); + BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[0].logQueries, false); + BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[0].logResponses, false); + BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[0].logMappedFrom, true); } BOOST_AUTO_TEST_CASE(test_yaml_defaults_dnstap) { // Two entries: one all default, one all overrides - const std::string yaml = R"EOT(logging: + const std::string yaml1 = R"EOT(logging: dnstap_framestream_servers: - - servers: [a] - - servers: [b] - logQueries: false - logResponses: false - bufferHint: 1 - flushTimeout: 2 - inputQueueSize: 3 - outputQueueSize: 4 - queueNotifyThreshold: 5 - reopenInterval: 6 + - servers: [3.4.5.6] )EOT"; - auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml); + auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml1); settings.validate(); BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[0].logQueries, true); BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[0].logResponses, true); @@ -556,25 +557,11 @@ BOOST_AUTO_TEST_CASE(test_yaml_defaults_dnstap) BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[0].queueNotifyThreshold, 0U); BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[0].reopenInterval, 0U); - BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[1].logQueries, false); - BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[1].logResponses, false); - BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[1].bufferHint, 1U); - BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[1].flushTimeout, 2U); - BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[1].inputQueueSize, 3U); - BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[1].outputQueueSize, 4U); - BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[1].queueNotifyThreshold, 5U); - BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[1].reopenInterval, 6U); -} - -BOOST_AUTO_TEST_CASE(test_yaml_defaults_dnstapnod) -{ - // Two entries: one all default, one all overrides - const std::string yaml = R"EOT(logging: - dnstap_nod_framestream_servers: - - servers: [a] - - servers: [b] - logNODs: false - logUDRs: true + const std::string yaml2 = R"EOT(logging: + dnstap_framestream_servers: + - servers: ['[::2]:99'] + logQueries: false + logResponses: false bufferHint: 1 flushTimeout: 2 inputQueueSize: 3 @@ -582,8 +569,27 @@ BOOST_AUTO_TEST_CASE(test_yaml_defaults_dnstapnod) queueNotifyThreshold: 5 reopenInterval: 6 )EOT"; + settings = pdns::rust::settings::rec::parse_yaml_string(yaml2); + settings.validate(); + BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[0].logQueries, false); + BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[0].logResponses, false); + BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[0].bufferHint, 1U); + BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[0].flushTimeout, 2U); + BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[0].inputQueueSize, 3U); + BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[0].outputQueueSize, 4U); + BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[0].queueNotifyThreshold, 5U); + BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[0].reopenInterval, 6U); +} + +BOOST_AUTO_TEST_CASE(test_yaml_defaults_dnstapnod) +{ + // Two entries: one all default, one all overrides + const std::string yaml1 = R"EOT(logging: + dnstap_nod_framestream_servers: + - servers: [1.2.3.4:100] +)EOT"; - auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml); + auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml1); settings.validate(); BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[0].logNODs, true); BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[0].logUDRs, false); @@ -594,14 +600,28 @@ BOOST_AUTO_TEST_CASE(test_yaml_defaults_dnstapnod) BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[0].queueNotifyThreshold, 0U); BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[0].reopenInterval, 0U); - BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[1].logNODs, false); - BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[1].logUDRs, true); - BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[1].bufferHint, 1U); - BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[1].flushTimeout, 2U); - BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[1].inputQueueSize, 3U); - BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[1].outputQueueSize, 4U); - BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[1].queueNotifyThreshold, 5U); - BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[1].reopenInterval, 6U); + const std::string yaml2 = R"EOT(logging: + dnstap_nod_framestream_servers: + - servers: [1::1] + logNODs: false + logUDRs: true + bufferHint: 1 + flushTimeout: 2 + inputQueueSize: 3 + outputQueueSize: 4 + queueNotifyThreshold: 5 + reopenInterval: 6 +)EOT"; + settings = pdns::rust::settings::rec::parse_yaml_string(yaml2); + settings.validate(); + BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[0].logNODs, false); + BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[0].logUDRs, true); + BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[0].bufferHint, 1U); + BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[0].flushTimeout, 2U); + BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[0].inputQueueSize, 3U); + BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[0].outputQueueSize, 4U); + BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[0].queueNotifyThreshold, 5U); + BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[0].reopenInterval, 6U); } BOOST_AUTO_TEST_CASE(test_yaml_defaults_rpz) @@ -630,10 +650,10 @@ BOOST_AUTO_TEST_CASE(test_yaml_defaults_rpz) tsig: name: f algo: g - secret: h + secret: ego= refresh: 103 maxReceivedMBytes: 104 - localAddress: i + localAddress: '1.2.3.4' axfrTimeout: 105 dumpFile: j seedFile: k @@ -687,10 +707,10 @@ BOOST_AUTO_TEST_CASE(test_yaml_defaults_rpz) BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[2].tsig.name), "f"); BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[2].tsig.algo), "g"); - BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[2].tsig.secret), "h"); + BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[2].tsig.secret), "ego="); BOOST_CHECK_EQUAL(settings.recursor.rpzs[2].refresh, 103U); BOOST_CHECK_EQUAL(settings.recursor.rpzs[2].maxReceivedMBytes, 104U); - BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[2].localAddress), "i"); + BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[2].localAddress), "1.2.3.4"); BOOST_CHECK_EQUAL(settings.recursor.rpzs[2].axfrTimeout, 105U); BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[2].dumpFile), "j"); BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[2].seedFile), "k"); @@ -722,16 +742,16 @@ BOOST_AUTO_TEST_CASE(test_yaml_ztc) sources: [1.2.3.4] - zone: zone2 method: axfr - sources: [1.2.3.4] + sources: ['[ffee::1]:99'] timeout: 1 tsig: name: a algo: b - secret: c + secret: a2FkanNrYWRqc2sK refreshPeriod: 2 retryOnErrorPeriod: 3 maxReceivedMBytes: 4 - localAddress: d + localAddress: ::1 zonemd: ignore dnssec: require )EOT"; @@ -754,15 +774,15 @@ BOOST_AUTO_TEST_CASE(test_yaml_ztc) BOOST_CHECK_EQUAL(std::string(settings.recordcache.zonetocaches[1].zone), "zone2"); BOOST_CHECK_EQUAL(std::string(settings.recordcache.zonetocaches[1].method), "axfr"); - BOOST_CHECK_EQUAL(std::string(settings.recordcache.zonetocaches[1].sources[0]), "1.2.3.4"); + BOOST_CHECK_EQUAL(std::string(settings.recordcache.zonetocaches[1].sources[0]), "[ffee::1]:99"); BOOST_CHECK_EQUAL(settings.recordcache.zonetocaches[1].timeout, 1U); BOOST_CHECK_EQUAL(std::string(settings.recordcache.zonetocaches[1].tsig.name), "a"); BOOST_CHECK_EQUAL(std::string(settings.recordcache.zonetocaches[1].tsig.algo), "b"); - BOOST_CHECK_EQUAL(std::string(settings.recordcache.zonetocaches[1].tsig.secret), "c"); + BOOST_CHECK_EQUAL(std::string(settings.recordcache.zonetocaches[1].tsig.secret), "a2FkanNrYWRqc2sK"); BOOST_CHECK_EQUAL(settings.recordcache.zonetocaches[1].refreshPeriod, 2U); BOOST_CHECK_EQUAL(settings.recordcache.zonetocaches[1].retryOnErrorPeriod, 3U); BOOST_CHECK_EQUAL(settings.recordcache.zonetocaches[1].maxReceivedMBytes, 4U); - BOOST_CHECK_EQUAL(settings.recordcache.zonetocaches[1].localAddress, "d"); + BOOST_CHECK_EQUAL(settings.recordcache.zonetocaches[1].localAddress, "::1"); BOOST_CHECK_EQUAL(settings.recordcache.zonetocaches[1].zonemd, "ignore"); BOOST_CHECK_EQUAL(settings.recordcache.zonetocaches[1].dnssec, "require"); } @@ -942,7 +962,7 @@ recordcache: - zone: anotherzone method: axfr sources: - - 4.5.6.7 + - '[::1]:999' timeout: 1 tsig: name: a.