From: Otto Moerbeek Date: Mon, 28 Jul 2025 11:19:11 +0000 (+0200) Subject: Check to see if authoritative NS and/or address records are usable X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5c3d54681b9be5d0659d4ae82ac4c2ecbfc0ecc2;p=thirdparty%2Fpdns.git Check to see if authoritative NS and/or address records are usable In the typical case we deal with non-authoritative records here, but we *might* have them in cache authoritatively. Signed-off-by: Otto Moerbeek --- diff --git a/pdns/recursordist/syncres.cc b/pdns/recursordist/syncres.cc index ea2048219c..2ccc4607ee 100644 --- a/pdns/recursordist/syncres.cc +++ b/pdns/recursordist/syncres.cc @@ -2220,6 +2220,16 @@ vector SyncRes::getAddrs(const DNSName& qname, unsigned int depth, return ret; } +bool SyncRes::canUseRecords(const std::string& prefix, const DNSName& qname, const DNSName& name, QType qtype, vState state) +{ + if (vStateIsBogus(state)) { + LOG(prefix << qname << ": Cannot use " << name << '/' << qtype << " records from cache: Bogus" << endl); + return false; + } + // We could validate Indeterminete authoritative records here. + return true; +} + void SyncRes::getBestNSFromCache(const DNSName& qname, const QType qtype, vector& bestns, bool* flawedNSSet, unsigned int depth, const string& prefix, set& beenthere, const boost::optional& cutOffDomain) // NOLINT(readability-function-cognitive-complexity) { DNSName subdomain(qname); @@ -2238,7 +2248,9 @@ void SyncRes::getBestNSFromCache(const DNSName& qname, const QType qtype, vector vector nsVector; *flawedNSSet = false; - if (bool isAuth = false; g_recCache->get(d_now.tv_sec, subdomain, QType::NS, flags, &nsVector, d_cacheRemote, d_routingTag, nullptr, nullptr, nullptr, nullptr, &isAuth) > 0) { + vState state{vState::Indeterminate}; + if (bool isAuth = false; g_recCache->get(d_now.tv_sec, subdomain, QType::NS, flags, &nsVector, d_cacheRemote, d_routingTag, nullptr, nullptr, nullptr, nullptr, &isAuth) > 0 && + canUseRecords(prefix, qname, subdomain, QType::NS, state)) { if (s_maxnsperresolve > 0 && nsVector.size() > s_maxnsperresolve) { vector selected; selected.reserve(s_maxnsperresolve); @@ -2260,7 +2272,12 @@ void SyncRes::getBestNSFromCache(const DNSName& qname, const QType qtype, vector } auto nrr = getRR(nsRecord); - if (nrr && (!nrr->getNS().isPartOf(subdomain) || g_recCache->get(d_now.tv_sec, nrr->getNS(), nsqt, flags, doLog() ? &aset : nullptr, d_cacheRemote, d_routingTag) > 0)) { + state = vState::Indeterminate; + if (nrr && (!nrr->getNS().isPartOf(subdomain) || g_recCache->get(d_now.tv_sec, nrr->getNS(), nsqt, flags, doLog() ? &aset : nullptr, d_cacheRemote, d_routingTag, nullptr, nullptr, nullptr, &state) > 0)) { + // We make use of the fact that if get() is not called the state is still Indeterminate + if (!canUseRecords(prefix, qname, nrr->getNS(), nsqt, state)) { + continue; + } bestns.push_back(nsRecord); LOG(prefix << qname << ": NS (with ip, or non-glue) in cache for '" << subdomain << "' -> '" << nrr->getNS() << "'"); LOG(", within bailiwick: " << nrr->getNS().isPartOf(subdomain)); diff --git a/pdns/recursordist/syncres.hh b/pdns/recursordist/syncres.hh index 050c07c98e..e0c9bf71a9 100644 --- a/pdns/recursordist/syncres.hh +++ b/pdns/recursordist/syncres.hh @@ -658,6 +658,7 @@ private: static domainmap_t::const_iterator getBestAuthZone(DNSName* qname); bool doCNAMECacheCheck(const DNSName& qname, QType qtype, vector& ret, unsigned int depth, const string& prefix, int& res, Context& context, bool wasAuthZone, bool wasForwardRecurse, bool checkForDups); bool doCacheCheck(const DNSName& qname, const DNSName& authname, bool wasForwardedOrAuthZone, bool wasAuthZone, bool wasForwardRecurse, QType qtype, vector& ret, unsigned int depth, const string& prefix, int& res, Context& context); + bool canUseRecords(const std::string& prefix, const DNSName& qname, const DNSName& name, QType qtype, vState state); void getBestNSFromCache(const DNSName& qname, QType qtype, vector& bestns, bool* flawedNSSet, unsigned int depth, const string& prefix, set& beenthere, const boost::optional& cutOffDomain = boost::none); DNSName getBestNSNamesFromCache(const DNSName& qname, QType qtype, NsSet& nsset, bool* flawedNSSet, unsigned int depth, const string& prefix, set& beenthere);