]> granicus.if.org Git - pdns/commitdiff
fix SOA caching with multiple backends
authorKees Monshouwer <mind04@monshouwer.org>
Wed, 27 Apr 2016 10:01:45 +0000 (12:01 +0200)
committermind04 <mind04@monshouwer.org>
Wed, 27 Apr 2016 10:10:18 +0000 (12:10 +0200)
pdns/dnsbackend.cc
pdns/dnsbackend.hh
pdns/ueberbackend.cc

index 158dd256f15791ac906888f1482b9b45ea5389a0..a7b4d016b5b71096ae4d55f00d952989e918174c 100644 (file)
 #include "dnspacket.hh"
 #include "dns.hh"
 
-bool DNSBackend::getAuth(DNSPacket *p, SOAData *sd, const DNSName &target, const int best_match_len, map<DNSName,int>& negCacheMap)
+bool DNSBackend::getAuth(DNSPacket *p, SOAData *sd, const DNSName &target)
 {
-  bool found=false;
-  DNSName subdomain(target);
-  do {
-    if( best_match_len >= (int)subdomain.toString().length() && p->qtype != QType::DS )
-      break;
-
-    map<DNSName,int>::iterator it = negCacheMap.find(subdomain);
-    bool negCached = ( it != negCacheMap.end() && it->second == 1 );
-
-    if(! negCached && this->getSOA( subdomain, *sd, p ) ) {
-      sd->qname = subdomain;
-      if (found) // Second SOA found, we are done
-        return true;
-
-      if(p->qtype.getCode() == QType::DS && subdomain==target) {
-        // Found authoritative zone but look for parent zone with 'DS' record.
-        found=true;
-      } else
-        return true;
-    }
-    if (found)
-      negCacheMap[subdomain]=2; // don't cache SOA's during our quest for a parent zone
-  }
-  while( subdomain.chopOff() );   // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
-
-  return found;
+  return this->getSOA(target, *sd, p);
 }
 
 void DNSBackend::setArgPrefix(const string &prefix)
index 1e1ff5cc3f8152e5e2aa4c5ef053c8481ebcb149..f2f151b6a49566b9b35d4e4149d1e7586f765ff8 100644 (file)
@@ -168,7 +168,7 @@ public:
   virtual void getAllDomains(vector<DomainInfo> *domains, bool include_disabled=false) { }
 
   /** Determines if we are authoritative for a zone, and at what level */
