2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #ifndef RECURSOR_CACHE_HH
23 #define RECURSOR_CACHE_HH
31 #include "dnsrecords.hh"
32 #include <boost/utility.hpp>
33 #include <boost/multi_index_container.hpp>
34 #include <boost/multi_index/ordered_index.hpp>
35 #include <boost/multi_index/hashed_index.hpp>
36 #include <boost/tuple/tuple_comparison.hpp>
37 #include <boost/multi_index/key_extractors.hpp>
38 #include <boost/multi_index/sequenced_index.hpp>
39 #include <boost/version.hpp>
41 #include "validate.hh"
44 #include "namespaces.hh"
45 using namespace ::boost::multi_index;
47 class MemRecursorCache : public boost::noncopyable // : public RecursorCache
50 MemRecursorCache() : d_cachecachevalid(false)
52 cacheHits = cacheMisses = 0;
54 unsigned int size() const;
55 unsigned int bytes() const;
56 size_t ecsIndexSize() const;
58 int32_t get(time_t, const DNSName &qname, const QType& qt, bool requireAuth, vector<DNSRecord>* res, const ComboAddress& who, vector<std::shared_ptr<RRSIGRecordContent>>* signatures=nullptr, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs=nullptr, bool* variable=nullptr, vState* state=nullptr, bool* wasAuth=nullptr);
60 void replace(time_t, const DNSName &qname, const QType& qt, const vector<DNSRecord>& content, const vector<shared_ptr<RRSIGRecordContent>>& signatures, const std::vector<std::shared_ptr<DNSRecord>>& authorityRecs, bool auth, boost::optional<Netmask> ednsmask=boost::none, vState state=Indeterminate);
62 void doPrune(unsigned int keep);
63 uint64_t doDump(int fd);
65 int doWipeCache(const DNSName& name, bool sub, uint16_t qtype=0xffff);
66 bool doAgeCache(time_t now, const DNSName& name, uint16_t qtype, uint32_t newTTL);
67 bool updateValidationStatus(time_t now, const DNSName &qname, const QType& qt, const ComboAddress& who, bool requireAuth, vState newState, boost::optional<time_t> capTTD);
69 uint64_t cacheHits, cacheMisses;
75 CacheEntry(const boost::tuple<DNSName, uint16_t, Netmask>& key, bool auth):
76 d_qname(key.get<0>()), d_netmask(key.get<2>()), d_state(Indeterminate), d_ttd(0), d_qtype(key.get<1>()), d_auth(auth)
80 typedef vector<std::shared_ptr<DNSRecordContent>> records_t;
87 std::vector<std::shared_ptr<RRSIGRecordContent>> d_signatures;
88 std::vector<std::shared_ptr<DNSRecord>> d_authorityRecs;
91 mutable vState d_state;
97 /* The ECS Index (d_ecsIndex) keeps track of whether there is any ECS-specific
98 entry for a given (qname,qtype) entry in the cache (d_cache), and if so
99 provides a NetmaskTree of those ECS entries.
100 This allows figuring out quickly if we should look for an entry
101 specific to the requestor IP, and if so which entry is the most
103 Keeping the entries in the regular cache is currently necessary
104 because of the way we manage expired entries (moving them to the
105 front of the expunge queue to be deleted at a regular interval).
110 ECSIndexEntry(const DNSName& qname, uint16_t qtype): d_nmt(true), d_qname(qname), d_qtype(qtype)
114 Netmask lookupBestMatch(const ComboAddress& addr) const
116 Netmask result = Netmask();
118 const auto best = d_nmt.lookup(addr);
119 if (best != nullptr) {
120 result = best->first;
126 void addMask(const Netmask& nm) const
128 d_nmt.insert(nm).second = true;
131 void removeNetmask(const Netmask& nm) const
138 return d_nmt.empty();
141 mutable NetmaskTree<bool> d_nmt;
147 struct SequencedTag {};
148 struct NameOnlyHashedTag {};
149 struct OrderedTag {};
151 typedef multi_index_container<
154 ordered_unique<tag<OrderedTag>,
157 member<CacheEntry,DNSName,&CacheEntry::d_qname>,
158 member<CacheEntry,uint16_t,&CacheEntry::d_qtype>,
159 member<CacheEntry,Netmask,&CacheEntry::d_netmask>
161 composite_key_compare<CanonDNSNameCompare, std::less<uint16_t>, std::less<Netmask> >
163 sequenced<tag<SequencedTag> >,
164 hashed_non_unique<tag<NameOnlyHashedTag>,
165 member<CacheEntry,DNSName,&CacheEntry::d_qname>
170 typedef MemRecursorCache::cache_t::index<MemRecursorCache::OrderedTag>::type::iterator OrderedTagIterator_t;
171 typedef MemRecursorCache::cache_t::index<MemRecursorCache::NameOnlyHashedTag>::type::iterator NameOnlyHashedTagIterator_t;
173 typedef multi_index_container<
176 hashed_unique <tag<HashedTag>,
179 member<ECSIndexEntry,DNSName,&ECSIndexEntry::d_qname>,
180 member<ECSIndexEntry,uint16_t,&ECSIndexEntry::d_qtype>
183 ordered_unique<tag<OrderedTag>,
186 member<ECSIndexEntry,DNSName,&ECSIndexEntry::d_qname>,
187 member<ECSIndexEntry,uint16_t,&ECSIndexEntry::d_qtype>
189 composite_key_compare<CanonDNSNameCompare, std::less<uint16_t> >
195 ecsIndex_t d_ecsIndex;
196 std::pair<MemRecursorCache::NameOnlyHashedTagIterator_t, MemRecursorCache::NameOnlyHashedTagIterator_t> d_cachecache;
197 DNSName d_cachedqname;
198 bool d_cachecachevalid;
200 bool entryMatches(OrderedTagIterator_t& entry, uint16_t qt, bool requireAuth, const ComboAddress& who);
201 std::pair<NameOnlyHashedTagIterator_t, NameOnlyHashedTagIterator_t> getEntries(const DNSName &qname, const QType& qt);
202 cache_t::const_iterator getEntryUsingECSIndex(time_t now, const DNSName &qname, uint16_t qtype, bool requireAuth, const ComboAddress& who);
203 int32_t handleHit(OrderedTagIterator_t& entry, const DNSName& qname, const ComboAddress& who, vector<DNSRecord>* res, vector<std::shared_ptr<RRSIGRecordContent>>* signatures, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, vState* state, bool* wasAuth);
206 void preRemoval(const CacheEntry& entry)
208 if (entry.d_netmask.empty()) {
212 auto key = tie(entry.d_qname, entry.d_qtype);
213 auto ecsIndexEntry = d_ecsIndex.find(key);
214 if (ecsIndexEntry != d_ecsIndex.end()) {
215 ecsIndexEntry->removeNetmask(entry.d_netmask);
216 if (ecsIndexEntry->isEmpty()) {
217 d_ecsIndex.erase(ecsIndexEntry);