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