]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
rec: be able to specify names for primaries for catalog zones and RPZs
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Wed, 6 Nov 2024 08:46:56 +0000 (09:46 +0100)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Wed, 13 Nov 2024 08:33:00 +0000 (09:33 +0100)
pdns/recursordist/Makefile.am
pdns/recursordist/rec-lua-conf.cc
pdns/recursordist/rec-system-resolve.cc
pdns/recursordist/rec-system-resolve.hh
pdns/recursordist/rec-xfr.cc
pdns/recursordist/rec-xfr.hh
pdns/recursordist/reczones.cc
pdns/recursordist/rpzloader.cc
pdns/recursordist/settings/cxxsupport.cc
pdns/recursordist/settings/rust/src/bridge.rs

index 482879ea2e521312d3196dfc2549306fb9ff6fb6..6607b95cb84ffaca79db5a47dc5dcac1896f3330 100644 (file)
@@ -548,9 +548,11 @@ rec_control_SOURCES = \
        qtype.cc \
        rcpgenerator.cc rcpgenerator.hh \
        rec-lua-conf.cc rec-lua-conf.hh \
+       rec-system-resolve.cc rec-system-resolve.hh \
        rec_channel.cc rec_channel.hh \
        rec_control.cc \
        settings/cxxsupport.cc \
+       threadname.cc threadname.hh \
        sillyrecords.cc \
        sortlist.cc sortlist.hh \
        svc-records.cc svc-records.hh \
index e398909e75793ea83c98622a92ade081efb57e1e..d25c528f66f9f99fd3114dc91ca6fca324000f80 100644 (file)
@@ -16,6 +16,7 @@
 #include "validate.hh"
 #include "validate-recursor.hh"
 #include "root-dnssec.hh"
+#include "rec-system-resolve.hh"
 
 GlobalStateHolder<LuaConfigItems> g_luaconfs;
 
