From a237278908f4557cac27f2bcf822f356e33960eb 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 6fb756b6cd49d61eacf7865ce48d0edb62730710) (cherry picked from commit d8b9d57103f1e1496767d9fac3955b1973e04302) --- 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 03f424ca21..b45362456d 100644 --- a/pdns/recursordist/test-syncres_cc.cc +++ b/pdns/recursordist/test-syncres_cc.cc @@ -647,6 +647,54 @@ BOOST_AUTO_TEST_CASE(test_edns_notimp_fallback) { BOOST_CHECK_EQUAL(queriesWithoutEDNS, 1); } +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, std::shared_ptr outgoingLogger, 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 f2813b4a82..78a7ca4cfe 100644 --- a/pdns/syncres.cc +++ b/pdns/syncres.cc @@ -479,7 +479,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_rcode == RCode::FormErr || res->d_rcode == RCode::NotImp) { + if(!res->d_haveEDNS && (res->d_rcode == RCode::FormErr || res->d_rcode == RCode::NotImp)) { // cerr<<"Downgrading to NOEDNS because of "<d_rcode)<<" for query to "<