]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
rec: Add support for dumping the in-memory RPZ zones to a file
authorRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 17 Aug 2017 09:17:56 +0000 (11:17 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 17 Aug 2017 09:17:56 +0000 (11:17 +0200)
pdns/filterpo.cc
pdns/filterpo.hh
pdns/rec-lua-conf.cc
pdns/rec_channel_rec.cc
pdns/recursordist/docs/manpages/rec_control.rst
pdns/reczones.cc
pdns/rpzloader.cc

index 8ef02f4db668f13bb38ae117fb531caeb4c6c502..a20380c70f302029d78f14598b100149b0871046 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
-#include "filterpo.hh"
+
+#include <cinttypes>
 #include <iostream>
+
+#include "filterpo.hh"
 #include "namespaces.hh"
 #include "dnsrecords.hh"
 
@@ -28,7 +31,44 @@ DNSFilterEngine::DNSFilterEngine()
 {
 }
 
-static bool findNamedPolicy(const std::unordered_map<DNSName, DNSFilterEngine::Policy>& polmap, const DNSName& qname, DNSFilterEngine::Policy& pol)
+bool DNSFilterEngine::Zone::findQNamePolicy(const DNSName& qname, DNSFilterEngine::Policy& pol) const
+{
+  return findNamedPolicy(d_qpolName, qname, pol);
+}
+
+bool DNSFilterEngine::Zone::findNSPolicy(const DNSName& qname, DNSFilterEngine::Policy& pol) const
+{
+  return findNamedPolicy(d_propolName, qname, pol);
+}
+
+bool DNSFilterEngine::Zone::findNSIPPolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const
+{
+  if (const auto fnd = d_propolNSAddr.lookup(addr)) {
+    pol = fnd->second;
+    return true;
+  }
+  return false;
+}
+
+bool DNSFilterEngine::Zone::findResponsePolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const
+{
+  if (const auto fnd = d_postpolAddr.lookup(addr)) {
+    pol = fnd->second;
+    return true;
+  }
+  return false;
+}
+
+bool DNSFilterEngine::Zone::findClientPolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const
+{
+  if (const auto fnd = d_qpolAddr.lookup(addr)) {
+    pol = fnd->second;
+    return true;
+  }
+  return false;
+}
+
+bool DNSFilterEngine::Zone::findNamedPolicy(const std::unordered_map<DNSName, DNSFilterEngine::Policy>& polmap, const DNSName& qname, DNSFilterEngine::Policy& pol) const
 {
   /* for www.powerdns.com, we need to check:
      www.powerdns.com.
@@ -66,7 +106,7 @@ DNSFilterEngine::Policy DNSFilterEngine::getProcessingPolicy(const DNSName& qnam
       continue;
     }
 
-    if(findNamedPolicy(z->d_propolName, qname, pol)) {
+    if(z->findNSPolicy(qname, pol)) {
       //      cerr<<"Had a hit on the nameserver ("<<qname<<") used to process the query"<<endl;
       return pol;
     }
@@ -76,6 +116,7 @@ DNSFilterEngine::Policy DNSFilterEngine::getProcessingPolicy(const DNSName& qnam
 
 DNSFilterEngine::Policy DNSFilterEngine::getProcessingPolicy(const ComboAddress& address, const std::unordered_map<std::string,bool>& discardedPolicies) const
 {
+  Policy pol;
   //  cout<<"Got question for nameserver IP "<<address.toString()<<endl;
   for(const auto& z : d_zones) {
     const auto zoneName = z->getName();
@@ -83,12 +124,12 @@ DNSFilterEngine::Policy DNSFilterEngine::getProcessingPolicy(const ComboAddress&
       continue;
     }
 
-    if(auto fnd=z->d_propolNSAddr.lookup(address)) {
+    if(z->findNSIPPolicy(address, pol)) {
       //      cerr<<"Had a hit on the nameserver ("<<address.toString()<<") used to process the query"<<endl;
-      return fnd->second;;
+      return pol;
     }
   }
-  return Policy();
+  return pol;
 }
 
 DNSFilterEngine::Policy DNSFilterEngine::getQueryPolicy(const DNSName& qname, const ComboAddress& ca, const std::unordered_map<std::string,bool>& discardedPolicies) const
@@ -101,14 +142,14 @@ DNSFilterEngine::Policy DNSFilterEngine::getQueryPolicy(const DNSName& qname, co
       continue;
     }
 
-    if(findNamedPolicy(z->d_qpolName, qname, pol)) {
+    if(z->findQNamePolicy(qname, pol)) {
       //      cerr<<"Had a hit on the name of the query"<<endl;
       return pol;
     }
-    
-    if(auto fnd=z->d_qpolAddr.lookup(ca)) {
+
+    if(z->findClientPolicy(ca, pol)) {
       //       cerr<<"Had a hit on the IP address ("<<ca.toString()<<") of the client"<<endl;
-      return fnd->second;
+      return pol;
     }
   }
 
@@ -117,9 +158,10 @@ DNSFilterEngine::Policy DNSFilterEngine::getQueryPolicy(const DNSName& qname, co
 
 DNSFilterEngine::Policy DNSFilterEngine::getPostPolicy(const vector<DNSRecord>& records, const std::unordered_map<std::string,bool>& discardedPolicies) const
 {
+  Policy pol;
   ComboAddress ca;
   for(const auto& r : records) {
-    if(r.d_place != DNSResourceRecord::ANSWER) 
+    if(r.d_place != DNSResourceRecord::ANSWER)
       continue;
     if(r.d_type == QType::A) {
       if (auto rec = getRR<ARecordContent>(r)) {
@@ -140,11 +182,12 @@ DNSFilterEngine::Policy DNSFilterEngine::getPostPolicy(const vector<DNSRecord>&
         continue;
       }
 
-      if(auto fnd=z->d_postpolAddr.lookup(ca))
-       return fnd->second;
+      if(z->findResponsePolicy(ca, pol)) {
+       return pol;
+      }
     }
   }
-  return Policy();
+  return pol;
 }
 
 void DNSFilterEngine::assureZones(size_t zone)
@@ -240,3 +283,131 @@ DNSRecord DNSFilterEngine::Policy::getCustomRecord(const DNSName& qname) const
 
   return result;
 }
+
+std::string DNSFilterEngine::Policy::getKindToString() const
+{
+  static const DNSName drop("rpz-drop."), truncate("rpz-tcp-only."), noaction("rpz-passthru.");
+  static const DNSName rpzClientIP("rpz-client-ip"), rpzIP("rpz-ip"),
+    rpzNSDname("rpz-nsdname"), rpzNSIP("rpz-nsip.");
+  static const std::string rpzPrefix("rpz-");
+
+  switch(d_kind) {
+  case DNSFilterEngine::PolicyKind::NoAction:
+    return noaction.toString();
+  case DNSFilterEngine::PolicyKind::Drop:
+    return drop.toString();
+  case DNSFilterEngine::PolicyKind::NXDOMAIN:
+    return g_rootdnsname.toString();
+  case PolicyKind::NODATA:
+    return g_wildcarddnsname.toString();
+  case DNSFilterEngine::PolicyKind::Truncate:
+    return truncate.toString();
+  default:
+    throw std::runtime_error("Unexpected DNSFilterEngine::Policy kind");
+  }
+}
+
+DNSRecord DNSFilterEngine::Policy::getRecord(const DNSName& qname) const
+{
+  DNSRecord dr;
+
+  if (d_kind == PolicyKind::Custom) {
+    dr = getCustomRecord(qname);
+  }
+  else {
+    dr.d_name = qname;
+    dr.d_ttl = static_cast<uint32_t>(d_ttl);
+    dr.d_type = QType::CNAME;
+    dr.d_class = QClass::IN;
+    dr.d_content = DNSRecordContent::mastermake(QType::CNAME, QClass::IN, getKindToString());
+  }
+
+  return dr;
+}
+
+void DNSFilterEngine::Zone::dumpNamedPolicy(FILE* fp, const DNSName& name, const Policy& pol) const
+{
+  DNSRecord dr = pol.getRecord(name);
+  fprintf(fp, "%s %" PRIu32 " IN %s %s\n", dr.d_name.toString().c_str(), dr.d_ttl, QType(dr.d_type).getName().c_str(), dr.d_content->getZoneRepresentation().c_str());
+}
+
+DNSName DNSFilterEngine::Zone::maskToRPZ(const Netmask& nm)
+{
+  int bits = nm.getBits();
+  DNSName res(std::to_string(bits));
+  const auto addr = nm.getNetwork();
+
+  if (addr.isIPv4()) {
+    const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&addr.sin4.sin_addr.s_addr);
+    res += DNSName(std::to_string(bytes[3]) + "." + std::to_string(bytes[2]) + "." + std::to_string(bytes[1]) + "." + std::to_string(bytes[0]));
+  }
+  else {
+    DNSName temp;
+    const auto str = addr.toString();
+    const auto len = str.size();
+    std::string::size_type begin = 0;
+
+    while (begin < len) {
+      std::string::size_type end = str.find(":", begin);
+      std::string sub;
+      if (end != string::npos) {
+        sub = str.substr(begin, end - begin);
+      }
+      else {
+        sub = str.substr(begin);
+      }
+
+      if (sub.empty()) {
+        temp = DNSName("zz") + temp;
+      }
+      else {
+        temp = DNSName(sub) + temp;
+      }
+
+      if (end == string::npos) {
+        break;
+      }
+      begin = end + 1;
+    }
+    res += temp;
+  }
+
+  return res;
+}
+
+
+void DNSFilterEngine::Zone::dumpAddrPolicy(FILE* fp, const Netmask& nm, const DNSName& name, const Policy& pol) const
+{
+  DNSName full = maskToRPZ(nm);
+  full += name;
+
+  DNSRecord dr = pol.getRecord(full);
+  fprintf(fp, "%s %" PRIu32 " IN %s %s\n", dr.d_name.toString().c_str(), dr.d_ttl, QType(dr.d_type).getName().c_str(), dr.d_content->getZoneRepresentation().c_str());
+}
+
+void DNSFilterEngine::Zone::dump(FILE* fp) const
+{
+  /* fake the SOA record */
+  auto soa = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "fake.RPZ. hostmaster.fake.RPZ. " + std::to_string(d_serial) + " " + std::to_string(d_refresh) + " 600 3600000 604800");
+  fprintf(fp, "%s IN SOA %s\n", d_domain.toString().c_str(), soa->getZoneRepresentation().c_str());
+
+  for (const auto& pair : d_qpolName) {
+    dumpNamedPolicy(fp, pair.first + d_domain, pair.second);
+  }
+
+  for (const auto& pair : d_propolName) {
+    dumpNamedPolicy(fp, pair.first + DNSName("rpz-nsdname.") + d_domain, pair.second);
+  }
+
+  for (const auto pair : d_qpolAddr) {
+    dumpAddrPolicy(fp, pair->first, DNSName("rpz-client-ip.") + d_domain, pair->second);
+  }
+
+  for (const auto pair : d_propolNSAddr) {
+    dumpAddrPolicy(fp, pair->first, DNSName("rpz-nsip.") + d_domain, pair->second);
+  }
+
+  for (const auto pair : d_postpolAddr) {
+    dumpAddrPolicy(fp, pair->first, DNSName("rpz-ip.") + d_domain, pair->second);
+  }
+}
index e2ddd91853853fa851dabb4620d4104215e8001b..3e757914dca80c8c69855d03ac59f4c73ac453a8 100644 (file)
@@ -22,6 +22,7 @@
 #pragma once
 #include "iputils.hh"
 #include "dns.hh"
