]> granicus.if.org Git - pdns/commitdiff
Move rectifyZone from pdnsutil to DNSSECKeeper
authorPieter Lexis <pieter.lexis@powerdns.com>
Wed, 4 Oct 2017 14:20:07 +0000 (16:20 +0200)
committerPieter Lexis <pieter.lexis@powerdns.com>
Tue, 17 Oct 2017 14:17:15 +0000 (16:17 +0200)
pdns/dbdnsseckeeper.cc
pdns/dnsseckeeper.hh
pdns/pdnsutil.cc

index 86e89f7e33a8ae63fca8129ecea74bfcd2c81b43..514043216e0528863a2693a4fc8a7ad55dd66857 100644 (file)
@@ -35,6 +35,7 @@
 #include <boost/format.hpp>
 #include <boost/assign/std/vector.hpp> // for 'operator+=()'
 #include <boost/assign/list_inserter.hpp>
+#include "base32.hh"
 #include "base64.hh"
 #include "cachecleaner.hh"
 #include "arguments.hh"
@@ -563,6 +564,181 @@ bool DNSSECKeeper::getTSIGForAccess(const DNSName& zone, const string& master, D
   return false;
 }
 
+bool DNSSECKeeper::rectifyZone(const DNSName& zone, string& error) {
+  if (isPresigned(zone)) {
+    error =  "Rectify presigned zone '"+zone.toLogString()+"' is not allowed/necessary.";
+    return false;
+  }
+
+  UeberBackend B("default");
+  SOAData sd;
+
+  if(!B.getSOAUncached(zone, sd)) {
+    error = "No SOA known for '" + zone.toLogString() + "', is such a zone in the database?";
+    return false;
+  }
+
+  sd.db->list(zone, sd.domain_id);
+
+  DNSResourceRecord rr;
+  set<DNSName> qnames, nsset, dsnames, insnonterm, delnonterm;
+  map<DNSName,bool> nonterm;
+  vector<DNSResourceRecord> rrs;
+
+  while(sd.db->get(rr)) {
+    rr.qname.makeUsLowerCase();
+    if (rr.qtype.getCode())
+    {
+      rrs.push_back(rr);
+      qnames.insert(rr.qname);
+      if(rr.qtype.getCode() == QType::NS && rr.qname != zone)
+        nsset.insert(rr.qname);
+      if(rr.qtype.getCode() == QType::DS)
+        dsnames.insert(rr.qname);
+    }
+    else
+      delnonterm.insert(rr.qname);
+  }
+
+  NSEC3PARAMRecordContent ns3pr;
+  bool narrow;
+  bool haveNSEC3 = getNSEC3PARAM(zone, &ns3pr, &narrow);
+  bool isOptOut = (haveNSEC3 && ns3pr.d_flags);
+
+  set<DNSName> nsec3set;
+  if (haveNSEC3 && !narrow) {
+    for (auto &rr: rrs) {
+      bool skip=false;
+      DNSName shorter = rr.qname;
+      if (shorter != zone && shorter.chopOff() && shorter != zone) {
+        do {
+          if(nsset.count(shorter)) {
+            skip=true;
+            break;
+          }
+        } while(shorter.chopOff() && shorter != zone);
+      }
+      shorter = rr.qname;
+      if(!skip && (rr.qtype.getCode() != QType::NS || !isOptOut)) {
+
+        do {
+          if(!nsec3set.count(shorter)) {
+            nsec3set.insert(shorter);
+          }
+        } while(shorter != zone && shorter.chopOff());
+      }
+    }
+  }
+
+  sd.db->startTransaction(zone, -1);
+
+  bool realrr=true;
+  bool doent=true;
+  uint32_t maxent = ::arg().asNum("max-ent-entries");
+
+  dononterm:;
+  for (const auto& qname: qnames)
+  {
+    bool auth=true;
+    DNSName ordername;
+    auto shorter(qname);
+
+    if(realrr) {
+      do {
+        if(nsset.count(shorter)) {
+          auth=false;
+          break;
+        }
+      } while(shorter.chopOff());
+    } else {
+      auth=nonterm.find(qname)->second;
+    }
+
+    if(haveNSEC3) // NSEC3
+    {
+      if(!narrow && nsec3set.count(qname)) {
+        ordername=DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, qname)));
+        if(!realrr)
+          auth=true;
+      } else if(!realrr)
+        auth=false;
+    }
+    else if (realrr) // NSEC
+      ordername=qname.makeRelative(zone);
+
+    /*
+    if(g_verbose)
+      cerr<<"'"<<qname<<"' -> '"<< ordername <<"'"<<endl;
+      */
+    sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, auth);
+
+    if(realrr)
+    {
+      if (dsnames.count(qname))
+        sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, true, QType::DS);
+      if (!auth || nsset.count(qname)) {
+        ordername.clear();
+        if(isOptOut && !dsnames.count(qname))
+          sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, false, QType::NS);
+        sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, false, QType::A);
+        sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, false, QType::AAAA);
+      }
+
+      if(doent)
+      {
+        shorter=qname;
+        while(shorter!=zone && shorter.chopOff())
+        {
+          if(!qnames.count(shorter))
+          {
+            if(!(maxent))
+            {
+              L<<Logger::Warning<<"Zone '"<<zone<<"' has too many empty non terminals."<<endl;
+              insnonterm.clear();
+              delnonterm.clear();
+              doent=false;
+              break;
+            }
+
+            if (!delnonterm.count(shorter) && !nonterm.count(shorter))
+              insnonterm.insert(shorter);
+            else
+              delnonterm.erase(shorter);
+
+            if (!nonterm.count(shorter)) {
+              nonterm.insert(pair<DNSName, bool>(shorter, auth));
+              --maxent;
+            } else if (auth)
+              nonterm[shorter]=true;
+          }
+        }
+      }
+    }
+  }
+
+  if(realrr)
+  {
+    //cerr<<"Total: "<<nonterm.size()<<" Insert: "<<insnonterm.size()<<" Delete: "<<delnonterm.size()<<endl;
+    if(!insnonterm.empty() || !delnonterm.empty() || !doent)
+    {
+      sd.db->updateEmptyNonTerminals(sd.domain_id, insnonterm, delnonterm, !doent);
+    }
+    if(doent)
+    {
+      realrr=false;
+      qnames.clear();
+      for(const auto& nt :  nonterm){
+        qnames.insert(nt.first);
+      }
+      goto dononterm;
+    }
+  }
+
+  sd.db->commitTransaction();
+
+  return true;
+}
+
 void DNSSECKeeper::cleanup()
 {
   struct timeval now;
index a84e4976237772bc983cbb1fc2b0864e6d69d6fd..12ba7548011251ff2162ce230d9d0307308fb3cb 100644 (file)
@@ -209,6 +209,7 @@ public:
   
   void getFromMeta(const DNSName& zname, const std::string& key, std::string& value);
   void getSoaEdit(const DNSName& zname, std::string& value);
+  bool rectifyZone(const DNSName& zone, std::string& error);
 private:
 
 
index db522db8d6b2f73160a82e510ed4e0275df81b55..d2e6900efddf557504951cf783247217fc1e5342 100644 (file)
@@ -135,196 +135,14 @@ void loadMainConfig(const std::string& configdir)
   UeberBackend::go();
 }
 
