]>
Commit | Line | Data |
---|---|---|
870a0fe4 AT |
1 | #ifdef HAVE_CONFIG_H |
2 | #include "config.h" | |
3 | #endif | |
6b68a4e3 RG |
4 | |
5 | #include <cinttypes> | |
6 | ||
eec1087c BH |
7 | #include "recursor_cache.hh" |
8 | #include "misc.hh" | |
9 | #include <iostream> | |
ea634573 | 10 | #include "dnsrecords.hh" |
bec87d21 | 11 | #include "arguments.hh" |
0ba0f794 | 12 | #include "syncres.hh" |
34264879 | 13 | #include "recursor_cache.hh" |
38c9ceaa | 14 | #include "cachecleaner.hh" |
61b26744 | 15 | #include "namespaces.hh" |
eec1087c | 16 | |
1ffea92c | 17 | unsigned int MemRecursorCache::size() const |
eec1087c | 18 | { |
705f31ae | 19 | return (unsigned int)d_cache.size(); |
43a2b29c BH |
20 | } |
21 | ||
1ffea92c RG |
22 | size_t MemRecursorCache::ecsIndexSize() const |
23 | { | |
24 | return d_ecsIndex.size(); | |
25 | } | |
26 | ||
8e42d27d | 27 | // this function is too slow to poll! |
1ffea92c | 28 | unsigned int MemRecursorCache::bytes() const |
43a2b29c BH |
29 | { |
30 | unsigned int ret=0; | |
31 | ||
4c8d2585 | 32 | for(const auto& i : d_cache) { |
9e5ed2e4 | 33 | ret+=sizeof(struct CacheEntry); |
4c8d2585 RG |
34 | ret+=(unsigned int)i.d_qname.toString().length(); |
35 | for(const auto& record : i.d_records) | |
9b750357 | 36 | ret+= sizeof(record); // XXX WRONG we don't know the stored size! |
43a2b29c BH |
37 | } |
38 | return ret; | |
eec1087c BH |
39 | } |
40 | ||
4c8d2585 | 41 | int32_t MemRecursorCache::handleHit(MemRecursorCache::OrderedTagIterator_t& entry, const DNSName& qname, const ComboAddress& who, vector<DNSRecord>* res, vector<std::shared_ptr<RRSIGRecordContent>>* signatures, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, vState* state, bool* wasAuth) |
e74f866a RG |
42 | { |
43 | int32_t ttd = entry->d_ttd; | |
44 | ||
45 | if(variable && !entry->d_netmask.empty()) { | |
46 | *variable = true; | |
47 | } | |
48 | ||
49 | // cerr<<"Looking at "<<entry->d_records.size()<<" records for this name"<<endl; | |
50 | if (res) { | |
4c8d2585 RG |
51 | res->reserve(res->size() + entry->d_records.size()); |
52 | ||
e74f866a RG |
53 | for(const auto& k : entry->d_records) { |
54 | DNSRecord dr; | |
55 | dr.d_name = qname; | |
56 | dr.d_type = entry->d_qtype; | |
57 | dr.d_class = QClass::IN; | |
58 | dr.d_content = k; | |
59 | dr.d_ttl = static_cast<uint32_t>(entry->d_ttd); | |
60 | dr.d_place = DNSResourceRecord::ANSWER; | |
4c8d2585 | 61 | res->push_back(std::move(dr)); |
e74f866a RG |
62 | } |
63 | } | |
64 | ||
65 | if(signatures) { // if you do an ANY lookup you are hosed XXXX | |
66 | *signatures = entry->d_signatures; | |
67 | } | |
68 | ||
69 | if(authorityRecs) { | |
70 | *authorityRecs = entry->d_authorityRecs; | |
71 | } | |
72 | ||
73 | if (state) { | |
74 | *state = entry->d_state; | |
75 | } | |
76 | ||
77 | if (wasAuth) { | |
78 | *wasAuth = entry->d_auth; | |
79 | } | |
80 | ||
94306029 | 81 | moveCacheItemToBack<SequencedTag>(d_cache, entry); |
e74f866a RG |
82 | |
83 | return ttd; | |
84 | } | |
85 | ||
b0274132 | 86 | MemRecursorCache::cache_t::const_iterator MemRecursorCache::getEntryUsingECSIndex(time_t now, const DNSName &qname, uint16_t qtype, bool requireAuth, const ComboAddress& who) |
e74f866a | 87 | { |
b0274132 RG |
88 | auto ecsIndexKey = tie(qname, qtype); |
89 | auto ecsIndex = d_ecsIndex.find(ecsIndexKey); | |
90 | if (ecsIndex != d_ecsIndex.end() && !ecsIndex->isEmpty()) { | |
e74f866a RG |
91 | /* we have netmask-specific entries, let's see if we match one */ |
92 | while (true) { | |
b0274132 | 93 | const Netmask best = ecsIndex->lookupBestMatch(who); |
e74f866a RG |
94 | if (best.empty()) { |
95 | /* we have nothing more specific for you */ | |
96 | break; | |
97 | } | |
e74f866a RG |
98 | auto key = boost::make_tuple(qname, qtype, best); |
99 | auto entry = d_cache.find(key); | |
100 | if (entry == d_cache.end()) { | |
b0274132 RG |
101 | /* ecsIndex is not up-to-date */ |
102 | ecsIndex->removeNetmask(best); | |
103 | if (ecsIndex->isEmpty()) { | |
104 | d_ecsIndex.erase(ecsIndex); | |
e74f866a RG |
105 | break; |
106 | } | |
107 | continue; | |
108 | } | |
109 | ||
110 | if (entry->d_ttd > now) { | |
111 | if (!requireAuth || entry->d_auth) { | |
112 | return entry; | |
113 | } | |
c8d4f498 RG |
114 | /* we need auth data and the best match is not authoritative */ |
115 | return d_cache.end(); | |
e74f866a RG |
116 | } |
117 | else { | |
118 | /* this netmask-specific entry has expired */ | |
94306029 | 119 | moveCacheItemToFront<SequencedTag>(d_cache, entry); |
b0274132 RG |
120 | ecsIndex->removeNetmask(best); |
121 | if (ecsIndex->isEmpty()) { | |
122 | d_ecsIndex.erase(ecsIndex); | |
e74f866a RG |
123 | break; |
124 | } | |
125 | } | |
126 | } | |
127 | } | |
128 | ||
129 | /* we have nothing specific, let's see if we have a generic one */ | |
130 | auto key = boost::make_tuple(qname, qtype, Netmask()); | |
131 | auto entry = d_cache.find(key); | |
132 | if (entry != d_cache.end()) { | |
133 | if (entry->d_ttd > now) { | |
134 | if (!requireAuth || entry->d_auth) { | |
135 | return entry; | |
136 | } | |
137 | } | |
138 | else { | |
94306029 | 139 | moveCacheItemToFront<SequencedTag>(d_cache, entry); |
e74f866a RG |
140 | } |
141 | } | |
142 | ||
143 | /* nothing for you, sorry */ | |
144 | return d_cache.end(); | |
145 | } | |
146 | ||
d0cd0376 | 147 | // returns -1 for no hits |
4c8d2585 | 148 | std::pair<MemRecursorCache::NameOnlyHashedTagIterator_t, MemRecursorCache::NameOnlyHashedTagIterator_t> MemRecursorCache::getEntries(const DNSName &qname, const QType& qt) |
eec1087c | 149 | { |
e325f20c | 150 | // cerr<<"looking up "<< qname<<"|"+qt.getName()<<"\n"; |
e325f20c | 151 | if(!d_cachecachevalid || d_cachedqname!= qname) { |
b0c3b7d8 | 152 | // cerr<<"had cache cache miss"<<endl; |
4c8d2585 RG |
153 | d_cachedqname = qname; |
154 | const auto& idx = d_cache.get<NameOnlyHashedTag>(); | |
155 | d_cachecache = idx.equal_range(qname); | |
156 | d_cachecachevalid = true; | |
cf98aa40 | 157 | } |
e325f20c | 158 | // else cerr<<"had cache cache hit!"<<endl; |
748eff9f | 159 | |
787737ae RG |
160 | return d_cachecache; |
161 | } | |
162 | ||
4c8d2585 | 163 | bool MemRecursorCache::entryMatches(MemRecursorCache::OrderedTagIterator_t& entry, uint16_t qt, bool requireAuth, const ComboAddress& who) |
787737ae RG |
164 | { |
165 | if (requireAuth && !entry->d_auth) | |
166 | return false; | |
167 | ||
e74f866a RG |
168 | return ((entry->d_qtype == qt || qt == QType::ANY || |
169 | (qt == QType::ADDR && (entry->d_qtype == QType::A || entry->d_qtype == QType::AAAA))) | |
787737ae RG |
170 | && (entry->d_netmask.empty() || entry->d_netmask.match(who))); |
171 | } | |
172 | ||
173 | // returns -1 for no hits | |
174 | int32_t MemRecursorCache::get(time_t now, const DNSName &qname, const QType& qt, bool requireAuth, vector<DNSRecord>* res, const ComboAddress& who, vector<std::shared_ptr<RRSIGRecordContent>>* signatures, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, vState* state, bool* wasAuth) | |
175 | { | |
176 | time_t ttd=0; | |
177 | // cerr<<"looking up "<< qname<<"|"+qt.getName()<<"\n"; | |
e74f866a RG |
178 | if(res) { |
179 | res->clear(); | |
180 | } | |
787737ae | 181 | |
e74f866a RG |
182 | const uint16_t qtype = qt.getCode(); |
183 | /* If we don't have any netmask-specific entries at all, let's just skip this | |
184 | to be able to use the nice d_cachecache hack. */ | |
b0274132 | 185 | if (qtype != QType::ANY && !d_ecsIndex.empty()) { |
e74f866a RG |
186 | if (qtype == QType::ADDR) { |
187 | int32_t ret = -1; | |
787737ae | 188 | |
b0274132 | 189 | auto entryA = getEntryUsingECSIndex(now, qname, QType::A, requireAuth, who); |
e74f866a RG |
190 | if (entryA != d_cache.end()) { |
191 | ret = handleHit(entryA, qname, who, res, signatures, authorityRecs, variable, state, wasAuth); | |
192 | } | |
b0274132 | 193 | auto entryAAAA = getEntryUsingECSIndex(now, qname, QType::AAAA, requireAuth, who); |
e74f866a | 194 | if (entryAAAA != d_cache.end()) { |
4474afe1 | 195 | int32_t ttdAAAA = handleHit(entryAAAA, qname, who, res, signatures, authorityRecs, variable, state, wasAuth); |
e74f866a RG |
196 | if (ret > 0) { |
197 | ret = std::min(ret, ttdAAAA); | |
198 | } else { | |
199 | ret = ttdAAAA; | |
200 | } | |
201 | } | |
202 | return ret > 0 ? static_cast<int32_t>(ret-now) : ret; | |
203 | } | |
204 | else { | |
b0274132 | 205 | auto entry = getEntryUsingECSIndex(now, qname, qtype, requireAuth, who); |
e74f866a RG |
206 | if (entry != d_cache.end()) { |
207 | return static_cast<int32_t>(handleHit(entry, qname, who, res, signatures, authorityRecs, variable, state, wasAuth) - now); | |
208 | } | |
209 | return -1; | |
210 | } | |
211 | } | |
212 | ||
213 | auto entries = getEntries(qname, qt); | |
ea634573 | 214 | |
787737ae | 215 | if(entries.first!=entries.second) { |
4c8d2585 | 216 | for(auto i=entries.first; i != entries.second; ++i) { |
787737ae | 217 | |
4c8d2585 | 218 | auto firstIndexIterator = d_cache.project<OrderedTag>(i); |
787737ae | 219 | if (i->d_ttd <= now) { |
94306029 | 220 | moveCacheItemToFront<SequencedTag>(d_cache, firstIndexIterator); |
24bb9b58 | 221 | continue; |
787737ae | 222 | } |
24bb9b58 | 223 | |
4c8d2585 | 224 | if (!entryMatches(firstIndexIterator, qtype, requireAuth, who)) |
787737ae RG |
225 | continue; |
226 | ||
4c8d2585 | 227 | ttd = handleHit(firstIndexIterator, qname, who, res, signatures, authorityRecs, variable, state, wasAuth); |
787737ae RG |
228 | |
229 | if(qt.getCode()!=QType::ANY && qt.getCode()!=QType::ADDR) // normally if we have a hit, we are done | |
230 | break; | |
24bb9b58 | 231 | } |
b0d4fb45 | 232 | |
4d2be65d | 233 | // cerr<<"time left : "<<ttd - now<<", "<< (res ? res->size() : 0) <<"\n"; |
6b68a4e3 | 234 | return static_cast<int32_t>(ttd-now); |
eec1087c | 235 | } |
eec1087c BH |
236 | return -1; |
237 | } | |
34264879 | 238 | |
e74f866a | 239 | void MemRecursorCache::replace(time_t now, const DNSName &qname, const QType& qt, const vector<DNSRecord>& content, const vector<shared_ptr<RRSIGRecordContent>>& signatures, const std::vector<std::shared_ptr<DNSRecord>>& authorityRecs, bool auth, boost::optional<Netmask> ednsmask, vState state) |
eec1087c | 240 | { |
e74f866a | 241 | d_cachecachevalid = false; |
f9c681bf | 242 | // cerr<<"Replacing "<<qname<<" for "<< (ednsmask ? ednsmask->toString() : "everyone") << endl; |
80462253 SB |
243 | if (ednsmask) { |
244 | ednsmask = ednsmask->getNormalized(); | |
245 | } | |
e74f866a | 246 | auto key = boost::make_tuple(qname, qt.getCode(), ednsmask ? *ednsmask : Netmask()); |
a072ce44 | 247 | bool isNew = false; |
e74f866a RG |
248 | cache_t::iterator stored = d_cache.find(key); |
249 | if (stored == d_cache.end()) { | |
48f19abe | 250 | stored = d_cache.insert(CacheEntry(key, auth)).first; |
a072ce44 | 251 | isNew = true; |
f9c681bf | 252 | } |
e74f866a | 253 | |
d0fcc32b RG |
254 | /* if we are inserting a new entry or updating an expired one (in which case the |
255 | ECS index might have been removed but the entry still exists because it has not | |
256 | been garbage collected yet) we might need to update the ECS index. | |
257 | Otherwise it should already be indexed and we don't need to update it. | |
258 | */ | |
259 | if (isNew || stored->d_ttd <= now) { | |
260 | /* don't bother building an ecsIndex if we don't have any netmask-specific entries */ | |
261 | if (ednsmask && !ednsmask->empty()) { | |
262 | auto ecsIndexKey = boost::make_tuple(qname, qt.getCode()); | |
263 | auto ecsIndex = d_ecsIndex.find(ecsIndexKey); | |
264 | if (ecsIndex == d_ecsIndex.end()) { | |
265 | ecsIndex = d_ecsIndex.insert(ECSIndexEntry(qname, qt.getCode())).first; | |
266 | } | |
267 | ecsIndex->addMask(*ednsmask); | |
e74f866a | 268 | } |
6c674e9a | 269 | } |
270 | ||
6b68a4e3 | 271 | time_t maxTTD=std::numeric_limits<time_t>::max(); |
d0cd0376 | 272 | CacheEntry ce=*stored; // this is a COPY |
e325f20c | 273 | ce.d_qtype=qt.getCode(); |
57769f13 | 274 | ce.d_signatures=signatures; |
2b984251 | 275 | ce.d_authorityRecs=authorityRecs; |
4d2be65d | 276 | ce.d_state=state; |
fbb356b6 | 277 | |
d0cd0376 | 278 | // cerr<<"asked to store "<< (qname.empty() ? "EMPTY" : qname.toString()) <<"|"+qt.getName()<<" -> '"; |
279 | // cerr<<(content.empty() ? string("EMPTY CONTENT") : content.begin()->d_content->getZoneRepresentation())<<"', auth="<<auth<<", ce.auth="<<ce.d_auth; | |
4d2be65d | 280 | // cerr<<", ednsmask: " << (ednsmask ? ednsmask->toString() : "none") <<endl; |
a85eb653 BH |
281 | |
282 | if(!auth && ce.d_auth) { // unauth data came in, we have some auth data, but is it fresh? | |
e325f20c | 283 | if(ce.d_ttd > now) { // we still have valid data, ignore unauth data |
bf4ab707 | 284 | // cerr<<"\tStill hold valid auth data, and the new data is unauth, return\n"; |
a85eb653 | 285 | return; |
609a76b3 BH |
286 | } |
287 | else { | |
288 | ce.d_auth = false; // new data won't be auth | |
289 | } | |
a85eb653 | 290 | } |
d0cd0376 | 291 | |
48f19abe RG |
292 | // refuse any attempt to *raise* the TTL of auth NS records, as it would make it possible |
293 | // for an auth to keep a "ghost" zone alive forever, even after the delegation is gone from | |
294 | // the parent | |
295 | // BUT make sure that we CAN refresh the root | |
fbb356b6 | 296 | if(ce.d_auth && auth && qt.getCode()==QType::NS && !isNew && !qname.isRoot()) { |
297 | // cerr<<"\tLimiting TTL of auth->auth NS set replace to "<<ce.d_ttd<<endl; | |
e325f20c | 298 | maxTTD = ce.d_ttd; |
fc202159 PD |
299 | } |
300 | ||
48f19abe | 301 | if(auth) { |
34264879 | 302 | ce.d_auth = true; |
34264879 | 303 | } |
09a6f097 | 304 | |
48f19abe RG |
305 | ce.d_records.clear(); |
306 | ce.d_records.reserve(content.size()); | |
6196f908 | 307 | |
e74f866a | 308 | for(const auto i : content) { |
6b68a4e3 RG |
309 | /* Yes, we have altered the d_ttl value by adding time(nullptr) to it |
310 | prior to calling this function, so the TTL actually holds a TTD. */ | |
e74f866a RG |
311 | ce.d_ttd=min(maxTTD, static_cast<time_t>(i.d_ttl)); // XXX this does weird things if TTLs differ in the set |
312 | // cerr<<"To store: "<<i.d_content->getZoneRepresentation()<<" with ttl/ttd "<<i.d_ttl<<", capped at: "<<maxTTD<<endl; | |
313 | ce.d_records.push_back(i.d_content); | |
ea634573 | 314 | } |
bf4ab707 | 315 | |
a072ce44 | 316 | if (!isNew) { |
94306029 | 317 | moveCacheItemToBack<SequencedTag>(d_cache, stored); |
a072ce44 | 318 | } |
ca0b5def | 319 | d_cache.replace(stored, ce); |
eec1087c | 320 | } |
92294b60 | 321 | |
86f3ca51 | 322 | int MemRecursorCache::doWipeCache(const DNSName& name, bool sub, uint16_t qtype) |
748eff9f | 323 | { |
85c143a2 | 324 | int count=0; |
7e6139ba | 325 | d_cachecachevalid=false; |
1ef00ba1 | 326 | |
86f3ca51 | 327 | if(!sub) { |
4c8d2585 RG |
328 | auto& idx = d_cache.get<NameOnlyHashedTag>(); |
329 | auto range = idx.equal_range(name); | |
330 | for(auto& i=range.first; i != range.second; ) { | |
331 | if (qtype == 0xffff || i->d_qtype == qtype) { | |
332 | count++; | |
333 | idx.erase(i++); | |
334 | } | |
335 | else { | |
336 | ++i; | |
337 | } | |
e74f866a | 338 | } |
4c8d2585 RG |
339 | if (qtype == 0xffff) { |
340 | auto& ecsIdx = d_ecsIndex.get<OrderedTag>(); | |
341 | auto ecsIndexRange = ecsIdx.equal_range(name); | |
342 | for(auto i = ecsIndexRange.first; i != ecsIndexRange.second; ) { | |
343 | ecsIdx.erase(i++); | |
344 | } | |
86f3ca51 | 345 | } |
4c8d2585 RG |
346 | else { |
347 | auto& ecsIdx = d_ecsIndex.get<HashedTag>(); | |
348 | auto ecsIndexRange = ecsIdx.equal_range(tie(name, qtype)); | |
349 | for(auto i = ecsIndexRange.first; i != ecsIndexRange.second; ) { | |
350 | ecsIdx.erase(i++); | |
351 | } | |
e74f866a | 352 | } |
86f3ca51 | 353 | } |
354 | else { | |
4c8d2585 RG |
355 | auto& idx = d_cache.get<OrderedTag>(); |
356 | auto& ecsIdx = d_ecsIndex.get<OrderedTag>(); | |
357 | ||
358 | for(auto iter = idx.lower_bound(name); iter != idx.end(); ) { | |
86f3ca51 | 359 | if(!iter->d_qname.isPartOf(name)) |
360 | break; | |
361 | if(iter->d_qtype == qtype || qtype == 0xffff) { | |
362 | count++; | |
4c8d2585 | 363 | idx.erase(iter++); |
86f3ca51 | 364 | } |
365 | else | |
366 | iter++; | |
367 | } | |
4c8d2585 | 368 | for(auto iter = ecsIdx.lower_bound(name); iter != ecsIdx.end(); ) { |
e74f866a RG |
369 | if(!iter->d_qname.isPartOf(name)) |
370 | break; | |
371 | if(iter->d_qtype == qtype || qtype == 0xffff) { | |
4c8d2585 | 372 | ecsIdx.erase(iter++); |
e74f866a RG |
373 | } |
374 | else { | |
375 | iter++; | |
376 | } | |
377 | } | |
85c143a2 BH |
378 | } |
379 | return count; | |
748eff9f | 380 | } |
92294b60 | 381 | |
6b68a4e3 | 382 | bool MemRecursorCache::doAgeCache(time_t now, const DNSName& name, uint16_t qtype, uint32_t newTTL) |
a2b4f72f BH |
383 | { |
384 | cache_t::iterator iter = d_cache.find(tie(name, qtype)); | |
e06f9f15 | 385 | if(iter == d_cache.end()) { |
a2b4f72f | 386 | return false; |
e06f9f15 PD |
387 | } |
388 | ||
389 | CacheEntry ce = *iter; | |
6b68a4e3 | 390 | if(ce.d_ttd < now) |
a2b4f72f BH |
391 | return false; // would be dead anyhow |
392 | ||
6b68a4e3 | 393 | uint32_t maxTTL = static_cast<uint32_t>(ce.d_ttd - now); |
e06f9f15 | 394 | if(maxTTL > newTTL) { |
a2b4f72f BH |
395 | d_cachecachevalid=false; |
396 | ||
6b68a4e3 | 397 | time_t newTTD = now + newTTL; |
3ddb9247 | 398 | |
e325f20c | 399 | |
400 | if(ce.d_ttd > newTTD) // do never renew expired or older TTLs | |
401 | ce.d_ttd = newTTD; | |
402 | ||
3ddb9247 | 403 | |
a2b4f72f BH |
404 | d_cache.replace(iter, ce); |
405 | return true; | |
406 | } | |
407 | return false; | |
408 | } | |
409 | ||
b9473937 | 410 | bool MemRecursorCache::updateValidationStatus(time_t now, const DNSName &qname, const QType& qt, const ComboAddress& who, bool requireAuth, vState newState, boost::optional<time_t> capTTD) |
787737ae RG |
411 | { |
412 | bool updated = false; | |
e74f866a | 413 | uint16_t qtype = qt.getCode(); |
b0274132 RG |
414 | if (qtype != QType::ANY && qtype != QType::ADDR && !d_ecsIndex.empty()) { |
415 | auto entry = getEntryUsingECSIndex(now, qname, qtype, requireAuth, who); | |
e74f866a RG |
416 | if (entry == d_cache.end()) { |
417 | return false; | |
418 | } | |
419 | ||
420 | entry->d_state = newState; | |
b9473937 RG |
421 | if (capTTD) { |
422 | entry->d_ttd = std::min(entry->d_ttd, *capTTD); | |
423 | } | |
e74f866a RG |
424 | return true; |
425 | } | |
426 | ||
787737ae RG |
427 | auto entries = getEntries(qname, qt); |
428 | ||
429 | for(auto i = entries.first; i != entries.second; ++i) { | |
4c8d2585 RG |
430 | auto firstIndexIterator = d_cache.project<OrderedTag>(i); |
431 | ||
432 | if (!entryMatches(firstIndexIterator, qtype, requireAuth, who)) | |
787737ae RG |
433 | continue; |
434 | ||
435 | i->d_state = newState; | |
b9473937 RG |
436 | if (capTTD) { |
437 | i->d_ttd = std::min(i->d_ttd, *capTTD); | |
438 | } | |
787737ae RG |
439 | updated = true; |
440 | ||
e74f866a | 441 | if(qtype != QType::ANY && qtype != QType::ADDR) // normally if we have a hit, we are done |
787737ae | 442 | break; |
787737ae RG |
443 | } |
444 | ||
445 | return updated; | |
446 | } | |
447 | ||
d7948528 | 448 | uint64_t MemRecursorCache::doDump(int fd) |
748eff9f | 449 | { |
5e1f23ca | 450 | auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fdopen(dup(fd), "w"), fclose); |
d7948528 BH |
451 | if(!fp) { // dup probably failed |
452 | return 0; | |
748eff9f | 453 | } |
5e1f23ca | 454 | fprintf(fp.get(), "; main record cache dump from thread follows\n;\n"); |
4c8d2585 | 455 | const auto& sidx=d_cache.get<SequencedTag>(); |
bec87d21 | 456 | |
d7948528 | 457 | uint64_t count=0; |
748eff9f | 458 | time_t now=time(0); |
e74f866a RG |
459 | for(const auto i : sidx) { |
460 | for(const auto j : i.d_records) { | |
d7948528 | 461 | count++; |
4327eadf | 462 | try { |
5e1f23ca | 463 | fprintf(fp.get(), "%s %" PRId64 " IN %s %s ; (%s) auth=%i %s\n", i.d_qname.toString().c_str(), static_cast<int64_t>(i.d_ttd - now), DNSRecordContent::NumberToType(i.d_qtype).c_str(), j->getZoneRepresentation().c_str(), vStates[i.d_state], i.d_auth, i.d_netmask.empty() ? "" : i.d_netmask.toString().c_str()); |
4327eadf BH |
464 | } |
465 | catch(...) { | |
5e1f23ca | 466 | fprintf(fp.get(), "; error printing '%s'\n", i.d_qname.empty() ? "EMPTY" : i.d_qname.toString().c_str()); |
4327eadf | 467 | } |
748eff9f | 468 | } |
d50e9bc8 PL |
469 | for(const auto &sig : i.d_signatures) { |
470 | count++; | |
471 | try { | |
5e1f23ca | 472 | fprintf(fp.get(), "%s %" PRId64 " IN RRSIG %s ; %s\n", i.d_qname.toString().c_str(), static_cast<int64_t>(i.d_ttd - now), sig->getZoneRepresentation().c_str(), i.d_netmask.empty() ? "" : i.d_netmask.toString().c_str()); |
d50e9bc8 PL |
473 | } |
474 | catch(...) { | |
5e1f23ca | 475 | fprintf(fp.get(), "; error printing '%s'\n", i.d_qname.empty() ? "EMPTY" : i.d_qname.toString().c_str()); |
d50e9bc8 PL |
476 | } |
477 | } | |
748eff9f | 478 | } |
d7948528 | 479 | return count; |
748eff9f | 480 | } |
43a2b29c | 481 | |
c68ae9fa | 482 | void MemRecursorCache::doPrune(unsigned int keep) |
eec1087c | 483 | { |
cf98aa40 | 484 | d_cachecachevalid=false; |
43a2b29c | 485 | |
94306029 | 486 | pruneCollection<SequencedTag>(*this, d_cache, keep); |
c68ae9fa RG |
487 | } |
488 |