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