+#include "dnsname.hh"
 #include "dnsparser.hh"
 #include <map>
 #include <unordered_map>
 
 
    We know the following actions:
-   
+
    No action - just pass it on
    Drop - drop a query, no response
-   NXDOMAIN - fake up an NXDOMAIN for the query 
+   NXDOMAIN - fake up an NXDOMAIN for the query
    NODATA - just return no data for this qtype
    Truncate - set TC bit
    Modified - "we fake an answer for you"
 
    These actions can be caused by the following triggers:
-   
+
    qname - the query name
    client-ip - the IP address of the requestor
    response-ip - an IP address in the response
@@ -57,7 +58,7 @@
    Wildcard versions (*.domain.com does NOT match domain.com)
    Netmasks (IPv4 and IPv6)
    Finally, triggers are grouped in different zones. The "first" zone that has a match
-   is consulted. Then within that zone, rules again have precedences. 
+   is consulted. Then within that zone, rules again have precedences.
 */
 
 
@@ -74,7 +75,10 @@ public:
     {
       return d_kind == rhs.d_kind; // XXX check d_custom too!
     }
+    std::string getKindToString() const;
     DNSRecord getCustomRecord(const DNSName& qname) const;
+    DNSRecord getRecord(const DNSName& qname) const;
+
     PolicyKind d_kind;
     std::shared_ptr<DNSRecordContent> d_custom;
     std::shared_ptr<std::string> d_name;
