]>
Commit | Line | Data |
---|---|---|
841128ba O |
1 | /* |
2 | * This file is part of PowerDNS or dnsdist. | |
3 | * Copyright -- PowerDNS.COM B.V. and its contributors | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * In addition, for the avoidance of any doubt, permission is granted to | |
10 | * link this program with OpenSSL and to (re)distribute the binaries | |
11 | * produced as the result of such linking. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | */ | |
22 | ||
23 | #include "rec-zonetocache.hh" | |
24 | ||
25 | #include "syncres.hh" | |
841128ba O |
26 | #include "zoneparser-tng.hh" |
27 | #include "query-local-address.hh" | |
28 | #include "axfr-retriever.hh" | |
29 | #include "validate-recursor.hh" | |
48defb61 | 30 | #include "logging.hh" |
48defb61 | 31 | #include "rec-lua-conf.hh" |
5ecf9d92 | 32 | #include "zonemd.hh" |
e5163239 | 33 | #include "validate.hh" |
841128ba | 34 | |
e807cd1e O |
35 | #ifdef HAVE_LIBCURL |
36 | #include "minicurl.hh" | |
37 | #endif | |
38 | ||
48defb61 | 39 | #include <fstream> |
841128ba O |
40 | |
41 | struct ZoneData | |
42 | { | |
24d8f14e | 43 | ZoneData(const std::shared_ptr<Logr::Logger>& log, const std::string& zone) : |
1b5314b9 O |
44 | d_log(log), |
45 | d_zone(zone), | |
46 | d_now(time(nullptr)) {} | |
48defb61 | 47 | |
1aa323fc O |
48 | // Potentially the two fields below could be merged into a single map. ATM it is not clear to me |
49 | // if that would make the code easier to read. | |
841128ba | 50 | std::map<pair<DNSName, QType>, vector<DNSRecord>> d_all; |
d06dcda4 | 51 | std::map<pair<DNSName, QType>, vector<shared_ptr<const RRSIGRecordContent>>> d_sigs; |
1aa323fc O |
52 | |
53 | // Maybe use a SuffixMatchTree? | |
841128ba | 54 | std::set<DNSName> d_delegations; |
1aa323fc | 55 | |
24d8f14e | 56 | std::shared_ptr<Logr::Logger> d_log; |
1b5314b9 O |
57 | DNSName d_zone; |
58 | time_t d_now; | |
841128ba | 59 | |
24d8f14e OM |
60 | [[nodiscard]] bool isRRSetAuth(const DNSName& qname, QType qtype) const; |
61 | void parseDRForCache(DNSRecord& resourceRecord); | |
62 | pdns::ZoneMD::Result getByAXFR(const RecZoneToCache::Config& config, pdns::ZoneMD& zonemd); | |
63 | pdns::ZoneMD::Result processLines(const std::vector<std::string>& lines, const RecZoneToCache::Config& config, pdns::ZoneMD& zonemd); | |
b8d0d0db | 64 | void ZoneToCache(const RecZoneToCache::Config& config); |
24d8f14e | 65 | vState dnssecValidate(pdns::ZoneMD& zonemd, size_t& zonemdCount) const; |
841128ba O |
66 | }; |
67 | ||
a0fc9882 | 68 | bool ZoneData::isRRSetAuth(const DNSName& qname, QType qtype) const |
841128ba O |
69 | { |
70 | DNSName delegatedZone(qname); | |
71 | if (qtype == QType::DS) { | |
72 | delegatedZone.chopOff(); | |
73 | } | |
74 | bool isDelegated = false; | |
75 | for (;;) { | |
76 | if (d_delegations.count(delegatedZone) > 0) { | |
77 | isDelegated = true; | |
78 | break; | |
79 | } | |
80 | delegatedZone.chopOff(); | |
24d8f14e | 81 | if (delegatedZone == g_rootdnsname || delegatedZone == d_zone) { |
841128ba | 82 | break; |
24d8f14e | 83 | } |
841128ba O |
84 | } |
85 | return !isDelegated; | |
86 | } | |
87 | ||
24d8f14e | 88 | void ZoneData::parseDRForCache(DNSRecord& dnsRecord) |
841128ba | 89 | { |
24d8f14e | 90 | if (dnsRecord.d_class != QClass::IN) { |
2088c7b8 OM |
91 | return; |
92 | } | |
24d8f14e | 93 | const auto key = pair(dnsRecord.d_name, dnsRecord.d_type); |
841128ba | 94 | |
24d8f14e | 95 | dnsRecord.d_ttl += d_now; |
841128ba | 96 | |
24d8f14e | 97 | switch (dnsRecord.d_type) { |
841128ba O |
98 | case QType::NSEC: |
99 | case QType::NSEC3: | |
100 | break; | |
101 | case QType::RRSIG: { | |
24d8f14e | 102 | const auto rrsig = getRR<RRSIGRecordContent>(dnsRecord); |
951479eb OM |
103 | if (rrsig == nullptr) { |
104 | break; | |
105 | } | |
24d8f14e | 106 | const auto sigkey = pair(key.first, rrsig->d_type); |
841128ba O |
107 | auto found = d_sigs.find(sigkey); |
108 | if (found != d_sigs.end()) { | |
24d8f14e | 109 | found->second.push_back(rrsig); |
841128ba O |
110 | } |
111 | else { | |
d06dcda4 | 112 | vector<shared_ptr<const RRSIGRecordContent>> sigsrr; |
24d8f14e | 113 | sigsrr.push_back(rrsig); |
841128ba O |
114 | d_sigs.insert({sigkey, sigsrr}); |
115 | } | |
116 | break; | |
117 | } | |
118 | case QType::NS: | |
24d8f14e OM |
119 | if (dnsRecord.d_name != d_zone) { |
120 | d_delegations.insert(dnsRecord.d_name); | |
841128ba O |
121 | } |
122 | break; | |
123 | default: | |
124 | break; | |
125 | } | |
126 | ||
127 | auto found = d_all.find(key); | |
128 | if (found != d_all.end()) { | |
24d8f14e | 129 | found->second.push_back(dnsRecord); |
841128ba O |
130 | } |
131 | else { | |
24d8f14e OM |
132 | vector<DNSRecord> dnsRecords; |
133 | dnsRecords.push_back(dnsRecord); | |
134 | d_all.insert({key, dnsRecords}); | |
841128ba O |
135 | } |
136 | } | |
137 | ||
e5163239 | 138 | pdns::ZoneMD::Result ZoneData::getByAXFR(const RecZoneToCache::Config& config, pdns::ZoneMD& zonemd) |
841128ba | 139 | { |
e807cd1e O |
140 | ComboAddress primary = ComboAddress(config.d_sources.at(0), 53); |
141 | uint16_t axfrTimeout = config.d_timeout; | |
142 | size_t maxReceivedBytes = config.d_maxReceivedBytes; | |
24d8f14e | 143 | const TSIGTriplet tsigTriplet = config.d_tt; |
e807cd1e | 144 | ComboAddress local = config.d_local; |
841128ba O |
145 | if (local == ComboAddress()) { |
146 | local = pdns::getQueryLocalAddress(primary.sin4.sin_family, 0); | |
147 | } | |
48defb61 | 148 | |
24d8f14e | 149 | AXFRRetriever axfr(primary, d_zone, tsigTriplet, &local, maxReceivedBytes, axfrTimeout); |
841128ba O |
150 | Resolver::res_t nop; |
151 | vector<DNSRecord> chunk; | |
152 | time_t axfrStart = time(nullptr); | |
153 | time_t axfrNow = time(nullptr); | |
48defb61 | 154 | |
8f67f0c2 | 155 | // coverity[store_truncates_time_t] |
24d8f14e OM |
156 | while (axfr.getChunk(nop, &chunk, (axfrStart + axfrTimeout - axfrNow)) != 0) { |
157 | for (auto& dnsRecord : chunk) { | |
5ecf9d92 | 158 | if (config.d_zonemd != pdns::ZoneMD::Config::Ignore) { |
24d8f14e | 159 | zonemd.readRecord(dnsRecord); |
5ecf9d92 | 160 | } |
24d8f14e | 161 | parseDRForCache(dnsRecord); |
841128ba O |
162 | } |
163 | axfrNow = time(nullptr); | |
164 | if (axfrNow < axfrStart || axfrNow - axfrStart > axfrTimeout) { | |
a0fc9882 | 165 | throw std::runtime_error("Total AXFR time for zoneToCache exceeded!"); |
841128ba O |
166 | } |
167 | } | |
5ecf9d92 | 168 | if (config.d_zonemd != pdns::ZoneMD::Config::Ignore) { |
24d8f14e OM |
169 | bool validationDone = false; |
170 | bool validationSuccess = false; | |
5ecf9d92 | 171 | zonemd.verify(validationDone, validationSuccess); |
8693e70b | 172 | d_log->info(Logr::Info, "ZONEMD digest validation", "validationDone", Logging::Loggable(validationDone), |
574447ad | 173 | "validationSuccess", Logging::Loggable(validationSuccess)); |
5ecf9d92 OM |
174 | if (!validationDone) { |
175 | return pdns::ZoneMD::Result::NoValidationDone; | |
176 | } | |
177 | if (!validationSuccess) { | |
178 | return pdns::ZoneMD::Result::ValidationFailure; | |
179 | } | |
180 | } | |
181 | return pdns::ZoneMD::Result::OK; | |
841128ba O |
182 | } |
183 | ||
a0fc9882 | 184 | static std::vector<std::string> getLinesFromFile(const std::string& file) |
841128ba | 185 | { |
e807cd1e | 186 | |
841128ba | 187 | std::vector<std::string> lines; |
a0fc9882 | 188 | std::ifstream stream(file); |
e807cd1e | 189 | if (!stream) { |
a0fc9882 | 190 | throw std::runtime_error("Cannot read file: " + file); |
e807cd1e | 191 | } |
841128ba O |
192 | std::string line; |
193 | while (std::getline(stream, line)) { | |
194 | lines.push_back(line); | |
195 | } | |
196 | return lines; | |
197 | } | |
198 | ||
e807cd1e | 199 | static std::vector<std::string> getURL(const RecZoneToCache::Config& config) |
841128ba O |
200 | { |
201 | std::vector<std::string> lines; | |
202 | #ifdef HAVE_LIBCURL | |
24d8f14e | 203 | MiniCurl miniCurl; |
e807cd1e | 204 | ComboAddress local = config.d_local; |
24d8f14e | 205 | std::string reply = miniCurl.getURL(config.d_sources.at(0), nullptr, local == ComboAddress() ? nullptr : &local, static_cast<int>(config.d_timeout), false, true); |
48defb61 OM |
206 | if (config.d_maxReceivedBytes > 0 && reply.size() > config.d_maxReceivedBytes) { |
207 | // We should actually detect this *during* the GET | |
a0fc9882 | 208 | throw std::runtime_error("Retrieved data exceeds maxReceivedBytes"); |
48defb61 | 209 | } |
841128ba O |
210 | std::istringstream stream(reply); |
211 | string line; | |
212 | while (std::getline(stream, line)) { | |
213 | lines.push_back(line); | |
214 | } | |
1b5314b9 O |
215 | #else |
216 | throw std::runtime_error("url method configured but libcurl not compiled in"); | |
841128ba O |
217 | #endif |
218 | return lines; | |
219 | } | |
220 | ||
e5163239 | 221 | pdns::ZoneMD::Result ZoneData::processLines(const vector<string>& lines, const RecZoneToCache::Config& config, pdns::ZoneMD& zonemd) |
5ee5e1e6 OM |
222 | { |
223 | DNSResourceRecord drr; | |
52b2a1f2 | 224 | ZoneParserTNG zpt(lines, d_zone, true); |
5ee5e1e6 OM |
225 | zpt.setMaxGenerateSteps(1); |
226 | zpt.setMaxIncludes(0); | |
227 | ||
5ee5e1e6 | 228 | while (zpt.get(drr)) { |
24d8f14e | 229 | DNSRecord dnsRecord(drr); |
5ee5e1e6 | 230 | if (config.d_zonemd != pdns::ZoneMD::Config::Ignore) { |
24d8f14e | 231 | zonemd.readRecord(dnsRecord); |
5ee5e1e6 | 232 | } |
24d8f14e | 233 | parseDRForCache(dnsRecord); |
5ee5e1e6 OM |
234 | } |
235 | if (config.d_zonemd != pdns::ZoneMD::Config::Ignore) { | |
24d8f14e OM |
236 | bool validationDone = false; |
237 | bool validationSuccess = false; | |
5ee5e1e6 | 238 | zonemd.verify(validationDone, validationSuccess); |
8693e70b | 239 | d_log->info(Logr::Info, "ZONEMD digest validation", "validationDone", Logging::Loggable(validationDone), |
574447ad | 240 | "validationSuccess", Logging::Loggable(validationSuccess)); |
5ee5e1e6 OM |
241 | if (!validationDone) { |
242 | return pdns::ZoneMD::Result::NoValidationDone; | |
243 | } | |
244 | if (!validationSuccess) { | |
245 | return pdns::ZoneMD::Result::ValidationFailure; | |
246 | } | |
247 | } | |
248 | return pdns::ZoneMD::Result::OK; | |
249 | } | |
250 | ||
b8d0d0db | 251 | vState ZoneData::dnssecValidate(pdns::ZoneMD& zonemd, size_t& zonemdCount) const |
e5163239 | 252 | { |
15e973d6 OM |
253 | pdns::validation::ValidationContext validationContext; |
254 | validationContext.d_nsec3IterationsRemainingQuota = std::numeric_limits<decltype(validationContext.d_nsec3IterationsRemainingQuota)>::max(); | |
b8d0d0db | 255 | zonemdCount = 0; |
e5163239 | 256 | |
24d8f14e OM |
257 | SyncRes resolver({d_now, 0}); |
258 | resolver.setDoDNSSEC(true); | |
259 | resolver.setDNSSECValidationRequested(true); | |
e5163239 | 260 | |
b8d0d0db | 261 | dsmap_t dsmap; // Actually a set |
24d8f14e | 262 | vState dsState = resolver.getDSRecords(d_zone, dsmap, false, 0, ""); |
e5163239 | 263 | if (dsState != vState::Secure) { |
574447ad | 264 | return dsState; |
e5163239 OM |
265 | } |
266 | ||
b8d0d0db | 267 | skeyset_t dnsKeys; |
e5163239 | 268 | sortedRecords_t records; |
24d8f14e | 269 | if (zonemd.getDNSKEYs().empty()) { |
e5163239 OM |
270 | return vState::BogusUnableToGetDNSKEYs; |
271 | } | |
b8d0d0db | 272 | for (const auto& key : zonemd.getDNSKEYs()) { |
e5163239 OM |
273 | dnsKeys.emplace(key); |
274 | records.emplace(key); | |
275 | } | |
276 | ||
277 | skeyset_t validKeys; | |
15e973d6 | 278 | vState dnsKeyState = validateDNSKeysAgainstDS(d_now, d_zone, dsmap, dnsKeys, records, zonemd.getRRSIGs(), validKeys, std::nullopt, validationContext); |
e5163239 OM |
279 | if (dnsKeyState != vState::Secure) { |
280 | return dnsKeyState; | |
281 | } | |
282 | ||
24d8f14e | 283 | if (validKeys.empty()) { |
e5163239 OM |
284 | return vState::BogusNoValidDNSKEY; |
285 | } | |
b8d0d0db OM |
286 | |
287 | auto zonemdRecords = zonemd.getZONEMDs(); | |
288 | zonemdCount = zonemdRecords.size(); | |
95b66e0d OM |
289 | |
290 | // De we need to do a denial validation? | |
b8d0d0db | 291 | if (zonemdCount == 0) { |
95b66e0d OM |
292 | const auto& nsecs = zonemd.getNSECs(); |
293 | const auto& nsec3s = zonemd.getNSEC3s(); | |
294 | cspmap_t csp; | |
295 | ||
24d8f14e | 296 | vState nsecValidationStatus = vState::Indeterminate; |
2088c7b8 | 297 | |
24d8f14e | 298 | if (!nsecs.records.empty() && !nsecs.signatures.empty()) { |
2088c7b8 | 299 | // Valdidate the NSEC |
15e973d6 | 300 | nsecValidationStatus = validateWithKeySet(d_now, d_zone, nsecs.records, nsecs.signatures, validKeys, std::nullopt, validationContext); |
0b0882f5 | 301 | csp.emplace(std::pair(d_zone, QType::NSEC), nsecs); |
6ee50109 | 302 | } |
24d8f14e | 303 | else if (!nsec3s.records.empty() && !nsec3s.signatures.empty()) { |
2088c7b8 OM |
304 | // Validate NSEC3PARAMS |
305 | records.clear(); | |
306 | for (const auto& rec : zonemd.getNSEC3Params()) { | |
307 | records.emplace(rec); | |
308 | } | |
15e973d6 | 309 | nsecValidationStatus = validateWithKeySet(d_now, d_zone, records, zonemd.getRRSIGs(), validKeys, std::nullopt, validationContext); |
2088c7b8 | 310 | if (nsecValidationStatus != vState::Secure) { |
8693e70b | 311 | d_log->info(Logr::Warning, "NSEC3PARAMS records did not validate"); |
2088c7b8 OM |
312 | return nsecValidationStatus; |
313 | } | |
314 | // Valdidate the NSEC3 | |
15e973d6 | 315 | nsecValidationStatus = validateWithKeySet(d_now, zonemd.getNSEC3Label(), nsec3s.records, nsec3s.signatures, validKeys, std::nullopt, validationContext); |
0b0882f5 | 316 | csp.emplace(std::pair(zonemd.getNSEC3Label(), QType::NSEC3), nsec3s); |
6ee50109 OM |
317 | } |
318 | else { | |
8693e70b | 319 | d_log->info(Logr::Warning, "No NSEC(3) records and/or RRSIGS found to deny ZONEMD"); |
95b66e0d OM |
320 | return vState::BogusInvalidDenial; |
321 | } | |
322 | ||
323 | if (nsecValidationStatus != vState::Secure) { | |
8693e70b | 324 | d_log->info(Logr::Warning, "zone NSEC(3) record does not validate"); |
95b66e0d OM |
325 | return nsecValidationStatus; |
326 | } | |
7f9ac81c | 327 | |
15e973d6 | 328 | auto denial = getDenial(csp, d_zone, QType::ZONEMD, false, false, validationContext, std::nullopt, true); |
7f9ac81c | 329 | if (denial == dState::NXQTYPE) { |
8693e70b | 330 | d_log->info(Logr::Info, "Validated denial of existence of ZONEMD record"); |
95b66e0d | 331 | return vState::Secure; |
95b66e0d | 332 | } |
8693e70b | 333 | d_log->info(Logr::Warning, "No ZONEMD record, but NSEC(3) record does not deny it"); |
7f9ac81c | 334 | return vState::BogusInvalidDenial; |
e5163239 | 335 | } |
e5163239 | 336 | |
95b66e0d OM |
337 | // Collect the ZONEMD records and validate them using the validated DNSSKEYs |
338 | records.clear(); | |
b8d0d0db | 339 | for (const auto& rec : zonemdRecords) { |
e5163239 OM |
340 | records.emplace(rec); |
341 | } | |
15e973d6 | 342 | return validateWithKeySet(d_now, d_zone, records, zonemd.getRRSIGs(), validKeys, std::nullopt, validationContext); |
e5163239 OM |
343 | } |
344 | ||
b8d0d0db | 345 | void ZoneData::ZoneToCache(const RecZoneToCache::Config& config) |
841128ba | 346 | { |
e807cd1e | 347 | if (config.d_sources.size() > 1) { |
24d8f14e | 348 | d_log->info(Logr::Warning, "Multiple sources not yet supported, using first"); |
e807cd1e | 349 | } |
841128ba | 350 | |
94223b01 OM |
351 | if (config.d_dnssec == pdns::ZoneMD::Config::Require && (g_dnssecmode == DNSSECMode::Off || g_dnssecmode == DNSSECMode::ProcessNoValidate)) { |
352 | throw PDNSException("ZONEMD DNSSEC validation failure: DNSSEC validation is switched off but required by ZoneToCache"); | |
353 | } | |
354 | ||
7f9ac81c | 355 | // First scan all records collecting info about delegations and sigs |
841128ba O |
356 | // A this moment, we ignore NSEC and NSEC3 records. It is not clear to me yet under which conditions |
357 | // they could be entered in into the (neg)cache. | |
358 | ||
e5163239 | 359 | auto zonemd = pdns::ZoneMD(DNSName(config.d_zone)); |
5ecf9d92 | 360 | pdns::ZoneMD::Result result = pdns::ZoneMD::Result::OK; |
e807cd1e | 361 | if (config.d_method == "axfr") { |
8693e70b | 362 | d_log->info(Logr::Info, "Getting zone by AXFR"); |
e5163239 | 363 | result = getByAXFR(config, zonemd); |
841128ba O |
364 | } |
365 | else { | |
366 | vector<string> lines; | |
e807cd1e | 367 | if (config.d_method == "url") { |
8693e70b | 368 | d_log->info(Logr::Info, "Getting zone by URL"); |
e807cd1e | 369 | lines = getURL(config); |
841128ba | 370 | } |
e807cd1e | 371 | else if (config.d_method == "file") { |
8693e70b | 372 | d_log->info(Logr::Info, "Getting zone from file"); |
a0fc9882 | 373 | lines = getLinesFromFile(config.d_sources.at(0)); |
841128ba | 374 | } |
e5163239 OM |
375 | result = processLines(lines, config, zonemd); |
376 | } | |
377 | ||
e5163239 | 378 | // Validate DNSKEYs and ZONEMD, rest of records are validated on-demand by SyncRes |
6ee50109 | 379 | if (config.d_dnssec == pdns::ZoneMD::Config::Require || (g_dnssecmode != DNSSECMode::Off && g_dnssecmode != DNSSECMode::ProcessNoValidate && config.d_dnssec != pdns::ZoneMD::Config::Ignore)) { |
24d8f14e | 380 | size_t zonemdCount = 0; |
b8d0d0db | 381 | auto validationStatus = dnssecValidate(zonemd, zonemdCount); |
8693e70b | 382 | d_log->info(Logr::Info, "ZONEMD record related DNSSEC validation", "validationStatus", Logging::Loggable(validationStatus), |
b8d0d0db | 383 | "zonemdCount", Logging::Loggable(zonemdCount)); |
af5b15bc | 384 | if (config.d_dnssec == pdns::ZoneMD::Config::Require && validationStatus != vState::Secure) { |
574447ad | 385 | throw PDNSException("ZONEMD required DNSSEC validation failed"); |
e5163239 | 386 | } |
b8d0d0db | 387 | if (validationStatus != vState::Secure && validationStatus != vState::Insecure) { |
95b66e0d | 388 | throw PDNSException("ZONEMD record DNSSEC validation failed"); |
b8d0d0db | 389 | } |
5ecf9d92 OM |
390 | } |
391 | ||
af5b15bc | 392 | if (config.d_zonemd == pdns::ZoneMD::Config::Require && result != pdns::ZoneMD::Result::OK) { |
5ecf9d92 | 393 | // We do not accept NoValidationDone in this case |
b8d0d0db | 394 | throw PDNSException("ZONEMD digest validation failure"); |
5ecf9d92 OM |
395 | return; |
396 | } | |
af5b15bc | 397 | if (config.d_zonemd == pdns::ZoneMD::Config::Validate && result == pdns::ZoneMD::Result::ValidationFailure) { |
e5163239 | 398 | throw PDNSException("ZONEMD digest validation failure"); |
5ecf9d92 OM |
399 | return; |
400 | } | |
e5163239 | 401 | |
841128ba | 402 | // Rerun, now inserting the rrsets into the cache with associated sigs |
48defb61 | 403 | d_now = time(nullptr); |
48defb61 | 404 | for (const auto& [key, v] : d_all) { |
841128ba O |
405 | const auto& [qname, qtype] = key; |
406 | switch (qtype) { | |
407 | case QType::NSEC: | |
408 | case QType::NSEC3: | |
841128ba O |
409 | case QType::RRSIG: |
410 | break; | |
411 | default: { | |
d06dcda4 | 412 | vector<shared_ptr<const RRSIGRecordContent>> sigsrr; |
24d8f14e OM |
413 | auto iter = d_sigs.find(key); |
414 | if (iter != d_sigs.end()) { | |
415 | sigsrr = iter->second; | |
841128ba | 416 | } |
48defb61 | 417 | bool auth = isRRSetAuth(qname, qtype); |
841128ba O |
418 | // Same decision as updateCacheFromRecords() (we do not test for NSEC since we skip those completely) |
419 | if (auth || (qtype == QType::NS || qtype == QType::A || qtype == QType::AAAA || qtype == QType::DS)) { | |
48defb61 OM |
420 | g_recCache->replace(d_now, qname, qtype, v, sigsrr, |
421 | std::vector<std::shared_ptr<DNSRecord>>(), auth, d_zone); | |
841128ba O |
422 | } |
423 | break; | |
424 | } | |
425 | } | |
426 | } | |
48defb61 OM |
427 | } |
428 | ||
11871d6c OM |
429 | void RecZoneToCache::maintainStates(const map<DNSName, Config>& configs, map<DNSName, State>& states, uint64_t mygeneration) |
430 | { | |
431 | // Delete states that have no config | |
432 | for (auto it = states.begin(); it != states.end();) { | |
433 | if (configs.find(it->first) == configs.end()) { | |
434 | it = states.erase(it); | |
435 | } | |
436 | else { | |
437 | it = ++it; | |
438 | } | |
439 | } | |
440 | // Reset states for which the config generation changed and create new states for new configs | |
dacf2931 | 441 | for (const auto& config : configs) { |
11871d6c OM |
442 | auto state = states.find(config.first); |
443 | if (state != states.end()) { | |
444 | if (state->second.d_generation != mygeneration) { | |
445 | state->second = {0, 0, mygeneration}; | |
446 | } | |
447 | } | |
448 | else { | |
0b0882f5 | 449 | states.emplace(config.first, State{0, 0, mygeneration}); |
11871d6c OM |
450 | } |
451 | } | |
452 | } | |
453 | ||
b8d0d0db | 454 | void RecZoneToCache::ZoneToCache(const RecZoneToCache::Config& config, RecZoneToCache::State& state) |
48defb61 | 455 | { |
b8d0d0db OM |
456 | if (state.d_waittime == 0 && state.d_lastrun > 0) { |
457 | // single shot | |
458 | return; | |
459 | } | |
460 | if (state.d_lastrun > 0 && state.d_lastrun + state.d_waittime > time(nullptr)) { | |
461 | return; | |
462 | } | |
48defb61 OM |
463 | auto log = g_slog->withName("ztc")->withValues("zone", Logging::Loggable(config.d_zone)); |
464 | ||
b8d0d0db OM |
465 | state.d_waittime = config.d_retryOnError; |
466 | try { | |
467 | ZoneData data(log, config.d_zone); | |
468 | data.ZoneToCache(config); | |
469 | state.d_waittime = config.d_refreshPeriod; | |
8693e70b | 470 | log->info(Logr::Info, "Loaded zone into cache", "refresh", Logging::Loggable(state.d_waittime)); |
b8d0d0db OM |
471 | } |
472 | catch (const PDNSException& e) { | |
c85af1d0 | 473 | log->error(Logr::Error, e.reason, "Unable to load zone into cache, will retry", "exception", Logging::Loggable("PDNSException"), "refresh", Logging::Loggable(state.d_waittime)); |
b8d0d0db OM |
474 | } |
475 | catch (const std::runtime_error& e) { | |
c85af1d0 | 476 | log->error(Logr::Error, e.what(), "Unable to load zone into cache, will retry", "exception", Logging::Loggable("std::runtime_error"), "refresh", Logging::Loggable(state.d_waittime)); |
b8d0d0db OM |
477 | } |
478 | catch (...) { | |
8693e70b | 479 | log->info(Logr::Error, "Unable to load zone into cache, will retry", "refresh", Logging::Loggable(state.d_waittime)); |
48defb61 | 480 | } |
b8d0d0db | 481 | state.d_lastrun = time(nullptr); |
841128ba | 482 | } |