]> granicus.if.org Git - pdns/commitdiff
rec: RPZ updates are done zone by zone, zones are now shared pointers
authorRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 6 Apr 2017 12:21:32 +0000 (14:21 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 26 Apr 2017 09:34:22 +0000 (11:34 +0200)
This prevents having to copy and update all the zones even though
the RPZ IXFR tracker only works on one of them at a time.
Also prevents race conditions if two RPZ IXFR tracker threads
update the state at the same time by using `GlobalStateHolder::modify()`
instead of `GlobalStateHolder::setState()`.

pdns/filterpo.cc
pdns/filterpo.hh
pdns/rec-lua-conf.cc
pdns/recursordist/test-syncres_cc.cc
pdns/reczones.cc
pdns/rpzloader.cc
pdns/rpzloader.hh

index d87c55ccc02020713060f5a96af2857ca73756c6..8a5b1e184096f1d6a402a3f4b123f5a4c38698fc 100644 (file)
@@ -61,11 +61,12 @@ DNSFilterEngine::Policy DNSFilterEngine::getProcessingPolicy(const DNSName& qnam
   //  cout<<"Got question for nameserver name "<<qname<<endl;
   Policy pol;
   for(const auto& z : d_zones) {
-    if(z.name && discardedPolicies.find(*z.name) != discardedPolicies.end()) {
+    const auto zoneName = z->getName();
+    if(zoneName && discardedPolicies.find(*zoneName) != discardedPolicies.end()) {
       continue;
     }
 
-    if(findNamedPolicy(z.propolName, qname, pol)) {
+    if(findNamedPolicy(z->d_propolName, qname, pol)) {
       //      cerr<<"Had a hit on the nameserver ("<<qname<<") used to process the query"<<endl;
       return pol;
     }
@@ -77,11 +78,12 @@ DNSFilterEngine::Policy DNSFilterEngine::getProcessingPolicy(const ComboAddress&
 {
   //  cout<<"Got question for nameserver IP "<<address.toString()<<endl;
   for(const auto& z : d_zones) {
-    if(z.name && discardedPolicies.find(*z.name) != discardedPolicies.end()) {
+    const auto zoneName = z->getName();
+    if(zoneName && discardedPolicies.find(*zoneName) != discardedPolicies.end()) {
       continue;
     }
 
-    if(auto fnd=z.propolNSAddr.lookup(address)) {
+    if(auto fnd=z->d_propolNSAddr.lookup(address)) {
       //      cerr<<"Had a hit on the nameserver ("<<address.toString()<<") used to process the query"<<endl;
       return fnd->second;;
     }
@@ -94,16 +96,17 @@ DNSFilterEngine::Policy DNSFilterEngine::getQueryPolicy(const DNSName& qname, co
   //  cout<<"Got question for "<<qname<<" from "<<ca.toString()<<endl;
   Policy pol;
   for(const auto& z : d_zones) {
-    if(z.name && discardedPolicies.find(*z.name) != discardedPolicies.end()) {
+    const auto zoneName = z->getName();
+    if(zoneName && discardedPolicies.find(*zoneName) != discardedPolicies.end()) {
       continue;
     }
 
-    if(findNamedPolicy(z.qpolName, qname, pol)) {
+    if(findNamedPolicy(z->d_qpolName, qname, pol)) {
       //      cerr<<"Had a hit on the name of the query"<<endl;
       return pol;
     }
     
-    if(auto fnd=z.qpolAddr.lookup(ca)) {
+    if(auto fnd=z->d_qpolAddr.lookup(ca)) {
       //       cerr<<"Had a hit on the IP address ("<<ca.toString()<<") of the client"<<endl;
       return fnd->second;
     }
@@ -132,11 +135,12 @@ DNSFilterEngine::Policy DNSFilterEngine::getPostPolicy(const vector<DNSRecord>&
       continue;
 
     for(const auto& z : d_zones) {
-      if(z.name && discardedPolicies.find(*z.name) != discardedPolicies.end()) {
+      const auto zoneName = z->getName();
+      if(zoneName && discardedPolicies.find(*zoneName) != discardedPolicies.end()) {
         continue;
       }
 
-      if(auto fnd=z.postpolAddr.lookup(ca))
+      if(auto fnd=z->d_postpolAddr.lookup(ca))
        return fnd->second;
     }
   }
@@ -149,98 +153,62 @@ void DNSFilterEngine::assureZones(size_t zone)
     d_zones.resize(zone+1);
 }
 
-void DNSFilterEngine::clear(size_t zone)
+void DNSFilterEngine::Zone::addClientTrigger(const Netmask& nm, Policy pol)
 {
-  assureZones(zone);
-  auto& z = d_zones[zone];
-  z.qpolAddr.clear();
-  z.postpolAddr.clear();
-  z.propolName.clear();
-  z.propolNSAddr.clear();
-  z.qpolName.clear();
+  pol.d_name = d_name;
+  d_qpolAddr.insert(nm).second=pol;
 }
 
-void DNSFilterEngine::clear()
+void DNSFilterEngine::Zone::addResponseTrigger(const Netmask& nm, Policy pol)
 {
-  for(auto& z : d_zones) {
-    z.qpolAddr.clear();
-    z.postpolAddr.clear();
-    z.propolName.clear();
-    z.propolNSAddr.clear();
-    z.qpolName.clear();
-  }
-}
-
-void DNSFilterEngine::addClientTrigger(const Netmask& nm, Policy pol, size_t zone)
-{
-  assureZones(zone);
-  pol.d_name = d_zones[zone].name;
-  d_zones[zone].qpolAddr.insert(nm).second=pol;
+  pol.d_name = d_name;
+  d_postpolAddr.insert(nm).second=pol;
 }
 
-void DNSFilterEngine::addResponseTrigger(const Netmask& nm, Policy pol, size_t zone)
+void DNSFilterEngine::Zone::addQNameTrigger(const DNSName& n, Policy pol)
 {
-  assureZones(zone);
-  pol.d_name = d_zones[zone].name;
-  d_zones[zone].postpolAddr.insert(nm).second=pol;
+  pol.d_name = d_name;
+  d_qpolName[n]=pol;
 }
 
-void DNSFilterEngine::addQNameTrigger(const DNSName& n, Policy pol, size_t zone)
+void DNSFilterEngine::Zone::addNSTrigger(const DNSName& n, Policy pol)
 {
-  assureZones(zone);
-  pol.d_name = d_zones[zone].name;
-  d_zones[zone].qpolName[n]=pol;
+  pol.d_name = d_name;
+  d_propolName[n]=pol;
 }
 
-void DNSFilterEngine::addNSTrigger(const DNSName& n, Policy pol, size_t zone)
+void DNSFilterEngine::Zone::addNSIPTrigger(const Netmask& nm, Policy pol)
 {
-  assureZones(zone);
-  pol.d_name = d_zones[zone].name;
-  d_zones[zone].propolName[n]=pol;
+  pol.d_name = d_name;
+  d_propolNSAddr.insert(nm).second = pol;
 }
 
-void DNSFilterEngine::addNSIPTrigger(const Netmask& nm, Policy pol, size_t zone)
+bool DNSFilterEngine::Zone::rmClientTrigger(const Netmask& nm, Policy pol)
 {
-  assureZones(zone);
-  pol.d_name = d_zones[zone].name;
-  d_zones[zone].propolNSAddr.insert(nm).second = pol;
-}
-
-bool DNSFilterEngine::rmClientTrigger(const Netmask& nm, Policy pol, size_t zone)
-{
-  assureZones(zone);
-
-  auto& qpols = d_zones[zone].qpolAddr;
-  qpols.erase(nm);
+  d_qpolAddr.erase(nm);
   return true;
 }
 
-bool DNSFilterEngine::rmResponseTrigger(const Netmask& nm, Policy pol, size_t zone)
+bool DNSFilterEngine::Zone::rmResponseTrigger(const Netmask& nm, Policy pol)
 {
-  assureZones(zone);
-  auto& postpols = d_zones[zone].postpolAddr;
-  postpols.erase(nm);  
+  d_postpolAddr.erase(nm);
   return true;
 }
 
-bool DNSFilterEngine::rmQNameTrigger(const DNSName& n, Policy pol, size_t zone)
+bool DNSFilterEngine::Zone::rmQNameTrigger(const DNSName& n, Policy pol)
 {
-  assureZones(zone);
-  d_zones[zone].qpolName.erase(n); // XXX verify we had identical policy?
+  d_qpolName.erase(n); // XXX verify we had identical policy?
   return true;
 }
 
-bool DNSFilterEngine::rmNSTrigger(const DNSName& n, Policy pol, size_t zone)
+bool DNSFilterEngine::Zone::rmNSTrigger(const DNSName& n, Policy pol)
 {
-  assureZones(zone);
-  d_zones[zone].propolName.erase(n); // XXX verify policy matched? =pol;
+  d_propolName.erase(n); // XXX verify policy matched? =pol;
   return true;
 }
 
-bool DNSFilterEngine::rmNSIPTrigger(const Netmask& nm, Policy pol, size_t zone)
+bool DNSFilterEngine::Zone::rmNSIPTrigger(const Netmask& nm, Policy pol)
 {
-  assureZones(zone);
-  auto& pols = d_zones[zone].propolNSAddr;
-  pols.erase(nm);
+  d_propolNSAddr.erase(nm);
   return true;
 }
index fb9ee4c1c44c1379bc5ba25f613ab6875ab3319a..abf647e2ae3fa62f4ccebdc565a49dea03a26f35 100644 (file)
@@ -80,48 +80,85 @@ public:
     int32_t d_ttl;
   };
 
-  DNSFilterEngine();
-  void clear();
-  void clear(size_t zone);
-  void reserve(size_t zone, size_t entriesCount) {
-    assureZones(zone);
-    d_zones[zone].qpolName.reserve(entriesCount);
-  }
-  void addClientTrigger(const Netmask& nm, Policy pol, size_t zone);
-  void addQNameTrigger(const DNSName& nm, Policy pol, size_t zone);
-  void addNSTrigger(const DNSName& dn, Policy pol, size_t zone);
-  void addNSIPTrigger(const Netmask& nm, Policy pol, size_t zone);
-  void addResponseTrigger(const Netmask& nm, Policy pol, size_t zone);
+  class Zone {
+  public:
+    void clear()
+    {
+      d_qpolAddr.clear();
+      d_postpolAddr.clear();
+      d_propolName.clear();
+      d_qpolName.clear();
+    }
+    void reserve(size_t entriesCount)
+    {
+      d_qpolName.reserve(entriesCount);
+    }
+    void setName(const std::string& name)
+    {
+      d_name = std::make_shared<std::string>(name);
+    }
+    const std::shared_ptr<std::string> getName() const
+    {
+      return d_name;
+    }
 
-  bool rmClientTrigger(const Netmask& nm, Policy pol, size_t zone);
-  bool rmQNameTrigger(const DNSName& nm, Policy pol, size_t zone);
-  bool rmNSTrigger(const DNSName& dn, Policy pol, size_t zone);
-  bool rmNSIPTrigger(const Netmask& nm, Policy pol, size_t zone);
-  bool rmResponseTrigger(const Netmask& nm, Policy pol, size_t zone);
+    void addClientTrigger(const Netmask& nm, Policy pol);
+    void addQNameTrigger(const DNSName& nm, Policy pol);
+    void addNSTrigger(const DNSName& dn, Policy pol);
+    void addNSIPTrigger(const Netmask& nm, Policy pol);
+    void addResponseTrigger(const Netmask& nm, Policy pol);
 
+    bool rmClientTrigger(const Netmask& nm, Policy pol);
+    bool rmQNameTrigger(const DNSName& nm, Policy pol);
+    bool rmNSTrigger(const DNSName& dn, Policy pol);
+    bool rmNSIPTrigger(const Netmask& nm, Policy pol);
+    bool rmResponseTrigger(const Netmask& nm, Policy pol);
+
+    std::unordered_map<DNSName, Policy> d_qpolName;   // QNAME trigger (RPZ)
+    NetmaskTree<Policy> d_qpolAddr;         // Source address
+    std::unordered_map<DNSName, Policy> d_propolName; // NSDNAME (RPZ)
+    NetmaskTree<Policy> d_propolNSAddr;     // NSIP (RPZ)
+    NetmaskTree<Policy> d_postpolAddr;      // IP trigger (RPZ)
+    std::shared_ptr<std::string> d_name;
+  };
+
+  DNSFilterEngine();
+  void clear()
+  {
+    for(auto& z : d_zones) {
+      z->clear();
+    }
+  }
+  const std::shared_ptr<Zone> getZone(size_t zoneIdx) const
+  {
+    std::shared_ptr<Zone> result{nullptr};
+    if (zoneIdx < d_zones.size()) {
+      result = d_zones[zoneIdx];
+    }
+    return result;
+  }
+  size_t addZone(std::shared_ptr<Zone> newZone)
+  {
+    d_zones.push_back(newZone);
+    return (d_zones.size() - 1);
+  }
+  void setZone(size_t zoneIdx, std::shared_ptr<Zone> newZone)
+  {
+    if (newZone) {
+      assureZones(zoneIdx);
+      d_zones[zoneIdx] = newZone;
+    }
+  }
 
   Policy getQueryPolicy(const DNSName& qname, const ComboAddress& nm, const std::unordered_map<std::string,bool>& discardedPolicies) const;
   Policy getProcessingPolicy(const DNSName& qname, const std::unordered_map<std::string,bool>& discardedPolicies) const;
   Policy getProcessingPolicy(const ComboAddress& address, const std::unordered_map<std::string,bool>& discardedPolicies) const;
   Policy getPostPolicy(const vector<DNSRecord>& records, const std::unordered_map<std::string,bool>& discardedPolicies) const;
 
-  size_t size() {
+  size_t size() const {
     return d_zones.size();
   }
-  void setPolicyName(size_t zoneIdx, std::string name)
-  {
-    assureZones(zoneIdx);
-    d_zones[zoneIdx].name = std::make_shared<std::string>(name);
-  }
 private:
   void assureZones(size_t zone);
-  struct Zone {
-    std::unordered_map<DNSName, Policy> qpolName;   // QNAME trigger (RPZ)
-    NetmaskTree<Policy> qpolAddr;         // Source address
-    std::unordered_map<DNSName, Policy> propolName; // NSDNAME (RPZ)
-    NetmaskTree<Policy> propolNSAddr;     // NSIP (RPZ)
-    NetmaskTree<Policy> postpolAddr;      // IP trigger (RPZ)
-    std::shared_ptr<std::string> name;
-  };
-  vector<Zone> d_zones;
+  vector<std::shared_ptr<Zone>> d_zones;
 };
index 5f816584aa3d118be69dfc182e421a5e8ebd9987..6c5e7e171e5d16c290fec63e05547be2dfdcd3b2 100644 (file)
@@ -114,19 +114,20 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
       try {
         boost::optional<DNSFilterEngine::Policy> defpol;
         std::string polName("rpzFile");
-        const size_t zoneIdx = lci.dfe.size();
+        std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
         uint32_t maxTTL = std::numeric_limits<uint32_t>::max();
         if(options) {
           auto& have = *options;
           size_t zoneSizeHint = 0;
           parseRPZParameters(have, polName, defpol, maxTTL, zoneSizeHint);
           if (zoneSizeHint > 0) {
-            lci.dfe.reserve(zoneIdx, zoneSizeHint);
+            zone->reserve(zoneSizeHint);
           }
         }
         theL()<<Logger::Warning<<"Loading RPZ from file '"<<filename<<"'"<<endl;
-        lci.dfe.setPolicyName(zoneIdx, polName);
-        loadRPZFromFile(filename, lci.dfe, defpol, maxTTL, zoneIdx);
+        zone->setName(polName);
+        loadRPZFromFile(filename, zone, defpol, maxTTL);
+        lci.dfe.addZone(zone);
         theL()<<Logger::Warning<<"Done loading RPZ from file '"<<filename<<"'"<<endl;
       }
       catch(std::exception& e) {
@@ -134,22 +135,22 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
       }
     });
 
-  Lua.writeFunction("rpzMaster", [&lci, checkOnly](const string& master_, const string& zone_, const boost::optional<std::unordered_map<string,boost::variant<uint32_t, string>>>& options) {
+  Lua.writeFunction("rpzMaster", [&lci, checkOnly](const string& master_, const string& zoneName, const boost::optional<std::unordered_map<string,boost::variant<uint32_t, string>>>& options) {
       try {
         boost::optional<DNSFilterEngine::Policy> defpol;
+        std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
         TSIGTriplet tt;
         uint32_t refresh=0;
-        std::string polName(zone_);
+        std::string polName(zoneName);
         size_t maxReceivedXFRMBytes = 0;
         uint32_t maxTTL = std::numeric_limits<uint32_t>::max();
         ComboAddress localAddress;
-        const size_t zoneIdx = lci.dfe.size();
         if(options) {
           auto& have = *options;
           size_t zoneSizeHint = 0;
           parseRPZParameters(have, polName, defpol, maxTTL, zoneSizeHint);
           if (zoneSizeHint > 0) {
-            lci.dfe.reserve(zoneIdx, zoneSizeHint);
+            zone->reserve(zoneSizeHint);
           }
           if(have.count("tsigname")) {
             tt.name=DNSName(toLower(boost::get<string>(constGet(have, "tsigname"))));
@@ -171,22 +172,23 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
         if (localAddress != ComboAddress() && localAddress.sin4.sin_family != master.sin4.sin_family)
           // We were passed a localAddress, check if its AF matches the master's
           throw PDNSException("Master address("+master.toString()+") is not of the same Address Family as the local address ("+localAddress.toString()+").");
-        DNSName zone(zone_);
-        lci.dfe.setPolicyName(zoneIdx, polName);
+        zone->setName(polName);
+        size_t zoneIdx = lci.dfe.addZone(zone);
 
         if (!checkOnly) {
-          auto sr=loadRPZFromServer(master, zone, lci.dfe, defpol, maxTTL, zoneIdx, tt, maxReceivedXFRMBytes * 1024 * 1024, localAddress);
+          auto sr=loadRPZFromServer(master, DNSName(zoneName), zone, defpol, maxTTL, tt, maxReceivedXFRMBytes * 1024 * 1024, localAddress);
           if(refresh)
             sr->d_st.refresh=refresh;
-          std::thread t(RPZIXFRTracker, master, zone, defpol, maxTTL, zoneIdx, tt, sr, maxReceivedXFRMBytes * 1024 * 1024, localAddress);
+
+          std::thread t(RPZIXFRTracker, master, DNSName(zoneName), defpol, maxTTL, zoneIdx, tt, sr, maxReceivedXFRMBytes * 1024 * 1024, localAddress);
           t.detach();
         }
       }
       catch(std::exception& e) {
-        theL()<<Logger::Error<<"Unable to load RPZ zone '"<<zone_<<"' from '"<<master_<<"': "<<e.what()<<endl;
+        theL()<<Logger::Error<<"Unable to load RPZ zone '"<<zoneName<<"' from '"<<master_<<"': "<<e.what()<<endl;
       }
       catch(PDNSException& e) {
-        theL()<<Logger::Error<<"Unable to load RPZ zone '"<<zone_<<"' from '"<<master_<<"': "<<e.reason<<endl;
+        theL()<<Logger::Error<<"Unable to load RPZ zone '"<<zoneName<<"' from '"<<master_<<"': "<<e.reason<<endl;
       }
 
     });
index 812ccb32f30ea763fa6c71f0164991d1690107c7..b3c28a8a68f4711417f4332d3db63aec141cb359 100644 (file)
@@ -2081,9 +2081,11 @@ BOOST_AUTO_TEST_CASE(test_nameserver_ipv4_rpz) {
 
   DNSFilterEngine::Policy pol;
   pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
+  std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
+  zone->setName("Unit test policy 0");
+  zone->addNSIPTrigger(Netmask(ns, 32), pol);
   auto luaconfsCopy = g_luaconfs.getCopy();
-  luaconfsCopy.dfe.setPolicyName(0, "Unit test policy 0");
-  luaconfsCopy.dfe.addNSIPTrigger(Netmask(ns, 32), pol, 0);
+  luaconfsCopy.dfe.addZone(zone);
   g_luaconfs.setState(luaconfsCopy);
 
   vector<DNSRecord> ret;
@@ -2121,9 +2123,11 @@ BOOST_AUTO_TEST_CASE(test_nameserver_ipv6_rpz) {
 
   DNSFilterEngine::Policy pol;
   pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
+  std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
+  zone->setName("Unit test policy 0");
+  zone->addNSIPTrigger(Netmask(ns, 128), pol);
   auto luaconfsCopy = g_luaconfs.getCopy();
-  luaconfsCopy.dfe.setPolicyName(0, "Unit test policy 0");
-  luaconfsCopy.dfe.addNSIPTrigger(Netmask(ns, 128), pol, 0);
+  luaconfsCopy.dfe.addZone(zone);
   g_luaconfs.setState(luaconfsCopy);
 
   vector<DNSRecord> ret;
@@ -2162,9 +2166,11 @@ BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz) {
 
   DNSFilterEngine::Policy pol;
   pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
+  std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
+  zone->setName("Unit test policy 0");
+  zone->addNSTrigger(nsName, pol);
   auto luaconfsCopy = g_luaconfs.getCopy();
-  luaconfsCopy.dfe.setPolicyName(0, "Unit test policy 0");
-  luaconfsCopy.dfe.addNSTrigger(nsName, pol, 0);
+  luaconfsCopy.dfe.addZone(zone);
   g_luaconfs.setState(luaconfsCopy);
 
   vector<DNSRecord> ret;
@@ -2203,10 +2209,12 @@ BOOST_AUTO_TEST_CASE(test_nameserver_name_rpz_disabled) {
 
   DNSFilterEngine::Policy pol;
   pol.d_kind = DNSFilterEngine::PolicyKind::Drop;
+  std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
+  zone->setName("Unit test policy 0");
+  zone->addNSIPTrigger(Netmask(ns, 128), pol);
+  zone->addNSTrigger(nsName, pol);
   auto luaconfsCopy = g_luaconfs.getCopy();
-  luaconfsCopy.dfe.setPolicyName(0, "Unit test policy 0");
-  luaconfsCopy.dfe.addNSIPTrigger(Netmask(ns, 128), pol, 0);
-  luaconfsCopy.dfe.addNSTrigger(nsName, pol, 0);
+  luaconfsCopy.dfe.addZone(zone);
   g_luaconfs.setState(luaconfsCopy);
 
   /* RPZ is disabled for this query, we should not be blocked */
index d319c4663f434770023f7b59bb6cf5b695419087..5a97903bea2e0c34a657e87eb3afa45a2c536247 100644 (file)
@@ -310,7 +310,7 @@ string reloadAuthAndForwards()
 }
 
 
-void RPZIXFRTracker(const ComboAddress& master, const DNSName& zone, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL, size_t polZone, const TSIGTriplet& tt, shared_ptr<SOARecordContent> oursr, size_t maxReceivedBytes, const ComboAddress& localAddress)
+void RPZIXFRTracker(const ComboAddress& master, const DNSName& zoneName, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL, size_t zoneIdx, const TSIGTriplet& tt, shared_ptr<SOARecordContent> oursr, size_t maxReceivedBytes, const ComboAddress& localAddress)
 {
   uint32_t refresh = oursr->d_st.refresh;
   for(;;) {
@@ -319,7 +319,7 @@ void RPZIXFRTracker(const ComboAddress& master, const DNSName& zone, boost::opti
 
     sleep(refresh);
     
-    L<<Logger::Info<<"Getting IXFR deltas for "<<zone<<" from "<<master.toStringWithPort()<<", our serial: "<<getRR<SOARecordContent>(dr)->d_st.serial<<endl;
+    L<<Logger::Info<<"Getting IXFR deltas for "<<zoneName<<" from "<<master.toStringWithPort()<<", our serial: "<<getRR<SOARecordContent>(dr)->d_st.serial<<endl;
     vector<pair<vector<DNSRecord>, vector<DNSRecord> > > deltas;
 
     ComboAddress local(localAddress);
@@ -327,23 +327,27 @@ void RPZIXFRTracker(const ComboAddress& master, const DNSName& zone, boost::opti
       local = getQueryLocalAddress(master.sin4.sin_family, 0);
 
     try {
-      deltas = getIXFRDeltas(master, zone, dr, tt, &local, maxReceivedBytes);
+      deltas = getIXFRDeltas(master, zoneName, dr, tt, &local, maxReceivedBytes);
     } catch(std::runtime_error& e ){
       L<<Logger::Warning<<e.what()<<endl;
       continue;
     }
     if(deltas.empty())
       continue;
-    L<<Logger::Info<<"Processing "<<deltas.size()<<" delta"<<addS(deltas)<<" for RPZ "<<zone<<endl;
+    L<<Logger::Info<<"Processing "<<deltas.size()<<" delta"<<addS(deltas)<<" for RPZ "<<zoneName<<endl;
+
+    auto luaconfsLocal = g_luaconfs.getLocal();
+    const std::shared_ptr<DNSFilterEngine::Zone> oldZone = luaconfsLocal->dfe.getZone(zoneIdx);
+    /* we need to make a _full copy_ of the zone we are going to work on */
+    std::shared_ptr<DNSFilterEngine::Zone> newZone = std::make_shared<DNSFilterEngine::Zone>(*oldZone);
 
-    auto luaconfsCopy = g_luaconfs.getCopy();
     int totremove=0, totadd=0;
     for(const auto& delta : deltas) {
       const auto& remove = delta.first;
       const auto& add = delta.second;
       if(remove.empty()) {
         L<<Logger::Warning<<"IXFR update is a whole new zone"<<endl;
-        luaconfsCopy.dfe.clear(polZone);
+        newZone->clear();
       }
       for(const auto& rr : remove) { // should always contain the SOA
         if(rr.d_type == QType::NS)
@@ -359,7 +363,7 @@ void RPZIXFRTracker(const ComboAddress& master, const DNSName& zone, boost::opti
        else {
           totremove++;
          L<<Logger::Debug<<"Had removal of "<<rr.d_name<<endl;
-         RPZRecordToPolicy(rr, luaconfsCopy.dfe, false, defpol, maxTTL, polZone);
+         RPZRecordToPolicy(rr, newZone, false, defpol, maxTTL);
        }
       }
 
@@ -368,7 +372,7 @@ void RPZIXFRTracker(const ComboAddress& master, const DNSName& zone, boost::opti
           continue;
        if(rr.d_type == QType::SOA) {
          auto newsr = getRR<SOARecordContent>(rr);
-         //      L<<Logger::Info<<"New SOA serial for "<<zone<<": "<<newsr->d_st.serial<<endl;
+         //      L<<Logger::Info<<"New SOA serial for "<<zoneName<<": "<<newsr->d_st.serial<<endl;
          if (newsr) {
            oursr = newsr;
          }
@@ -376,12 +380,19 @@ void RPZIXFRTracker(const ComboAddress& master, const DNSName& zone, boost::opti
        else {
           totadd++;
          L<<Logger::Debug<<"Had addition of "<<rr.d_name<<endl;
-         RPZRecordToPolicy(rr, luaconfsCopy.dfe, true, defpol, maxTTL, polZone);
+         RPZRecordToPolicy(rr, newZone, true, defpol, maxTTL);
        }
       }
     }
-    L<<Logger::Info<<"Had "<<totremove<<" RPZ removal"<<addS(totremove)<<", "<<totadd<<" addition"<<addS(totadd)<<" for "<<zone<<" New serial: "<<oursr->d_st.serial<<endl;
-    g_luaconfs.setState(luaconfsCopy);
+    L<<Logger::Info<<"Had "<<totremove<<" RPZ removal"<<addS(totremove)<<", "<<totadd<<" addition"<<addS(totadd)<<" for "<<zoneName<<" New serial: "<<oursr->d_st.serial<<endl;
+
+    /* we need to replace the existing zone with the new one,
+       but we don't want to touch anything else, especially other zones,
+       since they might have been updated by another RPZ IXFR tracker thread.
+    */
+    g_luaconfs.modify([zoneIdx, &newZone](LuaConfigItems& lci) {
+                        lci.dfe.setZone(zoneIdx, newZone);
+                      });
   }
 }
 
index 67c36f6ce05771386e1433d0386463f02902db1a..bddf4dd63e36f0d4c92f1ea8252d0903ea70361c 100644 (file)
@@ -58,7 +58,7 @@ static Netmask makeNetmaskFromRPZ(const DNSName& name)
   return Netmask(v6);
 }
 
-void RPZRecordToPolicy(const DNSRecord& dr, DNSFilterEngine& target, bool addOrRemove, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL, size_t place)
+void RPZRecordToPolicy(const DNSRecord& dr, std::shared_ptr<DNSFilterEngine::Zone> zone, bool addOrRemove, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL)
 {
   static const DNSName drop("rpz-drop."), truncate("rpz-tcp-only."), noaction("rpz-passthru.");
   static const DNSName rpzClientIP("rpz-client-ip"), rpzIP("rpz-ip"),
@@ -140,43 +140,43 @@ void RPZRecordToPolicy(const DNSRecord& dr, DNSFilterEngine& target, bool addOrR
   if(dr.d_name.isPartOf(rpzNSDname)) {
     DNSName filt=dr.d_name.makeRelative(rpzNSDname);
     if(addOrRemove)
-      target.addNSTrigger(filt, pol, place);
+      zone->addNSTrigger(filt, pol);
     else
-      target.rmNSTrigger(filt, pol, place);
+      zone->rmNSTrigger(filt, pol);
   } else       if(dr.d_name.isPartOf(rpzClientIP)) {
     DNSName filt=dr.d_name.makeRelative(rpzClientIP);
     auto nm=makeNetmaskFromRPZ(filt);
     if(addOrRemove)
-      target.addClientTrigger(nm, pol, place);
+      zone->addClientTrigger(nm, pol);
     else
-      target.rmClientTrigger(nm, pol, place);
+      zone->rmClientTrigger(nm, pol);
     
   } else       if(dr.d_name.isPartOf(rpzIP)) {
     // cerr<<"Should apply answer content IP policy: "<<dr.d_name<<endl;
     DNSName filt=dr.d_name.makeRelative(rpzIP);
     auto nm=makeNetmaskFromRPZ(filt);
     if(addOrRemove)
-      target.addResponseTrigger(nm, pol, place);
+      zone->addResponseTrigger(nm, pol);
     else
-      target.rmResponseTrigger(nm, pol, place);
+      zone->rmResponseTrigger(nm, pol);
   } else if(dr.d_name.isPartOf(rpzNSIP)) {
     DNSName filt=dr.d_name.makeRelative(rpzNSIP);
     auto nm=makeNetmaskFromRPZ(filt);
     if(addOrRemove)
-      target.addNSIPTrigger(nm, pol, place);
+      zone->addNSIPTrigger(nm, pol);
     else
-      target.rmNSIPTrigger(nm, pol, place);
+      zone->rmNSIPTrigger(nm, pol);
   } else {
     if(addOrRemove)
-      target.addQNameTrigger(dr.d_name, pol, place);
+      zone->addQNameTrigger(dr.d_name, pol);
     else
-      target.rmQNameTrigger(dr.d_name, pol, place);
+      zone->rmQNameTrigger(dr.d_name, pol);
   }
 }
 
-shared_ptr<SOARecordContent> loadRPZFromServer(const ComboAddress& master, const DNSName& zone, DNSFilterEngine& target, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL, size_t place, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress)
+shared_ptr<SOARecordContent> loadRPZFromServer(const ComboAddress& master, const DNSName& zoneName, std::shared_ptr<DNSFilterEngine::Zone> zone, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress)
 {
-  L<<Logger::Warning<<"Loading RPZ zone '"<<zone<<"' from "<<master.toStringWithPort()<<endl;
+  L<<Logger::Warning<<"Loading RPZ zone '"<<zoneName<<"' from "<<master.toStringWithPort()<<endl;
   if(!tt.name.empty())
     L<<Logger::Warning<<"With TSIG key '"<<tt.name<<"' of algorithm '"<<tt.algo<<"'"<<endl;
 
@@ -184,7 +184,7 @@ shared_ptr<SOARecordContent> loadRPZFromServer(const ComboAddress& master, const
   if (local == ComboAddress())
     local = getQueryLocalAddress(master.sin4.sin_family, 0);
 
-  AXFRRetriever axfr(master, zone, tt, &local, maxReceivedBytes);
+  AXFRRetriever axfr(master, zoneName, tt, &local, maxReceivedBytes);
   unsigned int nrecords=0;
   Resolver::res_t nop;
   vector<DNSRecord> chunk;
@@ -196,13 +196,13 @@ shared_ptr<SOARecordContent> loadRPZFromServer(const ComboAddress& master, const
        continue;
       }
 
-      dr.d_name.makeUsRelative(zone);
+      dr.d_name.makeUsRelative(zoneName);
       if(dr.d_type==QType::SOA) {
        sr = getRR<SOARecordContent>(dr);
        continue;
       }
 
-      RPZRecordToPolicy(dr, target, true, defpol, maxTTL, place);
+      RPZRecordToPolicy(dr, zone, true, defpol, maxTTL);
       nrecords++;
     } 
     if(last != time(0)) {
@@ -215,7 +215,7 @@ shared_ptr<SOARecordContent> loadRPZFromServer(const ComboAddress& master, const
 }
 
 // this function is silent - you do the logging
-int loadRPZFromFile(const std::string& fname, DNSFilterEngine& target, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL, size_t place)
+void loadRPZFromFile(const std::string& fname, std::shared_ptr<DNSFilterEngine::Zone> zone, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL)
 {
   ZoneParserTNG zpt(fname);
   DNSResourceRecord drr;
@@ -233,13 +233,11 @@ int loadRPZFromFile(const std::string& fname, DNSFilterEngine& target, boost::op
       }
       else {
        dr.d_name=dr.d_name.makeRelative(domain);
-       RPZRecordToPolicy(dr, target, true, defpol, maxTTL, place);
+       RPZRecordToPolicy(dr, zone, true, defpol, maxTTL);
       }
     }
     catch(PDNSException& pe) {
       throw PDNSException("Issue parsing '"+drr.qname.toString()+"' '"+drr.content+"' at "+zpt.getLineOfFile()+": "+pe.reason);
     }
   }
-  
-  return place;
 }
index 6026361bb9404be2b14e40fc569df5141086e6fb..83a367275a9964c83c22e419502be742007efcd0 100644 (file)
@@ -24,7 +24,7 @@
 #include <string>
 #include "dnsrecords.hh"
 
-int loadRPZFromFile(const std::string& fname, DNSFilterEngine& target, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL, size_t place);
-std::shared_ptr<SOARecordContent> loadRPZFromServer(const ComboAddress& master, const DNSName& zone, DNSFilterEngine& target, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL, size_t place, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress);
-void RPZRecordToPolicy(const DNSRecord& dr, DNSFilterEngine& target, bool addOrRemove, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL, size_t place);
-void RPZIXFRTracker(const ComboAddress& master, const DNSName& zone, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL, size_t polZone, const TSIGTriplet &tt, shared_ptr<SOARecordContent> oursr, size_t maxReceivedBytes, const ComboAddress& localAddress);
+void loadRPZFromFile(const std::string& fname, std::shared_ptr<DNSFilterEngine::Zone> zone, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL);
+std::shared_ptr<SOARecordContent> loadRPZFromServer(const ComboAddress& master, const DNSName& zoneName, std::shared_ptr<DNSFilterEngine::Zone> zone, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL, const TSIGTriplet& tt, size_t maxReceivedBytes, const ComboAddress& localAddress);
+void RPZRecordToPolicy(const DNSRecord& dr, std::shared_ptr<DNSFilterEngine::Zone> zone, bool addOrRemove, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL);
+void RPZIXFRTracker(const ComboAddress& master, const DNSName& zoneName, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL, size_t polZone, const TSIGTriplet &tt, shared_ptr<SOARecordContent> oursr, size_t maxReceivedBytes, const ComboAddress& localAddress);