@@ -99,10 +103,23 @@ public:
     {
       d_name = std::make_shared<std::string>(name);
     }
+    void setDomain(const DNSName& domain)
+    {
+      d_domain = domain;
+    }
+    void setSerial(uint32_t serial)
+    {
+      d_serial = serial;
+    }
+    void setRefresh(uint32_t refresh)
+    {
+      d_refresh = refresh;
+    }
     const std::shared_ptr<std::string> getName() const
     {
       return d_name;
     }
+    void dump(FILE * fp) const;
 
     void addClientTrigger(const Netmask& nm, Policy pol);
     void addQNameTrigger(const DNSName& nm, Policy pol);
@@ -116,12 +133,27 @@ public:
     bool rmNSIPTrigger(const Netmask& nm, Policy pol);
     bool rmResponseTrigger(const Netmask& nm, Policy pol);
 
+    bool findQNamePolicy(const DNSName& qname, DNSFilterEngine::Policy& pol) const;
+    bool findNSPolicy(const DNSName& qname, DNSFilterEngine::Policy& pol) const;
+    bool findNSIPPolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const;
+    bool findResponsePolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const;
+    bool findClientPolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const;
+
+  private:
+    static DNSName maskToRPZ(const Netmask& nm);
+    bool findNamedPolicy(const std::unordered_map<DNSName, DNSFilterEngine::Policy>& polmap, const DNSName& qname, DNSFilterEngine::Policy& pol) const;
+    void dumpNamedPolicy(FILE* fp, const DNSName& name, const Policy& pol) const;
+    void dumpAddrPolicy(FILE* fp, const Netmask& nm, const DNSName& name, const Policy& pol) const;
+
     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)
