From 8416631bf0202caba8159e29490f1ab8e1533fc8 Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Wed, 26 Dec 2018 11:18:29 +0100 Subject: [PATCH] rec: Add unit tests for the records sanitization in SyncRes --- pdns/recursordist/test-syncres_cc.cc | 181 +++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) diff --git a/pdns/recursordist/test-syncres_cc.cc b/pdns/recursordist/test-syncres_cc.cc index a6810e223..929dea179 100644 --- a/pdns/recursordist/test-syncres_cc.cc +++ b/pdns/recursordist/test-syncres_cc.cc @@ -10452,6 +10452,187 @@ BOOST_AUTO_TEST_CASE(test_cname_plus_authority_ns_ttl) { BOOST_CHECK_EQUAL(wasAuth, false); } +BOOST_AUTO_TEST_CASE(test_records_sanitization_general) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("sanitization.powerdns.com."); + + sr->setAsyncCallback([target](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) { + + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::A, "192.0.2.1"); + /* should be scrubbed because it doesn't match the QType */ + addRecordToLW(res, domain, QType::AAAA, "2001:db8::1"); + /* should be scrubbed because the DNAME is not relevant to the qname */ + addRecordToLW(res, DNSName("not-sanitization.powerdns.com."), QType::DNAME, "not-sanitization.powerdns.net."); + /* should be scrubbed because a MX has no reason to show up in AUTHORITY */ + addRecordToLW(res, domain, QType::MX, "10 mx.powerdns.com.", DNSResourceRecord::AUTHORITY); + /* should be scrubbed because the SOA name is not relevant to the qname */ + addRecordToLW(res, DNSName("not-sanitization.powerdns.com."), QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY); + /* should be scrubbed because types other than A or AAAA are not really supposed to show up in ADDITIONAL */ + addRecordToLW(res, domain, QType::TXT, "TXT", DNSResourceRecord::ADDITIONAL); + /* should be scrubbed because it doesn't match any of the accepted names in this answer (mostly 'domain') */ + addRecordToLW(res, DNSName("powerdns.com."), QType::AAAA, "2001:db8::1", DNSResourceRecord::ADDITIONAL); + return 1; + + return 0; + }); + + const time_t now = sr->getNow().tv_sec; + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + + const ComboAddress who; + vector cached; + BOOST_CHECK_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0); + cached.clear(); + BOOST_CHECK_LT(t_RC->get(now, target, QType(QType::AAAA), true, &cached, who), 0); + BOOST_CHECK_EQUAL(t_RC->get(now, DNSName("not-sanitization.powerdns.com."), QType(QType::DNAME), true, &cached, who), -1); + BOOST_CHECK_LT(t_RC->get(now, target, QType(QType::MX), true, &cached, who), 0); + BOOST_CHECK_EQUAL(t_RC->get(now, DNSName("not-sanitization.powerdns.com."), QType(QType::SOA), true, &cached, who), -1); + BOOST_CHECK_LT(t_RC->get(now, target, QType(QType::TXT), false, &cached, who), 0); + BOOST_CHECK_EQUAL(t_RC->get(now, DNSName("powerdns.com."), QType(QType::AAAA), false, &cached, who), -1); +} + +BOOST_AUTO_TEST_CASE(test_records_sanitization_keep_relevant_additional_aaaa) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("sanitization.powerdns.com."); + + sr->setAsyncCallback([target](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) { + + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::A, "192.0.2.1"); + addRecordToLW(res, domain, QType::AAAA, "2001:db8::1", DNSResourceRecord::ADDITIONAL); + return 1; + + return 0; + }); + + const time_t now = sr->getNow().tv_sec; + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_REQUIRE_EQUAL(ret.size(), 1); + + const ComboAddress who; + vector cached; + BOOST_CHECK_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0); + cached.clear(); + /* not auth since it was in the additional section */ + BOOST_CHECK_LT(t_RC->get(now, target, QType(QType::AAAA), true, &cached, who), 0); + BOOST_CHECK_GT(t_RC->get(now, target, QType(QType::AAAA), false, &cached, who), 0); +} + +BOOST_AUTO_TEST_CASE(test_records_sanitization_keep_glue) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("sanitization-glue.powerdns.com."); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target,&queriesCount](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) { + + queriesCount++; + + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.net.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "a.gtld-servers.net.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "a.gtld-servers.net.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + } + else if (ip == ComboAddress("192.0.2.1:53") || ip == ComboAddress("[2001:DB8::1]:53")) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "powerdns.com.", QType::NS, "pdns-public-ns2.powerdns.com.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::A, "192.0.2.2", DNSResourceRecord::ADDITIONAL, 172800); + addRecordToLW(res, "pdns-public-ns1.powerdns.com.", QType::AAAA, "2001:DB8::2", DNSResourceRecord::ADDITIONAL, 172800); + addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::A, "192.0.2.3", DNSResourceRecord::ADDITIONAL, 172800); + addRecordToLW(res, "pdns-public-ns2.powerdns.com.", QType::AAAA, "2001:DB8::3", DNSResourceRecord::ADDITIONAL, 172800); + return 1; + } + else if (ip == ComboAddress("192.0.2.2:53") || ip == ComboAddress("192.0.2.3:53") || ip == ComboAddress("[2001:DB8::2]:53") || ip == ComboAddress("[2001:DB8::3]:53")) { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, target, QType::A, "192.0.2.4"); + return 1; + } + else { + return 0; + } + }); + + const time_t now = sr->getNow().tv_sec; + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(ret.size(), 1); + BOOST_CHECK_EQUAL(queriesCount, 3); + + const ComboAddress who; + vector cached; + BOOST_CHECK_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0); + cached.clear(); + + BOOST_CHECK_GT(t_RC->get(now, DNSName("com."), QType(QType::NS), false, &cached, who), 0); + BOOST_CHECK_GT(t_RC->get(now, DNSName("a.gtld-servers.net."), QType(QType::A), false, &cached, who), 0); + BOOST_CHECK_GT(t_RC->get(now, DNSName("a.gtld-servers.net."), QType(QType::AAAA), false, &cached, who), 0); + BOOST_CHECK_GT(t_RC->get(now, DNSName("powerdns.com."), QType(QType::NS), false, &cached, who), 0); + BOOST_CHECK_GT(t_RC->get(now, DNSName("pdns-public-ns1.powerdns.com."), QType(QType::A), false, &cached, who), 0); + BOOST_CHECK_GT(t_RC->get(now, DNSName("pdns-public-ns1.powerdns.com."), QType(QType::AAAA), false, &cached, who), 0); + BOOST_CHECK_GT(t_RC->get(now, DNSName("pdns-public-ns2.powerdns.com."), QType(QType::A), false, &cached, who), 0); + BOOST_CHECK_GT(t_RC->get(now, DNSName("pdns-public-ns2.powerdns.com."), QType(QType::AAAA), false, &cached, who), 0); +} + +BOOST_AUTO_TEST_CASE(test_records_sanitization_scrubs_ns_nxd) { + std::unique_ptr sr; + initSR(sr); + + primeHints(); + + const DNSName target("sanitization-ns-nxd.powerdns.com."); + + sr->setAsyncCallback([target](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) { + + setLWResult(res, RCode::NXDomain, true, false, true); + addRecordToLW(res, "powerdns.com.", QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY); + addRecordToLW(res, "powerdns.com.", QType::NS, "spoofed.ns.", DNSResourceRecord::AUTHORITY, 172800); + addRecordToLW(res, "spoofed.ns.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRecordToLW(res, "spoofed.ns.", QType::AAAA, "2001:DB8::1", DNSResourceRecord::ADDITIONAL, 3600); + return 1; + }); + + const time_t now = sr->getNow().tv_sec; + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NXDomain); + BOOST_CHECK_EQUAL(ret.size(), 1); + + const ComboAddress who; + vector cached; + BOOST_CHECK_GT(t_RC->get(now, DNSName("powerdns.com."), QType(QType::SOA), true, &cached, who), 0); + cached.clear(); + + BOOST_CHECK_LT(t_RC->get(now, DNSName("powerdns.com."), QType(QType::NS), false, &cached, who), 0); + BOOST_CHECK_LT(t_RC->get(now, DNSName("spoofed.ns."), QType(QType::A), false, &cached, who), 0); + BOOST_CHECK_LT(t_RC->get(now, DNSName("spoofed.ns."), QType(QType::AAAA), false, &cached, who), 0); +} + /* // cerr<<"asyncresolve called to ask "<