]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
YAML defs for all Lua config constructs, plus converting old-style to YAML
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Tue, 16 Jan 2024 11:35:50 +0000 (12:35 +0100)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Thu, 25 Apr 2024 09:31:40 +0000 (11:31 +0200)
12 files changed:
.github/actions/spell-check/expect.txt
pdns/recursordist/rec-lua-conf.cc
pdns/recursordist/rec-lua-conf.hh
pdns/recursordist/rec-main.cc
pdns/recursordist/settings/cxxsettings.hh
pdns/recursordist/settings/cxxsupport.cc
pdns/recursordist/settings/generate.py
pdns/recursordist/settings/rust-bridge-in.rs
pdns/recursordist/settings/rust/src/bridge.rs
pdns/recursordist/settings/rust/src/helpers.rs
pdns/recursordist/settings/table.py
pdns/recursordist/test-settings.cc

index 788f3ccb5724d569cdb6849579e9fe29edc17bcf..cd77ab8d2094ea254a966dfe7bcaa5828db68b53 100644 (file)
@@ -1399,6 +1399,7 @@ Toshifumi
 Travaille
 tribool
 trustanchor
+trustanchorfile
 trusteer
 trx
 trxid
@@ -1567,6 +1568,7 @@ zonemd
 zonemetadata
 zonename
 zoneparser
+zonetocaches
 zonetransfer
 Zonneveld
 zsk
index bd080360f5a317011f2843088a49811fe764c82c..ff204c3cab8da8db35303c498a14a136584d3f7e 100644 (file)
@@ -380,6 +380,7 @@ static void rpzPrimary(LuaConfigItems& lci, luaConfigDelayedThreads& delayedThre
         zone->clear();
       }
     }
