]>
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 | 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 | |
16 | RecursorPacketCache::RecursorPacketCache() | |
17 | { | |
16beeaa4 | 18 | d_hits = d_misses = 0; |
3ea54bf0 BH |
19 | } |
20 | ||
65a60c2c | 21 | int 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 | 46 | static 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 | 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) |
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 |
93 | bool 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 | ||
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) | |
101 | { | |
102 | return getResponsePacket(tag, queryPacket, qname, qtype, qclass, now, responsePacket, age, qhash, nullptr); | |
103 | } | |
104 | ||
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) | |
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 | ||
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) | |
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 | 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) |
02b47f43 | 140 | { |
e9f63d47 | 141 | insertResponsePacket(tag, qhash, qname, qtype, qclass, responsePacket, now, ttl, nullptr); |
02b47f43 RG |
142 | } |
143 | ||
e9f63d47 | 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) |
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 |
186 | uint64_t RecursorPacketCache::size() |
187 | { | |
188 | return d_packetCache.size(); | |
189 | } | |
3f3459f0 | 190 | |
0bbf7d0a BH |
191 | uint64_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 |
200 | void RecursorPacketCache::doPruneTo(unsigned int maxCached) |
201 | { | |
e74f866a | 202 | pruneCollection(*this, d_packetCache, maxCached); |
3f3459f0 BH |
203 | } |
204 | ||
09645ebb | 205 | uint64_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 | } |