]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/recursor_cache.hh
rec: Don't account chained queries more than once
[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 */
6320ad3a
BH
22#ifndef RECURSOR_CACHE_HH
23#define RECURSOR_CACHE_HH
6320ad3a
BH
24#include <string>
25#include <set>
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#undef L
34#include <boost/multi_index_container.hpp>
35#include <boost/multi_index/ordered_index.hpp>
e74f866a 36#include <boost/multi_index/hashed_index.hpp>
748eff9f 37#include <boost/tuple/tuple_comparison.hpp>
ca0b5def 38#include <boost/multi_index/key_extractors.hpp>
bec87d21 39#include <boost/multi_index/sequenced_index.hpp>
1676d61a 40#include <boost/version.hpp>
c4443ccb 41#include "iputils.hh"
4d2be65d 42#include "validate.hh"
705f31ae
BH
43#undef max
44
ca0b5def 45#define L theL()
61b26744 46#include "namespaces.hh"
ca0b5def 47using namespace ::boost::multi_index;
6320ad3a 48
8e843282 49class MemRecursorCache : public boost::noncopyable // : public RecursorCache
6320ad3a
BH
50{
51public:
9348824d 52 MemRecursorCache() : d_cachecachevalid(false)
34264879 53 {
b0c3b7d8 54 cacheHits = cacheMisses = 0;
34264879 55 }
1ffea92c
RG
56 unsigned int size() const;
57 unsigned int bytes() const;
58 size_t ecsIndexSize() const;
59
428f41b7 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);
2b984251
RG
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);
b23b8614 63
c68ae9fa 64 void doPrune(unsigned int keep);
d7948528 65 uint64_t doDump(int fd);
a82ce718 66
86f3ca51 67 int doWipeCache(const DNSName& name, bool sub, uint16_t qtype=0xffff);
6b68a4e3 68 bool doAgeCache(time_t now, const DNSName& name, uint16_t qtype, uint32_t newTTL);
e74f866a 69 bool updateValidationStatus(time_t now, const DNSName &qname, const QType& qt, const ComboAddress& who, bool requireAuth, vState newState);
941db220 70
5e4a2466 71 uint64_t cacheHits, cacheMisses;
ea634573 72
6320ad3a 73private:
43a2b29c 74
ca0b5def
BH
75 struct CacheEntry
76 {
6c674e9a 77 CacheEntry(const boost::tuple<DNSName, uint16_t, Netmask>& key, const vector<shared_ptr<DNSRecordContent>>& records, bool auth) :
8edd5bb4 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)
ca0b5def 79 {}
748eff9f 80
e325f20c 81 typedef vector<std::shared_ptr<DNSRecordContent>> records_t;
6b68a4e3 82 time_t getTTD() const
ca0b5def 83 {
e325f20c 84 return d_ttd;
ca0b5def 85 }
34264879 86
c4443ccb 87 records_t d_records;
8edd5bb4 88 std::vector<std::shared_ptr<RRSIGRecordContent>> d_signatures;
2b984251 89 std::vector<std::shared_ptr<DNSRecord>> d_authorityRecs;
e74f866a 90 DNSName d_qname;
6c674e9a 91 Netmask d_netmask;
787737ae 92 mutable vState d_state;
e74f866a
RG
93 time_t d_ttd;
94 uint16_t d_qtype;
95 bool d_auth;
96 };
97
b0274132
RG
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
e74f866a
RG
109 {
110 public:
b0274132 111 ECSIndexEntry(const DNSName& qname, uint16_t qtype): d_qname(qname), d_qtype(qtype)
e74f866a
RG
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;
ca0b5def
BH
145 };
146
147 typedef multi_index_container<
148 CacheEntry,
149 indexed_by <
748eff9f
BH
150 ordered_unique<
151 composite_key<
152 CacheEntry,
c5c066bf 153 member<CacheEntry,DNSName,&CacheEntry::d_qname>,
6c674e9a 154 member<CacheEntry,uint16_t,&CacheEntry::d_qtype>,
155 member<CacheEntry,Netmask,&CacheEntry::d_netmask>
7738a23f 156 >,
6c674e9a 157 composite_key_compare<CanonDNSNameCompare, std::less<uint16_t>, std::less<Netmask> >
748eff9f 158 >,
bec87d21 159 sequenced<>
ca0b5def
BH
160 >
161 > cache_t;
e74f866a 162 typedef multi_index_container<
b0274132 163 ECSIndexEntry,
e74f866a
RG
164 indexed_by <
165 ordered_unique <
166 composite_key<
b0274132
RG
167 ECSIndexEntry,
168 member<ECSIndexEntry,DNSName,&ECSIndexEntry::d_qname>,
169 member<ECSIndexEntry,uint16_t,&ECSIndexEntry::d_qtype>
cee53c2e
RG
170 >,
171 composite_key_compare<CanonDNSNameCompare, std::less<uint16_t> >
e74f866a
RG
172 >
173 >
b0274132 174 > ecsIndex_t;
ca0b5def 175
6320ad3a 176 cache_t d_cache;
b0274132 177 ecsIndex_t d_ecsIndex;
bec87d21 178 pair<cache_t::iterator, cache_t::iterator> d_cachecache;
c5c066bf 179 DNSName d_cachedqname;
cf98aa40 180 bool d_cachecachevalid;
787737ae 181
e325f20c 182 bool attemptToRefreshNSTTL(const QType& qt, const vector<DNSRecord>& content, const CacheEntry& stored);
e74f866a 183 bool entryMatches(cache_t::const_iterator& entry, uint16_t qt, bool requireAuth, const ComboAddress& who);
787737ae 184 std::pair<cache_t::const_iterator, cache_t::const_iterator> getEntries(const DNSName &qname, const QType& qt);
b0274132 185 cache_t::const_iterator getEntryUsingECSIndex(time_t now, const DNSName &qname, uint16_t qtype, bool requireAuth, const ComboAddress& who);
e74f866a 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);
787737ae 187
e74f866a
RG
188public:
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);
b0274132
RG
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);
e74f866a
RG
201 }
202 }
203 }
6320ad3a 204};
6320ad3a 205#endif