]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
auth: rectify() do not update ordernames/auth when there is no need
authorKees Monshouwer <mind04@monshouwer.org>
Sat, 27 Mar 2021 17:41:50 +0000 (18:41 +0100)
committermind04 <mind04@monshouwer.org>
Sun, 28 Mar 2021 00:08:04 +0000 (01:08 +0100)
modules/gmysqlbackend/gmysqlbackend.cc
modules/godbcbackend/godbcbackend.cc
modules/gpgsqlbackend/gpgsqlbackend.cc
modules/gsqlite3backend/gsqlite3backend.cc
pdns/backends/gsql/gsqlbackend.cc
pdns/backends/gsql/gsqlbackend.hh
pdns/dbdnsseckeeper.cc
pdns/dns.hh
regression-tests/backends/godbc_sqlite3-master

index f1c10f7b4b2b6d2ffbbf9bd5f3093a389b1eaad0..c6f9d6bc5ae54ed35180252c05fe7c22fe767585 100644 (file)
@@ -95,7 +95,7 @@ public:
     declare(suffix, "any-query", "Any query", record_query + " disabled=0 and name=?");
     declare(suffix, "any-id-query", "Any with ID query", record_query + " disabled=0 and name=? and domain_id=?");
 
-    declare(suffix, "list-query", "AXFR query", record_query + " (disabled=0 OR ?) and domain_id=? order by name, type");
+    declare(suffix, "list-query", "AXFR query", "SELECT content,ttl,prio,type,domain_id,disabled,name,auth,ordername FROM records WHERE (disabled=0 OR ?) and domain_id=? order by name, type");
     declare(suffix, "list-subzone-query", "Subzone listing", record_query + " disabled=0 and (name=? OR name like ?) and domain_id=?");
 
     declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=? and type is null");
index e61c8dafa110d7dafd16d169da93fbf075c765fd..b41bdc3509bade24d66564d2f10dd4a6d3d44f55 100644 (file)
@@ -75,7 +75,7 @@ public:
     declare(suffix, "any-query", "Any query", record_query + " disabled=0 and name=?");
     declare(suffix, "any-id-query", "Any with ID query", record_query + " disabled=0 and name=? and domain_id=?");
 
-    declare(suffix, "list-query", "AXFR query", record_query + " (disabled=0 OR disabled=?) and domain_id=? order by name, type");
+    declare(suffix, "list-query", "AXFR query", "SELECT content,ttl,prio,type,domain_id,disabled,name,auth,CONVERT(varchar(255), ordername, 0) FROM records WHERE (disabled=0 OR disabled=?) and domain_id=? order by name, type");
     declare(suffix, "list-subzone-query", "Subzone listing", record_query + " disabled=0 and (name=? OR name like ?) and domain_id=?");
 
     declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=? and type is null");
index 7a2ad91ab768791db24259730b56c40661c15554..1b7fce75410660404e63efc3dd1a2e77b4b557d0 100644 (file)
@@ -102,7 +102,7 @@ public:
     declare(suffix, "any-query", "Any query", record_query + " disabled=false and name=$1");
     declare(suffix, "any-id-query", "Any with ID query", record_query + " disabled=false and name=$1 and domain_id=$2");
 
-    declare(suffix, "list-query", "AXFR query", record_query + " (disabled=false OR $1) and domain_id=$2 order by name, type");
+    declare(suffix, "list-query", "AXFR query", "SELECT content,ttl,prio,type,domain_id,disabled::int,name,auth::int,ordername FROM records WHERE (disabled=false OR $1) and domain_id=$2 order by name, type");
     declare(suffix, "list-subzone-query", "Subzone listing", record_query + " disabled=false and (name=$1 OR name like $2) and domain_id=$3");
 
     declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=$1 and type is null");
index b9670f4ab65577617e4c9f254286178cf4fbb5fb..6d9fae416dfa7a2aa6760ad95956d0815b1a01a8 100644 (file)
@@ -88,7 +88,7 @@ public:
     declare(suffix, "any-query", "Any query", record_query + " disabled=0 and name=:qname");
     declare(suffix, "any-id-query", "Any with ID query", record_query + " disabled=0 and name=:qname and domain_id=:domain_id");
 
-    declare(suffix, "list-query", "AXFR query", record_query + " (disabled=0 OR :include_disabled) and domain_id=:domain_id order by name, type");
+    declare(suffix, "list-query", "AXFR query", "SELECT content,ttl,prio,type,domain_id,disabled,name,auth,ordername FROM records WHERE (disabled=0 OR :include_disabled) and domain_id=:domain_id order by name, type");
     declare(suffix, "list-subzone-query", "Subzone listing", record_query + " disabled=0 and (name=:zone OR name like :wildzone) and domain_id=:domain_id");
 
     declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=:domain_id and type is null");