-// irritatingly enough, rectifyZone needs its own ueberbackend and can't therefore benefit from transactions outside its scope
-// I think this has to do with interlocking transactions between B and DK, but unsure.
 bool rectifyZone(DNSSECKeeper& dk, const DNSName& zone)
 {
-  if(dk.isPresigned(zone)){
-    cerr<<"Rectify presigned zone '"<<zone<<"' is not allowed/necessary."<<endl;
-    return false;
-  }
-
-  UeberBackend B("default");
-  bool doTransaction=true; // but see above
-  SOAData sd;
-
-  if(!B.getSOAUncached(zone, sd)) {
-    cerr<<"No SOA known for '"<<zone<<"', is such a zone in the database?"<<endl;
-    return false;
-  }
-  sd.db->list(zone, sd.domain_id);
-
-  DNSResourceRecord rr;
-  set<DNSName> qnames, nsset, dsnames, insnonterm, delnonterm;
-  map<DNSName,bool> nonterm;
-  vector<DNSResourceRecord> rrs;
-
-  while(sd.db->get(rr)) {
-    rr.qname.makeUsLowerCase();
-    if (rr.qtype.getCode())
-    {
-      rrs.push_back(rr);
-      qnames.insert(rr.qname);
-      if(rr.qtype.getCode() == QType::NS && rr.qname != zone)
-        nsset.insert(rr.qname);
-      if(rr.qtype.getCode() == QType::DS)
-        dsnames.insert(rr.qname);
-    }
-    else
-      delnonterm.insert(rr.qname);
-  }
-
-  NSEC3PARAMRecordContent ns3pr;
-  bool narrow;
-  bool haveNSEC3=dk.getNSEC3PARAM(zone, &ns3pr, &narrow);
-  bool isOptOut=(haveNSEC3 && ns3pr.d_flags);
-  if(dk.isSecuredZone(zone))
-  {
-    if(!haveNSEC3)
-      cerr<<"Adding NSEC ordering information "<<endl;
-    else if(!narrow) {
-      if(!isOptOut)
-        cerr<<"Adding NSEC3 hashed ordering information for '"<<zone<<"'"<<endl;
-      else
-        cerr<<"Adding NSEC3 opt-out hashed ordering information for '"<<zone<<"'"<<endl;
-    } else
-      cerr<<"Erasing NSEC3 ordering since we are narrow, only setting 'auth' fields"<<endl;
-  }
-  else
-    cerr<<"Adding empty non-terminals for non-DNSSEC zone"<<endl;
-
-  set<DNSName> nsec3set;
-  if (haveNSEC3 && !narrow) {
-    for (auto &rr: rrs) {
-      bool skip=false;
-      DNSName shorter = rr.qname;
-      if (shorter != zone && shorter.chopOff() && shorter != zone) {
-        do {
-          if(nsset.count(shorter)) {
-            skip=true;
-            break;
-          }
-        } while(shorter.chopOff() && shorter != zone);
-      }
-      shorter = rr.qname;
-      if(!skip && (rr.qtype.getCode() != QType::NS || !isOptOut)) {
-
-        do {
-          if(!nsec3set.count(shorter)) {
-            nsec3set.insert(shorter);
-          }
-        } while(shorter != zone && shorter.chopOff());
-      }
-    }
-  }
-
-  if(doTransaction)
-    sd.db->startTransaction(zone, -1);
-
-  bool realrr=true;
-  bool doent=true;
-  uint32_t maxent = ::arg().asNum("max-ent-entries");
-
-  dononterm:;
-  for (const auto& qname: qnames)
-  {
-    bool auth=true;
-    DNSName ordername;
-    auto shorter(qname);
-
-    if(realrr) {
-      do {
-        if(nsset.count(shorter)) {
-          auth=false;
-          break;
-        }
-      } while(shorter.chopOff());
-    } else {
-      auth=nonterm.find(qname)->second;
-    }
-
-    if(haveNSEC3) // NSEC3
-    {
-      if(!narrow && nsec3set.count(qname)) {
-        ordername=DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, qname)));
-        if(!realrr)
-          auth=true;
-      } else if(!realrr)
-        auth=false;
-    }
-    else if (realrr) // NSEC
-      ordername=qname.makeRelative(zone);
-
-    if(g_verbose)
-      cerr<<"'"<<qname<<"' -> '"<< ordername <<"'"<<endl;
-    sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, auth);
-
-    if(realrr)
-    {
-      if (dsnames.count(qname))
-        sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, true, QType::DS);
-      if (!auth || nsset.count(qname)) {
-        ordername.clear();
-        if(isOptOut && !dsnames.count(qname))
-          sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, false, QType::NS);
-        sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, false, QType::A);
-        sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, false, QType::AAAA);
-      }
-
-      if(doent)
-      {
-        shorter=qname;
-        while(shorter!=zone && shorter.chopOff())
-        {
-          if(!qnames.count(shorter))
-          {
-            if(!(maxent))
-            {
-              cerr<<"Zone '"<<zone<<"' has too many empty non terminals."<<endl;
-              insnonterm.clear();
-              delnonterm.clear();
-              doent=false;
-              break;
-            }
-
-            if (!delnonterm.count(shorter) && !nonterm.count(shorter))
-              insnonterm.insert(shorter);
-            else
-              delnonterm.erase(shorter);
-
-            if (!nonterm.count(shorter)) {
-              nonterm.insert(pair<DNSName, bool>(shorter, auth));
-              --maxent;
-            } else if (auth)
-              nonterm[shorter]=true;
-          }
-        }
-      }
-    }
+  string error;
+  bool ret = dk.rectifyZone(zone, error);
+  if (!ret) {
+    cerr<<error<<endl;
   }
-
-  if(realrr)
-  {
-    //cerr<<"Total: "<<nonterm.size()<<" Insert: "<<insnonterm.size()<<" Delete: "<<delnonterm.size()<<endl;
-    if(!insnonterm.empty() || !delnonterm.empty() || !doent)
-    {
-      sd.db->updateEmptyNonTerminals(sd.domain_id, insnonterm, delnonterm, !doent);
-    }
-    if(doent)
-    {
-      realrr=false;
-      qnames.clear();
-      for(const auto& nt :  nonterm){
-        qnames.insert(nt.first);
-      }
-      goto dononterm;
-    }
-  }
-
-  if(doTransaction)
-    sd.db->commitTransaction();
-
-  return true;
+  return ret;
 }
 
 void dbBench(const std::string& fname)