+    DNSName d_domain;
     std::shared_ptr<std::string> d_name;
+    uint32_t d_serial{0};
+    uint32_t d_refresh{0};
   };
 
   DNSFilterEngine();
@@ -139,6 +171,16 @@ public:
     }
     return result;
   }
+  const std::shared_ptr<Zone> getZone(const std::string& name) const
+  {
+    for (const auto zone : d_zones) {
+      const auto& zName = zone->getName();
+      if (zName && *zName == name) {
+        return zone;
+      }
+    }
+    return nullptr;
+  }
   size_t addZone(std::shared_ptr<Zone> newZone)
   {
     d_zones.push_back(newZone);
index 9e0c8a469bc040dd5a117874aca8c19b83c7b1de..da2d7491e7cb19d898eac258ea8dd9d5a7bed8b7 100644 (file)
@@ -128,7 +128,7 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
         lci.dfe.addZone(zone);
         theL()<<Logger::Warning<<"Done loading RPZ from file '"<<filename<<"'"<<endl;
       }
-      catch(std::exception& e) {
+      catch(const std::exception& e) {
         theL()<<Logger::Error<<"Unable to load RPZ zone from '"<<filename<<"': "<<e.what()<<endl;
       }
     });
@@ -167,25 +167,31 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
           }
         }
         ComboAddress master(master_, 53);
-        if (localAddress != ComboAddress() && localAddress.sin4.sin_family != master.sin4.sin_family)
+        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 domain(zoneName);
+        zone->setDomain(domain);
         zone->setName(polName);
+        zone->setRefresh(refresh);
         size_t zoneIdx = lci.dfe.addZone(zone);
 
         if (!checkOnly) {
-          auto sr=loadRPZFromServer(master, DNSName(zoneName), zone, defpol, maxTTL, tt, maxReceivedXFRMBytes * 1024 * 1024, localAddress);
+          auto sr=loadRPZFromServer(master, domain, zone, defpol, maxTTL, tt, maxReceivedXFRMBytes * 1024 * 1024, localAddress);
           if(refresh)
             sr->d_st.refresh=refresh;
+          zone->setSerial(sr->d_st.serial);
 
           std::thread t(RPZIXFRTracker, master, DNSName(zoneName), defpol, maxTTL, zoneIdx, tt, sr, maxReceivedXFRMBytes * 1024 * 1024, localAddress);
           t.detach();
         }
       }
