Permalink
Browse files

fix SOA caching with multiple backends

  • Loading branch information...
1 parent 03281d9 commit 58d6ab67f5deb1dd83c5a10fbc9ff833e294e063 @mind04 mind04 committed with mind04 Apr 26, 2016
Showing with 77 additions and 105 deletions.
  1. +2 −29 pdns/dnsbackend.cc
  2. +1 −1 pdns/dnsbackend.hh
  3. +74 −75 pdns/ueberbackend.cc
View
@@ -44,36 +44,9 @@ bool DNSBackend::getRemote(DNSPacket *p, struct sockaddr *sa, Utility::socklen_t
return true;
}
-bool DNSBackend::getAuth(DNSPacket *p, SOAData *sd, const string &target, int *zoneId, const int best_match_len, map<string,int>& negCacheMap)
+bool DNSBackend::getAuth(DNSPacket *p, SOAData *sd, const string &target)
{
- bool found=false;
- string subdomain(target);
- do {
- if( best_match_len >= (int)subdomain.length() && p->qtype != QType::DS )
- break;
-
- map<string,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(zoneId)
- *zoneId = sd->domain_id;
- if(found) // Second SOA found, we are done
- return true;
-
- if(p->qtype.getCode() == QType::DS && pdns_iequals(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( chopOff( subdomain ) ); // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
-
- return found;
+ return this->getSOA(target, *sd, p);
}
void DNSBackend::setArgPrefix(const string &prefix)
View
@@ -163,7 +163,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 string &target, int *zoneId, const int best_match_len, map<string,int>& negCacheMap);
+ virtual bool getAuth(DNSPacket *p, SOAData *sd, const string &target);
struct KeyData {
unsigned int id;
View
@@ -276,85 +276,73 @@ void UeberBackend::getUpdatedMasters(vector<DomainInfo>* domains)
bool UeberBackend::getAuth(DNSPacket *p, SOAData *sd, const string &target, int *zoneId)
{
- int best_match_len = -1;
- bool from_cache = false; // Was this result fetched from the cache?
- map<string,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)) {
- string 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.length();
-
- if ( p->qtype != QType::DS || best_match_len < (int)target.length())
- break;
- } else if (cstat==0 && d_negcache_ttl) {
- negCacheMap[subdomain]=1;
- } else
- negCacheMap[subdomain]=0;
- loops++;
+ bool found = false;
+ int cstat;
+ string shorter(target);
+ vector<pair<size_t, SOAData> > bestmatch (backends.size(), make_pair(target.size()+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<<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<<endl);
+ continue;
}
- while( chopOff( subdomain ) ); // '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.length() && p->qtype != QType::DS )
- goto auth_found;
-
- if((*i)->getAuth(p, sd, target, zoneId, best_match_len, negCacheMap)) {
- best_match_len = sd->qname.length();
- from_cache = false;
}
- }
-
- if( sd->db != (DNSBackend *)-1 && d_negcache_ttl) {
- string shorter(target);
- d_question.qtype=QType::SOA;
- d_question.zoneId=-1;
- while((int)shorter.length() > best_match_len ) {
- map<string,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) {
+
+ L<<Logger::Error<<"backend: "<<i-backends.begin()<<", qname: "<<shorter<<endl;
+
+ if(j->first < shorter.length()) {
+ DLOG(L<<Logger::Error<<"skipped, already found shorter best match: "<<j->second.qname<<endl);
+ continue;
+ } else if(j->first == shorter.length()) {
+ DLOG(L<<Logger::Error<<"use shorter best match: "<<j->second.qname<<endl);
+ *sd = j->second;
+ break;
+ } else {
+ L<<Logger::Error<<"lookup: "<<shorter<<endl;
+ if((*i)->getAuth(p, sd, shorter)) {
+ L<<Logger::Error<<"got: "<<sd->qname<<endl;
+ j->first = sd->qname.length();
+ if(sd->qname.length() == shorter.length()) {
+ break;
+ }
+ } else {
+ L<<Logger::Error<<"no match for: "<<shorter<<endl;
+ }
+ }
}
- if (!chopOff(shorter))
- 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) {
+ L<<Logger::Error<<"add neg:"<<shorter<<endl;
+ d_question.qname=shorter;
+ addNegCache(d_question);
+ }
+ continue;
+ } else if(d_cache_ttl) {
+ L<<Logger::Error<<"add pos: "<<sd->qname<<endl;
d_question.qtype = QType::SOA;
d_question.qname = sd->qname;
d_question.zoneId = -1;
@@ -368,9 +356,20 @@ bool UeberBackend::getAuth(DNSPacket *p, SOAData *sd, const string &target, int
vector<DNSResourceRecord> rrs;
rrs.push_back(rr);
addCache(d_question, rrs);
+ }
+ }
+
+found:
+ if(found == (p->qtype == QType::DS)){
+ DLOG(L<<Logger::Error<<"found: "<<sd->qname<<endl);
+ return true;
+ } else {
+ DLOG(L<<Logger::Error<<"chasing next: "<<sd->qname<<endl);
+ found = true;
}
- return true;
+ } while(chopOff(shorter));
+ return found;
}
/** special trick - if sd.db is set to -1, the cache is ignored */

0 comments on commit 58d6ab6

Please sign in to comment.