index 83c48fb530b8a021cca182022c5f5bf0de831704..e0724d1bd4ee11cf40ffdcf30bb9adbfc7cd559f 100644 (file)
@@ -1144,6 +1144,7 @@ void GSQLBackend::lookup(const QType &qtype,const DNSName &qname, int domain_id,
     throw PDNSException("GSQLBackend unable to lookup '" + qname.toLogString() + "|" + qtype.getName() + "':"+e.txtReason());
   }
 
+  d_list=false;
   d_qname=qname;
 }
 
@@ -1165,7 +1166,9 @@ bool GSQLBackend::list(const DNSName &target, int domain_id, bool include_disabl
     throw PDNSException("GSQLBackend unable to list domain '" + target.toLogString() + "': "+e.txtReason());
   }
 
+  d_list=true;
   d_qname.clear();
+
   return true;
 }
 
@@ -1187,7 +1190,10 @@ bool GSQLBackend::listSubZone(const DNSName &zone, int domain_id) {
   catch(SSqlException &e) {
     throw PDNSException("GSQLBackend unable to list SubZones for domain '" + zone.toLogString() + "': "+e.txtReason());
   }
+
+  d_list=false;
   d_qname.clear();
+
   return true;
 }
 
@@ -1200,7 +1206,12 @@ skiprow:
   if((*d_query_stmt)->hasNextRow()) {
     try {
       (*d_query_stmt)->nextRow(row);
-      ASSERT_ROW_COLUMNS(d_query_name, row, 8);
+      if (!d_list) {
+        ASSERT_ROW_COLUMNS(d_query_name, row, 8); // lookup(), listSubZone()
+      }
+      else {
+        ASSERT_ROW_COLUMNS(d_query_name, row, 9); // list()
+      }
     } catch (SSqlException &e) {
       throw PDNSException("GSQLBackend get: "+e.txtReason());
     }
@@ -1888,6 +1899,18 @@ void GSQLBackend::extractRecord(SSqlStatement::row_t& row, DNSResourceRecord& r)
   r.disabled = !row[5].empty() && row[5][0]=='1';
 
   r.domain_id=pdns_stou(row[4]);
+
+  if (row.size() > 8) {
+    if (!row.at(8).empty()) {
+      r.ordername=DNSName(boost::replace_all_copy(row.at(8), " ", ".")).labelReverse();
+    }
+    else {
+      r.ordername.clear();
+    }
+  }
+  else {
+    r.ordername.clear();
+  }
 }
 
 void GSQLBackend::extractComment(SSqlStatement::row_t& row, Comment& comment)
index fb964c019012492adee735952d591414f3a624db..0aa79f54a63c970e0a2bea96a31195cb436e2c19 100644 (file)
@@ -264,6 +264,7 @@ protected:
     return d_inTransaction;
   }
 
+  bool d_list{false};
   string d_query_name;
   DNSName d_qname;
   SSqlStatement::result_t d_result;
index dd79588cb0fd4c3b8336551ee92462d6d43058a8..5a052168d53b7111d6d566c39913ddfde6222125 100644 (file)
@@ -718,6 +718,15 @@ bool DNSSECKeeper::unSecureZone(const DNSName& zone, string& error, string& info
   return true;
 }
 
