]>
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" | |
88694a6a | 11 | #include "syncres.hh" |
3ea54bf0 BH |
12 | |
13 | RecursorPacketCache::RecursorPacketCache() | |
14 | { | |
16beeaa4 | 15 | d_hits = d_misses = 0; |
3ea54bf0 BH |
16 | } |
17 | ||
65a60c2c | 18 | int RecursorPacketCache::doWipePacketCache(const DNSName& name, uint16_t qtype, bool subtree) |
effe43d0 BH |
19 | { |
20 | int count=0; | |
49a3500d | 21 | auto& idx = d_packetCache.get<NameTag>(); |
22 | for(auto iter = idx.lower_bound(name); iter != idx.end(); ) { | |
65a60c2c | 23 | if(subtree) { |
49a3500d | 24 | if(!iter->d_name.isPartOf(name)) { // this is case insensitive |
65a60c2c | 25 | break; |
26 | } | |
27 | } | |
28 | else { | |
49a3500d | 29 | if(iter->d_name != name) |
65a60c2c | 30 | break; |
7313fe62 | 31 | } |
e9f63d47 | 32 | |
49a3500d | 33 | if(qtype==0xffff || iter->d_type == qtype) { |
34 | iter=idx.erase(iter); | |
7313fe62 | 35 | count++; |
effe43d0 | 36 | } |
7313fe62 | 37 | else |
38 | ++iter; | |
effe43d0 BH |
39 | } |
40 | return count; | |
41 | } | |
42 | ||
c15ff3df | 43 | static bool qrMatch(const DNSName& qname, uint16_t qtype, uint16_t qclass, const DNSName& rname, uint16_t rtype, uint16_t rclass) |
3ea54bf0 | 44 | { |
a774e78b | 45 | // this ignores checking on the EDNS subnet flags! |
e9f63d47 | 46 | return qname==rname && rtype == qtype && rclass == qclass; |
49a3500d | 47 | } |
48 | ||
88694a6a | 49 | bool RecursorPacketCache::checkResponseMatches(std::pair<packetCache_t::index<HashTag>::type::iterator, packetCache_t::index<HashTag>::type::iterator> range, const ComboAddress& source, 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 | 50 | { |
49a3500d | 51 | for(auto iter = range.first ; iter != range.second ; ++ iter) { |
52 | // the possibility is VERY real that we get hits that are not right - birthday paradox | |
c15ff3df | 53 | if(!qrMatch(qname, qtype, qclass, iter->d_name, iter->d_type, iter->d_class)) |
49a3500d | 54 | continue; |
6b68a4e3 RG |
55 | if(now < iter->d_ttd) { // it is right, it is fresh! |
56 | *age = static_cast<uint32_t>(now - iter->d_creation); | |
49a3500d | 57 | *responsePacket = iter->d_packet; |
58 | responsePacket->replace(0, 2, queryPacket.c_str(), 2); | |
90974597 | 59 | |
49a3500d | 60 | string::size_type i=sizeof(dnsheader); |
61 | ||
62 | for(;;) { | |
c15ff3df | 63 | unsigned int labellen = (unsigned char)queryPacket[i]; |
49a3500d | 64 | if(!labellen || i + labellen > responsePacket->size()) break; |
65 | i++; | |
66 | responsePacket->replace(i, labellen, queryPacket, i, labellen); | |
67 | i = i + labellen; | |
68 | } | |
3f3459f0 | 69 | |
88694a6a KM |
70 | if(iter->d_vstate == Bogus) { |
71 | if(t_bogusremotes) | |
72 | t_bogusremotes->push_back(source); | |
73 | if(t_bogusqueryring) | |
74 | t_bogusqueryring->push_back(make_pair(qname, qtype)); | |
75 | } | |
49a3500d | 76 | d_hits++; |
77 | moveCacheItemToBack(d_packetCache, iter); | |
02b47f43 RG |
78 | #ifdef HAVE_PROTOBUF |
79 | if (protobufMessage) { | |
d362f7c1 RG |
80 | if (iter->d_protobufMessage) { |
81 | *protobufMessage = *(iter->d_protobufMessage); | |
82 | } | |
83 | else { | |
84 | *protobufMessage = RecProtoBufMessage(DNSProtoBufMessage::DNSProtoBufMessageType::Response); | |
85 | } | |
02b47f43 RG |
86 | } |
87 | #endif | |
49a3500d | 88 | |
89 | return true; | |
90 | } | |
91 | else { | |
92 | moveCacheItemToFront(d_packetCache, iter); | |
93 | d_misses++; | |
94 | break; | |
95 | } | |
3ea54bf0 | 96 | } |
49a3500d | 97 | |
3ea54bf0 BH |
98 | return false; |
99 | } | |
100 | ||
c15ff3df RG |
101 | bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now, |
102 | std::string* responsePacket, uint32_t* age, uint32_t* qhash) | |
103 | { | |
88694a6a KM |
104 | ComboAddress source; |
105 | return getResponsePacket(tag, source, queryPacket, now, responsePacket, age, qhash, nullptr); | |
c15ff3df RG |
106 | } |
107 | ||
108 | bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, | |
109 | std::string* responsePacket, uint32_t* age, uint32_t* qhash) | |
110 | { | |
88694a6a KM |
111 | ComboAddress source; |
112 | return getResponsePacket(tag, source, queryPacket, qname, qtype, qclass, now, responsePacket, age, qhash, nullptr); | |
c15ff3df RG |
113 | } |
114 | ||
88694a6a | 115 | bool RecursorPacketCache::getResponsePacket(unsigned int tag, const ComboAddress& source, const std::string& queryPacket, const DNSName& qname, uint16_t qtype, uint16_t qclass, time_t now, |
c15ff3df RG |
116 | std::string* responsePacket, uint32_t* age, uint32_t* qhash, RecProtoBufMessage* protobufMessage) |
117 | { | |
bf269e28 | 118 | *qhash = canHashPacket(queryPacket, true); |
c15ff3df RG |
119 | const auto& idx = d_packetCache.get<HashTag>(); |
120 | auto range = idx.equal_range(tie(tag,*qhash)); | |
121 | ||
122 | if(range.first == range.second) { | |
123 | d_misses++; | |
124 | return false; | |
125 | } | |
88694a6a | 126 | return checkResponseMatches(range, source, queryPacket, qname, qtype, qclass, now, responsePacket, age, protobufMessage); |
c15ff3df RG |
127 | } |
128 | ||
88694a6a | 129 | bool RecursorPacketCache::getResponsePacket(unsigned int tag, const ComboAddress& source, const std::string& queryPacket, time_t now, |
c15ff3df RG |
130 | std::string* responsePacket, uint32_t* age, uint32_t* qhash, RecProtoBufMessage* protobufMessage) |
131 | { | |
bf269e28 | 132 | *qhash = canHashPacket(queryPacket, true); |
c15ff3df RG |
133 | const auto& idx = d_packetCache.get<HashTag>(); |
134 | auto range = idx.equal_range(tie(tag,*qhash)); | |
135 | ||
136 | if(range.first == range.second) { | |
137 | d_misses++; | |
138 | return false; | |
139 | } | |
140 | ||
141 | uint16_t qtype, qclass; | |
142 | DNSName qname(queryPacket.c_str(), queryPacket.length(), sizeof(dnsheader), false, &qtype, &qclass, 0); | |
143 | ||
88694a6a | 144 | return checkResponseMatches(range, source, queryPacket, qname, qtype, qclass, now, responsePacket, age, protobufMessage); |
c15ff3df RG |
145 | } |
146 | ||
e9f63d47 | 147 | 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 | 148 | { |
88694a6a | 149 | vState valState; |
c5c05077 | 150 | boost::optional<RecProtoBufMessage> pb(boost::none); |
88694a6a | 151 | insertResponsePacket(tag, qhash, qname, qtype, qclass, responsePacket, now, ttl, valState, pb); |
02b47f43 RG |
152 | } |
153 | ||
88694a6a | 154 | 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 vState& valState, const boost::optional<RecProtoBufMessage>& protobufMessage) |
3ea54bf0 | 155 | { |
49a3500d | 156 | auto& idx = d_packetCache.get<HashTag>(); |
157 | auto range = idx.equal_range(tie(tag,qhash)); | |
158 | auto iter = range.first; | |
159 | ||
160 | for( ; iter != range.second ; ++iter) { | |
bf269e28 | 161 | if(iter->d_type != qtype || iter->d_class != qclass || iter->d_name != qname) |
49a3500d | 162 | continue; |
bf269e28 | 163 | |
a072ce44 | 164 | moveCacheItemToBack(d_packetCache, iter); |
3ea54bf0 | 165 | iter->d_packet = responsePacket; |
3f3459f0 | 166 | iter->d_ttd = now + ttl; |
2c73e580 | 167 | iter->d_creation = now; |
02b47f43 RG |
168 | #ifdef HAVE_PROTOBUF |
169 | if (protobufMessage) { | |
170 | iter->d_protobufMessage = *protobufMessage; | |
171 | } | |
172 | #endif | |
173 | ||
49a3500d | 174 | break; |
3ea54bf0 | 175 | } |
49a3500d | 176 | |
177 | if(iter == range.second) { // nothing to refresh | |
972a6068 | 178 | struct Entry e(qname, responsePacket); |
49a3500d | 179 | e.d_qhash = qhash; |
180 | e.d_type = qtype; | |
e9f63d47 | 181 | e.d_class = qclass; |
49a3500d | 182 | e.d_ttd = now+ttl; |
183 | e.d_creation = now; | |
184 | e.d_tag = tag; | |
88694a6a | 185 | e.d_vstate = valState; |
02b47f43 RG |
186 | #ifdef HAVE_PROTOBUF |
187 | if (protobufMessage) { | |
188 | e.d_protobufMessage = *protobufMessage; | |
189 | } | |
190 | #endif | |
3ea54bf0 | 191 | d_packetCache.insert(e); |
49a3500d | 192 | } |
3ea54bf0 BH |
193 | } |
194 | ||
16beeaa4 BH |
195 | uint64_t RecursorPacketCache::size() |
196 | { | |
197 | return d_packetCache.size(); | |
198 | } | |
3f3459f0 | 199 | |
0bbf7d0a BH |
200 | uint64_t RecursorPacketCache::bytes() |
201 | { | |
202 | uint64_t sum=0; | |
f226db2f | 203 | for(const auto& e : d_packetCache) { |
0bbf7d0a BH |
204 | sum += sizeof(e) + e.d_packet.length() + 4; |
205 | } | |
206 | return sum; | |
207 | } | |
208 | ||
3f3459f0 BH |
209 | void RecursorPacketCache::doPruneTo(unsigned int maxCached) |
210 | { | |
e74f866a | 211 | pruneCollection(*this, d_packetCache, maxCached); |
3f3459f0 BH |
212 | } |
213 | ||
09645ebb | 214 | uint64_t RecursorPacketCache::doDump(int fd) |
215 | { | |
216 | FILE* fp=fdopen(dup(fd), "w"); | |
217 | if(!fp) { // dup probably failed | |
218 | return 0; | |
219 | } | |
220 | fprintf(fp, "; main packet cache dump from thread follows\n;\n"); | |
221 | const auto& sidx=d_packetCache.get<1>(); | |
222 | ||
223 | uint64_t count=0; | |
224 | time_t now=time(0); | |
225 | for(auto i=sidx.cbegin(); i != sidx.cend(); ++i) { | |
226 | count++; | |
227 | try { | |
6b68a4e3 | 228 | 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 | 229 | } |
230 | catch(...) { | |
231 | fprintf(fp, "; error printing '%s'\n", i->d_name.empty() ? "EMPTY" : i->d_name.toString().c_str()); | |
232 | } | |
233 | } | |
234 | fclose(fp); | |
235 | return count; | |
236 | ||
237 | } |