]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/recpacketcache.cc
7 #include "recpacketcache.hh"
8 #include "cachecleaner.hh"
10 #include "dnsparser.hh"
11 #include "namespaces.hh"
13 #include "dnswriter.hh"
14 #include "ednsoptions.hh"
16 RecursorPacketCache::RecursorPacketCache()
18 d_hits
= d_misses
= 0;
21 int RecursorPacketCache::doWipePacketCache(const DNSName
& name
, uint16_t qtype
, bool subtree
)
24 auto& idx
= d_packetCache
.get
<NameTag
>();
25 for(auto iter
= idx
.lower_bound(name
); iter
!= idx
.end(); ) {
27 if(!iter
->d_name
.isPartOf(name
)) { // this is case insensitive
32 if(iter
->d_name
!= name
)
36 if(qtype
==0xffff || iter
->d_type
== qtype
) {
46 bool 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
)
48 // this ignores checking on the EDNS subnet flags!
49 if (qname
!= iter
->d_name
|| iter
->d_type
!= qtype
|| iter
->d_class
!= qclass
) {
53 if (iter
->d_ecsBegin
!= ecsBegin
|| iter
->d_ecsEnd
!= ecsEnd
) {
57 return queryMatches(iter
->d_query
, queryPacket
, qname
, ecsBegin
, ecsEnd
);
60 bool 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
, uint16_t ecsBegin
, uint16_t ecsEnd
)
62 for(auto iter
= range
.first
; iter
!= range
.second
; ++iter
) {
63 // the possibility is VERY real that we get hits that are not right - birthday paradox
64 if (!qrMatch(iter
, queryPacket
, qname
, qtype
, qclass
, ecsBegin
, ecsEnd
)) {
68 if (now
< iter
->d_ttd
) { // it is right, it is fresh!
69 *age
= static_cast<uint32_t>(now
- iter
->d_creation
);
70 *responsePacket
= iter
->d_packet
;
71 responsePacket
->replace(0, 2, queryPacket
.c_str(), 2);
73 string::size_type i
=sizeof(dnsheader
);
76 unsigned int labellen
= (unsigned char)queryPacket
[i
];
77 if(!labellen
|| i
+ labellen
> responsePacket
->size()) break;
79 responsePacket
->replace(i
, labellen
, queryPacket
, i
, labellen
);
84 moveCacheItemToBack(d_packetCache
, iter
);
86 if (protobufMessage
) {
87 *protobufMessage
= iter
->d_protobufMessage
;
94 moveCacheItemToFront(d_packetCache
, iter
);
103 bool RecursorPacketCache::getResponsePacket(unsigned int tag
, const std::string
& queryPacket
, time_t now
,
104 std::string
* responsePacket
, uint32_t* age
, uint32_t* qhash
)
107 uint16_t qtype
, qclass
;
110 return getResponsePacket(tag
, queryPacket
, qname
, &qtype
, &qclass
, now
, responsePacket
, age
, qhash
, &ecsBegin
, &ecsEnd
, nullptr);
113 bool RecursorPacketCache::getResponsePacket(unsigned int tag
, const std::string
& queryPacket
, const DNSName
& qname
, uint16_t qtype
, uint16_t qclass
, time_t now
,
114 std::string
* responsePacket
, uint32_t* age
, uint32_t* qhash
)
118 return getResponsePacket(tag
, queryPacket
, qname
, qtype
, qclass
, now
, responsePacket
, age
, qhash
, &ecsBegin
, &ecsEnd
, nullptr);
121 bool RecursorPacketCache::getResponsePacket(unsigned int tag
, const std::string
& queryPacket
, const DNSName
& qname
, uint16_t qtype
, uint16_t qclass
, time_t now
,
122 std::string
* responsePacket
, uint32_t* age
, uint32_t* qhash
, uint16_t* ecsBegin
, uint16_t* ecsEnd
, RecProtoBufMessage
* protobufMessage
)
124 *qhash
= canHashPacket(queryPacket
, ecsBegin
, ecsEnd
);
125 const auto& idx
= d_packetCache
.get
<HashTag
>();
126 auto range
= idx
.equal_range(tie(tag
,*qhash
));
128 if(range
.first
== range
.second
) {
133 return checkResponseMatches(range
, queryPacket
, qname
, qtype
, qclass
, now
, responsePacket
, age
, protobufMessage
, *ecsBegin
, *ecsEnd
);
136 bool RecursorPacketCache::getResponsePacket(unsigned int tag
, const std::string
& queryPacket
, DNSName
& qname
, uint16_t* qtype
, uint16_t* qclass
, time_t now
,
137 std::string
* responsePacket
, uint32_t* age
, uint32_t* qhash
, uint16_t* ecsBegin
, uint16_t* ecsEnd
, RecProtoBufMessage
* protobufMessage
)
139 *qhash
= canHashPacket(queryPacket
, ecsBegin
, ecsEnd
);
140 const auto& idx
= d_packetCache
.get
<HashTag
>();
141 auto range
= idx
.equal_range(tie(tag
,*qhash
));
143 if(range
.first
== range
.second
) {
148 qname
= DNSName(queryPacket
.c_str(), queryPacket
.length(), sizeof(dnsheader
), false, qtype
, qclass
, 0);
150 return checkResponseMatches(range
, queryPacket
, qname
, *qtype
, *qclass
, now
, responsePacket
, age
, protobufMessage
, *ecsBegin
, *ecsEnd
);
154 void RecursorPacketCache::insertResponsePacket(unsigned int tag
, uint32_t qhash
, const std::string
& query
, const DNSName
& qname
, uint16_t qtype
, uint16_t qclass
, const std::string
& responsePacket
, time_t now
, uint32_t ttl
, uint16_t ecsBegin
, uint16_t ecsEnd
)
156 insertResponsePacket(tag
, qhash
, query
, qname
, qtype
, qclass
, responsePacket
, now
, ttl
, ecsBegin
, ecsEnd
, nullptr);
159 void RecursorPacketCache::insertResponsePacket(unsigned int tag
, uint32_t qhash
, const std::string
& query
, const DNSName
& qname
, uint16_t qtype
, uint16_t qclass
, const std::string
& responsePacket
, time_t now
, uint32_t ttl
, uint16_t ecsBegin
, uint16_t ecsEnd
, const RecProtoBufMessage
* protobufMessage
)
161 auto& idx
= d_packetCache
.get
<HashTag
>();
162 auto range
= idx
.equal_range(tie(tag
,qhash
));
163 auto iter
= range
.first
;
165 for( ; iter
!= range
.second
; ++iter
) {
166 if (iter
->d_type
!= qtype
|| iter
->d_class
!= qclass
|| iter
->d_name
!= qname
) {
170 moveCacheItemToBack(d_packetCache
, iter
);
171 iter
->d_packet
= responsePacket
;
172 iter
->d_query
= query
;
173 iter
->d_ecsBegin
= ecsBegin
;
174 iter
->d_ecsEnd
= ecsEnd
;
175 iter
->d_ttd
= now
+ ttl
;
176 iter
->d_creation
= now
;
178 if (protobufMessage
) {
179 iter
->d_protobufMessage
= *protobufMessage
;
186 if(iter
== range
.second
) { // nothing to refresh
187 struct Entry
e(qname
, responsePacket
, query
);
189 e
.d_ecsBegin
= ecsBegin
;
197 if (protobufMessage
) {
198 e
.d_protobufMessage
= *protobufMessage
;
201 d_packetCache
.insert(e
);
205 uint64_t RecursorPacketCache::size()
207 return d_packetCache
.size();
210 uint64_t RecursorPacketCache::bytes()
213 for(const auto& e
: d_packetCache
) {
214 sum
+= sizeof(e
) + e
.d_packet
.length() + 4;
219 void RecursorPacketCache::doPruneTo(unsigned int maxCached
)
221 pruneCollection(*this, d_packetCache
, maxCached
);
224 uint64_t RecursorPacketCache::doDump(int fd
)
226 FILE* fp
=fdopen(dup(fd
), "w");
227 if(!fp
) { // dup probably failed
230 fprintf(fp
, "; main packet cache dump from thread follows\n;\n");
231 const auto& sidx
=d_packetCache
.get
<1>();
235 for(auto i
=sidx
.cbegin(); i
!= sidx
.cend(); ++i
) {
238 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
);
241 fprintf(fp
, "; error printing '%s'\n", i
->d_name
.empty() ? "EMPTY" : i
->d_name
.toString().c_str());