@@ -278,11 +279,11 @@ static void rpzPrimary(LuaConfigItems& lci, const boost::variant<string, std::ve
 
   std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
   if (primaries_.type() == typeid(string)) {
-    params.zoneXFRParams.primaries.emplace_back(boost::get<std::string>(primaries_), 53);
+    params.zoneXFRParams.primaries.emplace_back(boost::get<std::string>(primaries_));
   }
   else {
     for (const auto& primary : boost::get<std::vector<std::pair<int, std::string>>>(primaries_)) {
-      params.zoneXFRParams.primaries.emplace_back(primary.second, 53);
+      params.zoneXFRParams.primaries.emplace_back(primary.second);
     }
   }
 
@@ -329,7 +330,8 @@ static void rpzPrimary(LuaConfigItems& lci, const boost::variant<string, std::ve
 
     if (params.zoneXFRParams.localAddress != ComboAddress()) {
       // We were passed a localAddress, check if its AF matches the primaries'
-      for (const auto& primary : params.zoneXFRParams.primaries) {
+      for (const auto& nameOrIP : params.zoneXFRParams.primaries) {
+        auto primary = pdns::fromNameOrIP(nameOrIP, 53, lci.d_slog);
         if (params.zoneXFRParams.localAddress.sin4.sin_family != primary.sin4.sin_family) {
           throw PDNSException("Primary address(" + primary.toString() + ") is not of the same Address Family as the local address (" + params.zoneXFRParams.localAddress.toString() + ").");
         }
index b50057cf74e584fd66b06870ad92def5d4821844..8a473d40724059719ec86e4ad16c6cadde4936ea 100644 (file)
@@ -304,3 +304,26 @@ void pdns::RecResolve::Refresher::trigger()
   wakeup = true;
   condVar.notify_one();
 }
+
+ComboAddress pdns::fromNameOrIP(const string& str, uint16_t defPort, Logr::log_t log)
+{
+  try {
+    ComboAddress addr = parseIPAndPort(str, defPort);
+    return addr;
+  }
+  catch (const PDNSException&) {
+    uint16_t port = defPort;
+    string::size_type pos = str.rfind(':');
+    if (pos != string::npos) {
+      port = pdns::checked_stoi<uint16_t>(str.substr(pos + 1));
+    }
+    auto& res = pdns::RecResolve::getInstance();
+    ComboAddress address = res.lookupAndRegister(str.substr(0, pos), time(nullptr));
+    if (address != ComboAddress()) {
+      address.setPort(port);
+      return address;
+    }
+    log->error(Logr::Error, "Could not resolve name", "name", Logging::Loggable(str));
+    throw PDNSException("Could not resolve " + str);
+  }
+}
index b3e199a46b64a7fea7dd361e07f46746cecb383c..3491598b717063afb0858ad8a1d6638acbec6a6f 100644 (file)
@@ -31,6 +31,7 @@
 #include "namespaces.hh"
 #include "iputils.hh"
 #include "lock.hh"
+#include "logr.hh"
 
 /************************************************************************************************
 The pdns::RecResolve class implements a facility to use the system configured resolver. At the moment
@@ -146,4 +147,5 @@ private:
   static bool s_selfResolveCheck;
 };
 
+  ComboAddress fromNameOrIP(const string& str, uint16_t defPort, Logr::log_t log);
 }
index 097a1930afa11cbe0a77a283bdf70b9bde755373..6a5ecfbf7b01c0ca3840371f21804d2760434bb7 100644 (file)
@@ -29,6 +29,7 @@
 #include "axfr-retriever.hh"
 #include "ixfr.hh"
 #include "dnsrecords.hh"
+#include "rec-system-resolve.hh"
 
 static const DNSName cZones("zones");
 static const DNSName cVersion("version");
@@ -85,6 +86,7 @@ void CatalogZone::registerForwarders(const FWCatalogZone& params, Logr::log_t lo
     if (const auto ptr = getRR<PTRRecordContent>(record.second)) {
       auto defsIter = params.d_defaults.find("");
       const auto& name = record.first.first;
+      const auto& target = ptr->getContent();
       auto groupKey = name;
       groupKey.prependRawLabel("group");
       // Look for group records matching the member
@@ -95,19 +97,18 @@ void CatalogZone::registerForwarders(const FWCatalogZone& params, Logr::log_t lo
           groupName = unquotify(groupName);
           auto iter = params.d_defaults.find(groupName);
           if (iter == params.d_defaults.end()) {
-            logger->info(Logr::Debug, "No match for group in YAML config", "name", Logging::Loggable(name), "groupName", Logging::Loggable(groupName));
+            logger->info(Logr::Error, "No match for group in YAML config", "name", Logging::Loggable(name), "groupName", Logging::Loggable(groupName), "target", Logging::Loggable(target));
             continue;
           }
-          logger->info(Logr::Debug, "Match for group in YAML config", "name", Logging::Loggable(name), "groupName", Logging::Loggable(groupName));
+          logger->info(Logr::Debug, "Match for group in YAML config", "name", Logging::Loggable(name), "groupName", Logging::Loggable(groupName), "target", Logging::Loggable(target));
           defsIter = iter;
           break;
         }
       }
       if (defsIter == params.d_defaults.end()) {
-        logger->info(Logr::Error, "No match for group in YAML config", "name", Logging::Loggable(name));
+        logger->info(Logr::Error, "No match for default group in YAML config", "name", Logging::Loggable(name), "target", Logging::Loggable(target));
         continue;
       }
-      auto target = ptr->getContent();
       pdns::rust::settings::rec::ForwardZone forward;
       forward.zone = target.toString();
       forward.recurse = defsIter->second.recurse;
@@ -236,8 +237,9 @@ void FWCatZoneXFR::preloadZoneFile(const DNSName& zoneName, const std::shared_pt
 
     /* full copy, as promised */
     auto newZone = std::make_shared<CatalogZone>(*oldZone);
-    for (const auto& primary : d_params.primaries) {
+    for (const auto& nameOrIp : d_params.primaries) {
       try {
+        auto primary = pdns::fromNameOrIP(nameOrIp, 53, logger);
         d_params.soaRecordContent = loadZoneFromServer(logger, primary, zoneName, newZone, d_params.tsigtriplet, d_params.maxReceivedMBytes, d_params.localAddress, d_params.xfrTimeout);
         newZone->setSerial(d_params.soaRecordContent->d_st.serial);
         newZone->setRefresh(d_params.soaRecordContent->d_st.refresh);
@@ -254,11 +256,11 @@ void FWCatZoneXFR::preloadZoneFile(const DNSName& zoneName, const std::shared_pt
         break;
       }
       catch (const std::exception& e) {
-        logger->error(Logr::Warning, e.what(), "Unable to load zone, will retry", "from", Logging::Loggable(primary), "exception", Logging::Loggable("std::exception"), "refresh", Logging::Loggable(refresh));
+        logger->error(Logr::Warning, e.what(), "Unable to load zone, will retry", "from", Logging::Loggable(nameOrIp), "exception", Logging::Loggable("std::exception"), "refresh", Logging::Loggable(refresh));
         // XXX Stats
       }
       catch (const PDNSException& e) {
-        logger->error(Logr::Warning, e.reason, "Unable to load zone, will retry", "from", Logging::Loggable(primary), "exception", Logging::Loggable("PDNSException"), "refresh", Logging::Loggable(refresh));
+        logger->error(Logr::Warning, e.reason, "Unable to load zone, will retry", "from", Logging::Loggable(nameOrIp), "exception", Logging::Loggable("PDNSException"), "refresh", Logging::Loggable(refresh));
         // XXX Stats
       }
     }
@@ -318,7 +320,8 @@ bool FWCatZoneXFR::zoneTrackerIteration(const DNSName& zoneName, std::shared_ptr
   }
 
   vector<pair<vector<DNSRecord>, vector<DNSRecord>>> deltas;
-  for (const auto& primary : d_params.primaries) {
+  for (const auto& nameOrIp : d_params.primaries) {
+    auto primary = pdns::fromNameOrIP(nameOrIp, 53, logger);
     auto soa = getRR<SOARecordContent>(soaRecord);
     auto serial = soa ? soa->d_st.serial : 0;
     logger->info(Logr::Info, "Getting IXFR deltas", "address", Logging::Loggable(primary), "ourserial", Logging::Loggable(serial));
index 541255c7ec76a0994e626f4cc5c4bff3a0043806..769053d3a543918d7d48a3c5bf39088480029870 100644 (file)
@@ -42,7 +42,7 @@ struct FWCatalogZone;
 struct ZoneXFRParams
 {
   std::string name;
-  std::vector<ComboAddress> primaries;
+  std::vector<std::string> primaries;
   ComboAddress localAddress;
   std::shared_ptr<const SOARecordContent> soaRecordContent;
   TSIGTriplet tsigtriplet;
index 7831b1afd6957c1847f7c7f44e47a028717d53b4..ae48402db4445d70912842bba1fd1dc370287a21 100644 (file)
@@ -65,29 +65,6 @@ bool primeHints(time_t now)
   return ret;
 }
 
-static ComboAddress fromNameOrIP(const string& str, uint16_t defPort, Logr::log_t log)
-{
-  try {
-    ComboAddress addr = parseIPAndPort(str, defPort);
-    return addr;
-  }
-  catch (const PDNSException&) {
-    uint16_t port = defPort;
-    string::size_type pos = str.rfind(':');
-    if (pos != string::npos) {
-      port = pdns::checked_stoi<uint16_t>(str.substr(pos + 1));
-    }
-    auto& res = pdns::RecResolve::getInstance();
-    ComboAddress address = res.lookupAndRegister(str.substr(0, pos), time(nullptr));
-    if (address != ComboAddress()) {
-      address.setPort(port);
-      return address;
-    }
-    log->error(Logr::Error, "Could not resolve name", "name", Logging::Loggable(str));
-    throw PDNSException("Could not resolve " + str);
-  }
-}
-
 static void convertServersForAD(const std::string& zone, const std::string& input, SyncRes::AuthDomain& authDomain, const char* sepa, Logr::log_t log, bool verbose = true)
 {
   vector<string> servers;
@@ -96,7 +73,7 @@ static void convertServersForAD(const std::string& zone, const std::string& inpu
 
   vector<string> addresses;
   for (auto& server : servers) {
-    ComboAddress addr = fromNameOrIP(server, 53, log);
+    ComboAddress addr = pdns::fromNameOrIP(server, 53, log);
     authDomain.d_servers.push_back(addr);
     if (verbose) {
       addresses.push_back(addr.toStringWithPort());
@@ -340,7 +317,7 @@ static void processApiZonesFile(const string& file, shared_ptr<SyncRes::domainma
     authDomain.d_name = DNSName(string(forward.zone));
     authDomain.d_rdForward = forward.recurse;
     for (const auto& forwarder : forward.forwarders) {
-      ComboAddress addr = parseIPAndPort(string(forwarder), 53);
+      ComboAddress addr = pdns::fromNameOrIP(string(forwarder), 53, log);
       authDomain.d_servers.emplace_back(addr);
     }
     (*newMap)[authDomain.d_name] = authDomain;
@@ -378,7 +355,7 @@ static void processForwardZonesFile(shared_ptr<SyncRes::domainmap_t>& newMap, sh
       authDomain.d_name = DNSName(string(forward.zone));
       authDomain.d_rdForward = forward.recurse;
       for (const auto& forwarder : forward.forwarders) {
-        ComboAddress addr = parseIPAndPort(string(forwarder), 53);
+        ComboAddress addr = pdns::fromNameOrIP(string(forwarder), 53, log);
         authDomain.d_servers.emplace_back(addr);
       }
       (*newMap)[authDomain.d_name] = authDomain;
index db554df57ff033fae3893059ca0e7100acb0d4ae..09792e92ee63c324db390600da69bede1b5b1943 100644 (file)
@@ -32,6 +32,7 @@
 #include "zoneparser-tng.hh"
 #include "threadname.hh"
 #include "query-local-address.hh"
+#include "rec-system-resolve.hh"
 
 Netmask makeNetmaskFromRPZ(const DNSName& name)
 {
@@ -443,7 +444,8 @@ static void preloadRPZFIle(RPZTrackerParams& params, const DNSName& zoneName, st
     std::shared_ptr<DNSFilterEngine::Zone> newZone = std::make_shared<DNSFilterEngine::Zone>(*oldZone);
     for (const auto& primary : params.zoneXFRParams.primaries) {
       try {
-        params.zoneXFRParams.soaRecordContent = loadRPZFromServer(logger, primary, zoneName, newZone, params.defpol, params.defpolOverrideLocal, params.maxTTL, params.zoneXFRParams.tsigtriplet, params.zoneXFRParams.maxReceivedMBytes, params.zoneXFRParams.localAddress, params.zoneXFRParams.xfrTimeout);
+        auto combo = pdns::fromNameOrIP(primary, 53, logger);
+        params.zoneXFRParams.soaRecordContent = loadRPZFromServer(logger, combo, zoneName, newZone, params.defpol, params.defpolOverrideLocal, params.maxTTL, params.zoneXFRParams.tsigtriplet, params.zoneXFRParams.maxReceivedMBytes, params.zoneXFRParams.localAddress, params.zoneXFRParams.xfrTimeout);
         newZone->setSerial(params.zoneXFRParams.soaRecordContent->d_st.serial);
         newZone->setRefresh(params.zoneXFRParams.soaRecordContent->d_st.refresh);
         refresh = std::max(params.zoneXFRParams.refreshFromConf != 0 ? params.zoneXFRParams.refreshFromConf : newZone->getRefresh(), 1U);
@@ -528,7 +530,8 @@ static bool RPZTrackerIteration(RPZTrackerParams& params, const DNSName& zoneNam
   }
 
   vector<pair<vector<DNSRecord>, vector<DNSRecord>>> deltas;
-  for (const auto& primary : params.zoneXFRParams.primaries) {
+  for (const auto& ipOrName : params.zoneXFRParams.primaries) {
+    auto primary = pdns::fromNameOrIP(ipOrName, 53, logger);
     auto soa = getRR<SOARecordContent>(dnsRecord);
     auto serial = soa ? soa->d_st.serial : 0;
     SLOG(g_log << Logger::Info << "Getting IXFR deltas for " << zoneName << " from " << primary.toStringWithPort() << ", our serial: " << serial << endl,
index f27b3e9f0bcd828470dd0016d0dcd47e9ae58abe..4c4fd13c1a339a7ee3856c62dd9a3213e806d651 100644 (file)
@@ -879,7 +879,7 @@ void fromLuaToRust(const vector<RPZTrackerParams>& rpzs, pdns::rust::settings::r
     };
 
     for (const auto& address : rpz.zoneXFRParams.primaries) {
-      rustrpz.addresses.emplace_back(address.toStringWithPort());
+      rustrpz.addresses.emplace_back(address);
     }
     rustrpz.name = rpz.zoneXFRParams.name;
     rustrpz.defcontent = rpz.defcontent;
@@ -1188,8 +1188,7 @@ void fromRustToLuaConfig(const rust::Vec<pdns::rust::settings::rec::RPZ>& rpzs,
   for (const auto& rpz : rpzs) {
     RPZTrackerParams params;
     for (const auto& address : rpz.addresses) {
-      ComboAddress combo = ComboAddress(std::string(address), 53);
-      params.zoneXFRParams.primaries.emplace_back(combo.toStringWithPort());
+      params.zoneXFRParams.primaries.emplace_back(address);
     }
     params.zoneXFRParams.name = std::string(rpz.name);
     params.polName = std::string(rpz.policyName);
@@ -1316,8 +1315,7 @@ void fromRustToLuaConfig(const rust::Vec<pdns::rust::settings::rec::ForwardingCa
     fwcatz.d_catz = std::make_shared<CatalogZone>();
 
     for (const auto& address : catz.xfr.addresses) {
-      ComboAddress combo = ComboAddress(std::string(address), 53);
-      fwcatz.d_params.primaries.emplace_back(combo.toStringWithPort());
+      fwcatz.d_params.primaries.emplace_back(address);
     }
     fwcatz.d_params.name = std::string(catz.zone);
     fwcatz.d_params.zoneSizeHint = catz.xfr.zoneSizeHint;
index e0764109798cacd67b96f371a01441d7b8110415..05872b9beacdfe9771e193231d7ab5b9c778ca7b 100644 (file)
@@ -186,7 +186,7 @@ fn validate_address_family(addrfield: &str, localfield: &str, vec: &[String], lo
         let msg = format!("{}: cannot be empty", addrfield);
         return Err(ValidationError { msg });
     }
-    validate_vec(addrfield, vec, validate_socket_address)?;
+    validate_vec(addrfield, vec, validate_socket_address_or_name)?;
     if local_address.is_empty() {
         return Ok(());
     }
@@ -200,7 +200,11 @@ fn validate_address_family(addrfield: &str, localfield: &str, vec: &[String], lo
         let mut wrong = false;
         let sa = SocketAddr::from_str(addr_str);
         if sa.is_err() {
-            let ip = IpAddr::from_str(addr_str).unwrap();
+            let ip = IpAddr::from_str(addr_str);
+            if ip.is_err() { // It is likely a name
+                continue;
+            }
+            let ip = ip.unwrap();
             if local.is_ipv4() != ip.is_ipv4() || local.is_ipv6() != ip.is_ipv6() {
                 wrong = true;
             }
@@ -656,7 +660,11 @@ impl TSIGTriplet {
 }
 
 impl ForwardingCatalogZone {
-    pub fn validate(&self, _field: &str) -> Result<(), ValidationError> {
+    pub fn validate(&self, field: &str) -> Result<(), ValidationError> {
+        self.xfr.tsig.validate(&(field.to_owned() + ".xfr.tsig"))?;
+        if !self.xfr.addresses.is_empty() {
+            validate_address_family(&(field.to_owned() + ".xfr.addresses"), &(field.to_owned() + ".xfr.localAddress"), &self.xfr.addresses, &self.xfr.localAddress)?;
+        }
         Ok(())
     }