]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/recpacketcache.cc
7 #include "recpacketcache.hh"
8 #include "cachecleaner.hh"
10 #include "namespaces.hh"
12 RecursorPacketCache::RecursorPacketCache()
14 d_hits
= d_misses
= 0;
17 int RecursorPacketCache::doWipePacketCache(const DNSName
& name
, uint16_t qtype
, bool subtree
)
20 auto& idx
= d_packetCache
.get
<NameTag
>();
21 for(auto iter
= idx
.lower_bound(name
); iter
!= idx
.end(); ) {
23 if(!iter
->d_name
.isPartOf(name
)) { // this is case insensitive
28 if(iter
->d_name
!= name
)
32 if(qtype
==0xffff || iter
->d_type
== qtype
) {
42 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
)
44 // this ignores checking on the EDNS subnet flags!
45 if (qname
!= iter
->d_name
|| iter
->d_type
!= qtype
|| iter
->d_class
!= qclass
) {
49 if (iter
->d_ecsBegin
!= ecsBegin
|| iter
->d_ecsEnd
!= ecsEnd
) {
53 return queryMatches(iter
->d_query
, queryPacket
, qname
, ecsBegin
, ecsEnd
);
56 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
, vState
* valState
, RecProtoBufMessage
* protobufMessage
, uint16_t ecsBegin
, uint16_t ecsEnd
)
58 for(auto iter
= range
.first
; iter
!= range
.second
; ++iter
) {
59 // the possibility is VERY real that we get hits that are not right - birthday paradox
60 if (!qrMatch(iter
, queryPacket
, qname
, qtype
, qclass
, ecsBegin
, ecsEnd
)) {
64 if (now
< iter
->d_ttd
) { // it is right, it is fresh!
65 *age
= static_cast<uint32_t>(now
- iter
->d_creation
);
66 *responsePacket
= iter
->d_packet
;
67 responsePacket
->replace(0, 2, queryPacket
.c_str(), 2);
68 *valState
= iter
->d_vstate
;
70 const size_t wirelength
= qname
.wirelength();
71 if (responsePacket
->size() > (sizeof(dnsheader
) + wirelength
)) {
72 responsePacket
->replace(sizeof(dnsheader
), wirelength
, queryPacket
, sizeof(dnsheader
), wirelength
);
76 moveCacheItemToBack
<SequencedTag
>(d_packetCache
, iter
);
78 if (protobufMessage
) {
79 if (iter
->d_protobufMessage
) {
80 protobufMessage
->copyFrom(*(iter
->d_protobufMessage
));
83 *protobufMessage
= RecProtoBufMessage(DNSProtoBufMessage::DNSProtoBufMessageType::Response
);
91 moveCacheItemToFront
<SequencedTag
>(d_packetCache
, iter
);
100 bool RecursorPacketCache::getResponsePacket(unsigned int tag
, const std::string
& queryPacket
, time_t now
,
101 std::string
* responsePacket
, uint32_t* age
, uint32_t* qhash
)
104 uint16_t qtype
, qclass
;
108 return getResponsePacket(tag
, queryPacket
, qname
, &qtype
, &qclass
, now
, responsePacket
, age
, &valState
, qhash
, &ecsBegin
, &ecsEnd
, nullptr);
111 bool 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
)
117 return getResponsePacket(tag
, queryPacket
, qname
, qtype
, qclass
, now
, responsePacket
, age
, &valState
, qhash
, &ecsBegin
, &ecsEnd
, nullptr);
120 bool RecursorPacketCache::getResponsePacket(unsigned int tag
, const std::string
& queryPacket
, const DNSName
& qname
, uint16_t qtype
, uint16_t qclass
, time_t now
,
121 std::string
* responsePacket
, uint32_t* age
, vState
* valState
, uint32_t* qhash
, uint16_t* ecsBegin
, uint16_t* ecsEnd
, RecProtoBufMessage
* protobufMessage
)
123 *qhash
= canHashPacket(queryPacket
, ecsBegin
, ecsEnd
);
124 const auto& idx
= d_packetCache
.get
<HashTag
>();
125 auto range
= idx
.equal_range(tie(tag
,*qhash
));
127 if(range
.first
== range
.second
) {
132 return checkResponseMatches(range
, queryPacket
, qname
, qtype
, qclass
, now
, responsePacket
, age
, valState
, protobufMessage
, *ecsBegin
, *ecsEnd
);
135 bool RecursorPacketCache::getResponsePacket(unsigned int tag
, const std::string
& queryPacket
, DNSName
& qname
, uint16_t* qtype
, uint16_t* qclass
, time_t now
,
136 std::string
* responsePacket
, uint32_t* age
, vState
* valState
, uint32_t* qhash
, uint16_t* ecsBegin
, uint16_t* ecsEnd
, RecProtoBufMessage
* protobufMessage
)
138 *qhash
= canHashPacket(queryPacket
, ecsBegin
, ecsEnd
);
139 const auto& idx
= d_packetCache
.get
<HashTag
>();
140 auto range
= idx
.equal_range(tie(tag
,*qhash
));
142 if(range
.first
== range
.second
) {
147 qname
= DNSName(queryPacket
.c_str(), queryPacket
.length(), sizeof(dnsheader
), false, qtype
, qclass
, 0);
149 return checkResponseMatches(range
, queryPacket
, qname
, *qtype
, *qclass
, now
, responsePacket
, age
, valState
, protobufMessage
, *ecsBegin
, *ecsEnd
);
153 void 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
)
155 auto& idx
= d_packetCache
.get
<HashTag
>();
156 auto range
= idx
.equal_range(tie(tag
,qhash
));
157 auto iter
= range
.first
;
159 for( ; iter
!= range
.second
; ++iter
) {
160 if (iter
->d_type
!= qtype
|| iter
->d_class
!= qclass
|| iter
->d_name
!= qname
) {
164 moveCacheItemToBack
<SequencedTag
>(d_packetCache
, iter
);
165 iter
->d_packet
= std::move(responsePacket
);
166 iter
->d_query
= std::move(query
);
167 iter
->d_ecsBegin
= ecsBegin
;
168 iter
->d_ecsEnd
= ecsEnd
;
169 iter
->d_ttd
= now
+ ttl
;
170 iter
->d_creation
= now
;
171 iter
->d_vstate
= valState
;
173 if (protobufMessage
) {
174 iter
->d_protobufMessage
= std::move(*protobufMessage
);
181 if(iter
== range
.second
) { // nothing to refresh
182 struct Entry
e(qname
, std::move(responsePacket
), std::move(query
));
184 e
.d_ecsBegin
= ecsBegin
;
191 e
.d_vstate
= valState
;
193 if (protobufMessage
) {
194 e
.d_protobufMessage
= std::move(*protobufMessage
);
197 d_packetCache
.insert(e
);
201 uint64_t RecursorPacketCache::size()
203 return d_packetCache
.size();
206 uint64_t RecursorPacketCache::bytes()
209 for(const auto& e
: d_packetCache
) {
210 sum
+= sizeof(e
) + e
.d_packet
.length() + 4;
215 void RecursorPacketCache::doPruneTo(unsigned int maxCached
)
217 pruneCollection
<SequencedTag
>(*this, d_packetCache
, maxCached
);
220 uint64_t RecursorPacketCache::doDump(int fd
)
222 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(dup(fd
), "w"), fclose
);
223 if(!fp
) { // dup probably failed
226 fprintf(fp
.get(), "; main packet cache dump from thread follows\n;\n");
227 const auto& sidx
=d_packetCache
.get
<1>();
231 for(auto i
=sidx
.cbegin(); i
!= sidx
.cend(); ++i
) {
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
);
237 fprintf(fp
.get(), "; error printing '%s'\n", i
->d_name
.empty() ? "EMPTY" : i
->d_name
.toString().c_str());