]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
rec: add SOA to RPZ result if configured to do so
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Tue, 30 May 2023 11:49:03 +0000 (13:49 +0200)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Wed, 31 May 2023 12:21:09 +0000 (14:21 +0200)
Fixes #8232

pdns/recursordist/filterpo.hh
pdns/recursordist/pdns_recursor.cc
pdns/recursordist/rec-lua-conf.cc
pdns/recursordist/rpzloader.cc
pdns/recursordist/syncres.cc

index 4d11af52ccd67df41fd18bbd822cbe872366c004..b5aa306bf737023d7e89f6d6ea0d66cbfb06f5f9 100644 (file)
@@ -28,6 +28,7 @@
 #include <map>
 #include <unordered_map>
 #include <limits>
+#include <utility>
 
 /* This class implements a filtering policy that is able to fully implement RPZ, but is not bound to it.
    In other words, it is generic enough to support RPZ, but could get its data from other places.
@@ -96,9 +97,11 @@ public:
     std::unordered_set<std::string> d_tags;
     std::string d_name;
     std::string d_extendedErrorExtra;
+    DNSRecord d_soa{};
     boost::optional<uint16_t> d_extendedErrorCode{boost::none};
     Priority d_priority{maximumPriority};
     bool d_policyOverridesGettag{true};
+    bool d_includeSOA{false};
   };
 
   struct Policy
@@ -168,6 +171,23 @@ public:
       return true;
     }
 
+    [[nodiscard]] bool getSOA(DNSRecord& rec) const
+    {
+      if (d_zoneData) {
+        rec = d_zoneData->d_soa;
+        return true;
+      }
+      return false;
+    }
+
+    [[nodiscard]] bool includeSOA() const
+    {
+      if (d_zoneData) {
+        return d_zoneData->d_includeSOA;
+      }
+      return false;
+    }
+
     bool wasHit() const
     {
       return (d_type != DNSFilterEngine::PolicyType::None && d_kind != DNSFilterEngine::PolicyKind::NoAction);
@@ -187,6 +207,15 @@ public:
     PolicyKind d_kind;
     PolicyType d_type;
 
+    void addSOAtoRPZResult(vector<DNSRecord>& ret) const
+    {
+      DNSRecord soa{};
+      if (includeSOA() && getSOA(soa)) {
+        soa.d_place = DNSResourceRecord::ADDITIONAL;
+        ret.emplace_back(soa);
+      }
+    }
+
   private:
     DNSRecord getRecordFromCustom(const DNSName& qname, const std::shared_ptr<const DNSRecordContent>& custom) const;
   };
@@ -243,7 +272,10 @@ public:
     {
       d_zoneData->d_extendedErrorExtra = extra;
     }
-
+    void setSOA(DNSRecord soa)
+    {
+      d_zoneData->d_soa = std::move(soa);
+    }
     const std::string& getName() const
     {
       return d_zoneData->d_name;
@@ -269,6 +301,11 @@ public:
       return d_qpolAddr.size() + d_postpolAddr.size() + d_propolName.size() + d_propolNSAddr.size() + d_qpolName.size();
     }
 
+    void setIncludeSOA(bool flag)
+    {
+      d_zoneData->d_includeSOA = flag;
+    }
+
     void dump(FILE* fp) const;
 
     void addClientTrigger(const Netmask& nm, Policy&& pol, bool ignoreDuplicate = false);
index e1dbcf7bd414542cf5b835e8d0341b9a427c62fb..9df794155c60493c18514b5610b12267f410f2de 100644 (file)
@@ -524,17 +524,20 @@ static PolicyResult handlePolicyHit(const DNSFilterEngine::Policy& appliedPolicy
 
   case DNSFilterEngine::PolicyKind::NXDOMAIN:
     ret.clear();
+    appliedPolicy.addSOAtoRPZResult(ret);
     res = RCode::NXDomain;
     return PolicyResult::HaveAnswer;
 
   case DNSFilterEngine::PolicyKind::NODATA:
     ret.clear();
+    appliedPolicy.addSOAtoRPZResult(ret);
     res = RCode::NoError;
     return PolicyResult::HaveAnswer;
 
   case DNSFilterEngine::PolicyKind::Truncate:
     if (!dc->d_tcp) {
       ret.clear();
+      appliedPolicy.addSOAtoRPZResult(ret);
       res = RCode::NoError;
       pw.getHeader()->tc = 1;
       return PolicyResult::HaveAnswer;
@@ -570,6 +573,7 @@ static PolicyResult handlePolicyHit(const DNSFilterEngine::Policy& appliedPolicy
         }
       }
 
+      appliedPolicy.addSOAtoRPZResult(ret);
       return PolicyResult::HaveAnswer;
     }
   }
index c384bd65b2d3b6f02f0c3506aafb21f4398c57b1..78e5cb90f3df50cfdf1cd480e73ee64b1654d96e 100644 (file)
@@ -153,6 +153,9 @@ static void parseRPZParameters(rpzOptions_t& have, std::shared_ptr<DNSFilterEngi
       zone->setExtendedErrorExtra(boost::get<std::string>(have["extendedErrorExtra"]));
     }
   }
+  if (have.count("includeSOA")) {
+    zone->setIncludeSOA(boost::get<bool>(have["includeSOA"]));
+  }
 }
 
 typedef std::unordered_map<std::string, boost::variant<bool, uint64_t, std::string, std::vector<std::pair<int, std::string>>>> protobufOptions_t;
index f81ef2fbce4e78f1ead98e8c84943c81bb816c6b..c99480fea3150136b1a60e596ee144084eba4661 100644 (file)
@@ -226,6 +226,7 @@ static shared_ptr<const SOARecordContent> loadRPZFromServer(Logr::log_t plogger,
       dr.d_name.makeUsRelative(zoneName);
       if (dr.d_type == QType::SOA) {
         sr = getRR<SOARecordContent>(dr);
+        zone->setSOA(dr);
         continue;
       }
 
@@ -293,6 +294,7 @@ std::shared_ptr<const SOARecordContent> loadRPZFromFile(const std::string& fname
   zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps"));
   zpt.setMaxIncludes(::arg().asNum("max-include-depth"));
   DNSResourceRecord drr;
+  DNSRecord soaRecord;
   DNSName domain;
   auto log = g_slog->withName("rpz")->withValues("file", Logging::Loggable(fname), "zone", Logging::Loggable(zone->getName()));
   while (zpt.get(drr)) {
@@ -304,6 +306,7 @@ std::shared_ptr<const SOARecordContent> loadRPZFromFile(const std::string& fname
         sr = getRR<SOARecordContent>(dr);
         domain = dr.d_name;
         zone->setDomain(domain);
+        soaRecord = dr;
       }
       else if (dr.d_type == QType::NS) {
         continue;
@@ -320,6 +323,7 @@ std::shared_ptr<const SOARecordContent> loadRPZFromFile(const std::string& fname
 
   if (sr != nullptr) {
     zone->setRefresh(sr->d_st.refresh);
+    zone->setSOA(soaRecord);
     setRPZZoneNewState(zone->getName(), sr->d_st.serial, zone->size(), true, false);
   }
   return sr;
index a2cba559bfbb019f3d10fb6c56999511616c3a36..1472266b8900aabd16959c10b8cf7c5eafc9dc0c 100644 (file)
@@ -3230,12 +3230,14 @@ void SyncRes::handlePolicyHit(const std::string& prefix, const DNSName& qname, c
 
   case DNSFilterEngine::PolicyKind::NXDOMAIN:
     ret.clear();
+    d_appliedPolicy.addSOAtoRPZResult(ret);
     rcode = RCode::NXDomain;
     done = true;
     return;
 
   case DNSFilterEngine::PolicyKind::NODATA:
     ret.clear();
+    d_appliedPolicy.addSOAtoRPZResult(ret);
     rcode = RCode::NoError;
     done = true;
     return;
@@ -3243,6 +3245,7 @@ void SyncRes::handlePolicyHit(const std::string& prefix, const DNSName& qname, c
   case DNSFilterEngine::PolicyKind::Truncate:
     if (!d_queryReceivedOverTCP) {
       ret.clear();
+      d_appliedPolicy.addSOAtoRPZResult(ret);
       rcode = RCode::NoError;
       throw SendTruncatedAnswerException();
     }
@@ -3270,6 +3273,7 @@ void SyncRes::handlePolicyHit(const std::string& prefix, const DNSName& qname, c
         }
       }
     }
+    d_appliedPolicy.addSOAtoRPZResult(ret);
   }
   }
 }