+
+struct RecordStatus
+{
+  DNSName ordername;
+  bool auth{false};
+  bool update{false};
+};
+
+
 /* Rectifies the zone
  *
  * \param zone The zone to rectify
@@ -757,48 +766,60 @@ bool DNSSECKeeper::rectifyZone(const DNSName& zone, string& error, string& info,
   ostringstream infostream;
   DNSResourceRecord rr;
   set<DNSName> qnames, nsset, dsnames, insnonterm, delnonterm;
-  map<DNSName,bool> nonterm;
+  std::unordered_map<DNSName,bool> nonterm;
   vector<DNSResourceRecord> rrs;
+  std::unordered_map<DNSName,RecordStatus> rss;
+
+  NSEC3PARAMRecordContent ns3pr;
+  bool securedZone = isSecuredZone(zone, doTransaction);
+  bool haveNSEC3 = false, isOptOut = false, narrow = false;
+
+  if(securedZone) {
+    haveNSEC3 = getNSEC3PARAM(zone, &ns3pr, &narrow, doTransaction);
+    isOptOut = (haveNSEC3 && ns3pr.d_flags);
+  }
 
   while(sd.db->get(rr)) {
     rr.qname.makeUsLowerCase();
+
+    auto res=rss.insert({rr.qname,{rr.ordername, rr.auth, rr.ordername.empty() != (!securedZone || narrow)}}); // only a set ordername is reliable
+    if (!res.second && !res.first->second.update) {
+      res.first->second.update = res.first->second.auth != rr.auth || res.first->second.ordername != rr.ordername;
+    }
+    else if ((!securedZone || narrow) && rr.qname == zone) {
+      res.first->second.update = true;
+    }
+
     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);
+      rrs.emplace_back(rr);
     }
     else
-      delnonterm.insert(rr.qname);
+      delnonterm.insert(std::move(rr.qname));
   }
 
-  NSEC3PARAMRecordContent ns3pr;
-  bool securedZone = isSecuredZone(zone, doTransaction);
-  bool haveNSEC3 = false, isOptOut = false, narrow = false;
-
   if(securedZone) {
-    haveNSEC3 = getNSEC3PARAM(zone, &ns3pr, &narrow, doTransaction);
-    isOptOut = (haveNSEC3 && ns3pr.d_flags);
-
     if(!haveNSEC3) {
-      infostream<<"Adding NSEC ordering information ";
+      infostream<<"Adding NSEC ordering information for zone '"<<zone<<"'";
     }
     else if(!narrow) {
       if(!isOptOut) {
-        infostream<<"Adding NSEC3 hashed ordering information for '"<<zone<<"'";
+        infostream<<"Adding NSEC3 hashed ordering information for zone '"<<zone<<"'";
       }
       else {
-        infostream<<"Adding NSEC3 opt-out hashed ordering information for '"<<zone<<"'";
+        infostream<<"Adding NSEC3 opt-out hashed ordering information for zone '"<<zone<<"'";
       }
     } else {
-      infostream<<"Erasing NSEC3 ordering since we are narrow, only setting 'auth' fields";
+      infostream<<"Erasing NSEC3 ordering since we are narrow, only setting 'auth' fields for zone '"<<zone<<"'";
     }
   }
   else {
-    infostream<<"Adding empty non-terminals for non-DNSSEC zone";
+    infostream<<"Adding empty non-terminals for non-DNSSEC zone '"<<zone<<"'";
   }
 
   set<DNSName> nsec3set;
@@ -831,9 +852,11 @@ bool DNSSECKeeper::rectifyZone(const DNSName& zone, string& error, string& info,
 
   bool realrr=true;
   bool doent=true;
+  int updates=0;
   uint32_t maxent = ::arg().asNum("max-ent-entries");
 
   dononterm:;
+  std::unordered_map<DNSName,RecordStatus>::const_iterator it;
   for (const auto& qname: qnames)
   {
     bool auth=true;
@@ -861,20 +884,32 @@ bool DNSSECKeeper::rectifyZone(const DNSName& zone, string& error, string& info,
       }
     }
     else if (realrr && securedZone) // NSEC
+    {
       ordername=qname.makeRelative(zone);
+    }
 
-    sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, auth);
+    it = rss.find(qname);
+    if(it == rss.end() || it->second.update || it->second.auth != auth || it->second.ordername != ordername) {
+      sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, auth);
+      ++updates;
+    }
 
     if(realrr)
     {
-      if (dsnames.count(qname))
+      if (dsnames.count(qname)) {
         sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, true, QType::DS);
+        ++updates;
+      }
       if (!auth || nsset.count(qname)) {
         ordername.clear();
-        if(isOptOut && !dsnames.count(qname))
+        if(isOptOut && !dsnames.count(qname)){
           sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, false, QType::NS);
+          ++updates;
+        }
         sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, false, QType::A);
+        ++updates;
         sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, false, QType::AAAA);
+        ++updates;
       }
 
       if(doent)
@@ -930,6 +965,7 @@ bool DNSSECKeeper::rectifyZone(const DNSName& zone, string& error, string& info,
   if (doTransaction)
     sd.db->commitTransaction();
 
+  infostream<<", "<<updates<<" updates";
   info = infostream.str();
   return true;
 }
index 608d61ccd7dd63beb86eb6295e19289693678f8f..b5ca2ada1fd4c6dfd68113371f08b0e3559f7106 100644 (file)
@@ -90,6 +90,7 @@ public:
 
   // data
   DNSName qname; //!< the name of this record, for example: www.powerdns.com
+  DNSName ordername;
   DNSName wildcardname;
   string content; //!< what this record points to. Example: 10.1.2.3
 
index e17a3bd134981a90327cd18031b9755264731fa6..3efedc66a79e6aa0664cca4082cd00609105e44b 100644 (file)
@@ -50,7 +50,7 @@ godbc-insert-record-query=insert into records (content,ttl,prio,type,domain_id,d
 godbc-insert-zone-query=insert into domains (type,name,master,account,last_check,notified_serial) values(?, ?, ?, ?, null, null)
 godbc-list-comments-query=SELECT domain_id,name,type,modified_at,account,comment FROM comments WHERE domain_id=?
 godbc-list-domain-keys-query=select cryptokeys.id, flags, active, published, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=?
-godbc-list-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE (disabled=0 OR ?) and domain_id=? order by name, type
+godbc-list-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth,ordername FROM records WHERE (disabled=0 OR ?) and domain_id=? order by name, type
 godbc-list-subzone-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and (name=? OR name like ?) and domain_id=?
 godbc-nullify-ordername-and-update-auth-query=update records set ordername=NULL,auth=? where domain_id=? and name=? and disabled=0
 godbc-nullify-ordername-and-update-auth-type-query=update records set ordername=NULL,auth=? where domain_id=? and name=? and type=? and disabled=0