]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/recursor_cache.hh
wip2
[thirdparty/pdns.git] / pdns / recursor_cache.hh
CommitLineData
12471842
PL
1/*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
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.
8 *
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.
12 *
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.
17 *
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.
21 */
e8c59f2d 22#pragma once
6320ad3a
BH
23#include <string>
24#include <set>
a7956123 25#include <mutex>
6320ad3a
BH
26#include "dns.hh"
27#include "qtype.hh"
7738a23f 28#include "misc.hh"
c5c066bf 29#include "dnsname.hh"
c154c8a4 30#include <iostream>
57769f13 31#include "dnsrecords.hh"
8e843282 32#include <boost/utility.hpp>
ca0b5def
BH
33#include <boost/multi_index_container.hpp>
34#include <boost/multi_index/ordered_index.hpp>
e74f866a 35#include <boost/multi_index/hashed_index.hpp>
748eff9f 36#include <boost/tuple/tuple_comparison.hpp>
ca0b5def 37#include <boost/multi_index/key_extractors.hpp>
bec87d21 38#include <boost/multi_index/sequenced_index.hpp>
1676d61a 39#include <boost/version.hpp>
c4443ccb 40#include "iputils.hh"
4d2be65d 41#include "validate.hh"
705f31ae
BH
42#undef max
43
61b26744 44#include "namespaces.hh"
ca0b5def 45using namespace ::boost::multi_index;
6320ad3a 46
8e843282 47class MemRecursorCache : public boost::noncopyable // : public RecursorCache
6320ad3a
BH
48{
49public:
a7956123
OM
50 MemRecursorCache(size_t mapsCount = 1024);
51 ~MemRecursorCache();
52
53 size_t size();
54 size_t bytes();
55 size_t ecsIndexSize();
1ffea92c 56
428f41b7 57 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);
2b984251
RG
58
59 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);
b23b8614 60
a7956123 61 void doPrune(size_t keep);
d7948528 62 uint64_t doDump(int fd);
a82ce718 63
a7956123 64 size_t doWipeCache(const DNSName& name, bool sub, uint16_t qtype=0xffff);
6b68a4e3 65 bool doAgeCache(time_t now, const DNSName& name, uint16_t qtype, uint32_t newTTL);
b9473937 66 bool updateValidationStatus(time_t now, const DNSName &qname, const QType& qt, const ComboAddress& who, bool requireAuth, vState newState, boost::optional<time_t> capTTD);
941db220 67
a7956123 68 std::atomic<uint64_t> cacheHits{0}, cacheMisses{0};
ea634573 69
6320ad3a 70private:
43a2b29c 71
ca0b5def
BH
72 struct CacheEntry
73 {
48f19abe 74 CacheEntry(const boost::tuple<DNSName, uint16_t, Netmask>& key, bool auth):
80462253 75 d_qname(key.get<0>()), d_netmask(key.get<2>().getNormalized()), d_state(Indeterminate), d_ttd(0), d_qtype(key.get<1>()), d_auth(auth)
48f19abe
RG
76 {
77 }
748eff9f 78
e325f20c 79 typedef vector<std::shared_ptr<DNSRecordContent>> records_t;
6b68a4e3 80 time_t getTTD() const
ca0b5def 81 {
e325f20c 82 return d_ttd;
ca0b5def 83 }
34264879 84
c4443ccb 85 records_t d_records;
8edd5bb4 86 std::vector<std::shared_ptr<RRSIGRecordContent>> d_signatures;
2b984251 87 std::vector<std::shared_ptr<DNSRecord>> d_authorityRecs;
e74f866a 88 DNSName d_qname;
6c674e9a 89 Netmask d_netmask;
787737ae 90 mutable vState d_state;
b9473937 91 mutable time_t d_ttd;
e74f866a
RG
92 uint16_t d_qtype;
93 bool d_auth;
94 };
95
b0274132 96 /* The ECS Index (d_ecsIndex) keeps track of whether there is any ECS-specific
a7956123 97 entry for a given (qname,qtype) entry in the cache (d_map), and if so
b0274132
RG
98 provides a NetmaskTree of those ECS entries.
99 This allows figuring out quickly if we should look for an entry
100 specific to the requestor IP, and if so which entry is the most
101 specific one.
102 Keeping the entries in the regular cache is currently necessary
103 because of the way we manage expired entries (moving them to the
104 front of the expunge queue to be deleted at a regular interval).
105 */
106 class ECSIndexEntry
e74f866a
RG
107 {
108 public:
9772e56d 109 ECSIndexEntry(const DNSName& qname, uint16_t qtype): d_nmt(), d_qname(qname), d_qtype(qtype)
e74f866a
RG
110 {
111 }
112
113 Netmask lookupBestMatch(const ComboAddress& addr) const
114 {
e74f866a
RG
115 const auto best = d_nmt.lookup(addr);
116 if (best != nullptr) {
a7956123 117 return best->first;
e74f866a
RG
118 }
119
a7956123 120 return Netmask();
e74f866a
RG
121 }
122
123 void addMask(const Netmask& nm) const
124 {
125 d_nmt.insert(nm).second = true;
126 }
127
128 void removeNetmask(const Netmask& nm) const
129 {
130 d_nmt.erase(nm);
131 }
132
133 bool isEmpty() const
134 {
135 return d_nmt.empty();
136 }
137
138 mutable NetmaskTree<bool> d_nmt;
139 DNSName d_qname;
140 uint16_t d_qtype;
ca0b5def
BH
141 };
142
4c8d2585
RG
143 struct HashedTag {};
144 struct SequencedTag {};
145 struct NameOnlyHashedTag {};
146 struct OrderedTag {};
147
ca0b5def
BH
148 typedef multi_index_container<
149 CacheEntry,
150 indexed_by <
4c8d2585
RG
151 ordered_unique<tag<OrderedTag>,
152 composite_key<
153 CacheEntry,
154 member<CacheEntry,DNSName,&CacheEntry::d_qname>,
155 member<CacheEntry,uint16_t,&CacheEntry::d_qtype>,
156 member<CacheEntry,Netmask,&CacheEntry::d_netmask>
157 >,
158 composite_key_compare<CanonDNSNameCompare, std::less<uint16_t>, std::less<Netmask> >
748eff9f 159 >,
4c8d2585
RG
160 sequenced<tag<SequencedTag> >,
161 hashed_non_unique<tag<NameOnlyHashedTag>,
162 member<CacheEntry,DNSName,&CacheEntry::d_qname>
163 >
ca0b5def
BH
164 >
165 > cache_t;
4c8d2585
RG
166
167 typedef MemRecursorCache::cache_t::index<MemRecursorCache::OrderedTag>::type::iterator OrderedTagIterator_t;
168 typedef MemRecursorCache::cache_t::index<MemRecursorCache::NameOnlyHashedTag>::type::iterator NameOnlyHashedTagIterator_t;
169
e74f866a 170 typedef multi_index_container<
b0274132 171 ECSIndexEntry,
e74f866a 172 indexed_by <
4c8d2585 173 hashed_unique <tag<HashedTag>,
e74f866a 174 composite_key<
b0274132
RG
175 ECSIndexEntry,
176 member<ECSIndexEntry,DNSName,&ECSIndexEntry::d_qname>,
177 member<ECSIndexEntry,uint16_t,&ECSIndexEntry::d_qtype>
e74f866a 178 >
4c8d2585
RG
179 >,
180 ordered_unique<tag<OrderedTag>,
181 composite_key<
182 ECSIndexEntry,
183 member<ECSIndexEntry,DNSName,&ECSIndexEntry::d_qname>,
184 member<ECSIndexEntry,uint16_t,&ECSIndexEntry::d_qtype>
185 >,
186 composite_key_compare<CanonDNSNameCompare, std::less<uint16_t> >
e74f866a
RG
187 >
188 >
b0274132 189 > ecsIndex_t;
ca0b5def 190
a7956123
OM
191 struct MapCombo
192 {
193 MapCombo()
194 {
195 }
196 ~MapCombo()
197 {
198 }
199 MapCombo(const MapCombo &) = delete;
200 MapCombo & operator=(const MapCombo &) = delete;
201 cache_t d_map;
202 ecsIndex_t d_ecsIndex;
203 DNSName d_cachedqname;
204 std::pair<MemRecursorCache::NameOnlyHashedTagIterator_t, MemRecursorCache::NameOnlyHashedTagIterator_t> d_cachecache;
a7956123 205 std::mutex mutex;
cdde2458
OM
206 bool d_cachecachevalid{false};
207 std::atomic<uint64_t> d_entriesCount{0};
a7956123
OM
208 };
209
210 vector<MapCombo> d_maps;
211 MapCombo& getMap(const DNSName &qname)
212 {
213 return d_maps[qname.hash() % d_maps.size()];
214 }
787737ae 215
4c8d2585 216 bool entryMatches(OrderedTagIterator_t& entry, uint16_t qt, bool requireAuth, const ComboAddress& who);
a7956123
OM
217 std::pair<NameOnlyHashedTagIterator_t, NameOnlyHashedTagIterator_t> getEntries(MapCombo& map, const DNSName &qname, const QType& qt);
218 cache_t::const_iterator getEntryUsingECSIndex(MapCombo& map, time_t now, const DNSName &qname, uint16_t qtype, bool requireAuth, const ComboAddress& who);
219 int32_t handleHit(MapCombo& map, 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);
787737ae 220
e74f866a
RG
221public:
222 void preRemoval(const CacheEntry& entry)
223 {
224 if (entry.d_netmask.empty()) {
225 return;
226 }
227
228 auto key = tie(entry.d_qname, entry.d_qtype);
a7956123
OM
229 auto& map = getMap(entry.d_qname);
230 auto ecsIndexEntry = map.d_ecsIndex.find(key);
231 if (ecsIndexEntry != map.d_ecsIndex.end()) {
b0274132
RG
232 ecsIndexEntry->removeNetmask(entry.d_netmask);
233 if (ecsIndexEntry->isEmpty()) {
a7956123 234 map.d_ecsIndex.erase(ecsIndexEntry);
e74f866a
RG
235 }
236 }
237 }
6320ad3a 238};