]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Add --config support and validation of a few fields
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Fri, 16 Feb 2024 14:28:34 +0000 (15:28 +0100)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Thu, 25 Apr 2024 09:31:40 +0000 (11:31 +0200)
14 files changed:
pdns/recursordist/Makefile.am
pdns/recursordist/rec-main.cc
pdns/recursordist/rec_channel_rec.cc
pdns/recursordist/settings/Makefile.am
pdns/recursordist/settings/cxxsupport.cc
pdns/recursordist/settings/generate.py
pdns/recursordist/settings/rust-bridge-in.rs
pdns/recursordist/settings/rust/Cargo.lock
pdns/recursordist/settings/rust/Cargo.toml
pdns/recursordist/settings/rust/build.rs
pdns/recursordist/settings/rust/src/bridge.hh [new file with mode: 0644]
pdns/recursordist/settings/rust/src/bridge.rs
pdns/recursordist/settings/table.py
pdns/recursordist/test-settings.cc

index fbec4c82b1e8755a7403fc16cbdc32b8027009ec..63b821d4eb253e1004805726cbbbf3e9f6fd1d7f 100644 (file)
@@ -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
index bf2255404456960d99414c5bb38d99b8bd161887..06c0ec3cdc9a81e594320cfd08445f9f170ed07f 100644 (file)
@@ -2901,7 +2901,7 @@ static void recursorThread()
   }
 }
 
-static pair<int, bool> doYamlConfig(Logr::log_t startupLog, int argc, char* argv[]) // NOLINT: Posix API
+static pair<int, bool> 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<int, bool> 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<int, bool> 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;
       }
index dd45c5e5f873456c0d55663493aee8aa13b24435..75b5bc862ccdcf2c46bf436607197f21379e7e61 100644 (file)
@@ -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<ProxyMapping> 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>(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<ProxyMapping> 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>(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>(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 <typename T>
index f7eca1cbe86c6316c1615280a50caf174fc40b7f..e9293a4ebaf2752fb04bc2f232b6028fa73cb6cf 100644 (file)
@@ -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
index feaeafa5d6e753afd3b3255e13143a76fe2b591e..66fffff37121e254d073f7b183bbd8110e8273d4 100644 (file)
@@ -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());
+}
index 8515ec2a020e96fc81f315654c02cff72b3b71b8..84db15513feb928733fee58af0dec6f55c643a27 100644 (file)
@@ -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')
 
index 5807bd6de705b5bac047e4d559f0002c1c289138..232838544330ab217faa10ef28e09d43bfd80d1f 100644 (file)
@@ -343,3 +343,8 @@ extern "Rust" {
     fn validate_negativetrustanchors(field: &str, vec: &Vec<NegativeTrustAnchor>) -> Result<()>;
     fn api_delete_zone(file: &str, zone: &str) -> Result<()>;
 }
+
+unsafe extern "C++" {
+    include!("bridge.hh");
+    fn qTypeStringToCode(name: &str) -> u16;
+}
index 6c098259647e280e1407615560b9f023c21739f8..48d4f5457123c534761b5e4e4754a087e38880d2 100644 (file)
@@ -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",
index c14e85d6e03fc9d6273887c8eb4fb9437f105c6c..3dd157c50d1e22694c2c796e821df22420ce9ee3 100644 (file)
@@ -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"
index 3bf2cbca45d211a9b834b91bbdf3d23c940abeac..256f9981bfb1207a70c38141a57449145bedc07e 100644 (file)
@@ -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 (file)
index 0000000..02f8beb
--- /dev/null
@@ -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);
+}
index fd8d04107ea8f728a82077d1cdac5742f362b2b5..cbb9ef04ee6f20b8584d19771099c59072dccaaf 100644 (file)
@@ -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<T, F>(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<AuthZone>) -> 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(())
+}
index 63d59ca00fc09913d0cf8e89daeffe0e2ae5ce69..96ddd434411a844f5229846ac1f6713b519fc490 100644 (file)
@@ -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'],
     },
index 6fbdde7ec8efaa90a9b70ebe77a80b6b5f5b7e57..f469e6f03c89fc6d734731f11dd2c365c71531d0 100644 (file)
@@ -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.