]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Tweaks and handle trust anchors better
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Mon, 19 Feb 2024 14:20:31 +0000 (15:20 +0100)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Thu, 25 Apr 2024 09:31:40 +0000 (11:31 +0200)
13 files changed:
pdns/recursordist/rec-main.cc
pdns/recursordist/rec_channel_rec.cc
pdns/recursordist/rpzloader.cc
pdns/recursordist/settings/cxxsupport.cc
pdns/recursordist/settings/generate.py
pdns/recursordist/settings/rust-bridge-in.rs
pdns/recursordist/settings/table.py
pdns/recursordist/test-settings.cc
regression-tests.recursor-dnssec/recursortests.py
regression-tests.recursor-dnssec/runtests
regression-tests.recursor-dnssec/test_NTA.py
regression-tests.recursor-dnssec/test_NoDSYAML.py [new file with mode: 0644]
regression-tests.recursor-dnssec/test_SimpleYAML.py

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