]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/recpacketcache.cc
Merge pull request #8223 from PowerDNS/omoerbeek-patch-1
[thirdparty/pdns.git] / pdns / recpacketcache.cc
CommitLineData
870a0fe4
AT
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
3ea54bf0 4#include <iostream>
6b68a4e3 5#include <cinttypes>
fa8fd4d2 6
3ea54bf0 7#include "recpacketcache.hh"
38c9ceaa 8#include "cachecleaner.hh"
3ea54bf0
BH
9#include "dns.hh"
10#include "namespaces.hh"
3ea54bf0
BH
11
12RecursorPacketCache::RecursorPacketCache()
13{
16beeaa4 14 d_hits = d_misses = 0;
3ea54bf0
BH
15}
16
65a60c2c 17int RecursorPacketCache::doWipePacketCache(const DNSName& name, uint16_t qtype, bool subtree)
effe43d0
BH
18{
19 int count=0;
49a3500d 20 auto& idx = d_packetCache.get<NameTag>();
21 for(auto iter = idx.lower_bound(name); iter != idx.end(); ) {
65a60c2c 22 if(subtree) {
49a3500d 23 if(!iter->d_name.isPartOf(name)) { // this is case insensitive
65a60c2c 24 break;
25 }
26 }
27 else {
49a3500d 28 if(iter->d_name != name)
65a60c2c 29 break;
7313fe62 30 }
e9f63d47 31
49a3500d 32 if(qtype==0xffff || iter->d_type == qtype) {
33 iter=idx.erase(iter);
7313fe62 34 count++;
effe43d0 35 }
7313fe62 36 else
37 ++iter;
effe43d0
BH
38 }
39 return count;
40}
41
08b02366 42bool RecursorPacketCache::qrMatch(const packetCache_t::index<HashTag>::type::iterator& iter, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint16_t ecsBegin, uint16_t ecsEnd)
3ea54bf0 43{
a774e78b 44 // this ignores checking on the EDNS subnet flags!
08b02366
RG
45 if (qname != iter->d_name || iter->d_type != qtype || iter->d_class != qclass) {
46 return false;
47 }
48
49 if (iter->d_ecsBegin != ecsBegin || iter->d_ecsEnd != ecsEnd) {
50 return false;
51 }
52
53 return queryMatches(iter->d_query, queryPacket, qname, ecsBegin, ecsEnd);
49a3500d 54}
55
08b02366 56bool RecursorPacketCache::checkResponseMatches(std::pair<packetCache_t::index<HashTag>::type::iterator, packetCache_t::index<HashTag>::type::iterator> range, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, RecProtoBufMessage* protobufMessage, uint16_t ecsBegin, uint16_t ecsEnd)
49a3500d 57{
08b02366 58 for(auto iter = range.first ; iter != range.second ; ++iter) {
49a3500d 59 // the possibility is VERY real that we get hits that are not right - birthday paradox
08b02366 60 if (!qrMatch(iter, queryPacket, qname, qtype, qclass, ecsBegin, ecsEnd)) {
49a3500d 61 continue;
08b02366
RG
62 }
63
64 if (now < iter->d_ttd) { // it is right, it is fresh!
6b68a4e3 65 *age = static_cast<uint32_t>(now - iter->d_creation);
49a3500d 66 *responsePacket = iter->d_packet;
67 responsePacket->replace(0, 2, queryPacket.c_str(), 2);
8467ec26 68 *valState = iter->d_vstate;
90974597 69
2651c4ce
RG
70 const size_t wirelength = qname.wirelength();
71 if (responsePacket->size() > (sizeof(dnsheader) + wirelength)) {
72 responsePacket->replace(sizeof(dnsheader), wirelength, queryPacket, sizeof(dnsheader), wirelength);
49a3500d 73 }
3f3459f0 74
49a3500d 75 d_hits++;
76 moveCacheItemToBack(d_packetCache, iter);
02b47f43
RG
77#ifdef HAVE_PROTOBUF
78 if (protobufMessage) {
d362f7c1 79 if (iter->d_protobufMessage) {
29478011 80 protobufMessage->copyFrom(*(iter->d_protobufMessage));
d362f7c1
RG
81 }
82 else {
83 *protobufMessage = RecProtoBufMessage(DNSProtoBufMessage::DNSProtoBufMessageType::Response);
84 }
02b47f43
RG
85 }
86#endif
49a3500d 87
88 return true;
89 }
90 else {
91 moveCacheItemToFront(d_packetCache, iter);
92 d_misses++;
93 break;
94 }
3ea54bf0 95 }
49a3500d 96
3ea54bf0
BH
97 return false;
98}
99
c15ff3df
RG
100bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now,
101 std::string* responsePacket, uint32_t* age, uint32_t* qhash)
102{
8467ec26
KM
103 DNSName qname;
104 uint16_t qtype, qclass;
08b02366
RG
105 uint16_t ecsBegin;
106 uint16_t ecsEnd;
8467ec26 107 vState valState;
08b02366 108 return getResponsePacket(tag, queryPacket, qname, &qtype, &qclass, now, responsePacket, age, &valState, qhash, &ecsBegin, &ecsEnd, nullptr);
c15ff3df
RG
109}
110
111bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now,
112 std::string* responsePacket, uint32_t* age, uint32_t* qhash)
113{
8467ec26 114 vState valState;
08b02366
RG
115 uint16_t ecsBegin;
116 uint16_t ecsEnd;
117 return getResponsePacket(tag, queryPacket, qname, qtype, qclass, now, responsePacket, age, &valState, qhash, &ecsBegin, &ecsEnd, nullptr);
c15ff3df
RG
118}
119
8467ec26 120bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now,
08b02366 121 std::string* responsePacket, uint32_t* age, vState* valState, uint32_t* qhash, uint16_t* ecsBegin, uint16_t* ecsEnd, RecProtoBufMessage* protobufMessage)
c15ff3df 122{
08b02366 123 *qhash = canHashPacket(queryPacket, ecsBegin, ecsEnd);
c15ff3df
RG
124 const auto& idx = d_packetCache.get<HashTag>();
125 auto range = idx.equal_range(tie(tag,*qhash));
126
127 if(range.first == range.second) {
128 d_misses++;
129 return false;
130 }
08b02366
RG
131
132 return checkResponseMatches(range, queryPacket, qname, qtype, qclass, now, responsePacket, age, valState, protobufMessage, *ecsBegin, *ecsEnd);
c15ff3df
RG
133}
134
8467ec26 135bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, DNSName& qname, uint16_t* qtype, uint16_t* qclass, time_t now,
08b02366 136 std::string* responsePacket, uint32_t* age, vState* valState, uint32_t* qhash, uint16_t* ecsBegin, uint16_t* ecsEnd, RecProtoBufMessage* protobufMessage)
c15ff3df 137{
08b02366 138 *qhash = canHashPacket(queryPacket, ecsBegin, ecsEnd);
c15ff3df
RG
139 const auto& idx = d_packetCache.get<HashTag>();
140 auto range = idx.equal_range(tie(tag,*qhash));
141
142 if(range.first == range.second) {
143 d_misses++;
144 return false;
145 }
146
8467ec26 147 qname = DNSName(queryPacket.c_str(), queryPacket.length(), sizeof(dnsheader), false, qtype, qclass, 0);
c15ff3df 148
08b02366 149 return checkResponseMatches(range, queryPacket, qname, *qtype, *qclass, now, responsePacket, age, valState, protobufMessage, *ecsBegin, *ecsEnd);
c15ff3df
RG
150}
151
8467ec26 152
4b0bdd5f 153void RecursorPacketCache::insertResponsePacket(unsigned int tag, uint32_t qhash, std::string&& query, const DNSName& qname, uint16_t qtype, uint16_t qclass, std::string&& responsePacket, time_t now, uint32_t ttl, const vState& valState, uint16_t ecsBegin, uint16_t ecsEnd, boost::optional<RecProtoBufMessage>&& protobufMessage)
3ea54bf0 154{
49a3500d 155 auto& idx = d_packetCache.get<HashTag>();
156 auto range = idx.equal_range(tie(tag,qhash));
157 auto iter = range.first;
158
159 for( ; iter != range.second ; ++iter) {
08b02366 160 if (iter->d_type != qtype || iter->d_class != qclass || iter->d_name != qname) {
49a3500d 161 continue;
08b02366 162 }
bf269e28 163
a072ce44 164 moveCacheItemToBack(d_packetCache, iter);
b5e675a7
RG
165 iter->d_packet = std::move(responsePacket);
166 iter->d_query = std::move(query);
08b02366
RG
167 iter->d_ecsBegin = ecsBegin;
168 iter->d_ecsEnd = ecsEnd;
3f3459f0 169 iter->d_ttd = now + ttl;
2c73e580 170 iter->d_creation = now;
4d3f74e8 171 iter->d_vstate = valState;
02b47f43
RG
172#ifdef HAVE_PROTOBUF
173 if (protobufMessage) {
4b0bdd5f 174 iter->d_protobufMessage = std::move(*protobufMessage);
02b47f43
RG
175 }
176#endif
177
49a3500d 178 break;
3ea54bf0 179 }
49a3500d 180
181 if(iter == range.second) { // nothing to refresh
b5e675a7 182 struct Entry e(qname, std::move(responsePacket), std::move(query));
49a3500d 183 e.d_qhash = qhash;
08b02366
RG
184 e.d_ecsBegin = ecsBegin;
185 e.d_ecsEnd = ecsEnd;
49a3500d 186 e.d_type = qtype;
e9f63d47 187 e.d_class = qclass;
49a3500d 188 e.d_ttd = now+ttl;
189 e.d_creation = now;
190 e.d_tag = tag;
88694a6a 191 e.d_vstate = valState;
02b47f43
RG
192#ifdef HAVE_PROTOBUF
193 if (protobufMessage) {
4b0bdd5f 194 e.d_protobufMessage = std::move(*protobufMessage);
02b47f43
RG
195 }
196#endif
3ea54bf0 197 d_packetCache.insert(e);
49a3500d 198 }
3ea54bf0
BH
199}
200
16beeaa4
BH
201uint64_t RecursorPacketCache::size()
202{
203 return d_packetCache.size();
204}
3f3459f0 205
0bbf7d0a
BH
206uint64_t RecursorPacketCache::bytes()
207{
208 uint64_t sum=0;
f226db2f 209 for(const auto& e : d_packetCache) {
0bbf7d0a
BH
210 sum += sizeof(e) + e.d_packet.length() + 4;
211 }
212 return sum;
213}
214
3f3459f0
BH
215void RecursorPacketCache::doPruneTo(unsigned int maxCached)
216{
e74f866a 217 pruneCollection(*this, d_packetCache, maxCached);
3f3459f0
BH
218}
219
09645ebb 220uint64_t RecursorPacketCache::doDump(int fd)
221{
5e1f23ca 222 auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fdopen(dup(fd), "w"), fclose);
09645ebb 223 if(!fp) { // dup probably failed
224 return 0;
225 }
5e1f23ca 226 fprintf(fp.get(), "; main packet cache dump from thread follows\n;\n");
09645ebb 227 const auto& sidx=d_packetCache.get<1>();
228
229 uint64_t count=0;
230 time_t now=time(0);
231 for(auto i=sidx.cbegin(); i != sidx.cend(); ++i) {
232 count++;
233 try {
5e1f23ca 234 fprintf(fp.get(), "%s %" PRId64 " %s ; tag %d\n", i->d_name.toString().c_str(), static_cast<int64_t>(i->d_ttd - now), DNSRecordContent::NumberToType(i->d_type).c_str(), i->d_tag);
09645ebb 235 }
236 catch(...) {
5e1f23ca 237 fprintf(fp.get(), "; error printing '%s'\n", i->d_name.empty() ? "EMPTY" : i->d_name.toString().c_str());
09645ebb 238 }
239 }
09645ebb 240 return count;
241
242}