From: Remi Gacogne Date: Thu, 17 Dec 2020 13:45:59 +0000 (+0100) Subject: rec: Store the zone and remote server IP in the records cache X-Git-Tag: rec-4.5.0-alpha1~40^2~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=928c0f926859012945a223d28ffd3ce3f3ba2ac1;p=thirdparty%2Fpdns.git rec: Store the zone and remote server IP in the records cache --- diff --git a/pdns/recursor_cache.cc b/pdns/recursor_cache.cc index 497147b97b..8a798a60a1 100644 --- a/pdns/recursor_cache.cc +++ b/pdns/recursor_cache.cc @@ -111,7 +111,7 @@ static void updateDNSSECValidationStateFromCache(boost::optional& state, } } -int32_t MemRecursorCache::handleHit(MapCombo& map, MemRecursorCache::OrderedTagIterator_t& entry, const DNSName& qname, vector* res, vector>* signatures, std::vector>* authorityRecs, bool* variable, boost::optional& state, bool* wasAuth) +int32_t MemRecursorCache::handleHit(MapCombo& map, MemRecursorCache::OrderedTagIterator_t& entry, const DNSName& qname, vector* res, vector>* signatures, std::vector>* authorityRecs, bool* variable, boost::optional& state, bool* wasAuth, DNSName* fromAuthZone) { // MUTEX SHOULD BE ACQUIRED int32_t ttd = entry->d_ttd; @@ -150,6 +150,10 @@ int32_t MemRecursorCache::handleHit(MapCombo& map, MemRecursorCache::OrderedTagI *wasAuth = *wasAuth && entry->d_auth; } + if (fromAuthZone) { + *fromAuthZone = entry->d_authZone; + } + moveCacheItemToBack(map.d_map, entry); return ttd; @@ -246,7 +250,7 @@ bool MemRecursorCache::entryMatches(MemRecursorCache::OrderedTagIterator_t& entr } // returns -1 for no hits -int32_t MemRecursorCache::get(time_t now, const DNSName &qname, const QType& qt, bool requireAuth, vector* res, const ComboAddress& who, const OptTag& routingTag, vector>* signatures, std::vector>* authorityRecs, bool* variable, vState* state, bool* wasAuth) +int32_t MemRecursorCache::get(time_t now, const DNSName &qname, const QType& qt, bool requireAuth, vector* res, const ComboAddress& who, const OptTag& routingTag, vector>* signatures, std::vector>* authorityRecs, bool* variable, vState* state, bool* wasAuth, DNSName* fromAuthZone) { boost::optional cachedState{boost::none}; time_t ttd=0; @@ -272,11 +276,11 @@ int32_t MemRecursorCache::get(time_t now, const DNSName &qname, const QType& qt, auto entryA = getEntryUsingECSIndex(map, now, qname, QType::A, requireAuth, who); if (entryA != map.d_map.end()) { - ret = handleHit(map, entryA, qname, res, signatures, authorityRecs, variable, cachedState, wasAuth); + ret = handleHit(map, entryA, qname, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone); } auto entryAAAA = getEntryUsingECSIndex(map, now, qname, QType::AAAA, requireAuth, who); if (entryAAAA != map.d_map.end()) { - int32_t ttdAAAA = handleHit(map, entryAAAA, qname, res, signatures, authorityRecs, variable, cachedState, wasAuth); + int32_t ttdAAAA = handleHit(map, entryAAAA, qname, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone); if (ret > 0) { ret = std::min(ret, ttdAAAA); } else { @@ -293,7 +297,7 @@ int32_t MemRecursorCache::get(time_t now, const DNSName &qname, const QType& qt, else { auto entry = getEntryUsingECSIndex(map, now, qname, qtype, requireAuth, who); if (entry != map.d_map.end()) { - int32_t ret = handleHit(map, entry, qname, res, signatures, authorityRecs, variable, cachedState, wasAuth); + int32_t ret = handleHit(map, entry, qname, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone); if (state && cachedState) { *state = *cachedState; } @@ -319,7 +323,7 @@ int32_t MemRecursorCache::get(time_t now, const DNSName &qname, const QType& qt, continue; } - ttd = handleHit(map, firstIndexIterator, qname, res, signatures, authorityRecs, variable, cachedState, wasAuth); + ttd = handleHit(map, firstIndexIterator, qname, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone); if (qt.getCode() != QType::ANY && qt.getCode() != QType::ADDR) { // normally if we have a hit, we are done break; @@ -347,7 +351,7 @@ int32_t MemRecursorCache::get(time_t now, const DNSName &qname, const QType& qt, continue; } - ttd = handleHit(map, firstIndexIterator, qname, res, signatures, authorityRecs, variable, cachedState, wasAuth); + ttd = handleHit(map, firstIndexIterator, qname, res, signatures, authorityRecs, variable, cachedState, wasAuth, fromAuthZone); if (qt.getCode() != QType::ANY && qt.getCode() != QType::ADDR) { // normally if we have a hit, we are done break; @@ -361,7 +365,7 @@ int32_t MemRecursorCache::get(time_t now, const DNSName &qname, const QType& qt, return -1; } -void MemRecursorCache::replace(time_t now, const DNSName &qname, const QType& qt, const vector& content, const vector>& signatures, const std::vector>& authorityRecs, bool auth, boost::optional ednsmask, const OptTag& routingTag, vState state) +void MemRecursorCache::replace(time_t now, const DNSName &qname, const QType& qt, const vector& content, const vector>& signatures, const std::vector>& authorityRecs, bool auth, const DNSName& authZone, boost::optional ednsmask, const OptTag& routingTag, vState state, boost::optional from) { auto& map = getMap(qname); const lock l(map); @@ -403,8 +407,6 @@ void MemRecursorCache::replace(time_t now, const DNSName &qname, const QType& qt time_t maxTTD=std::numeric_limits::max(); CacheEntry ce=*stored; // this is a COPY ce.d_qtype=qt.getCode(); - ce.d_signatures=signatures; - ce.d_authorityRecs=authorityRecs; // cerr<<"asked to store "<< (qname.empty() ? "EMPTY" : qname.toString()) <<"|"+qt.getName()<<" -> '"; // cerr<<(content.empty() ? string("EMPTY CONTENT") : content.begin()->d_content->getZoneRepresentation())<<"', auth="<auth NS set replace to "<(i.d_ttl)); // XXX this does weird things if TTLs differ in the set @@ -619,12 +627,12 @@ uint64_t MemRecursorCache::doDump(int fd) const lock l(map); const auto& sidx = map.d_map.get(); - time_t now = time(0); + time_t now = time(nullptr); for (const auto& i : sidx) { for (const auto& j : i.d_records) { count++; try { - fprintf(fp.get(), "%s %" PRId64 " IN %s %s ; (%s) auth=%i %s %s\n", i.d_qname.toString().c_str(), static_cast(i.d_ttd - now), DNSRecordContent::NumberToType(i.d_qtype).c_str(), j->getZoneRepresentation().c_str(), vStateToString(i.d_state).c_str(), i.d_auth, i.d_netmask.empty() ? "" : i.d_netmask.toString().c_str(), !i.d_rtag ? "" : i.d_rtag.get().c_str()); + fprintf(fp.get(), "%s %" PRId64 " IN %s %s ; (%s) auth=%i zone=%s from=%s %s %s\n", i.d_qname.toString().c_str(), static_cast(i.d_ttd - now), DNSRecordContent::NumberToType(i.d_qtype).c_str(), j->getZoneRepresentation().c_str(), vStateToString(i.d_state).c_str(), i.d_auth, i.d_authZone.toLogString().c_str(), i.d_from.toString().c_str(), i.d_netmask.empty() ? "" : i.d_netmask.toString().c_str(), !i.d_rtag ? "" : i.d_rtag.get().c_str()); } catch(...) { fprintf(fp.get(), "; error printing '%s'\n", i.d_qname.empty() ? "EMPTY" : i.d_qname.toString().c_str()); diff --git a/pdns/recursor_cache.hh b/pdns/recursor_cache.hh index b2cbca1125..ed81e8cefb 100644 --- a/pdns/recursor_cache.hh +++ b/pdns/recursor_cache.hh @@ -57,9 +57,9 @@ public: typedef boost::optional OptTag; - int32_t get(time_t, const DNSName &qname, const QType& qt, bool requireAuth, vector* res, const ComboAddress& who, const OptTag& routingTag = boost::none, vector>* signatures=nullptr, std::vector>* authorityRecs=nullptr, bool* variable=nullptr, vState* state=nullptr, bool* wasAuth=nullptr); + int32_t get(time_t, const DNSName &qname, const QType& qt, bool requireAuth, vector* res, const ComboAddress& who, const OptTag& routingTag = boost::none, vector>* signatures=nullptr, std::vector>* authorityRecs=nullptr, bool* variable=nullptr, vState* state=nullptr, bool* wasAuth=nullptr, DNSName* fromAuthZone=nullptr); - void replace(time_t, const DNSName &qname, const QType& qt, const vector& content, const vector>& signatures, const std::vector>& authorityRecs, bool auth, boost::optional ednsmask=boost::none, const OptTag& routingTag = boost::none, vState state=vState::Indeterminate); + void replace(time_t, const DNSName &qname, const QType& qt, const vector& content, const vector>& signatures, const std::vector>& authorityRecs, bool auth, const DNSName& authZone, boost::optional ednsmask=boost::none, const OptTag& routingTag = boost::none, vState state=vState::Indeterminate, boost::optional from=boost::none); void doPrune(size_t keep); uint64_t doDump(int fd); @@ -89,6 +89,8 @@ private: std::vector> d_signatures; std::vector> d_authorityRecs; DNSName d_qname; + DNSName d_authZone; + ComboAddress d_from; Netmask d_netmask; OptTag d_rtag; mutable vState d_state; @@ -230,7 +232,7 @@ private: bool entryMatches(OrderedTagIterator_t& entry, uint16_t qt, bool requireAuth, const ComboAddress& who); Entries getEntries(MapCombo& map, const DNSName &qname, const QType& qt, const OptTag& rtag); cache_t::const_iterator getEntryUsingECSIndex(MapCombo& map, time_t now, const DNSName &qname, uint16_t qtype, bool requireAuth, const ComboAddress& who); - int32_t handleHit(MapCombo& map, OrderedTagIterator_t& entry, const DNSName& qname, vector* res, vector>* signatures, std::vector>* authorityRecs, bool* variable, boost::optional& state, bool* wasAuth); + int32_t handleHit(MapCombo& map, OrderedTagIterator_t& entry, const DNSName& qname, vector* res, vector>* signatures, std::vector>* authorityRecs, bool* variable, boost::optional& state, bool* wasAuth, DNSName* authZone); public: struct lock { diff --git a/pdns/recursordist/test-recursorcache_cc.cc b/pdns/recursordist/test-recursorcache_cc.cc index a96edf020d..799240bd63 100644 --- a/pdns/recursordist/test-recursorcache_cc.cc +++ b/pdns/recursordist/test-recursorcache_cc.cc @@ -18,6 +18,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple) std::vector records; std::vector> authRecords; std::vector> signatures; + const DNSName authZone("."); time_t now = time(nullptr); time_t ttd = now + 30; @@ -34,7 +35,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple) records.push_back(dr0); BOOST_CHECK_EQUAL(MRC.size(), 0U); - MRC.replace(now, DNSName("hello"), QType(QType::A), records, signatures, authRecords, true, boost::none); + MRC.replace(now, DNSName("hello"), QType(QType::A), records, signatures, authRecords, true, authZone, boost::none); BOOST_CHECK_EQUAL(MRC.size(), 1U); BOOST_CHECK_GT(MRC.bytes(), 1U); BOOST_CHECK_EQUAL(MRC.doWipeCache(DNSName("hello"), false, QType::A), 1U); @@ -47,10 +48,10 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple) DNSName a = DNSName("hello ") + DNSName(std::to_string(counter)); BOOST_CHECK_EQUAL(DNSName(a.toString()), a); - MRC.replace(now, a, QType(QType::A), records, signatures, authRecords, true, boost::none); + MRC.replace(now, a, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none); if (!MRC.doWipeCache(a, false)) BOOST_FAIL("Could not remove entry we just added to the cache!"); - MRC.replace(now, a, QType(QType::A), records, signatures, authRecords, true, boost::none); + MRC.replace(now, a, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none); } BOOST_CHECK_EQUAL(MRC.size(), counter); @@ -102,7 +103,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple) // insert a subnet specific entry records.clear(); records.push_back(dr1); - MRC.replace(now, power, QType(QType::AAAA), records, signatures, authRecords, true, boost::optional("192.0.2.1/25")); + MRC.replace(now, power, QType(QType::AAAA), records, signatures, authRecords, true, authZone, boost::optional("192.0.2.1/25")); BOOST_CHECK_EQUAL(MRC.size(), 1U); // subnet specific should be returned for a matching subnet @@ -121,7 +122,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple) // insert a NON-subnet specific entry records.clear(); records.push_back(dr2); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::none); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none); BOOST_CHECK_EQUAL(MRC.size(), 1U); // NON-subnet specific should always be returned @@ -132,14 +133,14 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple) // insert a subnet specific entry for the same name but a different QType records.clear(); records.push_back(dr1); - MRC.replace(now, power, QType(QType::AAAA), records, signatures, authRecords, true, boost::optional("192.0.2.1/25")); + MRC.replace(now, power, QType(QType::AAAA), records, signatures, authRecords, true, authZone, boost::optional("192.0.2.1/25")); // we should not have replaced the existing entry BOOST_CHECK_EQUAL(MRC.size(), 2U); // insert a TXT one, we will use that later records.clear(); records.push_back(dr1); - MRC.replace(now, power, QType(QType::TXT), records, signatures, authRecords, true, boost::none); + MRC.replace(now, power, QType(QType::TXT), records, signatures, authRecords, true, authZone, boost::none); // we should not have replaced any existing entry BOOST_CHECK_EQUAL(MRC.size(), 3U); @@ -223,7 +224,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple) // insert auth record records.push_back(dr2); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::none); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none); BOOST_CHECK_EQUAL(MRC.size(), 1U); BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), false, &retrieved, ComboAddress("127.0.0.1")), (ttd - now)); BOOST_CHECK_EQUAL(retrieved.size(), 1U); @@ -245,23 +246,23 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple) records.push_back(dr3); // non-auth should not replace valid auth - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, false, boost::none); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, false, authZone, boost::none); BOOST_CHECK_EQUAL(MRC.size(), 1U); BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), false, &retrieved, ComboAddress("127.0.0.1")), (ttd - now)); BOOST_REQUIRE_EQUAL(retrieved.size(), 1U); BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr2Content.toString()); // but non-auth _should_ replace expired auth - MRC.replace(ttd + 1, power, QType(QType::A), records, signatures, authRecords, false, boost::none); + MRC.replace(ttd + 1, power, QType(QType::A), records, signatures, authRecords, false, authZone, boost::none); BOOST_CHECK_EQUAL(MRC.size(), 1U); BOOST_CHECK_EQUAL(MRC.get(ttd + 1, power, QType(QType::A), false, &retrieved, ComboAddress("127.0.0.1")), (dr3.d_ttl - (ttd + 1))); BOOST_REQUIRE_EQUAL(retrieved.size(), 1U); BOOST_CHECK_EQUAL(getRR(retrieved.at(0))->getCA().toString(), dr3Content.toString()); - // auth should replace non-auth + // non-auth should replace non-auth records.clear(); records.push_back(dr2); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, false, boost::none); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, false, authZone, boost::none); BOOST_CHECK_EQUAL(MRC.size(), 1U); // let's first check that non-auth is not returned when we need authoritative data BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), true, &retrieved, ComboAddress("127.0.0.1")), -now); @@ -276,7 +277,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple) // insert Secure record records.push_back(dr2); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::none, boost::none, vState::Secure); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none, boost::none, vState::Secure); BOOST_CHECK_EQUAL(MRC.size(), 1U); vState retrievedState = vState::Indeterminate; bool wasAuth = false; @@ -285,7 +286,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple) BOOST_CHECK_EQUAL(vStateToString(retrievedState), vStateToString(vState::Secure)); BOOST_CHECK_EQUAL(wasAuth, true); // try to replace that with a Bogus record - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::none, boost::none, vState::BogusNoRRSIG); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none, boost::none, vState::BogusNoRRSIG); BOOST_CHECK_EQUAL(MRC.size(), 1U); retrievedState = vState::Indeterminate; wasAuth = false; @@ -304,7 +305,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple) // insert an entry for 192.0.0.1/8 records.clear(); records.push_back(dr2); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::optional("192.0.0.1/8")); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::optional("192.0.0.1/8")); BOOST_CHECK_EQUAL(MRC.size(), 1U); /* same as dr2 except for the actual IP */ @@ -320,14 +321,14 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple) // insert another entry but for 192.168.0.1/31 records.clear(); records.push_back(dr4); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::optional("192.168.0.1/31")); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::optional("192.168.0.1/31")); // we should not have replaced any existing entry BOOST_CHECK_EQUAL(MRC.size(), 2U); // insert the same than the first one but for 192.168.0.2/32 records.clear(); records.push_back(dr2); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::optional("192.168.0.2/32")); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::optional("192.168.0.2/32")); // we should not have replaced any existing entry BOOST_CHECK_EQUAL(MRC.size(), 3U); @@ -344,7 +345,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple) // insert an entry for 192.0.0.1/8, non auth records.clear(); records.push_back(dr2); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, false, boost::optional("192.0.0.1/8")); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, false, authZone, boost::optional("192.0.0.1/8")); BOOST_CHECK_EQUAL(MRC.size(), 1U); // we should not get it when we need authoritative data @@ -385,7 +386,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheGhost) ns1.d_ttl = static_cast(ttd); ns1.d_place = DNSResourceRecord::ANSWER; records.push_back(ns1); - MRC.replace(now, ns1.d_name, QType(ns1.d_type), records, signatures, authRecords, true, boost::none); + MRC.replace(now, ns1.d_name, QType(ns1.d_type), records, signatures, authRecords, true, DNSName("powerdns.com."), boost::none); BOOST_CHECK_EQUAL(MRC.size(), 1U); /* try to raise the TTL, simulating the delegated authoritative server @@ -393,7 +394,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheGhost) records.clear(); ns1.d_ttl = static_cast(ttd + 3600); records.push_back(ns1); - MRC.replace(now, ns1.d_name, QType(ns1.d_type), records, signatures, authRecords, true, boost::none); + MRC.replace(now, ns1.d_name, QType(ns1.d_type), records, signatures, authRecords, true, DNSName("ghost.powerdns.com."), boost::none); BOOST_CHECK_EQUAL(MRC.size(), 1U); /* the TTL should not have been raisd */ @@ -410,6 +411,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingExpiredEntries) std::vector records; std::vector> signatures; std::vector> authRecs; + const DNSName authZone("."); BOOST_CHECK_EQUAL(MRC.size(), 0U); time_t now = time(nullptr); DNSName power1("powerdns.com."); @@ -440,10 +442,10 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingExpiredEntries) /* insert both entries */ records.push_back(dr1); - MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none); + MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, boost::none); records.clear(); records.push_back(dr2); - MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, boost::none); + MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, authZone, boost::none); records.clear(); BOOST_CHECK_EQUAL(MRC.size(), 2U); @@ -468,10 +470,10 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingExpiredEntries) /* insert both entries back */ records.push_back(dr1); - MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none); + MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, boost::none); records.clear(); records.push_back(dr2); - MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, boost::none); + MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, authZone, boost::none); records.clear(); BOOST_CHECK_EQUAL(MRC.size(), 2U); @@ -500,6 +502,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingValidEntries) std::vector records; std::vector> signatures; std::vector> authRecs; + const DNSName authZone("."); BOOST_CHECK_EQUAL(MRC.size(), 0U); time_t now = time(nullptr); DNSName power1("powerdns.com."); @@ -530,10 +533,10 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingValidEntries) /* insert both entries */ records.push_back(dr1); - MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none); + MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, boost::none); records.clear(); records.push_back(dr2); - MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, boost::none); + MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, authZone, boost::none); records.clear(); BOOST_CHECK_EQUAL(MRC.size(), 2U); @@ -557,16 +560,16 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingValidEntries) /* insert both entries back */ records.push_back(dr1); - MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none); + MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, boost::none); records.clear(); records.push_back(dr2); - MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, boost::none); + MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, authZone, boost::none); records.clear(); BOOST_CHECK_EQUAL(MRC.size(), 2U); /* replace the entry for power1 */ records.push_back(dr1); - MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none); + MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, boost::none); records.clear(); BOOST_CHECK_EQUAL(MRC.size(), 2U); @@ -591,10 +594,10 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingValidEntries) /* insert both entries back */ records.push_back(dr1); - MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none); + MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, authZone, boost::none); records.clear(); records.push_back(dr2); - MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, boost::none); + MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, authZone, boost::none); records.clear(); BOOST_CHECK_EQUAL(MRC.size(), 2U); @@ -633,7 +636,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingValidEntries) r1.d_place = DNSResourceRecord::ANSWER; records.push_back(r1); - MRC.replace(now, power1, QType(QType::A), records, signatures, authRecs, true, Netmask(r1Content, 32)); + MRC.replace(now, power1, QType(QType::A), records, signatures, authRecs, true, authZone, Netmask(r1Content, 32)); } BOOST_CHECK_EQUAL(MRC.size(), 256U); @@ -675,6 +678,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheECSIndex) MemRecursorCache MRC(1); const DNSName power("powerdns.com."); + const DNSName authZone("."); std::vector records; std::vector> authRecords; std::vector> signatures; @@ -710,7 +714,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheECSIndex) /* insert a non-specific entry */ records.push_back(dr1); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::none); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none); BOOST_CHECK_EQUAL(MRC.size(), 1U); BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0U); @@ -726,7 +730,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheECSIndex) BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0U); /* insert a specific entry */ - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/31")); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, Netmask("192.0.2.0/31")); BOOST_CHECK_EQUAL(MRC.size(), 1U); BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1U); @@ -751,7 +755,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheECSIndex) /* add back the entry while it still exists in the cache but has been removed from the ECS index. It should be added back to the ECS index, and we should be able to retrieve it */ - MRC.replace(now + ttl + 1, power, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/31")); + MRC.replace(now + ttl + 1, power, QType(QType::A), records, signatures, authRecords, true, authZone, Netmask("192.0.2.0/31")); BOOST_CHECK_EQUAL(MRC.size(), 1U); BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1U); BOOST_CHECK_EQUAL(MRC.get(now, power, QType(QType::A), false, &retrieved, ComboAddress("192.0.2.1")), ttd - now); @@ -764,7 +768,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheECSIndex) BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0U); /* insert a specific entry */ - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/24")); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, Netmask("192.0.2.0/24")); BOOST_CHECK_EQUAL(MRC.size(), 1U); BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1U); @@ -772,7 +776,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheECSIndex) /* insert a slightly more specific one, but expiring sooner */ records.clear(); records.push_back(dr2); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/26")); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, Netmask("192.0.2.0/26")); BOOST_CHECK_EQUAL(MRC.size(), 2U); BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1U); @@ -801,7 +805,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheECSIndex) /* insert a non-specific entry */ records.clear(); records.push_back(dr1); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, boost::none); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, boost::none); BOOST_CHECK_EQUAL(MRC.size(), 1U); BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0U); @@ -809,7 +813,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheECSIndex) /* insert a subnet-specific entry */ records.clear(); records.push_back(dr2); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.42/32")); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, Netmask("192.0.2.42/32")); BOOST_CHECK_EQUAL(MRC.size(), 2U); BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1U); @@ -833,6 +837,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_Wipe) MemRecursorCache MRC; const DNSName power("powerdns.com."); + const DNSName authZone("."); std::vector records; std::vector> authRecords; std::vector> signatures; @@ -859,7 +864,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_Wipe) /* insert a specific entry */ records.push_back(dr1); - MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/31")); + MRC.replace(now, power, QType(QType::A), records, signatures, authRecords, true, authZone, Netmask("192.0.2.0/31")); BOOST_CHECK_EQUAL(MRC.size(), 1U); BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1U); @@ -869,7 +874,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_Wipe) dr1.d_name = sub1; records.clear(); records.push_back(dr1); - MRC.replace(now, sub1, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/31")); + MRC.replace(now, sub1, QType(QType::A), records, signatures, authRecords, true, authZone, Netmask("192.0.2.0/31")); BOOST_CHECK_EQUAL(MRC.size(), 2U); BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 2U); @@ -878,7 +883,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_Wipe) dr1.d_name = sub2; records.clear(); records.push_back(dr1); - MRC.replace(now, sub2, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/31")); + MRC.replace(now, sub2, QType(QType::A), records, signatures, authRecords, true, authZone, Netmask("192.0.2.0/31")); BOOST_CHECK_EQUAL(MRC.size(), 3U); BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 3U); @@ -888,7 +893,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_Wipe) dr1.d_name = other1; records.clear(); records.push_back(dr1); - MRC.replace(now, other1, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/31")); + MRC.replace(now, other1, QType(QType::A), records, signatures, authRecords, true, authZone, Netmask("192.0.2.0/31")); BOOST_CHECK_EQUAL(MRC.size(), 4U); BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 4U); @@ -897,7 +902,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCache_Wipe) dr1.d_name = other2; records.clear(); records.push_back(dr1); - MRC.replace(now, other2, QType(QType::A), records, signatures, authRecords, true, Netmask("192.0.2.0/31")); + MRC.replace(now, other2, QType(QType::A), records, signatures, authRecords, true, authZone, Netmask("192.0.2.0/31")); BOOST_CHECK_EQUAL(MRC.size(), 5U); BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 5U); @@ -921,6 +926,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheTagged) { MemRecursorCache MRC; + const DNSName authZone("."); std::vector> authRecords; std::vector> signatures; time_t now = time(nullptr); @@ -951,8 +957,8 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheTagged) BOOST_CHECK_EQUAL(MRC.size(), 0U); // An entry without edns subnet gets stored without tag as well - MRC.replace(ttd, DNSName("hello"), QType(QType::A), rset0, signatures, authRecords, true, boost::none, boost::none); - MRC.replace(ttd, DNSName("hello"), QType(QType::A), rset0, signatures, authRecords, true, boost::none, string("mytag")); + MRC.replace(ttd, DNSName("hello"), QType(QType::A), rset0, signatures, authRecords, true, authZone, boost::none, boost::none); + MRC.replace(ttd, DNSName("hello"), QType(QType::A), rset0, signatures, authRecords, true, authZone, boost::none, string("mytag")); BOOST_CHECK_EQUAL(MRC.size(), 1U); BOOST_CHECK_EQUAL(MRC.doWipeCache(DNSName("hello"), false, QType::A), 1U); BOOST_CHECK_EQUAL(MRC.size(), 0U); @@ -967,8 +973,8 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheTagged) DNSName a = DNSName("hello ") + DNSName(std::to_string(counter)); BOOST_CHECK_EQUAL(DNSName(a.toString()), a); - MRC.replace(now, a, QType(QType::A), rset0, signatures, authRecords, true, boost::none, string("mytagA")); - MRC.replace(now, a, QType(QType::A), rset0, signatures, authRecords, true, boost::none, string("mytagB")); + MRC.replace(now, a, QType(QType::A), rset0, signatures, authRecords, true, authZone, boost::none, string("mytagA")); + MRC.replace(now, a, QType(QType::A), rset0, signatures, authRecords, true, authZone, boost::none, string("mytagB")); // After this, we have untagged entries, since no address was specified for both replace calls } @@ -1010,7 +1016,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheTagged) // Now insert some tagged entries for (counter = 0; counter < 50; ++counter) { DNSName a = DNSName("hello ") + DNSName(std::to_string(counter)); - MRC.replace(now, a, QType(QType::A), rset0tagged, signatures, authRecords, true, boost::optional("128.0.0.0/8"), string("mytagA")); + MRC.replace(now, a, QType(QType::A), rset0tagged, signatures, authRecords, true, authZone, boost::optional("128.0.0.0/8"), string("mytagA")); } BOOST_CHECK_EQUAL(MRC.size(), 150U); @@ -1087,7 +1093,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheTagged) rset3.push_back(dr3); // insert a tagged entry - MRC.replace(now, power, QType(QType::A), rset1, signatures, authRecords, true, boost::optional("192.0.2.0/24"), string("mytag")); + MRC.replace(now, power, QType(QType::A), rset1, signatures, authRecords, true, authZone, boost::optional("192.0.2.0/24"), string("mytag")); BOOST_CHECK_EQUAL(MRC.size(), 1U); // tagged specific should be returned for a matching tag @@ -1100,7 +1106,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheTagged) BOOST_CHECK_EQUAL(retrieved.size(), 0U); // insert a new entry without tag - MRC.replace(now, power, QType(QType::A), rset2, signatures, authRecords, true, boost::optional("192.0.3.0/24"), boost::none); + MRC.replace(now, power, QType(QType::A), rset2, signatures, authRecords, true, authZone, boost::optional("192.0.3.0/24"), boost::none); BOOST_CHECK_EQUAL(MRC.size(), 2U); // tagged specific should be returned for a matching tag @@ -1117,7 +1123,7 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheTagged) BOOST_REQUIRE_EQUAL(retrieved.size(), 0U); // Insert untagged entry with no netmask - MRC.replace(now, power, QType(QType::A), rset3, signatures, authRecords, true, boost::none, boost::none); + MRC.replace(now, power, QType(QType::A), rset3, signatures, authRecords, true, authZone, boost::none, boost::none); BOOST_CHECK_EQUAL(MRC.size(), 3U); // Retrieval with no address and no tag should get that one diff --git a/pdns/recursordist/test-syncres_cc.cc b/pdns/recursordist/test-syncres_cc.cc index a3845fe154..61f55ea7bc 100644 --- a/pdns/recursordist/test-syncres_cc.cc +++ b/pdns/recursordist/test-syncres_cc.cc @@ -75,18 +75,18 @@ bool primeHints(void) arr.d_content = std::make_shared(ComboAddress(rootIps4[c - 'a'])); vector aset; aset.push_back(arr); - g_recCache->replace(time(nullptr), DNSName(templ), QType(QType::A), aset, vector>(), vector>(), true); // auth, nuke it all + g_recCache->replace(time(nullptr), DNSName(templ), QType(QType::A), aset, vector>(), vector>(), true, g_rootdnsname); // auth, nuke it all if (rootIps6[c - 'a'] != NULL) { aaaarr.d_content = std::make_shared(ComboAddress(rootIps6[c - 'a'])); vector aaaaset; aaaaset.push_back(aaaarr); - g_recCache->replace(time(nullptr), DNSName(templ), QType(QType::AAAA), aaaaset, vector>(), vector>(), true); + g_recCache->replace(time(nullptr), DNSName(templ), QType(QType::AAAA), aaaaset, vector>(), vector>(), true, g_rootdnsname); } nsset.push_back(nsrr); } - g_recCache->replace(time(nullptr), g_rootdnsname, QType(QType::NS), nsset, vector>(), vector>(), false); // and stuff in the cache + g_recCache->replace(time(nullptr), g_rootdnsname, QType(QType::NS), nsset, vector>(), vector>(), false, g_rootdnsname); // and stuff in the cache return true; } diff --git a/pdns/recursordist/test-syncres_cc2.cc b/pdns/recursordist/test-syncres_cc2.cc index 2c4944dad3..065adc5b80 100644 --- a/pdns/recursordist/test-syncres_cc2.cc +++ b/pdns/recursordist/test-syncres_cc2.cc @@ -1297,7 +1297,7 @@ BOOST_AUTO_TEST_CASE(test_flawed_nsset) std::vector> sigs; addRecordToList(records, target, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, now + 3600); - g_recCache->replace(now, target, QType(QType::NS), records, sigs, vector>(), true, boost::optional()); + g_recCache->replace(now, target, QType(QType::NS), records, sigs, vector>(), true, g_rootdnsname, boost::optional()); vector ret; int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); @@ -1403,7 +1403,7 @@ BOOST_AUTO_TEST_CASE(test_cache_hit) std::vector> sigs; addRecordToList(records, target, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, now + 3600); - g_recCache->replace(now, target, QType(QType::A), records, sigs, vector>(), true, boost::optional()); + g_recCache->replace(now, target, QType(QType::A), records, sigs, vector>(), true, g_rootdnsname, boost::optional()); vector ret; int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); @@ -1592,7 +1592,7 @@ BOOST_AUTO_TEST_CASE(test_cache_expired_ttl) std::vector> sigs; addRecordToList(records, target, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, now - 60); - g_recCache->replace(now - 3600, target, QType(QType::A), records, sigs, vector>(), true, boost::optional()); + g_recCache->replace(now - 3600, target, QType(QType::A), records, sigs, vector>(), true, g_rootdnsname, boost::optional()); vector ret; int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); diff --git a/pdns/recursordist/test-syncres_cc7.cc b/pdns/recursordist/test-syncres_cc7.cc index 235ff0581c..8a04eb7f7c 100644 --- a/pdns/recursordist/test-syncres_cc7.cc +++ b/pdns/recursordist/test-syncres_cc7.cc @@ -1589,6 +1589,129 @@ BOOST_AUTO_TEST_CASE(test_dnssec_secure_to_insecure_cut_with_cname_at_apex) BOOST_CHECK_EQUAL(res, RCode::NoError); BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure); BOOST_REQUIRE_EQUAL(ret.size(), 1U); + BOOST_CHECK_EQUAL(queriesCount, 13U); +} + +BOOST_AUTO_TEST_CASE(test_dnssec_cname_inside_secure_zone) +{ + /* this test makes sure we don't request the DS + again and again when there is a CNAME inside a + Secure zone */ + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("powerdns.com."); + const DNSName targetCName("power-dns.com."); + const ComboAddress targetCNameAddr("192.0.2.42"); + testkeysset_t keys; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::DIGEST_SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + size_t queriesCount = 0; + + sr->setAsyncCallback([target, targetCName, targetCNameAddr, &queriesCount, keys](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 (type == QType::DS) { + if (domain.isPartOf(DNSName("powerdns.com.")) || domain.isPartOf(DNSName("power-dns.com."))) { + /* no cut */ + /* technically the zone is com., but we are going to chop off in genericDSAndDNSKEYHandler() */ + return genericDSAndDNSKEYHandler(res, domain, DNSName("powerdns.com."), type, keys, false); + } + else { + return genericDSAndDNSKEYHandler(res, domain, domain, type, keys); + } + } + else if (type == QType::DNSKEY) { + if (domain == g_rootdnsname || domain == DNSName("com.")) { + setLWResult(res, 0, true, false, true); + addDNSKEY(keys, domain, 300, res->d_records); + addRRSIG(keys, res->d_records, domain, 300); + return LWResult::Result::Success; + } + else { + setLWResult(res, 0, true, false, true); + addRecordToLW(res, domain, QType::SOA, "pdns-public-ns1.powerdns.com. pieter\\.lexis.powerdns.com. 2017032301 10800 3600 604800 3600", DNSResourceRecord::AUTHORITY, 3600); + return LWResult::Result::Success; + } + } + else { + if (isRootServer(ip)) { + setLWResult(res, 0, false, false, true); + addRecordToLW(res, "com.", QType::NS, "a.gtld-servers.com.", DNSResourceRecord::AUTHORITY, 3600); + addDS(DNSName("com."), 300, res->d_records, keys); + addRRSIG(keys, res->d_records, DNSName("."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + return LWResult::Result::Success; + } + else if (ip == ComboAddress("192.0.2.1:53")) { + setLWResult(res, 0, true, false, true); + + if (domain == DNSName("com.")) { + addRecordToLW(res, domain, QType::NS, "a.gtld-servers.com."); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + addRecordToLW(res, "a.gtld-servers.com.", QType::A, "192.0.2.1", DNSResourceRecord::ADDITIONAL, 3600); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + } + else { + if (domain == DNSName("powerdns.com.")) { + addRecordToLW(res, domain, QType::CNAME, targetCName.toString()); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + } + else if (domain == DNSName("www.powerdns.com.") || domain == DNSName("www2.powerdns.com.")) { + addRecordToLW(res, domain, QType::A, "192.0.2.43"); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + } + else if (domain == targetCName) { + addRecordToLW(res, domain, QType::A, targetCNameAddr.toString()); + addRRSIG(keys, res->d_records, DNSName("com."), 300); + } + } + + return LWResult::Result::Success; + } + } + + return LWResult::Result::Timeout; + }); + + vector ret; + int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 4U); + BOOST_CHECK_EQUAL(queriesCount, 8U); + + /* again, to test the cache */ + ret.clear(); + res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 4U); + BOOST_CHECK_EQUAL(queriesCount, 8U); + + /* this time we ask for www.powerdns.com, let's make sure the CNAME does not get in the way */ + ret.clear(); + res = sr->beginResolve(DNSName("www.powerdns.com."), QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 2U); + BOOST_CHECK_EQUAL(queriesCount, 10U); + + /* now we remove the denial of powerdns.com DS from the cache and ask www2 */ + BOOST_REQUIRE_EQUAL(g_negCache->wipe(target, false), 1); + ret.clear(); + res = sr->beginResolve(DNSName("www2.powerdns.com."), QType(QType::A), QClass::IN, ret); + BOOST_CHECK_EQUAL(res, RCode::NoError); + BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure); + BOOST_REQUIRE_EQUAL(ret.size(), 2U); BOOST_CHECK_EQUAL(queriesCount, 12U); } diff --git a/pdns/reczones.cc b/pdns/reczones.cc index 5a92d37f6f..753d87e65b 100644 --- a/pdns/reczones.cc +++ b/pdns/reczones.cc @@ -46,6 +46,7 @@ bool primeHints(void) { // prime root cache const vState validationState = vState::Insecure; + static const ComboAddress from("255.255.255.255"); vector nsset; t_rootNSZones.clear(); @@ -68,13 +69,13 @@ bool primeHints(void) arr.d_content=std::make_shared(ComboAddress(rootIps4[c-'a'])); vector aset; aset.push_back(arr); - g_recCache->replace(time(0), DNSName(templ), QType(QType::A), aset, vector>(), vector>(), true, boost::none, boost::none, validationState); // auth, nuke it all + g_recCache->replace(time(0), DNSName(templ), QType(QType::A), aset, vector>(), vector>(), true, g_rootdnsname, boost::none, boost::none, validationState, from); // auth, nuke it all if (rootIps6[c-'a'] != NULL) { aaaarr.d_content=std::make_shared(ComboAddress(rootIps6[c-'a'])); vector aaaaset; aaaaset.push_back(aaaarr); - g_recCache->replace(time(0), DNSName(templ), QType(QType::AAAA), aaaaset, vector>(), vector>(), true, boost::none, boost::none, validationState); + g_recCache->replace(time(0), DNSName(templ), QType(QType::AAAA), aaaaset, vector>(), vector>(), true, g_rootdnsname, boost::none, boost::none, validationState, from); } nsset.push_back(nsrr); @@ -94,12 +95,12 @@ bool primeHints(void) seenA.insert(rr.qname); vector aset; aset.push_back(DNSRecord(rr)); - g_recCache->replace(time(0), rr.qname, QType(QType::A), aset, vector>(), vector>(), true, boost::none, boost::none, validationState); // auth, etc see above + g_recCache->replace(time(0), rr.qname, QType(QType::A), aset, vector>(), vector>(), true, g_rootdnsname, boost::none, boost::none, validationState, from); // auth, etc see above } else if(rr.qtype.getCode()==QType::AAAA) { seenAAAA.insert(rr.qname); vector aaaaset; aaaaset.push_back(DNSRecord(rr)); - g_recCache->replace(time(0), rr.qname, QType(QType::AAAA), aaaaset, vector>(), vector>(), true, boost::none, boost::none, validationState); + g_recCache->replace(time(0), rr.qname, QType(QType::AAAA), aaaaset, vector>(), vector>(), true, g_rootdnsname, boost::none, boost::none, validationState, from); } else if(rr.qtype.getCode()==QType::NS) { seenNS.insert(DNSName(rr.content)); rr.content=toLower(rr.content); @@ -135,7 +136,7 @@ bool primeHints(void) } g_recCache->doWipeCache(g_rootdnsname, false, QType::NS); - g_recCache->replace(time(0), g_rootdnsname, QType(QType::NS), nsset, vector>(), vector>(), false, boost::none, boost::none, validationState); // and stuff in the cache + g_recCache->replace(time(0), g_rootdnsname, QType(QType::NS), nsset, vector>(), vector>(), false, g_rootdnsname, boost::none, boost::none, validationState, from); // and stuff in the cache return true; } diff --git a/pdns/syncres.cc b/pdns/syncres.cc index 611a07fea6..d75989d625 100644 --- a/pdns/syncres.cc +++ b/pdns/syncres.cc @@ -1390,11 +1390,12 @@ bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector bool wasAuth; uint32_t capTTL = std::numeric_limits::max(); DNSName foundName; + DNSName authZone; QType foundQT = QType(0); // 0 == QTYPE::ENT LOG(prefix<get(d_now.tv_sec, qname, QType(QType::CNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_routingTag, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth) > 0) { + if (g_recCache->get(d_now.tv_sec, qname, QType(QType::CNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_routingTag, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth, &authZone) > 0) { foundName = qname; foundQT = QType(QType::CNAME); } @@ -1411,7 +1412,7 @@ bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector if (dnameName == qname && qtype != QType::DNAME) { // The client does not want a DNAME, but we've reached the QNAME already. So there is no match break; } - if (g_recCache->get(d_now.tv_sec, dnameName, QType(QType::DNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_routingTag, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth) > 0) { + if (g_recCache->get(d_now.tv_sec, dnameName, QType(QType::DNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_routingTag, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth, &authZone) > 0) { foundName = dnameName; foundQT = QType(QType::DNAME); break; @@ -1423,7 +1424,14 @@ bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector LOG(prefix< ednsmask, vState& state, bool& needWildcardProof, bool& gatherWildcardProof, unsigned int& wildcardLabelsCount, bool rdQuery) +RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, const boost::optional ednsmask, vState& state, bool& needWildcardProof, bool& gatherWildcardProof, unsigned int& wildcardLabelsCount, bool rdQuery, const ComboAddress& remoteIP) { bool wasForwardRecurse = wasForwarded && rdQuery; tcache_t tcache; @@ -3253,7 +3261,7 @@ RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, LWResult& lwr } } if (doCache) { - g_recCache->replace(d_now.tv_sec, i->first.name, QType(i->first.type), i->second.records, i->second.signatures, authorityRecs, i->first.type == QType::DS ? true : isAA, i->first.place == DNSResourceRecord::ANSWER ? ednsmask : boost::none, d_routingTag, recordState); + g_recCache->replace(d_now.tv_sec, i->first.name, QType(i->first.type), i->second.records, i->second.signatures, authorityRecs, i->first.type == QType::DS ? true : isAA, auth, i->first.place == DNSResourceRecord::ANSWER ? ednsmask : boost::none, d_routingTag, recordState, remoteIP); } } @@ -3808,7 +3816,7 @@ void SyncRes::handleNewTarget(const std::string& prefix, const DNSName& qname, c updateValidationState(state, cnameState); } -bool SyncRes::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) +bool SyncRes::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) { string prefix; if(doLog()) { @@ -3835,7 +3843,7 @@ bool SyncRes::processAnswer(unsigned int depth, LWResult& lwr, const DNSName& qn bool needWildcardProof = false; bool gatherWildcardProof = false; unsigned int wildcardLabelsCount; - *rcode = updateCacheFromRecords(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, state, needWildcardProof, gatherWildcardProof, wildcardLabelsCount, sendRDQuery); + *rcode = updateCacheFromRecords(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, state, needWildcardProof, gatherWildcardProof, wildcardLabelsCount, sendRDQuery, remoteIP); if (*rcode != RCode::NoError) { return true; } @@ -4002,7 +4010,8 @@ int SyncRes::doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, con int rcode = RCode::NoError; bool gotNewServers = false; - if(tns->first.empty() && !wasForwarded) { + if (tns->first.empty() && !wasForwarded) { + static ComboAddress const s_oobRemote("255.255.255.255"); LOG(prefix<dfe, &gotNewServers, &rcode, state); + bool done = processAnswer(depth, lwr, qname, qtype, auth, false, ednsmask, sendRDQuery, nameservers, ret, luaconfsLocal->dfe, &gotNewServers, &rcode, state, s_oobRemote); if (done) { return rcode; } @@ -4090,7 +4099,7 @@ int SyncRes::doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, con t_sstorage.nsSpeeds[tns->first.empty()? DNSName(remoteIP->toStringWithPort()) : tns->first].submit(*remoteIP, lwr.d_usec, d_now); /* we have received an answer, are we done ? */ - bool done = processAnswer(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, sendRDQuery, nameservers, ret, luaconfsLocal->dfe, &gotNewServers, &rcode, state); + bool done = processAnswer(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, sendRDQuery, nameservers, ret, luaconfsLocal->dfe, &gotNewServers, &rcode, state, *remoteIP); if (done) { return rcode; } diff --git a/pdns/syncres.hh b/pdns/syncres.hh index 8581459b8a..684bfeafca 100644 --- a/pdns/syncres.hh +++ b/pdns/syncres.hh @@ -809,7 +809,7 @@ private: int doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype, vector&ret, unsigned int depth, set&beenthere, vState& state, StopAtDelegation* stopAtDelegation); 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& truncated, bool& spoofed); - 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); + 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, const QType &qtype, vector&ret, unsigned int depth, set& beenthere, vState& state); int doResolveNoQNameMinimization(const DNSName &qname, const QType &qtype, vector&ret, unsigned int depth, set& beenthere, vState& state, bool* fromCache = NULL, StopAtDelegation* stopAtDelegation = NULL, bool considerforwards = true); @@ -834,7 +834,7 @@ private: vector retrieveAddressesForNS(const std::string& prefix, const DNSName& qname, vector>::const_iterator& tns, const unsigned int depth, set& beenthere, const vector>& rnameservers, NsSet& nameservers, bool& sendRDQuery, bool& pierceDontQuery, bool& flawedNSSet, bool cacheOnly, unsigned int& addressQueriesForNS); void sanitizeRecords(const std::string& prefix, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, bool rdQuery); - RCode::rcodes_ updateCacheFromRecords(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, const boost::optional, vState& state, bool& needWildcardProof, bool& gatherWildcardProof, unsigned int& wildcardLabelsCount, bool sendRDQuery); + RCode::rcodes_ updateCacheFromRecords(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, const boost::optional, vState& state, bool& needWildcardProof, bool& gatherWildcardProof, unsigned int& wildcardLabelsCount, bool sendRDQuery, const ComboAddress& remoteIP); bool processRecords(const std::string& prefix, const DNSName& qname, const QType& qtype, const DNSName& auth, LWResult& lwr, const bool sendRDQuery, vector& ret, set& nsset, DNSName& newtarget, DNSName& newauth, bool& realreferral, bool& negindic, vState& state, const bool needWildcardProof, const bool gatherwildcardProof, const unsigned int wildcardLabelsCount, int& rcode, unsigned int depth); bool doSpecialNamesResolve(const DNSName &qname, const QType &qtype, const uint16_t qclass, vector &ret);