]>
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 static bool qrMatch(const DNSName
& qname
, uint16_t qtype
, uint16_t qclass
, const DNSName
& rname
, uint16_t rtype
, uint16_t rclass
)
48 // this ignores checking on the EDNS subnet flags!
49 return qname
==rname
&& rtype
== qtype
&& rclass
== qclass
;
52 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
)
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
56 if(!qrMatch(qname
, qtype
, qclass
, iter
->d_name
, iter
->d_type
, iter
->d_class
))
58 if(now
< iter
->d_ttd
) { // it is right, it is fresh!
59 *age
= static_cast<uint32_t>(now
- iter
->d_creation
);
60 *responsePacket
= iter
->d_packet
;
61 responsePacket
->replace(0, 2, queryPacket
.c_str(), 2);
63 string::size_type i
=sizeof(dnsheader
);
66 unsigned int labellen
= (unsigned char)queryPacket
[i
];
67 if(!labellen
|| i
+ labellen
> responsePacket
->size()) break;
69 responsePacket
->replace(i
, labellen
, queryPacket
, i
, labellen
);
74 moveCacheItemToBack(d_packetCache
, iter
);
76 if (protobufMessage
) {
77 *protobufMessage
= iter
->d_protobufMessage
;
84 moveCacheItemToFront(d_packetCache
, iter
);
93 bool RecursorPacketCache::getResponsePacket(unsigned int tag
, const std::string
& queryPacket
, time_t now
,
94 std::string
* responsePacket
, uint32_t* age
, uint32_t* qhash
)
96 return getResponsePacket(tag
, queryPacket
, now
, responsePacket
, age
, qhash
, nullptr);
99 bool 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
)
102 return getResponsePacket(tag
, queryPacket
, qname
, qtype
, qclass
, now
, responsePacket
, age
, qhash
, nullptr);
105 bool 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
)
108 *qhash
= canHashPacket(queryPacket
, true);
109 const auto& idx
= d_packetCache
.get
<HashTag
>();
110 auto range
= idx
.equal_range(tie(tag
,*qhash
));
112 if(range
.first
== range
.second
) {
117 return checkResponseMatches(range
, queryPacket
, qname
, qtype
, qclass
, now
, responsePacket
, age
, protobufMessage
);
120 bool RecursorPacketCache::getResponsePacket(unsigned int tag
, const std::string
& queryPacket
, time_t now
,
121 std::string
* responsePacket
, uint32_t* age
, uint32_t* qhash
, RecProtoBufMessage
* protobufMessage
)
123 *qhash
= canHashPacket(queryPacket
, true);
124 const auto& idx
= d_packetCache
.get
<HashTag
>();
125 auto range
= idx
.equal_range(tie(tag
,*qhash
));
127 if(range
.first
== range
.second
) {
132 uint16_t qtype
, qclass
;
133 DNSName
qname(queryPacket
.c_str(), queryPacket
.length(), sizeof(dnsheader
), false, &qtype
, &qclass
, 0);
135 return checkResponseMatches(range
, queryPacket
, qname
, qtype
, qclass
, now
, responsePacket
, age
, protobufMessage
);
139 void 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
)
141 insertResponsePacket(tag
, qhash
, qname
, qtype
, qclass
, responsePacket
, now
, ttl
, nullptr);
144 void 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
)
146 auto& idx
= d_packetCache
.get
<HashTag
>();
147 auto range
= idx
.equal_range(tie(tag
,qhash
));
148 auto iter
= range
.first
;
150 for( ; iter
!= range
.second
; ++iter
) {
151 if(iter
->d_type
!= qtype
|| iter
->d_class
!= qclass
|| iter
->d_name
!= qname
)
154 moveCacheItemToBack(d_packetCache
, iter
);
155 iter
->d_packet
= responsePacket
;
156 iter
->d_ttd
= now
+ ttl
;
157 iter
->d_creation
= now
;
159 if (protobufMessage
) {
160 iter
->d_protobufMessage
= *protobufMessage
;
167 if(iter
== range
.second
) { // nothing to refresh
169 e
.d_packet
= responsePacket
;
178 if (protobufMessage
) {
179 e
.d_protobufMessage
= *protobufMessage
;
182 d_packetCache
.insert(e
);
186 uint64_t RecursorPacketCache::size()
188 return d_packetCache
.size();
191 uint64_t RecursorPacketCache::bytes()
194 for(const auto& e
: d_packetCache
) {
195 sum
+= sizeof(e
) + e
.d_packet
.length() + 4;
200 void RecursorPacketCache::doPruneTo(unsigned int maxCached
)
202 pruneCollection(*this, d_packetCache
, maxCached
);
205 uint64_t RecursorPacketCache::doDump(int fd
)
207 FILE* fp
=fdopen(dup(fd
), "w");
208 if(!fp
) { // dup probably failed
211 fprintf(fp
, "; main packet cache dump from thread follows\n;\n");
212 const auto& sidx
=d_packetCache
.get
<1>();
216 for(auto i
=sidx
.cbegin(); i
!= sidx
.cend(); ++i
) {
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
);
222 fprintf(fp
, "; error printing '%s'\n", i
->d_name
.empty() ? "EMPTY" : i
->d_name
.toString().c_str());