2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
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.
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.
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.
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.
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"
33 #include "lua-recursor4.hh"
34 #include "rec-lua-conf.hh"
36 #include "dnsseckeeper.hh"
37 #include "validate-recursor.hh"
39 thread_local
SyncRes::ThreadLocalStorage
SyncRes::t_sstorage
;
40 thread_local
std::unique_ptr
<addrringbuf_t
> t_timeouts
;
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 const std::unordered_set
<uint16_t> SyncRes::s_redirectionQTypes
= {QType::CNAME
, QType::DNAME
};
52 unsigned int SyncRes::s_maxnegttl
;
53 unsigned int SyncRes::s_maxbogusttl
;
54 unsigned int SyncRes::s_maxcachettl
;
55 unsigned int SyncRes::s_maxqperq
;
56 unsigned int SyncRes::s_maxtotusec
;
57 unsigned int SyncRes::s_maxdepth
;
58 unsigned int SyncRes::s_minimumTTL
;
59 unsigned int SyncRes::s_minimumECSTTL
;
60 unsigned int SyncRes::s_packetcachettl
;
61 unsigned int SyncRes::s_packetcacheservfailttl
;
62 unsigned int SyncRes::s_serverdownmaxfails
;
63 unsigned int SyncRes::s_serverdownthrottletime
;
64 unsigned int SyncRes::s_ecscachelimitttl
;
65 std::atomic
<uint64_t> SyncRes::s_authzonequeries
;
66 std::atomic
<uint64_t> SyncRes::s_queries
;
67 std::atomic
<uint64_t> SyncRes::s_outgoingtimeouts
;
68 std::atomic
<uint64_t> SyncRes::s_outgoing4timeouts
;
69 std::atomic
<uint64_t> SyncRes::s_outgoing6timeouts
;
70 std::atomic
<uint64_t> SyncRes::s_outqueries
;
71 std::atomic
<uint64_t> SyncRes::s_tcpoutqueries
;
72 std::atomic
<uint64_t> SyncRes::s_throttledqueries
;
73 std::atomic
<uint64_t> SyncRes::s_dontqueries
;
74 std::atomic
<uint64_t> SyncRes::s_nodelegated
;
75 std::atomic
<uint64_t> SyncRes::s_unreachables
;
76 std::atomic
<uint64_t> SyncRes::s_ecsqueries
;
77 std::atomic
<uint64_t> SyncRes::s_ecsresponses
;
78 std::map
<uint8_t, std::atomic
<uint64_t>> SyncRes::s_ecsResponsesBySubnetSize4
;
79 std::map
<uint8_t, std::atomic
<uint64_t>> SyncRes::s_ecsResponsesBySubnetSize6
;
81 uint8_t SyncRes::s_ecsipv4limit
;
82 uint8_t SyncRes::s_ecsipv6limit
;
83 uint8_t SyncRes::s_ecsipv4cachelimit
;
84 uint8_t SyncRes::s_ecsipv6cachelimit
;
86 bool SyncRes::s_doIPv6
;
87 bool SyncRes::s_nopacketcache
;
88 bool SyncRes::s_rootNXTrust
;
89 bool SyncRes::s_noEDNS
;
90 bool SyncRes::s_qnameminimization
;
92 #define LOG(x) if(d_lm == Log) { g_log <<Logger::Warning << x; } else if(d_lm == Store) { d_trace << x; }
94 static void accountAuthLatency(int usec
, int family
)
96 if(family
== AF_INET
) {
98 g_stats
.auth4Answers0_1
++;
100 g_stats
.auth4Answers1_10
++;
101 else if(usec
< 100000)
102 g_stats
.auth4Answers10_100
++;
103 else if(usec
< 1000000)
104 g_stats
.auth4Answers100_1000
++;
106 g_stats
.auth4AnswersSlow
++;
109 g_stats
.auth6Answers0_1
++;
110 else if(usec
< 10000)
111 g_stats
.auth6Answers1_10
++;
112 else if(usec
< 100000)
113 g_stats
.auth6Answers10_100
++;
114 else if(usec
< 1000000)
115 g_stats
.auth6Answers100_1000
++;
117 g_stats
.auth6AnswersSlow
++;
123 SyncRes::SyncRes(const struct timeval
& now
) : d_authzonequeries(0), d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
124 d_totUsec(0), d_now(now
),
125 d_cacheonly(false), d_doDNSSEC(false), d_doEDNS0(false), d_qNameMinimization(s_qnameminimization
), d_lm(s_lm
)
130 /** everything begins here - this is the entry point just after receiving a packet */
131 int SyncRes::beginResolve(const DNSName
&qname
, const QType
&qtype
, uint16_t qclass
, vector
<DNSRecord
>&ret
)
133 vState state
= Indeterminate
;
136 d_wasOutOfBand
=false;
138 if (doSpecialNamesResolve(qname
, qtype
, qclass
, ret
)) {
139 d_queryValidationState
= Insecure
; // this could fool our stats into thinking a validation took place
140 return 0; // so do check before updating counters (we do now)
143 auto qtypeCode
= qtype
.getCode();
144 /* rfc6895 section 3.1 */
145 if ((qtypeCode
>= 128 && qtypeCode
<= 254) || qtypeCode
== QType::RRSIG
|| qtypeCode
== QType::NSEC3
|| qtypeCode
== QType::OPT
|| qtypeCode
== 65535) {
149 if(qclass
==QClass::ANY
)
151 else if(qclass
!=QClass::IN
)
154 set
<GetBestNSAnswer
> beenthere
;
155 int res
=doResolve(qname
, qtype
, ret
, 0, beenthere
, state
);
156 d_queryValidationState
= state
;
158 if (shouldValidate()) {
159 if (d_queryValidationState
!= Indeterminate
) {
160 g_stats
.dnssecValidations
++;
162 increaseDNSSECStateCounter(d_queryValidationState
);
168 /*! Handles all special, built-in names
169 * Fills ret with an answer and returns true if it handled the query.
171 * Handles the following queries (and their ANY variants):
174 * - localhost. IN AAAA
175 * - 1.0.0.127.in-addr.arpa. IN PTR
176 * - 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
177 * - version.bind. CH TXT
178 * - version.pdns. CH TXT
179 * - id.server. CH TXT
181 bool SyncRes::doSpecialNamesResolve(const DNSName
&qname
, const QType
&qtype
, const uint16_t qclass
, vector
<DNSRecord
> &ret
)
183 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."),
184 localhost("localhost."), versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns.");
186 bool handled
= false;
187 vector
<pair
<QType::typeenum
, string
> > answers
;
189 if ((qname
== arpa
|| qname
== ip6_arpa
) &&
190 qclass
== QClass::IN
) {
192 if (qtype
== QType::PTR
|| qtype
== QType::ANY
)
193 answers
.push_back({QType::PTR
, "localhost."});
196 if (qname
== localhost
&&
197 qclass
== QClass::IN
) {
199 if (qtype
== QType::A
|| qtype
== QType::ANY
)
200 answers
.push_back({QType::A
, "127.0.0.1"});
201 if (qtype
== QType::AAAA
|| qtype
== QType::ANY
)
202 answers
.push_back({QType::AAAA
, "::1"});
205 if ((qname
== versionbind
|| qname
== idserver
|| qname
== versionpdns
) &&
206 qclass
== QClass::CHAOS
) {
208 if (qtype
== QType::TXT
|| qtype
== QType::ANY
) {
209 if(qname
== versionbind
|| qname
== versionpdns
)
210 answers
.push_back({QType::TXT
, "\""+::arg()["version-string"]+"\""});
211 else if (s_serverID
!= "disabled")
212 answers
.push_back({QType::TXT
, "\""+s_serverID
+"\""});
216 if (handled
&& !answers
.empty()) {
222 dr
.d_place
= DNSResourceRecord::ANSWER
;
225 for (const auto& ans
: answers
) {
226 dr
.d_type
= ans
.first
;
227 dr
.d_content
= DNSRecordContent::mastermake(ans
.first
, qclass
, ans
.second
);
236 //! This is the 'out of band resolver', in other words, the authoritative server
237 void SyncRes::AuthDomain::addSOA(std::vector
<DNSRecord
>& records
) const
239 SyncRes::AuthDomain::records_t::const_iterator ziter
= d_records
.find(boost::make_tuple(getName(), QType::SOA
));
240 if (ziter
!= d_records
.end()) {
241 DNSRecord dr
= *ziter
;
242 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
243 records
.push_back(dr
);
246 // cerr<<qname<<": can't find SOA record '"<<getName()<<"' in our zone!"<<endl;
250 int SyncRes::AuthDomain::getRecords(const DNSName
& qname
, uint16_t qtype
, std::vector
<DNSRecord
>& records
) const
252 int result
= RCode::NoError
;
256 std::pair
<records_t::const_iterator
,records_t::const_iterator
> range
= d_records
.equal_range(tie(qname
));
258 SyncRes::AuthDomain::records_t::const_iterator ziter
;
259 bool somedata
= false;
261 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
264 if(qtype
== QType::ANY
|| ziter
->d_type
== qtype
|| ziter
->d_type
== QType::CNAME
) {
265 // let rest of nameserver do the legwork on this one
266 records
.push_back(*ziter
);
268 else if (ziter
->d_type
== QType::NS
&& ziter
->d_name
.countLabels() > getName().countLabels()) {
269 // we hit a delegation point!
270 DNSRecord dr
= *ziter
;
271 dr
.d_place
=DNSResourceRecord::AUTHORITY
;
272 records
.push_back(dr
);
276 if (!records
.empty()) {
277 /* We have found an exact match, we're done */
278 // cerr<<qname<<": exact match in zone '"<<getName()<<"'"<<endl;
283 /* We have records for that name, but not of the wanted qtype */
284 // cerr<<qname<<": found record in '"<<getName()<<"', but nothing of the right type, sending SOA"<<endl;
290 // cerr<<qname<<": nothing found so far in '"<<getName()<<"', trying wildcards"<<endl;
291 DNSName
wcarddomain(qname
);
292 while(wcarddomain
!= getName() && wcarddomain
.chopOff()) {
293 // cerr<<qname<<": trying '*."<<wcarddomain<<"' in "<<getName()<<endl;
294 range
= d_records
.equal_range(boost::make_tuple(g_wildcarddnsname
+ wcarddomain
));
295 if (range
.first
==range
.second
)
298 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
299 DNSRecord dr
= *ziter
;
300 // if we hit a CNAME, just answer that - rest of recursor will do the needful & follow
301 if(dr
.d_type
== qtype
|| qtype
== QType::ANY
|| dr
.d_type
== QType::CNAME
) {
303 dr
.d_place
= DNSResourceRecord::ANSWER
;
304 records
.push_back(dr
);
308 if (records
.empty()) {
312 // cerr<<qname<<": in '"<<getName()<<"', had wildcard match on '*."<<wcarddomain<<"'"<<endl;
316 /* Nothing for this name, no wildcard, let's see if there is some NS */
317 DNSName
nsdomain(qname
);
318 while (nsdomain
.chopOff() && nsdomain
!= getName()) {
319 range
= d_records
.equal_range(boost::make_tuple(nsdomain
,QType::NS
));
320 if(range
.first
== range
.second
)
323 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
324 DNSRecord dr
= *ziter
;
325 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
326 records
.push_back(dr
);
330 if(records
.empty()) {
331 // cerr<<qname<<": no NS match in zone '"<<getName()<<"' either, handing out SOA"<<endl;
333 result
= RCode::NXDomain
;
339 bool SyncRes::doOOBResolve(const AuthDomain
& domain
, const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, int& res
)
344 res
= domain
.getRecords(qname
, qtype
.getCode(), ret
);
348 bool SyncRes::doOOBResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int& res
)
353 prefix
.append(depth
, ' ');
356 DNSName
authdomain(qname
);
357 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
358 if(iter
==t_sstorage
.domainmap
->end() || !iter
->second
.isAuth()) {
359 LOG(prefix
<<qname
<<": auth storage has no zone for this query!"<<endl
);
363 LOG(prefix
<<qname
<<": auth storage has data, zone='"<<authdomain
<<"'"<<endl
);
364 return doOOBResolve(iter
->second
, qname
, qtype
, ret
, res
);
367 uint64_t SyncRes::doEDNSDump(int fd
)
369 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(dup(fd
), "w"), fclose
);
375 fprintf(fp
.get(),"; edns from thread follows\n;\n");
376 for(const auto& eds
: t_sstorage
.ednsstatus
) {
378 fprintf(fp
.get(), "%s\t%d\t%s", eds
.first
.toString().c_str(), (int)eds
.second
.mode
, ctime(&eds
.second
.modeSetAt
));
383 uint64_t SyncRes::doDumpNSSpeeds(int fd
)
385 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(dup(fd
), "w"), fclose
);
388 fprintf(fp
.get(), "; nsspeed dump from thread follows\n;\n");
391 for(const auto& i
: t_sstorage
.nsSpeeds
)
395 // an <empty> can appear hear in case of authoritative (hosted) zones
396 fprintf(fp
.get(), "%s -> ", i
.first
.toLogString().c_str());
397 for(const auto& j
: i
.second
.d_collection
)
399 // typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
400 fprintf(fp
.get(), "%s/%f ", j
.first
.toString().c_str(), j
.second
.peek());
402 fprintf(fp
.get(), "\n");
407 uint64_t SyncRes::doDumpThrottleMap(int fd
)
409 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(dup(fd
), "w"), fclose
);
412 fprintf(fp
.get(), "; throttle map dump follows\n");
413 fprintf(fp
.get(), "; remote IP\tqname\tqtype\tcount\tttd\n");
416 const auto& throttleMap
= t_sstorage
.throttle
.getThrottleMap();
417 for(const auto& i
: throttleMap
)
420 // remote IP, dns name, qtype, count, ttd
421 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
));
427 /* so here is the story. First we complete the full resolution process for a domain name. And only THEN do we decide
428 to also do DNSSEC validation, which leads to new queries. To make this simple, we *always* ask for DNSSEC records
429 so that if there are RRSIGs for a name, we'll have them.
431 However, some hosts simply can't answer questions which ask for DNSSEC. This can manifest itself as:
436 The cause of "No answer" may be fragmentation, and it is tempting to probe if smaller answers would get through.
437 Another cause of "No answer" may simply be a network condition.
438 Nonsense answers are a clearer indication this host won't be able to do DNSSEC evah.
440 Previous implementations have suffered from turning off DNSSEC questions for an authoritative server based on timeouts.
441 A clever idea is to only turn off DNSSEC if we know a domain isn't signed anyhow. The problem with that really
442 clever idea however is that at this point in PowerDNS, we may simply not know that yet. All the DNSSEC thinking happens
443 elsewhere. It may not have happened yet.
445 For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish.
448 int SyncRes::asyncresolveWrapper(const ComboAddress
& ip
, bool ednsMANDATORY
, const DNSName
& domain
, const DNSName
& auth
, int type
, bool doTCP
, bool sendRDQuery
, struct timeval
* now
, boost::optional
<Netmask
>& srcmask
, LWResult
* res
, bool* chained
) const
450 /* what is your QUEST?
451 the goal is to get as many remotes as possible on the highest level of EDNS support
454 0) UNKNOWN Unknown state
455 1) EDNS: Honors EDNS0
456 2) EDNSIGNORANT: Ignores EDNS0, gives replies without EDNS0
457 3) NOEDNS: Generates FORMERR on EDNS queries
459 Everybody starts out assumed to be '0'.
460 If '0', send out EDNS0
461 If you FORMERR us, go to '3',
462 If no EDNS in response, go to '2'
463 If '1', send out EDNS0
464 If FORMERR, downgrade to 3
465 If '2', keep on including EDNS0, see what happens
467 If '3', send bare queries
470 SyncRes::EDNSStatus
* ednsstatus
;
471 ednsstatus
= &t_sstorage
.ednsstatus
[ip
]; // does this include port? YES
473 if(ednsstatus
->modeSetAt
&& ednsstatus
->modeSetAt
+ 3600 < d_now
.tv_sec
) {
474 *ednsstatus
=SyncRes::EDNSStatus();
475 // cerr<<"Resetting EDNS Status for "<<ip.toString()<<endl);
478 SyncRes::EDNSStatus::EDNSMode
& mode
=ednsstatus
->mode
;
479 SyncRes::EDNSStatus::EDNSMode oldmode
= mode
;
481 auto luaconfsLocal
= g_luaconfs
.getLocal();
484 ctx
.d_initialRequestId
= d_initialRequestId
;
491 for(int tries
= 0; tries
< 3; ++tries
) {
492 // cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl;
494 if(mode
==EDNSStatus::NOEDNS
) {
495 g_stats
.noEdnsOutQueries
++;
496 EDNSLevel
= 0; // level != mode
498 else if(ednsMANDATORY
|| mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
==EDNSStatus::EDNSIGNORANT
)
501 DNSName
sendQname(domain
);
502 if (g_lowercaseOutgoing
)
503 sendQname
.makeUsLowerCase();
505 if (d_asyncResolve
) {
506 ret
= d_asyncResolve(ip
, sendQname
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, res
, chained
);
509 ret
=asyncresolve(ip
, sendQname
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, d_outgoingProtobufServers
, d_frameStreamServers
, luaconfsLocal
->outgoingProtobufExportConfig
.exportTypes
, res
, chained
);
512 return ret
; // transport error, nothing to learn here
515 if(ret
== 0) { // timeout, not doing anything with it now
518 else if(mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
== EDNSStatus::EDNSIGNORANT
) {
519 if(res
->d_validpacket
&& !res
->d_haveEDNS
&& res
->d_rcode
== RCode::FormErr
) {
520 // cerr<<"Downgrading to NOEDNS because of "<<RCode::to_s(res->d_rcode)<<" for query to "<<ip.toString()<<" for '"<<domain<<"'"<<endl;
521 mode
= EDNSStatus::NOEDNS
;
524 else if(!res
->d_haveEDNS
) {
525 if(mode
!= EDNSStatus::EDNSIGNORANT
) {
526 mode
= EDNSStatus::EDNSIGNORANT
;
527 // cerr<<"We find that "<<ip.toString()<<" is an EDNS-ignorer for '"<<domain<<"', moving to mode 2"<<endl;
531 mode
= EDNSStatus::EDNSOK
;
532 // cerr<<"We find that "<<ip.toString()<<" is EDNS OK!"<<endl;
536 if(oldmode
!= mode
|| !ednsstatus
->modeSetAt
)
537 ednsstatus
->modeSetAt
=d_now
.tv_sec
;
538 // cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", new mode: "<<mode<<endl;
544 #define QLOG(x) LOG(prefix << " child=" << child << ": " << x << endl)
546 int SyncRes::doResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, vState
& state
) {
548 if (!getQNameMinimization()) {
549 return doResolveNoQNameMinimization(qname
, qtype
, ret
, depth
, beenthere
, state
);
552 // The qname minimization algorithm is a simplified version of the one in RFC 7816 (bis).
553 // It could be simplified because the cache maintenance (both positive and negative)
554 // is already done by doResolveNoQNameMinimization().
556 // Sketch of algorithm:
558 // If result found: done
559 // Otherwise determine closes ancestor from cache data
560 // Repeat querying A, adding more labels of the original qname
561 // If we get a delegation continue at ancestor determination
562 // Until we have the full name.
564 // The algorithm starts with adding a single label per iteration, and
565 // moves to three labels per iteration after three iterations.
568 string prefix
= d_prefix
;
569 prefix
.append(depth
, ' ');
570 prefix
.append(string("QM ") + qname
.toString() + "|" + qtype
.getName());
574 // Look in cache only
575 vector
<DNSRecord
> retq
;
576 bool old
= setCacheOnly(true);
577 bool fromCache
= false;
578 int res
= doResolveNoQNameMinimization(qname
, qtype
, retq
, depth
+ 1, beenthere
, state
, &fromCache
);
581 QLOG("Step0 Found in cache");
582 ret
.insert(ret
.end(), retq
.begin(), retq
.end());
585 QLOG("Step0 Not cached");
587 const unsigned int qnamelen
= qname
.countLabels();
589 for (unsigned int i
= 0; i
<= qnamelen
; ) {
592 vector
<DNSRecord
> bestns
;
593 // the two retries allow getBestNSFromCache&co to reprime the root
594 // hints, in case they ever go missing
595 for (int tries
= 0; tries
< 2 && bestns
.empty(); ++tries
) {
596 bool flawedNSSet
= false;
597 set
<GetBestNSAnswer
> beenthereIgnored
;
598 getBestNSFromCache(qname
, qtype
, bestns
, &flawedNSSet
, depth
+ 1, beenthereIgnored
);
601 if (bestns
.size() > 0) {
602 ancestor
= bestns
[0].d_name
;
603 QLOG("Step1 Ancestor from cache is " << ancestor
.toString());
605 QLOG("Step1 No ancestor found return ServFail");
606 return RCode::ServFail
;
611 unsigned int targetlen
= std::min(child
.countLabels() + (i
> 3 ? 3 : 1), qnamelen
);
613 for (; i
<= qnamelen
; i
++) {
615 while (child
.countLabels() < targetlen
) {
616 child
.prependRawLabel(qname
.getRawLabel(qnamelen
- child
.countLabels() - 1));
618 targetlen
+= i
> 3 ? 3 : 1;
619 targetlen
= std::min(targetlen
, qnamelen
);
621 QLOG("Step2 New child");
624 if (child
== qname
) {
625 QLOG("Step3 Going to do final resolve");
626 res
= doResolveNoQNameMinimization(qname
, qtype
, ret
, depth
+ 1, beenthere
, state
);
627 QLOG("Step3 Final resolve: " << RCode::to_s(res
) << "/" << ret
.size() << endl
);
632 QLOG("Step4 Resolve A for child");
634 StopAtDelegation stopAtDelegation
= Stop
;
635 res
= doResolveNoQNameMinimization(child
, QType::A
, retq
, depth
+ 1, beenthere
, state
, NULL
, &stopAtDelegation
);
636 QLOG("Step4 Resolve A result is " << RCode::to_s(res
) << "/" << retq
.size() << "/" << stopAtDelegation
);
637 if (stopAtDelegation
== Stopped
) {
638 QLOG("Delegation seen, continue at step 1");
641 if (res
!= RCode::NoError
) {
642 // Case 5: unexpected answer
643 QLOG("Step5: other rcode, last effort final resolve");
644 setQNameMinimization(false);
645 res
= doResolveNoQNameMinimization(qname
, qtype
, ret
, depth
+ 1, beenthere
, state
);
646 QLOG("Step5 End resolve: " << RCode::to_s(res
) << "/" << ret
.size() << endl
);
652 // Should not be reached
653 QLOG("Max iterations reached, return ServFail");
654 return RCode::ServFail
;
657 /*! This function will check the cache and go out to the internet if the answer is not in cache
659 * \param qname The name we need an answer for
661 * \param ret The vector of DNSRecords we need to fill with the answers
662 * \param depth The recursion depth we are in
664 * \return DNS RCODE or -1 (Error) or -2 (RPZ hit)
666 int SyncRes::doResolveNoQNameMinimization(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, vState
& state
, bool *fromCache
, StopAtDelegation
*stopAtDelegation
)
671 prefix
.append(depth
, ' ');
674 LOG(prefix
<<qname
<<": Wants "<< (d_doDNSSEC
? "" : "NO ") << "DNSSEC processing, "<<(d_requireAuthData
? "" : "NO ")<<"auth data in query for "<<qtype
.getName()<<endl
);
676 state
= Indeterminate
;
678 if(s_maxdepth
&& depth
> s_maxdepth
)
679 throw ImmediateServFailException("More than "+std::to_string(s_maxdepth
)+" (max-recursion-depth) levels of recursion needed while resolving "+qname
.toLogString());
683 // This is a difficult way of expressing "this is a normal query", i.e. not getRootNS.
684 if(!(d_updatingRootNS
&& qtype
.getCode()==QType::NS
&& qname
.isRoot())) {
685 if(d_cacheonly
) { // very limited OOB support
687 LOG(prefix
<<qname
<<": Recursion not requested for '"<<qname
<<"|"<<qtype
.getName()<<"', peeking at auth/forward zones"<<endl
);
688 DNSName
authname(qname
);
689 domainmap_t::const_iterator iter
=getBestAuthZone(&authname
);
690 if(iter
!= t_sstorage
.domainmap
->end()) {
691 if(iter
->second
.isAuth()) {
693 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, ret
, depth
, res
);
695 *fromCache
= d_wasOutOfBand
;
699 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
700 const ComboAddress remoteIP
= servers
.front();
701 LOG(prefix
<<qname
<<": forwarding query to hardcoded nameserver '"<< remoteIP
.toStringWithPort()<<"' for zone '"<<authname
<<"'"<<endl
);
703 boost::optional
<Netmask
> nm
;
704 bool chained
= false;
705 res
=asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, authname
, qtype
.getCode(), false, false, &d_now
, nm
, &lwr
, &chained
);
707 d_totUsec
+= lwr
.d_usec
;
708 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
712 // filter out the good stuff from lwr.result()
714 for(const auto& rec
: lwr
.d_records
) {
715 if(rec
.d_place
== DNSResourceRecord::ANSWER
)
721 return RCode::ServFail
;
727 DNSName
authname(qname
);
728 bool wasForwardedOrAuthZone
= false;
729 bool wasAuthZone
= false;
730 bool wasForwardRecurse
= false;
731 domainmap_t::const_iterator iter
= getBestAuthZone(&authname
);
732 if(iter
!= t_sstorage
.domainmap
->end()) {
733 const auto& domain
= iter
->second
;
734 wasForwardedOrAuthZone
= true;
736 if (domain
.isAuth()) {
738 } else if (domain
.shouldRecurse()) {
739 wasForwardRecurse
= true;
743 if(!d_skipCNAMECheck
&& doCNAMECacheCheck(qname
, qtype
, ret
, depth
, res
, state
, wasAuthZone
, wasForwardRecurse
)) { // will reroute us if needed
744 d_wasOutOfBand
= wasAuthZone
;
748 if(doCacheCheck(qname
, authname
, wasForwardedOrAuthZone
, wasAuthZone
, wasForwardRecurse
, qtype
, ret
, depth
, res
, state
)) {
750 d_wasOutOfBand
= wasAuthZone
;
761 LOG(prefix
<<qname
<<": No cache hit for '"<<qname
<<"|"<<qtype
.getName()<<"', trying to find an appropriate NS record"<<endl
);
763 DNSName
subdomain(qname
);
764 if(qtype
== QType::DS
) subdomain
.chopOff();
767 bool flawedNSSet
=false;
769 /* we use subdomain here instead of qname because for DS queries we only care about the state of the parent zone */
770 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
772 // the two retries allow getBestNSNamesFromCache&co to reprime the root
773 // hints, in case they ever go missing
774 for(int tries
=0;tries
<2 && nsset
.empty();++tries
) {
775 subdomain
=getBestNSNamesFromCache(subdomain
, qtype
, nsset
, &flawedNSSet
, depth
, beenthere
); // pass beenthere to both occasions
778 state
= getValidationStatus(qname
, false);
780 LOG(prefix
<<qname
<<": initial validation status for "<<qname
<<" is "<<vStates
[state
]<<endl
);
782 if(!(res
=doResolveAt(nsset
, subdomain
, flawedNSSet
, qname
, qtype
, ret
, depth
, beenthere
, state
, stopAtDelegation
)))
785 LOG(prefix
<<qname
<<": failed (res="<<res
<<")"<<endl
);
790 return res
<0 ? RCode::ServFail
: res
;
794 // for testing purposes
795 static bool ipv6First(const ComboAddress
& a
, const ComboAddress
& b
)
797 return !(a
.sin4
.sin_family
< a
.sin4
.sin_family
);
803 speedOrderCA(std::map
<ComboAddress
,double>& speeds
): d_speeds(speeds
) {}
804 bool operator()(const ComboAddress
& a
, const ComboAddress
& b
) const
806 return d_speeds
[a
] < d_speeds
[b
];
808 std::map
<ComboAddress
, double>& d_speeds
;
811 /** This function explicitly goes out for A or AAAA addresses
813 vector
<ComboAddress
> SyncRes::getAddrs(const DNSName
&qname
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, bool cacheOnly
)
815 typedef vector
<DNSRecord
> res_t
;
816 typedef vector
<ComboAddress
> ret_t
;
819 bool oldCacheOnly
= setCacheOnly(cacheOnly
);
820 bool oldRequireAuthData
= d_requireAuthData
;
821 bool oldValidationRequested
= d_DNSSECValidationRequested
;
822 d_requireAuthData
= false;
823 d_DNSSECValidationRequested
= false;
825 vState newState
= Indeterminate
;
827 // If IPv4 ever becomes second class, we should revisit this
828 if (doResolve(qname
, QType::A
, resv4
, depth
+1, beenthere
, newState
) == 0) { // this consults cache, OR goes out
829 for (auto const &i
: resv4
) {
830 if (i
.d_type
== QType::A
) {
831 if (auto rec
= getRR
<ARecordContent
>(i
)) {
832 ret
.push_back(rec
->getCA(53));
839 // We did not find IPv4 addresses, try to get IPv6 ones
840 newState
= Indeterminate
;
842 if (doResolve(qname
, QType::AAAA
, resv6
, depth
+1, beenthere
, newState
) == 0) { // this consults cache, OR goes out
843 for (const auto &i
: resv6
) {
844 if (i
.d_type
== QType::AAAA
) {
845 if (auto rec
= getRR
<AAAARecordContent
>(i
))
846 ret
.push_back(rec
->getCA(53));
851 // We have some IPv4 records, don't bother with going out to get IPv6, but do consult the cache
852 // Once IPv6 adoption matters, this needs to be revisited
854 if (t_RC
->get(d_now
.tv_sec
, qname
, QType(QType::AAAA
), false, &cset
, d_cacheRemote
) > 0) {
855 for (const auto &i
: cset
) {
856 if (i
.d_ttl
> (unsigned int)d_now
.tv_sec
) {
857 if (auto rec
= getRR
<AAAARecordContent
>(i
)) {
858 ret
.push_back(rec
->getCA(53));
866 d_requireAuthData
= oldRequireAuthData
;
867 d_DNSSECValidationRequested
= oldValidationRequested
;
868 setCacheOnly(oldCacheOnly
);
870 /* we need to remove from the nsSpeeds collection the existing IPs
871 for this nameserver that are no longer in the set, even if there
872 is only one or none at all in the current set.
874 map
<ComboAddress
, double> speeds
;
875 auto& collection
= t_sstorage
.nsSpeeds
[qname
].d_collection
;
876 for(const auto& val
: ret
) {
877 speeds
[val
] = collection
[val
].get(&d_now
);
880 t_sstorage
.nsSpeeds
[qname
].purge(speeds
);
883 random_shuffle(ret
.begin(), ret
.end());
884 speedOrderCA
so(speeds
);
885 stable_sort(ret
.begin(), ret
.end(), so
);
888 string prefix
=d_prefix
;
889 prefix
.append(depth
, ' ');
890 LOG(prefix
<<"Nameserver "<<qname
<<" IPs: ");
892 for(const auto& addr
: ret
) {
899 LOG((addr
.toString())<<"(" << (boost::format("%0.2f") % (speeds
[addr
]/1000.0)).str() <<"ms)");
908 void SyncRes::getBestNSFromCache(const DNSName
&qname
, const QType
& qtype
, vector
<DNSRecord
>& bestns
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
)
911 DNSName
subdomain(qname
);
914 prefix
.append(depth
, ' ');
920 LOG(prefix
<<qname
<<": Checking if we have NS in cache for '"<<subdomain
<<"'"<<endl
);
921 vector
<DNSRecord
> ns
;
922 *flawedNSSet
= false;
924 if(t_RC
->get(d_now
.tv_sec
, subdomain
, QType(QType::NS
), false, &ns
, d_cacheRemote
) > 0) {
925 bestns
.reserve(ns
.size());
927 for(auto k
=ns
.cbegin();k
!=ns
.cend(); ++k
) {
928 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
929 vector
<DNSRecord
> aset
;
931 const DNSRecord
& dr
=*k
;
932 auto nrr
= getRR
<NSRecordContent
>(dr
);
933 if(nrr
&& (!nrr
->getNS().isPartOf(subdomain
) || t_RC
->get(d_now
.tv_sec
, nrr
->getNS(), s_doIPv6
? QType(QType::ADDR
) : QType(QType::A
),
934 false, doLog() ? &aset
: 0, d_cacheRemote
) > 5)) {
935 bestns
.push_back(dr
);
936 LOG(prefix
<<qname
<<": NS (with ip, or non-glue) in cache for '"<<subdomain
<<"' -> '"<<nrr
->getNS()<<"'"<<endl
);
937 LOG(prefix
<<qname
<<": within bailiwick: "<< nrr
->getNS().isPartOf(subdomain
));
939 LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset
.begin()->d_ttl
- d_now
.tv_sec
))<<endl
);
942 LOG(", not in cache / did not look at cache"<<endl
);
947 LOG(prefix
<<qname
<<": NS in cache for '"<<subdomain
<<"', but needs glue ("<<nrr
->getNS()<<") which we miss or is expired"<<endl
);
952 if(!bestns
.empty()) {
953 GetBestNSAnswer answer
;
955 answer
.qtype
=qtype
.getCode();
956 for(const auto& dr
: bestns
) {
957 if (auto nsContent
= getRR
<NSRecordContent
>(dr
)) {
958 answer
.bestns
.insert(make_pair(dr
.d_name
, nsContent
->getNS()));
962 if(beenthere
.count(answer
)) {
964 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' but part of LOOP (already seen "<<answer
.qname
<<")! Trying less specific NS"<<endl
);
967 for( set
<GetBestNSAnswer
>::const_iterator j
=beenthere
.begin();j
!=beenthere
.end();++j
) {
968 bool neo
= !(*j
< answer
|| answer
<*j
);
969 LOG(prefix
<<qname
<<": beenthere"<<(neo
?"*":"")<<": "<<j
->qname
<<"|"<<DNSRecordContent::NumberToType(j
->qtype
)<<" ("<<(unsigned int)j
->bestns
.size()<<")"<<endl
);
974 beenthere
.insert(answer
);
975 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' (flawedNSSet="<<*flawedNSSet
<<")"<<endl
);
980 LOG(prefix
<<qname
<<": no valid/useful NS in cache for '"<<subdomain
<<"'"<<endl
);
982 if(subdomain
.isRoot() && !brokeloop
) {
983 // We lost the root NS records
985 LOG(prefix
<<qname
<<": reprimed the root"<<endl
);
986 /* let's prevent an infinite loop */
987 if (!d_updatingRootNS
) {
988 getRootNS(d_now
, d_asyncResolve
);
991 } while(subdomain
.chopOff());
994 SyncRes::domainmap_t::const_iterator
SyncRes::getBestAuthZone(DNSName
* qname
) const
996 SyncRes::domainmap_t::const_iterator ret
;
998 ret
=t_sstorage
.domainmap
->find(*qname
);
999 if(ret
!=t_sstorage
.domainmap
->end())
1001 }while(qname
->chopOff());
1005 /** doesn't actually do the work, leaves that to getBestNSFromCache */
1006 DNSName
SyncRes::getBestNSNamesFromCache(const DNSName
&qname
, const QType
& qtype
, NsSet
& nsset
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
)
1008 DNSName
subdomain(qname
);
1009 DNSName
authdomain(qname
);
1011 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
1012 if(iter
!=t_sstorage
.domainmap
->end()) {
1013 if( iter
->second
.isAuth() )
1014 // this gets picked up in doResolveAt, the empty DNSName, combined with the
1015 // empty vector means 'we are auth for this zone'
1016 nsset
.insert({DNSName(), {{}, false}});
1018 // Again, picked up in doResolveAt. An empty DNSName, combined with a
1019 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
1020 // This is actually picked up in retrieveAddressesForNS called from doResolveAt.
1021 nsset
.insert({DNSName(), {iter
->second
.d_servers
, iter
->second
.shouldRecurse() }});
1026 vector
<DNSRecord
> bestns
;
1027 getBestNSFromCache(subdomain
, qtype
, bestns
, flawedNSSet
, depth
, beenthere
);
1029 for(auto k
=bestns
.cbegin() ; k
!= bestns
.cend(); ++k
) {
1030 // The actual resolver code will not even look at the ComboAddress or bool
1031 const auto nsContent
= getRR
<NSRecordContent
>(*k
);
1033 nsset
.insert({nsContent
->getNS(), {{}, false}});
1034 if(k
==bestns
.cbegin())
1035 subdomain
=k
->d_name
;
1041 void SyncRes::updateValidationStatusInCache(const DNSName
&qname
, const QType
& qt
, bool aa
, vState newState
) const
1043 if (newState
== Bogus
) {
1044 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qt
, d_cacheRemote
, aa
, newState
, s_maxbogusttl
+ d_now
.tv_sec
);
1047 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qt
, d_cacheRemote
, aa
, newState
, boost::none
);
1051 bool SyncRes::doCNAMECacheCheck(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>& ret
, unsigned int depth
, int &res
, vState
& state
, bool wasAuthZone
, bool wasForwardRecurse
)
1056 prefix
.append(depth
, ' ');
1059 if((depth
>9 && d_outqueries
>10 && d_throttledqueries
>5) || depth
> 15) {
1060 LOG(prefix
<<qname
<<": recursing (CNAME or other indirection) too deep, depth="<<depth
<<endl
);
1061 res
=RCode::ServFail
;
1065 vector
<DNSRecord
> cset
;
1066 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
1067 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1069 uint32_t capTTL
= std::numeric_limits
<uint32_t>::max();
1071 QType foundQT
= QType(0); // 0 == QTYPE::ENT
1073 LOG(prefix
<<qname
<<": Looking for CNAME cache hit of '"<<qname
<<"|CNAME"<<"'"<<endl
);
1074 /* we don't require auth data for forward-recurse lookups */
1075 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) {
1077 foundQT
= QType(QType::CNAME
);
1080 if (foundName
.empty() && qname
!= g_rootdnsname
) {
1081 // look for a DNAME cache hit
1082 auto labels
= qname
.getRawLabels();
1083 DNSName
dnameName(g_rootdnsname
);
1086 dnameName
.prependRawLabel(labels
.back());
1088 if (dnameName
== qname
&& qtype
!= QType::DNAME
) { // The client does not want a DNAME, but we've reached the QNAME already. So there is no match
1091 LOG(prefix
<<qname
<<": Looking for DNAME cache hit of '"<<dnameName
<<"|DNAME"<<"'"<<endl
);
1092 if (t_RC
->get(d_now
.tv_sec
, dnameName
, QType(QType::DNAME
), !wasForwardRecurse
&& d_requireAuthData
, &cset
, d_cacheRemote
, d_doDNSSEC
? &signatures
: nullptr, d_doDNSSEC
? &authorityRecs
: nullptr, &d_wasVariable
, &state
, &wasAuth
) > 0) {
1093 foundName
= dnameName
;
1094 foundQT
= QType(QType::DNAME
);
1097 } while(!labels
.empty());
1100 if(!foundName
.empty()) {
1101 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
1102 if (j
->d_class
!= QClass::IN
) {
1106 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
1108 if (!wasAuthZone
&& shouldValidate() && (wasAuth
|| wasForwardRecurse
) && state
== Indeterminate
&& d_requireAuthData
) {
1109 /* This means we couldn't figure out the state when this entry was cached,
1110 most likely because we hadn't computed the zone cuts yet. */
1111 /* make sure they are computed before validating */
1112 DNSName
subdomain(foundName
);
1113 /* if we are retrieving a DS, we only care about the state of the parent zone */
1114 if(qtype
== QType::DS
)
1115 subdomain
.chopOff();
1117 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1119 vState recordState
= getValidationStatus(foundName
, false);
1120 if (recordState
== Secure
) {
1121 LOG(prefix
<<qname
<<": got Indeterminate state from the "<<foundQT
.getName()<<" cache, validating.."<<endl
);
1122 state
= SyncRes::validateRecordsWithSigs(depth
, foundName
, foundQT
, foundName
, cset
, signatures
);
1123 if (state
!= Indeterminate
) {
1124 LOG(prefix
<<qname
<<": got Indeterminate state from the CNAME cache, new validation result is "<<vStates
[state
]<<endl
);
1125 if (state
== Bogus
) {
1126 capTTL
= s_maxbogusttl
;
1128 updateValidationStatusInCache(foundName
, foundQT
, wasAuth
, state
);
1133 LOG(prefix
<<qname
<<": Found cache "<<foundQT
.getName()<<" hit for '"<< foundName
<< "|"<<foundQT
.getName()<<"' to '"<<j
->d_content
->getZoneRepresentation()<<"', validation state is "<<vStates
[state
]<<endl
);
1136 dr
.d_ttl
-= d_now
.tv_sec
;
1137 dr
.d_ttl
= std::min(dr
.d_ttl
, capTTL
);
1138 const uint32_t ttl
= dr
.d_ttl
;
1139 ret
.reserve(ret
.size() + 2 + signatures
.size() + authorityRecs
.size());
1142 for(const auto& signature
: signatures
) {
1144 sigdr
.d_type
=QType::RRSIG
;
1145 sigdr
.d_name
=foundName
;
1147 sigdr
.d_content
=signature
;
1148 sigdr
.d_place
=DNSResourceRecord::ANSWER
;
1149 sigdr
.d_class
=QClass::IN
;
1150 ret
.push_back(sigdr
);
1153 for(const auto& rec
: authorityRecs
) {
1154 DNSRecord
authDR(*rec
);
1156 ret
.push_back(authDR
);
1160 if (foundQT
== QType::DNAME
) {
1161 if (qtype
== QType::DNAME
&& qname
== foundName
) { // client wanted the DNAME, no need to synthesize a CNAME
1165 // Synthesize a CNAME
1166 auto dnameRR
= getRR
<DNAMERecordContent
>(*j
);
1167 if (dnameRR
== nullptr) {
1168 throw ImmediateServFailException("Unable to get record content for "+foundName
.toLogString()+"|DNAME cache entry");
1170 const auto& dnameSuffix
= dnameRR
->getTarget();
1171 DNSName targetPrefix
= qname
.makeRelative(foundName
);
1173 dr
.d_type
= QType::CNAME
;
1174 dr
.d_name
= targetPrefix
+ foundName
;
1175 newTarget
= targetPrefix
+ dnameSuffix
;
1176 dr
.d_content
= std::make_shared
<CNAMERecordContent
>(CNAMERecordContent(newTarget
));
1178 } catch (const std::exception
&e
) {
1179 // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
1180 // But this is consistent with processRecords
1181 throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + foundName
.toLogString() +
1182 "', DNAME target: '" + dnameSuffix
.toLogString() + "', substituted name: '" +
1183 targetPrefix
.toLogString() + "." + dnameSuffix
.toLogString() +
1187 LOG(prefix
<<qname
<<": Synthesized "<<dr
.d_name
<<"|CNAME "<<newTarget
<<endl
);
1190 if(qtype
== QType::CNAME
) { // perhaps they really wanted a CNAME!
1195 // We have a DNAME _or_ CNAME cache hit and the client wants something else than those two.
1196 // Let's find the answer!
1197 if (foundQT
== QType::CNAME
) {
1198 const auto cnameContent
= getRR
<CNAMERecordContent
>(*j
);
1199 if (cnameContent
== nullptr) {
1200 throw ImmediateServFailException("Unable to get record content for "+foundName
.toLogString()+"|CNAME cache entry");
1202 newTarget
= cnameContent
->getTarget();
1205 set
<GetBestNSAnswer
>beenthere
;
1206 vState cnameState
= Indeterminate
;
1207 res
= doResolve(newTarget
, qtype
, ret
, depth
+1, beenthere
, cnameState
);
1208 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the DNAME/CNAME quest: "<<vStates
[cnameState
]<<endl
);
1209 updateValidationState(state
, cnameState
);
1215 LOG(prefix
<<qname
<<": No CNAME or DNAME cache hit of '"<< qname
<<"' found"<<endl
);
1222 vector
<DNSRecord
> records
;
1223 vector
<shared_ptr
<RRSIGRecordContent
>> signatures
;
1224 uint32_t signaturesTTL
{std::numeric_limits
<uint32_t>::max()};
1230 DNSResourceRecord::Place place
;
1231 bool operator<(const CacheKey
& rhs
) const {
1232 return tie(type
, place
, name
) < tie(rhs
.type
, rhs
.place
, rhs
.name
);
1235 typedef map
<CacheKey
, CacheEntry
> tcache_t
;
1238 static void reapRecordsFromNegCacheEntryForValidation(tcache_t
& tcache
, const vector
<DNSRecord
>& records
)
1240 for (const auto& rec
: records
) {
1241 if (rec
.d_type
== QType::RRSIG
) {
1242 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1244 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
1247 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(rec
);
1253 * Convience function to push the records from records into ret with a new TTL
1255 * \param records DNSRecords that need to go into ret
1256 * \param ttl The new TTL for these records
1257 * \param ret The vector of DNSRecords that should contian the records with the modified TTL
1259 static void addTTLModifiedRecords(const vector
<DNSRecord
>& records
, const uint32_t ttl
, vector
<DNSRecord
>& ret
) {
1260 for (const auto& rec
: records
) {
1267 void SyncRes::computeNegCacheValidationStatus(const NegCache::NegCacheEntry
* ne
, const DNSName
& qname
, const QType
& qtype
, const int res
, vState
& state
, unsigned int depth
)
1269 DNSName
subdomain(qname
);
1270 /* if we are retrieving a DS, we only care about the state of the parent zone */
1271 if(qtype
== QType::DS
)
1272 subdomain
.chopOff();
1274 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1277 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->authoritySOA
.records
);
1278 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->authoritySOA
.signatures
);
1279 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->DNSSECRecords
.records
);
1280 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->DNSSECRecords
.signatures
);
1282 for (const auto& entry
: tcache
) {
1283 // this happens when we did store signatures, but passed on the records themselves
1284 if (entry
.second
.records
.empty()) {
1288 const DNSName
& owner
= entry
.first
.name
;
1290 vState recordState
= getValidationStatus(owner
, false);
1291 if (state
== Indeterminate
) {
1292 state
= recordState
;
1295 if (recordState
== Secure
) {
1296 recordState
= SyncRes::validateRecordsWithSigs(depth
, qname
, qtype
, owner
, entry
.second
.records
, entry
.second
.signatures
);
1299 if (recordState
!= Indeterminate
&& recordState
!= state
) {
1300 updateValidationState(state
, recordState
);
1301 if (state
!= Secure
) {
1307 if (state
== Secure
) {
1308 vState neValidationState
= ne
->d_validationState
;
1309 dState expectedState
= res
== RCode::NXDomain
? NXDOMAIN
: NXQTYPE
;
1310 dState denialState
= getDenialValidationState(*ne
, state
, expectedState
, false);
1311 updateDenialValidationState(neValidationState
, ne
->d_name
, state
, denialState
, expectedState
, qtype
== QType::DS
);
1313 if (state
!= Indeterminate
) {
1314 /* validation succeeded, let's update the cache entry so we don't have to validate again */
1315 boost::optional
<uint32_t> capTTD
= boost::none
;
1316 if (state
== Bogus
) {
1317 capTTD
= d_now
.tv_sec
+ s_maxbogusttl
;
1319 t_sstorage
.negcache
.updateValidationStatus(ne
->d_name
, ne
->d_qtype
, state
, capTTD
);
1323 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
)
1325 bool giveNegative
=false;
1330 prefix
.append(depth
, ' ');
1333 // 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)
1334 DNSName
sqname(qname
);
1337 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
1339 const NegCache::NegCacheEntry
* ne
= nullptr;
1342 t_sstorage
.negcache
.getRootNXTrust(qname
, d_now
, &ne
) &&
1343 ne
->d_auth
.isRoot() &&
1344 !(wasForwardedOrAuthZone
&& !authname
.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
1345 sttl
= ne
->d_ttd
- d_now
.tv_sec
;
1346 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
->d_auth
<<"' & '"<<ne
->d_name
<<"' for another "<<sttl
<<" seconds"<<endl
);
1347 res
= RCode::NXDomain
;
1348 giveNegative
= true;
1349 cachedState
= ne
->d_validationState
;
1351 else if (t_sstorage
.negcache
.get(qname
, qtype
, d_now
, &ne
)) {
1352 /* If we are looking for a DS, discard NXD if auth == qname
1353 and ask for a specific denial instead */
1354 if (qtype
!= QType::DS
|| ne
->d_qtype
.getCode() || ne
->d_auth
!= qname
||
1355 t_sstorage
.negcache
.get(qname
, qtype
, d_now
, &ne
, true))
1358 sttl
= ne
->d_ttd
- d_now
.tv_sec
;
1359 giveNegative
= true;
1360 cachedState
= ne
->d_validationState
;
1361 if(ne
->d_qtype
.getCode()) {
1362 LOG(prefix
<<qname
<<": "<<qtype
.getName()<<" is negatively cached via '"<<ne
->d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1363 res
= RCode::NoError
;
1366 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
->d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1367 res
= RCode::NXDomain
;
1374 state
= cachedState
;
1376 if (!wasAuthZone
&& shouldValidate() && state
== Indeterminate
) {
1377 LOG(prefix
<<qname
<<": got Indeterminate state for records retrieved from the negative cache, validating.."<<endl
);
1378 computeNegCacheValidationStatus(ne
, qname
, qtype
, res
, state
, depth
);
1380 if (state
!= cachedState
&& state
== Bogus
) {
1381 sttl
= std::min(sttl
, s_maxbogusttl
);
1385 // Transplant SOA to the returned packet
1386 addTTLModifiedRecords(ne
->authoritySOA
.records
, sttl
, ret
);
1388 addTTLModifiedRecords(ne
->authoritySOA
.signatures
, sttl
, ret
);
1389 addTTLModifiedRecords(ne
->DNSSECRecords
.records
, sttl
, ret
);
1390 addTTLModifiedRecords(ne
->DNSSECRecords
.signatures
, sttl
, ret
);
1393 LOG(prefix
<<qname
<<": updating validation state with negative cache content for "<<qname
<<" to "<<vStates
[state
]<<endl
);
1397 vector
<DNSRecord
> cset
;
1398 bool found
=false, expired
=false;
1399 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
1400 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1402 uint32_t capTTL
= std::numeric_limits
<uint32_t>::max();
1404 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) {
1406 LOG(prefix
<<sqname
<<": Found cache hit for "<<sqt
.getName()<<": ");
1408 if (!wasAuthZone
&& shouldValidate() && (wasCachedAuth
|| wasForwardRecurse
) && cachedState
== Indeterminate
&& d_requireAuthData
) {
1410 /* This means we couldn't figure out the state when this entry was cached,
1411 most likely because we hadn't computed the zone cuts yet. */
1412 /* make sure they are computed before validating */
1413 DNSName
subdomain(sqname
);
1414 /* if we are retrieving a DS, we only care about the state of the parent zone */
1415 if(qtype
== QType::DS
)
1416 subdomain
.chopOff();
1418 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1420 vState recordState
= getValidationStatus(qname
, false);
1421 if (recordState
== Secure
) {
1422 LOG(prefix
<<sqname
<<": got Indeterminate state from the cache, validating.."<<endl
);
1423 cachedState
= SyncRes::validateRecordsWithSigs(depth
, sqname
, sqt
, sqname
, cset
, signatures
);
1426 cachedState
= recordState
;
1429 if (cachedState
!= Indeterminate
) {
1430 LOG(prefix
<<qname
<<": got Indeterminate state from the cache, validation result is "<<vStates
[cachedState
]<<endl
);
1431 if (cachedState
== Bogus
) {
1432 capTTL
= s_maxbogusttl
;
1434 updateValidationStatusInCache(sqname
, sqt
, wasCachedAuth
, cachedState
);
1438 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
1440 LOG(j
->d_content
->getZoneRepresentation());
1442 if (j
->d_class
!= QClass::IN
) {
1446 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
1448 dr
.d_ttl
-= d_now
.tv_sec
;
1449 dr
.d_ttl
= std::min(dr
.d_ttl
, capTTL
);
1452 LOG("[ttl="<<dr
.d_ttl
<<"] ");
1461 ret
.reserve(ret
.size() + signatures
.size() + authorityRecs
.size());
1463 for(const auto& signature
: signatures
) {
1465 dr
.d_type
=QType::RRSIG
;
1468 dr
.d_content
=signature
;
1469 dr
.d_place
= DNSResourceRecord::ANSWER
;
1470 dr
.d_class
=QClass::IN
;
1474 for(const auto& rec
: authorityRecs
) {
1481 if(found
&& !expired
) {
1484 LOG(prefix
<<qname
<<": updating validation state with cache content for "<<qname
<<" to "<<vStates
[cachedState
]<<endl
);
1485 state
= cachedState
;
1489 LOG(prefix
<<qname
<<": cache had only stale entries"<<endl
);
1495 bool SyncRes::moreSpecificThan(const DNSName
& a
, const DNSName
&b
) const
1497 return (a
.isPartOf(b
) && a
.countLabels() > b
.countLabels());
1502 bool operator()(const std::pair
<DNSName
, double> &a
, const std::pair
<DNSName
, double> &b
) const
1504 return a
.second
< b
.second
;
1508 inline std::vector
<std::pair
<DNSName
, double>> SyncRes::shuffleInSpeedOrder(NsSet
&tnameservers
, const string
&prefix
)
1510 std::vector
<std::pair
<DNSName
, double>> rnameservers
;
1511 rnameservers
.reserve(tnameservers
.size());
1512 for(const auto& tns
: tnameservers
) {
1513 double speed
= t_sstorage
.nsSpeeds
[tns
.first
].get(&d_now
);
1514 rnameservers
.push_back({tns
.first
, speed
});
1515 if(tns
.first
.empty()) // this was an authoritative OOB zone, don't pollute the nsSpeeds with that
1516 return rnameservers
;
1519 random_shuffle(rnameservers
.begin(),rnameservers
.end());
1521 stable_sort(rnameservers
.begin(),rnameservers
.end(), so
);
1524 LOG(prefix
<<"Nameservers: ");
1525 for(auto i
=rnameservers
.begin();i
!=rnameservers
.end();++i
) {
1526 if(i
!=rnameservers
.begin()) {
1528 if(!((i
-rnameservers
.begin())%3)) {
1529 LOG(endl
<<prefix
<<" ");
1532 LOG(i
->first
.toLogString()<<"(" << (boost::format("%0.2f") % (i
->second
/1000.0)).str() <<"ms)");
1536 return rnameservers
;
1539 inline vector
<ComboAddress
> SyncRes::shuffleForwardSpeed(const vector
<ComboAddress
> &rnameservers
, const string
&prefix
, const bool wasRd
)
1541 vector
<ComboAddress
> nameservers
= rnameservers
;
1542 map
<ComboAddress
, double> speeds
;
1544 for(const auto& val
: nameservers
) {
1546 DNSName nsName
= DNSName(val
.toStringWithPort());
1547 speed
=t_sstorage
.nsSpeeds
[nsName
].get(&d_now
);
1550 random_shuffle(nameservers
.begin(),nameservers
.end());
1551 speedOrderCA
so(speeds
);
1552 stable_sort(nameservers
.begin(),nameservers
.end(), so
);
1555 LOG(prefix
<<"Nameservers: ");
1556 for(vector
<ComboAddress
>::const_iterator i
=nameservers
.cbegin();i
!=nameservers
.cend();++i
) {
1557 if(i
!=nameservers
.cbegin()) {
1559 if(!((i
-nameservers
.cbegin())%3)) {
1560 LOG(endl
<<prefix
<<" ");
1563 LOG((wasRd
? string("+") : string("-")) << i
->toStringWithPort() <<"(" << (boost::format("%0.2f") % (speeds
[*i
]/1000.0)).str() <<"ms)");
1570 static uint32_t getRRSIGTTL(const time_t now
, const std::shared_ptr
<RRSIGRecordContent
>& rrsig
)
1573 if (now
< rrsig
->d_sigexpire
) {
1574 res
= static_cast<uint32_t>(rrsig
->d_sigexpire
) - now
;
1579 static const set
<uint16_t> nsecTypes
= {QType::NSEC
, QType::NSEC3
};
1581 /* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
1583 * \param records The records to parse for the authority SOA and NSEC(3) records
1584 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
1586 static void harvestNXRecords(const vector
<DNSRecord
>& records
, NegCache::NegCacheEntry
& ne
, const time_t now
, uint32_t* lowestTTL
) {
1587 for(const auto& rec
: records
) {
1588 if(rec
.d_place
!= DNSResourceRecord::AUTHORITY
)
1589 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
1590 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
1591 // records MUST be in the same section as the records they cover.
1592 // Hence, we ignore all records outside of the AUTHORITY section.
1595 if(rec
.d_type
== QType::RRSIG
) {
1596 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1598 if(rrsig
->d_type
== QType::SOA
) {
1599 ne
.authoritySOA
.signatures
.push_back(rec
);
1600 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1601 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1602 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1605 if(nsecTypes
.count(rrsig
->d_type
)) {
1606 ne
.DNSSECRecords
.signatures
.push_back(rec
);
1607 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1608 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1609 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1615 if(rec
.d_type
== QType::SOA
) {
1616 ne
.authoritySOA
.records
.push_back(rec
);
1618 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1622 if(nsecTypes
.count(rec
.d_type
)) {
1623 ne
.DNSSECRecords
.records
.push_back(rec
);
1625 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1632 static cspmap_t
harvestCSPFromNE(const NegCache::NegCacheEntry
& ne
)
1635 for(const auto& rec
: ne
.DNSSECRecords
.signatures
) {
1636 if(rec
.d_type
== QType::RRSIG
) {
1637 auto rrc
= getRR
<RRSIGRecordContent
>(rec
);
1639 cspmap
[{rec
.d_name
,rrc
->d_type
}].signatures
.push_back(rrc
);
1643 for(const auto& rec
: ne
.DNSSECRecords
.records
) {
1644 cspmap
[{rec
.d_name
, rec
.d_type
}].records
.push_back(rec
.d_content
);
1649 // TODO remove after processRecords is fixed!
1650 // Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
1651 static void addNXNSECS(vector
<DNSRecord
>&ret
, const vector
<DNSRecord
>& records
)
1653 NegCache::NegCacheEntry ne
;
1654 harvestNXRecords(records
, ne
, 0, nullptr);
1655 ret
.insert(ret
.end(), ne
.authoritySOA
.signatures
.begin(), ne
.authoritySOA
.signatures
.end());
1656 ret
.insert(ret
.end(), ne
.DNSSECRecords
.records
.begin(), ne
.DNSSECRecords
.records
.end());
1657 ret
.insert(ret
.end(), ne
.DNSSECRecords
.signatures
.begin(), ne
.DNSSECRecords
.signatures
.end());
1660 bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine
& dfe
, const NsSet
& nameservers
)
1663 for (auto const &ns
: nameservers
) {
1664 d_appliedPolicy
= dfe
.getProcessingPolicy(ns
.first
, d_discardedPolicies
);
1665 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1666 LOG(", however nameserver "<<ns
.first
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1670 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1671 for (auto const &address
: ns
.second
.first
) {
1672 d_appliedPolicy
= dfe
.getProcessingPolicy(address
, d_discardedPolicies
);
1673 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1674 LOG(", however nameserver "<<ns
.first
<<" IP address "<<address
.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1683 bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine
& dfe
, const ComboAddress
& remoteIP
)
1686 d_appliedPolicy
= dfe
.getProcessingPolicy(remoteIP
, d_discardedPolicies
);
1687 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) {
1688 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")+"')");
1695 vector
<ComboAddress
> SyncRes::retrieveAddressesForNS(const std::string
& prefix
, const DNSName
& qname
, std::vector
<std::pair
<DNSName
, double>>::const_iterator
& tns
, const unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, const vector
<std::pair
<DNSName
, double>>& rnameservers
, NsSet
& nameservers
, bool& sendRDQuery
, bool& pierceDontQuery
, bool& flawedNSSet
, bool cacheOnly
)
1697 vector
<ComboAddress
> result
;
1699 if(!tns
->first
.empty()) {
1700 LOG(prefix
<<qname
<<": Trying to resolve NS '"<<tns
->first
<< "' ("<<1+tns
-rnameservers
.begin()<<"/"<<(unsigned int)rnameservers
.size()<<")"<<endl
);
1701 result
= getAddrs(tns
->first
, depth
+2, beenthere
, cacheOnly
);
1702 pierceDontQuery
=false;
1705 LOG(prefix
<<qname
<<": Domain has hardcoded nameserver");
1707 if(nameservers
[tns
->first
].first
.size() > 1) {
1712 sendRDQuery
= nameservers
[tns
->first
].second
;
1713 result
= shuffleForwardSpeed(nameservers
[tns
->first
].first
, doLog() ? (prefix
+qname
.toString()+": ") : string(), sendRDQuery
);
1714 pierceDontQuery
=true;
1719 bool SyncRes::throttledOrBlocked(const std::string
& prefix
, const ComboAddress
& remoteIP
, const DNSName
& qname
, const QType
& qtype
, bool pierceDontQuery
)
1721 if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0))) {
1722 LOG(prefix
<<qname
<<": server throttled "<<endl
);
1723 s_throttledqueries
++; d_throttledqueries
++;
1726 else if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()))) {
1727 LOG(prefix
<<qname
<<": query throttled "<<remoteIP
.toString()<<", "<<qname
<<"; "<<qtype
.getName()<<endl
);
1728 s_throttledqueries
++; d_throttledqueries
++;
1731 else if(!pierceDontQuery
&& s_dontQuery
&& s_dontQuery
->match(&remoteIP
)) {
1732 LOG(prefix
<<qname
<<": not sending query to " << remoteIP
.toString() << ", blocked by 'dont-query' setting" << endl
);
1739 bool SyncRes::validationEnabled() const
1741 return g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
;
1744 uint32_t SyncRes::computeLowestTTD(const std::vector
<DNSRecord
>& records
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, uint32_t signaturesTTL
) const
1746 uint32_t lowestTTD
= std::numeric_limits
<uint32_t>::max();
1747 for(const auto& record
: records
)
1748 lowestTTD
= min(lowestTTD
, record
.d_ttl
);
1750 /* even if it was not requested for that request (Process, and neither AD nor DO set),
1751 it might be requested at a later time so we need to be careful with the TTL. */
1752 if (validationEnabled() && !signatures
.empty()) {
1753 /* if we are validating, we don't want to cache records after their signatures expire. */
1754 /* records TTL are now TTD, let's add 'now' to the signatures lowest TTL */
1755 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(signaturesTTL
+ d_now
.tv_sec
));
1757 for(const auto& sig
: signatures
) {
1758 if (isRRSIGNotExpired(d_now
.tv_sec
, sig
)) {
1759 // we don't decerement d_sigexpire by 'now' because we actually want a TTD, not a TTL */
1760 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(sig
->d_sigexpire
));
1768 void SyncRes::updateValidationState(vState
& state
, const vState stateUpdate
)
1770 LOG(d_prefix
<<"validation state was "<<std::string(vStates
[state
])<<", state update is "<<std::string(vStates
[stateUpdate
]));
1772 if (stateUpdate
== TA
) {
1775 else if (stateUpdate
== NTA
) {
1778 else if (stateUpdate
== Bogus
) {
1781 else if (state
== Indeterminate
) {
1782 state
= stateUpdate
;
1784 else if (stateUpdate
== Insecure
) {
1785 if (state
!= Bogus
) {
1789 LOG(", validation state is now "<<std::string(vStates
[state
])<<endl
);
1792 vState
SyncRes::getTA(const DNSName
& zone
, dsmap_t
& ds
)
1794 auto luaLocal
= g_luaconfs
.getLocal();
1796 if (luaLocal
->dsAnchors
.empty()) {
1797 LOG(d_prefix
<<": No trust anchors configured, everything is Insecure"<<endl
);
1798 /* We have no TA, everything is insecure */
1803 if (haveNegativeTrustAnchor(luaLocal
->negAnchors
, zone
, reason
)) {
1804 LOG(d_prefix
<<": got NTA for '"<<zone
<<"'"<<endl
);
1808 if (getTrustAnchor(luaLocal
->dsAnchors
, zone
, ds
)) {
1809 LOG(d_prefix
<<": got TA for '"<<zone
<<"'"<<endl
);
1813 LOG(d_prefix
<<": no TA found for '"<<zone
<<"' among "<< luaLocal
->dsAnchors
.size()<<endl
);
1816 if (zone
.isRoot()) {
1817 /* No TA for the root */
1821 return Indeterminate
;
1824 static size_t countSupportedDS(const dsmap_t
& dsmap
)
1828 for (const auto& ds
: dsmap
) {
1829 if (isSupportedDS(ds
)) {
1837 vState
SyncRes::getDSRecords(const DNSName
& zone
, dsmap_t
& ds
, bool taOnly
, unsigned int depth
, bool bogusOnNXD
, bool* foundCut
)
1839 vState result
= getTA(zone
, ds
);
1841 if (result
!= Indeterminate
|| taOnly
) {
1843 *foundCut
= (result
!= Indeterminate
);
1847 if (countSupportedDS(ds
) == 0) {
1855 else if (result
== NTA
) {
1862 bool oldSkipCNAME
= d_skipCNAMECheck
;
1863 d_skipCNAMECheck
= true;
1865 std::set
<GetBestNSAnswer
> beenthere
;
1866 std::vector
<DNSRecord
> dsrecords
;
1868 vState state
= Indeterminate
;
1869 int rcode
= doResolve(zone
, QType(QType::DS
), dsrecords
, depth
+ 1, beenthere
, state
);
1870 d_skipCNAMECheck
= oldSkipCNAME
;
1872 if (rcode
== RCode::NoError
|| (rcode
== RCode::NXDomain
&& !bogusOnNXD
)) {
1873 uint8_t bestDigestType
= 0;
1875 bool gotCNAME
= false;
1876 for (const auto& record
: dsrecords
) {
1877 if (record
.d_type
== QType::DS
) {
1878 const auto dscontent
= getRR
<DSRecordContent
>(record
);
1879 if (dscontent
&& isSupportedDS(*dscontent
)) {
1880 // Make GOST a lower prio than SHA256
1881 if (dscontent
->d_digesttype
== DNSSECKeeper::GOST
&& bestDigestType
== DNSSECKeeper::SHA256
) {
1884 if (dscontent
->d_digesttype
> bestDigestType
|| (bestDigestType
== DNSSECKeeper::GOST
&& dscontent
->d_digesttype
== DNSSECKeeper::SHA256
)) {
1885 bestDigestType
= dscontent
->d_digesttype
;
1887 ds
.insert(*dscontent
);
1890 else if (record
.d_type
== QType::CNAME
&& record
.d_name
== zone
) {
1895 /* RFC 4509 section 3: "Validator implementations SHOULD ignore DS RRs containing SHA-1
1896 * digests if DS RRs with SHA-256 digests are present in the DS RRset."
1897 * As SHA348 is specified as well, the spirit of the this line is "use the best algorithm".
1899 for (auto dsrec
= ds
.begin(); dsrec
!= ds
.end(); ) {
1900 if (dsrec
->d_digesttype
!= bestDigestType
) {
1901 dsrec
= ds
.erase(dsrec
);
1908 if (rcode
== RCode::NoError
) {
1910 /* we have no DS, it's either:
1911 - a delegation to a non-DNSSEC signed zone
1912 - no delegation, we stay in the same zone
1914 if (gotCNAME
|| denialProvesNoDelegation(zone
, dsrecords
)) {
1915 /* we are still inside the same zone */
1923 /* delegation with no DS, might be Secure -> Insecure */
1928 /* a delegation with no DS is either:
1929 - a signed zone (Secure) to an unsigned one (Insecure)
1930 - an unsigned zone to another unsigned one (Insecure stays Insecure, Bogus stays Bogus)
1932 return state
== Secure
? Insecure
: state
;
1944 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
1948 bool SyncRes::haveExactValidationStatus(const DNSName
& domain
)
1950 if (!shouldValidate()) {
1953 const auto& it
= d_cutStates
.find(domain
);
1954 if (it
!= d_cutStates
.cend()) {
1960 vState
SyncRes::getValidationStatus(const DNSName
& subdomain
, bool allowIndeterminate
)
1962 vState result
= Indeterminate
;
1964 if (!shouldValidate()) {
1967 DNSName
name(subdomain
);
1969 const auto& it
= d_cutStates
.find(name
);
1970 if (it
!= d_cutStates
.cend()) {
1971 if (allowIndeterminate
|| it
->second
!= Indeterminate
) {
1972 LOG(d_prefix
<<": got status "<<vStates
[it
->second
]<<" for name "<<subdomain
<<" (from "<<name
<<")"<<endl
);
1977 while (name
.chopOff());
1982 bool SyncRes::lookForCut(const DNSName
& qname
, unsigned int depth
, const vState existingState
, vState
& newState
)
1984 bool foundCut
= false;
1986 vState dsState
= getDSRecords(qname
, ds
, newState
== Bogus
|| existingState
== Insecure
|| existingState
== Bogus
, depth
, false, &foundCut
);
1988 if (dsState
!= Indeterminate
) {
1995 void SyncRes::computeZoneCuts(const DNSName
& begin
, const DNSName
& end
, unsigned int depth
)
1997 if(!begin
.isPartOf(end
)) {
1998 LOG(d_prefix
<<" "<<begin
.toLogString()<<" is not part of "<<end
.toLogString()<<endl
);
1999 throw PDNSException(begin
.toLogString() + " is not part of " + end
.toLogString());
2002 if (d_cutStates
.count(begin
) != 0) {
2007 vState cutState
= getDSRecords(end
, ds
, false, depth
);
2008 LOG(d_prefix
<<": setting cut state for "<<end
<<" to "<<vStates
[cutState
]<<endl
);
2009 d_cutStates
[end
] = cutState
;
2011 if (!shouldValidate()) {
2016 std::vector
<string
> labelsToAdd
= begin
.makeRelative(end
).getRawLabels();
2018 bool oldSkipCNAME
= d_skipCNAMECheck
;
2019 d_skipCNAMECheck
= true;
2021 while(qname
!= begin
) {
2022 if (labelsToAdd
.empty())
2025 qname
.prependRawLabel(labelsToAdd
.back());
2026 labelsToAdd
.pop_back();
2027 LOG(d_prefix
<<": - Looking for a cut at "<<qname
<<endl
);
2029 const auto cutIt
= d_cutStates
.find(qname
);
2030 if (cutIt
!= d_cutStates
.cend()) {
2031 if (cutIt
->second
!= Indeterminate
) {
2032 LOG(d_prefix
<<": - Cut already known at "<<qname
<<endl
);
2033 cutState
= cutIt
->second
;
2038 /* no need to look for NS and DS if we are already insecure or bogus,
2041 if (cutState
== Insecure
|| cutState
== Bogus
) {
2043 vState newState
= getDSRecords(qname
, cutDS
, true, depth
);
2044 if (newState
== Indeterminate
) {
2048 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[newState
]<<endl
);
2049 cutState
= newState
;
2051 d_cutStates
[qname
] = cutState
;
2056 vState newState
= Indeterminate
;
2057 /* temporarily mark as Indeterminate, so that we won't enter an endless loop
2058 trying to determine that zone cut again. */
2059 d_cutStates
[qname
] = newState
;
2060 bool foundCut
= lookForCut(qname
, depth
+ 1, cutState
, newState
);
2062 LOG(d_prefix
<<": - Found cut at "<<qname
<<endl
);
2063 if (newState
!= Indeterminate
) {
2064 cutState
= newState
;
2066 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[cutState
]<<endl
);
2067 d_cutStates
[qname
] = cutState
;
2070 /* remove the temporary cut */
2071 LOG(d_prefix
<<qname
<<": removing cut state for "<<qname
<<endl
);
2072 d_cutStates
.erase(qname
);
2076 d_skipCNAMECheck
= oldSkipCNAME
;
2078 LOG(d_prefix
<<": list of cuts from "<<begin
<<" to "<<end
<<endl
);
2079 for (const auto& cut
: d_cutStates
) {
2080 if (cut
.first
.isRoot() || (begin
.isPartOf(cut
.first
) && cut
.first
.isPartOf(end
))) {
2081 LOG(" - "<<cut
.first
<<": "<<vStates
[cut
.second
]<<endl
);
2086 vState
SyncRes::validateDNSKeys(const DNSName
& zone
, const std::vector
<DNSRecord
>& dnskeys
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, unsigned int depth
)
2089 if (!signatures
.empty()) {
2090 DNSName signer
= getSigner(signatures
);
2092 if (!signer
.empty() && zone
.isPartOf(signer
)) {
2093 vState state
= getDSRecords(signer
, ds
, false, depth
);
2095 if (state
!= Secure
) {
2101 skeyset_t tentativeKeys
;
2102 std::vector
<shared_ptr
<DNSRecordContent
> > toSign
;
2104 for (const auto& dnskey
: dnskeys
) {
2105 if (dnskey
.d_type
== QType::DNSKEY
) {
2106 auto content
= getRR
<DNSKEYRecordContent
>(dnskey
);
2108 tentativeKeys
.insert(content
);
2109 toSign
.push_back(content
);
2114 LOG(d_prefix
<<": trying to validate "<<std::to_string(tentativeKeys
.size())<<" DNSKEYs with "<<std::to_string(ds
.size())<<" DS"<<endl
);
2115 skeyset_t validatedKeys
;
2116 validateDNSKeysAgainstDS(d_now
.tv_sec
, zone
, ds
, tentativeKeys
, toSign
, signatures
, validatedKeys
);
2118 LOG(d_prefix
<<": we now have "<<std::to_string(validatedKeys
.size())<<" DNSKEYs"<<endl
);
2120 /* if we found at least one valid RRSIG covering the set,
2121 all tentative keys are validated keys. Otherwise it means
2122 we haven't found at least one DNSKEY and a matching RRSIG
2123 covering this set, this looks Bogus. */
2124 if (validatedKeys
.size() != tentativeKeys
.size()) {
2125 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
2132 vState
SyncRes::getDNSKeys(const DNSName
& signer
, skeyset_t
& keys
, unsigned int depth
)
2134 std::vector
<DNSRecord
> records
;
2135 std::set
<GetBestNSAnswer
> beenthere
;
2136 LOG(d_prefix
<<"Retrieving DNSKeys for "<<signer
<<endl
);
2138 vState state
= Indeterminate
;
2139 /* following CNAME might lead to us to the wrong DNSKEY */
2140 bool oldSkipCNAME
= d_skipCNAMECheck
;
2141 d_skipCNAMECheck
= true;
2142 int rcode
= doResolve(signer
, QType(QType::DNSKEY
), records
, depth
+ 1, beenthere
, state
);
2143 d_skipCNAMECheck
= oldSkipCNAME
;
2145 if (rcode
== RCode::NoError
) {
2146 if (state
== Secure
) {
2147 for (const auto& key
: records
) {
2148 if (key
.d_type
== QType::DNSKEY
) {
2149 auto content
= getRR
<DNSKEYRecordContent
>(key
);
2151 keys
.insert(content
);
2156 LOG(d_prefix
<<"Retrieved "<<keys
.size()<<" DNSKeys for "<<signer
<<", state is "<<vStates
[state
]<<endl
);
2160 LOG(d_prefix
<<"Returning Bogus state from "<<__func__
<<"("<<signer
<<")"<<endl
);
2164 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
)
2167 if (!signatures
.empty()) {
2168 const DNSName signer
= getSigner(signatures
);
2169 if (!signer
.empty() && name
.isPartOf(signer
)) {
2170 if ((qtype
== QType::DNSKEY
|| qtype
== QType::DS
) && signer
== qname
) {
2171 /* we are already retrieving those keys, sorry */
2172 if (qtype
== QType::DS
) {
2173 /* something is very wrong */
2174 LOG(d_prefix
<<"The DS for "<<qname
<<" is signed by itself, going Bogus"<<endl
);
2177 return Indeterminate
;
2179 vState state
= getDNSKeys(signer
, keys
, depth
);
2180 if (state
!= Secure
) {
2185 LOG(d_prefix
<<"Bogus!"<<endl
);
2189 std::vector
<std::shared_ptr
<DNSRecordContent
> > recordcontents
;
2190 for (const auto& record
: records
) {
2191 recordcontents
.push_back(record
.d_content
);
2194 LOG(d_prefix
<<"Going to validate "<<recordcontents
.size()<< " record contents with "<<signatures
.size()<<" sigs and "<<keys
.size()<<" keys for "<<name
<<endl
);
2195 if (validateWithKeySet(d_now
.tv_sec
, name
, recordcontents
, signatures
, keys
, false)) {
2196 LOG(d_prefix
<<"Secure!"<<endl
);
2200 LOG(d_prefix
<<"Bogus!"<<endl
);
2204 static bool allowAdditionalEntry(std::unordered_set
<DNSName
>& allowedAdditionals
, const DNSRecord
& rec
)
2206 switch(rec
.d_type
) {
2209 if (auto mxContent
= getRR
<MXRecordContent
>(rec
)) {
2210 allowedAdditionals
.insert(mxContent
->d_mxname
);
2216 if (auto nsContent
= getRR
<NSRecordContent
>(rec
)) {
2217 allowedAdditionals
.insert(nsContent
->getNS());
2223 if (auto srvContent
= getRR
<SRVRecordContent
>(rec
)) {
2224 allowedAdditionals
.insert(srvContent
->d_target
);
2233 void SyncRes::sanitizeRecords(const std::string
& prefix
, LWResult
& lwr
, const DNSName
& qname
, const QType
& qtype
, const DNSName
& auth
, bool wasForwarded
, bool rdQuery
)
2235 const bool wasForwardRecurse
= wasForwarded
&& rdQuery
;
2236 /* list of names for which we will allow A and AAAA records in the additional section
2238 std::unordered_set
<DNSName
> allowedAdditionals
= { qname
};
2239 bool haveAnswers
= false;
2240 bool isNXDomain
= false;
2241 bool isNXQType
= false;
2243 for(auto rec
= lwr
.d_records
.begin(); rec
!= lwr
.d_records
.end(); ) {
2245 if (rec
->d_type
== QType::OPT
) {
2250 if (rec
->d_class
!= QClass::IN
) {
2251 LOG(prefix
<<"Removing non internet-classed data received from "<<auth
<<endl
);
2252 rec
= lwr
.d_records
.erase(rec
);
2256 if (rec
->d_type
== QType::ANY
) {
2257 LOG(prefix
<<"Removing 'ANY'-typed data received from "<<auth
<<endl
);
2258 rec
= lwr
.d_records
.erase(rec
);
2262 if (!rec
->d_name
.isPartOf(auth
)) {
2263 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
);
2264 rec
= lwr
.d_records
.erase(rec
);
2268 /* dealing with the records in answer */
2269 if (!(lwr
.d_aabit
|| wasForwardRecurse
) && rec
->d_place
== DNSResourceRecord::ANSWER
) {
2270 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2271 are sending such responses */
2272 if (!(rec
->d_type
== QType::CNAME
&& qname
== rec
->d_name
)) {
2273 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
);
2274 rec
= lwr
.d_records
.erase(rec
);
2279 if (rec
->d_type
== QType::DNAME
&& (rec
->d_place
!= DNSResourceRecord::ANSWER
|| !qname
.isPartOf(rec
->d_name
))) {
2280 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
);
2281 rec
= lwr
.d_records
.erase(rec
);
2285 if (rec
->d_place
== DNSResourceRecord::ANSWER
&& (qtype
!= QType::ANY
&& rec
->d_type
!= qtype
.getCode() && s_redirectionQTypes
.count(rec
->d_type
) == 0 && rec
->d_type
!= QType::SOA
&& rec
->d_type
!= QType::RRSIG
)) {
2286 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
);
2287 rec
= lwr
.d_records
.erase(rec
);
2291 if (rec
->d_place
== DNSResourceRecord::ANSWER
&& !haveAnswers
) {
2295 if (rec
->d_place
== DNSResourceRecord::ANSWER
) {
2296 allowAdditionalEntry(allowedAdditionals
, *rec
);
2299 /* dealing with the records in authority */
2300 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
) {
2301 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
);
2302 rec
= lwr
.d_records
.erase(rec
);
2306 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::SOA
) {
2307 if (!qname
.isPartOf(rec
->d_name
)) {
2308 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
);
2309 rec
= lwr
.d_records
.erase(rec
);
2313 if (!(lwr
.d_aabit
|| wasForwardRecurse
)) {
2314 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
);
2315 rec
= lwr
.d_records
.erase(rec
);
2320 if (lwr
.d_rcode
== RCode::NXDomain
) {
2323 else if (lwr
.d_rcode
== RCode::NoError
) {
2329 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::NS
&& (isNXDomain
|| isNXQType
)) {
2330 /* we don't want to pick up NS records in AUTHORITY or ADDITIONAL sections of NXDomain answers
2331 because they are somewhat easy to insert into a large, fragmented UDP response
2332 for an off-path attacker by injecting spoofed UDP fragments.
2334 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
);
2335 rec
= lwr
.d_records
.erase(rec
);
2339 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::NS
) {
2340 allowAdditionalEntry(allowedAdditionals
, *rec
);
2343 /* dealing with the records in additional */
2344 if (rec
->d_place
== DNSResourceRecord::ADDITIONAL
&& rec
->d_type
!= QType::A
&& rec
->d_type
!= QType::AAAA
&& rec
->d_type
!= QType::RRSIG
) {
2345 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
);
2346 rec
= lwr
.d_records
.erase(rec
);
2350 if (rec
->d_place
== DNSResourceRecord::ADDITIONAL
&& allowedAdditionals
.count(rec
->d_name
) == 0) {
2351 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
);
2352 rec
= lwr
.d_records
.erase(rec
);
2360 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
, bool& gatherWildcardProof
, unsigned int& wildcardLabelsCount
, bool rdQuery
)
2362 bool wasForwardRecurse
= wasForwarded
&& rdQuery
;
2368 prefix
.append(depth
, ' ');
2371 sanitizeRecords(prefix
, lwr
, qname
, qtype
, auth
, wasForwarded
, rdQuery
);
2373 std::vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
2374 const unsigned int labelCount
= qname
.countLabels();
2375 bool isCNAMEAnswer
= false;
2376 bool isDNAMEAnswer
= false;
2377 for(const auto& rec
: lwr
.d_records
) {
2378 if (rec
.d_class
!= QClass::IN
) {
2382 if(!isCNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
&& !isDNAMEAnswer
) {
2383 isCNAMEAnswer
= true;
2385 if(!isDNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::DNAME
&& qtype
!= QType(QType::DNAME
) && qname
.isPartOf(rec
.d_name
)) {
2386 isDNAMEAnswer
= true;
2387 isCNAMEAnswer
= false;
2390 /* if we have a positive answer synthetized from a wildcard,
2391 we need to store the corresponding NSEC/NSEC3 records proving
2392 that the exact name did not exist in the negative cache */
2393 if(gatherWildcardProof
) {
2394 if (nsecTypes
.count(rec
.d_type
)) {
2395 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
2397 else if (rec
.d_type
== QType::RRSIG
) {
2398 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
2399 if (rrsig
&& nsecTypes
.count(rrsig
->d_type
)) {
2400 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
2404 if(rec
.d_type
== QType::RRSIG
) {
2405 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
2407 /* As illustrated in rfc4035's Appendix B.6, the RRSIG label
2408 count can be lower than the name's label count if it was
2409 synthetized from the wildcard. Note that the difference might
2411 if (rec
.d_name
== qname
&& isWildcardExpanded(labelCount
, rrsig
)) {
2412 gatherWildcardProof
= true;
2413 if (!isWildcardExpandedOntoItself(rec
.d_name
, labelCount
, rrsig
)) {
2414 /* if we have a wildcard expanded onto itself, we don't need to prove
2415 that the exact name doesn't exist because it actually does.
2416 We still want to gather the corresponding NSEC/NSEC3 records
2417 to pass them to our client in case it wants to validate by itself.
2419 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthetized from a wildcard, we need a wildcard proof"<<endl
);
2420 needWildcardProof
= true;
2423 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthetized from a wildcard expanded onto itself, we need to gather wildcard proof"<<endl
);
2425 wildcardLabelsCount
= rrsig
->d_labels
;
2428 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
2429 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
2430 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
);
2435 // reap all answers from this packet that are acceptable
2436 for(auto& rec
: lwr
.d_records
) {
2437 if(rec
.d_type
== QType::OPT
) {
2438 LOG(prefix
<<qname
<<": OPT answer '"<<rec
.d_name
<<"' from '"<<auth
<<"' nameservers" <<endl
);
2441 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
<<" ");
2442 if(rec
.d_type
== QType::ANY
) {
2443 LOG("NO! - we don't accept 'ANY'-typed data"<<endl
);
2447 if(rec
.d_class
!= QClass::IN
) {
2448 LOG("NO! - we don't accept records for any other class than 'IN'"<<endl
);
2452 if (!(lwr
.d_aabit
|| wasForwardRecurse
) && rec
.d_place
== DNSResourceRecord::ANSWER
) {
2453 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2454 are sending such responses */
2455 if (!(rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
)) {
2456 LOG("NO! - we don't accept records in the answers section without the AA bit set"<<endl
);
2461 if(rec
.d_name
.isPartOf(auth
)) {
2462 if(rec
.d_type
== QType::RRSIG
) {
2463 LOG("RRSIG - separate"<<endl
);
2465 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
)) {
2466 LOG("NO! Is from delegation-only zone"<<endl
);
2468 return RCode::NXDomain
;
2471 bool haveLogged
= false;
2472 if (isDNAMEAnswer
&& rec
.d_type
== QType::CNAME
) {
2473 LOG("NO - we already have a DNAME answer for this domain");
2476 if (!t_sstorage
.domainmap
->empty()) {
2477 // Check if we are authoritative for a zone in this answer
2478 DNSName
tmp_qname(rec
.d_name
);
2479 auto auth_domain_iter
=getBestAuthZone(&tmp_qname
);
2480 if(auth_domain_iter
!=t_sstorage
.domainmap
->end() &&
2481 auth
.countLabels() <= auth_domain_iter
->first
.countLabels()) {
2482 if (auth_domain_iter
->first
!= auth
) {
2483 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter
->first
<<endl
);
2486 LOG("YES! - This answer was ");
2487 if (!wasForwarded
) {
2488 LOG("retrieved from the local auth store.");
2490 LOG("received from a server we forward to.");
2501 rec
.d_ttl
=min(s_maxcachettl
, rec
.d_ttl
);
2504 dr
.d_ttl
+= d_now
.tv_sec
;
2505 dr
.d_place
=DNSResourceRecord::ANSWER
;
2506 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(dr
);
2514 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2515 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)
2516 uint32_t lowestTTD
=computeLowestTTD(i
->second
.records
, i
->second
.signatures
, i
->second
.signaturesTTL
);
2518 for(auto& record
: i
->second
.records
)
2519 record
.d_ttl
= lowestTTD
; // boom
2522 // cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
2523 // cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
2526 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2528 if(i
->second
.records
.empty()) // this happens when we did store signatures, but passed on the records themselves
2531 /* Even if the AA bit is set, additional data cannot be considered
2532 as authoritative. This is especially important during validation
2533 because keeping records in the additional section is allowed even
2534 if the corresponding RRSIGs are not included, without setting the TC
2535 bit, as stated in rfc4035's section 3.1.1. Including RRSIG RRs in a Response:
2536 "When placing a signed RRset in the Additional section, the name
2537 server MUST also place its RRSIG RRs in the Additional section.
2538 If space does not permit inclusion of both the RRset and its
2539 associated RRSIG RRs, the name server MAY retain the RRset while
2540 dropping the RRSIG RRs. If this happens, the name server MUST NOT
2541 set the TC bit solely because these RRSIG RRs didn't fit."
2543 bool isAA
= lwr
.d_aabit
&& i
->first
.place
!= DNSResourceRecord::ADDITIONAL
;
2544 /* if we forwarded the query to a recursor, we can expect the answer to be signed,
2545 even if the answer is not AA. Of course that's not only true inside a Secure
2546 zone, but we check that below. */
2547 bool expectSignature
= i
->first
.place
== DNSResourceRecord::ANSWER
|| ((lwr
.d_aabit
|| wasForwardRecurse
) && i
->first
.place
!= DNSResourceRecord::ADDITIONAL
);
2548 if (isCNAMEAnswer
&& (i
->first
.place
!= DNSResourceRecord::ANSWER
|| i
->first
.type
!= QType::CNAME
|| i
->first
.name
!= qname
)) {
2551 Note that the answer section of an authoritative answer normally
2552 contains only authoritative data. However when the name sought is an
2553 alias (see section 10.1.1) only the record describing that alias is
2554 necessarily authoritative. Clients should assume that other records
2555 may have come from the server's cache. Where authoritative answers
2556 are required, the client should query again, using the canonical name
2557 associated with the alias.
2560 expectSignature
= false;
2563 if (isCNAMEAnswer
&& i
->first
.place
== DNSResourceRecord::AUTHORITY
&& i
->first
.type
== QType::NS
&& auth
== i
->first
.name
) {
2564 /* These NS can't be authoritative since we have a CNAME answer for which (see above) only the
2565 record describing that alias is necessarily authoritative.
2566 But if we allow the current auth, which might be serving the child zone, to raise the TTL
2567 of non-authoritative NS in the cache, they might be able to keep a "ghost" zone alive forever,
2568 even after the delegation is gone from the parent.
2569 So let's just do nothing with them, we can fetch them directly if we need them.
2571 LOG(d_prefix
<<": skipping authority NS from '"<<auth
<<"' nameservers in CNAME answer "<<i
->first
.name
<<"|"<<DNSRecordContent::NumberToType(i
->first
.type
)<<endl
);
2575 vState recordState
= getValidationStatus(i
->first
.name
, false);
2576 LOG(d_prefix
<<": got initial zone status "<<vStates
[recordState
]<<" for record "<<i
->first
.name
<<"|"<<DNSRecordContent::NumberToType(i
->first
.type
)<<endl
);
2578 if (shouldValidate() && recordState
== Secure
) {
2579 vState initialState
= recordState
;
2581 if (expectSignature
) {
2582 if (i
->first
.place
!= DNSResourceRecord::ADDITIONAL
) {
2583 /* the additional entries can be insecure,
2585 "Glue address RRsets associated with delegations MUST NOT be signed"
2587 if (i
->first
.type
== QType::DNSKEY
&& i
->first
.place
== DNSResourceRecord::ANSWER
) {
2588 LOG(d_prefix
<<"Validating DNSKEY for "<<i
->first
.name
<<endl
);
2589 recordState
= validateDNSKeys(i
->first
.name
, i
->second
.records
, i
->second
.signatures
, depth
);
2593 * RFC 6672 section 5.3.1
2594 * In any response, a signed DNAME RR indicates a non-terminal
2595 * redirection of the query. There might or might not be a server-
2596 * synthesized CNAME in the answer section; if there is, the CNAME will
2597 * never be signed. For a DNSSEC validator, verification of the DNAME
2598 * RR and then that the CNAME was properly synthesized is sufficient
2601 * We do the synthesis check in processRecords, here we make sure we
2602 * don't validate the CNAME.
2604 if (!(isDNAMEAnswer
&& i
->first
.type
== QType::CNAME
)) {
2605 LOG(d_prefix
<<"Validating non-additional record for "<<i
->first
.name
<<endl
);
2606 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2607 /* 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 */
2608 if (qtype
== QType::NS
&& i
->second
.signatures
.empty() && recordState
== Bogus
&& haveExactValidationStatus(i
->first
.name
) && getValidationStatus(i
->first
.name
) == Indeterminate
) {
2609 recordState
= Indeterminate
;
2616 recordState
= Indeterminate
;
2618 /* in a non authoritative answer, we only care about the DS record (or lack of) */
2619 if ((i
->first
.type
== QType::DS
|| i
->first
.type
== QType::NSEC
|| i
->first
.type
== QType::NSEC3
) && i
->first
.place
== DNSResourceRecord::AUTHORITY
) {
2620 LOG(d_prefix
<<"Validating DS record for "<<i
->first
.name
<<endl
);
2621 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2625 if (initialState
== Secure
&& state
!= recordState
&& expectSignature
) {
2626 updateValidationState(state
, recordState
);
2630 if (shouldValidate()) {
2631 LOG(d_prefix
<<"Skipping validation because the current state is "<<vStates
[recordState
]<<endl
);
2635 if (recordState
== Bogus
) {
2636 /* this is a TTD by now, be careful */
2637 for(auto& record
: i
->second
.records
) {
2638 record
.d_ttl
= std::min(record
.d_ttl
, static_cast<uint32_t>(s_maxbogusttl
+ d_now
.tv_sec
));
2642 /* We don't need to store NSEC3 records in the positive cache because:
2643 - we don't allow direct NSEC3 queries
2644 - denial of existence proofs in wildcard expanded positive responses are stored in authorityRecs
2645 - denial of existence proofs for negative responses are stored in the negative cache
2646 We also don't want to cache non-authoritative data except for:
2647 - records coming from non forward-recurse servers (those will never be AA)
2649 - NS, A and AAAA (used for infra queries)
2651 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
)) {
2653 bool doCache
= true;
2654 if (i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
) {
2655 // If ednsmask is relevant, we do not want to cache if the scope prefix length is large and TTL is small
2656 if (SyncRes::s_ecscachelimitttl
> 0) {
2657 bool manyMaskBits
= (ednsmask
->isIpv4() && ednsmask
->getBits() > SyncRes::s_ecsipv4cachelimit
) ||
2658 (ednsmask
->isIpv6() && ednsmask
->getBits() > SyncRes::s_ecsipv6cachelimit
);
2661 uint32_t minttl
= UINT32_MAX
;
2662 for (const auto &it
: i
->second
.records
) {
2663 if (it
.d_ttl
< minttl
)
2666 bool ttlIsSmall
= minttl
< SyncRes::s_ecscachelimitttl
+ d_now
.tv_sec
;
2668 // Case: many bits and ttlIsSmall
2675 t_RC
->replace(d_now
.tv_sec
, i
->first
.name
, QType(i
->first
.type
), i
->second
.records
, i
->second
.signatures
, authorityRecs
, i
->first
.type
== QType::DS
? true : isAA
, i
->first
.place
== DNSResourceRecord::ANSWER
? ednsmask
: boost::none
, recordState
);
2679 if(i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
)
2683 return RCode::NoError
;
2686 void SyncRes::updateDenialValidationState(vState
& neValidationState
, const DNSName
& neName
, vState
& state
, const dState denialState
, const dState expectedState
, bool allowOptOut
)
2688 if (denialState
== expectedState
) {
2689 neValidationState
= Secure
;
2692 if (denialState
== OPTOUT
&& allowOptOut
) {
2693 LOG(d_prefix
<<"OPT-out denial found for "<<neName
<<endl
);
2694 neValidationState
= Secure
;
2697 else if (denialState
== INSECURE
) {
2698 LOG(d_prefix
<<"Insecure denial found for "<<neName
<<", returning Insecure"<<endl
);
2699 neValidationState
= Insecure
;
2702 LOG(d_prefix
<<"Invalid denial found for "<<neName
<<", returning Bogus, res="<<denialState
<<", expectedState="<<expectedState
<<endl
);
2703 neValidationState
= Bogus
;
2705 updateValidationState(state
, neValidationState
);
2709 dState
SyncRes::getDenialValidationState(const NegCache::NegCacheEntry
& ne
, const vState state
, const dState expectedState
, bool referralToUnsigned
)
2711 cspmap_t csp
= harvestCSPFromNE(ne
);
2712 return getDenial(csp
, ne
.d_name
, ne
.d_qtype
.getCode(), referralToUnsigned
, expectedState
== NXQTYPE
);
2715 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 bool gatherWildcardProof
, const unsigned int wildcardLabelsCount
)
2718 DNSName dnameTarget
, dnameOwner
;
2719 uint32_t dnameTTL
= 0;
2721 for(auto& rec
: lwr
.d_records
) {
2722 if (rec
.d_type
!=QType::OPT
&& rec
.d_class
!=QClass::IN
)
2725 if (rec
.d_place
==DNSResourceRecord::ANSWER
&& !(lwr
.d_aabit
|| sendRDQuery
)) {
2726 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2727 are sending such responses */
2728 if (!(rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
)) {
2733 if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2734 lwr
.d_rcode
==RCode::NXDomain
&& qname
.isPartOf(rec
.d_name
) && rec
.d_name
.isPartOf(auth
)) {
2735 LOG(prefix
<<qname
<<": got negative caching indication for name '"<<qname
<<"' (accept="<<rec
.d_name
.isPartOf(auth
)<<"), newtarget='"<<newtarget
<<"'"<<endl
);
2737 rec
.d_ttl
= min(rec
.d_ttl
, s_maxnegttl
);
2738 if(newtarget
.empty()) // only add a SOA if we're not going anywhere after this
2741 NegCache::NegCacheEntry ne
;
2743 uint32_t lowestTTL
= rec
.d_ttl
;
2744 /* if we get an NXDomain answer with a CNAME, the name
2745 does exist but the target does not */
2746 ne
.d_name
= newtarget
.empty() ? qname
: newtarget
;
2747 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2748 ne
.d_auth
= rec
.d_name
;
2749 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2751 if (state
== Secure
) {
2752 dState denialState
= getDenialValidationState(ne
, state
, NXDOMAIN
, false);
2753 updateDenialValidationState(ne
.d_validationState
, ne
.d_name
, state
, denialState
, NXDOMAIN
, false);
2756 ne
.d_validationState
= state
;
2759 if (ne
.d_validationState
== Bogus
) {
2760 lowestTTL
= min(lowestTTL
, s_maxbogusttl
);
2763 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2764 /* if we get an NXDomain answer with a CNAME, let's not cache the
2765 target, even the server was authoritative for it,
2766 and do an additional query for the CNAME target.
2767 We have a regression test making sure we do exactly that.
2769 if(!wasVariable() && newtarget
.empty()) {
2770 t_sstorage
.negcache
.add(ne
);
2771 if(s_rootNXTrust
&& ne
.d_auth
.isRoot() && auth
.isRoot() && lwr
.d_aabit
) {
2772 ne
.d_name
= ne
.d_name
.getLastLabel();
2773 t_sstorage
.negcache
.add(ne
);
2779 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& s_redirectionQTypes
.count(rec
.d_type
) > 0 && // CNAME or DNAME answer
2780 s_redirectionQTypes
.count(qtype
.getCode()) == 0) { // But not in response to a CNAME or DNAME query
2781 if (rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
) {
2782 if (!dnameOwner
.empty()) { // We synthesize ourselves
2786 if (auto content
= getRR
<CNAMERecordContent
>(rec
)) {
2787 newtarget
=content
->getTarget();
2789 } else if (rec
.d_type
== QType::DNAME
&& qname
.isPartOf(rec
.d_name
)) { // DNAME
2791 if (auto content
= getRR
<DNAMERecordContent
>(rec
)) {
2792 dnameOwner
= rec
.d_name
;
2793 dnameTarget
= content
->getTarget();
2794 dnameTTL
= rec
.d_ttl
;
2795 if (!newtarget
.empty()) { // We had a CNAME before, remove it from ret so we don't cache it
2796 ret
.erase(std::remove_if(
2799 [&qname
](DNSRecord
& rr
) {
2800 return (rr
.d_place
== DNSResourceRecord::ANSWER
&& rr
.d_type
== QType::CNAME
&& rr
.d_name
== qname
);
2805 newtarget
= qname
.makeRelative(dnameOwner
) + dnameTarget
;
2806 } catch (const std::exception
&e
) {
2807 // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
2808 // But there is no way to set the RCODE from this function
2809 throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + dnameOwner
.toLogString() +
2810 "', DNAME target: '" + dnameTarget
.toLogString() + "', substituted name: '" +
2811 qname
.makeRelative(dnameOwner
).toLogString() + "." + dnameTarget
.toLogString() +
2817 /* if we have a positive answer synthetized from a wildcard, we need to
2818 return the corresponding NSEC/NSEC3 records from the AUTHORITY section
2819 proving that the exact name did not exist */
2820 else if(gatherWildcardProof
&& (rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::AUTHORITY
) {
2821 ret
.push_back(rec
); // enjoy your DNSSEC
2823 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
2824 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&&
2826 rec
.d_type
==qtype
.getCode() || ((lwr
.d_aabit
|| sendRDQuery
) && qtype
== QType(QType::ANY
))
2830 LOG(prefix
<<qname
<<": answer is in: resolved to '"<< rec
.d_content
->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"'"<<endl
);
2834 if (state
== Secure
&& needWildcardProof
) {
2835 /* We have a positive answer synthetized from a wildcard, we need to check that we have
2836 proof that the exact name doesn't exist so the wildcard can be used,
2837 as described in section 5.3.4 of RFC 4035 and 5.3 of FRC 7129.
2839 NegCache::NegCacheEntry ne
;
2841 uint32_t lowestTTL
= rec
.d_ttl
;
2843 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2844 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2846 cspmap_t csp
= harvestCSPFromNE(ne
);
2847 dState res
= getDenial(csp
, qname
, ne
.d_qtype
.getCode(), false, false, false, wildcardLabelsCount
);
2848 if (res
!= NXDOMAIN
) {
2850 if (res
== INSECURE
) {
2851 /* Some part could not be validated, for example a NSEC3 record with a too large number of iterations,
2852 this is not enough to warrant a Bogus, but go Insecure. */
2854 LOG(d_prefix
<<"Unable to validate denial in wildcard expanded positive response found for "<<qname
<<", returning Insecure, res="<<res
<<endl
);
2857 LOG(d_prefix
<<"Invalid denial in wildcard expanded positive response found for "<<qname
<<", returning Bogus, res="<<res
<<endl
);
2858 rec
.d_ttl
= std::min(rec
.d_ttl
, s_maxbogusttl
);
2861 updateValidationState(state
, st
);
2862 /* we already stored the record with a different validation status, let's fix it */
2863 updateValidationStatusInCache(qname
, qtype
, lwr
.d_aabit
, st
);
2868 else if((rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::ANSWER
) {
2869 if(rec
.d_type
!= QType::RRSIG
|| rec
.d_name
== qname
) {
2870 ret
.push_back(rec
); // enjoy your DNSSEC
2871 } else if(rec
.d_type
== QType::RRSIG
&& qname
.isPartOf(rec
.d_name
)) {
2872 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
2873 if (rrsig
!= nullptr && rrsig
->d_type
== QType::DNAME
) {
2878 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::NS
&& qname
.isPartOf(rec
.d_name
)) {
2879 if(moreSpecificThan(rec
.d_name
,auth
)) {
2881 LOG(prefix
<<qname
<<": got NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2885 LOG(prefix
<<qname
<<": got upwards/level NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"', had '"<<auth
<<"'"<<endl
);
2887 if (auto content
= getRR
<NSRecordContent
>(rec
)) {
2888 nsset
.insert(content
->getNS());
2891 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::DS
&& qname
.isPartOf(rec
.d_name
)) {
2892 LOG(prefix
<<qname
<<": got DS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2894 else if(realreferral
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& (rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && newauth
.isPartOf(auth
)) {
2895 /* we might have received a denial of the DS, let's check */
2896 if (state
== Secure
) {
2897 NegCache::NegCacheEntry ne
;
2899 ne
.d_name
= newauth
;
2900 ne
.d_qtype
= QType::DS
;
2901 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2902 uint32_t lowestTTL
= rec
.d_ttl
;
2903 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2905 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, true);
2907 if (denialState
== NXQTYPE
|| denialState
== OPTOUT
|| denialState
== INSECURE
) {
2908 ne
.d_ttd
= lowestTTL
+ d_now
.tv_sec
;
2909 ne
.d_validationState
= Secure
;
2910 LOG(prefix
<<qname
<<": got negative indication of DS record for '"<<newauth
<<"'"<<endl
);
2912 if(!wasVariable()) {
2913 t_sstorage
.negcache
.add(ne
);
2916 if (qname
== newauth
&& qtype
== QType::DS
) {
2917 /* we are actually done! */
2924 else if(!done
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2925 lwr
.d_rcode
==RCode::NoError
&& qname
.isPartOf(rec
.d_name
)) {
2926 LOG(prefix
<<qname
<<": got negative caching indication for '"<< qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
2928 if(!newtarget
.empty()) {
2929 LOG(prefix
<<qname
<<": Hang on! Got a redirect to '"<<newtarget
<<"' already"<<endl
);
2932 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2934 NegCache::NegCacheEntry ne
;
2935 ne
.d_auth
= rec
.d_name
;
2936 uint32_t lowestTTL
= rec
.d_ttl
;
2939 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2941 if (state
== Secure
) {
2942 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, false);
2943 updateDenialValidationState(ne
.d_validationState
, ne
.d_name
, state
, denialState
, NXQTYPE
, qtype
== QType::DS
);
2945 ne
.d_validationState
= state
;
2948 if (ne
.d_validationState
== Bogus
) {
2949 lowestTTL
= min(lowestTTL
, s_maxbogusttl
);
2950 rec
.d_ttl
= min(rec
.d_ttl
, s_maxbogusttl
);
2952 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2954 if(!wasVariable()) {
2955 if(qtype
.getCode()) { // prevents us from blacking out a whole domain
2956 t_sstorage
.negcache
.add(ne
);
2966 if (!dnameTarget
.empty()) {
2967 // Synthesize a CNAME
2968 auto cnamerec
= DNSRecord();
2969 cnamerec
.d_name
= qname
;
2970 cnamerec
.d_type
= QType::CNAME
;
2971 cnamerec
.d_ttl
= dnameTTL
;
2972 cnamerec
.d_content
= std::make_shared
<CNAMERecordContent
>(CNAMERecordContent(newtarget
));
2973 ret
.push_back(cnamerec
);
2978 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
)
2980 bool chained
= false;
2981 int resolveret
= RCode::NoError
;
2985 if(d_outqueries
+ d_throttledqueries
> s_maxqperq
) {
2986 throw ImmediateServFailException("more than "+std::to_string(s_maxqperq
)+" (max-qperq) queries sent while resolving "+qname
.toLogString());
2989 if(s_maxtotusec
&& d_totUsec
> s_maxtotusec
) {
2990 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");
2994 LOG(prefix
<<qname
<<": using TCP with "<< remoteIP
.toStringWithPort() <<endl
);
2999 if(d_pdl
&& d_pdl
->preoutquery(remoteIP
, d_requestor
, qname
, qtype
, doTCP
, lwr
.d_records
, resolveret
)) {
3000 LOG(prefix
<<qname
<<": query handled by Lua"<<endl
);
3003 ednsmask
=getEDNSSubnetMask(qname
, remoteIP
);
3005 LOG(prefix
<<qname
<<": Adding EDNS Client Subnet Mask "<<ednsmask
->toString()<<" to query"<<endl
);
3008 resolveret
= asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, auth
, qtype
.getCode(),
3009 doTCP
, sendRDQuery
, &d_now
, ednsmask
, &lwr
, &chained
); // <- we go out on the wire!
3012 LOG(prefix
<<qname
<<": Received EDNS Client Subnet Mask "<<ednsmask
->toString()<<" on response"<<endl
);
3013 if (ednsmask
->getBits() > 0) {
3014 if (ednsmask
->isIpv4()) {
3015 ++SyncRes::s_ecsResponsesBySubnetSize4
.at(ednsmask
->getBits()-1);
3018 ++SyncRes::s_ecsResponsesBySubnetSize6
.at(ednsmask
->getBits()-1);
3024 /* preoutquery killed the query by setting dq.rcode to -3 */
3025 if(resolveret
==-3) {
3026 throw ImmediateServFailException("Query killed by policy");
3029 d_totUsec
+= lwr
.d_usec
;
3030 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
3032 bool dontThrottle
= false;
3034 auto dontThrottleNames
= g_dontThrottleNames
.getLocal();
3035 auto dontThrottleNetmasks
= g_dontThrottleNetmasks
.getLocal();
3036 dontThrottle
= dontThrottleNames
->check(nsName
) || dontThrottleNetmasks
->match(remoteIP
);
3039 if(resolveret
!= 1) {
3040 /* Error while resolving */
3041 if(resolveret
== 0) {
3044 LOG(prefix
<<qname
<<": timeout resolving after "<<lwr
.d_usec
/1000.0<<"msec "<< (doTCP
? "over TCP" : "")<<endl
);
3046 s_outgoingtimeouts
++;
3048 if(remoteIP
.sin4
.sin_family
== AF_INET
)
3049 s_outgoing4timeouts
++;
3051 s_outgoing6timeouts
++;
3054 t_timeouts
->push_back(remoteIP
);
3056 else if(resolveret
== -2) {
3057 /* OS resource limit reached */
3058 LOG(prefix
<<qname
<<": hit a local resource limit resolving"<< (doTCP
? " over TCP" : "")<<", probable error: "<<stringerror()<<endl
);
3059 g_stats
.resourceLimits
++;
3062 /* -1 means server unreachable */
3065 LOG(prefix
<<qname
<<": error resolving from "<<remoteIP
.toString()<< (doTCP
? " over TCP" : "") <<", possible error: "<<strerror(errno
)<< endl
);
3068 if(resolveret
!= -2 && !chained
&& !dontThrottle
) {
3069 // don't account for resource limits, they are our own fault
3070 // And don't throttle when the IP address is on the dontThrottleNetmasks list or the name is part of dontThrottleNames
3071 t_sstorage
.nsSpeeds
[nsName
.empty()? DNSName(remoteIP
.toStringWithPort()) : nsName
].submit(remoteIP
, 1000000, &d_now
); // 1 sec
3073 // code below makes sure we don't filter COM or the root
3074 if (s_serverdownmaxfails
> 0 && (auth
!= g_rootdnsname
) && t_sstorage
.fails
.incr(remoteIP
) >= s_serverdownmaxfails
) {
3075 LOG(prefix
<<qname
<<": Max fails reached resolving on "<< remoteIP
.toString() <<". Going full throttle for "<< s_serverdownthrottletime
<<" seconds" <<endl
);
3076 // mark server as down
3077 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0), s_serverdownthrottletime
, 10000);
3079 else if (resolveret
== -1) {
3080 // unreachable, 1 minute or 100 queries
3081 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 100);
3084 // timeout, 10 seconds or 5 queries
3085 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 10, 5);
3092 /* we got an answer */
3093 if(lwr
.d_rcode
==RCode::ServFail
|| lwr
.d_rcode
==RCode::Refused
) {
3094 LOG(prefix
<<qname
<<": "<<nsName
<<" ("<<remoteIP
.toString()<<") returned a "<< (lwr
.d_rcode
==RCode::ServFail
? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl
);
3095 if (!chained
&& !dontThrottle
) {
3096 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
3101 /* this server sent a valid answer, mark it backup up if it was down */
3102 if(s_serverdownmaxfails
> 0) {
3103 t_sstorage
.fails
.clear(remoteIP
);
3110 LOG(prefix
<<qname
<<": truncated bit set, over TCP?"<<endl
);
3111 if (!dontThrottle
) {
3112 /* let's treat that as a ServFail answer from this server */
3113 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
3117 LOG(prefix
<<qname
<<": truncated bit set, over UDP"<<endl
);
3125 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
)
3130 prefix
.append(depth
, ' ');
3134 for(auto& rec
: lwr
.d_records
) {
3135 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumTTL
);
3139 /* if the answer is ECS-specific, a minimum TTL is set for this kind of answers
3140 and it's higher than the global minimum TTL */
3141 if (ednsmask
&& s_minimumECSTTL
> 0 && (s_minimumTTL
== 0 || s_minimumECSTTL
> s_minimumTTL
)) {
3142 for(auto& rec
: lwr
.d_records
) {
3143 if (rec
.d_place
== DNSResourceRecord::ANSWER
) {
3144 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumECSTTL
);
3149 bool needWildcardProof
= false;
3150 bool gatherWildcardProof
= false;
3151 unsigned int wildcardLabelsCount
;
3152 *rcode
= updateCacheFromRecords(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, state
, needWildcardProof
, gatherWildcardProof
, wildcardLabelsCount
, sendRDQuery
);
3153 if (*rcode
!= RCode::NoError
) {
3157 LOG(prefix
<<qname
<<": determining status after receiving this packet"<<endl
);
3160 bool realreferral
=false, negindic
=false;
3164 bool done
= processRecords(prefix
, qname
, qtype
, auth
, lwr
, sendRDQuery
, ret
, nsset
, newtarget
, newauth
, realreferral
, negindic
, state
, needWildcardProof
, gatherWildcardProof
, wildcardLabelsCount
);
3167 LOG(prefix
<<qname
<<": status=got results, this level of recursion done"<<endl
);
3168 LOG(prefix
<<qname
<<": validation status is "<<vStates
[state
]<<endl
);
3169 *rcode
= RCode::NoError
;
3173 if(!newtarget
.empty()) {
3174 if(newtarget
== qname
) {
3175 LOG(prefix
<<qname
<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl
);
3176 *rcode
= RCode::ServFail
;
3181 LOG(prefix
<<qname
<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl
);
3182 *rcode
= RCode::ServFail
;
3186 if (qtype
== QType::DS
) {
3187 LOG(prefix
<<qname
<<": status=got a CNAME referral, but we are looking for a DS"<<endl
);
3190 addNXNSECS(ret
, lwr
.d_records
);
3192 *rcode
= RCode::NoError
;
3196 LOG(prefix
<<qname
<<": status=got a CNAME referral, starting over with "<<newtarget
<<endl
);
3198 set
<GetBestNSAnswer
> beenthere2
;
3199 vState cnameState
= Indeterminate
;
3200 *rcode
= doResolve(newtarget
, qtype
, ret
, depth
+ 1, beenthere2
, cnameState
);
3201 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
3202 updateValidationState(state
, cnameState
);
3207 if(lwr
.d_rcode
== RCode::NXDomain
) {
3208 LOG(prefix
<<qname
<<": status=NXDOMAIN, we are done "<<(negindic
? "(have negative SOA)" : "")<<endl
);
3211 addNXNSECS(ret
, lwr
.d_records
);
3213 *rcode
= RCode::NXDomain
;
3217 if(nsset
.empty() && !lwr
.d_rcode
&& (negindic
|| lwr
.d_aabit
|| sendRDQuery
)) {
3218 LOG(prefix
<<qname
<<": status=noerror, other types may exist, but we are done "<<(negindic
? "(have negative SOA) " : "")<<(lwr
.d_aabit
? "(have aa bit) " : "")<<endl
);
3220 if(state
== Secure
&& (lwr
.d_aabit
|| sendRDQuery
) && !negindic
) {
3221 updateValidationState(state
, Bogus
);
3225 addNXNSECS(ret
, lwr
.d_records
);
3227 *rcode
= RCode::NoError
;
3232 LOG(prefix
<<qname
<<": status=did not resolve, got "<<(unsigned int)nsset
.size()<<" NS, ");
3234 nameservers
.clear();
3235 for (auto const &nameserver
: nsset
) {
3237 d_appliedPolicy
= dfe
.getProcessingPolicy(nameserver
, d_discardedPolicies
);
3238 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
3239 LOG("however "<<nameserver
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
3244 nameservers
.insert({nameserver
, {{}, false}});
3246 LOG("looping to them"<<endl
);
3247 *gotNewServers
= true;
3257 * -1 in case of no results
3258 * -2 when a FilterEngine Policy was hit
3261 int SyncRes::doResolveAt(NsSet
&nameservers
, DNSName auth
, bool flawedNSSet
, const DNSName
&qname
, const QType
&qtype
,
3262 vector
<DNSRecord
>&ret
,
3263 unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
, vState
& state
, StopAtDelegation
* stopAtDelegation
)
3265 auto luaconfsLocal
= g_luaconfs
.getLocal();
3269 prefix
.append(depth
, ' ');
3272 LOG(prefix
<<qname
<<": Cache consultations done, have "<<(unsigned int)nameservers
.size()<<" NS to contact");
3274 if (nameserversBlockedByRPZ(luaconfsLocal
->dfe
, nameservers
)) {
3280 for(;;) { // we may get more specific nameservers
3281 auto rnameservers
= shuffleInSpeedOrder(nameservers
, doLog() ? (prefix
+qname
.toString()+": ") : string() );
3283 for(auto tns
=rnameservers
.cbegin();;++tns
) {
3284 if(tns
==rnameservers
.cend()) {
3285 LOG(prefix
<<qname
<<": Failed to resolve via any of the "<<(unsigned int)rnameservers
.size()<<" offered NS at level '"<<auth
<<"'"<<endl
);
3286 if(!auth
.isRoot() && flawedNSSet
) {
3287 LOG(prefix
<<qname
<<": Ageing nameservers for level '"<<auth
<<"', next query might succeed"<<endl
);
3289 if(t_RC
->doAgeCache(d_now
.tv_sec
, auth
, QType::NS
, 10))
3290 g_stats
.nsSetInvalidations
++;
3295 bool cacheOnly
= false;
3296 // this line needs to identify the 'self-resolving' behaviour
3297 if(qname
== tns
->first
&& (qtype
.getCode() == QType::A
|| qtype
.getCode() == QType::AAAA
)) {
3298 /* we might have a glue entry in cache so let's try this NS
3299 but only if we have enough in the cache to know how to reach it */
3300 LOG(prefix
<<qname
<<": Using NS to resolve itself, but only using what we have in cache ("<<(1+tns
-rnameservers
.cbegin())<<"/"<<rnameservers
.size()<<")"<<endl
);
3304 typedef vector
<ComboAddress
> remoteIPs_t
;
3305 remoteIPs_t remoteIPs
;
3306 remoteIPs_t::const_iterator remoteIP
;
3307 bool pierceDontQuery
=false;
3308 bool sendRDQuery
=false;
3309 boost::optional
<Netmask
> ednsmask
;
3311 const bool wasForwarded
= tns
->first
.empty() && (!nameservers
[tns
->first
].first
.empty());
3312 int rcode
= RCode::NoError
;
3313 bool gotNewServers
= false;
3315 if(tns
->first
.empty() && !wasForwarded
) {
3316 LOG(prefix
<<qname
<<": Domain is out-of-band"<<endl
);
3317 /* setting state to indeterminate since validation is disabled for local auth zone,
3318 and Insecure would be misleading. */
3319 state
= Indeterminate
;
3320 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, lwr
.d_records
, depth
, lwr
.d_rcode
);
3324 /* we have received an answer, are we done ? */
3325 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, false, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
3329 if (gotNewServers
) {
3330 if (stopAtDelegation
&& *stopAtDelegation
== Stop
) {
3331 *stopAtDelegation
= Stopped
;
3338 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
3339 remoteIPs
= retrieveAddressesForNS(prefix
, qname
, tns
, depth
, beenthere
, rnameservers
, nameservers
, sendRDQuery
, pierceDontQuery
, flawedNSSet
, cacheOnly
);
3341 if(remoteIPs
.empty()) {
3342 LOG(prefix
<<qname
<<": Failed to get IP for NS "<<tns
->first
<<", trying next if available"<<endl
);
3347 bool hitPolicy
{false};
3348 LOG(prefix
<<qname
<<": Resolved '"<<auth
<<"' NS "<<tns
->first
<<" to: ");
3349 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
3350 if(remoteIP
!= remoteIPs
.cbegin()) {
3353 LOG(remoteIP
->toString());
3354 if(nameserverIPBlockedByRPZ(luaconfsLocal
->dfe
, *remoteIP
)) {
3359 if (hitPolicy
) //implies d_wantsRPZ
3363 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
3364 LOG(prefix
<<qname
<<": Trying IP "<< remoteIP
->toStringWithPort() <<", asking '"<<qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
3366 if (throttledOrBlocked(prefix
, *remoteIP
, qname
, qtype
, pierceDontQuery
)) {
3370 bool truncated
= false;
3371 bool gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
3372 tns
->first
, *remoteIP
, false, &truncated
);
3373 if (gotAnswer
&& truncated
) {
3374 /* retry, over TCP this time */
3375 gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
3376 tns
->first
, *remoteIP
, true, &truncated
);
3383 LOG(prefix
<<qname
<<": Got "<<(unsigned int)lwr
.d_records
.size()<<" answers from "<<tns
->first
<<" ("<< remoteIP
->toString() <<"), rcode="<<lwr
.d_rcode
<<" ("<<RCode::to_s(lwr
.d_rcode
)<<"), aa="<<lwr
.d_aabit
<<", in "<<lwr
.d_usec
/1000<<"ms"<<endl
);
3385 /* // for you IPv6 fanatics :-)
3386 if(remoteIP->sin4.sin_family==AF_INET6)
3389 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
3391 t_sstorage
.nsSpeeds
[tns
->first
.empty()? DNSName(remoteIP
->toStringWithPort()) : tns
->first
].submit(*remoteIP
, lwr
.d_usec
, &d_now
);
3393 /* we have received an answer, are we done ? */
3394 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
3398 if (gotNewServers
) {
3399 if (stopAtDelegation
&& *stopAtDelegation
== Stop
) {
3400 *stopAtDelegation
= Stopped
;
3406 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100);
3409 if (gotNewServers
) {
3413 if(remoteIP
== remoteIPs
.cend()) // we tried all IP addresses, none worked
3422 void SyncRes::setQuerySource(const ComboAddress
& requestor
, boost::optional
<const EDNSSubnetOpts
&> incomingECS
)
3424 d_requestor
= requestor
;
3426 if (incomingECS
&& incomingECS
->source
.getBits() > 0) {
3427 d_cacheRemote
= incomingECS
->source
.getMaskedNetwork();
3428 uint8_t bits
= std::min(incomingECS
->source
.getBits(), (incomingECS
->source
.isIpv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
3429 ComboAddress trunc
= incomingECS
->source
.getNetwork();
3430 trunc
.truncate(bits
);
3431 d_outgoingECSNetwork
= boost::optional
<Netmask
>(Netmask(trunc
, bits
));
3433 d_cacheRemote
= d_requestor
;
3434 if(!incomingECS
&& s_ednslocalsubnets
.match(d_requestor
)) {
3435 ComboAddress trunc
= d_requestor
;
3436 uint8_t bits
= d_requestor
.isIPv4() ? 32 : 128;
3437 bits
= std::min(bits
, (trunc
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
3438 trunc
.truncate(bits
);
3439 d_outgoingECSNetwork
= boost::optional
<Netmask
>(Netmask(trunc
, bits
));
3440 } else if (s_ecsScopeZero
.source
.getBits() > 0) {
3441 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0.
3442 But using an empty ECS in that case would mean inserting
3443 a non ECS-specific entry into the cache, preventing any further
3444 ECS-specific query to be sent.
3445 So instead we use the trick described in section 7.1.2:
3446 "The subsequent Recursive Resolver query to the Authoritative Nameserver
3447 will then either not include an ECS option or MAY optionally include
3448 its own address information, which is what the Authoritative
3449 Nameserver will almost certainly use to generate any Tailored
3450 Response in lieu of an option. This allows the answer to be handled
3451 by the same caching mechanism as other queries, with an explicit
3452 indicator of the applicable scope. Subsequent Stub Resolver queries
3453 for /0 can then be answered from this cached response.
3455 d_outgoingECSNetwork
= boost::optional
<Netmask
>(s_ecsScopeZero
.source
.getMaskedNetwork());
3456 d_cacheRemote
= s_ecsScopeZero
.source
.getNetwork();
3458 // ECS disabled because no scope-zero address could be derived.
3459 d_outgoingECSNetwork
= boost::none
;
3464 boost::optional
<Netmask
> SyncRes::getEDNSSubnetMask(const DNSName
& dn
, const ComboAddress
& rem
)
3466 if(d_outgoingECSNetwork
&& (s_ednsdomains
.check(dn
) || s_ednsremotesubnets
.match(rem
))) {
3467 return d_outgoingECSNetwork
;
3472 void SyncRes::parseEDNSSubnetWhitelist(const std::string
& wlist
)
3474 vector
<string
> parts
;
3475 stringtok(parts
, wlist
, ",; ");
3476 for(const auto& a
: parts
) {
3478 s_ednsremotesubnets
.addMask(Netmask(a
));
3481 s_ednsdomains
.add(DNSName(a
));
3486 void SyncRes::parseEDNSSubnetAddFor(const std::string
& subnetlist
)
3488 vector
<string
> parts
;
3489 stringtok(parts
, subnetlist
, ",; ");
3490 for(const auto& a
: parts
) {
3491 s_ednslocalsubnets
.addMask(a
);
3495 // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
3496 int directResolve(const DNSName
& qname
, const QType
& qtype
, int qclass
, vector
<DNSRecord
>& ret
)
3499 gettimeofday(&now
, 0);
3504 res
= sr
.beginResolve(qname
, QType(qtype
), qclass
, ret
);
3506 catch(const PDNSException
& e
) {
3507 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got pdns exception: "<<e
.reason
<<endl
;
3510 catch(const ImmediateServFailException
& e
) {
3511 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got ImmediateServFailException: "<<e
.reason
<<endl
;
3514 catch(const std::exception
& e
) {
3515 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got STL error: "<<e
.what()<<endl
;
3519 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got an exception"<<endl
;
3526 int SyncRes::getRootNS(struct timeval now
, asyncresolve_t asyncCallback
) {
3528 sr
.setDoEDNS0(true);
3529 sr
.setUpdatingRootNS();
3530 sr
.setDoDNSSEC(g_dnssecmode
!= DNSSECMode::Off
);
3531 sr
.setDNSSECValidationRequested(g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
);
3532 sr
.setAsyncCallback(asyncCallback
);
3534 vector
<DNSRecord
> ret
;
3537 res
=sr
.beginResolve(g_rootdnsname
, QType(QType::NS
), 1, ret
);
3538 if (g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
) {
3539 auto state
= sr
.getValidationState();
3541 throw PDNSException("Got Bogus validation result for .|NS");
3545 catch(const PDNSException
& e
) {
3546 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
3548 catch(const ImmediateServFailException
& e
) {
3549 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
3551 catch(const std::exception
& e
) {
3552 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.what()<<endl
;
3555 g_log
<<Logger::Error
<<"Failed to update . records, got an exception"<<endl
;
3559 g_log
<<Logger::Notice
<<"Refreshed . records"<<endl
;
3562 g_log
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;