]>
Commit | Line | Data |
---|---|---|
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 | |
12 | RecursorPacketCache::RecursorPacketCache() | |
13 | { | |
16beeaa4 | 14 | d_hits = d_misses = 0; |
3ea54bf0 BH |
15 | } |
16 | ||
65a60c2c | 17 | int 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 | 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) |
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 | 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) |
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 |
100 | bool 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 | ||
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) | |
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 | 120 | bool 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 | 135 | bool 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 | 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) |
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 |
201 | uint64_t RecursorPacketCache::size() |
202 | { | |
203 | return d_packetCache.size(); | |
204 | } | |
3f3459f0 | 205 | |
0bbf7d0a BH |
206 | uint64_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 |
215 | void RecursorPacketCache::doPruneTo(unsigned int maxCached) |
216 | { | |
e74f866a | 217 | pruneCollection(*this, d_packetCache, maxCached); |
3f3459f0 BH |
218 | } |
219 | ||
09645ebb | 220 | uint64_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 | } |