From 27ae17df820677d6165264c7f4594b1912c3e85c Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Thu, 20 Sep 2018 14:46:11 +0200 Subject: [PATCH] rec: Keep the EDNS status of a server on FormErr with EDNS Note that the choice of DNAME in the unit test is an arbitrary choice, we could even have used A here. (cherry picked from commit ff45e509a92b6f22ff8b61d15731b26235523350) --- pdns/recursordist/test-syncres_cc.cc | 48 ++++++++++++++++++++++++++++ pdns/syncres.cc | 2 +- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/pdns/recursordist/test-syncres_cc.cc b/pdns/recursordist/test-syncres_cc.cc index c547ea3f5..c6c8782b8 100644 --- a/pdns/recursordist/test-syncres_cc.cc +++ b/pdns/recursordist/test-syncres_cc.cc @@ -617,6 +617,54 @@ BOOST_AUTO_TEST_CASE(test_edns_formerr_fallback) { BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(noEDNSServer), SyncRes::EDNSStatus::NOEDNS); } +BOOST_AUTO_TEST_CASE(test_edns_formerr_but_edns_enabled) { + std::unique_ptr sr; + initSR(sr); + + /* in this test, the auth answers with FormErr to an EDNS-enabled + query, but the response does contain EDNS so we should not mark + it as EDNS ignorant or intolerant. + */ + size_t queriesWithEDNS = 0; + size_t queriesWithoutEDNS = 0; + std::set usedServers; + + sr->setAsyncCallback([&queriesWithEDNS, &queriesWithoutEDNS, &usedServers](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, LWResult* res, bool* chained) { + + if (EDNS0Level > 0) { + queriesWithEDNS++; + } + else { + queriesWithoutEDNS++; + } + usedServers.insert(ip); + + if (type == QType::DNAME) { + setLWResult(res, RCode::FormErr); + if (EDNS0Level > 0) { + res->d_haveEDNS = true; + } + return 1; + } + + return 0; + }); + + primeHints(); + + vector ret; + int res = sr->beginResolve(DNSName("powerdns.com."), QType(QType::DNAME), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::ServFail); + BOOST_CHECK_EQUAL(ret.size(), 0); + BOOST_CHECK_EQUAL(queriesWithEDNS, 26); + BOOST_CHECK_EQUAL(queriesWithoutEDNS, 0); + BOOST_CHECK_EQUAL(SyncRes::getEDNSStatusesSize(), 26); + BOOST_CHECK_EQUAL(usedServers.size(), 26); + for (const auto& server : usedServers) { + BOOST_CHECK_EQUAL(SyncRes::getEDNSStatus(server), SyncRes::EDNSStatus::EDNSOK); + } +} + BOOST_AUTO_TEST_CASE(test_tc_fallback_to_tcp) { std::unique_ptr sr; initSR(sr); diff --git a/pdns/syncres.cc b/pdns/syncres.cc index caaa33078..84ae05c70 100644 --- a/pdns/syncres.cc +++ b/pdns/syncres.cc @@ -504,7 +504,7 @@ int SyncRes::asyncresolveWrapper(const ComboAddress& ip, bool ednsMANDATORY, con return ret; } else if(mode==EDNSStatus::UNKNOWN || mode==EDNSStatus::EDNSOK || mode == EDNSStatus::EDNSIGNORANT ) { - if(res->d_validpacket && res->d_rcode == RCode::FormErr) { + if(res->d_validpacket && !res->d_haveEDNS && res->d_rcode == RCode::FormErr) { // cerr<<"Downgrading to NOEDNS because of "<d_rcode)<<" for query to "<