]> git.ipfire.org Git - thirdparty/pdns.git/blame_incremental - pdns/syncres.cc
Avoid shadowing of var names and use modern C++
[thirdparty/pdns.git] / pdns / syncres.cc
... / ...
CommitLineData
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#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25
26#include "arguments.hh"
27#include "cachecleaner.hh"
28#include "dns_random.hh"
29#include "dnsparser.hh"
30#include "dnsrecords.hh"
31#include "ednssubnet.hh"
32#include "logger.hh"
33#include "lua-recursor4.hh"
34#include "rec-lua-conf.hh"
35#include "syncres.hh"
36#include "dnsseckeeper.hh"
37#include "validate-recursor.hh"
38
39thread_local SyncRes::ThreadLocalStorage SyncRes::t_sstorage;
40thread_local std::unique_ptr<addrringbuf_t> t_timeouts;
41
42std::unordered_set<DNSName> SyncRes::s_delegationOnly;
43std::unique_ptr<NetmaskGroup> SyncRes::s_dontQuery{nullptr};
44NetmaskGroup SyncRes::s_ednslocalsubnets;
45NetmaskGroup SyncRes::s_ednsremotesubnets;
46SuffixMatchNode SyncRes::s_ednsdomains;
47EDNSSubnetOpts SyncRes::s_ecsScopeZero;
48string SyncRes::s_serverID;
49SyncRes::LogMode SyncRes::s_lm;
50
51unsigned int SyncRes::s_maxnegttl;
52unsigned int SyncRes::s_maxbogusttl;
53unsigned int SyncRes::s_maxcachettl;
54unsigned int SyncRes::s_maxqperq;
55unsigned int SyncRes::s_maxtotusec;
56unsigned int SyncRes::s_maxdepth;
57unsigned int SyncRes::s_minimumTTL;
58unsigned int SyncRes::s_packetcachettl;
59unsigned int SyncRes::s_packetcacheservfailttl;
60unsigned int SyncRes::s_serverdownmaxfails;
61unsigned int SyncRes::s_serverdownthrottletime;
62std::atomic<uint64_t> SyncRes::s_authzonequeries;
63std::atomic<uint64_t> SyncRes::s_queries;
64std::atomic<uint64_t> SyncRes::s_outgoingtimeouts;
65std::atomic<uint64_t> SyncRes::s_outgoing4timeouts;
66std::atomic<uint64_t> SyncRes::s_outgoing6timeouts;
67std::atomic<uint64_t> SyncRes::s_outqueries;
68std::atomic<uint64_t> SyncRes::s_tcpoutqueries;
69std::atomic<uint64_t> SyncRes::s_throttledqueries;
70std::atomic<uint64_t> SyncRes::s_dontqueries;
71std::atomic<uint64_t> SyncRes::s_nodelegated;
72std::atomic<uint64_t> SyncRes::s_unreachables;
73std::atomic<uint64_t> SyncRes::s_ecsqueries;
74std::atomic<uint64_t> SyncRes::s_ecsresponses;
75uint8_t SyncRes::s_ecsipv4limit;
76uint8_t SyncRes::s_ecsipv6limit;
77bool SyncRes::s_doIPv6;
78bool SyncRes::s_nopacketcache;
79bool SyncRes::s_rootNXTrust;
80bool SyncRes::s_noEDNS;
81
82#define LOG(x) if(d_lm == Log) { g_log <<Logger::Warning << x; } else if(d_lm == Store) { d_trace << x; }
83
84static void accountAuthLatency(int usec, int family)
85{
86 if(family == AF_INET) {
87 if(usec < 1000)
88 g_stats.auth4Answers0_1++;
89 else if(usec < 10000)
90 g_stats.auth4Answers1_10++;
91 else if(usec < 100000)
92 g_stats.auth4Answers10_100++;
93 else if(usec < 1000000)
94 g_stats.auth4Answers100_1000++;
95 else
96 g_stats.auth4AnswersSlow++;
97 } else {
98 if(usec < 1000)
99 g_stats.auth6Answers0_1++;
100 else if(usec < 10000)
101 g_stats.auth6Answers1_10++;
102 else if(usec < 100000)
103 g_stats.auth6Answers10_100++;
104 else if(usec < 1000000)
105 g_stats.auth6Answers100_1000++;
106 else
107 g_stats.auth6AnswersSlow++;
108 }
109
110}
111
112
113SyncRes::SyncRes(const struct timeval& now) : d_authzonequeries(0), d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
114 d_totUsec(0), d_now(now),
115 d_cacheonly(false), d_doDNSSEC(false), d_doEDNS0(false), d_lm(s_lm)
116
117{
118}
119
120/** everything begins here - this is the entry point just after receiving a packet */
121int SyncRes::beginResolve(const DNSName &qname, const QType &qtype, uint16_t qclass, vector<DNSRecord>&ret)
122{
123 vState state = Indeterminate;
124 s_queries++;
125 d_wasVariable=false;
126 d_wasOutOfBand=false;
127
128 if (doSpecialNamesResolve(qname, qtype, qclass, ret)) {
129 d_queryValidationState = Insecure; // this could fool our stats into thinking a validation took place
130 return 0; // so do check before updating counters (we do now)
131 }
132
133 auto qtypeCode = qtype.getCode();
134 /* rfc6895 section 3.1 */
135 if ((qtypeCode >= 128 && qtypeCode <= 254) || qtypeCode == QType::RRSIG || qtypeCode == QType::NSEC3 || qtypeCode == QType::OPT || qtypeCode == 65535) {
136 return -1;
137 }
138
139 if(qclass==QClass::ANY)
140 qclass=QClass::IN;
141 else if(qclass!=QClass::IN)
142 return -1;
143
144 set<GetBestNSAnswer> beenthere;
145 int res=doResolve(qname, qtype, ret, 0, beenthere, state);
146 d_queryValidationState = state;
147
148 if (shouldValidate()) {
149 if (d_queryValidationState != Indeterminate) {
150 g_stats.dnssecValidations++;
151 }
152 increaseDNSSECStateCounter(d_queryValidationState);
153 }
154
155 return res;
156}
157
158/*! Handles all special, built-in names
159 * Fills ret with an answer and returns true if it handled the query.
160 *
161 * Handles the following queries (and their ANY variants):
162 *
163 * - localhost. IN A
164 * - localhost. IN AAAA
165 * - 1.0.0.127.in-addr.arpa. IN PTR
166 * - 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. IN PTR
167 * - version.bind. CH TXT
168 * - version.pdns. CH TXT
169 * - id.server. CH TXT
170 */
171bool SyncRes::doSpecialNamesResolve(const DNSName &qname, const QType &qtype, const uint16_t qclass, vector<DNSRecord> &ret)
172{
173 static const DNSName arpa("1.0.0.127.in-addr.arpa."), ip6_arpa("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa."),
174 localhost("localhost."), versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns.");
175
176 bool handled = false;
177 vector<pair<QType::typeenum, string> > answers;
178
179 if ((qname == arpa || qname == ip6_arpa) &&
180 qclass == QClass::IN) {
181 handled = true;
182 if (qtype == QType::PTR || qtype == QType::ANY)
183 answers.push_back({QType::PTR, "localhost."});
184 }
185
186 if (qname == localhost &&
187 qclass == QClass::IN) {
188 handled = true;
189 if (qtype == QType::A || qtype == QType::ANY)
190 answers.push_back({QType::A, "127.0.0.1"});
191 if (qtype == QType::AAAA || qtype == QType::ANY)
192 answers.push_back({QType::AAAA, "::1"});
193 }
194
195 if ((qname == versionbind || qname == idserver || qname == versionpdns) &&
196 qclass == QClass::CHAOS) {
197 handled = true;
198 if (qtype == QType::TXT || qtype == QType::ANY) {
199 if(qname == versionbind || qname == versionpdns)
200 answers.push_back({QType::TXT, "\""+::arg()["version-string"]+"\""});
201 else if (s_serverID != "disabled")
202 answers.push_back({QType::TXT, "\""+s_serverID+"\""});
203 }
204 }
205
206 if (handled && !answers.empty()) {
207 ret.clear();
208 d_wasOutOfBand=true;
209
210 DNSRecord dr;
211 dr.d_name = qname;
212 dr.d_place = DNSResourceRecord::ANSWER;
213 dr.d_class = qclass;
214 dr.d_ttl = 86400;
215 for (const auto& ans : answers) {
216 dr.d_type = ans.first;
217 dr.d_content = DNSRecordContent::mastermake(ans.first, qclass, ans.second);
218 ret.push_back(dr);
219 }
220 }
221
222 return handled;
223}
224
225
226//! This is the 'out of band resolver', in other words, the authoritative server
227void SyncRes::AuthDomain::addSOA(std::vector<DNSRecord>& records) const
228{
229 SyncRes::AuthDomain::records_t::const_iterator ziter = d_records.find(boost::make_tuple(getName(), QType::SOA));
230 if (ziter != d_records.end()) {
231 DNSRecord dr = *ziter;
232 dr.d_place = DNSResourceRecord::AUTHORITY;
233 records.push_back(dr);
234 }
235 else {
236 // cerr<<qname<<": can't find SOA record '"<<getName()<<"' in our zone!"<<endl;
237 }
238}
239
240int SyncRes::AuthDomain::getRecords(const DNSName& qname, uint16_t qtype, std::vector<DNSRecord>& records) const
241{
242 int result = RCode::NoError;
243 records.clear();
244
245 // partial lookup
246 std::pair<records_t::const_iterator,records_t::const_iterator> range = d_records.equal_range(tie(qname));
247
248 SyncRes::AuthDomain::records_t::const_iterator ziter;
249 bool somedata = false;
250
251 for(ziter = range.first; ziter != range.second; ++ziter) {
252 somedata = true;
253
254 if(qtype == QType::ANY || ziter->d_type == qtype || ziter->d_type == QType::CNAME) {
255 // let rest of nameserver do the legwork on this one
256 records.push_back(*ziter);
257 }
258 else if (ziter->d_type == QType::NS && ziter->d_name.countLabels() > getName().countLabels()) {
259 // we hit a delegation point!
260 DNSRecord dr = *ziter;
261 dr.d_place=DNSResourceRecord::AUTHORITY;
262 records.push_back(dr);
263 }
264 }
265
266 if (!records.empty()) {
267 /* We have found an exact match, we're done */
268 // cerr<<qname<<": exact match in zone '"<<getName()<<"'"<<endl;
269 return result;
270 }
271
272 if (somedata) {
273 /* We have records for that name, but not of the wanted qtype */
274 // cerr<<qname<<": found record in '"<<getName()<<"', but nothing of the right type, sending SOA"<<endl;
275 addSOA(records);
276
277 return result;
278 }
279
280 // cerr<<qname<<": nothing found so far in '"<<getName()<<"', trying wildcards"<<endl;
281 DNSName wcarddomain(qname);
282 while(wcarddomain != getName() && wcarddomain.chopOff()) {
283 // cerr<<qname<<": trying '*."<<wcarddomain<<"' in "<<getName()<<endl;
284 range = d_records.equal_range(boost::make_tuple(g_wildcarddnsname + wcarddomain));
285 if (range.first==range.second)
286 continue;
287
288 for(ziter = range.first; ziter != range.second; ++ziter) {
289 DNSRecord dr = *ziter;
290 // if we hit a CNAME, just answer that - rest of recursor will do the needful & follow
291 if(dr.d_type == qtype || qtype == QType::ANY || dr.d_type == QType::CNAME) {
292 dr.d_name = qname;
293 dr.d_place = DNSResourceRecord::ANSWER;
294 records.push_back(dr);
295 }
296 }
297
298 if (records.empty()) {
299 addSOA(records);
300 }
301
302 // cerr<<qname<<": in '"<<getName()<<"', had wildcard match on '*."<<wcarddomain<<"'"<<endl;
303 return result;
304 }
305
306 /* Nothing for this name, no wildcard, let's see if there is some NS */
307 DNSName nsdomain(qname);
308 while (nsdomain.chopOff() && nsdomain != getName()) {
309 range = d_records.equal_range(boost::make_tuple(nsdomain,QType::NS));
310 if(range.first == range.second)
311 continue;
312
313 for(ziter = range.first; ziter != range.second; ++ziter) {
314 DNSRecord dr = *ziter;
315 dr.d_place = DNSResourceRecord::AUTHORITY;
316 records.push_back(dr);
317 }
318 }
319
320 if(records.empty()) {
321 // cerr<<qname<<": no NS match in zone '"<<getName()<<"' either, handing out SOA"<<endl;
322 addSOA(records);
323 result = RCode::NXDomain;
324 }
325
326 return result;
327}
328
329bool SyncRes::doOOBResolve(const AuthDomain& domain, const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, int& res)
330{
331 d_authzonequeries++;
332 s_authzonequeries++;
333
334 res = domain.getRecords(qname, qtype.getCode(), ret);
335 return true;
336}
337
338bool SyncRes::doOOBResolve(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int& res)
339{
340 string prefix;
341 if(doLog()) {
342 prefix=d_prefix;
343 prefix.append(depth, ' ');
344 }
345
346 DNSName authdomain(qname);
347 domainmap_t::const_iterator iter=getBestAuthZone(&authdomain);
348 if(iter==t_sstorage.domainmap->end() || !iter->second.isAuth()) {
349 LOG(prefix<<qname<<": auth storage has no zone for this query!"<<endl);
350 return false;
351 }
352
353 LOG(prefix<<qname<<": auth storage has data, zone='"<<authdomain<<"'"<<endl);
354 return doOOBResolve(iter->second, qname, qtype, ret, res);
355}
356
357uint64_t SyncRes::doEDNSDump(int fd)
358{
359 auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fdopen(dup(fd), "w"), fclose);
360 if (!fp) {
361 return 0;
362 }
363 uint64_t count = 0;
364
365 fprintf(fp.get(),"; edns from thread follows\n;\n");
366 for(const auto& eds : t_sstorage.ednsstatus) {
367 count++;
368 fprintf(fp.get(), "%s\t%d\t%s", eds.first.toString().c_str(), (int)eds.second.mode, ctime(&eds.second.modeSetAt));
369 }
370 return count;
371}
372
373uint64_t SyncRes::doDumpNSSpeeds(int fd)
374{
375 auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fdopen(dup(fd), "w"), fclose);
376 if(!fp)
377 return 0;
378 fprintf(fp.get(), "; nsspeed dump from thread follows\n;\n");
379 uint64_t count=0;
380
381 for(const auto& i : t_sstorage.nsSpeeds)
382 {
383 count++;
384
385 // an <empty> can appear hear in case of authoritative (hosted) zones
386 fprintf(fp.get(), "%s -> ", i.first.toLogString().c_str());
387 for(const auto& j : i.second.d_collection)
388 {
389 // typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
390 fprintf(fp.get(), "%s/%f ", j.first.toString().c_str(), j.second.peek());
391 }
392 fprintf(fp.get(), "\n");
393 }
394 return count;
395}
396
397uint64_t SyncRes::doDumpThrottleMap(int fd)
398{
399 auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fdopen(dup(fd), "w"), fclose);
400 if(!fp)
401 return 0;
402 fprintf(fp.get(), "; throttle map dump follows\n");
403 fprintf(fp.get(), "; remote IP\tqname\tqtype\tcount\tttd\n");
404 uint64_t count=0;
405
406 const auto& throttleMap = t_sstorage.throttle.getThrottleMap();
407 for(const auto& i : throttleMap)
408 {
409 count++;
410 // remote IP, dns name, qtype, count, ttd
411 fprintf(fp.get(), "%s\t%s\t%d\t%u\t%s", i.first.get<0>().toString().c_str(), i.first.get<1>().toLogString().c_str(), i.first.get<2>(), i.second.count, ctime(&i.second.ttd));
412 }
413
414 return count;
415}
416
417/* so here is the story. First we complete the full resolution process for a domain name. And only THEN do we decide
418 to also do DNSSEC validation, which leads to new queries. To make this simple, we *always* ask for DNSSEC records
419 so that if there are RRSIGs for a name, we'll have them.
420
421 However, some hosts simply can't answer questions which ask for DNSSEC. This can manifest itself as:
422 * No answer
423 * FormErr
424 * Nonsense answer
425
426 The cause of "No answer" may be fragmentation, and it is tempting to probe if smaller answers would get through.
427 Another cause of "No answer" may simply be a network condition.
428 Nonsense answers are a clearer indication this host won't be able to do DNSSEC evah.
429
430 Previous implementations have suffered from turning off DNSSEC questions for an authoritative server based on timeouts.
431 A clever idea is to only turn off DNSSEC if we know a domain isn't signed anyhow. The problem with that really
432 clever idea however is that at this point in PowerDNS, we may simply not know that yet. All the DNSSEC thinking happens
433 elsewhere. It may not have happened yet.
434
435 For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish.
436*/
437
438int SyncRes::asyncresolveWrapper(const ComboAddress& ip, bool ednsMANDATORY, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, struct timeval* now, boost::optional<Netmask>& srcmask, LWResult* res, bool* chained) const
439{
440 /* what is your QUEST?
441 the goal is to get as many remotes as possible on the highest level of EDNS support
442 The levels are:
443
444 0) UNKNOWN Unknown state
445 1) EDNS: Honors EDNS0
446 2) EDNSIGNORANT: Ignores EDNS0, gives replies without EDNS0
447 3) NOEDNS: Generates FORMERR on EDNS queries
448
449 Everybody starts out assumed to be '0'.
450 If '0', send out EDNS0
451 If you FORMERR us, go to '3',
452 If no EDNS in response, go to '2'
453 If '1', send out EDNS0
454 If FORMERR, downgrade to 3
455 If '2', keep on including EDNS0, see what happens
456 Same behaviour as 0
457 If '3', send bare queries
458 */
459
460 SyncRes::EDNSStatus* ednsstatus;
461 ednsstatus = &t_sstorage.ednsstatus[ip]; // does this include port? YES
462
463 if(ednsstatus->modeSetAt && ednsstatus->modeSetAt + 3600 < d_now.tv_sec) {
464 *ednsstatus=SyncRes::EDNSStatus();
465 // cerr<<"Resetting EDNS Status for "<<ip.toString()<<endl);
466 }
467
468 SyncRes::EDNSStatus::EDNSMode& mode=ednsstatus->mode;
469 SyncRes::EDNSStatus::EDNSMode oldmode = mode;
470 int EDNSLevel = 0;
471 auto luaconfsLocal = g_luaconfs.getLocal();
472 ResolveContext ctx;
473#ifdef HAVE_PROTOBUF
474 ctx.d_initialRequestId = d_initialRequestId;
475#endif
476
477 int ret;
478 for(int tries = 0; tries < 3; ++tries) {
479 // cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl;
480
481 if(mode==EDNSStatus::NOEDNS) {
482 g_stats.noEdnsOutQueries++;
483 EDNSLevel = 0; // level != mode
484 }
485 else if(ednsMANDATORY || mode==EDNSStatus::UNKNOWN || mode==EDNSStatus::EDNSOK || mode==EDNSStatus::EDNSIGNORANT)
486 EDNSLevel = 1;
487
488 DNSName sendQname(domain);
489 if (g_lowercaseOutgoing)
490 sendQname.makeUsLowerCase();
491
492 if (d_asyncResolve) {
493 ret = d_asyncResolve(ip, sendQname, type, doTCP, sendRDQuery, EDNSLevel, now, srcmask, ctx, res, chained);
494 }
495 else {
496 ret=asyncresolve(ip, sendQname, type, doTCP, sendRDQuery, EDNSLevel, now, srcmask, ctx, d_outgoingProtobufServers, luaconfsLocal->outgoingProtobufExportConfig.exportTypes, res, chained);
497 }
498 if(ret < 0) {
499 return ret; // transport error, nothing to learn here
500 }
501
502 if(ret == 0) { // timeout, not doing anything with it now
503 return ret;
504 }
505 else if(mode==EDNSStatus::UNKNOWN || mode==EDNSStatus::EDNSOK || mode == EDNSStatus::EDNSIGNORANT ) {
506 if(res->d_validpacket && !res->d_haveEDNS && res->d_rcode == RCode::FormErr) {
507 // cerr<<"Downgrading to NOEDNS because of "<<RCode::to_s(res->d_rcode)<<" for query to "<<ip.toString()<<" for '"<<domain<<"'"<<endl;
508 mode = EDNSStatus::NOEDNS;
509 continue;
510 }
511 else if(!res->d_haveEDNS) {
512 if(mode != EDNSStatus::EDNSIGNORANT) {
513 mode = EDNSStatus::EDNSIGNORANT;
514 // cerr<<"We find that "<<ip.toString()<<" is an EDNS-ignorer for '"<<domain<<"', moving to mode 2"<<endl;
515 }
516 }
517 else {
518 mode = EDNSStatus::EDNSOK;
519 // cerr<<"We find that "<<ip.toString()<<" is EDNS OK!"<<endl;
520 }
521
522 }
523 if(oldmode != mode || !ednsstatus->modeSetAt)
524 ednsstatus->modeSetAt=d_now.tv_sec;
525 // cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", new mode: "<<mode<<endl;
526 return ret;
527 }
528 return ret;
529}
530
531/*! This function will check the cache and go out to the internet if the answer is not in cache
532 *
533 * \param qname The name we need an answer for
534 * \param qtype
535 * \param ret The vector of DNSRecords we need to fill with the answers
536 * \param depth The recursion depth we are in
537 * \param beenthere
538 * \return DNS RCODE or -1 (Error) or -2 (RPZ hit)
539 */
540int SyncRes::doResolve(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, set<GetBestNSAnswer>& beenthere, vState& state)
541{
542 string prefix;
543 if(doLog()) {
544 prefix=d_prefix;
545 prefix.append(depth, ' ');
546 }
547
548 LOG(prefix<<qname<<": Wants "<< (d_doDNSSEC ? "" : "NO ") << "DNSSEC processing, "<<(d_requireAuthData ? "" : "NO ")<<"auth data in query for "<<qtype.getName()<<endl);
549
550 state = Indeterminate;
551
552 if(s_maxdepth && depth > s_maxdepth)
553 throw ImmediateServFailException("More than "+std::to_string(s_maxdepth)+" (max-recursion-depth) levels of recursion needed while resolving "+qname.toLogString());
554
555 int res=0;
556
557 // This is a difficult way of expressing "this is a normal query", i.e. not getRootNS.
558 if(!(d_updatingRootNS && qtype.getCode()==QType::NS && qname.isRoot())) {
559 if(d_cacheonly) { // very limited OOB support
560 LWResult lwr;
561 LOG(prefix<<qname<<": Recursion not requested for '"<<qname<<"|"<<qtype.getName()<<"', peeking at auth/forward zones"<<endl);
562 DNSName authname(qname);
563 domainmap_t::const_iterator iter=getBestAuthZone(&authname);
564 if(iter != t_sstorage.domainmap->end()) {
565 if(iter->second.isAuth()) {
566 ret.clear();
567 d_wasOutOfBand = doOOBResolve(qname, qtype, ret, depth, res);
568 return res;
569 }
570 else {
571 const vector<ComboAddress>& servers = iter->second.d_servers;
572 const ComboAddress remoteIP = servers.front();
573 LOG(prefix<<qname<<": forwarding query to hardcoded nameserver '"<< remoteIP.toStringWithPort()<<"' for zone '"<<authname<<"'"<<endl);
574
575 boost::optional<Netmask> nm;
576 bool chained = false;
577 res=asyncresolveWrapper(remoteIP, d_doDNSSEC, qname, qtype.getCode(), false, false, &d_now, nm, &lwr, &chained);
578
579 d_totUsec += lwr.d_usec;
580 accountAuthLatency(lwr.d_usec, remoteIP.sin4.sin_family);
581
582 // filter out the good stuff from lwr.result()
583 if (res == 1) {
584 for(const auto& rec : lwr.d_records) {
585 if(rec.d_place == DNSResourceRecord::ANSWER)
586 ret.push_back(rec);
587 }
588 return 0;
589 }
590 else {
591 return RCode::ServFail;
592 }
593 }
594 }
595 }
596
597 DNSName authname(qname);
598 bool wasForwardedOrAuthZone = false;
599 bool wasAuthZone = false;
600 bool wasForwardRecurse = false;
601 domainmap_t::const_iterator iter = getBestAuthZone(&authname);
602 if(iter != t_sstorage.domainmap->end()) {
603 const auto& domain = iter->second;
604 wasForwardedOrAuthZone = true;
605
606 if (domain.isAuth()) {
607 wasAuthZone = true;
608 } else if (domain.shouldRecurse()) {
609 wasForwardRecurse = true;
610 }
611 }
612
613 if(!d_skipCNAMECheck && doCNAMECacheCheck(qname, qtype, ret, depth, res, state, wasAuthZone, wasForwardRecurse)) { // will reroute us if needed
614 d_wasOutOfBand = wasAuthZone;
615 return res;
616 }
617
618 if(doCacheCheck(qname, authname, wasForwardedOrAuthZone, wasAuthZone, wasForwardRecurse, qtype, ret, depth, res, state)) {
619 // we done
620 d_wasOutOfBand = wasAuthZone;
621 return res;
622 }
623 }
624
625 if(d_cacheonly)
626 return 0;
627
628 LOG(prefix<<qname<<": No cache hit for '"<<qname<<"|"<<qtype.getName()<<"', trying to find an appropriate NS record"<<endl);
629
630 DNSName subdomain(qname);
631 if(qtype == QType::DS) subdomain.chopOff();
632
633 NsSet nsset;
634 bool flawedNSSet=false;
635
636 /* we use subdomain here instead of qname because for DS queries we only care about the state of the parent zone */
637 computeZoneCuts(subdomain, g_rootdnsname, depth);
638
639 // the two retries allow getBestNSNamesFromCache&co to reprime the root
640 // hints, in case they ever go missing
641 for(int tries=0;tries<2 && nsset.empty();++tries) {
642 subdomain=getBestNSNamesFromCache(subdomain, qtype, nsset, &flawedNSSet, depth, beenthere); // pass beenthere to both occasions
643 }
644
645 state = getValidationStatus(qname, false);
646
647 LOG(prefix<<qname<<": initial validation status for "<<qname<<" is "<<vStates[state]<<endl);
648
649 if(!(res=doResolveAt(nsset, subdomain, flawedNSSet, qname, qtype, ret, depth, beenthere, state)))
650 return 0;
651
652 LOG(prefix<<qname<<": failed (res="<<res<<")"<<endl);
653
654 if (res == -2)
655 return res;
656
657 return res<0 ? RCode::ServFail : res;
658}
659
660#if 0
661// for testing purposes
662static bool ipv6First(const ComboAddress& a, const ComboAddress& b)
663{
664 return !(a.sin4.sin_family < a.sin4.sin_family);
665}
666#endif
667
668struct speedOrderCA
669{
670 speedOrderCA(std::map<ComboAddress,double>& speeds): d_speeds(speeds) {}
671 bool operator()(const ComboAddress& a, const ComboAddress& b) const
672 {
673 return d_speeds[a] < d_speeds[b];
674 }
675 std::map<ComboAddress, double>& d_speeds;
676};
677
678/** This function explicitly goes out for A or AAAA addresses
679*/
680vector<ComboAddress> SyncRes::getAddrs(const DNSName &qname, unsigned int depth, set<GetBestNSAnswer>& beenthere, bool cacheOnly)
681{
682 typedef vector<DNSRecord> res_t;
683 typedef vector<ComboAddress> ret_t;
684 ret_t ret;
685
686 bool oldCacheOnly = d_cacheonly;
687 bool oldRequireAuthData = d_requireAuthData;
688 bool oldValidationRequested = d_DNSSECValidationRequested;
689 d_requireAuthData = false;
690 d_DNSSECValidationRequested = false;
691 d_cacheonly = cacheOnly;
692
693 vState newState = Indeterminate;
694 res_t resv4;
695 // If IPv4 ever becomes second class, we should revisit this
696 if (doResolve(qname, QType::A, resv4, depth+1, beenthere, newState) == 0) { // this consults cache, OR goes out
697 for (auto i = resv4.cbegin(); i != resv4.end(); ++i) {
698 if (i->d_type == QType::A) {
699 if (auto rec = getRR<ARecordContent>(*i)) {
700 ret.push_back(rec->getCA(53));
701 }
702 }
703 }
704 }
705 if (s_doIPv6) {
706 if (ret.empty()) {
707 // We did not find IPv4 addresses, try to get IPv6 ones
708 newState = Indeterminate;
709 res_t resv6;
710 if (doResolve(qname, QType::AAAA, resv6, depth+1, beenthere, newState) == 0) { // this consults cache, OR goes out
711 for (auto i = resv6.cbegin(); i != resv6.end(); ++i) {
712 if (i->d_type == QType::AAAA) {
713 if (auto rec = getRR<AAAARecordContent>(*i))
714 ret.push_back(rec->getCA(53));
715 }
716 }
717 }
718 } else {
719 // We have some IPv4 records, don't bother with going out to get IPv6, but do consult the cache
720 // Once IPv6 adoption matters, this needs to be revisited
721 res_t cset;
722 if (t_RC->get(d_now.tv_sec, qname, QType(QType::AAAA), false, &cset, d_cacheRemote) > 0) {
723 for (auto k = cset.cbegin(); k != cset.cend(); ++k) {
724 if (k->d_ttl > (unsigned int)d_now.tv_sec ) {
725 if (auto rec = getRR<AAAARecordContent>(*k)) {
726 ret.push_back(rec->getCA(53));
727 }
728 }
729 }
730 }
731 }
732 }
733
734 d_requireAuthData = oldRequireAuthData;
735 d_DNSSECValidationRequested = oldValidationRequested;
736 d_cacheonly = oldCacheOnly;
737
738 /* we need to remove from the nsSpeeds collection the existing IPs
739 for this nameserver that are no longer in the set, even if there
740 is only one or none at all in the current set.
741 */
742 map<ComboAddress, double> speeds;
743 auto& collection = t_sstorage.nsSpeeds[qname].d_collection;
744 for(const auto& val: ret) {
745 speeds[val] = collection[val].get(&d_now);
746 }
747
748 t_sstorage.nsSpeeds[qname].purge(speeds);
749
750 if(ret.size() > 1) {
751 random_shuffle(ret.begin(), ret.end(), dns_random);
752 speedOrderCA so(speeds);
753 stable_sort(ret.begin(), ret.end(), so);
754
755 if(doLog()) {
756 string prefix=d_prefix;
757 prefix.append(depth, ' ');
758 LOG(prefix<<"Nameserver "<<qname<<" IPs: ");
759 bool first = true;
760 for(const auto& addr : ret) {
761 if (first) {
762 first = false;
763 }
764 else {
765 LOG(", ");
766 }
767 LOG((addr.toString())<<"(" << (boost::format("%0.2f") % (speeds[addr]/1000.0)).str() <<"ms)");
768 }
769 LOG(endl);
770 }
771 }
772
773 return ret;
774}
775
776void SyncRes::getBestNSFromCache(const DNSName &qname, const QType& qtype, vector<DNSRecord>& bestns, bool* flawedNSSet, unsigned int depth, set<GetBestNSAnswer>& beenthere)
777{
778 string prefix;
779 DNSName subdomain(qname);
780 if(doLog()) {
781 prefix=d_prefix;
782 prefix.append(depth, ' ');
783 }
784 bestns.clear();
785 bool brokeloop;
786 do {
787 brokeloop=false;
788 LOG(prefix<<qname<<": Checking if we have NS in cache for '"<<subdomain<<"'"<<endl);
789 vector<DNSRecord> ns;
790 *flawedNSSet = false;
791
792 if(t_RC->get(d_now.tv_sec, subdomain, QType(QType::NS), false, &ns, d_cacheRemote) > 0) {
793 for(auto k=ns.cbegin();k!=ns.cend(); ++k) {
794 if(k->d_ttl > (unsigned int)d_now.tv_sec ) {
795 vector<DNSRecord> aset;
796
797 const DNSRecord& dr=*k;
798 auto nrr = getRR<NSRecordContent>(dr);
799 if(nrr && (!nrr->getNS().isPartOf(subdomain) || t_RC->get(d_now.tv_sec, nrr->getNS(), s_doIPv6 ? QType(QType::ADDR) : QType(QType::A),
800 false, doLog() ? &aset : 0, d_cacheRemote) > 5)) {
801 bestns.push_back(dr);
802 LOG(prefix<<qname<<": NS (with ip, or non-glue) in cache for '"<<subdomain<<"' -> '"<<nrr->getNS()<<"'"<<endl);
803 LOG(prefix<<qname<<": within bailiwick: "<< nrr->getNS().isPartOf(subdomain));
804 if(!aset.empty()) {
805 LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset.begin()->d_ttl- d_now.tv_sec ))<<endl);
806 }
807 else {
808 LOG(", not in cache / did not look at cache"<<endl);
809 }
810 }
811 else {
812 *flawedNSSet=true;
813 LOG(prefix<<qname<<": NS in cache for '"<<subdomain<<"', but needs glue ("<<nrr->getNS()<<") which we miss or is expired"<<endl);
814 }
815 }
816 }
817
818 if(!bestns.empty()) {
819 GetBestNSAnswer answer;
820 answer.qname=qname;
821 answer.qtype=qtype.getCode();
822 for(const auto& dr : bestns) {
823 if (auto nsContent = getRR<NSRecordContent>(dr)) {
824 answer.bestns.insert(make_pair(dr.d_name, nsContent->getNS()));
825 }
826 }
827
828 if(beenthere.count(answer)) {
829 brokeloop=true;
830 LOG(prefix<<qname<<": We have NS in cache for '"<<subdomain<<"' but part of LOOP (already seen "<<answer.qname<<")! Trying less specific NS"<<endl);
831 ;
832 if(doLog())
833 for( set<GetBestNSAnswer>::const_iterator j=beenthere.begin();j!=beenthere.end();++j) {
834 bool neo = !(*j< answer || answer<*j);
835 LOG(prefix<<qname<<": beenthere"<<(neo?"*":"")<<": "<<j->qname<<"|"<<DNSRecordContent::NumberToType(j->qtype)<<" ("<<(unsigned int)j->bestns.size()<<")"<<endl);
836 }
837 bestns.clear();
838 }
839 else {
840 beenthere.insert(answer);
841 LOG(prefix<<qname<<": We have NS in cache for '"<<subdomain<<"' (flawedNSSet="<<*flawedNSSet<<")"<<endl);
842 return;
843 }
844 }
845 }
846 LOG(prefix<<qname<<": no valid/useful NS in cache for '"<<subdomain<<"'"<<endl);
847
848 if(subdomain.isRoot() && !brokeloop) {
849 // We lost the root NS records
850 primeHints();
851 LOG(prefix<<qname<<": reprimed the root"<<endl);
852 /* let's prevent an infinite loop */
853 if (!d_updatingRootNS) {
854 getRootNS(d_now, d_asyncResolve);
855 }
856 }
857 } while(subdomain.chopOff());
858}
859
860SyncRes::domainmap_t::const_iterator SyncRes::getBestAuthZone(DNSName* qname) const
861{
862 SyncRes::domainmap_t::const_iterator ret;
863 do {
864 ret=t_sstorage.domainmap->find(*qname);
865 if(ret!=t_sstorage.domainmap->end())
866 break;
867 }while(qname->chopOff());
868 return ret;
869}
870
871/** doesn't actually do the work, leaves that to getBestNSFromCache */
872DNSName SyncRes::getBestNSNamesFromCache(const DNSName &qname, const QType& qtype, NsSet& nsset, bool* flawedNSSet, unsigned int depth, set<GetBestNSAnswer>&beenthere)
873{
874 DNSName subdomain(qname);
875 DNSName authdomain(qname);
876
877 domainmap_t::const_iterator iter=getBestAuthZone(&authdomain);
878 if(iter!=t_sstorage.domainmap->end()) {
879 if( iter->second.isAuth() )
880 // this gets picked up in doResolveAt, the empty DNSName, combined with the
881 // empty vector means 'we are auth for this zone'
882 nsset.insert({DNSName(), {{}, false}});
883 else {
884 // Again, picked up in doResolveAt. An empty DNSName, combined with a
885 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
886 // This is actually picked up in retrieveAddressesForNS called from doResolveAt.
887 nsset.insert({DNSName(), {iter->second.d_servers, iter->second.shouldRecurse() }});
888 }
889 return authdomain;
890 }
891
892 vector<DNSRecord> bestns;
893 getBestNSFromCache(subdomain, qtype, bestns, flawedNSSet, depth, beenthere);
894
895 for(auto k=bestns.cbegin() ; k != bestns.cend(); ++k) {
896 // The actual resolver code will not even look at the ComboAddress or bool
897 const auto nsContent = getRR<NSRecordContent>(*k);
898 if (nsContent) {
899 nsset.insert({nsContent->getNS(), {{}, false}});
900 if(k==bestns.cbegin())
901 subdomain=k->d_name;
902 }
903 }
904 return subdomain;
905}
906
907void SyncRes::updateValidationStatusInCache(const DNSName &qname, const QType& qt, bool aa, vState newState) const
908{
909 if (newState == Bogus) {
910 t_RC->updateValidationStatus(d_now.tv_sec, qname, qt, d_cacheRemote, aa, newState, s_maxbogusttl + d_now.tv_sec);
911 }
912 else {
913 t_RC->updateValidationStatus(d_now.tv_sec, qname, qt, d_cacheRemote, aa, newState, boost::none);
914 }
915}
916
917bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>& ret, unsigned int depth, int &res, vState& state, bool wasAuthZone, bool wasForwardRecurse)
918{
919 string prefix;
920 if(doLog()) {
921 prefix=d_prefix;
922 prefix.append(depth, ' ');
923 }
924
925 if((depth>9 && d_outqueries>10 && d_throttledqueries>5) || depth > 15) {
926 LOG(prefix<<qname<<": recursing (CNAME or other indirection) too deep, depth="<<depth<<endl);
927 res=RCode::ServFail;
928 return true;
929 }
930
931 LOG(prefix<<qname<<": Looking for CNAME cache hit of '"<<qname<<"|CNAME"<<"'"<<endl);
932 vector<DNSRecord> cset;
933 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
934 vector<std::shared_ptr<DNSRecord>> authorityRecs;
935 bool wasAuth;
936 uint32_t capTTL = std::numeric_limits<uint32_t>::max();
937 /* we don't require auth data for forward-recurse lookups */
938 if(t_RC->get(d_now.tv_sec, qname, QType(QType::CNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth) > 0) {
939
940 for(auto j=cset.cbegin() ; j != cset.cend() ; ++j) {
941 if (j->d_class != QClass::IN) {
942 continue;
943 }
944
945 if(j->d_ttl>(unsigned int) d_now.tv_sec) {
946
947 if (!wasAuthZone && shouldValidate() && (wasAuth || wasForwardRecurse) && state == Indeterminate && d_requireAuthData) {
948 /* This means we couldn't figure out the state when this entry was cached,
949 most likely because we hadn't computed the zone cuts yet. */
950 /* make sure they are computed before validating */
951 DNSName subdomain(qname);
952 /* if we are retrieving a DS, we only care about the state of the parent zone */
953 if(qtype == QType::DS)
954 subdomain.chopOff();
955
956 computeZoneCuts(subdomain, g_rootdnsname, depth);
957
958 vState recordState = getValidationStatus(qname, false);
959 if (recordState == Secure) {
960 LOG(prefix<<qname<<": got Indeterminate state from the CNAME cache, validating.."<<endl);
961 state = SyncRes::validateRecordsWithSigs(depth, qname, QType(QType::CNAME), qname, cset, signatures);
962 if (state != Indeterminate) {
963 LOG(prefix<<qname<<": got Indeterminate state from the CNAME cache, new validation result is "<<vStates[state]<<endl);
964 if (state == Bogus) {
965 capTTL = s_maxbogusttl;
966 }
967 updateValidationStatusInCache(qname, QType(QType::CNAME), wasAuth, state);
968 }
969 }
970 }
971
972 LOG(prefix<<qname<<": Found cache CNAME hit for '"<< qname << "|CNAME" <<"' to '"<<j->d_content->getZoneRepresentation()<<"', validation state is "<<vStates[state]<<endl);
973
974 DNSRecord dr=*j;
975 dr.d_ttl -= d_now.tv_sec;
976 dr.d_ttl = std::min(dr.d_ttl, capTTL);
977 const uint32_t ttl = dr.d_ttl;
978 ret.reserve(ret.size() + 1 + signatures.size() + authorityRecs.size());
979 ret.push_back(dr);
980
981 for(const auto& signature : signatures) {
982 DNSRecord sigdr;
983 sigdr.d_type=QType::RRSIG;
984 sigdr.d_name=qname;
985 sigdr.d_ttl=ttl;
986 sigdr.d_content=signature;
987 sigdr.d_place=DNSResourceRecord::ANSWER;
988 sigdr.d_class=QClass::IN;
989 ret.push_back(sigdr);
990 }
991
992 for(const auto& rec : authorityRecs) {
993 DNSRecord authDR(*rec);
994 authDR.d_ttl=ttl;
995 ret.push_back(authDR);
996 }
997
998 if(qtype != QType::CNAME) { // perhaps they really wanted a CNAME!
999 set<GetBestNSAnswer>beenthere;
1000
1001 vState cnameState = Indeterminate;
1002 const auto cnameContent = getRR<CNAMERecordContent>(*j);
1003 if (cnameContent) {
1004 res=doResolve(cnameContent->getTarget(), qtype, ret, depth+1, beenthere, cnameState);
1005 LOG(prefix<<qname<<": updating validation state for response to "<<qname<<" from "<<vStates[state]<<" with the state from the CNAME quest: "<<vStates[cnameState]<<endl);
1006 updateValidationState(state, cnameState);
1007 }
1008 }
1009 else
1010 res=0;
1011
1012 return true;
1013 }
1014 }
1015 }
1016 LOG(prefix<<qname<<": No CNAME cache hit of '"<< qname << "|CNAME" <<"' found"<<endl);
1017 return false;
1018}
1019
1020namespace {
1021struct CacheEntry
1022{
1023 vector<DNSRecord> records;
1024 vector<shared_ptr<RRSIGRecordContent>> signatures;
1025 uint32_t signaturesTTL{std::numeric_limits<uint32_t>::max()};
1026};
1027struct CacheKey
1028{
1029 DNSName name;
1030 uint16_t type;
1031 DNSResourceRecord::Place place;
1032 bool operator<(const CacheKey& rhs) const {
1033 return tie(name, type, place) < tie(rhs.name, rhs.type, rhs.place);
1034 }
1035};
1036typedef map<CacheKey, CacheEntry> tcache_t;
1037}
1038
1039static void reapRecordsFromNegCacheEntryForValidation(tcache_t& tcache, const vector<DNSRecord>& records)
1040{
1041 for (const auto& rec : records) {
1042 if (rec.d_type == QType::RRSIG) {
1043 auto rrsig = getRR<RRSIGRecordContent>(rec);
1044 if (rrsig) {
1045 tcache[{rec.d_name, rrsig->d_type, rec.d_place}].signatures.push_back(rrsig);
1046 }
1047 } else {
1048 tcache[{rec.d_name,rec.d_type,rec.d_place}].records.push_back(rec);
1049 }
1050 }
1051}
1052
1053/*!
1054 * Convience function to push the records from records into ret with a new TTL
1055 *
1056 * \param records DNSRecords that need to go into ret
1057 * \param ttl The new TTL for these records
1058 * \param ret The vector of DNSRecords that should contian the records with the modified TTL
1059 */
1060static void addTTLModifiedRecords(const vector<DNSRecord>& records, const uint32_t ttl, vector<DNSRecord>& ret) {
1061 for (const auto& rec : records) {
1062 DNSRecord r(rec);
1063 r.d_ttl = ttl;
1064 ret.push_back(r);
1065 }
1066}
1067
1068void SyncRes::computeNegCacheValidationStatus(const NegCache::NegCacheEntry* ne, const DNSName& qname, const QType& qtype, const int res, vState& state, unsigned int depth)
1069{
1070 DNSName subdomain(qname);
1071 /* if we are retrieving a DS, we only care about the state of the parent zone */
1072 if(qtype == QType::DS)
1073 subdomain.chopOff();
1074
1075 computeZoneCuts(subdomain, g_rootdnsname, depth);
1076
1077 tcache_t tcache;
1078 reapRecordsFromNegCacheEntryForValidation(tcache, ne->authoritySOA.records);
1079 reapRecordsFromNegCacheEntryForValidation(tcache, ne->authoritySOA.signatures);
1080 reapRecordsFromNegCacheEntryForValidation(tcache, ne->DNSSECRecords.records);
1081 reapRecordsFromNegCacheEntryForValidation(tcache, ne->DNSSECRecords.signatures);
1082
1083 for (const auto& entry : tcache) {
1084 // this happens when we did store signatures, but passed on the records themselves
1085 if (entry.second.records.empty()) {
1086 continue;
1087 }
1088
1089 const DNSName& owner = entry.first.name;
1090
1091 vState recordState = getValidationStatus(owner, false);
1092 if (state == Indeterminate) {
1093 state = recordState;
1094 }
1095
1096 if (recordState == Secure) {
1097 recordState = SyncRes::validateRecordsWithSigs(depth, qname, qtype, owner, entry.second.records, entry.second.signatures);
1098 }
1099
1100 if (recordState != Indeterminate && recordState != state) {
1101 updateValidationState(state, recordState);
1102 if (state != Secure) {
1103 break;
1104 }
1105 }
1106 }
1107
1108 if (state == Secure) {
1109 vState neValidationState = ne->d_validationState;
1110 dState expectedState = res == RCode::NXDomain ? NXDOMAIN : NXQTYPE;
1111 dState denialState = getDenialValidationState(*ne, state, expectedState, false);
1112 updateDenialValidationState(neValidationState, ne->d_name, state, denialState, expectedState, qtype == QType::DS);
1113 }
1114 if (state != Indeterminate) {
1115 /* validation succeeded, let's update the cache entry so we don't have to validate again */
1116 boost::optional<uint32_t> capTTD = boost::none;
1117 if (state == Bogus) {
1118 capTTD = d_now.tv_sec + s_maxbogusttl;
1119 }
1120 t_sstorage.negcache.updateValidationStatus(ne->d_name, ne->d_qtype, state, capTTD);
1121 }
1122}
1123
1124bool SyncRes::doCacheCheck(const DNSName &qname, const DNSName& authname, bool wasForwardedOrAuthZone, bool wasAuthZone, bool wasForwardRecurse, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res, vState& state)
1125{
1126 bool giveNegative=false;
1127
1128 string prefix;
1129 if(doLog()) {
1130 prefix=d_prefix;
1131 prefix.append(depth, ' ');
1132 }
1133
1134 // sqname and sqtype are used contain 'higher' names if we have them (e.g. powerdns.com|SOA when we find a negative entry for doesnotexists.powerdns.com|A)
1135 DNSName sqname(qname);
1136 QType sqt(qtype);
1137 uint32_t sttl=0;
1138 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
1139 vState cachedState;
1140 const NegCache::NegCacheEntry* ne = nullptr;
1141
1142 if(s_rootNXTrust &&
1143 t_sstorage.negcache.getRootNXTrust(qname, d_now, &ne) &&
1144 ne->d_auth.isRoot() &&
1145 !(wasForwardedOrAuthZone && !authname.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
1146 sttl = ne->d_ttd - d_now.tv_sec;
1147 LOG(prefix<<qname<<": Entire name '"<<qname<<"', is negatively cached via '"<<ne->d_auth<<"' & '"<<ne->d_name<<"' for another "<<sttl<<" seconds"<<endl);
1148 res = RCode::NXDomain;
1149 giveNegative = true;
1150 cachedState = ne->d_validationState;
1151 }
1152 else if (t_sstorage.negcache.get(qname, qtype, d_now, &ne)) {
1153 /* If we are looking for a DS, discard NXD if auth == qname
1154 and ask for a specific denial instead */
1155 if (qtype != QType::DS || ne->d_qtype.getCode() || ne->d_auth != qname ||
1156 t_sstorage.negcache.get(qname, qtype, d_now, &ne, true))
1157 {
1158 res = 0;
1159 sttl = ne->d_ttd - d_now.tv_sec;
1160 giveNegative = true;
1161 cachedState = ne->d_validationState;
1162 if(ne->d_qtype.getCode()) {
1163 LOG(prefix<<qname<<": "<<qtype.getName()<<" is negatively cached via '"<<ne->d_auth<<"' for another "<<sttl<<" seconds"<<endl);
1164 res = RCode::NoError;
1165 }
1166 else {
1167 LOG(prefix<<qname<<": Entire name '"<<qname<<"', is negatively cached via '"<<ne->d_auth<<"' for another "<<sttl<<" seconds"<<endl);
1168 res = RCode::NXDomain;
1169 }
1170 }
1171 }
1172
1173 if (giveNegative) {
1174
1175 state = cachedState;
1176
1177 if (!wasAuthZone && shouldValidate() && state == Indeterminate) {
1178 LOG(prefix<<qname<<": got Indeterminate state for records retrieved from the negative cache, validating.."<<endl);
1179 computeNegCacheValidationStatus(ne, qname, qtype, res, state, depth);
1180
1181 if (state != cachedState && state == Bogus) {
1182 sttl = std::min(sttl, s_maxbogusttl);
1183 }
1184 }
1185
1186 // Transplant SOA to the returned packet
1187 addTTLModifiedRecords(ne->authoritySOA.records, sttl, ret);
1188 if(d_doDNSSEC) {
1189 addTTLModifiedRecords(ne->authoritySOA.signatures, sttl, ret);
1190 addTTLModifiedRecords(ne->DNSSECRecords.records, sttl, ret);
1191 addTTLModifiedRecords(ne->DNSSECRecords.signatures, sttl, ret);
1192 }
1193
1194 LOG(prefix<<qname<<": updating validation state with negative cache content for "<<qname<<" to "<<vStates[state]<<endl);
1195 return true;
1196 }
1197
1198 vector<DNSRecord> cset;
1199 bool found=false, expired=false;
1200 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
1201 vector<std::shared_ptr<DNSRecord>> authorityRecs;
1202 uint32_t ttl=0;
1203 uint32_t capTTL = std::numeric_limits<uint32_t>::max();
1204 bool wasCachedAuth;
1205 if(t_RC->get(d_now.tv_sec, sqname, sqt, !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &cachedState, &wasCachedAuth) > 0) {
1206
1207 LOG(prefix<<sqname<<": Found cache hit for "<<sqt.getName()<<": ");
1208
1209 if (!wasAuthZone && shouldValidate() && (wasCachedAuth || wasForwardRecurse) && cachedState == Indeterminate && d_requireAuthData) {
1210
1211 /* This means we couldn't figure out the state when this entry was cached,
1212 most likely because we hadn't computed the zone cuts yet. */
1213 /* make sure they are computed before validating */
1214 DNSName subdomain(sqname);
1215 /* if we are retrieving a DS, we only care about the state of the parent zone */
1216 if(qtype == QType::DS)
1217 subdomain.chopOff();
1218
1219 computeZoneCuts(subdomain, g_rootdnsname, depth);
1220
1221 vState recordState = getValidationStatus(qname, false);
1222 if (recordState == Secure) {
1223 LOG(prefix<<sqname<<": got Indeterminate state from the cache, validating.."<<endl);
1224 cachedState = SyncRes::validateRecordsWithSigs(depth, sqname, sqt, sqname, cset, signatures);
1225 }
1226 else {
1227 cachedState = recordState;
1228 }
1229
1230 if (cachedState != Indeterminate) {
1231 LOG(prefix<<qname<<": got Indeterminate state from the cache, validation result is "<<vStates[cachedState]<<endl);
1232 if (cachedState == Bogus) {
1233 capTTL = s_maxbogusttl;
1234 }
1235 updateValidationStatusInCache(sqname, sqt, wasCachedAuth, cachedState);
1236 }
1237 }
1238
1239 for(auto j=cset.cbegin() ; j != cset.cend() ; ++j) {
1240
1241 LOG(j->d_content->getZoneRepresentation());
1242
1243 if (j->d_class != QClass::IN) {
1244 continue;
1245 }
1246
1247 if(j->d_ttl>(unsigned int) d_now.tv_sec) {
1248 DNSRecord dr=*j;
1249 dr.d_ttl -= d_now.tv_sec;
1250 dr.d_ttl = std::min(dr.d_ttl, capTTL);
1251 ttl = dr.d_ttl;
1252 ret.push_back(dr);
1253 LOG("[ttl="<<dr.d_ttl<<"] ");
1254 found=true;
1255 }
1256 else {
1257 LOG("[expired] ");
1258 expired=true;
1259 }
1260 }
1261
1262 ret.reserve(ret.size() + signatures.size() + authorityRecs.size());
1263
1264 for(const auto& signature : signatures) {
1265 DNSRecord dr;
1266 dr.d_type=QType::RRSIG;
1267 dr.d_name=sqname;
1268 dr.d_ttl=ttl;
1269 dr.d_content=signature;
1270 dr.d_place = DNSResourceRecord::ANSWER;
1271 dr.d_class=QClass::IN;
1272 ret.push_back(dr);
1273 }
1274
1275 for(const auto& rec : authorityRecs) {
1276 DNSRecord dr(*rec);
1277 dr.d_ttl=ttl;
1278 ret.push_back(dr);
1279 }
1280
1281 LOG(endl);
1282 if(found && !expired) {
1283 if (!giveNegative)
1284 res=0;
1285 LOG(prefix<<qname<<": updating validation state with cache content for "<<qname<<" to "<<vStates[cachedState]<<endl);
1286 state = cachedState;
1287 return true;
1288 }
1289 else
1290 LOG(prefix<<qname<<": cache had only stale entries"<<endl);
1291 }
1292
1293 return false;
1294}
1295
1296bool SyncRes::moreSpecificThan(const DNSName& a, const DNSName &b) const
1297{
1298 return (a.isPartOf(b) && a.countLabels() > b.countLabels());
1299}
1300
1301struct speedOrder
1302{
1303 speedOrder(map<DNSName,double> &speeds) : d_speeds(speeds) {}
1304 bool operator()(const DNSName &a, const DNSName &b) const
1305 {
1306 return d_speeds[a] < d_speeds[b];
1307 }
1308 map<DNSName, double>& d_speeds;
1309};
1310
1311inline vector<DNSName> SyncRes::shuffleInSpeedOrder(NsSet &tnameservers, const string &prefix)
1312{
1313 vector<DNSName> rnameservers;
1314 rnameservers.reserve(tnameservers.size());
1315 for(const auto& tns: tnameservers) {
1316 rnameservers.push_back(tns.first);
1317 if(tns.first.empty()) // this was an authoritative OOB zone, don't pollute the nsSpeeds with that
1318 return rnameservers;
1319 }
1320 map<DNSName, double> speeds;
1321
1322 for(const auto& val: rnameservers) {
1323 double speed;
1324 speed=t_sstorage.nsSpeeds[val].get(&d_now);
1325 speeds[val]=speed;
1326 }
1327 random_shuffle(rnameservers.begin(),rnameservers.end(), dns_random);
1328 speedOrder so(speeds);
1329 stable_sort(rnameservers.begin(),rnameservers.end(), so);
1330
1331 if(doLog()) {
1332 LOG(prefix<<"Nameservers: ");
1333 for(vector<DNSName>::const_iterator i=rnameservers.begin();i!=rnameservers.end();++i) {
1334 if(i!=rnameservers.begin()) {
1335 LOG(", ");
1336 if(!((i-rnameservers.begin())%3)) {
1337 LOG(endl<<prefix<<" ");
1338 }
1339 }
1340 LOG(i->toLogString()<<"(" << (boost::format("%0.2f") % (speeds[*i]/1000.0)).str() <<"ms)");
1341 }
1342 LOG(endl);
1343 }
1344 return rnameservers;
1345}
1346
1347inline vector<ComboAddress> SyncRes::shuffleForwardSpeed(const vector<ComboAddress> &rnameservers, const string &prefix, const bool wasRd)
1348{
1349 vector<ComboAddress> nameservers = rnameservers;
1350 map<ComboAddress, double> speeds;
1351
1352 for(const auto& val: nameservers) {
1353 double speed;
1354 DNSName nsName = DNSName(val.toStringWithPort());
1355 speed=t_sstorage.nsSpeeds[nsName].get(&d_now);
1356 speeds[val]=speed;
1357 }
1358 random_shuffle(nameservers.begin(),nameservers.end(), dns_random);
1359 speedOrderCA so(speeds);
1360 stable_sort(nameservers.begin(),nameservers.end(), so);
1361
1362 if(doLog()) {
1363 LOG(prefix<<"Nameservers: ");
1364 for(vector<ComboAddress>::const_iterator i=nameservers.cbegin();i!=nameservers.cend();++i) {
1365 if(i!=nameservers.cbegin()) {
1366 LOG(", ");
1367 if(!((i-nameservers.cbegin())%3)) {
1368 LOG(endl<<prefix<<" ");
1369 }
1370 }
1371 LOG((wasRd ? string("+") : string("-")) << i->toStringWithPort() <<"(" << (boost::format("%0.2f") % (speeds[*i]/1000.0)).str() <<"ms)");
1372 }
1373 LOG(endl);
1374 }
1375 return nameservers;
1376}
1377
1378static uint32_t getRRSIGTTL(const time_t now, const std::shared_ptr<RRSIGRecordContent>& rrsig)
1379{
1380 uint32_t res = 0;
1381 if (now < rrsig->d_sigexpire) {
1382 res = static_cast<uint32_t>(rrsig->d_sigexpire) - now;
1383 }
1384 return res;
1385}
1386
1387static const set<uint16_t> nsecTypes = {QType::NSEC, QType::NSEC3};
1388
1389/* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
1390 *
1391 * \param records The records to parse for the authority SOA and NSEC(3) records
1392 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
1393 */
1394static void harvestNXRecords(const vector<DNSRecord>& records, NegCache::NegCacheEntry& ne, const time_t now, uint32_t* lowestTTL) {
1395 for(const auto& rec : records) {
1396 if(rec.d_place != DNSResourceRecord::AUTHORITY)
1397 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
1398 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
1399 // records MUST be in the same section as the records they cover.
1400 // Hence, we ignore all records outside of the AUTHORITY section.
1401 continue;
1402
1403 if(rec.d_type == QType::RRSIG) {
1404 auto rrsig = getRR<RRSIGRecordContent>(rec);
1405 if(rrsig) {
1406 if(rrsig->d_type == QType::SOA) {
1407 ne.authoritySOA.signatures.push_back(rec);
1408 if (lowestTTL && isRRSIGNotExpired(now, rrsig)) {
1409 *lowestTTL = min(*lowestTTL, rec.d_ttl);
1410 *lowestTTL = min(*lowestTTL, getRRSIGTTL(now, rrsig));
1411 }
1412 }
1413 if(nsecTypes.count(rrsig->d_type)) {
1414 ne.DNSSECRecords.signatures.push_back(rec);
1415 if (lowestTTL && isRRSIGNotExpired(now, rrsig)) {
1416 *lowestTTL = min(*lowestTTL, rec.d_ttl);
1417 *lowestTTL = min(*lowestTTL, getRRSIGTTL(now, rrsig));
1418 }
1419 }
1420 }
1421 continue;
1422 }
1423 if(rec.d_type == QType::SOA) {
1424 ne.authoritySOA.records.push_back(rec);
1425 if (lowestTTL) {
1426 *lowestTTL = min(*lowestTTL, rec.d_ttl);
1427 }
1428 continue;
1429 }
1430 if(nsecTypes.count(rec.d_type)) {
1431 ne.DNSSECRecords.records.push_back(rec);
1432 if (lowestTTL) {
1433 *lowestTTL = min(*lowestTTL, rec.d_ttl);
1434 }
1435 continue;
1436 }
1437 }
1438}
1439
1440static cspmap_t harvestCSPFromNE(const NegCache::NegCacheEntry& ne)
1441{
1442 cspmap_t cspmap;
1443 for(const auto& rec : ne.DNSSECRecords.signatures) {
1444 if(rec.d_type == QType::RRSIG) {
1445 auto rrc = getRR<RRSIGRecordContent>(rec);
1446 if (rrc) {
1447 cspmap[{rec.d_name,rrc->d_type}].signatures.push_back(rrc);
1448 }
1449 }
1450 }
1451 for(const auto& rec : ne.DNSSECRecords.records) {
1452 cspmap[{rec.d_name, rec.d_type}].records.push_back(rec.d_content);
1453 }
1454 return cspmap;
1455}
1456
1457// TODO remove after processRecords is fixed!
1458// Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
1459static void addNXNSECS(vector<DNSRecord>&ret, const vector<DNSRecord>& records)
1460{
1461 NegCache::NegCacheEntry ne;
1462 harvestNXRecords(records, ne, 0, nullptr);
1463 ret.insert(ret.end(), ne.authoritySOA.signatures.begin(), ne.authoritySOA.signatures.end());
1464 ret.insert(ret.end(), ne.DNSSECRecords.records.begin(), ne.DNSSECRecords.records.end());
1465 ret.insert(ret.end(), ne.DNSSECRecords.signatures.begin(), ne.DNSSECRecords.signatures.end());
1466}
1467
1468bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine& dfe, const NsSet& nameservers)
1469{
1470 if(d_wantsRPZ) {
1471 for (auto const &ns : nameservers) {
1472 d_appliedPolicy = dfe.getProcessingPolicy(ns.first, d_discardedPolicies);
1473 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
1474 LOG(", however nameserver "<<ns.first<<" was blocked by RPZ policy '"<<(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")<<"'"<<endl);
1475 return true;
1476 }
1477
1478 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1479 for (auto const &address : ns.second.first) {
1480 d_appliedPolicy = dfe.getProcessingPolicy(address, d_discardedPolicies);
1481 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
1482 LOG(", however nameserver "<<ns.first<<" IP address "<<address.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")<<"'"<<endl);
1483 return true;
1484 }
1485 }
1486 }
1487 }
1488 return false;
1489}
1490
1491bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine& dfe, const ComboAddress& remoteIP)
1492{
1493 if (d_wantsRPZ) {
1494 d_appliedPolicy = dfe.getProcessingPolicy(remoteIP, d_discardedPolicies);
1495 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) {
1496 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")+"')");
1497 return true;
1498 }
1499 }
1500 return false;
1501}
1502
1503vector<ComboAddress> SyncRes::retrieveAddressesForNS(const std::string& prefix, const DNSName& qname, vector<DNSName >::const_iterator& tns, const unsigned int depth, set<GetBestNSAnswer>& beenthere, const vector<DNSName >& rnameservers, NsSet& nameservers, bool& sendRDQuery, bool& pierceDontQuery, bool& flawedNSSet, bool cacheOnly)
1504{
1505 vector<ComboAddress> result;
1506
1507 if(!tns->empty()) {
1508 LOG(prefix<<qname<<": Trying to resolve NS '"<<*tns<< "' ("<<1+tns-rnameservers.begin()<<"/"<<(unsigned int)rnameservers.size()<<")"<<endl);
1509 result = getAddrs(*tns, depth+2, beenthere, cacheOnly);
1510 pierceDontQuery=false;
1511 }
1512 else {
1513 LOG(prefix<<qname<<": Domain has hardcoded nameserver");
1514
1515 if(nameservers[*tns].first.size() > 1) {
1516 LOG("s");
1517 }
1518 LOG(endl);
1519
1520 sendRDQuery = nameservers[*tns].second;
1521 result = shuffleForwardSpeed(nameservers[*tns].first, doLog() ? (prefix+qname.toString()+": ") : string(), sendRDQuery);
1522 pierceDontQuery=true;
1523 }
1524 return result;
1525}
1526
1527bool SyncRes::throttledOrBlocked(const std::string& prefix, const ComboAddress& remoteIP, const DNSName& qname, const QType& qtype, bool pierceDontQuery)
1528{
1529 if(t_sstorage.throttle.shouldThrottle(d_now.tv_sec, boost::make_tuple(remoteIP, "", 0))) {
1530 LOG(prefix<<qname<<": server throttled "<<endl);
1531 s_throttledqueries++; d_throttledqueries++;
1532 return true;
1533 }
1534 else if(t_sstorage.throttle.shouldThrottle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()))) {
1535 LOG(prefix<<qname<<": query throttled "<<remoteIP.toString()<<", "<<qname<<"; "<<qtype.getName()<<endl);
1536 s_throttledqueries++; d_throttledqueries++;
1537 return true;
1538 }
1539 else if(!pierceDontQuery && s_dontQuery && s_dontQuery->match(&remoteIP)) {
1540 LOG(prefix<<qname<<": not sending query to " << remoteIP.toString() << ", blocked by 'dont-query' setting" << endl);
1541 s_dontqueries++;
1542 return true;
1543 }
1544 return false;
1545}
1546
1547bool SyncRes::validationEnabled() const
1548{
1549 return g_dnssecmode != DNSSECMode::Off && g_dnssecmode != DNSSECMode::ProcessNoValidate;
1550}
1551
1552uint32_t SyncRes::computeLowestTTD(const std::vector<DNSRecord>& records, const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures, uint32_t signaturesTTL) const
1553{
1554 uint32_t lowestTTD = std::numeric_limits<uint32_t>::max();
1555 for(const auto& record : records)
1556 lowestTTD = min(lowestTTD, record.d_ttl);
1557
1558 /* even if it was not requested for that request (Process, and neither AD nor DO set),
1559 it might be requested at a later time so we need to be careful with the TTL. */
1560 if (validationEnabled() && !signatures.empty()) {
1561 /* if we are validating, we don't want to cache records after their signatures expire. */
1562 /* records TTL are now TTD, let's add 'now' to the signatures lowest TTL */
1563 lowestTTD = min(lowestTTD, static_cast<uint32_t>(signaturesTTL + d_now.tv_sec));
1564
1565 for(const auto& sig : signatures) {
1566 if (isRRSIGNotExpired(d_now.tv_sec, sig)) {
1567 // we don't decerement d_sigexpire by 'now' because we actually want a TTD, not a TTL */
1568 lowestTTD = min(lowestTTD, static_cast<uint32_t>(sig->d_sigexpire));
1569 }
1570 }
1571 }
1572
1573 return lowestTTD;
1574}
1575
1576void SyncRes::updateValidationState(vState& state, const vState stateUpdate)
1577{
1578 LOG(d_prefix<<"validation state was "<<std::string(vStates[state])<<", state update is "<<std::string(vStates[stateUpdate]));
1579
1580 if (stateUpdate == TA) {
1581 state = Secure;
1582 }
1583 else if (stateUpdate == NTA) {
1584 state = Insecure;
1585 }
1586 else if (stateUpdate == Bogus) {
1587 state = Bogus;
1588 }
1589 else if (state == Indeterminate) {
1590 state = stateUpdate;
1591 }
1592 else if (stateUpdate == Insecure) {
1593 if (state != Bogus) {
1594 state = Insecure;
1595 }
1596 }
1597 LOG(", validation state is now "<<std::string(vStates[state])<<endl);
1598}
1599
1600vState SyncRes::getTA(const DNSName& zone, dsmap_t& ds)
1601{
1602 auto luaLocal = g_luaconfs.getLocal();
1603
1604 if (luaLocal->dsAnchors.empty()) {
1605 LOG(d_prefix<<": No trust anchors configured, everything is Insecure"<<endl);
1606 /* We have no TA, everything is insecure */
1607 return Insecure;
1608 }
1609
1610 std::string reason;
1611 if (haveNegativeTrustAnchor(luaLocal->negAnchors, zone, reason)) {
1612 LOG(d_prefix<<": got NTA for '"<<zone<<"'"<<endl);
1613 return NTA;
1614 }
1615
1616 if (getTrustAnchor(luaLocal->dsAnchors, zone, ds)) {
1617 LOG(d_prefix<<": got TA for '"<<zone<<"'"<<endl);
1618 return TA;
1619 }
1620 else {
1621 LOG(d_prefix<<": no TA found for '"<<zone<<"' among "<< luaLocal->dsAnchors.size()<<endl);
1622 }
1623
1624 if (zone.isRoot()) {
1625 /* No TA for the root */
1626 return Insecure;
1627 }
1628
1629 return Indeterminate;
1630}
1631
1632static size_t countSupportedDS(const dsmap_t& dsmap)
1633{
1634 size_t count = 0;
1635
1636 for (const auto& ds : dsmap) {
1637 if (isSupportedDS(ds)) {
1638 count++;
1639 }
1640 }
1641
1642 return count;
1643}
1644
1645vState SyncRes::getDSRecords(const DNSName& zone, dsmap_t& ds, bool taOnly, unsigned int depth, bool bogusOnNXD, bool* foundCut)
1646{
1647 vState result = getTA(zone, ds);
1648
1649 if (result != Indeterminate || taOnly) {
1650 if (foundCut) {
1651 *foundCut = (result != Indeterminate);
1652 }
1653
1654 if (result == TA) {
1655 if (countSupportedDS(ds) == 0) {
1656 ds.clear();
1657 result = Insecure;
1658 }
1659 else {
1660 result = Secure;
1661 }
1662 }
1663 else if (result == NTA) {
1664 result = Insecure;
1665 }
1666
1667 return result;
1668 }
1669
1670 bool oldSkipCNAME = d_skipCNAMECheck;
1671 d_skipCNAMECheck = true;
1672
1673 std::set<GetBestNSAnswer> beenthere;
1674 std::vector<DNSRecord> dsrecords;
1675
1676 vState state = Indeterminate;
1677 int rcode = doResolve(zone, QType(QType::DS), dsrecords, depth + 1, beenthere, state);
1678 d_skipCNAMECheck = oldSkipCNAME;
1679
1680 if (rcode == RCode::NoError || (rcode == RCode::NXDomain && !bogusOnNXD)) {
1681
1682 uint8_t bestDigestType = 0;
1683
1684 if (state == Secure) {
1685 bool gotCNAME = false;
1686 for (const auto& record : dsrecords) {
1687 if (record.d_type == QType::DS) {
1688 const auto dscontent = getRR<DSRecordContent>(record);
1689 if (dscontent && isSupportedDS(*dscontent)) {
1690 // Make GOST a lower prio than SHA256
1691 if (dscontent->d_digesttype == DNSSECKeeper::GOST && bestDigestType == DNSSECKeeper::SHA256) {
1692 continue;
1693 }
1694 if (dscontent->d_digesttype > bestDigestType || (bestDigestType == DNSSECKeeper::GOST && dscontent->d_digesttype == DNSSECKeeper::SHA256)) {
1695 bestDigestType = dscontent->d_digesttype;
1696 }
1697 ds.insert(*dscontent);
1698 }
1699 }
1700 else if (record.d_type == QType::CNAME && record.d_name == zone) {
1701 gotCNAME = true;
1702 }
1703 }
1704
1705 /* RFC 4509 section 3: "Validator implementations SHOULD ignore DS RRs containing SHA-1
1706 * digests if DS RRs with SHA-256 digests are present in the DS RRset."
1707 * As SHA348 is specified as well, the spirit of the this line is "use the best algorithm".
1708 */
1709 for (auto dsrec = ds.begin(); dsrec != ds.end(); ) {
1710 if (dsrec->d_digesttype != bestDigestType) {
1711 dsrec = ds.erase(dsrec);
1712 }
1713 else {
1714 ++dsrec;
1715 }
1716 }
1717
1718 if (rcode == RCode::NoError && ds.empty()) {
1719 if (foundCut) {
1720 if (gotCNAME || denialProvesNoDelegation(zone, dsrecords)) {
1721 /* we are still inside the same Secure zone */
1722
1723 *foundCut = false;
1724 return Secure;
1725 }
1726
1727 *foundCut = true;
1728 }
1729
1730 return Insecure;
1731 } else if (foundCut && rcode == RCode::NoError && !ds.empty()) {
1732 *foundCut = true;
1733 }
1734 }
1735
1736 return state;
1737 }
1738
1739 LOG(d_prefix<<": returning Bogus state from "<<__func__<<"("<<zone<<")"<<endl);
1740 return Bogus;
1741}
1742
1743bool SyncRes::haveExactValidationStatus(const DNSName& domain)
1744{
1745 if (!shouldValidate()) {
1746 return false;
1747 }
1748 const auto& it = d_cutStates.find(domain);
1749 if (it != d_cutStates.cend()) {
1750 return true;
1751 }
1752 return false;
1753}
1754
1755vState SyncRes::getValidationStatus(const DNSName& subdomain, bool allowIndeterminate)
1756{
1757 vState result = Indeterminate;
1758
1759 if (!shouldValidate()) {
1760 return result;
1761 }
1762 DNSName name(subdomain);
1763 do {
1764 const auto& it = d_cutStates.find(name);
1765 if (it != d_cutStates.cend()) {
1766 if (allowIndeterminate || it->second != Indeterminate) {
1767 LOG(d_prefix<<": got status "<<vStates[it->second]<<" for name "<<subdomain<<" (from "<<name<<")"<<endl);
1768 return it->second;
1769 }
1770 }
1771 }
1772 while (name.chopOff());
1773
1774 return result;
1775}
1776
1777bool SyncRes::lookForCut(const DNSName& qname, unsigned int depth, const vState existingState, vState& newState)
1778{
1779 bool foundCut = false;
1780 dsmap_t ds;
1781 vState dsState = getDSRecords(qname, ds, newState == Bogus || existingState == Insecure || existingState == Bogus, depth, false, &foundCut);
1782
1783 if (dsState != Indeterminate) {
1784 newState = dsState;
1785 }
1786
1787 return foundCut;
1788}
1789
1790void SyncRes::computeZoneCuts(const DNSName& begin, const DNSName& end, unsigned int depth)
1791{
1792 if(!begin.isPartOf(end)) {
1793 LOG(d_prefix<<" "<<begin.toLogString()<<" is not part of "<<end.toLogString()<<endl);
1794 throw PDNSException(begin.toLogString() + " is not part of " + end.toLogString());
1795 }
1796
1797 if (d_cutStates.count(begin) != 0) {
1798 return;
1799 }
1800
1801 dsmap_t ds;
1802 vState cutState = getDSRecords(end, ds, false, depth);
1803 LOG(d_prefix<<": setting cut state for "<<end<<" to "<<vStates[cutState]<<endl);
1804 d_cutStates[end] = cutState;
1805
1806 if (!shouldValidate()) {
1807 return;
1808 }
1809
1810 DNSName qname(end);
1811 std::vector<string> labelsToAdd = begin.makeRelative(end).getRawLabels();
1812
1813 bool oldSkipCNAME = d_skipCNAMECheck;
1814 d_skipCNAMECheck = true;
1815
1816 while(qname != begin) {
1817 if (labelsToAdd.empty())
1818 break;
1819
1820 qname.prependRawLabel(labelsToAdd.back());
1821 labelsToAdd.pop_back();
1822 LOG(d_prefix<<": - Looking for a cut at "<<qname<<endl);
1823
1824 const auto cutIt = d_cutStates.find(qname);
1825 if (cutIt != d_cutStates.cend()) {
1826 if (cutIt->second != Indeterminate) {
1827 LOG(d_prefix<<": - Cut already known at "<<qname<<endl);
1828 cutState = cutIt->second;
1829 continue;
1830 }
1831 }
1832
1833 /* no need to look for NS and DS if we are already insecure or bogus,
1834 just look for (N)TA
1835 */
1836 if (cutState == Insecure || cutState == Bogus) {
1837 dsmap_t cutDS;
1838 vState newState = getDSRecords(qname, cutDS, true, depth);
1839 if (newState == Indeterminate) {
1840 continue;
1841 }
1842
1843 LOG(d_prefix<<": New state for "<<qname<<" is "<<vStates[newState]<<endl);
1844 cutState = newState;
1845
1846 d_cutStates[qname] = cutState;
1847
1848 continue;
1849 }
1850
1851 vState newState = Indeterminate;
1852 /* temporarily mark as Indeterminate, so that we won't enter an endless loop
1853 trying to determine that zone cut again. */
1854 d_cutStates[qname] = newState;
1855 bool foundCut = lookForCut(qname, depth + 1, cutState, newState);
1856 if (foundCut) {
1857 LOG(d_prefix<<": - Found cut at "<<qname<<endl);
1858 if (newState != Indeterminate) {
1859 cutState = newState;
1860 }
1861 LOG(d_prefix<<": New state for "<<qname<<" is "<<vStates[cutState]<<endl);
1862 d_cutStates[qname] = cutState;
1863 }
1864 else {
1865 /* remove the temporary cut */
1866 LOG(d_prefix<<qname<<": removing cut state for "<<qname<<endl);
1867 d_cutStates.erase(qname);
1868 }
1869 }
1870
1871 d_skipCNAMECheck = oldSkipCNAME;
1872
1873 LOG(d_prefix<<": list of cuts from "<<begin<<" to "<<end<<endl);
1874 for (const auto& cut : d_cutStates) {
1875 if (cut.first.isRoot() || (begin.isPartOf(cut.first) && cut.first.isPartOf(end))) {
1876 LOG(" - "<<cut.first<<": "<<vStates[cut.second]<<endl);
1877 }
1878 }
1879}
1880
1881vState SyncRes::validateDNSKeys(const DNSName& zone, const std::vector<DNSRecord>& dnskeys, const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures, unsigned int depth)
1882{
1883 dsmap_t ds;
1884 if (!signatures.empty()) {
1885 DNSName signer = getSigner(signatures);
1886
1887 if (!signer.empty() && zone.isPartOf(signer)) {
1888 vState state = getDSRecords(signer, ds, false, depth);
1889
1890 if (state != Secure) {
1891 return state;
1892 }
1893 }
1894 }
1895
1896 skeyset_t tentativeKeys;
1897 std::vector<shared_ptr<DNSRecordContent> > toSign;
1898
1899 for (const auto& dnskey : dnskeys) {
1900 if (dnskey.d_type == QType::DNSKEY) {
1901 auto content = getRR<DNSKEYRecordContent>(dnskey);
1902 if (content) {
1903 tentativeKeys.insert(content);
1904 toSign.push_back(content);
1905 }
1906 }
1907 }
1908
1909 LOG(d_prefix<<": trying to validate "<<std::to_string(tentativeKeys.size())<<" DNSKEYs with "<<std::to_string(ds.size())<<" DS"<<endl);
1910 skeyset_t validatedKeys;
1911 validateDNSKeysAgainstDS(d_now.tv_sec, zone, ds, tentativeKeys, toSign, signatures, validatedKeys);
1912
1913 LOG(d_prefix<<": we now have "<<std::to_string(validatedKeys.size())<<" DNSKEYs"<<endl);
1914
1915 /* if we found at least one valid RRSIG covering the set,
1916 all tentative keys are validated keys. Otherwise it means
1917 we haven't found at least one DNSKEY and a matching RRSIG
1918 covering this set, this looks Bogus. */
1919 if (validatedKeys.size() != tentativeKeys.size()) {
1920 LOG(d_prefix<<": returning Bogus state from "<<__func__<<"("<<zone<<")"<<endl);
1921 return Bogus;
1922 }
1923
1924 return Secure;
1925}
1926
1927vState SyncRes::getDNSKeys(const DNSName& signer, skeyset_t& keys, unsigned int depth)
1928{
1929 std::vector<DNSRecord> records;
1930 std::set<GetBestNSAnswer> beenthere;
1931 LOG(d_prefix<<"Retrieving DNSKeys for "<<signer<<endl);
1932
1933 vState state = Indeterminate;
1934 /* following CNAME might lead to us to the wrong DNSKEY */
1935 bool oldSkipCNAME = d_skipCNAMECheck;
1936 d_skipCNAMECheck = true;
1937 int rcode = doResolve(signer, QType(QType::DNSKEY), records, depth + 1, beenthere, state);
1938 d_skipCNAMECheck = oldSkipCNAME;
1939
1940 if (rcode == RCode::NoError) {
1941 if (state == Secure) {
1942 for (const auto& key : records) {
1943 if (key.d_type == QType::DNSKEY) {
1944 auto content = getRR<DNSKEYRecordContent>(key);
1945 if (content) {
1946 keys.insert(content);
1947 }
1948 }
1949 }
1950 }
1951 LOG(d_prefix<<"Retrieved "<<keys.size()<<" DNSKeys for "<<signer<<", state is "<<vStates[state]<<endl);
1952 return state;
1953 }
1954
1955 LOG(d_prefix<<"Returning Bogus state from "<<__func__<<"("<<signer<<")"<<endl);
1956 return Bogus;
1957}
1958
1959vState SyncRes::validateRecordsWithSigs(unsigned int depth, const DNSName& qname, const QType& qtype, const DNSName& name, const std::vector<DNSRecord>& records, const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures)
1960{
1961 skeyset_t keys;
1962 if (!signatures.empty()) {
1963 const DNSName signer = getSigner(signatures);
1964 if (!signer.empty() && name.isPartOf(signer)) {
1965 if ((qtype == QType::DNSKEY || qtype == QType::DS) && signer == qname) {
1966 /* we are already retrieving those keys, sorry */
1967 return Indeterminate;
1968 }
1969 vState state = getDNSKeys(signer, keys, depth);
1970 if (state != Secure) {
1971 return state;
1972 }
1973 }
1974 } else {
1975 LOG(d_prefix<<"Bogus!"<<endl);
1976 return Bogus;
1977 }
1978
1979 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
1980 for (const auto& record : records) {
1981 recordcontents.push_back(record.d_content);
1982 }
1983
1984 LOG(d_prefix<<"Going to validate "<<recordcontents.size()<< " record contents with "<<signatures.size()<<" sigs and "<<keys.size()<<" keys for "<<name<<endl);
1985 if (validateWithKeySet(d_now.tv_sec, name, recordcontents, signatures, keys, false)) {
1986 LOG(d_prefix<<"Secure!"<<endl);
1987 return Secure;
1988 }
1989
1990 LOG(d_prefix<<"Bogus!"<<endl);
1991 return Bogus;
1992}
1993
1994static bool allowAdditionalEntry(std::unordered_set<DNSName>& allowedAdditionals, const DNSRecord& rec)
1995{
1996 switch(rec.d_type) {
1997 case QType::MX:
1998 {
1999 if (auto mxContent = getRR<MXRecordContent>(rec)) {
2000 allowedAdditionals.insert(mxContent->d_mxname);
2001 }
2002 return true;
2003 }
2004 case QType::NS:
2005 {
2006 if (auto nsContent = getRR<NSRecordContent>(rec)) {
2007 allowedAdditionals.insert(nsContent->getNS());
2008 }
2009 return true;
2010 }
2011 case QType::SRV:
2012 {
2013 if (auto srvContent = getRR<SRVRecordContent>(rec)) {
2014 allowedAdditionals.insert(srvContent->d_target);
2015 }
2016 return true;
2017 }
2018 default:
2019 return false;
2020 }
2021}
2022
2023void SyncRes::sanitizeRecords(const std::string& prefix, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, bool rdQuery)
2024{
2025 const bool wasForwardRecurse = wasForwarded && rdQuery;
2026 /* list of names for which we will allow A and AAAA records in the additional section
2027 to remain */
2028 std::unordered_set<DNSName> allowedAdditionals = { qname };
2029 bool haveAnswers = false;
2030 bool isNXDomain = false;
2031 bool isNXQType = false;
2032
2033 for(auto rec = lwr.d_records.begin(); rec != lwr.d_records.end(); ) {
2034
2035 if (rec->d_type == QType::OPT) {
2036 ++rec;
2037 continue;
2038 }
2039
2040 if (rec->d_class != QClass::IN) {
2041 LOG(prefix<<"Removing non internet-classed data received from "<<auth<<endl);
2042 rec = lwr.d_records.erase(rec);
2043 continue;
2044 }
2045
2046 if (rec->d_type == QType::ANY) {
2047 LOG(prefix<<"Removing 'ANY'-typed data received from "<<auth<<endl);
2048 rec = lwr.d_records.erase(rec);
2049 continue;
2050 }
2051
2052 if (!rec->d_name.isPartOf(auth)) {
2053 LOG(prefix<<"Removing record '"<<rec->d_name<<"|"<<DNSRecordContent::NumberToType(rec->d_type)<<"|"<<rec->d_content->getZoneRepresentation()<<"' in the "<<(int)rec->d_place<<" section received from "<<auth<<endl);
2054 rec = lwr.d_records.erase(rec);
2055 continue;
2056 }
2057
2058 /* dealing with the records in answer */
2059 if (!(lwr.d_aabit || wasForwardRecurse) && rec->d_place == DNSResourceRecord::ANSWER) {
2060 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2061 are sending such responses */
2062 if (!(rec->d_type == QType::CNAME && qname == rec->d_name)) {
2063 LOG(prefix<<"Removing record '"<<rec->d_name<<"|"<<DNSRecordContent::NumberToType(rec->d_type)<<"|"<<rec->d_content->getZoneRepresentation()<<"' in the answer section without the AA bit set received from "<<auth<<endl);
2064 rec = lwr.d_records.erase(rec);
2065 continue;
2066 }
2067 }
2068
2069 if (rec->d_type == QType::DNAME && (rec->d_place != DNSResourceRecord::ANSWER || !qname.isPartOf(rec->d_name))) {
2070 LOG(prefix<<"Removing invalid DNAME record '"<<rec->d_name<<"|"<<DNSRecordContent::NumberToType(rec->d_type)<<"|"<<rec->d_content->getZoneRepresentation()<<"' in the "<<(int)rec->d_place<<" section received from "<<auth<<endl);
2071 rec = lwr.d_records.erase(rec);
2072 continue;
2073 }
2074
2075 if (rec->d_place == DNSResourceRecord::ANSWER && (qtype != QType::ANY && rec->d_type != qtype.getCode() && rec->d_type != QType::CNAME && rec->d_type != QType::SOA && rec->d_type != QType::RRSIG)) {
2076 LOG(prefix<<"Removing irrelevant record '"<<rec->d_name<<"|"<<DNSRecordContent::NumberToType(rec->d_type)<<"|"<<rec->d_content->getZoneRepresentation()<<"' in the "<<(int)rec->d_place<<" section received from "<<auth<<endl);
2077 rec = lwr.d_records.erase(rec);
2078 continue;
2079 }
2080
2081 if (rec->d_place == DNSResourceRecord::ANSWER && !haveAnswers) {
2082 haveAnswers = true;
2083 }
2084
2085 if (rec->d_place == DNSResourceRecord::ANSWER) {
2086 allowAdditionalEntry(allowedAdditionals, *rec);
2087 }
2088
2089 /* dealing with the records in authority */
2090 if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type != QType::NS && rec->d_type != QType::DS && rec->d_type != QType::SOA && rec->d_type != QType::RRSIG && rec->d_type != QType::NSEC && rec->d_type != QType::NSEC3) {
2091 LOG(prefix<<"Removing irrelevant record '"<<rec->d_name<<"|"<<DNSRecordContent::NumberToType(rec->d_type)<<"|"<<rec->d_content->getZoneRepresentation()<<"' in the "<<(int)rec->d_place<<" section received from "<<auth<<endl);
2092 rec = lwr.d_records.erase(rec);
2093 continue;
2094 }
2095
2096 if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type == QType::SOA) {
2097 if (!qname.isPartOf(rec->d_name)) {
2098 LOG(prefix<<"Removing irrelevant record '"<<rec->d_name<<"|"<<DNSRecordContent::NumberToType(rec->d_type)<<"|"<<rec->d_content->getZoneRepresentation()<<"' in the "<<(int)rec->d_place<<" section received from "<<auth<<endl);
2099 rec = lwr.d_records.erase(rec);
2100 continue;
2101 }
2102
2103 if (!(lwr.d_aabit || wasForwardRecurse)) {
2104 LOG(prefix<<"Removing irrelevant record '"<<rec->d_name<<"|"<<DNSRecordContent::NumberToType(rec->d_type)<<"|"<<rec->d_content->getZoneRepresentation()<<"' in the "<<(int)rec->d_place<<" section received from "<<auth<<endl);
2105 rec = lwr.d_records.erase(rec);
2106 continue;
2107 }
2108
2109 if (!haveAnswers) {
2110 if (lwr.d_rcode == RCode::NXDomain) {
2111 isNXDomain = true;
2112 }
2113 else if (lwr.d_rcode == RCode::NoError) {
2114 isNXQType = true;
2115 }
2116 }
2117 }
2118
2119 if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type == QType::NS && (isNXDomain || isNXQType)) {
2120 /* we don't want to pick up NS records in AUTHORITY or ADDITIONAL sections of NXDomain answers
2121 because they are somewhat easy to insert into a large, fragmented UDP response
2122 for an off-path attacker by injecting spoofed UDP fragments.
2123 */
2124 LOG(prefix<<"Removing NS record '"<<rec->d_name<<"|"<<DNSRecordContent::NumberToType(rec->d_type)<<"|"<<rec->d_content->getZoneRepresentation()<<"' in the "<<(int)rec->d_place<<" section of a "<<(isNXDomain ? "NXD" : "NXQTYPE")<<" response received from "<<auth<<endl);
2125 rec = lwr.d_records.erase(rec);
2126 continue;
2127 }
2128
2129 if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type == QType::NS) {
2130 allowAdditionalEntry(allowedAdditionals, *rec);
2131 }
2132
2133 /* dealing with the records in additional */
2134 if (rec->d_place == DNSResourceRecord::ADDITIONAL && rec->d_type != QType::A && rec->d_type != QType::AAAA && rec->d_type != QType::RRSIG) {
2135 LOG(prefix<<"Removing irrelevant record '"<<rec->d_name<<"|"<<DNSRecordContent::NumberToType(rec->d_type)<<"|"<<rec->d_content->getZoneRepresentation()<<"' in the "<<(int)rec->d_place<<" section received from "<<auth<<endl);
2136 rec = lwr.d_records.erase(rec);
2137 continue;
2138 }
2139
2140 if (rec->d_place == DNSResourceRecord::ADDITIONAL && allowedAdditionals.count(rec->d_name) == 0) {
2141 LOG(prefix<<"Removing irrelevant additional record '"<<rec->d_name<<"|"<<DNSRecordContent::NumberToType(rec->d_type)<<"|"<<rec->d_content->getZoneRepresentation()<<"' in the "<<(int)rec->d_place<<" section received from "<<auth<<endl);
2142 rec = lwr.d_records.erase(rec);
2143 continue;
2144 }
2145
2146 ++rec;
2147 }
2148}
2149
2150RCode::rcodes_ SyncRes::updateCacheFromRecords(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, const boost::optional<Netmask> ednsmask, vState& state, bool& needWildcardProof, unsigned int& wildcardLabelsCount, bool rdQuery)
2151{
2152 bool wasForwardRecurse = wasForwarded && rdQuery;
2153 tcache_t tcache;
2154
2155 string prefix;
2156 if(doLog()) {
2157 prefix=d_prefix;
2158 prefix.append(depth, ' ');
2159 }
2160
2161 sanitizeRecords(prefix, lwr, qname, qtype, auth, wasForwarded, rdQuery);
2162
2163 std::vector<std::shared_ptr<DNSRecord>> authorityRecs;
2164 const unsigned int labelCount = qname.countLabels();
2165 bool isCNAMEAnswer = false;
2166 for(const auto& rec : lwr.d_records) {
2167 if (rec.d_class != QClass::IN) {
2168 continue;
2169 }
2170
2171 if(!isCNAMEAnswer && rec.d_place == DNSResourceRecord::ANSWER && rec.d_type == QType::CNAME && (!(qtype==QType(QType::CNAME))) && rec.d_name == qname) {
2172 isCNAMEAnswer = true;
2173 }
2174
2175 /* if we have a positive answer synthetized from a wildcard,
2176 we need to store the corresponding NSEC/NSEC3 records proving
2177 that the exact name did not exist in the negative cache */
2178 if(needWildcardProof) {
2179 if (nsecTypes.count(rec.d_type)) {
2180 authorityRecs.push_back(std::make_shared<DNSRecord>(rec));
2181 }
2182 else if (rec.d_type == QType::RRSIG) {
2183 auto rrsig = getRR<RRSIGRecordContent>(rec);
2184 if (rrsig && nsecTypes.count(rrsig->d_type)) {
2185 authorityRecs.push_back(std::make_shared<DNSRecord>(rec));
2186 }
2187 }
2188 }
2189 if(rec.d_type == QType::RRSIG) {
2190 auto rrsig = getRR<RRSIGRecordContent>(rec);
2191 if (rrsig) {
2192 /* As illustrated in rfc4035's Appendix B.6, the RRSIG label
2193 count can be lower than the name's label count if it was
2194 synthetized from the wildcard. Note that the difference might
2195 be > 1. */
2196 if (rec.d_name == qname && rrsig->d_labels < labelCount) {
2197 LOG(prefix<<qname<<": RRSIG indicates the name was synthetized from a wildcard, we need a wildcard proof"<<endl);
2198 needWildcardProof = true;
2199 wildcardLabelsCount = rrsig->d_labels;
2200 }
2201
2202 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
2203 tcache[{rec.d_name, rrsig->d_type, rec.d_place}].signatures.push_back(rrsig);
2204 tcache[{rec.d_name, rrsig->d_type, rec.d_place}].signaturesTTL = std::min(tcache[{rec.d_name, rrsig->d_type, rec.d_place}].signaturesTTL, rec.d_ttl);
2205 }
2206 }
2207 }
2208
2209 // reap all answers from this packet that are acceptable
2210 for(auto& rec : lwr.d_records) {
2211 if(rec.d_type == QType::OPT) {
2212 LOG(prefix<<qname<<": OPT answer '"<<rec.d_name<<"' from '"<<auth<<"' nameservers" <<endl);
2213 continue;
2214 }
2215 LOG(prefix<<qname<<": accept answer '"<<rec.d_name<<"|"<<DNSRecordContent::NumberToType(rec.d_type)<<"|"<<rec.d_content->getZoneRepresentation()<<"' from '"<<auth<<"' nameservers? ttl="<<rec.d_ttl<<", place="<<(int)rec.d_place<<" ");
2216 if(rec.d_type == QType::ANY) {
2217 LOG("NO! - we don't accept 'ANY'-typed data"<<endl);
2218 continue;
2219 }
2220
2221 if(rec.d_class != QClass::IN) {
2222 LOG("NO! - we don't accept records for any other class than 'IN'"<<endl);
2223 continue;
2224 }
2225
2226 if (!(lwr.d_aabit || wasForwardRecurse) && rec.d_place == DNSResourceRecord::ANSWER) {
2227 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2228 are sending such responses */
2229 if (!(rec.d_type == QType::CNAME && rec.d_name == qname)) {
2230 LOG("NO! - we don't accept records in the answers section without the AA bit set"<<endl);
2231 continue;
2232 }
2233 }
2234
2235 if(rec.d_name.isPartOf(auth)) {
2236 if(rec.d_type == QType::RRSIG) {
2237 LOG("RRSIG - separate"<<endl);
2238 }
2239 else if(lwr.d_aabit && lwr.d_rcode==RCode::NoError && rec.d_place==DNSResourceRecord::ANSWER && ((rec.d_type != QType::DNSKEY && rec.d_type != QType::DS) || rec.d_name != auth) && s_delegationOnly.count(auth)) {
2240 LOG("NO! Is from delegation-only zone"<<endl);
2241 s_nodelegated++;
2242 return RCode::NXDomain;
2243 }
2244 else {
2245 bool haveLogged = false;
2246 if (!t_sstorage.domainmap->empty()) {
2247 // Check if we are authoritative for a zone in this answer
2248 DNSName tmp_qname(rec.d_name);
2249 auto auth_domain_iter=getBestAuthZone(&tmp_qname);
2250 if(auth_domain_iter!=t_sstorage.domainmap->end() &&
2251 auth.countLabels() <= auth_domain_iter->first.countLabels()) {
2252 if (auth_domain_iter->first != auth) {
2253 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter->first<<endl);
2254 continue;
2255 } else {
2256 LOG("YES! - This answer was ");
2257 if (!wasForwarded) {
2258 LOG("retrieved from the local auth store.");
2259 } else {
2260 LOG("received from a server we forward to.");
2261 }
2262 haveLogged = true;
2263 LOG(endl);
2264 }
2265 }
2266 }
2267 if (!haveLogged) {
2268 LOG("YES!"<<endl);
2269 }
2270
2271 rec.d_ttl=min(s_maxcachettl, rec.d_ttl);
2272
2273 DNSRecord dr(rec);
2274 dr.d_ttl += d_now.tv_sec;
2275 dr.d_place=DNSResourceRecord::ANSWER;
2276 tcache[{rec.d_name,rec.d_type,rec.d_place}].records.push_back(dr);
2277 }
2278 }
2279 else
2280 LOG("NO!"<<endl);
2281 }
2282
2283 // supplant
2284 for(tcache_t::iterator i = tcache.begin(); i != tcache.end(); ++i) {
2285 if((i->second.records.size() + i->second.signatures.size()) > 1) { // need to group the ttl to be the minimum of the RRSET (RFC 2181, 5.2)
2286 uint32_t lowestTTD=computeLowestTTD(i->second.records, i->second.signatures, i->second.signaturesTTL);
2287
2288 for(auto& record : i->second.records)
2289 record.d_ttl = lowestTTD; // boom
2290 }
2291
2292// cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
2293// cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
2294 }
2295
2296 for(tcache_t::iterator i = tcache.begin(); i != tcache.end(); ++i) {
2297
2298 if(i->second.records.empty()) // this happens when we did store signatures, but passed on the records themselves
2299 continue;
2300
2301 /* Even if the AA bit is set, additional data cannot be considered
2302 as authoritative. This is especially important during validation
2303 because keeping records in the additional section is allowed even
2304 if the corresponding RRSIGs are not included, without setting the TC
2305 bit, as stated in rfc4035's section 3.1.1. Including RRSIG RRs in a Response:
2306 "When placing a signed RRset in the Additional section, the name
2307 server MUST also place its RRSIG RRs in the Additional section.
2308 If space does not permit inclusion of both the RRset and its
2309 associated RRSIG RRs, the name server MAY retain the RRset while
2310 dropping the RRSIG RRs. If this happens, the name server MUST NOT
2311 set the TC bit solely because these RRSIG RRs didn't fit."
2312 */
2313 bool isAA = lwr.d_aabit && i->first.place != DNSResourceRecord::ADDITIONAL;
2314 /* if we forwarded the query to a recursor, we can expect the answer to be signed,
2315 even if the answer is not AA. Of course that's not only true inside a Secure
2316 zone, but we check that below. */
2317 bool expectSignature = i->first.place == DNSResourceRecord::ANSWER || ((lwr.d_aabit || wasForwardRecurse) && i->first.place != DNSResourceRecord::ADDITIONAL);
2318 if (isCNAMEAnswer && (i->first.place != DNSResourceRecord::ANSWER || i->first.type != QType::CNAME || i->first.name != qname)) {
2319 /*
2320 rfc2181 states:
2321 Note that the answer section of an authoritative answer normally
2322 contains only authoritative data. However when the name sought is an
2323 alias (see section 10.1.1) only the record describing that alias is
2324 necessarily authoritative. Clients should assume that other records
2325 may have come from the server's cache. Where authoritative answers
2326 are required, the client should query again, using the canonical name
2327 associated with the alias.
2328 */
2329 isAA = false;
2330 expectSignature = false;
2331 }
2332
2333 if (isCNAMEAnswer && i->first.place == DNSResourceRecord::AUTHORITY && i->first.type == QType::NS && auth == i->first.name) {
2334 /* These NS can't be authoritative since we have a CNAME answer for which (see above) only the
2335 record describing that alias is necessarily authoritative.
2336 But if we allow the current auth, which might be serving the child zone, to raise the TTL
2337 of non-authoritative NS in the cache, they might be able to keep a "ghost" zone alive forever,
2338 even after the delegation is gone from the parent.
2339 So let's just do nothing with them, we can fetch them directly if we need them.
2340 */
2341 LOG(d_prefix<<": skipping authority NS from '"<<auth<<"' nameservers in CNAME answer "<<i->first.name<<"|"<<DNSRecordContent::NumberToType(i->first.type)<<endl);
2342 continue;
2343 }
2344
2345 vState recordState = getValidationStatus(i->first.name, false);
2346 LOG(d_prefix<<": got initial zone status "<<vStates[recordState]<<" for record "<<i->first.name<<"|"<<DNSRecordContent::NumberToType(i->first.type)<<endl);
2347
2348 if (shouldValidate() && recordState == Secure) {
2349 vState initialState = recordState;
2350
2351 if (expectSignature) {
2352 if (i->first.place != DNSResourceRecord::ADDITIONAL) {
2353 /* the additional entries can be insecure,
2354 like glue:
2355 "Glue address RRsets associated with delegations MUST NOT be signed"
2356 */
2357 if (i->first.type == QType::DNSKEY && i->first.place == DNSResourceRecord::ANSWER) {
2358 LOG(d_prefix<<"Validating DNSKEY for "<<i->first.name<<endl);
2359 recordState = validateDNSKeys(i->first.name, i->second.records, i->second.signatures, depth);
2360 }
2361 else {
2362 LOG(d_prefix<<"Validating non-additional record for "<<i->first.name<<endl);
2363 recordState = validateRecordsWithSigs(depth, qname, qtype, i->first.name, i->second.records, i->second.signatures);
2364 /* we might have missed a cut (zone cut within the same auth servers), causing the NS query for an Insecure zone to seem Bogus during zone cut determination */
2365 if (qtype == QType::NS && i->second.signatures.empty() && recordState == Bogus && haveExactValidationStatus(i->first.name) && getValidationStatus(i->first.name) == Indeterminate) {
2366 recordState = Indeterminate;
2367 }
2368 }
2369 }
2370 }
2371 else {
2372 recordState = Indeterminate;
2373
2374 /* in a non authoritative answer, we only care about the DS record (or lack of) */
2375 if ((i->first.type == QType::DS || i->first.type == QType::NSEC || i->first.type == QType::NSEC3) && i->first.place == DNSResourceRecord::AUTHORITY) {
2376 LOG(d_prefix<<"Validating DS record for "<<i->first.name<<endl);
2377 recordState = validateRecordsWithSigs(depth, qname, qtype, i->first.name, i->second.records, i->second.signatures);
2378 }
2379 }
2380
2381 if (initialState == Secure && state != recordState && expectSignature) {
2382 updateValidationState(state, recordState);
2383 }
2384 }
2385 else {
2386 if (shouldValidate()) {
2387 LOG(d_prefix<<"Skipping validation because the current state is "<<vStates[recordState]<<endl);
2388 }
2389 }
2390
2391 if (recordState == Bogus) {
2392 /* this is a TTD by now, be careful */
2393 for(auto& record : i->second.records) {
2394 record.d_ttl = std::min(record.d_ttl, static_cast<uint32_t>(s_maxbogusttl + d_now.tv_sec));
2395 }
2396 }
2397
2398 /* We don't need to store NSEC3 records in the positive cache because:
2399 - we don't allow direct NSEC3 queries
2400 - denial of existence proofs in wildcard expanded positive responses are stored in authorityRecs
2401 - denial of existence proofs for negative responses are stored in the negative cache
2402 We also don't want to cache non-authoritative data except for:
2403 - records coming from non forward-recurse servers (those will never be AA)
2404 - DS (special case)
2405 - NS, A and AAAA (used for infra queries)
2406 */
2407 if (i->first.type != QType::NSEC3 && (i->first.type == QType::DS || i->first.type == QType::NS || i->first.type == QType::A || i->first.type == QType::AAAA || isAA || wasForwardRecurse)) {
2408 t_RC->replace(d_now.tv_sec, i->first.name, QType(i->first.type), i->second.records, i->second.signatures, authorityRecs, i->first.type == QType::DS ? true : isAA, i->first.place == DNSResourceRecord::ANSWER ? ednsmask : boost::none, recordState);
2409 }
2410
2411 if(i->first.place == DNSResourceRecord::ANSWER && ednsmask)
2412 d_wasVariable=true;
2413 }
2414
2415 return RCode::NoError;
2416}
2417
2418void SyncRes::updateDenialValidationState(vState& neValidationState, const DNSName& neName, vState& state, const dState denialState, const dState expectedState, bool allowOptOut)
2419{
2420 if (denialState == expectedState) {
2421 neValidationState = Secure;
2422 }
2423 else {
2424 if (denialState == OPTOUT && allowOptOut) {
2425 LOG(d_prefix<<"OPT-out denial found for "<<neName<<endl);
2426 neValidationState = Secure;
2427 return;
2428 }
2429 else if (denialState == INSECURE) {
2430 LOG(d_prefix<<"Insecure denial found for "<<neName<<", returning Insecure"<<endl);
2431 neValidationState = Insecure;
2432 }
2433 else {
2434 LOG(d_prefix<<"Invalid denial found for "<<neName<<", returning Bogus, res="<<denialState<<", expectedState="<<expectedState<<endl);
2435 neValidationState = Bogus;
2436 }
2437 updateValidationState(state, neValidationState);
2438 }
2439}
2440
2441dState SyncRes::getDenialValidationState(const NegCache::NegCacheEntry& ne, const vState state, const dState expectedState, bool referralToUnsigned)
2442{
2443 cspmap_t csp = harvestCSPFromNE(ne);
2444 return getDenial(csp, ne.d_name, ne.d_qtype.getCode(), referralToUnsigned, expectedState == NXQTYPE);
2445}
2446
2447bool SyncRes::processRecords(const std::string& prefix, const DNSName& qname, const QType& qtype, const DNSName& auth, LWResult& lwr, const bool sendRDQuery, vector<DNSRecord>& ret, set<DNSName>& nsset, DNSName& newtarget, DNSName& newauth, bool& realreferral, bool& negindic, vState& state, const bool needWildcardProof, const unsigned int wildcardLabelsCount)
2448{
2449 bool done = false;
2450
2451 for(auto& rec : lwr.d_records) {
2452 if (rec.d_type!=QType::OPT && rec.d_class!=QClass::IN)
2453 continue;
2454
2455 if (rec.d_place==DNSResourceRecord::ANSWER && !(lwr.d_aabit || sendRDQuery)) {
2456 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2457 are sending such responses */
2458 if (!(rec.d_type == QType::CNAME && rec.d_name == qname)) {
2459 continue;
2460 }
2461 }
2462
2463 if(rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::SOA &&
2464 lwr.d_rcode==RCode::NXDomain && qname.isPartOf(rec.d_name) && rec.d_name.isPartOf(auth)) {
2465 LOG(prefix<<qname<<": got negative caching indication for name '"<<qname<<"' (accept="<<rec.d_name.isPartOf(auth)<<"), newtarget='"<<newtarget<<"'"<<endl);
2466
2467 rec.d_ttl = min(rec.d_ttl, s_maxnegttl);
2468 if(newtarget.empty()) // only add a SOA if we're not going anywhere after this
2469 ret.push_back(rec);
2470
2471 NegCache::NegCacheEntry ne;
2472
2473 uint32_t lowestTTL = rec.d_ttl;
2474 /* if we get an NXDomain answer with a CNAME, the name
2475 does exist but the target does not */
2476 ne.d_name = newtarget.empty() ? qname : newtarget;
2477 ne.d_qtype = QType(0); // this encodes 'whole record'
2478 ne.d_auth = rec.d_name;
2479 harvestNXRecords(lwr.d_records, ne, d_now.tv_sec, &lowestTTL);
2480
2481 if (state == Secure) {
2482 dState denialState = getDenialValidationState(ne, state, NXDOMAIN, false);
2483 updateDenialValidationState(ne.d_validationState, ne.d_name, state, denialState, NXDOMAIN, false);
2484 }
2485 else {
2486 ne.d_validationState = state;
2487 }
2488
2489 if (ne.d_validationState == Bogus) {
2490 lowestTTL = min(lowestTTL, s_maxbogusttl);
2491 }
2492
2493 ne.d_ttd = d_now.tv_sec + lowestTTL;
2494 /* if we get an NXDomain answer with a CNAME, let's not cache the
2495 target, even the server was authoritative for it,
2496 and do an additional query for the CNAME target.
2497 We have a regression test making sure we do exactly that.
2498 */
2499 if(!wasVariable() && newtarget.empty()) {
2500 t_sstorage.negcache.add(ne);
2501 if(s_rootNXTrust && ne.d_auth.isRoot() && auth.isRoot() && lwr.d_aabit) {
2502 ne.d_name = ne.d_name.getLastLabel();
2503 t_sstorage.negcache.add(ne);
2504 }
2505 }
2506
2507 negindic=true;
2508 }
2509 else if(rec.d_place==DNSResourceRecord::ANSWER && rec.d_type==QType::CNAME && (!(qtype==QType(QType::CNAME))) && rec.d_name == qname) {
2510 ret.push_back(rec);
2511 if (auto content = getRR<CNAMERecordContent>(rec)) {
2512 newtarget=content->getTarget();
2513 }
2514 }
2515 /* if we have a positive answer synthetized from a wildcard, we need to
2516 return the corresponding NSEC/NSEC3 records from the AUTHORITY section
2517 proving that the exact name did not exist */
2518 else if(needWildcardProof && (rec.d_type==QType::RRSIG || rec.d_type==QType::NSEC || rec.d_type==QType::NSEC3) && rec.d_place==DNSResourceRecord::AUTHORITY) {
2519 ret.push_back(rec); // enjoy your DNSSEC
2520 }
2521 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
2522 else if(rec.d_place==DNSResourceRecord::ANSWER && rec.d_name == qname &&
2523 (
2524 rec.d_type==qtype.getCode() || ((lwr.d_aabit || sendRDQuery) && qtype == QType(QType::ANY))
2525 )
2526 )
2527 {
2528 LOG(prefix<<qname<<": answer is in: resolved to '"<< rec.d_content->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec.d_type)<<"'"<<endl);
2529
2530 done=true;
2531
2532 if (state == Secure && needWildcardProof) {
2533 /* We have a positive answer synthetized from a wildcard, we need to check that we have
2534 proof that the exact name doesn't exist so the wildcard can be used,
2535 as described in section 5.3.4 of RFC 4035 and 5.3 of FRC 7129.
2536 */
2537 NegCache::NegCacheEntry ne;
2538
2539 uint32_t lowestTTL = rec.d_ttl;
2540 ne.d_name = qname;
2541 ne.d_qtype = QType(0); // this encodes 'whole record'
2542 harvestNXRecords(lwr.d_records, ne, d_now.tv_sec, &lowestTTL);
2543
2544 cspmap_t csp = harvestCSPFromNE(ne);
2545 dState res = getDenial(csp, qname, ne.d_qtype.getCode(), false, false, false, wildcardLabelsCount);
2546 if (res != NXDOMAIN) {
2547 vState st = Bogus;
2548 if (res == INSECURE) {
2549 /* Some part could not be validated, for example a NSEC3 record with a too large number of iterations,
2550 this is not enough to warrant a Bogus, but go Insecure. */
2551 st = Insecure;
2552 LOG(d_prefix<<"Unable to validate denial in wildcard expanded positive response found for "<<qname<<", returning Insecure, res="<<res<<endl);
2553 }
2554 else {
2555 LOG(d_prefix<<"Invalid denial in wildcard expanded positive response found for "<<qname<<", returning Bogus, res="<<res<<endl);
2556 rec.d_ttl = std::min(rec.d_ttl, s_maxbogusttl);
2557 }
2558
2559 updateValidationState(state, st);
2560 /* we already stored the record with a different validation status, let's fix it */
2561 updateValidationStatusInCache(qname, qtype, lwr.d_aabit, st);
2562 }
2563 }
2564 ret.push_back(rec);
2565 }
2566 else if((rec.d_type==QType::RRSIG || rec.d_type==QType::NSEC || rec.d_type==QType::NSEC3) && rec.d_place==DNSResourceRecord::ANSWER) {
2567 if(rec.d_type != QType::RRSIG || rec.d_name == qname)
2568 ret.push_back(rec); // enjoy your DNSSEC
2569 }
2570 else if(rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::NS && qname.isPartOf(rec.d_name)) {
2571 if(moreSpecificThan(rec.d_name,auth)) {
2572 newauth=rec.d_name;
2573 LOG(prefix<<qname<<": got NS record '"<<rec.d_name<<"' -> '"<<rec.d_content->getZoneRepresentation()<<"'"<<endl);
2574 realreferral=true;
2575 }
2576 else {
2577 LOG(prefix<<qname<<": got upwards/level NS record '"<<rec.d_name<<"' -> '"<<rec.d_content->getZoneRepresentation()<<"', had '"<<auth<<"'"<<endl);
2578 }
2579 if (auto content = getRR<NSRecordContent>(rec)) {
2580 nsset.insert(content->getNS());
2581 }
2582 }
2583 else if(rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::DS && qname.isPartOf(rec.d_name)) {
2584 LOG(prefix<<qname<<": got DS record '"<<rec.d_name<<"' -> '"<<rec.d_content->getZoneRepresentation()<<"'"<<endl);
2585 }
2586 else if(realreferral && rec.d_place==DNSResourceRecord::AUTHORITY && (rec.d_type==QType::NSEC || rec.d_type==QType::NSEC3) && newauth.isPartOf(auth)) {
2587 /* we might have received a denial of the DS, let's check */
2588 if (state == Secure) {
2589 NegCache::NegCacheEntry ne;
2590 ne.d_auth = auth;
2591 ne.d_name = newauth;
2592 ne.d_qtype = QType::DS;
2593 rec.d_ttl = min(s_maxnegttl, rec.d_ttl);
2594 uint32_t lowestTTL = rec.d_ttl;
2595 harvestNXRecords(lwr.d_records, ne, d_now.tv_sec, &lowestTTL);
2596
2597 dState denialState = getDenialValidationState(ne, state, NXQTYPE, true);
2598
2599 if (denialState == NXQTYPE || denialState == OPTOUT || denialState == INSECURE) {
2600 ne.d_ttd = lowestTTL + d_now.tv_sec;
2601 ne.d_validationState = Secure;
2602 LOG(prefix<<qname<<": got negative indication of DS record for '"<<newauth<<"'"<<endl);
2603
2604 if(!wasVariable()) {
2605 t_sstorage.negcache.add(ne);
2606 }
2607
2608 if (qname == newauth && qtype == QType::DS) {
2609 /* we are actually done! */
2610 negindic=true;
2611 nsset.clear();
2612 }
2613 }
2614 }
2615 }
2616 else if(!done && rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::SOA &&
2617 lwr.d_rcode==RCode::NoError && qname.isPartOf(rec.d_name)) {
2618 LOG(prefix<<qname<<": got negative caching indication for '"<< qname<<"|"<<qtype.getName()<<"'"<<endl);
2619
2620 if(!newtarget.empty()) {
2621 LOG(prefix<<qname<<": Hang on! Got a redirect to '"<<newtarget<<"' already"<<endl);
2622 }
2623 else {
2624 rec.d_ttl = min(s_maxnegttl, rec.d_ttl);
2625
2626 NegCache::NegCacheEntry ne;
2627 ne.d_auth = rec.d_name;
2628 uint32_t lowestTTL = rec.d_ttl;
2629 ne.d_name = qname;
2630 ne.d_qtype = qtype;
2631 harvestNXRecords(lwr.d_records, ne, d_now.tv_sec, &lowestTTL);
2632
2633 if (state == Secure) {
2634 dState denialState = getDenialValidationState(ne, state, NXQTYPE, false);
2635 updateDenialValidationState(ne.d_validationState, ne.d_name, state, denialState, NXQTYPE, qtype == QType::DS);
2636 } else {
2637 ne.d_validationState = state;
2638 }
2639
2640 if (ne.d_validationState == Bogus) {
2641 lowestTTL = min(lowestTTL, s_maxbogusttl);
2642 rec.d_ttl = min(rec.d_ttl, s_maxbogusttl);
2643 }
2644 ne.d_ttd = d_now.tv_sec + lowestTTL;
2645
2646 if(!wasVariable()) {
2647 if(qtype.getCode()) { // prevents us from blacking out a whole domain
2648 t_sstorage.negcache.add(ne);
2649 }
2650 }
2651
2652 ret.push_back(rec);
2653 negindic=true;
2654 }
2655 }
2656 }
2657
2658 return done;
2659}
2660
2661bool SyncRes::doResolveAtThisIP(const std::string& prefix, const DNSName& qname, const QType& qtype, LWResult& lwr, boost::optional<Netmask>& ednsmask, const DNSName& auth, bool const sendRDQuery, const DNSName& nsName, const ComboAddress& remoteIP, bool doTCP, bool* truncated)
2662{
2663 bool chained = false;
2664 int resolveret = RCode::NoError;
2665 s_outqueries++;
2666 d_outqueries++;
2667
2668 if(d_outqueries + d_throttledqueries > s_maxqperq) {
2669 throw ImmediateServFailException("more than "+std::to_string(s_maxqperq)+" (max-qperq) queries sent while resolving "+qname.toLogString());
2670 }
2671
2672 if(s_maxtotusec && d_totUsec > s_maxtotusec) {
2673 throw ImmediateServFailException("Too much time waiting for "+qname.toLogString()+"|"+qtype.getName()+", timeouts: "+std::to_string(d_timeouts) +", throttles: "+std::to_string(d_throttledqueries) + ", queries: "+std::to_string(d_outqueries)+", "+std::to_string(d_totUsec/1000)+"msec");
2674 }
2675
2676 if(doTCP) {
2677 LOG(prefix<<qname<<": using TCP with "<< remoteIP.toStringWithPort() <<endl);
2678 s_tcpoutqueries++;
2679 d_tcpoutqueries++;
2680 }
2681
2682 if(d_pdl && d_pdl->preoutquery(remoteIP, d_requestor, qname, qtype, doTCP, lwr.d_records, resolveret)) {
2683 LOG(prefix<<qname<<": query handled by Lua"<<endl);
2684 }
2685 else {
2686 ednsmask=getEDNSSubnetMask(qname, remoteIP);
2687 if(ednsmask) {
2688 LOG(prefix<<qname<<": Adding EDNS Client Subnet Mask "<<ednsmask->toString()<<" to query"<<endl);
2689 s_ecsqueries++;
2690 }
2691 resolveret = asyncresolveWrapper(remoteIP, d_doDNSSEC, qname, qtype.getCode(),
2692 doTCP, sendRDQuery, &d_now, ednsmask, &lwr, &chained); // <- we go out on the wire!
2693 if(ednsmask) {
2694 s_ecsresponses++;
2695 LOG(prefix<<qname<<": Received EDNS Client Subnet Mask "<<ednsmask->toString()<<" on response"<<endl);
2696 }
2697 }
2698
2699 /* preoutquery killed the query by setting dq.rcode to -3 */
2700 if(resolveret==-3) {
2701 throw ImmediateServFailException("Query killed by policy");
2702 }
2703
2704 d_totUsec += lwr.d_usec;
2705 accountAuthLatency(lwr.d_usec, remoteIP.sin4.sin_family);
2706
2707 if(resolveret != 1) {
2708 /* Error while resolving */
2709 if(resolveret == 0) {
2710 /* Time out */
2711
2712 LOG(prefix<<qname<<": timeout resolving after "<<lwr.d_usec/1000.0<<"msec "<< (doTCP ? "over TCP" : "")<<endl);
2713 d_timeouts++;
2714 s_outgoingtimeouts++;
2715
2716 if(remoteIP.sin4.sin_family == AF_INET)
2717 s_outgoing4timeouts++;
2718 else
2719 s_outgoing6timeouts++;
2720
2721 if(t_timeouts)
2722 t_timeouts->push_back(remoteIP);
2723 }
2724 else if(resolveret == -2) {
2725 /* OS resource limit reached */
2726 LOG(prefix<<qname<<": hit a local resource limit resolving"<< (doTCP ? " over TCP" : "")<<", probable error: "<<stringerror()<<endl);
2727 g_stats.resourceLimits++;
2728 }
2729 else {
2730 /* -1 means server unreachable */
2731 s_unreachables++;
2732 d_unreachables++;
2733 LOG(prefix<<qname<<": error resolving from "<<remoteIP.toString()<< (doTCP ? " over TCP" : "") <<", possible error: "<<strerror(errno)<< endl);
2734 }
2735
2736 if(resolveret != -2 && !chained) { // don't account for resource limits, they are our own fault
2737 t_sstorage.nsSpeeds[nsName.empty()? DNSName(remoteIP.toStringWithPort()) : nsName].submit(remoteIP, 1000000, &d_now); // 1 sec
2738
2739 // code below makes sure we don't filter COM or the root
2740 if (s_serverdownmaxfails > 0 && (auth != g_rootdnsname) && t_sstorage.fails.incr(remoteIP) >= s_serverdownmaxfails) {
2741 LOG(prefix<<qname<<": Max fails reached resolving on "<< remoteIP.toString() <<". Going full throttle for "<< s_serverdownthrottletime <<" seconds" <<endl);
2742 // mark server as down
2743 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, "", 0), s_serverdownthrottletime, 10000);
2744 }
2745 else if (resolveret == -1) {
2746 // unreachable, 1 minute or 100 queries
2747 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 60, 100);
2748 }
2749 else {
2750 // timeout
2751 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 10, 5);
2752 }
2753 }
2754
2755 return false;
2756 }
2757
2758 /* we got an answer */
2759 if(lwr.d_rcode==RCode::ServFail || lwr.d_rcode==RCode::Refused) {
2760 LOG(prefix<<qname<<": "<<nsName<<" ("<<remoteIP.toString()<<") returned a "<< (lwr.d_rcode==RCode::ServFail ? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl);
2761 if (!chained) {
2762 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 60, 3);
2763 }
2764 return false;
2765 }
2766
2767 /* this server sent a valid answer, mark it backup up if it was down */
2768 if(s_serverdownmaxfails > 0) {
2769 t_sstorage.fails.clear(remoteIP);
2770 }
2771
2772 if(lwr.d_tcbit) {
2773 *truncated = true;
2774
2775 if (doTCP) {
2776 LOG(prefix<<qname<<": truncated bit set, over TCP?"<<endl);
2777 /* let's treat that as a ServFail answer from this server */
2778 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 60, 3);
2779 return false;
2780 }
2781
2782 return true;
2783 }
2784
2785 return true;
2786}
2787
2788bool SyncRes::processAnswer(unsigned int depth, LWResult& lwr, const DNSName& qname, const QType& qtype, DNSName& auth, bool wasForwarded, const boost::optional<Netmask> ednsmask, bool sendRDQuery, NsSet &nameservers, std::vector<DNSRecord>& ret, const DNSFilterEngine& dfe, bool* gotNewServers, int* rcode, vState& state)
2789{
2790 string prefix;
2791 if(doLog()) {
2792 prefix=d_prefix;
2793 prefix.append(depth, ' ');
2794 }
2795
2796 if(s_minimumTTL) {
2797 for(auto& rec : lwr.d_records) {
2798 rec.d_ttl = max(rec.d_ttl, s_minimumTTL);
2799 }
2800 }
2801
2802 bool needWildcardProof = false;
2803 unsigned int wildcardLabelsCount;
2804 *rcode = updateCacheFromRecords(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, state, needWildcardProof, wildcardLabelsCount, sendRDQuery);
2805 if (*rcode != RCode::NoError) {
2806 return true;
2807 }
2808
2809 LOG(prefix<<qname<<": determining status after receiving this packet"<<endl);
2810
2811 set<DNSName> nsset;
2812 bool realreferral=false, negindic=false;
2813 DNSName newauth;
2814 DNSName newtarget;
2815
2816 bool done = processRecords(prefix, qname, qtype, auth, lwr, sendRDQuery, ret, nsset, newtarget, newauth, realreferral, negindic, state, needWildcardProof, wildcardLabelsCount);
2817
2818 if(done){
2819 LOG(prefix<<qname<<": status=got results, this level of recursion done"<<endl);
2820 LOG(prefix<<qname<<": validation status is "<<vStates[state]<<endl);
2821 *rcode = RCode::NoError;
2822 return true;
2823 }
2824
2825 if(!newtarget.empty()) {
2826 if(newtarget == qname) {
2827 LOG(prefix<<qname<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl);
2828 *rcode = RCode::ServFail;
2829 return true;
2830 }
2831
2832 if(depth > 10) {
2833 LOG(prefix<<qname<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl);
2834 *rcode = RCode::ServFail;
2835 return true;
2836 }
2837
2838 if (qtype == QType::DS) {
2839 LOG(prefix<<qname<<": status=got a CNAME referral, but we are looking for a DS"<<endl);
2840
2841 if(d_doDNSSEC)
2842 addNXNSECS(ret, lwr.d_records);
2843
2844 *rcode = RCode::NoError;
2845 return true;
2846 }
2847 else {
2848 LOG(prefix<<qname<<": status=got a CNAME referral, starting over with "<<newtarget<<endl);
2849
2850 set<GetBestNSAnswer> beenthere2;
2851 vState cnameState = Indeterminate;
2852 *rcode = doResolve(newtarget, qtype, ret, depth + 1, beenthere2, cnameState);
2853 LOG(prefix<<qname<<": updating validation state for response to "<<qname<<" from "<<vStates[state]<<" with the state from the CNAME quest: "<<vStates[cnameState]<<endl);
2854 updateValidationState(state, cnameState);
2855 return true;
2856 }
2857 }
2858
2859 if(lwr.d_rcode == RCode::NXDomain) {
2860 LOG(prefix<<qname<<": status=NXDOMAIN, we are done "<<(negindic ? "(have negative SOA)" : "")<<endl);
2861
2862 if(d_doDNSSEC)
2863 addNXNSECS(ret, lwr.d_records);
2864
2865 *rcode = RCode::NXDomain;
2866 return true;
2867 }
2868
2869 if(nsset.empty() && !lwr.d_rcode && (negindic || lwr.d_aabit || sendRDQuery)) {
2870 LOG(prefix<<qname<<": status=noerror, other types may exist, but we are done "<<(negindic ? "(have negative SOA) " : "")<<(lwr.d_aabit ? "(have aa bit) " : "")<<endl);
2871
2872 if(state == Secure && (lwr.d_aabit || sendRDQuery) && !negindic) {
2873 updateValidationState(state, Bogus);
2874 }
2875
2876 if(d_doDNSSEC)
2877 addNXNSECS(ret, lwr.d_records);
2878
2879 *rcode = RCode::NoError;
2880 return true;
2881 }
2882
2883 if(realreferral) {
2884 LOG(prefix<<qname<<": status=did not resolve, got "<<(unsigned int)nsset.size()<<" NS, ");
2885
2886 nameservers.clear();
2887 for (auto const &nameserver : nsset) {
2888 if (d_wantsRPZ) {
2889 d_appliedPolicy = dfe.getProcessingPolicy(nameserver, d_discardedPolicies);
2890 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
2891 LOG("however "<<nameserver<<" was blocked by RPZ policy '"<<(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")<<"'"<<endl);
2892 *rcode = -2;
2893 return true;
2894 }
2895 }
2896 nameservers.insert({nameserver, {{}, false}});
2897 }
2898 LOG("looping to them"<<endl);
2899 *gotNewServers = true;
2900 auth=newauth;
2901
2902 return false;
2903 }
2904
2905 return false;
2906}
2907
2908/** returns:
2909 * -1 in case of no results
2910 * -2 when a FilterEngine Policy was hit
2911 * rcode otherwise
2912 */
2913int SyncRes::doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype,
2914 vector<DNSRecord>&ret,
2915 unsigned int depth, set<GetBestNSAnswer>&beenthere, vState& state)
2916{
2917 auto luaconfsLocal = g_luaconfs.getLocal();
2918 string prefix;
2919 if(doLog()) {
2920 prefix=d_prefix;
2921 prefix.append(depth, ' ');
2922 }
2923
2924 LOG(prefix<<qname<<": Cache consultations done, have "<<(unsigned int)nameservers.size()<<" NS to contact");
2925
2926 if (nameserversBlockedByRPZ(luaconfsLocal->dfe, nameservers)) {
2927 return -2;
2928 }
2929
2930 LOG(endl);
2931
2932 for(;;) { // we may get more specific nameservers
2933 vector<DNSName > rnameservers = shuffleInSpeedOrder(nameservers, doLog() ? (prefix+qname.toString()+": ") : string() );
2934
2935 for(auto tns=rnameservers.cbegin();;++tns) {
2936 if(tns==rnameservers.cend()) {
2937 LOG(prefix<<qname<<": Failed to resolve via any of the "<<(unsigned int)rnameservers.size()<<" offered NS at level '"<<auth<<"'"<<endl);
2938 if(!auth.isRoot() && flawedNSSet) {
2939 LOG(prefix<<qname<<": Ageing nameservers for level '"<<auth<<"', next query might succeed"<<endl);
2940
2941 if(t_RC->doAgeCache(d_now.tv_sec, auth, QType::NS, 10))
2942 g_stats.nsSetInvalidations++;
2943 }
2944 return -1;
2945 }
2946
2947 bool cacheOnly = false;
2948 // this line needs to identify the 'self-resolving' behaviour
2949 if(qname == *tns && (qtype.getCode() == QType::A || qtype.getCode() == QType::AAAA)) {
2950 /* we might have a glue entry in cache so let's try this NS
2951 but only if we have enough in the cache to know how to reach it */
2952 LOG(prefix<<qname<<": Using NS to resolve itself, but only using what we have in cache ("<<(1+tns-rnameservers.cbegin())<<"/"<<rnameservers.size()<<")"<<endl);
2953 cacheOnly = true;
2954 }
2955
2956 typedef vector<ComboAddress> remoteIPs_t;
2957 remoteIPs_t remoteIPs;
2958 remoteIPs_t::const_iterator remoteIP;
2959 bool pierceDontQuery=false;
2960 bool sendRDQuery=false;
2961 boost::optional<Netmask> ednsmask;
2962 LWResult lwr;
2963 const bool wasForwarded = tns->empty() && (!nameservers[*tns].first.empty());
2964 int rcode = RCode::NoError;
2965 bool gotNewServers = false;
2966
2967 if(tns->empty() && !wasForwarded) {
2968 LOG(prefix<<qname<<": Domain is out-of-band"<<endl);
2969 /* setting state to indeterminate since validation is disabled for local auth zone,
2970 and Insecure would be misleading. */
2971 state = Indeterminate;
2972 d_wasOutOfBand = doOOBResolve(qname, qtype, lwr.d_records, depth, lwr.d_rcode);
2973 lwr.d_tcbit=false;
2974 lwr.d_aabit=true;
2975
2976 /* we have received an answer, are we done ? */
2977 bool done = processAnswer(depth, lwr, qname, qtype, auth, false, ednsmask, sendRDQuery, nameservers, ret, luaconfsLocal->dfe, &gotNewServers, &rcode, state);
2978 if (done) {
2979 return rcode;
2980 }
2981 if (gotNewServers) {
2982 break;
2983 }
2984 }
2985 else {
2986 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
2987 remoteIPs = retrieveAddressesForNS(prefix, qname, tns, depth, beenthere, rnameservers, nameservers, sendRDQuery, pierceDontQuery, flawedNSSet, cacheOnly);
2988
2989 if(remoteIPs.empty()) {
2990 LOG(prefix<<qname<<": Failed to get IP for NS "<<*tns<<", trying next if available"<<endl);
2991 flawedNSSet=true;
2992 continue;
2993 }
2994 else {
2995 bool hitPolicy{false};
2996 LOG(prefix<<qname<<": Resolved '"<<auth<<"' NS "<<*tns<<" to: ");
2997 for(remoteIP = remoteIPs.cbegin(); remoteIP != remoteIPs.cend(); ++remoteIP) {
2998 if(remoteIP != remoteIPs.cbegin()) {
2999 LOG(", ");
3000 }
3001 LOG(remoteIP->toString());
3002 if(nameserverIPBlockedByRPZ(luaconfsLocal->dfe, *remoteIP)) {
3003 hitPolicy = true;
3004 }
3005 }
3006 LOG(endl);
3007 if (hitPolicy) //implies d_wantsRPZ
3008 return -2;
3009 }
3010
3011 for(remoteIP = remoteIPs.cbegin(); remoteIP != remoteIPs.cend(); ++remoteIP) {
3012 LOG(prefix<<qname<<": Trying IP "<< remoteIP->toStringWithPort() <<", asking '"<<qname<<"|"<<qtype.getName()<<"'"<<endl);
3013
3014 if (throttledOrBlocked(prefix, *remoteIP, qname, qtype, pierceDontQuery)) {
3015 continue;
3016 }
3017
3018 bool truncated = false;
3019 bool gotAnswer = doResolveAtThisIP(prefix, qname, qtype, lwr, ednsmask, auth, sendRDQuery,
3020 *tns, *remoteIP, false, &truncated);
3021 if (gotAnswer && truncated ) {
3022 /* retry, over TCP this time */
3023 gotAnswer = doResolveAtThisIP(prefix, qname, qtype, lwr, ednsmask, auth, sendRDQuery,
3024 *tns, *remoteIP, true, &truncated);
3025 }
3026
3027 if (!gotAnswer) {
3028 continue;
3029 }
3030
3031 LOG(prefix<<qname<<": Got "<<(unsigned int)lwr.d_records.size()<<" answers from "<<*tns<<" ("<< remoteIP->toString() <<"), rcode="<<lwr.d_rcode<<" ("<<RCode::to_s(lwr.d_rcode)<<"), aa="<<lwr.d_aabit<<", in "<<lwr.d_usec/1000<<"ms"<<endl);
3032
3033 /* // for you IPv6 fanatics :-)
3034 if(remoteIP->sin4.sin_family==AF_INET6)
3035 lwr.d_usec/=3;
3036 */
3037 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
3038
3039 t_sstorage.nsSpeeds[tns->empty()? DNSName(remoteIP->toStringWithPort()) : *tns].submit(*remoteIP, lwr.d_usec, &d_now);
3040
3041 /* we have received an answer, are we done ? */
3042 bool done = processAnswer(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, sendRDQuery, nameservers, ret, luaconfsLocal->dfe, &gotNewServers, &rcode, state);
3043 if (done) {
3044 return rcode;
3045 }
3046 if (gotNewServers) {
3047 break;
3048 }
3049 /* was lame */
3050 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100);
3051 }
3052
3053 if (gotNewServers) {
3054 break;
3055 }
3056
3057 if(remoteIP == remoteIPs.cend()) // we tried all IP addresses, none worked
3058 continue;
3059
3060 }
3061 }
3062 }
3063 return -1;
3064}
3065
3066void SyncRes::setQuerySource(const ComboAddress& requestor, boost::optional<const EDNSSubnetOpts&> incomingECS)
3067{
3068 d_requestor = requestor;
3069
3070 if (incomingECS && incomingECS->source.getBits() > 0) {
3071 d_cacheRemote = incomingECS->source.getMaskedNetwork();
3072 uint8_t bits = std::min(incomingECS->source.getBits(), (incomingECS->source.isIpv4() ? s_ecsipv4limit : s_ecsipv6limit));
3073 ComboAddress trunc = incomingECS->source.getNetwork();
3074 trunc.truncate(bits);
3075 d_outgoingECSNetwork = boost::optional<Netmask>(Netmask(trunc, bits));
3076 } else {
3077 d_cacheRemote = d_requestor;
3078 if(!incomingECS && s_ednslocalsubnets.match(d_requestor)) {
3079 ComboAddress trunc = d_requestor;
3080 uint8_t bits = d_requestor.isIPv4() ? 32 : 128;
3081 bits = std::min(bits, (trunc.isIPv4() ? s_ecsipv4limit : s_ecsipv6limit));
3082 trunc.truncate(bits);
3083 d_outgoingECSNetwork = boost::optional<Netmask>(Netmask(trunc, bits));
3084 } else if (s_ecsScopeZero.source.getBits() > 0) {
3085 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0.
3086 But using an empty ECS in that case would mean inserting
3087 a non ECS-specific entry into the cache, preventing any further
3088 ECS-specific query to be sent.
3089 So instead we use the trick described in section 7.1.2:
3090 "The subsequent Recursive Resolver query to the Authoritative Nameserver
3091 will then either not include an ECS option or MAY optionally include
3092 its own address information, which is what the Authoritative
3093 Nameserver will almost certainly use to generate any Tailored
3094 Response in lieu of an option. This allows the answer to be handled
3095 by the same caching mechanism as other queries, with an explicit
3096 indicator of the applicable scope. Subsequent Stub Resolver queries
3097 for /0 can then be answered from this cached response.
3098 */
3099 d_outgoingECSNetwork = boost::optional<Netmask>(s_ecsScopeZero.source.getMaskedNetwork());
3100 d_cacheRemote = s_ecsScopeZero.source.getNetwork();
3101 } else {
3102 // ECS disabled because no scope-zero address could be derived.
3103 d_outgoingECSNetwork = boost::none;
3104 }
3105 }
3106}
3107
3108boost::optional<Netmask> SyncRes::getEDNSSubnetMask(const DNSName& dn, const ComboAddress& rem)
3109{
3110 if(d_outgoingECSNetwork && (s_ednsdomains.check(dn) || s_ednsremotesubnets.match(rem))) {
3111 return d_outgoingECSNetwork;
3112 }
3113 return boost::none;
3114}
3115
3116void SyncRes::parseEDNSSubnetWhitelist(const std::string& wlist)
3117{
3118 vector<string> parts;
3119 stringtok(parts, wlist, ",; ");
3120 for(const auto& a : parts) {
3121 try {
3122 s_ednsremotesubnets.addMask(Netmask(a));
3123 }
3124 catch(...) {
3125 s_ednsdomains.add(DNSName(a));
3126 }
3127 }
3128}
3129
3130void SyncRes::parseEDNSSubnetAddFor(const std::string& subnetlist)
3131{
3132 vector<string> parts;
3133 stringtok(parts, subnetlist, ",; ");
3134 for(const auto& a : parts) {
3135 s_ednslocalsubnets.addMask(a);
3136 }
3137}
3138
3139// used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
3140int directResolve(const DNSName& qname, const QType& qtype, int qclass, vector<DNSRecord>& ret)
3141{
3142 struct timeval now;
3143 gettimeofday(&now, 0);
3144
3145 SyncRes sr(now);
3146 int res = -1;
3147 try {
3148 res = sr.beginResolve(qname, QType(qtype), qclass, ret);
3149 }
3150 catch(const PDNSException& e) {
3151 g_log<<Logger::Error<<"Failed to resolve "<<qname.toLogString()<<", got pdns exception: "<<e.reason<<endl;
3152 ret.clear();
3153 }
3154 catch(const ImmediateServFailException& e) {
3155 g_log<<Logger::Error<<"Failed to resolve "<<qname.toLogString()<<", got ImmediateServFailException: "<<e.reason<<endl;
3156 ret.clear();
3157 }
3158 catch(const std::exception& e) {
3159 g_log<<Logger::Error<<"Failed to resolve "<<qname.toLogString()<<", got STL error: "<<e.what()<<endl;
3160 ret.clear();
3161 }
3162 catch(...) {
3163 g_log<<Logger::Error<<"Failed to resolve "<<qname.toLogString()<<", got an exception"<<endl;
3164 ret.clear();
3165 }
3166
3167 return res;
3168}
3169
3170int SyncRes::getRootNS(struct timeval now, asyncresolve_t asyncCallback) {
3171 SyncRes sr(now);
3172 sr.setDoEDNS0(true);
3173 sr.setUpdatingRootNS();
3174 sr.setDoDNSSEC(g_dnssecmode != DNSSECMode::Off);
3175 sr.setDNSSECValidationRequested(g_dnssecmode != DNSSECMode::Off && g_dnssecmode != DNSSECMode::ProcessNoValidate);
3176 sr.setAsyncCallback(asyncCallback);
3177
3178 vector<DNSRecord> ret;
3179 int res=-1;
3180 try {
3181 res=sr.beginResolve(g_rootdnsname, QType(QType::NS), 1, ret);
3182 if (g_dnssecmode != DNSSECMode::Off && g_dnssecmode != DNSSECMode::ProcessNoValidate) {
3183 auto state = sr.getValidationState();
3184 if (state == Bogus)
3185 throw PDNSException("Got Bogus validation result for .|NS");
3186 }
3187 return res;
3188 }
3189 catch(const PDNSException& e) {
3190 g_log<<Logger::Error<<"Failed to update . records, got an exception: "<<e.reason<<endl;
3191 }
3192 catch(const ImmediateServFailException& e) {
3193 g_log<<Logger::Error<<"Failed to update . records, got an exception: "<<e.reason<<endl;
3194 }
3195 catch(const std::exception& e) {
3196 g_log<<Logger::Error<<"Failed to update . records, got an exception: "<<e.what()<<endl;
3197 }
3198 catch(...) {
3199 g_log<<Logger::Error<<"Failed to update . records, got an exception"<<endl;
3200 }
3201
3202 if(!res) {
3203 g_log<<Logger::Notice<<"Refreshed . records"<<endl;
3204 }
3205 else
3206 g_log<<Logger::Error<<"Failed to update . records, RCODE="<<res<<endl;
3207
3208 return res;
3209}