-  virtual bool getAuth(DNSPacket *p, SOAData *sd, const DNSName &target, const int best_match_len, map<DNSName,int>& negCacheMap);
+  virtual bool getAuth(DNSPacket *p, SOAData *sd, const DNSName &target);
 
   struct KeyData {
     std::string content;
index 359d0b024605811f8d6ec75246561222e6bf4d7f..6d0b693aec0dd984e2068adcd3fbcfdcf4419d9b 100644 (file)
@@ -249,84 +249,73 @@ void UeberBackend::getUpdatedMasters(vector<DomainInfo>* domains)
 
 bool UeberBackend::getAuth(DNSPacket *p, SOAData *sd, const DNSName &target)
 {
-  int best_match_len = -1;
-  bool from_cache = false;  // Was this result fetched from the cache?
-  map<DNSName,int> negCacheMap;
-
-  // If not special case of caching explicitly disabled (sd->db = -1), first
-  // find the best match from the cache. If DS then we need to find parent so
-  // dont bother with caching as it confuses matters.
-  if( sd->db != (DNSBackend *)-1 && (d_cache_ttl || d_negcache_ttl)) {
-      DNSName subdomain(target);
-      int cstat, loops = 0;
-      do {
-        d_question.qtype = QType::SOA;
-        d_question.qname = subdomain;
-        d_question.zoneId = -1;
-
-        cstat = cacheHas(d_question,d_answers);
-
-        if(cstat==1 && !d_answers.empty() && d_cache_ttl) {
-          fillSOAData(d_answers[0].content,*sd);
-          sd->domain_id = d_answers[0].domain_id;
-          sd->ttl = d_answers[0].ttl;
-          sd->db = 0;
-          sd->qname = subdomain;
-          //L<<Logger::Error<<"Best cache match: " << sd->qname << " itteration " << loops <<endl;
-
-          // Found first time round this must be the best match
-          if( loops == 0  && p->qtype != QType::DS)
-            return true;
-
-          from_cache = true;
-          best_match_len = sd->qname.countLabels();
-
-          if ( p->qtype != QType::DS || best_match_len < (int)target.countLabels())
-            break;
-        } else if (cstat==0 && d_negcache_ttl) {
-          negCacheMap[subdomain]=1;
-        } else
-          negCacheMap[subdomain]=0;
-        loops++;
+  bool found = false;
+  int cstat;
+  DNSName shorter(target);
+  vector<pair<size_t, SOAData> > bestmatch (backends.size(), make_pair(target.wirelength()+1, SOAData()));
+  do {
+
+    // Check cache
+    if(sd->db != (DNSBackend *)-1 && (d_cache_ttl || d_negcache_ttl)) {
+      d_question.qtype = QType::SOA;
+      d_question.qname = shorter;
+      d_question.zoneId = -1;
+
+      cstat = cacheHas(d_question,d_answers);
+
+      if(cstat == 1 && !d_answers.empty() && d_cache_ttl) {
+        DLOG(L<<Logger::Error<<"has pos: "<<shorter.toLogString()<<endl);
+        fillSOAData(d_answers[0].content, *sd);
+        sd->domain_id = d_answers[0].domain_id;
+        sd->ttl = d_answers[0].ttl;
+        sd->db = 0;
+        sd->qname = shorter;
+        goto found;
+      } else if(cstat == 0 && d_negcache_ttl) {
+        DLOG(L<<Logger::Error<<"has neg: "<<shorter.toLogString()<<endl);
+        continue;
       }
-      while( subdomain.chopOff() );   // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
-  }
-
-  for(vector<DNSBackend *>::const_iterator i=backends.begin(); i!=backends.end();++i) {
-    // Shortcut for the case that we got a direct hit - no need to go
-    // through the other backends then.
-    if( best_match_len == (int)target.countLabels() && p->qtype != QType::DS )
-      goto auth_found;
-
-    if((*i)->getAuth(p, sd, target, best_match_len, negCacheMap)) {
-        best_match_len = sd->qname.countLabels(); // FIXME400
-        from_cache = false;
     }
-  }
-
-  if( sd->db != (DNSBackend *)-1 && d_negcache_ttl) {
-    DNSName shorter(target);
 
-    d_question.qtype=QType::SOA;
-    d_question.zoneId=-1;
-    while((int)shorter.countLabels() > best_match_len ) {
-      map<DNSName,int>::iterator it = negCacheMap.find(shorter);
-      if (it == negCacheMap.end() || it->second == 0) {
-        d_question.qname=shorter;
-        addNegCache(d_question);
+    // Check backends
+    {
+      vector<DNSBackend *>::const_iterator i = backends.begin();
+      vector<pair<size_t, SOAData> >::iterator j = bestmatch.begin();
+      for(; i != backends.end() && j != bestmatch.end(); ++i, ++j) {
+
+        DLOG(L<<Logger::Error<<"backend: "<<i-backends.begin()<<", qname: "<<shorter<<endl);
+
+        if(j->first < shorter.wirelength()) {
+          DLOG(L<<Logger::Error<<"skipped, already found shorter best match: "<<j->second.qname.toLogString()<<endl);
+          continue;
+        } else if(j->first == shorter.wirelength()) {
+          DLOG(L<<Logger::Error<<"use shorter best match: "<<j->second.qname.toLogString()<<endl);
+          *sd = j->second;
+          break;
+        } else {
+          DLOG(L<<Logger::Error<<"lookup: "<<shorter<<endl);
+          if((*i)->getAuth(p, sd, shorter)) {
+            DLOG(L<<Logger::Error<<"got: "<<sd->qname<<endl);
+            j->first = sd->qname.wirelength();
+            if(sd->qname == shorter) {
+              break;
+            }
+          } else {
+            DLOG(L<<Logger::Error<<"no match for: "<<shorter.toLogString()<<endl);
+          }
+        }
       }
-      if (!shorter.chopOff())
-        break;
-    }
-  }
 
-  if( best_match_len == -1 )
-      return false;
-
-auth_found:
-    // Insert into cache. Don't cache if the query was a DS
-    if( d_cache_ttl && ! from_cache && p->qtype != QType::DS ) {
-        //L<<Logger::Error<<"Saving auth cache for " << sd->qname <<endl;
+      // Add to cache
+      if(i == backends.end()) {
+        if(d_negcache_ttl) {
+          DLOG(L<<Logger::Error<<"add neg:"<<shorter.toLogString()<<endl);
+          d_question.qname=shorter;
+          addNegCache(d_question);
+        }
+        continue;
+      } else if(d_cache_ttl) {
+        DLOG(L<<Logger::Error<<"add pos: "<<sd->qname.toLogString()<<endl);
         d_question.qtype = QType::SOA;
         d_question.qname = sd->qname;
         d_question.zoneId = -1;
@@ -340,9 +329,20 @@ auth_found:
         vector<DNSResourceRecord> rrs;
         rrs.push_back(rr);
         addCache(d_question, rrs);
+      }
     }
 
-    return true;
+found:
+    if(found == (p->qtype == QType::DS)){
+      DLOG(L<<Logger::Error<<"found: "<<sd->qname.toLogString()<<endl);
+      return true;
+    } else {
+      DLOG(L<<Logger::Error<<"chasing next: "<<sd->qname.toLogString()<<endl);
+      found = true;
+    }
+
+  } while(shorter.chopOff());
+  return found;
 }
 
 bool UeberBackend::getSOA(const DNSName &domain, SOAData &sd, DNSPacket *p)