From: Otto Moerbeek Date: Wed, 14 Dec 2022 13:06:36 +0000 (+0100) Subject: Generate EDE in more cases, specifically on unreachable auths or synthesized results. X-Git-Tag: dnsdist-1.8.0-rc1~142^2~4 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3e5667f995c7825bf17fd0622f72d1609101370e;p=thirdparty%2Fpdns.git Generate EDE in more cases, specifically on unreachable auths or synthesized results. As there is no specific EDE for synthesised, use noError with a text. We have to be careful here: a single client query can lead to multiple beginResolve calls. Some of these are done after the main result has been looked up, for example to validate the result. These subsequent calls can generate EDE's but we do not want to copy the EDE to the main result in those cases. A typical example would be an absent DS for an Insecure domain. Nothing wrong with these but we do not want the potential absent DS EDE (which could be synthesize) to be returned with the main query, To solve this, mimic the processing of validation state and add an extra argument to a few methods. I am not terribly happy with the extra argument. Maybe we should move to an object holding the parameters and result status of the nested or subsequent calls. This would also avoid some of the saveX, setX, beginResolve, restore X sequences. So marking this as Draft for now. --- diff --git a/pdns/recursordist/pdns_recursor.cc b/pdns/recursordist/pdns_recursor.cc index 5bc0969d4c..2e409a9a58 100644 --- a/pdns/recursordist/pdns_recursor.cc +++ b/pdns/recursordist/pdns_recursor.cc @@ -1474,7 +1474,7 @@ void startDoResolve(void* p) if (haveEDNS) { auto state = sr.getValidationState(); - if (dc->d_extendedErrorCode || (g_addExtendedResolutionDNSErrors && vStateIsBogus(state))) { + if (dc->d_extendedErrorCode || sr.d_extendedError || (SyncRes::s_addExtendedResolutionDNSErrors && vStateIsBogus(state))) { EDNSExtendedError::code code; std::string extra; @@ -1482,6 +1482,10 @@ void startDoResolve(void* p) code = static_cast(*dc->d_extendedErrorCode); extra = std::move(dc->d_extendedErrorExtra); } + else if (sr.d_extendedError) { + code = static_cast(sr.d_extendedError->infoCode); + extra = std::move(sr.d_extendedError->extraText); + } else { switch (state) { case vState::BogusNoValidDNSKEY: diff --git a/pdns/recursordist/rec-main.cc b/pdns/recursordist/rec-main.cc index b30f7fa262..0160aaedde 100644 --- a/pdns/recursordist/rec-main.cc +++ b/pdns/recursordist/rec-main.cc @@ -89,7 +89,6 @@ std::shared_ptr g_initialAllowNotifyFrom; // new threads need this std::shared_ptr g_initialAllowNotifyFor; // new threads need this to be setup bool g_logRPZChanges{false}; static time_t s_statisticsInterval; -bool g_addExtendedResolutionDNSErrors; static std::atomic s_counter; int g_argc; char** g_argv; @@ -1703,7 +1702,7 @@ static int serviceMain(int argc, char* argv[], Logr::log_t log) s_statisticsInterval = ::arg().asNum("statistics-interval"); - g_addExtendedResolutionDNSErrors = ::arg().mustDo("extended-resolution-errors"); + SyncRes::s_addExtendedResolutionDNSErrors = ::arg().mustDo("extended-resolution-errors"); if (::arg().asNum("aggressive-nsec-cache-size") > 0) { if (g_dnssecmode == DNSSECMode::ValidateAll || g_dnssecmode == DNSSECMode::ValidateForLog || g_dnssecmode == DNSSECMode::Process) { diff --git a/pdns/recursordist/rec-main.hh b/pdns/recursordist/rec-main.hh index cb3787a8ae..9416f4a8d7 100644 --- a/pdns/recursordist/rec-main.hh +++ b/pdns/recursordist/rec-main.hh @@ -217,7 +217,6 @@ extern bool g_useIncomingECS; extern boost::optional g_dns64Prefix; extern DNSName g_dns64PrefixReverse; extern uint64_t g_latencyStatSize; -extern bool g_addExtendedResolutionDNSErrors; extern NetmaskGroup g_proxyProtocolACL; extern std::atomic g_statsWanted; extern uint32_t g_disthashseed; diff --git a/pdns/recursordist/syncres.cc b/pdns/recursordist/syncres.cc index 79201e4f0f..ce92c99d39 100644 --- a/pdns/recursordist/syncres.cc +++ b/pdns/recursordist/syncres.cc @@ -467,6 +467,7 @@ bool SyncRes::s_dot_to_port_853; int SyncRes::s_event_trace_enabled; bool SyncRes::s_save_parent_ns_set; unsigned int SyncRes::s_max_busy_dot_probes; +bool SyncRes::s_addExtendedResolutionDNSErrors; #define LOG(x) \ if (d_lm == Log) { \ @@ -519,7 +520,8 @@ void SyncRes::resolveAdditionals(const DNSName& qname, QType qtype, AdditionalMo switch (mode) { case AdditionalMode::ResolveImmediately: { set beenthere; - int res = doResolve(qname, qtype, addRecords, depth, beenthere, state); + boost::optional extendedError; + int res = doResolve(qname, qtype, addRecords, depth, beenthere, state, extendedError); if (res != 0) { return; } @@ -563,7 +565,8 @@ void SyncRes::resolveAdditionals(const DNSName& qname, QType qtype, AdditionalMo case AdditionalMode::ResolveDeferred: { const bool oldCacheOnly = setCacheOnly(true); set beenthere; - int res = doResolve(qname, qtype, addRecords, depth, beenthere, state); + boost::optional extendedError; + int res = doResolve(qname, qtype, addRecords, depth, beenthere, state, extendedError); setCacheOnly(oldCacheOnly); if (res == 0 && addRecords.size() > 0) { // We're conservative here. We do not add Bogus records in any circumstance, we add Indeterminates only if no @@ -729,8 +732,10 @@ int SyncRes::beginResolve(const DNSName& qname, const QType qtype, QClass qclass } set beenthere; - int res = doResolve(qname, qtype, ret, depth, beenthere, state); + boost::optional extendedError; + int res = doResolve(qname, qtype, ret, depth, beenthere, state, extendedError); d_queryValidationState = state; + d_extendedError = extendedError; if (shouldValidate()) { if (d_queryValidationState != vState::Indeterminate) { @@ -1600,7 +1605,7 @@ static unsigned int qmStepLen(unsigned int labels, unsigned int qnamelen, unsign return targetlen; } -int SyncRes::doResolve(const DNSName& qname, const QType qtype, vector& ret, unsigned int depth, set& beenthere, vState& state) +int SyncRes::doResolve(const DNSName& qname, const QType qtype, vector& ret, unsigned int depth, set& beenthere, vState& state, boost::optional& extendedError) { string prefix = d_prefix; @@ -1624,7 +1629,7 @@ int SyncRes::doResolve(const DNSName& qname, const QType qtype, vector& ret, unsigned int depth, set& beenthere, vState& state, bool* fromCache, StopAtDelegation* stopAtDelegation, bool considerforwards) +int SyncRes::doResolveNoQNameMinimization(const DNSName& qname, const QType qtype, vector& ret, unsigned int depth, set& beenthere, vState& state, boost::optional& extendedError, bool* fromCache, StopAtDelegation* stopAtDelegation, bool considerforwards) { string prefix; if (doLog()) { @@ -1926,7 +1931,7 @@ int SyncRes::doResolveNoQNameMinimization(const DNSName& qname, const QType qtyp return res; } - if (doCacheCheck(qname, authname, wasForwardedOrAuthZone, wasAuthZone, wasForwardRecurse, qtype, ret, depth, res, state)) { + if (doCacheCheck(qname, authname, wasForwardedOrAuthZone, wasAuthZone, wasForwardRecurse, qtype, ret, depth, res, state, extendedError)) { // we done d_wasOutOfBand = wasAuthZone; if (fromCache) { @@ -1996,7 +2001,7 @@ int SyncRes::doResolveNoQNameMinimization(const DNSName& qname, const QType qtyp subdomain = getBestNSNamesFromCache(subdomain, qtype, nsset, &flawedNSSet, depth, beenthere); // pass beenthere to both occasions } - res = doResolveAt(nsset, subdomain, flawedNSSet, qname, qtype, ret, depth, beenthere, state, stopAtDelegation, nullptr); + res = doResolveAt(nsset, subdomain, flawedNSSet, qname, qtype, ret, depth, beenthere, state, extendedError, stopAtDelegation, nullptr); if (res == -1 && s_save_parent_ns_set) { // It did not work out, lets check if we have a saved parent NS set @@ -2015,8 +2020,8 @@ int SyncRes::doResolveNoQNameMinimization(const DNSName& qname, const QType qtyp } } if (fallBack.size() > 0) { - LOG(prefix << qname << ": Failure, but we have a saved parent NS set, trying that one" << endl) - res = doResolveAt(nsset, subdomain, flawedNSSet, qname, qtype, ret, depth, beenthere, state, stopAtDelegation, &fallBack); + LOG(prefix << qname << ": Failure, but we have a saved parent NS set, trying that one" << endl); + res = doResolveAt(nsset, subdomain, flawedNSSet, qname, qtype, ret, depth, beenthere, state, extendedError, stopAtDelegation, &fallBack); if (res == 0) { // It did work out s_savedParentNSSet.lock()->inc(subdomain); @@ -2113,9 +2118,10 @@ vector SyncRes::getAddrs(const DNSName& qname, unsigned int depth, if (ret.empty()) { // Neither A nor AAAA in the cache... vState newState = vState::Indeterminate; + boost::optional extendedError; cset.clear(); // Go out to get A's - if (s_doIPv4 && doResolve(qname, QType::A, cset, depth + 1, beenthere, newState) == 0) { // this consults cache, OR goes out + if (s_doIPv4 && doResolve(qname, QType::A, cset, depth + 1, beenthere, newState, extendedError) == 0) { // this consults cache, OR goes out for (auto const& i : cset) { if (i.d_type == QType::A) { if (auto rec = getRR(i)) { @@ -2129,7 +2135,7 @@ vector SyncRes::getAddrs(const DNSName& qname, unsigned int depth, // We only go out immediately to find IPv6 records if we did not find any IPv4 ones. newState = vState::Indeterminate; cset.clear(); - if (doResolve(qname, QType::AAAA, cset, depth + 1, beenthere, newState) == 0) { // this consults cache, OR goes out + if (doResolve(qname, QType::AAAA, cset, depth + 1, beenthere, newState, extendedError) == 0) { // this consults cache, OR goes out for (const auto& i : cset) { if (i.d_type == QType::AAAA) { if (auto rec = getRR(i)) { @@ -2644,9 +2650,10 @@ bool SyncRes::doCNAMECacheCheck(const DNSName& qname, const QType qtype, vector< set beenthere; vState cnameState = vState::Indeterminate; + boost::optional extendedError; // Be aware that going out on the network might be disabled (cache-only), for example because we are in QM Step0, // so you can't trust that a real lookup will have been made. - res = doResolve(newTarget, qtype, ret, depth + 1, beenthere, cnameState); + res = doResolve(newTarget, qtype, ret, depth + 1, beenthere, cnameState, extendedError); LOG(prefix << qname << ": updating validation state for response to " << qname << " from " << state << " with the state from the DNAME/CNAME quest: " << cnameState << endl); updateValidationState(state, cnameState); @@ -2775,7 +2782,7 @@ void SyncRes::computeNegCacheValidationStatus(const NegCache::NegCacheEntry& ne, } } -bool SyncRes::doCacheCheck(const DNSName& qname, const DNSName& authname, bool wasForwardedOrAuthZone, bool wasAuthZone, bool wasForwardRecurse, QType qtype, vector& ret, unsigned int depth, int& res, vState& state) +bool SyncRes::doCacheCheck(const DNSName& qname, const DNSName& authname, bool wasForwardedOrAuthZone, bool wasAuthZone, bool wasForwardRecurse, QType qtype, vector& ret, unsigned int depth, int& res, vState& state, boost::optional& extendedError) { bool giveNegative = false; @@ -2799,6 +2806,9 @@ bool SyncRes::doCacheCheck(const DNSName& qname, const DNSName& authname, bool w res = RCode::NXDomain; giveNegative = true; cachedState = ne.d_validationState; + if (s_addExtendedResolutionDNSErrors) { + extendedError = EDNSExtendedError{0, "Result synthesized by root-nx-trust"}; + } } else if (g_negCache->get(qname, qtype, d_now, ne, false, d_serveStale, d_refresh)) { /* If we are looking for a DS, discard NXD if auth == qname @@ -2822,6 +2832,10 @@ bool SyncRes::doCacheCheck(const DNSName& qname, const DNSName& authname, bool w else { LOG(prefix << qname << ": Entire name '" << qname << "' is negatively cached via '" << ne.d_auth << "' for another " << sttl << " seconds" << endl); } + if (s_addExtendedResolutionDNSErrors) { + // XXX Do we want this? + extendedError = EDNSExtendedError{0, "Result from negative cache"}; + } } } } @@ -2844,6 +2858,9 @@ bool SyncRes::doCacheCheck(const DNSName& qname, const DNSName& authname, bool w giveNegative = true; cachedState = ne.d_validationState; LOG(prefix << qname << ": Name '" << negCacheName << "' and below, is negatively cached via '" << ne.d_auth << "' for another " << sttl << " seconds" << endl); + if (s_addExtendedResolutionDNSErrors) { + extendedError = EDNSExtendedError{0, "Result synthesized by nothing-below-nxdomain (RFC8020)"}; + } break; } } @@ -3003,6 +3020,9 @@ bool SyncRes::doCacheCheck(const DNSName& qname, const DNSName& authname, bool w if (g_aggressiveNSECCache && !wasForwardedOrAuthZone) { if (g_aggressiveNSECCache->getDenial(d_now.tv_sec, qname, qtype, ret, res, d_cacheRemote, d_routingTag, d_doDNSSEC)) { state = vState::Secure; + if (s_addExtendedResolutionDNSErrors) { + extendedError = EDNSExtendedError{0, "Result synthesized from aggressive NSEC cache (RFC8198)"}; + } return true; } } @@ -3612,9 +3632,11 @@ vState SyncRes::getDSRecords(const DNSName& zone, dsmap_t& ds, bool taOnly, unsi std::vector dsrecords; vState state = vState::Indeterminate; + boost::optional extendedError; + const bool oldCacheOnly = setCacheOnly(false); const bool oldQM = setQNameMinimization(true); - int rcode = doResolve(zone, QType::DS, dsrecords, depth + 1, beenthere, state); + int rcode = doResolve(zone, QType::DS, dsrecords, depth + 1, beenthere, state, extendedError); setCacheOnly(oldCacheOnly); setQNameMinimization(oldQM); @@ -3869,8 +3891,10 @@ vState SyncRes::getDNSKeys(const DNSName& signer, skeyset_t& keys, bool& servFai LOG(d_prefix << "Retrieving DNSKeys for " << signer << endl); vState state = vState::Indeterminate; + boost::optional extendedError; + const bool oldCacheOnly = setCacheOnly(false); - int rcode = doResolve(signer, QType::DNSKEY, records, depth + 1, beenthere, state); + int rcode = doResolve(signer, QType::DNSKEY, records, depth + 1, beenthere, state, extendedError); setCacheOnly(oldCacheOnly); if (rcode == RCode::ServFail) { @@ -5126,7 +5150,8 @@ bool SyncRes::tryDoT(const DNSName& qname, const QType qtype, const DNSName& nsN // We use the fact that qname equals auth bool ok = false; try { - ok = doResolveAtThisIP("", qname, qtype, lwr, nm, qname, false, false, nsName, address, true, true, truncated, spoofed, true); + boost::optional extendedError; + ok = doResolveAtThisIP("", qname, qtype, lwr, nm, qname, false, false, nsName, address, true, true, truncated, spoofed, extendedError, true); ok = ok && lwr.d_rcode == RCode::NoError && lwr.d_records.size() > 0; } catch (const PDNSException& e) { @@ -5148,7 +5173,7 @@ bool SyncRes::tryDoT(const DNSName& qname, const QType qtype, const DNSName& nsN return ok; } -bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname, const QType qtype, LWResult& lwr, boost::optional& ednsmask, const DNSName& auth, bool const sendRDQuery, const bool wasForwarded, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool doDoT, bool& truncated, bool& spoofed, bool dontThrottle) +bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname, const QType qtype, LWResult& lwr, boost::optional& ednsmask, const DNSName& auth, bool const sendRDQuery, const bool wasForwarded, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool doDoT, bool& truncated, bool& spoofed, boost::optional& extendedError, bool dontThrottle) { bool chained = false; LWResult::Result resolveret = LWResult::Result::Success; @@ -5157,6 +5182,9 @@ bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname, checkMaxQperQ(qname); if (s_maxtotusec && d_totUsec > s_maxtotusec) { + if (s_addExtendedResolutionDNSErrors) { + extendedError = EDNSExtendedError{static_cast(EDNSExtendedError::code::NoReachableAuthority), "Timeout waiting for answer(s)"}; + } throw ImmediateServFailException("Too much time waiting for " + qname.toLogString() + "|" + qtype.toString() + ", timeouts: " + std::to_string(d_timeouts) + ", throttles: " + std::to_string(d_throttledqueries) + ", queries: " + std::to_string(d_outqueries) + ", " + std::to_string(d_totUsec / 1000) + "msec"); } @@ -5379,7 +5407,8 @@ void SyncRes::handleNewTarget(const std::string& prefix, const DNSName& qname, c set beenthere; vState cnameState = vState::Indeterminate; - rcode = doResolve(newtarget, qtype, ret, depth + 1, beenthere, cnameState); + boost::optional extendedError; + rcode = doResolve(newtarget, qtype, ret, depth + 1, beenthere, cnameState, extendedError); LOG(prefix << qname << ": updating validation state for response to " << qname << " from " << state << " with the state from the CNAME quest: " << cnameState << endl); updateValidationState(state, cnameState); } @@ -5526,7 +5555,7 @@ bool SyncRes::doDoTtoAuth(const DNSName& ns) const */ int SyncRes::doResolveAt(NsSet& nameservers, DNSName auth, bool flawedNSSet, const DNSName& qname, const QType qtype, vector& ret, - unsigned int depth, set& beenthere, vState& state, StopAtDelegation* stopAtDelegation, + unsigned int depth, set& beenthere, vState& state, boost::optional& extendedError, StopAtDelegation* stopAtDelegation, map>* fallBack) { auto luaconfsLocal = g_luaconfs.getLocal(); @@ -5571,11 +5600,14 @@ int SyncRes::doResolveAt(NsSet& nameservers, DNSName auth, bool flawedNSSet, con } if (tns == rnameservers.cend()) { LOG(prefix << qname << ": Failed to resolve via any of the " << (unsigned int)rnameservers.size() << " offered NS at level '" << auth << "'" << endl); + if (s_addExtendedResolutionDNSErrors) { + extendedError = EDNSExtendedError{static_cast(EDNSExtendedError::code::NoReachableAuthority), "delegation " + auth.toLogString()}; + } if (!auth.isRoot() && flawedNSSet) { LOG(prefix << qname << ": Ageing nameservers for level '" << auth << "', next query might succeed" << endl); - - if (g_recCache->doAgeCache(d_now.tv_sec, auth, QType::NS, 10)) + if (g_recCache->doAgeCache(d_now.tv_sec, auth, QType::NS, 10)) { t_Counters.at(rec::Counter::nsSetInvalidations)++; + } } return -1; } @@ -5691,12 +5723,12 @@ int SyncRes::doResolveAt(NsSet& nameservers, DNSName auth, bool flawedNSSet, con } if (!forceTCP) { gotAnswer = doResolveAtThisIP(prefix, qname, qtype, lwr, ednsmask, auth, sendRDQuery, wasForwarded, - tns->first, *remoteIP, false, false, truncated, spoofed); + tns->first, *remoteIP, false, false, truncated, spoofed, extendedError); } if (forceTCP || (spoofed || (gotAnswer && truncated))) { /* retry, over TCP this time */ gotAnswer = doResolveAtThisIP(prefix, qname, qtype, lwr, ednsmask, auth, sendRDQuery, wasForwarded, - tns->first, *remoteIP, true, doDoT, truncated, spoofed); + tns->first, *remoteIP, true, doDoT, truncated, spoofed, extendedError); } if (!gotAnswer) { diff --git a/pdns/recursordist/syncres.hh b/pdns/recursordist/syncres.hh index 097e1db7d2..43bd45e381 100644 --- a/pdns/recursordist/syncres.hh +++ b/pdns/recursordist/syncres.hh @@ -54,6 +54,7 @@ #include "rec-eventtrace.hh" #include "logr.hh" #include "rec-tcounters.hh" +#include "ednsextendederror.hh" #ifdef HAVE_CONFIG_H #include "config.h" @@ -520,6 +521,7 @@ public: static const int event_trace_to_log = 2; static int s_event_trace_enabled; static bool s_save_parent_ns_set; + static bool s_addExtendedResolutionDNSErrors; std::unordered_map d_discardedPolicies; DNSFilterEngine::Policy d_appliedPolicy; @@ -528,6 +530,7 @@ public: ComboAddress d_fromAuthIP; RecEventTrace d_eventTrace; std::shared_ptr d_slog = g_slog->withName("syncres"); + boost::optional d_extendedError; unsigned int d_authzonequeries; unsigned int d_outqueries; @@ -575,20 +578,20 @@ private: bool doDoTtoAuth(const DNSName& ns) const; int doResolveAt(NsSet& nameservers, DNSName auth, bool flawedNSSet, const DNSName& qname, QType qtype, vector& ret, - unsigned int depth, set& beenthere, vState& state, StopAtDelegation* stopAtDelegation, + unsigned int depth, set& beenthere, vState& state, boost::optional& extendedError, StopAtDelegation* stopAtDelegation, std::map>* fallback); - bool doResolveAtThisIP(const std::string& prefix, const DNSName& qname, const QType qtype, LWResult& lwr, boost::optional& ednsmask, const DNSName& auth, bool const sendRDQuery, const bool wasForwarded, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool doDoT, bool& truncated, bool& spoofed, bool dontThrottle = false); + bool doResolveAtThisIP(const std::string& prefix, const DNSName& qname, const QType qtype, LWResult& lwr, boost::optional& ednsmask, const DNSName& auth, bool const sendRDQuery, const bool wasForwarded, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool doDoT, bool& truncated, bool& spoofed, boost::optional& extendedError, bool dontThrottle = false); bool processAnswer(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType qtype, DNSName& auth, bool wasForwarded, const boost::optional ednsmask, bool sendRDQuery, NsSet& nameservers, std::vector& ret, const DNSFilterEngine& dfe, bool* gotNewServers, int* rcode, vState& state, const ComboAddress& remoteIP); - int doResolve(const DNSName& qname, QType qtype, vector& ret, unsigned int depth, set& beenthere, vState& state); - int doResolveNoQNameMinimization(const DNSName& qname, QType qtype, vector& ret, unsigned int depth, set& beenthere, vState& state, bool* fromCache = NULL, StopAtDelegation* stopAtDelegation = NULL, bool considerforwards = true); + int doResolve(const DNSName& qname, QType qtype, vector& ret, unsigned int depth, set& beenthere, vState& state, boost::optional& extendedError); + int doResolveNoQNameMinimization(const DNSName& qname, QType qtype, vector& ret, unsigned int depth, set& beenthere, vState& state, boost::optional& extendedError, bool* fromCache = NULL, StopAtDelegation* stopAtDelegation = NULL, bool considerforwards = true); bool doOOBResolve(const AuthDomain& domain, const DNSName& qname, QType qtype, vector& ret, int& res); bool doOOBResolve(const DNSName& qname, QType qtype, vector& ret, unsigned int depth, int& res); bool isRecursiveForwardOrAuth(const DNSName& qname) const; bool isForwardOrAuth(const DNSName& qname) const; domainmap_t::const_iterator getBestAuthZone(DNSName* qname) const; bool doCNAMECacheCheck(const DNSName& qname, QType qtype, vector& ret, unsigned int depth, int& res, vState& state, bool wasAuthZone, bool wasForwardRecurse); - bool doCacheCheck(const DNSName& qname, const DNSName& authname, bool wasForwardedOrAuthZone, bool wasAuthZone, bool wasForwardRecurse, QType qtype, vector& ret, unsigned int depth, int& res, vState& state); + bool doCacheCheck(const DNSName& qname, const DNSName& authname, bool wasForwardedOrAuthZone, bool wasAuthZone, bool wasForwardRecurse, QType qtype, vector& ret, unsigned int depth, int& res, vState& state, boost::optional& extendedError); void getBestNSFromCache(const DNSName& qname, QType qtype, vector& bestns, bool* flawedNSSet, unsigned int depth, set& beenthere, const boost::optional& cutOffDomain = boost::none); DNSName getBestNSNamesFromCache(const DNSName& qname, QType qtype, NsSet& nsset, bool* flawedNSSet, unsigned int depth, set& beenthere);