From: Pieter Lexis Date: Mon, 4 Mar 2019 16:51:22 +0000 (+0100) Subject: Retrieve DNAMEs from the cache X-Git-Tag: rec-4.2.0-beta1~6^2~17 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d30b54935bc9037bdded105812ef232a133433f0;p=thirdparty%2Fpdns.git Retrieve DNAMEs from the cache --- diff --git a/pdns/syncres.cc b/pdns/syncres.cc index 01d22c530d..28216fbb0e 100644 --- a/pdns/syncres.cc +++ b/pdns/syncres.cc @@ -936,15 +936,43 @@ bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector return true; } - LOG(prefix< cset; vector> signatures; vector> authorityRecs; bool wasAuth; uint32_t capTTL = std::numeric_limits::max(); - /* we don't require auth data for forward-recurse lookups */ - if(t_RC->get(d_now.tv_sec, qname, QType(QType::CNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth) > 0) { + DNSName foundName; + QType foundQT = QType(0); // 0 == QTYPE::ENT + + if (qname != g_rootdnsname) { + // look for a DNAME cache hit + auto labels = qname.getRawLabels(); + DNSName dnameName(g_rootdnsname); + + do { + dnameName.prependRawLabel(labels.back()); + labels.pop_back(); + LOG(prefix<get(d_now.tv_sec, dnameName, QType(QType::DNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth) > 0) { + if (dnameName != qname && qtype != QType::DNAME) { + foundName = dnameName; + foundQT = QType(QType::DNAME); + break; + } + } + } while(!labels.empty()); + } + if (foundName.empty()) { + LOG(prefix<get(d_now.tv_sec, qname, QType(QType::CNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth) > 0) { + foundName = qname; + foundQT = QType(QType::CNAME); + } + } + + if(!foundName.empty()) { for(auto j=cset.cbegin() ; j != cset.cend() ; ++j) { if (j->d_class != QClass::IN) { continue; @@ -956,28 +984,28 @@ bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector /* This means we couldn't figure out the state when this entry was cached, most likely because we hadn't computed the zone cuts yet. */ /* make sure they are computed before validating */ - DNSName subdomain(qname); + DNSName subdomain(foundName); /* if we are retrieving a DS, we only care about the state of the parent zone */ if(qtype == QType::DS) subdomain.chopOff(); computeZoneCuts(subdomain, g_rootdnsname, depth); - vState recordState = getValidationStatus(qname, false); + vState recordState = getValidationStatus(foundName, false); if (recordState == Secure) { - LOG(prefix<d_content->getZoneRepresentation()<<"', validation state is "<d_content->getZoneRepresentation()<<"', validation state is "<beenthere; + DNSName newTarget; + if (foundQT == QType::DNAME) { + if (qtype == QType::DNAME && qname == foundName) { // client wanted the DNAME, no need to synthesize a CNAME + res = 0; + return true; + } + // Synthesize a CNAME + auto dnameRR = getRR(*j); + if (dnameRR == nullptr) { + throw ImmediateServFailException("Unable to get record content for "+foundName.toLogString()+"|DNAME cache entry"); + } + auto dnameSuffix = dnameRR->getTarget(); + DNSName targetPrefix = qname.makeRelative(foundName); + dr.d_type = QType::CNAME; + dr.d_name = targetPrefix + foundName; + newTarget = targetPrefix + dnameSuffix; + dr.d_content = std::make_shared(CNAMERecordContent(newTarget)); + ret.push_back(dr); + + LOG(prefix<(*j); - if (cnameContent) { - res=doResolve(cnameContent->getTarget(), qtype, ret, depth+1, beenthere, cnameState); - LOG(prefix<getTarget(); } - else - res=0; + + setbeenthere; + vState cnameState = Indeterminate; + res = doResolve(newTarget, qtype, ret, depth+1, beenthere, cnameState); + LOG(prefix<empty()) { // Check if we are authoritative for a zone in this answer DNSName tmp_qname(rec.d_name);