+    lci.rpzRaw.emplace_back(RPZRaw{primaries, zoneName, options});
   }
   catch (const std::exception& e) {
     SLOG(g_log << Logger::Error << "Problem configuring 'rpzPrimary': " << e.what() << endl,
@@ -472,6 +473,7 @@ void loadRecursorLuaConfig(const std::string& fname, luaConfigDelayedThreads& de
       lci.dfe.addZone(std::move(zone));
       SLOG(g_log << Logger::Warning << "Done loading RPZ from file '" << filename << "'" << endl,
            log->info(Logr::Info,  "Done loading RPZ from file"));
+      lci.rpzRaw.emplace_back(RPZRaw{{}, filename, options});
     }
     catch (const std::exception& e) {
       SLOG(g_log << Logger::Error << "Unable to load RPZ zone from '" << filename << "': " << e.what() << endl,
index e278acd108a709a5c12e481f23659a3389e3bf42..abed5c4196d26a43e61a38e7ed20553449f58c83 100644 (file)
@@ -21,6 +21,7 @@
  */
 #pragma once
 #include <set>
+#include <boost/variant.hpp>
 
 #include "sholder.hh"
 #include "sortlist.hh"
@@ -98,12 +99,22 @@ struct ProxyByTableValue
 
 using ProxyMapping = NetmaskTree<ProxyByTableValue, Netmask>;
 
+using rpzOptions_t = std::unordered_map<std::string, boost::variant<bool, uint32_t, std::string, std::vector<std::pair<int, std::string>>>>;
+
+struct RPZRaw
+{
+  std::vector<ComboAddress> addresses;
+  std::string name;
+  boost::optional<rpzOptions_t> options;
+};
+
 class LuaConfigItems
 {
 public:
   LuaConfigItems();
   SortList sortlist;
   DNSFilterEngine dfe;
+  vector<RPZRaw> rpzRaw;
   TrustAnchorFileInfo trustAnchorFileInfo; // Used to update the Trust Anchors from file periodically
   map<DNSName, dsset_t> dsAnchors;
   map<DNSName, std::string> negAnchors;
index b441f3acc9e635d272710d1eac9f563ae7eb7816..2bfc587aa81490b89d25458d80d1bca6bef0b5ec 100644 (file)
@@ -2905,8 +2905,8 @@ static pair<int, bool> doYamlConfig(Logr::log_t startupLog, int argc, char* argv
     pdns::rust::settings::rec::Recursorsettings settings;
     pdns::settings::rec::oldStyleSettingsToBridgeStruct(settings);
     luaConfigDelayedThreads delayedLuaThreads;
+    ProxyMapping proxyMapping;
     try {
-      ProxyMapping proxyMapping;
       loadRecursorLuaConfig(::arg()["lua-config-file"], delayedLuaThreads, proxyMapping);
     }
     catch (PDNSException& e) {
@@ -2914,21 +2914,7 @@ static pair<int, bool> doYamlConfig(Logr::log_t startupLog, int argc, char* argv
            startupLog->error(Logr::Error, e.reason, "Cannot load Lua configuration"));
     }
     auto luaConfig = g_luaconfs.getLocal();
-    settings.dnssec.trustanchorfile = luaConfig->trustAnchorFileInfo.fname;
-    settings.dnssec.trustanchorfile_interval = luaConfig->trustAnchorFileInfo.interval;
-    for (const auto& anchors : luaConfig->dsAnchors) {
-      rust::Vec<rust::String> dsRecords;
-      for (const auto& dsRecord : anchors.second) {
-        dsRecords.emplace_back(dsRecord.getZoneRepresentation());
-      }
-      pdns::rust::settings::rec::TrustAnchor trustAnchor{anchors.first.toString(), dsRecords};
-      settings.dnssec.trustanchors.emplace_back(trustAnchor);
-    }
-    for (const auto& anchors : luaConfig->negAnchors) {
-      pdns::rust::settings::rec::NegativeTrustAnchor negtrustAnchor{anchors.first.toString(), anchors.second};
-      settings.dnssec.negative_trustanchors.emplace_back(negtrustAnchor);
-    }
-
+    pdns::settings::rec::fromLuaConfigToBridgeStruct(luaConfig, proxyMapping, settings);
     auto yaml = settings.to_yaml_string();
     cout << yaml << endl;
   }
index ad21578da1ee64a3ef5846764c8551f60e494a36..8b4993bf378fe68c331d25c3cc0dd75ec2d35135 100644 (file)
@@ -24,7 +24,9 @@
 #include <string>
 #include "rust/cxx.h"
 #include "rust/lib.rs.h"
+#include "sholder.hh"
 #include "logging.hh"
+#include "rec-lua-conf.hh"
 
 namespace pdns::settings::rec
 {
@@ -50,4 +52,5 @@ void readYamlAllowFromFile(const std::string& filename, ::rust::Vec<::rust::Stri
 void readYamlAllowNotifyForFile(const std::string& filename, ::rust::Vec<::rust::String>& vec, Logr::log_t log);
 void setArgsForZoneRelatedSettings(pdns::rust::settings::rec::Recursorsettings& settings);
 void setArgsForACLRelatedSettings(pdns::rust::settings::rec::Recursorsettings& settings);
+void fromLuaConfigToBridgeStruct(LocalStateHolder<LuaConfigItems>& luaConfig, const ProxyMapping& proxyMapping, pdns::rust::settings::rec::Recursorsettings& settings);
 }
index 9c690a0bff30462b57af08e435241988d5051aa6..348cddd128a03571de88660b08347904810e50d1 100644 (file)
@@ -33,6 +33,7 @@
 #include "cxxsettings-private.hh"
 #include "logger.hh"
 #include "logging.hh"
+#include "rec-lua-conf.hh"
 
 ::rust::Vec<::rust::String> pdns::settings::rec::getStrings(const std::string& name)
 {
@@ -518,7 +519,7 @@ static void processLine(const std::string& arg, FieldMap& map, bool mainFile)
   ::rust::String section;
   ::rust::String fieldname;
   ::rust::String type_name;
-  pdns::rust::settings::rec::Value rustvalue = {false, 0, 0.0, "", {}, {}, {}, {}, {}};
+  pdns::rust::settings::rec::Value rustvalue = {false, 0, 0.0, "", {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}};
   if (pdns::settings::rec::oldKVToBridgeStruct(var, val, section, fieldname, type_name, rustvalue)) {
     auto overriding = !mainFile && !incremental && !simpleRustType(type_name);
     auto [existing, inserted] = map.emplace(std::pair{std::pair{section, fieldname}, pdns::rust::settings::rec::OldStyle{section, fieldname, var, std::move(type_name), rustvalue, overriding}});
@@ -618,13 +619,34 @@ std::string pdns::settings::rec::defaultsToYaml()
     ::rust::String section;
     ::rust::String fieldname;
     ::rust::String type_name;
-    pdns::rust::settings::rec::Value rustvalue{false, 0, 0.0, "", {}, {}, {}, {}, {}};
+    pdns::rust::settings::rec::Value rustvalue{false, 0, 0.0, "", {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}};
     string name = var;
     string val = arg().getDefault(var);
     if (pdns::settings::rec::oldKVToBridgeStruct(name, val, section, fieldname, type_name, rustvalue)) {
       map.emplace(std::pair{std::pair{section, fieldname}, pdns::rust::settings::rec::OldStyle{section, fieldname, name, std::move(type_name), std::move(rustvalue), false}});
     }
   }
+
+  // Should be generated
+  auto def = [&](const string& section, const string& name, const string& type) {
+    pdns::rust::settings::rec::Value rustvalue{.vec_trustanchor_val = {}, .vec_negativetrustanchor_val = {}, .string_val = "", .u64_val = 24, .vec_protobufserver_val = {}};
+    map.emplace(std::pair{std::pair{section, name}, pdns::rust::settings::rec::OldStyle{section, name, name, type, rustvalue, false}});
+  };
+  def("dnssec", "trustanchors", "Vec<TrustAnchor>");
+  def("dnssec", "negative_trustanchors", "Vec<NegativeTrustAnchor>");
+  def("dnssec", "trustanchorfile", "String");
+  def("dnssec", "trustanchorfile_interval", "u64");
+  def("logging", "protobuf_servers", "Vec<ProtobufServer>");
+  def("logging", "outgoing_protobuf_servers", "Vec<ProtobufServer>");
+  def("logging", "dnstap_framestream_servers", "Vec<DNSTapFrameStreamServer>");
+  def("logging", "dnstap_nod_framestream_servers", "Vec<DNSTapNODFrameStreamServer>");
+  def("recursor", "rpzs", "Vec<RPZ>");
+  def("recursor", "sortlists", "Vec<SortList>");
+  def("recordcache", "zonetocaches", "Vec<ZoneToCache>");
+  def("recursor", "allowed_additional_qtypes", "Vec<AllowedAdditionalQType>");
+  def("incoming", "proxymappings", "Vec<ProxyMapping>");
+  // End of should be generated XXX
+
   // Convert the map to a vector, as CXX does not have any dictionary like support.
   ::rust::Vec<pdns::rust::settings::rec::OldStyle> vec;
   vec.reserve(map.size());
@@ -682,3 +704,246 @@ std::string pdns::settings::rec::defaultsToYaml()
   }
   return res;
 }
+
+namespace
+{
+void fromLuaToProtobufServerStruct(const ProtobufExportConfig& pbConfig, pdns::rust::settings::rec::ProtobufServer& pbServer)
+{
+  for (const auto& server : pbConfig.servers) {
+    pbServer.servers.emplace_back(server.toStringWithPort());
+  }
+  pbServer.timeout = pbConfig.timeout;
+  pbServer.maxQueuedEntries = pbConfig.maxQueuedEntries;
+  pbServer.reconnectWaitTime = pbConfig.reconnectWaitTime;
+  pbServer.taggedOnly = pbConfig.taggedOnly;
+  pbServer.asyncConnect = pbConfig.asyncConnect;
+  pbServer.logQueries = pbConfig.logQueries;
+  pbServer.logResponses = pbConfig.logResponses;
+  for (const auto num : pbConfig.exportTypes) {
+    pbServer.exportTypes.emplace_back(QType(num).toString());
+  }
+  pbServer.logMappedFrom = pbConfig.logMappedFrom;
+}
+
+void fromLuaConfigToTAInfo(LocalStateHolder<LuaConfigItems>& luaConfig, pdns::rust::settings::rec::Dnssec& dnssec)
+{
+  dnssec.trustanchorfile = luaConfig->trustAnchorFileInfo.fname;
+  dnssec.trustanchorfile_interval = luaConfig->trustAnchorFileInfo.interval;
+  for (const auto& anchors : luaConfig->dsAnchors) {
+    ::rust::Vec<::rust::String> dsRecords;
+    for (const auto& dsRecord : anchors.second) {
+      dsRecords.emplace_back(dsRecord.getZoneRepresentation());
+    }
+    pdns::rust::settings::rec::TrustAnchor trustAnchor{anchors.first.toString(), dsRecords};
+    dnssec.trustanchors.emplace_back(trustAnchor);
+  }
+  for (const auto& anchors : luaConfig->negAnchors) {
+    pdns::rust::settings::rec::NegativeTrustAnchor negtrustAnchor{anchors.first.toString(), anchors.second};
+    dnssec.negative_trustanchors.emplace_back(negtrustAnchor);
+  }
+}
+
+template <typename T>
+void setIfAvailable(const rpzOptions_t& table, T& var, const std::string& name)
+{
+  if (table.count(name) != 0) {
+    var = boost::get<T>(table.at(name));
+  }
+}
+
+void setIfAvailable(const rpzOptions_t& table, rust::string& var, const std::string& name)
+{
+  if (table.count(name) != 0) {
+    var = boost::get<std::string>(table.at(name));
+  }
+}
+
+void setIfAvailable(const rpzOptions_t& table, pdns::rust::settings::rec::TSIGTriplet& var, const std::string& name)
+{
+  if (table.count(name) != 0) {
+    var.name = boost::get<std::string>(table.at("tsigname"));
+    var.algo = boost::get<std::string>(table.at("tsigalgo"));
+    var.secret = boost::get<std::string>(table.at("tsigsecret"));
+  }
+}
+void fromLuaConfigToRPZ(const vector<RPZRaw>& rpzs, pdns::rust::settings::rec::Recursor& rec)
+{
+  for (const auto& rpz : rpzs) {
+    pdns::rust::settings::rec::RPZ rustrpz{
+      .defpolOverrideLocalData = true,
+      .defttl = std::numeric_limits<uint32_t>::max(),
+      .extendedErrorCode = 0,
+      .includeSOA = false,
+      .ignoreDuplicates = false,
+      .maxTTL = std::numeric_limits<uint32_t>::max(),
+      .overridesGettag = true,
+      .zoneSizeHint = 0,
+      .refresh = 0,
+      .maxReceivedMBytes = 0,
+      .axfrTimeout = 20};
+
+    for (const auto& address : rpz.addresses) {
+      rustrpz.addresses.emplace_back(address.toStringWithPort());
+    }
+    rustrpz.name = rpz.name;
+    if (rpz.options) {
+      setIfAvailable(*rpz.options, rustrpz.defcontent, "defcontent");
+      setIfAvailable(*rpz.options, rustrpz.defpol, "defpol");
+      setIfAvailable(*rpz.options, rustrpz.defpolOverrideLocalData, "defpolOverrideLocalData");
+      setIfAvailable(*rpz.options, rustrpz.defttl, "defttl");
+      setIfAvailable(*rpz.options, rustrpz.extendedErrorCode, "extendedErrorCode");
+      setIfAvailable(*rpz.options, rustrpz.extendedErrorExtra, "extendedErrorExtra");
+      setIfAvailable(*rpz.options, rustrpz.includeSOA, "includeSOA");
+      setIfAvailable(*rpz.options, rustrpz.ignoreDuplicates, "ignoreDuplicates");
+      setIfAvailable(*rpz.options, rustrpz.maxTTL, "maxTTL");
+      setIfAvailable(*rpz.options, rustrpz.policyName, "policyName");
+      if (rpz.options->count("tags") != 0) {
+        const auto& tags = boost::get<vector<std::pair<int, std::string>>>(rpz.options->at("have"));
+        for (const auto& tag : tags) {
+          rustrpz.tags.emplace_back(tag.second);
+        }
+      }
+      setIfAvailable(*rpz.options, rustrpz.overridesGettag, "overridesGettag");
+      setIfAvailable(*rpz.options, rustrpz.zoneSizeHint, "zoneSizeHint");
+      setIfAvailable(*rpz.options, rustrpz.tsig, "tsig");
+      setIfAvailable(*rpz.options, rustrpz.refresh, "refresh");
+      setIfAvailable(*rpz.options, rustrpz.maxReceivedMBytes, "maxReceivedMBytes");
+      setIfAvailable(*rpz.options, rustrpz.localAddress, "localAddress");
+      setIfAvailable(*rpz.options, rustrpz.axfrTimeout, "axfrTimeout");
+      setIfAvailable(*rpz.options, rustrpz.dumpFile, "dumpFile");
+      setIfAvailable(*rpz.options, rustrpz.seedFile, "seedFile");
+    }
+    rec.rpzs.emplace_back(rustrpz);
+  }
+}
+
+string cvt(pdns::ZoneMD::Config cfg)
+{
+  switch (cfg) {
+  case pdns::ZoneMD::Config::Ignore:
+    return "ignore";
+  case pdns::ZoneMD::Config::Validate:
+    return "validate";
+  case pdns::ZoneMD::Config::Require:
+    return "require";
+  }
+}
+
+void fromLuaConfigToZoneToCache(const map<DNSName, RecZoneToCache::Config>& ztcConfigs, pdns::rust::settings::rec::Recordcache& recordcache)
+{
+  for (const auto& [_, iter] : ztcConfigs) {
+    pdns::rust::settings::rec::ZoneToCache ztc;
+    ztc.zone = iter.d_zone;
+    ztc.method = iter.d_method;
+    for (const auto& src : iter.d_sources) {
+      ztc.sources.emplace_back(src);
+    }
+    ztc.timeout = iter.d_timeout;
+    if (!iter.d_tt.name.empty()) {
+      ztc.tsig.name = iter.d_tt.name.toString();
+      ztc.tsig.algo = iter.d_tt.algo.toString();
+      ztc.tsig.secret = iter.d_tt.secret;
+    }
+    ztc.refreshPeriod = iter.d_refreshPeriod;
+    ztc.retryOnErrorPeriod = iter.d_retryOnError;
+    ztc.maxReceivedMBytes = iter.d_maxReceivedBytes;
+    ztc.localAddress = iter.d_local.toStringWithPort();
+    ztc.zonemd = cvt(iter.d_zonemd);
+    ztc.dnssec = cvt(iter.d_dnssec);
+    recordcache.zonetocaches.emplace_back(ztc);
+  }
+}
+string cvt(AdditionalMode mode)
+{
+  switch (mode) {
+  case AdditionalMode::Ignore:
+    return "Ignore";
+  case AdditionalMode::CacheOnly:
+    return "CacheOnly";
+  case AdditionalMode::CacheOnlyRequireAuth:
+    return "CacheOnlyRequireAuth";
+  case AdditionalMode::ResolveImmediately:
+    return "ResolveImmediately";
+  case AdditionalMode::ResolveDeferred:
+    return "ResolveDeferred";
+  }
+}
+
+void fromLuaConfigToAllowAddtionalQTypes(const std::map<QType, std::pair<std::set<QType>, AdditionalMode>>& allowAdditionalQTypes, pdns::rust::settings::rec::Recursor& rec)
+{
+  for (const auto& [qtype, data] : allowAdditionalQTypes) {
+    const auto& [qtypeset, mode] = data;
+    pdns::rust::settings::rec::AllowedAdditionalQType add;
+    add.qtype = qtype.toString();
+    for (const auto& extra : qtypeset) {
+      add.targets.emplace_back(extra.toString());
+    }
+    add.mode = cvt(mode);
+    rec.allowed_additional_qtypes.emplace_back(add);
+  }
+}
+
+void fromLuaConfigToProxyMappings(const ProxyMapping& proxyMapping, pdns::rust::settings::rec::Incoming& incoming)
+{
+  for (const auto& mapping : proxyMapping) {
+    pdns::rust::settings::rec::ProxyMapping pmap;
+    pmap.subnet = mapping.first.toString();
+    pmap.address = mapping.second.address.toString();
+    if (mapping.second.suffixMatchNode) {
+      for (const auto& domain : mapping.second.suffixMatchNode->d_tree.getNodes()) {
+        pmap.domains.emplace_back(domain.toString());
+      }
+    }
+    incoming.proxymappings.emplace_back(pmap);
+  }
+}
+
+void fromLuaConfigToSortList(const SortList& arg, pdns::rust::settings::rec::Recursor& rec)
+{
+  const auto& sortlist = arg.getTree();
+  for (const auto& iter : sortlist) {
+    pdns::rust::settings::rec::SortList rsl;
+    rsl.key = iter.first.toString();
+    const auto& sub = iter.second;
+    // Some extra work to present them ordered in the YAML
+    std::set<int> indexes;
+    std::multimap<int, Netmask> ordered;
+    for (auto& order : sub.d_orders) {
+      indexes.emplace(order.second);
+      ordered.emplace(order.second, order.first);
+    }
+    for (const auto& index : indexes) {
+      const auto& range = ordered.equal_range(index);
+      for (auto subnet = range.first; subnet != range.second; ++subnet) {
+        pdns::rust::settings::rec::SubnetOrder snorder;
+        snorder.order = index;
+        snorder.subnet = subnet->second.toString();
+        rsl.subnets.emplace_back(snorder);
+      }
+    }
+    rec.sortlists.emplace_back(rsl);
+  }
+}
+} // namespace
+
+void pdns::settings::rec::fromLuaConfigToBridgeStruct(LocalStateHolder<LuaConfigItems>& luaConfig, const ProxyMapping& proxyMapping, pdns::rust::settings::rec::Recursorsettings& settings)
+{
+
+  fromLuaConfigToTAInfo(luaConfig, settings.dnssec);
+  if (luaConfig->protobufExportConfig.enabled) {
+    pdns::rust::settings::rec::ProtobufServer pbServer;
+    fromLuaToProtobufServerStruct(luaConfig->protobufExportConfig, pbServer);
+    settings.logging.protobuf_servers.emplace_back(pbServer);
+  }
+  if (luaConfig->outgoingProtobufExportConfig.enabled) {
+    pdns::rust::settings::rec::ProtobufServer pbServer;
+    fromLuaToProtobufServerStruct(luaConfig->outgoingProtobufExportConfig, pbServer);
+    settings.logging.outgoing_protobuf_servers.emplace_back(pbServer);
+  }
+
+  fromLuaConfigToRPZ(luaConfig->rpzRaw, settings.recursor);
+  fromLuaConfigToSortList(luaConfig->sortlist, settings.recursor);
+  fromLuaConfigToZoneToCache(luaConfig->ztcConfigs, settings.recordcache);
+  fromLuaConfigToAllowAddtionalQTypes(luaConfig->allowAdditionalQTypes, settings.recursor);
+  fromLuaConfigToProxyMappings(proxyMapping, settings.incoming);
+}
index b1cbb64b262efc884167589d8405655c8cc4b132..8515ec2a020e96fc81f315654c02cff72b3b71b8 100644 (file)
@@ -94,18 +94,29 @@ class LType(Enum):
     Bool = auto()
     Command = auto()
     Double = auto()
+    ListAllowedAdditionalQTypes = auto()
     ListAuthZones = auto()
+    ListDNSTapFrameStreamServers = auto()
+    ListDNSTapNODFrameStreamServers = auto()
     ListForwardZones = auto()
     ListNegativeTrustAnchors = auto()
+    ListProtobufServers = auto()
+    ListProxyMappings = auto()
+    ListRPZs = auto();
     ListSocketAddresses = auto()
+    ListSortLists = auto()
     ListStrings = auto()
     ListSubnets = auto()
     ListTrustAnchors = auto()
+    ListZoneToCaches = auto()
     String = auto()
     Uint64 = auto()
 
 listOfStringTypes = (LType.ListSocketAddresses,  LType.ListStrings, LType.ListSubnets)
-listOfStructuredTypes = (LType.ListAuthZones, LType.ListForwardZones, LType.ListTrustAnchors, LType.ListNegativeTrustAnchors)
+listOfStructuredTypes = (LType.ListAuthZones, LType.ListForwardZones, LType.ListTrustAnchors, LType.ListNegativeTrustAnchors,
+                         LType.ListProtobufServers, LType.ListDNSTapFrameStreamServers, LType.ListDNSTapNODFrameStreamServers,
+                         LType.ListSortLists, LType.ListRPZs, LType.ListZoneToCaches, LType.ListAllowedAdditionalQTypes,
+                         LType.ListProxyMappings)
 
 def get_olddoc_typename(typ):
     """Given a type from table.py, return the old-style type name"""
index b0c0bd2e6430baf4b5ef5d0ccfede04396bd28ef..f18c0a4aca4c75d22af04346c254bd12a880ee38 100644 (file)
@@ -47,10 +47,211 @@ pub struct NegativeTrustAnchor {
     reason: String,
 }
 
-// A struct holding bot a vector of forward zones and a vector o auth zones, used by REST API code
+// A protobuf logging server
+#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
+#[serde(deny_unknown_fields)]
+pub struct ProtobufServer {
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    servers: Vec<String>,
+    #[serde(default = "crate::U64::<2>::value", skip_serializing_if = "crate::U64::<2>::is_equal")]
+    timeout: u64,
+    #[serde(default = "crate::U64::<100>::value", skip_serializing_if = "crate::U64::<100>::is_equal")]
+    maxQueuedEntries: u64,
+    #[serde(default = "crate::U64::<1>::value", skip_serializing_if = "crate::U64::<1>::is_equal")]
+    reconnectWaitTime: u64,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    taggedOnly: bool,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    asyncConnect: bool,
+    #[serde(default = "crate::Bool::<true>::value", skip_serializing_if = "crate::if_true")]
+    logQueries: bool,
+    #[serde(default = "crate::Bool::<true>::value", skip_serializing_if = "crate::if_true")]
+    logResponses: bool,
+    #[serde(default = "crate::def_pb_export_qtypes", skip_serializing_if = "crate::default_value_equal_pb_export_qtypes")]
+    exportTypes: Vec<String>,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    logMappedFrom: bool,
+}
+
+// A dnstap logging server
+#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
+#[serde(deny_unknown_fields)]
+pub struct DNSTapFrameStreamServer {
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    servers: Vec<String>,
+    #[serde(default = "crate::Bool::<true>::value", skip_serializing_if = "crate::if_true")]
+    logQueries: bool,
+    #[serde(default = "crate::Bool::<true>::value", skip_serializing_if = "crate::if_true")]
+    logResponses: bool,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    bufferHint: u64,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    flushTimeout: u64,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    inputQueueSize: u64,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    outputQueueSize: u64,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    queueNotifyThreshold: u64,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    reopenInterval: u64,
+}
+
+// A dnstap logging NOD server
+#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
+#[serde(deny_unknown_fields)]
+pub struct DNSTapNODFrameStreamServer {
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    servers: Vec<String>,
+    #[serde(default = "crate::Bool::<true>::value", skip_serializing_if = "crate::if_true")]
+    logNODs: bool,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    logUDRs: bool,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    bufferHint: u64,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    flushTimeout: u64,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    inputQueueSize: u64,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    outputQueueSize: u64,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    queueNotifyThreshold: u64,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    reopenInterval: u64,
+}
+
+#[derive(Default, Deserialize, Serialize, Clone, Debug, PartialEq)]
+#[serde(deny_unknown_fields)]
+pub struct TSIGTriplet {
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    name: String,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    algo: String,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    secret: String,
+}
+
+#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
+#[serde(deny_unknown_fields)]
+pub struct RPZ {
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    addresses: Vec<String>,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    name: String,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    defcontent: String,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    defpol: String,
+    #[serde(default = "crate::Bool::<true>::value", skip_serializing_if = "crate::if_true")]
+    defpolOverrideLocalData: bool,
+    #[serde(default = "crate::U32::<{u32::MAX}>::value", skip_serializing_if = "crate::U32::<{u32::MAX}>::is_equal")]
+    defttl: u32,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    extendedErrorCode: u32,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    extendedErrorExtra: String,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    includeSOA: bool,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    ignoreDuplicates: bool,
+    #[serde(default = "crate::U32::<{u32::MAX}>::value", skip_serializing_if = "crate::U32::<{u32::MAX}>::is_equal")]
+    maxTTL: u32,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    policyName: String,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    tags: Vec<String>,
+    #[serde(default = "crate::Bool::<true>::value", skip_serializing_if = "crate::if_true")]
+    overridesGettag: bool,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    zoneSizeHint: u32,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    tsig: TSIGTriplet,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    refresh: u32,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    maxReceivedMBytes: u32,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    localAddress: String,
+    #[serde(default = "crate::U32::<20>::value", skip_serializing_if = "crate::U32::<20>::is_equal")]
+    axfrTimeout: u32,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    dumpFile: String,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    seedFile: String,
+}
+
+#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
+#[serde(deny_unknown_fields)]
+pub struct ZoneToCache {
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    zone: String,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    method: String,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    sources: Vec<String>,
+    #[serde(default = "crate::U64::<20>::value", skip_serializing_if = "crate::U64::<20>::is_equal")]
+    timeout: u64,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    tsig: TSIGTriplet,
+    #[serde(default = "crate::U64::<86400>::value", skip_serializing_if = "crate::U64::<86400>::is_equal")]
+    refreshPeriod: u64,
+    #[serde(default = "crate::U64::<60>::value", skip_serializing_if = "crate::U64::<60>::is_equal")]
+    retryOnErrorPeriod: u64,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    maxReceivedMBytes: u64,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    localAddress: String,
+    #[serde(default = "crate::def_ztc_validate", skip_serializing_if = "crate::def_value_equals_ztc_validate")]
+    zonemd: String,
+    #[serde(default = "crate::def_ztc_validate", skip_serializing_if = "crate::def_value_equals_ztc_validate")]
+    dnssec: String,
+}
+
+#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
+#[serde(deny_unknown_fields)]
+pub struct SubnetOrder {
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    subnet: String,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    order: u32,
+}
+
+#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
+#[serde(deny_unknown_fields)]
+pub struct SortList {
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    key: String,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    subnets: Vec<SubnetOrder>,
+}
+
+#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
+#[serde(deny_unknown_fields)]
+pub struct AllowedAdditionalQType {
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    qtype: String,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    targets: Vec<String>,
+    #[serde(default = "crate::def_additional_mode", skip_serializing_if = "crate::default_value_equals_additional_mode")]
+    mode: String,
+}
+
+#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
+#[serde(deny_unknown_fields)]
+pub struct ProxyMapping {
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    subnet: String,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    address: String,
+    #[serde(default, skip_serializing_if = "crate::is_default")]
+    domains: Vec<String>,
+}
+
+// A struct holding both a vector of forward zones and a vector o auth zones, used by REST API code
 #[derive(Deserialize, Serialize, Debug, PartialEq)]
 #[serde(deny_unknown_fields)]
-struct ApiZones {
+pub struct ApiZones {
     #[serde(default, skip_serializing_if = "crate::is_default")]
     auth_zones: Vec<AuthZone>,
     #[serde(default, skip_serializing_if = "crate::is_default")]
@@ -69,6 +270,14 @@ struct Value {
     vec_authzone_val: Vec<AuthZone>,
     vec_trustanchor_val: Vec<TrustAnchor>,
     vec_negativetrustanchor_val: Vec<NegativeTrustAnchor>,
+    vec_protobufserver_val: Vec<ProtobufServer>,
+    vec_dnstap_framestream_server_val: Vec<DNSTapFrameStreamServer>,
+    vec_dnstap_nod_framestream_server_val: Vec<DNSTapNODFrameStreamServer>,
+    vec_rpz_val: Vec<RPZ>,
+    vec_sortlist_val: Vec<SortList>,
+    vec_zonetocache_val: Vec<ZoneToCache>,
+    vec_allowedadditionalqtype_val: Vec<AllowedAdditionalQType>,
+    vec_proxymapping_val: Vec<ProxyMapping>,
 }
 
 struct OldStyle {
@@ -111,7 +320,7 @@ extern "Rust" {
 
     // Validate the sections inside the main settings struct, sections themselves will valdiate their fields
     fn validate(self: &Recursorsettings) -> Result<()>;
-    // The validate function bewlo are "hand-crafted" as their structs afre mnot generated
+    // The validate function below are "hand-crafted" as their structs are not generated
     fn validate(self: &AuthZone, field: &str) -> Result<()>;
     fn validate(self: &ForwardZone, field: &str) -> Result<()>;
     fn validate(self: &TrustAnchor, field: &str) -> Result<()>;
index 80cd21c98a70860ae5a232a01a3f0284d62f0938..dfb5ed6922464892e46d538b8c31d53f2db9c125 100644 (file)
@@ -59,7 +59,6 @@ impl Default for NegativeTrustAnchor {
     }
 }
 
-
 impl Default for ApiZones {
     fn default() -> Self {
         let deserialized: ApiZones = serde_yaml::from_str("").unwrap();
@@ -186,6 +185,41 @@ pub fn forward_zones_to_yaml_string(vec: &Vec<ForwardZone>) -> Result<String, se
     serde_yaml::to_string(vec)
 }
 
+fn insertb(map: &mut serde_yaml::Mapping, name: &str, val: bool) {
+    map.insert(
+        serde_yaml::Value::String(name.to_owned()),
+        serde_yaml::Value::Bool(val),
+    );
+}
+
+fn insertu(map: &mut serde_yaml::Mapping, name: &str, val: u64) {
+    map.insert(
+        serde_yaml::Value::String(name.to_owned()),
+        serde_yaml::Value::Number(serde_yaml::Number::from(val)),
+    );
+}
+
+fn insertu32(map: &mut serde_yaml::Mapping, name: &str, val: u32) {
+    map.insert(
+        serde_yaml::Value::String(name.to_owned()),
+        serde_yaml::Value::Number(serde_yaml::Number::from(val)),
+    );
+}
+
+fn inserts(map: &mut serde_yaml::Mapping, name: &str, val: &str) {
+    map.insert(
+        serde_yaml::Value::String(name.to_owned()),
+        serde_yaml::Value::String(val.to_owned()),
+    );
+}
+
+fn insertseq(map: &mut serde_yaml::Mapping, name: &str, val: &serde_yaml::Sequence) {
+    map.insert(
+        serde_yaml::Value::String(name.to_owned()),
+        serde_yaml::Value::Sequence(val.to_owned()),
+    );
+}
+
 impl ForwardZone {
     pub fn validate(&self, field: &str) -> Result<(), ValidationError> {
         validate_name(&(field.to_owned() + ".zone"), &self.zone)?;
@@ -207,14 +241,8 @@ impl ForwardZone {
         }
 
         let mut map = serde_yaml::Mapping::new();
-        map.insert(
-            serde_yaml::Value::String("zone".to_owned()),
-            serde_yaml::Value::String(self.zone.to_owned()),
-        );
-        map.insert(
-            serde_yaml::Value::String("recurse".to_owned()),
-            serde_yaml::Value::Bool(self.recurse),
-        );
+        inserts(&mut map, "zone", &self.zone);
+        insertb(&mut map, "recurse", self.recurse);
         map.insert(
             serde_yaml::Value::String("forwarders".to_owned()),
             serde_yaml::Value::Sequence(seq),
@@ -235,14 +263,8 @@ impl AuthZone {
 
     fn to_yaml_map(&self) -> serde_yaml::Value {
         let mut map = serde_yaml::Mapping::new();
-        map.insert(
-            serde_yaml::Value::String("zone".to_owned()),
-            serde_yaml::Value::String(self.zone.to_owned()),
-        );
-        map.insert(
-            serde_yaml::Value::String("file".to_owned()),
-            serde_yaml::Value::String(self.file.to_owned()),
-        );
+        inserts(&mut map, "zone", &self.zone);
+        inserts(&mut map, "file", &self.file);
         serde_yaml::Value::Mapping(map)
     }
 }
@@ -258,14 +280,8 @@ impl TrustAnchor {
             seq.push(serde_yaml::Value::String(entry.to_owned()));
         }
         let mut map = serde_yaml::Mapping::new();
-        map.insert(
-            serde_yaml::Value::String("name".to_owned()),
-            serde_yaml::Value::String(self.name.to_owned()),
-        );
-        map.insert(
-            serde_yaml::Value::String("dsrecord".to_owned()),
-            serde_yaml::Value::Sequence(seq),
-        );
+        inserts(&mut map, "name", &self.name);
+        insertseq(&mut map, "dsrecords", &seq);
         serde_yaml::Value::Mapping(map)
     }
 }
@@ -277,14 +293,229 @@ impl NegativeTrustAnchor {
 
     fn to_yaml_map(&self) -> serde_yaml::Value {
         let mut map = serde_yaml::Mapping::new();
+        inserts(&mut map, "name", &self.name);
+        inserts(&mut map, "reason", &self.reason);
+        serde_yaml::Value::Mapping(map)
+    }
+}
+
+impl ProtobufServer {
+    pub fn validate(&self, _field: &str) -> Result<(), ValidationError> {
+        Ok(())
+    }
+
+    fn to_yaml_map(&self) -> serde_yaml::Value {
+        let mut seq = serde_yaml::Sequence::new();
+        for entry in &self.servers {
+            seq.push(serde_yaml::Value::String(entry.to_owned()));
+        }
+        let mut map = serde_yaml::Mapping::new();
+        insertseq(&mut map, "servers", &seq);
+        insertu(&mut map, "timeout", self.timeout);
+        insertu(&mut map, "maxQueuedEntries", self.maxQueuedEntries);
+        insertu(&mut map, "reconnectWaitTime", self.reconnectWaitTime);
+        insertb(&mut map, "taggedOnly", self.taggedOnly);
+        insertb(&mut map, "asyncConnect", self.asyncConnect);
+        insertb(&mut map, "logQueries", self.logQueries);
+        insertb(&mut map, "logResponses", self.logResponses);
+        let mut seq2 = serde_yaml::Sequence::new();
+        for entry in &self.exportTypes {
+            seq2.push(serde_yaml::Value::String(entry.to_owned()));
+        }
+        insertseq(&mut map, "exportTypes", &seq2);
+        serde_yaml::Value::Mapping(map)
+    }
+}
+
+impl DNSTapFrameStreamServer {
+    pub fn validate(&self, _field: &str) -> Result<(), ValidationError> {
+        Ok(())
+    }
+
+    fn to_yaml_map(&self) -> serde_yaml::Value {
+        let mut seq = serde_yaml::Sequence::new();
+        for entry in &self.servers {
+            seq.push(serde_yaml::Value::String(entry.to_owned()));
+        }
+        let mut map = serde_yaml::Mapping::new();
+        insertseq(&mut map, "servers", &seq);
+        insertb(&mut map, "logQueries", self.logQueries);
+        insertb(&mut map, "logResponses", self.logResponses);
+        insertu(&mut map, "bufferHint", self.bufferHint);
+        insertu(&mut map, "flushTimeout", self.flushTimeout);
+        insertu(&mut map, "inputQueueSize", self.inputQueueSize);
+        insertu(&mut map, "outputQueueSize", self.outputQueueSize);
+        insertu(&mut map, "queueNotifyThreshold", self.queueNotifyThreshold);
+        insertu(&mut map, "reopenInterval", self.reopenInterval);
+        serde_yaml::Value::Mapping(map)
+    }
+}
+
+impl DNSTapNODFrameStreamServer {
+    pub fn validate(&self, _field: &str) -> Result<(), ValidationError> {
+        Ok(())
+    }
+
+    fn to_yaml_map(&self) -> serde_yaml::Value {
+        let mut seq = serde_yaml::Sequence::new();
+        for entry in &self.servers {
+            seq.push(serde_yaml::Value::String(entry.to_owned()));
+        }
+        let mut map = serde_yaml::Mapping::new();
+        insertseq(&mut map, "servers", &seq);
+        insertb(&mut map, "logNODs", self.logNODs);
+        insertb(&mut map, "logUDRs", self.logUDRs);
+        insertu(&mut map, "bufferHint", self.bufferHint);
+        insertu(&mut map, "flushTimeout", self.flushTimeout);
+        insertu(&mut map, "inputQueueSize", self.inputQueueSize);
+        insertu(&mut map, "outputQueueSize", self.outputQueueSize);
+        insertu(&mut map, "queueNotifyThreshold", self.queueNotifyThreshold);
+        insertu(&mut map, "reopenInterval", self.reopenInterval);
+        serde_yaml::Value::Mapping(map)
+    }
+}
+
+impl SortList {
+    pub fn validate(&self, _field: &str) -> Result<(), ValidationError> {
+        Ok(())
+    }
+
+    fn to_yaml_map(&self) -> serde_yaml::Value {
+        let mut map = serde_yaml::Mapping::new();
+        inserts(&mut map, "key", &self.key);
+        let mut seq = serde_yaml::Sequence::new();
+        for entry in &self.subnets {
+            let mut submap = serde_yaml::Mapping::new();
+            inserts(&mut submap, "subnet", &entry.subnet);
+            insertu32(&mut submap, "order", entry.order);
+            seq.push(serde_yaml::Value::Mapping(submap));
+        }
+        insertseq(&mut map, "subnets", &seq);
+        serde_yaml::Value::Mapping(map)
+    }
+}
+
+impl RPZ {
+    pub fn validate(&self, _field: &str) -> Result<(), ValidationError> {
+        Ok(())
+    }
+
+    fn to_yaml_map(&self) -> serde_yaml::Value {
+        let mut map = serde_yaml::Mapping::new();
+        let mut seq1 = serde_yaml::Sequence::new();
+        for entry in &self.addresses {
+            seq1.push(serde_yaml::Value::String(entry.to_owned()));
+        }
+        insertseq(&mut map, "addresses", &seq1);
+        inserts(&mut map, "name", &self.name);
+        inserts(&mut map, "defcontent", &self.defcontent);
+        inserts(&mut map, "defpol", &self.defpol);
+        insertb(
+            &mut map,
+            "defpolOverrideLocalData",
+            self.defpolOverrideLocalData,
+        );
+        insertu32(&mut map, "defttl", self.defttl);
+        insertu32(&mut map, "extendedErrorCode", self.extendedErrorCode);
+        insertb(&mut map, "includeSOA", self.includeSOA);
+        insertb(&mut map, "ignoreDuplicates", self.ignoreDuplicates);
+        insertu32(&mut map, "maxTTL", self.maxTTL);
+        inserts(&mut map, "policyName", &self.policyName);
+        let mut seq2 = serde_yaml::Sequence::new();
+        for entry in &self.tags {
+            seq2.push(serde_yaml::Value::String(entry.to_owned()));
+        }
+        insertseq(&mut map, "tags", &seq2);
+        insertb(&mut map, "overridesGettag", self.overridesGettag);
+        insertu32(&mut map, "zoneSizeHint", self.zoneSizeHint);
+
+        let mut tsigmap = serde_yaml::Mapping::new();
+        inserts(&mut tsigmap, "name", &self.tsig.name);
+        inserts(&mut tsigmap, "algo", &self.tsig.algo);
+        inserts(&mut tsigmap, "secret", &self.tsig.secret);
         map.insert(
-            serde_yaml::Value::String("name".to_owned()),
-            serde_yaml::Value::String(self.name.to_owned()),
+            serde_yaml::Value::String("tsig".to_owned()),
+            serde_yaml::Value::Mapping(tsigmap),
         );
+
+        insertu32(&mut map, "refresh", self.refresh);
+        insertu32(&mut map, "maxReceivedMBytes", self.maxReceivedMBytes);
+        inserts(&mut map, "localAddress", &self.localAddress);
+        insertu32(&mut map, "axfrTimeout", self.axfrTimeout);
+        inserts(&mut map, "dumpFile", &self.dumpFile);
+        inserts(&mut map, "seedFile", &self.seedFile);
+        serde_yaml::Value::Mapping(map)
+    }
+}
+
+impl ZoneToCache {
+    pub fn validate(&self, _field: &str) -> Result<(), ValidationError> {
+        Ok(())
+    }
+
+    fn to_yaml_map(&self) -> serde_yaml::Value {
+        let mut map = serde_yaml::Mapping::new();
+        inserts(&mut map, "zone", &self.zone);
+        inserts(&mut map, "method", &self.method);
+        let mut seq = serde_yaml::Sequence::new();
+        for entry in &self.sources {
+            seq.push(serde_yaml::Value::String(entry.to_owned()));
+        }
+        insertseq(&mut map, "sources", &seq);
+        insertu(&mut map, "timeout", self.timeout);
+
+        let mut tsigmap = serde_yaml::Mapping::new();
+        inserts(&mut tsigmap, "name", &self.tsig.name);
+        inserts(&mut tsigmap, "algo", &self.tsig.algo);
+        inserts(&mut tsigmap, "secret", &self.tsig.secret);
         map.insert(
-            serde_yaml::Value::String("reason".to_owned()),
-            serde_yaml::Value::String(self.reason.to_owned()),
+            serde_yaml::Value::String("tsig".to_owned()),
+            serde_yaml::Value::Mapping(tsigmap),
         );
+
+        insertu(&mut map, "refreshPeriod", self.refreshPeriod);
+        insertu(&mut map, "retryOnErrorPeriod", self.retryOnErrorPeriod);
+        insertu(&mut map, "maxReceivedMBytes", self.maxReceivedMBytes);
+        inserts(&mut map, "localAddress", &self.localAddress);
+        inserts(&mut map, "zonemd", &self.zonemd);
+        inserts(&mut map, "dnssec", &self.dnssec);
+
+        serde_yaml::Value::Mapping(map)
+    }
+}
+
+impl AllowedAdditionalQType {
+    pub fn validate(&self, _field: &str) -> Result<(), ValidationError> {
+        Ok(())
+    }
+
+    fn to_yaml_map(&self) -> serde_yaml::Value {
+        let mut map = serde_yaml::Mapping::new();
+        inserts(&mut map, "qtype", &self.qtype);
+        let mut seq = serde_yaml::Sequence::new();
+        for entry in &self.targets {
+            seq.push(serde_yaml::Value::String(entry.to_owned()));
+        }
+        insertseq(&mut map, "targets", &seq);
+        inserts(&mut map, "mode", &self.mode);
+        serde_yaml::Value::Mapping(map)
+    }
+}
+
+impl ProxyMapping {
+    pub fn validate(&self, _field: &str) -> Result<(), ValidationError> {
+        Ok(())
+    }
+
+    fn to_yaml_map(&self) -> serde_yaml::Value {
+        let mut map = serde_yaml::Mapping::new();
+        inserts(&mut map, "subnet", &self.subnet);
+        inserts(&mut map, "address", &self.address);
+        let mut seq = serde_yaml::Sequence::new();
+        for entry in &self.domains {
+            seq.push(serde_yaml::Value::String(entry.to_owned()));
+        }
+        insertseq(&mut map, "domains", &seq);
         serde_yaml::Value::Mapping(map)
     }
 }
@@ -300,10 +531,7 @@ pub fn validate_forward_zones(field: &str, vec: &Vec<ForwardZone>) -> Result<(),
 }
 
 #[allow(clippy::ptr_arg)] //# Avoids creating a rust::Slice object on the C++ side.
-pub fn validate_trustanchors(
-    field: &str,
-    vec: &Vec<TrustAnchor>,
-) -> Result<(), ValidationError> {
+pub fn validate_trustanchors(field: &str, vec: &Vec<TrustAnchor>) -> Result<(), ValidationError> {
     validate_vec(field, vec, |field, element| element.validate(field))
 }
 
@@ -457,7 +685,65 @@ pub fn map_to_yaml_string(vec: &Vec<OldStyle>) -> Result<String, serde_yaml::Err
                         }
                         serde_yaml::Value::Sequence(seq)
                     }
-                    other => serde_yaml::Value::String("map_to_yaml_string: Unknown type: ".to_owned() + other),
+                    "Vec<ProtobufServer>" => {
+                        let mut seq = serde_yaml::Sequence::new();
+                        for element in &entry.value.vec_protobufserver_val {
+                            seq.push(element.to_yaml_map());
+                        }
+                        serde_yaml::Value::Sequence(seq)
+                    }
+                    "Vec<DNSTapFrameStreamServer>" => {
+                        let mut seq = serde_yaml::Sequence::new();
+                        for element in &entry.value.vec_dnstap_framestream_server_val {
+                            seq.push(element.to_yaml_map());
+                        }
+                        serde_yaml::Value::Sequence(seq)
+                    }
+                    "Vec<DNSTapNODFrameStreamServer>" => {
+                        let mut seq = serde_yaml::Sequence::new();
+                        for element in &entry.value.vec_dnstap_nod_framestream_server_val {
+                            seq.push(element.to_yaml_map());
+                        }
+                        serde_yaml::Value::Sequence(seq)
+                    }
+                    "Vec<RPZ>" => {
+                        let mut seq = serde_yaml::Sequence::new();
+                        for element in &entry.value.vec_rpz_val {
+                            seq.push(element.to_yaml_map());
+                        }
+                        serde_yaml::Value::Sequence(seq)
+                    }
+                    "Vec<SortList>" => {
+                        let mut seq = serde_yaml::Sequence::new();
+                        for element in &entry.value.vec_sortlist_val {
+                            seq.push(element.to_yaml_map());
+                        }
+                        serde_yaml::Value::Sequence(seq)
+                    }
+                    "Vec<ZoneToCache>" => {
+                        let mut seq = serde_yaml::Sequence::new();
+                        for element in &entry.value.vec_zonetocache_val {
+                            seq.push(element.to_yaml_map());
+                        }
+                        serde_yaml::Value::Sequence(seq)
+                    }
+                    "Vec<AllowedAdditionalQType>" => {
+                        let mut seq = serde_yaml::Sequence::new();
+                        for element in &entry.value.vec_allowedadditionalqtype_val {
+                            seq.push(element.to_yaml_map());
+                        }
+                        serde_yaml::Value::Sequence(seq)
+                    }
+                    "Vec<ProxyMapping>" => {
+                        let mut seq = serde_yaml::Sequence::new();
+                        for element in &entry.value.vec_proxymapping_val {
+                            seq.push(element.to_yaml_map());
+                        }
+                        serde_yaml::Value::Sequence(seq)
+                    }
+                    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 {
@@ -592,3 +878,31 @@ pub fn api_delete_zone(path: &str, zone: &str) -> Result<(), std::io::Error> {
     zones.forward_zones.retain(|x| x.zone != zone);
     api_write_zones(path, &zones)
 }
+
+pub fn def_pb_export_qtypes() -> Vec<String> {
+    vec![
+        String::from("A"),
+        String::from("CNAME"),
+        String::from("AAAA"),
+    ]
+}
+
+pub fn default_value_equal_pb_export_qtypes(value: &Vec<String>) -> bool {
+    &def_pb_export_qtypes() == value
+}
+
+pub fn def_ztc_validate() -> String {
+    String::from("validate")
+}
+
+pub fn def_value_equals_ztc_validate(value: &String) -> bool {
+    &def_ztc_validate() == value
+}
+
+pub fn def_additional_mode() -> String {
+    String::from("CacheOnlyRequireAuth")
+}
+
+pub fn default_value_equals_additional_mode(value: &String) -> bool {
+    &def_additional_mode() == value
+}
index a49786f6162600a278faed6187dca69a947edd89..8bb99a2e3286ea719720cf1c8fabe9fb108336ef 100644 (file)
@@ -44,6 +44,16 @@ impl<const U: u64> U64<U> {
     }
 }
 
+pub struct U32<const U: u32>;
+impl<const U: u32> U32<U> {
+    pub const fn value() -> u32 {
+        U
+    }
+    pub fn is_equal(v: &u32) -> bool {
+        v == &U
+    }
+}
+
 // A helper to define constant value as a Rust path */
 pub struct Bool<const U: bool>;
 impl<const U: bool> Bool<U> {
index 64c6cbfa29cc06e05ec51f43028920562e0a4644..5e91bd3770a07fd37d086e78c842eba456dad59a 100644 (file)
@@ -3232,6 +3232,114 @@ XXX
         'default' : '24',
         'help' : 'XXX',
         'doc' : ''',
+XXX
+        ''',
+        'skip-old' : True,
+        'versionadded': '5.1.0',
+    },
+    {
+        'name' : 'protobuf_servers',
+        'section' : 'logging',
+        'type' : LType.ListProtobufServers,
+        'default' : '',
+        'help' : 'XXX',
+        'doc' : ''',
+XXX
+        ''',
+        'skip-old' : True,
+        'versionadded': '5.1.0',
+    },
+    {
+        'name' : 'outgoing_protobuf_servers',
+        'section' : 'logging',
+        'type' : LType.ListProtobufServers,
+        'default' : '',
+        'help' : 'XXX',
+        'doc' : ''',
+XXX
+        ''',
+        'skip-old' : True,
+        'versionadded': '5.1.0',
+    },
+    {
+        'name' : 'dnstap_framestream_servers',
+        'section' : 'logging',
+        'type' : LType.ListDNSTapFrameStreamServers,
+        'default' : '',
+        'help' : 'XXX',
+        'doc' : ''',
+XXX
+        ''',
+        'skip-old' : True,
+        'versionadded': '5.1.0',
+    },
+    {
+        'name' : 'dnstap_nod_framestream_servers',
+        'section' : 'logging',
+        'type' : LType.ListDNSTapNODFrameStreamServers,
+        'default' : '',
+        'help' : 'XXX',
+        'doc' : ''',
+XXX
+        ''',
+        'skip-old' : True,
+        'versionadded': '5.1.0',
+    },
+    {
+        'name' : 'sortlists',
+        'section' : 'recursor',
+        'type' : LType.ListSortLists,
+        'default' : '',
+        'help' : 'XXX',
+        'doc' : ''',
+XXX
+        ''',
+        'skip-old' : True,
+        'versionadded': '5.1.0',
+    },
+    {
+        'name' : 'rpzs',
+        'section' : 'recursor',
+        'type' : LType.ListRPZs,
+        'default' : '',
+        'help' : 'XXX',
+        'doc' : ''',
+XXX
+        ''',
+        'skip-old' : True,
+        'versionadded': '5.1.0',
+    },
+    {
+        'name' : 'zonetocaches',
+        'section' : 'recordcache',
+        'type' : LType.ListZoneToCaches,
+        'default' : '',
+        'help' : 'XXX',
+        'doc' : ''',
+XXX
+        ''',
+        'skip-old' : True,
+        'versionadded': '5.1.0',
+    },
+    {
+        'name' : 'allowed_additional_qtypes',
+        'section' : 'recursor',
+        'type' : LType.ListAllowedAdditionalQTypes,
+        'default' : '',
+        'help' : 'XXX',
+        'doc' : ''',
+XXX
+        ''',
+        'skip-old' : True,
+        'versionadded': '5.1.0',
+    },
+    {
+        'name' : 'proxymappings',
+        'section' : 'incoming',
+        'type' : LType.ListProxyMappings,
+        'default' : '',
+        'help' : 'XXX',
+        'doc' : ''',
 XXX
         ''',
         'skip-old' : True,
index 0e1eb5b002df47dfac27b79154998b63d8ec1869..7335c6021e47e38cfe0562d9eca701e3fb85532c 100644 (file)
@@ -422,4 +422,390 @@ BOOST_AUTO_TEST_CASE(test_rust_merge_override)
   BOOST_CHECK_EQUAL(lhs.recordcache.max_entries, 99U);
 }
 
+BOOST_AUTO_TEST_CASE(test_yaml_defaults_ta)
+{
+  // Two entries: one all default, one all overrides
+  const std::string yaml = R"EOT(dnssec:
+  trustanchors:
+    - name: a
+      dsrecords: [b] 
+  negative_trustanchors:
+    - name: c
+      reason: d
+  trustanchorfile: e
+  trustanchorfile_interval: 99
+)EOT";
+  auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml);
+  settings.validate();
+  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.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_defaults_protobuf)
+{
+  // Two entries: one all default, one all overrides
+  const std::string yaml = 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
+)EOT";
+
+  auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml);
+  settings.validate();
+  BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[0].timeout, 2U);
+  BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[0].maxQueuedEntries, 100U);
+  BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[0].reconnectWaitTime, 1U);
+  BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[0].taggedOnly, false);
+  BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[0].asyncConnect, false);
+  BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[0].logQueries, true);
+  BOOST_CHECK_EQUAL(settings.logging.protobuf_servers[0].logResponses, true);
+  // Code below crashes clang
+  // std::vector<string> testv = {"A", "AAAA", "CNAME"})
+  // 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]
+    timeout: 100
+    maxQueuedEntries: 101
+    reconnectWaitTime: 102
+    taggedOnly: true
+    asyncConnect: true
+    logQueries: false
+    logResponses: false
+    logMappedFrom: true
+)EOT";
+
+  auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml);
+  settings.validate();
+  BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[0].timeout, 2U);
+  BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[0].maxQueuedEntries, 100U);
+  BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[0].reconnectWaitTime, 1U);
+  BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[0].taggedOnly, false);
+  BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[0].asyncConnect, false);
+  BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[0].logQueries, true);
+  BOOST_CHECK_EQUAL(settings.logging.outgoing_protobuf_servers[0].logResponses, true);
+  // Code below crashes clang
+  // std::vector<string> testv = {"A", "AAAA", "CNAME"})
+  // 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);
+}
+
+BOOST_AUTO_TEST_CASE(test_yaml_defaults_dnstap)
+{
+  // Two entries: one all default, one all overrides
+  const std::string yaml = 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
+)EOT";
+
+  auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml);
+  settings.validate();
+  BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[0].logQueries, true);
+  BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[0].logResponses, true);
+  BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[0].bufferHint, 0U);
+  BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[0].flushTimeout, 0U);
+  BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[0].inputQueueSize, 0U);
+  BOOST_CHECK_EQUAL(settings.logging.dnstap_framestream_servers[0].outputQueueSize, 0U);
+  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
+    bufferHint: 1
+    flushTimeout: 2
+    inputQueueSize: 3
+    outputQueueSize: 4
+    queueNotifyThreshold: 5
+    reopenInterval: 6
+)EOT";
+
+  auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml);
+  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);
+  BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[0].bufferHint, 0U);
+  BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[0].flushTimeout, 0U);
+  BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[0].inputQueueSize, 0U);
+  BOOST_CHECK_EQUAL(settings.logging.dnstap_nod_framestream_servers[0].outputQueueSize, 0U);
+  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);
+}
+
+BOOST_AUTO_TEST_CASE(test_yaml_defaults_rpz)
+{
+  // Two entries: one all default, one all overrides
+  const std::string yaml = R"EOT(recursor:
+  rpzs:
+  - name: file
+  - name: zone
+    addresses: [1.2.3.4]
+  - name: nondef
+    addresses: [1.2.3.4]
+    defcontent: a
+    defpol: b
+    defpolOverrideLocalData: false
+    defttl: 99
+    extendedErrorCode: 100
+    extendedErrorExtra: c
+    includeSOA: true
+    ignoreDuplicates: true
+    maxTTL: 101
+    policyName: c
+    tags: [d,e]
+    overridesGettag: false
+    zoneSizeHint: 102
+    tsig:
+      name: f
+      algo: g
+      secret: h
+    refresh: 103
+    maxReceivedMBytes: 104
+    localAddress: i
+    axfrTimeout: 105
+    dumpFile: j
+    seedFile: k
+)EOT";
+
+  auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml);
+  settings.validate();
+
+  BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[0].name), "file");
+  BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[0].defcontent), "");
+  BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[0].defpol), "");
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[0].defpolOverrideLocalData, true);
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[0].defttl, -1U);
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[0].extendedErrorCode, 0U);
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[0].extendedErrorExtra, "");
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[0].includeSOA, false);
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[0].ignoreDuplicates, false);
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[0].maxTTL, -1U);
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[0].tags.size(), 0U);
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[0].overridesGettag, true);
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[0].zoneSizeHint, 0U);
+
+  BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[1].name), "zone");
+  BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[1].addresses[0]), "1.2.3.4");
+  BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[1].tsig.name), "");
+  BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[1].tsig.algo), "");
+  BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[1].tsig.secret), "");
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[1].refresh, 0U);
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[1].maxReceivedMBytes, 0U);
+  BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[1].localAddress), "");
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[1].axfrTimeout, 20U);
+  BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[1].dumpFile), "");
+  BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[1].seedFile), "");
+
+  BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[2].name), "nondef");
+  BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[1].addresses[0]), "1.2.3.4");
+  BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[2].defcontent), "a");
+  BOOST_CHECK_EQUAL(std::string(settings.recursor.rpzs[2].defpol), "b");
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[2].defpolOverrideLocalData, false);
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[2].defttl, 99U);
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[2].extendedErrorCode, 100U);
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[2].extendedErrorExtra, "c");
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[2].includeSOA, true);
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[2].ignoreDuplicates, true);
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[2].maxTTL, 101U);
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[2].tags.size(), 2U);
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[2].overridesGettag, false);
+  BOOST_CHECK_EQUAL(settings.recursor.rpzs[2].zoneSizeHint, 102U);
+
+  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(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(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");
+}
+
+BOOST_AUTO_TEST_CASE(test_yaml_sortlist)
+{
+  const std::string yaml = R"EOT(recursor:
+  sortlists:
+    - key: 1.2.3.4/8
+      subnets:
+      - subnet: 5.6.7.8
+        order: 99
+)EOT";
+
+  auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml);
+  settings.validate();
+  BOOST_CHECK_EQUAL(std::string(settings.recursor.sortlists[0].key), "1.2.3.4/8");
+  BOOST_CHECK_EQUAL(std::string(settings.recursor.sortlists[0].subnets[0].subnet), "5.6.7.8");
+  BOOST_CHECK_EQUAL(settings.recursor.sortlists[0].subnets[0].order, 99U);
+}
+
+BOOST_AUTO_TEST_CASE(test_yaml_ztc)
+{
+  const std::string yaml = R"EOT(recordcache:
+    zonetocaches:
+    - zone: zone
+      method: axfr
+      sources: [1.2.3.4]
+    - zone: zone2
+      method: axfr
+      sources: [1.2.3.4]
+      timeout: 1
+      tsig:
+        name: a
+        algo: b
+        secret: c
+      refreshPeriod: 2
+      retryOnErrorPeriod: 3
+      maxReceivedMBytes: 4
+      localAddress: d
+      zonemd: ignore
+      dnssec: require
+)EOT";
+
+  auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml);
+  settings.validate();
+  BOOST_CHECK_EQUAL(std::string(settings.recordcache.zonetocaches[0].zone), "zone");
+  BOOST_CHECK_EQUAL(std::string(settings.recordcache.zonetocaches[0].method), "axfr");
+  BOOST_CHECK_EQUAL(std::string(settings.recordcache.zonetocaches[0].sources[0]), "1.2.3.4");
+  BOOST_CHECK_EQUAL(settings.recordcache.zonetocaches[0].timeout, 20U);
+  BOOST_CHECK_EQUAL(std::string(settings.recordcache.zonetocaches[0].tsig.name), "");
+  BOOST_CHECK_EQUAL(std::string(settings.recordcache.zonetocaches[0].tsig.algo), "");
+  BOOST_CHECK_EQUAL(std::string(settings.recordcache.zonetocaches[0].tsig.secret), "");
+  BOOST_CHECK_EQUAL(settings.recordcache.zonetocaches[0].refreshPeriod, 86400U);
+  BOOST_CHECK_EQUAL(settings.recordcache.zonetocaches[0].retryOnErrorPeriod, 60U);
+  BOOST_CHECK_EQUAL(settings.recordcache.zonetocaches[0].maxReceivedMBytes, 0U);
+  BOOST_CHECK_EQUAL(settings.recordcache.zonetocaches[0].localAddress, "");
+  BOOST_CHECK_EQUAL(settings.recordcache.zonetocaches[0].zonemd, "validate");
+  BOOST_CHECK_EQUAL(settings.recordcache.zonetocaches[0].dnssec, "validate");
+
+  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(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(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].zonemd, "ignore");
+  BOOST_CHECK_EQUAL(settings.recordcache.zonetocaches[1].dnssec, "require");
+}
+
+BOOST_AUTO_TEST_CASE(test_yaml_additionals)
+{
+  const std::string yaml = R"EOT(recursor:
+    allowed_additional_qtypes:
+    - qtype: A
+      targets: [A, MX, AAAA]
+    - qtype: MX
+      targets: [A]
+      mode: CacheOnly
+)EOT";
+
+  auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml);
+  settings.validate();
+  BOOST_CHECK_EQUAL(std::string(settings.recursor.allowed_additional_qtypes[0].qtype), "A");
+  BOOST_CHECK_EQUAL(settings.recursor.allowed_additional_qtypes[0].targets.size(), 3U);
+  BOOST_CHECK_EQUAL(std::string(settings.recursor.allowed_additional_qtypes[0].mode), "CacheOnlyRequireAuth");
+
+  BOOST_CHECK_EQUAL(std::string(settings.recursor.allowed_additional_qtypes[1].qtype), "MX");
+  BOOST_CHECK_EQUAL(settings.recursor.allowed_additional_qtypes[1].targets.size(), 1U);
+  BOOST_CHECK_EQUAL(std::string(settings.recursor.allowed_additional_qtypes[1].mode), "CacheOnly");
+}
+
+BOOST_AUTO_TEST_CASE(test_yaml_proxymapping)
+{
+  const std::string yaml = R"EOT(incoming:
+    proxymappings:
+    - subnet: 1.2.3.4
+      address: 4.5.6.7
+    - subnet: 3.4.5.6
+      address: 6.7.8.9
+      domains: [a, b, c]
+)EOT";
+
+  auto settings = pdns::rust::settings::rec::parse_yaml_string(yaml);
+  settings.validate();
+  BOOST_CHECK_EQUAL(std::string(settings.incoming.proxymappings[0].subnet), "1.2.3.4");
+  BOOST_CHECK_EQUAL(std::string(settings.incoming.proxymappings[0].address), "4.5.6.7");
+  BOOST_CHECK_EQUAL(settings.incoming.proxymappings[0].domains.size(), 0U);
+
+  BOOST_CHECK_EQUAL(std::string(settings.incoming.proxymappings[1].subnet), "3.4.5.6");
+  BOOST_CHECK_EQUAL(std::string(settings.incoming.proxymappings[1].address), "6.7.8.9");
+  BOOST_CHECK_EQUAL(settings.incoming.proxymappings[1].domains.size(), 3U);
+}
+
 BOOST_AUTO_TEST_SUITE_END()