-      catch(std::exception& e) {
+      catch(const std::exception& e) {
         theL()<<Logger::Error<<"Unable to load RPZ zone '"<<zoneName<<"' from '"<<master_<<"': "<<e.what()<<endl;
       }
-      catch(PDNSException& e) {
+      catch(const PDNSException& e) {
         theL()<<Logger::Error<<"Unable to load RPZ zone '"<<zoneName<<"' from '"<<master_<<"': "<<e.reason<<endl;
       }
 
index 2d086f1ed426a405248d600698df118106a60688..53be4e1b669d55eef3b6ce812a3bfcda993db31d 100644 (file)
@@ -261,6 +261,46 @@ string doDumpEDNSStatus(T begin, T end)
   return "done\n";
 }
 
+template<typename T>
+string doDumpRPZ(T begin, T end)
+{
+  T i=begin;
+
+  if (i == end) {
+    return "No zone name specified\n";
+  }
+  string zoneName = *i;
+  i++;
+
+  if (i == end) {
+    return "No file name specified\n";
+  }
+  string fname = *i;
+
+  auto luaconf = g_luaconfs.getLocal();
+  const auto zone = luaconf->dfe.getZone(zoneName);
+  if (!zone) {
+    return "No RPZ zone named "+zoneName+"\n";
+  }
+
+  int fd = open(fname.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660);
+
+  if(fd < 0) {
+    return "Error opening dump file for writing: "+string(strerror(errno))+"\n";
+  }
+
+  FILE* fp = fdopen(fd, "w");
+  if (!fp) {
+    close(fd);
+    return "Error converting file descriptor: "+string(strerror(errno))+"\n";
+  }
+
+  zone->dump(fp);
+  fclose(fp);
+
+  return "done\n";
+}
+
 uint64_t* pleaseWipeCache(const DNSName& canon, bool subtree)
 {
   return new uint64_t(t_RC->doWipeCache(canon, subtree));
@@ -1150,6 +1190,7 @@ string RecursorControlParser::getAnswer(const string& question, RecursorControlP
 "dump-cache <filename>            dump cache contents to the named file\n"
 "dump-edns [status] <filename>    dump EDNS status to the named file\n"
 "dump-nsspeeds <filename>         dump nsspeeds statistics to the named file\n"
+"dump-rpz <zone name> <filename>  dump the content of a RPZ zone to the named file\n"
 "get [key1] [key2] ..             get specific statistics\n"
 "get-all                          get all statistics\n"
 "get-ntas                         get all configured Negative Trust Anchors\n"
@@ -1183,10 +1224,10 @@ string RecursorControlParser::getAnswer(const string& question, RecursorControlP
   if(cmd=="get-all")
     return getAllStats();
 
-  if(cmd=="get") 
+  if(cmd=="get")
     return doGet(begin, end);
-  
-  if(cmd=="get-parameter") 
+
+  if(cmd=="get-parameter")
     return doGetParameter(begin, end);
 
   if(cmd=="quit") {
@@ -1197,25 +1238,29 @@ string RecursorControlParser::getAnswer(const string& question, RecursorControlP
   if(cmd=="version") {
     return getPDNSVersion()+"\n";
   }
-  
+
   if(cmd=="quit-nicely") {
     *command=&doExitNicely;
     return "bye nicely\n";
-  }  
+  }
 
-  if(cmd=="dump-cache") 
+  if(cmd=="dump-cache")
     return doDumpCache(begin, end);
 
-  if(cmd=="dump-ednsstatus" || cmd=="dump-edns") 
+  if(cmd=="dump-ednsstatus" || cmd=="dump-edns")
     return doDumpEDNSStatus(begin, end);
 
   if(cmd=="dump-nsspeeds")
     return doDumpNSSpeeds(begin, end);
 
-  if(cmd=="wipe-cache" || cmd=="flushname") 
+  if(cmd=="dump-rpz") {
+    return doDumpRPZ(begin, end);
+  }
+
+  if(cmd=="wipe-cache" || cmd=="flushname")
     return doWipeCache(begin, end);
 
-  if(cmd=="reload-lua-script") 
+  if(cmd=="reload-lua-script")
     return doQueueReloadLuaScript(begin, end);
 
   if(cmd=="reload-lua-config") {
@@ -1235,10 +1280,10 @@ string RecursorControlParser::getAnswer(const string& question, RecursorControlP
     }
   }
 
-  if(cmd=="set-carbon-server") 
+  if(cmd=="set-carbon-server")
     return doSetCarbonServer(begin, end);
 
-  if(cmd=="trace-regex") 
+  if(cmd=="trace-regex")
     return doTraceRegex(begin, end);
 
   if(cmd=="unload-lua-script") {
index c0e5303875d559e65736b1eaf607039f8a9d69bf..352b5d577c2fae1d96ca9822bba45e162840662e 100644 (file)
@@ -85,6 +85,12 @@ dump-nsspeeds *FILENAME*
     dumping, the recursor will not answer questions. Statistics are kept per
     thread, and the dumps end up in the same file.
 
+dump-rpz *ZONE NAME* *FILE NAME*
+    Dumps the content of the RPZ zone named *ZONE NAME* to the *FILENAME*
+    mentioned. This file should not exist already, PowerDNS will refuse to
+    overwrite it otherwise. While dumping, the recursor will not answer
+    questions.
+
 get *STATISTIC* [*STATISTIC*]...
     Retrieve a statistic. For items that can be queried, see
     :doc:`../metrics`
index 53c90edea1678bbe7d7c6d96abeae3e56eadb337..c1d46543c441bfe6f6cdfa4d3475c0aa305120b3 100644 (file)
@@ -390,6 +390,7 @@ void RPZIXFRTracker(const ComboAddress& master, const DNSName& zoneName, boost::
       }
     }
     L<<Logger::Info<<"Had "<<totremove<<" RPZ removal"<<addS(totremove)<<", "<<totadd<<" addition"<<addS(totadd)<<" for "<<zoneName<<" New serial: "<<oursr->d_st.serial<<endl;
+    newZone->setSerial(oursr->d_st.serial);
 
     /* we need to replace the existing zone with the new one,
        but we don't want to touch anything else, especially other zones,
index bddf4dd63e36f0d4c92f1ea8252d0903ea70361c..b5977d9d0467d0976c420844b25fb002ba1ae43f 100644 (file)
@@ -143,7 +143,7 @@ void RPZRecordToPolicy(const DNSRecord& dr, std::shared_ptr<DNSFilterEngine::Zon
       zone->addNSTrigger(filt, pol);
     else
       zone->rmNSTrigger(filt, pol);
-  } else       if(dr.d_name.isPartOf(rpzClientIP)) {
+  } else if(dr.d_name.isPartOf(rpzClientIP)) {
     DNSName filt=dr.d_name.makeRelative(rpzClientIP);
     auto nm=makeNetmaskFromRPZ(filt);
     if(addOrRemove)
@@ -151,7 +151,7 @@ void RPZRecordToPolicy(const DNSRecord& dr, std::shared_ptr<DNSFilterEngine::Zon
     else
       zone->rmClientTrigger(nm, pol);
     
-  } else       if(dr.d_name.isPartOf(rpzIP)) {
+  } 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);
@@ -226,7 +226,8 @@ void loadRPZFromFile(const std::string& fname, std::shared_ptr<DNSFilterEngine::
        drr.content=".";
       DNSRecord dr(drr);
       if(dr.d_type == QType::SOA) {
-       domain = dr.d_name;
+        domain = dr.d_name;
+        zone->setDomain(domain);
       }
       else if(dr.d_type == QType::NS) {
        continue;
@@ -236,7 +237,7 @@ void loadRPZFromFile(const std::string& fname, std::shared_ptr<DNSFilterEngine::
        RPZRecordToPolicy(dr, zone, true, defpol, maxTTL);
       }
     }
-    catch(PDNSException& pe) {
+    catch(const PDNSException& pe) {
       throw PDNSException("Issue parsing '"+drr.qname.toString()+"' '"+drr.content+"' at "+zpt.getLineOfFile()+": "+pe.reason);
     }
   }