From da6be6e31c8277b0b9f311253e8459a982bce8b5 Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Tue, 5 Jan 2021 17:19:50 +0100 Subject: [PATCH] rec: Add support for wiping the aggressive cache --- pdns/dnsname.hh | 13 +++++++-- pdns/rec_channel_rec.cc | 15 ++++++++++ pdns/recursordist/aggressive_nsec.cc | 42 ++++++++++++++++++++++++---- pdns/recursordist/aggressive_nsec.hh | 7 +++-- 4 files changed, 67 insertions(+), 10 deletions(-) diff --git a/pdns/dnsname.hh b/pdns/dnsname.hh index 10a4f0d2b1..76981f513a 100644 --- a/pdns/dnsname.hh +++ b/pdns/dnsname.hh @@ -326,19 +326,22 @@ struct SuffixMatchTree } } - void remove(const DNSName &name) const + void remove(const DNSName &name, bool subtree=false) const { auto labels = name.getRawLabels(); - remove(labels); + remove(labels, subtree); } /* Removes the node at `labels`, also make sure that no empty * children will be left behind in memory */ - void remove(std::vector& labels) const + void remove(std::vector& labels, bool subtree = false) const { if (labels.empty()) { // this allows removal of the root endNode = false; + if (subtree) { + children.clear(); + } return; } @@ -355,6 +358,10 @@ struct SuffixMatchTree // The child is no longer an endnode child->endNode = false; + if (subtree) { + child->children.clear(); + } + // If the child has no further children, just remove it from the set. if (child->children.empty()) { children.erase(child); diff --git a/pdns/rec_channel_rec.cc b/pdns/rec_channel_rec.cc index e13a421062..ca92008537 100644 --- a/pdns/rec_channel_rec.cc +++ b/pdns/rec_channel_rec.cc @@ -442,6 +442,9 @@ static string doWipeCache(T begin, T end, uint16_t qtype) count += g_recCache->doWipeCache(wipe.first, wipe.second, qtype); pcount += broadcastAccFunction([=]{ return pleaseWipePacketCache(wipe.first, wipe.second, qtype);}); countNeg += g_negCache->wipe(wipe.first, wipe.second); + if (g_aggressiveNSECCache) { + g_aggressiveNSECCache->removeZoneInfo(wipe.first, wipe.second); + } } catch (const std::exception& e) { g_log<doWipeCache(who, true, 0xffff); broadcastAccFunction([=]{return pleaseWipePacketCache(who, true, 0xffff);}); g_negCache->wipe(who, true); + if (g_aggressiveNSECCache) { + g_aggressiveNSECCache->removeZoneInfo(who, true); + } } catch (std::exception& e) { g_log<doWipeCache(entry, true, 0xffff); broadcastAccFunction([=]{return pleaseWipePacketCache(entry, true, 0xffff);}); g_negCache->wipe(entry, true); + if (g_aggressiveNSECCache) { + g_aggressiveNSECCache->removeZoneInfo(entry, true); + } if (!first) { first = false; removed += ","; @@ -667,6 +676,9 @@ static string doAddTA(T begin, T end) g_recCache->doWipeCache(who, true, 0xffff); broadcastAccFunction([=]{return pleaseWipePacketCache(who, true, 0xffff);}); g_negCache->wipe(who, true); + if (g_aggressiveNSECCache) { + g_aggressiveNSECCache->removeZoneInfo(who, true); + } g_log<doWipeCache(entry, true, 0xffff); broadcastAccFunction([=]{return pleaseWipePacketCache(entry, true, 0xffff);}); g_negCache->wipe(entry, true); + if (g_aggressiveNSECCache) { + g_aggressiveNSECCache->removeZoneInfo(entry, true); + } if (!first) { first = false; removed += ","; diff --git a/pdns/recursordist/aggressive_nsec.cc b/pdns/recursordist/aggressive_nsec.cc index 014bcb955b..d6bbef6401 100644 --- a/pdns/recursordist/aggressive_nsec.cc +++ b/pdns/recursordist/aggressive_nsec.cc @@ -70,6 +70,36 @@ std::shared_ptr AggressiveNSECCache::getZone(con } } +void AggressiveNSECCache::updateEntriesCount() +{ + /* need to be called while holding a write lock */ + uint64_t counter = 0; + d_zones.visit([&counter](const SuffixMatchTree>& node) { + counter += node.d_value->d_entries.size(); + }); + d_entriesCount = counter; +} + +void AggressiveNSECCache::removeZoneInfo(const DNSName& zone, bool subzones) +{ + WriteLock rl(d_lock); + auto got = d_zones.lookup(zone); + if (!got || !*got || (*got)->d_zone != zone) { + return; + } + + if (subzones) { + d_zones.remove(zone, true); + updateEntriesCount(); + } + else { + std::lock_guard lock((*got)->d_lock); + auto removed = (*got)->d_entries.size(); + d_zones.remove(zone, false); + d_entriesCount -= removed; + } +} + static bool isMinimallyCoveringNSEC(const DNSName& owner, const std::shared_ptr& nsec) { /* this test only covers Cloudflare's ones (https://blog.cloudflare.com/black-lies/), @@ -219,8 +249,9 @@ bool AggressiveNSECCache::getNSECBefore(time_t now, std::shared_ptrd_ttd <= now) { - idx.erase(it); - --d_entriesCount; + moveCacheItemToFront(zoneEntry->d_entries, it); + //idx.erase(it); + //--d_entriesCount; return false; } @@ -245,14 +276,15 @@ bool AggressiveNSECCache::getNSEC3(time_t now, std::shared_ptrd_entries.project(it); if (it->d_ttd <= now) { - idx.erase(it); - --d_entriesCount; + moveCacheItemToBack(zoneEntry->d_entries, firstIndexIterator); + //idx.erase(it); + //--d_entriesCount; return false; } entry = *it; - auto firstIndexIterator = zoneEntry->d_entries.project(it); moveCacheItemToBack(zoneEntry->d_entries, firstIndexIterator); return true; } diff --git a/pdns/recursordist/aggressive_nsec.hh b/pdns/recursordist/aggressive_nsec.hh index 659e3d9414..132a53a4b3 100644 --- a/pdns/recursordist/aggressive_nsec.hh +++ b/pdns/recursordist/aggressive_nsec.hh @@ -41,7 +41,7 @@ public: void insertNSEC(const DNSName& zone, const DNSName& owner, const DNSRecord& record, const std::vector>& signatures, bool nsec3); bool getDenial(time_t, const DNSName& name, const QType& type, std::vector& ret, int& res, const ComboAddress& who, const boost::optional& routingTag, bool doDNSSEC); - //void removeZoneInfo(const DNSName& zone); + void removeZoneInfo(const DNSName& zone, bool subzones); uint64_t getEntriesCount() const { @@ -124,13 +124,16 @@ private: bool synthesizeFromNSEC3Wildcard(time_t now, const DNSName& name, const QType& type, std::vector& ret, int& res, bool doDNSSEC, ZoneEntry::CacheEntry& nextCloser, const DNSName& wildcardName); bool synthesizeFromNSECWildcard(time_t now, const DNSName& name, const QType& type, std::vector& ret, int& res, bool doDNSSEC, ZoneEntry::CacheEntry& nsec, const DNSName& wildcardName); + /* slowly updates d_entriesCount */ + void updateEntriesCount(); + SuffixMatchTree> d_zones; ReadWriteLock d_lock; - std::atomic d_entriesCount{0}; std::atomic d_nsecHits{0}; std::atomic d_nsec3Hits{0}; std::atomic d_nsecWildcardHits{0}; std::atomic d_nsec3WildcardHits{0}; + std::atomic d_entriesCount{0}; }; -- 2.47.2