]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/recursor_cache.hh
Sphinx 1.8.0 seems broken, use any other version available instead
[thirdparty/pdns.git] / pdns / recursor_cache.hh
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 */
22 #ifndef RECURSOR_CACHE_HH
23 #define RECURSOR_CACHE_HH
24 #include <string>
25 #include <set>
26 #include "dns.hh"
27 #include "qtype.hh"
28 #include "misc.hh"
29 #include "dnsname.hh"
30 #include <iostream>
31 #include "dnsrecords.hh"
32 #include <boost/utility.hpp>
33 #undef L
34 #include <boost/multi_index_container.hpp>
35 #include <boost/multi_index/ordered_index.hpp>
36 #include <boost/multi_index/hashed_index.hpp>
37 #include <boost/tuple/tuple_comparison.hpp>
38 #include <boost/multi_index/key_extractors.hpp>
39 #include <boost/multi_index/sequenced_index.hpp>
40 #include <boost/version.hpp>
41 #include "iputils.hh"
42 #include "validate.hh"
43 #undef max
44
45 #define L theL()
46 #include "namespaces.hh"
47 using namespace ::boost::multi_index;
48
49 class MemRecursorCache : public boost::noncopyable // : public RecursorCache
50 {
51 public:
52 MemRecursorCache() : d_cachecachevalid(false)
53 {
54 cacheHits = cacheMisses = 0;
55 }
56 unsigned int size() const;
57 unsigned int bytes() const;
58 size_t ecsIndexSize() const;
59
60 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);
61
62 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);
63
64 void doPrune(unsigned int keep);
65 uint64_t doDump(int fd);
66
67 int doWipeCache(const DNSName& name, bool sub, uint16_t qtype=0xffff);
68 bool doAgeCache(time_t now, const DNSName& name, uint16_t qtype, uint32_t newTTL);
69 bool updateValidationStatus(time_t now, const DNSName &qname, const QType& qt, const ComboAddress& who, bool requireAuth, vState newState);
70
71 uint64_t cacheHits, cacheMisses;
72
73 private:
74
75 struct CacheEntry
76 {
77 CacheEntry(const boost::tuple<DNSName, uint16_t, Netmask>& key, const vector<shared_ptr<DNSRecordContent>>& records, bool auth) :
78 d_records(records), d_qname(key.get<0>()), d_netmask(key.get<2>()), d_state(Indeterminate), d_ttd(0), d_qtype(key.get<1>()), d_auth(auth)
79 {}
80
81 typedef vector<std::shared_ptr<DNSRecordContent>> records_t;
82 time_t getTTD() const
83 {
84 return d_ttd;
85 }
86
87 records_t d_records;
88 std::vector<std::shared_ptr<RRSIGRecordContent>> d_signatures;
89 std::vector<std::shared_ptr<DNSRecord>> d_authorityRecs;
90 DNSName d_qname;
91 Netmask d_netmask;
92 mutable vState d_state;
93 time_t d_ttd;
94 uint16_t d_qtype;
95 bool d_auth;
96 };
97
98 /* The ECS Index (d_ecsIndex) keeps track of whether there is any ECS-specific
99 entry for a given (qname,qtype) entry in the cache (d_cache), and if so
100 provides a NetmaskTree of those ECS entries.
101 This allows figuring out quickly if we should look for an entry
102 specific to the requestor IP, and if so which entry is the most
103 specific one.
104 Keeping the entries in the regular cache is currently necessary
105 because of the way we manage expired entries (moving them to the
106 front of the expunge queue to be deleted at a regular interval).
107 */
108 class ECSIndexEntry
109 {
110 public:
111 ECSIndexEntry(const DNSName& qname, uint16_t qtype): d_nmt(true), d_qname(qname), d_qtype(qtype)
112 {
113 }
114
115 Netmask lookupBestMatch(const ComboAddress& addr) const
116 {
117 Netmask result = Netmask();
118
119 const auto best = d_nmt.lookup(addr);
120 if (best != nullptr) {
121 result = best->first;
122 }
123
124 return result;
125 }
126
127 void addMask(const Netmask& nm) const
128 {
129 d_nmt.insert(nm).second = true;
130 }
131
132 void removeNetmask(const Netmask& nm) const
133 {
134 d_nmt.erase(nm);
135 }
136
137 bool isEmpty() const
138 {
139 return d_nmt.empty();
140 }
141
142 mutable NetmaskTree<bool> d_nmt;
143 DNSName d_qname;
144 uint16_t d_qtype;
145 };
146
147 typedef multi_index_container<
148 CacheEntry,
149 indexed_by <
150 ordered_unique<
151 composite_key<
152 CacheEntry,
153 member<CacheEntry,DNSName,&CacheEntry::d_qname>,
154 member<CacheEntry,uint16_t,&CacheEntry::d_qtype>,
155 member<CacheEntry,Netmask,&CacheEntry::d_netmask>
156 >,
157 composite_key_compare<CanonDNSNameCompare, std::less<uint16_t>, std::less<Netmask> >
158 >,
159 sequenced<>
160 >
161 > cache_t;
162 typedef multi_index_container<
163 ECSIndexEntry,
164 indexed_by <
165 ordered_unique <
166 composite_key<
167 ECSIndexEntry,
168 member<ECSIndexEntry,DNSName,&ECSIndexEntry::d_qname>,
169 member<ECSIndexEntry,uint16_t,&ECSIndexEntry::d_qtype>
170 >,
171 composite_key_compare<CanonDNSNameCompare, std::less<uint16_t> >
172 >
173 >
174 > ecsIndex_t;
175
176 cache_t d_cache;
177 ecsIndex_t d_ecsIndex;
178 pair<cache_t::iterator, cache_t::iterator> d_cachecache;
179 DNSName d_cachedqname;
180 bool d_cachecachevalid;
181
182 bool attemptToRefreshNSTTL(const QType& qt, const vector<DNSRecord>& content, const CacheEntry& stored);
183 bool entryMatches(cache_t::const_iterator& entry, uint16_t qt, bool requireAuth, const ComboAddress& who);
184 std::pair<cache_t::const_iterator, cache_t::const_iterator> getEntries(const DNSName &qname, const QType& qt);
185 cache_t::const_iterator getEntryUsingECSIndex(time_t now, const DNSName &qname, uint16_t qtype, bool requireAuth, const ComboAddress& who);
186 int32_t handleHit(cache_t::iterator 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);
187
188 public:
189 void preRemoval(const CacheEntry& entry)
190 {
191 if (entry.d_netmask.empty()) {
192 return;
193 }
194
195 auto key = tie(entry.d_qname, entry.d_qtype);
196 auto ecsIndexEntry = d_ecsIndex.find(key);
197 if (ecsIndexEntry != d_ecsIndex.end()) {
198 ecsIndexEntry->removeNetmask(entry.d_netmask);
199 if (ecsIndexEntry->isEmpty()) {
200 d_ecsIndex.erase(ecsIndexEntry);
201 }
202 }
203 }
204 };
205 #endif