From 26ca3513523f1e89290d715428e1a57a496f7baa Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Fri, 3 Mar 2017 12:05:45 +0100 Subject: [PATCH] rec: Split SyncRes::doResolveAt() --- pdns/syncres.cc | 586 ++++++++++++++++++++++++++---------------------- pdns/syncres.hh | 9 + 2 files changed, 326 insertions(+), 269 deletions(-) diff --git a/pdns/syncres.cc b/pdns/syncres.cc index 528244658..455aa014d 100644 --- a/pdns/syncres.cc +++ b/pdns/syncres.cc @@ -961,6 +961,300 @@ static void addNXNSECS(vector&ret, const vector& records) } } +bool SyncRes::nameserversBlockedByRPZ(const NsSet& nameservers) +{ + if(d_wantsRPZ) { + for (auto const &ns : nameservers) { + d_appliedPolicy = g_luaconfs.getLocal()->dfe.getProcessingPolicy(ns.first, d_discardedPolicies); + if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response + LOG(", however nameserver "<dfe.getProcessingPolicy(address, d_discardedPolicies); + if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response + LOG(", however nameserver "<dfe.getProcessingPolicy(remoteIP, d_discardedPolicies); + if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { + LOG(" (blocked by RPZ policy '"+(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")+"')"); + return true; + } + } + return false; +} + +vector SyncRes::retrieveAddressesForNS(const std::string& prefix, const DNSName& qname, vector::const_iterator& tns, const unsigned int depth, set& beenthere, const vector& rnameservers, NsSet& nameservers, bool& sendRDQuery, bool& pierceDontQuery, bool& flawedNSSet) +{ + vector result; + + if(!tns->empty()) { + LOG(prefix< 1) { + LOG("s"); + } + LOG(endl); + + sendRDQuery = nameservers[*tns].second; + pierceDontQuery=true; + } + return result; +} + +bool SyncRes::throttledOrBlocked(const std::string& prefix, const ComboAddress& remoteIP, const DNSName& qname, const QType& qtype, bool pierceDontQuery) +{ + extern NetmaskGroup* g_dontQuery; + + if(t_sstorage->throttle.shouldThrottle(d_now.tv_sec, boost::make_tuple(remoteIP, "", 0))) { + LOG(prefix<throttle.shouldThrottle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()))) { + LOG(prefix<match(&remoteIP)) { + LOG(prefix< ednsmask) +{ + struct CachePair + { + vector records; + vector> signatures; + }; + struct CacheKey + { + DNSName name; + uint16_t type; + DNSResourceRecord::Place place; + bool operator<(const CacheKey& rhs) const { + return tie(name, type) < tie(rhs.name, rhs.type); + } + }; + typedef map tcache_t; + tcache_t tcache; + + for(const auto& rec : lwr.d_records) { + if(rec.d_type == QType::RRSIG) { + auto rrsig = getRR(rec); + if (rrsig) { + // cerr<<"Got an RRSIG for "<d_type)<<" with name '"<d_type, rec.d_place}].signatures.push_back(rrsig); + } + } + } + + // reap all answers from this packet that are acceptable + for(auto& rec : lwr.d_records) { + if(rec.d_type == QType::OPT) { + LOG(prefix<getZoneRepresentation()<<"' from '"<domainmap->empty()) { + // Check if we are authoritative for a zone in this answer + DNSName tmp_qname(rec.d_name); + auto auth_domain_iter=getBestAuthZone(&tmp_qname); + if(auth_domain_iter!=t_sstorage->domainmap->end() && + auth.countLabels() <= auth_domain_iter->first.countLabels()) { + if (auth_domain_iter->first != auth) { + LOG("NO! - we are authoritative for the zone "<first<second.records.size() > 1) { // need to group the ttl to be the minimum of the RRSET (RFC 2181, 5.2) + uint32_t lowestTTL=std::numeric_limits::max(); + for(const auto& record : i->second.records) + lowestTTL=min(lowestTTL, record.d_ttl); + + for(auto& record : i->second.records) + *const_cast(&record.d_ttl)=lowestTTL; // boom + } + +// cout<<"Have "<second.records.size()<<" records and "<second.signatures.size()<<" signatures for "<first.name; +// cout<<'|'<first.type)<second.records.empty()) // this happens when we did store signatures, but passed on the records themselves + continue; + t_RC->replace(d_now.tv_sec, i->first.name, QType(i->first.type), i->second.records, i->second.signatures, lwr.d_aabit, i->first.place == DNSResourceRecord::ANSWER ? ednsmask : boost::optional()); + if(i->first.place == DNSResourceRecord::ANSWER && ednsmask) + d_wasVariable=true; + } + + return RCode::NoError; +} + +bool SyncRes::processRecords(const std::string& prefix, const DNSName& qname, const QType& qtype, const DNSName& auth, LWResult& lwr, const bool sendRDQuery, vector& ret, set& nsset, DNSName& newtarget, DNSName& newauth, bool& realreferral, bool& negindic, bool& sawDS) +{ + bool done = false; + + for(auto& rec : lwr.d_records) { + if (rec.d_type!=QType::OPT && rec.d_class!=QClass::IN) + continue; + + if(rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::SOA && + lwr.d_rcode==RCode::NXDomain && qname.isPartOf(rec.d_name) && rec.d_name.isPartOf(auth)) { + LOG(prefix<negcache, ne); + if(s_rootNXTrust && auth.isRoot()) { + ne.d_name = getLastLabel(ne.d_name); + replacing_insert(t_sstorage->negcache, ne); + } + } + + negindic=true; + } + else if(rec.d_place==DNSResourceRecord::ANSWER && rec.d_name == qname && rec.d_type==QType::CNAME && (!(qtype==QType(QType::CNAME)))) { + ret.push_back(rec); + if (auto content = getRR(rec)) { + newtarget=content->getTarget(); + } + } + else if((rec.d_type==QType::RRSIG || rec.d_type==QType::NSEC || rec.d_type==QType::NSEC3) && rec.d_place==DNSResourceRecord::ANSWER){ + if(rec.d_type != QType::RRSIG || rec.d_name == qname) + ret.push_back(rec); // enjoy your DNSSEC + } + // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively + else if(rec.d_place==DNSResourceRecord::ANSWER && rec.d_name == qname && + ( + rec.d_type==qtype.getCode() || (lwr.d_aabit && (qtype==QType(QType::ANY) || magicAddrMatch(qtype, QType(rec.d_type)) ) ) || sendRDQuery + ) + ) + { + LOG(prefix<getZoneRepresentation()<<"|"< '"<getZoneRepresentation()<<"'"< '"<getZoneRepresentation()<<"', had '"<(rec)) { + nsset.insert(content->getNS()); + } + } + else if(rec.d_place==DNSResourceRecord::AUTHORITY && qname.isPartOf(rec.d_name) && rec.d_type==QType::DS) { + LOG(prefix< '"<getZoneRepresentation()<<"'"<negcache, ne); + } + } + negindic=true; + } + } + } + + return done; +} + /** returns: * -1 in case of no results * -2 when a FilterEngine Policy was hit @@ -978,23 +1272,8 @@ int SyncRes::doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, con LOG(prefix<dfe.getProcessingPolicy(ns.first, d_discardedPolicies); - if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response - LOG(", however nameserver "<dfe.getProcessingPolicy(address, d_discardedPolicies); - if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response - LOG(", however nameserver "< rnameservers = shuffleInSpeedOrder(nameservers, doLog() ? (prefix+qname.toString()+": ") : string() ); - for(vector::const_iterator tns=rnameservers.begin();;++tns) { - if(tns==rnameservers.end()) { + for(auto tns=rnameservers.cbegin();;++tns) { + if(tns==rnameservers.cend()) { LOG(prefix<doAgeCache(d_now.tv_sec, auth, QType::NS, 10)) @@ -1014,8 +1293,8 @@ int SyncRes::doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, con return -1; } // this line needs to identify the 'self-resolving' behaviour, but we get it wrong now - if(qname == *tns && qtype.getCode()==QType::A && rnameservers.size() > (unsigned)(1+1*s_doIPv6)) { - LOG(prefix< (size_t)(1+1*s_doIPv6)) { + LOG(prefix< ednsmask; @@ -1035,26 +1313,7 @@ int SyncRes::doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, con lwr.d_aabit=true; } else { - if(!tns->empty()) { - LOG(prefix<empty()) { - LOG(prefix< 1) { - LOG("s"); - } - LOG(endl); - - sendRDQuery = nameservers[*tns].second; - pierceDontQuery=true; - } - else { - remoteIPs=getAddrs(*tns, depth+2, beenthere); - pierceDontQuery=false; - } + remoteIPs = retrieveAddressesForNS(prefix, qname, tns, depth, beenthere, rnameservers, nameservers, sendRDQuery, pierceDontQuery, flawedNSSet); if(remoteIPs.empty()) { LOG(prefix<toString()); - if (d_wantsRPZ) { - d_appliedPolicy = g_luaconfs.getLocal()->dfe.getProcessingPolicy(*remoteIP, d_discardedPolicies); - if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { - hitPolicy = true; - LOG(" (blocked by RPZ policy '"+(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")+"')"); - } + if(nameserverIPBlockedByRPZ(*remoteIP)) { + hitPolicy = true; } } LOG(endl); @@ -1082,26 +1337,13 @@ int SyncRes::doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, con return -2; } - for(remoteIP = remoteIPs.begin(); remoteIP != remoteIPs.end(); ++remoteIP) { + for(remoteIP = remoteIPs.cbegin(); remoteIP != remoteIPs.cend(); ++remoteIP) { LOG(prefix<toStringWithPort() <<", asking '"<throttle.shouldThrottle(d_now.tv_sec, boost::make_tuple(*remoteIP, "", 0))) { - LOG(prefix<throttle.shouldThrottle(d_now.tv_sec, boost::make_tuple(*remoteIP, qname, qtype.getCode()))) { - LOG(prefix<match(&*remoteIP)) { - LOG(prefix<toString() << ", blocked by 'dont-query' setting" << endl); - s_dontqueries++; + if (throttledOrBlocked(prefix, *remoteIP, qname, qtype, pierceDontQuery)) { continue; } else { + int resolveret; s_outqueries++; d_outqueries++; if(d_outqueries + d_throttledqueries > s_maxqperq) throw ImmediateServFailException("more than "+std::to_string(s_maxqperq)+" (max-qperq) queries sent while resolving "+qname.toLogString()); TryTCP: @@ -1186,7 +1428,7 @@ int SyncRes::doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, con } } - if(remoteIP == remoteIPs.end()) // we tried all IP addresses, none worked + if(remoteIP == remoteIPs.cend()) // we tried all IP addresses, none worked continue; if(lwr.d_tcbit) { @@ -1215,213 +1457,19 @@ int SyncRes::doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, con } } - struct CachePair - { - vector records; - vector> signatures; - }; - struct CacheKey - { - DNSName name; - uint16_t type; - DNSResourceRecord::Place place; - bool operator<(const CacheKey& rhs) const { - return tie(name, type) < tie(rhs.name, rhs.type); - } - }; - typedef map tcache_t; - tcache_t tcache; - - for(const auto& rec : lwr.d_records) { - if(rec.d_type == QType::RRSIG) { - auto rrsig = getRR(rec); - if (rrsig) { - // cerr<<"Got an RRSIG for "<d_type)<<" with name '"<d_type, rec.d_place}].signatures.push_back(rrsig); - } - } + RCode::rcodes_ rcode = updateCacheFromRecords(prefix, lwr, qname, auth, nameservers, *tns, ednsmask); + if (rcode != RCode::NoError) { + return rcode; } - // reap all answers from this packet that are acceptable - for(auto& rec : lwr.d_records) { - if(rec.d_type == QType::OPT) { - LOG(prefix<getZoneRepresentation()<<"' from '"<domainmap->empty()) { - // Check if we are authoritative for a zone in this answer - DNSName tmp_qname(rec.d_name); - auto auth_domain_iter=getBestAuthZone(&tmp_qname); - if(auth_domain_iter!=t_sstorage->domainmap->end() && - auth.countLabels() <= auth_domain_iter->first.countLabels()) { - if (auth_domain_iter->first != auth) { - LOG("NO! - we are authoritative for the zone "<first<second.records.size() > 1) { // need to group the ttl to be the minimum of the RRSET (RFC 2181, 5.2) - uint32_t lowestTTL=std::numeric_limits::max(); - for(auto& record : i->second.records) - lowestTTL=min(lowestTTL, record.d_ttl); - - for(auto& record : i->second.records) - *const_cast(&record.d_ttl)=lowestTTL; // boom - } - -// cout<<"Have "<second.records.size()<<" records and "<second.signatures.size()<<" signatures for "<first.name; -// cout<<'|'<first.type)<second.records.empty()) // this happens when we did store signatures, but passed on the records themselves - continue; - t_RC->replace(d_now.tv_sec, i->first.name, QType(i->first.type), i->second.records, i->second.signatures, lwr.d_aabit, i->first.place == DNSResourceRecord::ANSWER ? ednsmask : boost::optional()); - if(i->first.place == DNSResourceRecord::ANSWER && ednsmask) - d_wasVariable=true; - } - set nsset; LOG(prefix< nsset; + bool realreferral=false, negindic=false, sawDS=false; + DNSName newauth; DNSName newtarget; - for(auto& rec : lwr.d_records) { - if (rec.d_type!=QType::OPT && rec.d_class!=QClass::IN) - continue; - - if(rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::SOA && - lwr.d_rcode==RCode::NXDomain && qname.isPartOf(rec.d_name) && rec.d_name.isPartOf(auth)) { - LOG(prefix<negcache, ne); - if(s_rootNXTrust && auth.isRoot()) { - ne.d_name = getLastLabel(ne.d_name); - replacing_insert(t_sstorage->negcache, ne); - } - } - - negindic=true; - } - else if(rec.d_place==DNSResourceRecord::ANSWER && rec.d_name == qname && rec.d_type==QType::CNAME && (!(qtype==QType(QType::CNAME)))) { - ret.push_back(rec); - if (auto content = getRR(rec)) { - newtarget=content->getTarget(); - } - } - else if((rec.d_type==QType::RRSIG || rec.d_type==QType::NSEC || rec.d_type==QType::NSEC3) && rec.d_place==DNSResourceRecord::ANSWER){ - if(rec.d_type != QType::RRSIG || rec.d_name == qname) - ret.push_back(rec); // enjoy your DNSSEC - } - // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively - else if(rec.d_place==DNSResourceRecord::ANSWER && rec.d_name == qname && - ( - rec.d_type==qtype.getCode() || (lwr.d_aabit && (qtype==QType(QType::ANY) || magicAddrMatch(qtype, QType(rec.d_type)) ) ) || sendRDQuery - ) - ) - { - - LOG(prefix<getZoneRepresentation()<<"|"< '"<getZoneRepresentation()<<"'"< '"<getZoneRepresentation()<<"', had '"<(rec)) { - nsset.insert(content->getNS()); - } - } - else if(rec.d_place==DNSResourceRecord::AUTHORITY && qname.isPartOf(rec.d_name) && rec.d_type==QType::DS) { - LOG(prefix< '"<getZoneRepresentation()<<"'"<negcache, ne); - } - } - negindic=true; - } - } - } + bool done = processRecords(prefix, qname, qtype, auth, lwr, sendRDQuery, ret, nsset, newtarget, newauth, realreferral, negindic, sawDS); if(done){ LOG(prefix< shuffleInSpeedOrder(NsSet &nameservers, const string &prefix); bool moreSpecificThan(const DNSName& a, const DNSName &b); vector getAddrs(const DNSName &qname, unsigned int depth, set& beenthere); + + bool nameserversBlockedByRPZ(const NsSet& nameservers); + bool nameserverIPBlockedByRPZ(const ComboAddress&); + bool throttledOrBlocked(const std::string& prefix, const ComboAddress& remoteIP, const DNSName& qname, const QType& qtype, bool pierceDontQuery); + + vector retrieveAddressesForNS(const std::string& prefix, const DNSName& qname, vector::const_iterator& tns, const unsigned int depth, set& beenthere, const vector& rnameservers, NsSet& nameservers, bool& sendRDQuery, bool& pierceDontQuery, bool& flawedNSSet); + RCode::rcodes_ updateCacheFromRecords(const std::string& prefix, LWResult& lwr, const DNSName& qname, const DNSName& auth, NsSet& nameservers, const DNSName& tns, const boost::optional); + bool processRecords(const std::string& prefix, const DNSName& qname, const QType& qtype, const DNSName& auth, LWResult& lwr, const bool sendRDQuery, vector& ret, set& nsset, DNSName& newtarget, DNSName& newauth, bool& realreferral, bool& negindic, bool& sawDS); + private: ostringstream d_trace; shared_ptr d_pdl; -- 2.50.0