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 // Something terrible is wrong
603 QLOG("Step1 No ancestor found return ServFail");
604 return RCode::ServFail
;
607 const DNSName
& ancestor(bestns
[0].d_name
);
608 QLOG("Step1 Ancestor from cache is " << ancestor
.toString());
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());
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());
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 * \param fromCache tells the caller the result came from the cache, may be nullptr
665 * \param stopAtDelegation if non-nullptr and pointed-to value is Stop requests the callee to stop at a delegation, if so pointed-to value is set to Stopped
666 * \return DNS RCODE or -1 (Error) or -2 (RPZ hit)
668 int SyncRes::doResolveNoQNameMinimization(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, vState
& state
, bool *fromCache
, StopAtDelegation
*stopAtDelegation
)
673 prefix
.append(depth
, ' ');
676 LOG(prefix
<<qname
<<": Wants "<< (d_doDNSSEC
? "" : "NO ") << "DNSSEC processing, "<<(d_requireAuthData
? "" : "NO ")<<"auth data in query for "<<qtype
.getName()<<endl
);
678 state
= Indeterminate
;
680 if(s_maxdepth
&& depth
> s_maxdepth
)
681 throw ImmediateServFailException("More than "+std::to_string(s_maxdepth
)+" (max-recursion-depth) levels of recursion needed while resolving "+qname
.toLogString());
685 // This is a difficult way of expressing "this is a normal query", i.e. not getRootNS.
686 if(!(d_updatingRootNS
&& qtype
.getCode()==QType::NS
&& qname
.isRoot())) {
687 if(d_cacheonly
) { // very limited OOB support
689 LOG(prefix
<<qname
<<": Recursion not requested for '"<<qname
<<"|"<<qtype
.getName()<<"', peeking at auth/forward zones"<<endl
);
690 DNSName
authname(qname
);
691 domainmap_t::const_iterator iter
=getBestAuthZone(&authname
);
692 if(iter
!= t_sstorage
.domainmap
->end()) {
693 if(iter
->second
.isAuth()) {
695 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, ret
, depth
, res
);
697 *fromCache
= d_wasOutOfBand
;
701 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
702 const ComboAddress remoteIP
= servers
.front();
703 LOG(prefix
<<qname
<<": forwarding query to hardcoded nameserver '"<< remoteIP
.toStringWithPort()<<"' for zone '"<<authname
<<"'"<<endl
);
705 boost::optional
<Netmask
> nm
;
706 bool chained
= false;
707 res
=asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, authname
, qtype
.getCode(), false, false, &d_now
, nm
, &lwr
, &chained
);
709 d_totUsec
+= lwr
.d_usec
;
710 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
714 // filter out the good stuff from lwr.result()
716 for(const auto& rec
: lwr
.d_records
) {
717 if(rec
.d_place
== DNSResourceRecord::ANSWER
)
723 return RCode::ServFail
;
729 DNSName
authname(qname
);
730 bool wasForwardedOrAuthZone
= false;
731 bool wasAuthZone
= false;
732 bool wasForwardRecurse
= false;
733 domainmap_t::const_iterator iter
= getBestAuthZone(&authname
);
734 if(iter
!= t_sstorage
.domainmap
->end()) {
735 const auto& domain
= iter
->second
;
736 wasForwardedOrAuthZone
= true;
738 if (domain
.isAuth()) {
740 } else if (domain
.shouldRecurse()) {
741 wasForwardRecurse
= true;
745 if(!d_skipCNAMECheck
&& doCNAMECacheCheck(qname
, qtype
, ret
, depth
, res
, state
, wasAuthZone
, wasForwardRecurse
)) { // will reroute us if needed
746 d_wasOutOfBand
= wasAuthZone
;
750 if(doCacheCheck(qname
, authname
, wasForwardedOrAuthZone
, wasAuthZone
, wasForwardRecurse
, qtype
, ret
, depth
, res
, state
)) {
752 d_wasOutOfBand
= wasAuthZone
;
762 LOG(prefix
<<qname
<<": No cache hit for '"<<qname
<<"|"<<qtype
.getName()<<"', trying to find an appropriate NS record"<<endl
);
764 DNSName
subdomain(qname
);
765 if(qtype
== QType::DS
) subdomain
.chopOff();
768 bool flawedNSSet
=false;
770 /* we use subdomain here instead of qname because for DS queries we only care about the state of the parent zone */
771 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
773 // the two retries allow getBestNSNamesFromCache&co to reprime the root
774 // hints, in case they ever go missing
775 for(int tries
=0;tries
<2 && nsset
.empty();++tries
) {
776 subdomain
=getBestNSNamesFromCache(subdomain
, qtype
, nsset
, &flawedNSSet
, depth
, beenthere
); // pass beenthere to both occasions
779 state
= getValidationStatus(qname
, false);
781 LOG(prefix
<<qname
<<": initial validation status for "<<qname
<<" is "<<vStates
[state
]<<endl
);
783 if(!(res
=doResolveAt(nsset
, subdomain
, flawedNSSet
, qname
, qtype
, ret
, depth
, beenthere
, state
, stopAtDelegation
)))
786 LOG(prefix
<<qname
<<": failed (res="<<res
<<")"<<endl
);
791 return res
<0 ? RCode::ServFail
: res
;
795 // for testing purposes
796 static bool ipv6First(const ComboAddress
& a
, const ComboAddress
& b
)
798 return !(a
.sin4
.sin_family
< a
.sin4
.sin_family
);
804 speedOrderCA(std::map
<ComboAddress
,double>& speeds
): d_speeds(speeds
) {}
805 bool operator()(const ComboAddress
& a
, const ComboAddress
& b
) const
807 return d_speeds
[a
] < d_speeds
[b
];
809 std::map
<ComboAddress
, double>& d_speeds
;
812 /** This function explicitly goes out for A or AAAA addresses
814 vector
<ComboAddress
> SyncRes::getAddrs(const DNSName
&qname
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, bool cacheOnly
)
816 typedef vector
<DNSRecord
> res_t
;
817 typedef vector
<ComboAddress
> ret_t
;
820 bool oldCacheOnly
= setCacheOnly(cacheOnly
);
821 bool oldRequireAuthData
= d_requireAuthData
;
822 bool oldValidationRequested
= d_DNSSECValidationRequested
;
823 d_requireAuthData
= false;
824 d_DNSSECValidationRequested
= false;
826 vState newState
= Indeterminate
;
828 // If IPv4 ever becomes second class, we should revisit this
829 if (doResolve(qname
, QType::A
, resv4
, depth
+1, beenthere
, newState
) == 0) { // this consults cache, OR goes out
830 for (auto const &i
: resv4
) {
831 if (i
.d_type
== QType::A
) {
832 if (auto rec
= getRR
<ARecordContent
>(i
)) {
833 ret
.push_back(rec
->getCA(53));
840 // We did not find IPv4 addresses, try to get IPv6 ones
841 newState
= Indeterminate
;
843 if (doResolve(qname
, QType::AAAA
, resv6
, depth
+1, beenthere
, newState
) == 0) { // this consults cache, OR goes out
844 for (const auto &i
: resv6
) {
845 if (i
.d_type
== QType::AAAA
) {
846 if (auto rec
= getRR
<AAAARecordContent
>(i
))
847 ret
.push_back(rec
->getCA(53));
852 // We have some IPv4 records, don't bother with going out to get IPv6, but do consult the cache
853 // Once IPv6 adoption matters, this needs to be revisited
855 if (t_RC
->get(d_now
.tv_sec
, qname
, QType(QType::AAAA
), false, &cset
, d_cacheRemote
) > 0) {
856 for (const auto &i
: cset
) {
857 if (i
.d_ttl
> (unsigned int)d_now
.tv_sec
) {
858 if (auto rec
= getRR
<AAAARecordContent
>(i
)) {
859 ret
.push_back(rec
->getCA(53));
867 d_requireAuthData
= oldRequireAuthData
;
868 d_DNSSECValidationRequested
= oldValidationRequested
;
869 setCacheOnly(oldCacheOnly
);
871 /* we need to remove from the nsSpeeds collection the existing IPs
872 for this nameserver that are no longer in the set, even if there
873 is only one or none at all in the current set.
875 map
<ComboAddress
, double> speeds
;
876 auto& collection
= t_sstorage
.nsSpeeds
[qname
].d_collection
;
877 for(const auto& val
: ret
) {
878 speeds
[val
] = collection
[val
].get(&d_now
);
881 t_sstorage
.nsSpeeds
[qname
].purge(speeds
);
884 random_shuffle(ret
.begin(), ret
.end());
885 speedOrderCA
so(speeds
);
886 stable_sort(ret
.begin(), ret
.end(), so
);
889 string prefix
=d_prefix
;
890 prefix
.append(depth
, ' ');
891 LOG(prefix
<<"Nameserver "<<qname
<<" IPs: ");
893 for(const auto& addr
: ret
) {
900 LOG((addr
.toString())<<"(" << (boost::format("%0.2f") % (speeds
[addr
]/1000.0)).str() <<"ms)");
909 void SyncRes::getBestNSFromCache(const DNSName
&qname
, const QType
& qtype
, vector
<DNSRecord
>& bestns
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
)
912 DNSName
subdomain(qname
);
915 prefix
.append(depth
, ' ');
921 LOG(prefix
<<qname
<<": Checking if we have NS in cache for '"<<subdomain
<<"'"<<endl
);
922 vector
<DNSRecord
> ns
;
923 *flawedNSSet
= false;
925 if(t_RC
->get(d_now
.tv_sec
, subdomain
, QType(QType::NS
), false, &ns
, d_cacheRemote
) > 0) {
926 bestns
.reserve(ns
.size());
928 for(auto k
=ns
.cbegin();k
!=ns
.cend(); ++k
) {
929 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
930 vector
<DNSRecord
> aset
;
932 const DNSRecord
& dr
=*k
;
933 auto nrr
= getRR
<NSRecordContent
>(dr
);
934 if(nrr
&& (!nrr
->getNS().isPartOf(subdomain
) || t_RC
->get(d_now
.tv_sec
, nrr
->getNS(), s_doIPv6
? QType(QType::ADDR
) : QType(QType::A
),
935 false, doLog() ? &aset
: 0, d_cacheRemote
) > 5)) {
936 bestns
.push_back(dr
);
937 LOG(prefix
<<qname
<<": NS (with ip, or non-glue) in cache for '"<<subdomain
<<"' -> '"<<nrr
->getNS()<<"'"<<endl
);
938 LOG(prefix
<<qname
<<": within bailiwick: "<< nrr
->getNS().isPartOf(subdomain
));
940 LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset
.begin()->d_ttl
- d_now
.tv_sec
))<<endl
);
943 LOG(", not in cache / did not look at cache"<<endl
);
948 LOG(prefix
<<qname
<<": NS in cache for '"<<subdomain
<<"', but needs glue ("<<nrr
->getNS()<<") which we miss or is expired"<<endl
);
953 if(!bestns
.empty()) {
954 GetBestNSAnswer answer
;
956 answer
.qtype
=qtype
.getCode();
957 for(const auto& dr
: bestns
) {
958 if (auto nsContent
= getRR
<NSRecordContent
>(dr
)) {
959 answer
.bestns
.insert(make_pair(dr
.d_name
, nsContent
->getNS()));
963 if(beenthere
.count(answer
)) {
965 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' but part of LOOP (already seen "<<answer
.qname
<<")! Trying less specific NS"<<endl
);
968 for( set
<GetBestNSAnswer
>::const_iterator j
=beenthere
.begin();j
!=beenthere
.end();++j
) {
969 bool neo
= !(*j
< answer
|| answer
<*j
);
970 LOG(prefix
<<qname
<<": beenthere"<<(neo
?"*":"")<<": "<<j
->qname
<<"|"<<DNSRecordContent::NumberToType(j
->qtype
)<<" ("<<(unsigned int)j
->bestns
.size()<<")"<<endl
);
975 beenthere
.insert(answer
);
976 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' (flawedNSSet="<<*flawedNSSet
<<")"<<endl
);
981 LOG(prefix
<<qname
<<": no valid/useful NS in cache for '"<<subdomain
<<"'"<<endl
);
983 if(subdomain
.isRoot() && !brokeloop
) {
984 // We lost the root NS records
986 LOG(prefix
<<qname
<<": reprimed the root"<<endl
);
987 /* let's prevent an infinite loop */
988 if (!d_updatingRootNS
) {
989 getRootNS(d_now
, d_asyncResolve
);
992 } while(subdomain
.chopOff());
995 SyncRes::domainmap_t::const_iterator
SyncRes::getBestAuthZone(DNSName
* qname
) const
997 SyncRes::domainmap_t::const_iterator ret
;
999 ret
=t_sstorage
.domainmap
->find(*qname
);
1000 if(ret
!=t_sstorage
.domainmap
->end())
1002 }while(qname
->chopOff());
1006 /** doesn't actually do the work, leaves that to getBestNSFromCache */
1007 DNSName
SyncRes::getBestNSNamesFromCache(const DNSName
&qname
, const QType
& qtype
, NsSet
& nsset
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
)
1009 DNSName
subdomain(qname
);
1010 DNSName
authdomain(qname
);
1012 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
1013 if(iter
!=t_sstorage
.domainmap
->end()) {
1014 if( iter
->second
.isAuth() )
1015 // this gets picked up in doResolveAt, the empty DNSName, combined with the
1016 // empty vector means 'we are auth for this zone'
1017 nsset
.insert({DNSName(), {{}, false}});
1019 // Again, picked up in doResolveAt. An empty DNSName, combined with a
1020 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
1021 // This is actually picked up in retrieveAddressesForNS called from doResolveAt.
1022 nsset
.insert({DNSName(), {iter
->second
.d_servers
, iter
->second
.shouldRecurse() }});
1027 vector
<DNSRecord
> bestns
;
1028 getBestNSFromCache(subdomain
, qtype
, bestns
, flawedNSSet
, depth
, beenthere
);
1030 for(auto k
=bestns
.cbegin() ; k
!= bestns
.cend(); ++k
) {
1031 // The actual resolver code will not even look at the ComboAddress or bool
1032 const auto nsContent
= getRR
<NSRecordContent
>(*k
);
1034 nsset
.insert({nsContent
->getNS(), {{}, false}});
1035 if(k
==bestns
.cbegin())
1036 subdomain
=k
->d_name
;
1042 void SyncRes::updateValidationStatusInCache(const DNSName
&qname
, const QType
& qt
, bool aa
, vState newState
) const
1044 if (newState
== Bogus
) {
1045 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qt
, d_cacheRemote
, aa
, newState
, s_maxbogusttl
+ d_now
.tv_sec
);
1048 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qt
, d_cacheRemote
, aa
, newState
, boost::none
);
1052 bool SyncRes::doCNAMECacheCheck(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>& ret
, unsigned int depth
, int &res
, vState
& state
, bool wasAuthZone
, bool wasForwardRecurse
)
1057 prefix
.append(depth
, ' ');
1060 if((depth
>9 && d_outqueries
>10 && d_throttledqueries
>5) || depth
> 15) {
1061 LOG(prefix
<<qname
<<": recursing (CNAME or other indirection) too deep, depth="<<depth
<<endl
);
1062 res
=RCode::ServFail
;
1066 vector
<DNSRecord
> cset
;
1067 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
1068 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1070 uint32_t capTTL
= std::numeric_limits
<uint32_t>::max();
1072 QType foundQT
= QType(0); // 0 == QTYPE::ENT
1074 LOG(prefix
<<qname
<<": Looking for CNAME cache hit of '"<<qname
<<"|CNAME"<<"'"<<endl
);
1075 /* we don't require auth data for forward-recurse lookups */
1076 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) {
1078 foundQT
= QType(QType::CNAME
);
1081 if (foundName
.empty() && qname
!= g_rootdnsname
) {
1082 // look for a DNAME cache hit
1083 auto labels
= qname
.getRawLabels();
1084 DNSName
dnameName(g_rootdnsname
);
1086 LOG(prefix
<<qname
<<": Looking for DNAME cache hit of '"<<qname
<<"|DNAME' or its ancestors"<<endl
);
1088 dnameName
.prependRawLabel(labels
.back());
1090 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
1093 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) {
1094 foundName
= dnameName
;
1095 foundQT
= QType(QType::DNAME
);
1098 } while(!labels
.empty());
1101 if (foundName
.empty()) {
1102 LOG(prefix
<<qname
<<": No CNAME or DNAME cache hit of '"<< qname
<<"' found"<<endl
);
1106 for(auto const &record
: cset
) {
1107 if (record
.d_class
!= QClass::IN
) {
1111 if(record
.d_ttl
> (unsigned int) d_now
.tv_sec
) {
1113 if (!wasAuthZone
&& shouldValidate() && (wasAuth
|| wasForwardRecurse
) && state
== Indeterminate
&& d_requireAuthData
) {
1114 /* This means we couldn't figure out the state when this entry was cached,
1115 most likely because we hadn't computed the zone cuts yet. */
1116 /* make sure they are computed before validating */
1117 DNSName
subdomain(foundName
);
1118 /* if we are retrieving a DS, we only care about the state of the parent zone */
1119 if(qtype
== QType::DS
)
1120 subdomain
.chopOff();
1122 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1124 vState recordState
= getValidationStatus(foundName
, false);
1125 if (recordState
== Secure
) {
1126 LOG(prefix
<<qname
<<": got Indeterminate state from the "<<foundQT
.getName()<<" cache, validating.."<<endl
);
1127 state
= SyncRes::validateRecordsWithSigs(depth
, foundName
, foundQT
, foundName
, cset
, signatures
);
1128 if (state
!= Indeterminate
) {
1129 LOG(prefix
<<qname
<<": got Indeterminate state from the CNAME cache, new validation result is "<<vStates
[state
]<<endl
);
1130 if (state
== Bogus
) {
1131 capTTL
= s_maxbogusttl
;
1133 updateValidationStatusInCache(foundName
, foundQT
, wasAuth
, state
);
1138 LOG(prefix
<<qname
<<": Found cache "<<foundQT
.getName()<<" hit for '"<< foundName
<< "|"<<foundQT
.getName()<<"' to '"<<record
.d_content
->getZoneRepresentation()<<"', validation state is "<<vStates
[state
]<<endl
);
1140 DNSRecord dr
= record
;
1141 dr
.d_ttl
-= d_now
.tv_sec
;
1142 dr
.d_ttl
= std::min(dr
.d_ttl
, capTTL
);
1143 const uint32_t ttl
= dr
.d_ttl
;
1144 ret
.reserve(ret
.size() + 2 + signatures
.size() + authorityRecs
.size());
1147 for(const auto& signature
: signatures
) {
1149 sigdr
.d_type
=QType::RRSIG
;
1150 sigdr
.d_name
=foundName
;
1152 sigdr
.d_content
=signature
;
1153 sigdr
.d_place
=DNSResourceRecord::ANSWER
;
1154 sigdr
.d_class
=QClass::IN
;
1155 ret
.push_back(sigdr
);
1158 for(const auto& rec
: authorityRecs
) {
1159 DNSRecord
authDR(*rec
);
1161 ret
.push_back(authDR
);
1165 if (foundQT
== QType::DNAME
) {
1166 if (qtype
== QType::DNAME
&& qname
== foundName
) { // client wanted the DNAME, no need to synthesize a CNAME
1170 // Synthesize a CNAME
1171 auto dnameRR
= getRR
<DNAMERecordContent
>(record
);
1172 if (dnameRR
== nullptr) {
1173 throw ImmediateServFailException("Unable to get record content for "+foundName
.toLogString()+"|DNAME cache entry");
1175 const auto& dnameSuffix
= dnameRR
->getTarget();
1176 DNSName targetPrefix
= qname
.makeRelative(foundName
);
1178 dr
.d_type
= QType::CNAME
;
1179 dr
.d_name
= targetPrefix
+ foundName
;
1180 newTarget
= targetPrefix
+ dnameSuffix
;
1181 dr
.d_content
= std::make_shared
<CNAMERecordContent
>(CNAMERecordContent(newTarget
));
1183 } catch (const std::exception
&e
) {
1184 // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
1185 // But this is consistent with processRecords
1186 throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + foundName
.toLogString() +
1187 "', DNAME target: '" + dnameSuffix
.toLogString() + "', substituted name: '" +
1188 targetPrefix
.toLogString() + "." + dnameSuffix
.toLogString() +
1192 LOG(prefix
<<qname
<<": Synthesized "<<dr
.d_name
<<"|CNAME "<<newTarget
<<endl
);
1195 if(qtype
== QType::CNAME
) { // perhaps they really wanted a CNAME!
1200 // We have a DNAME _or_ CNAME cache hit and the client wants something else than those two.
1201 // Let's find the answer!
1202 if (foundQT
== QType::CNAME
) {
1203 const auto cnameContent
= getRR
<CNAMERecordContent
>(record
);
1204 if (cnameContent
== nullptr) {
1205 throw ImmediateServFailException("Unable to get record content for "+foundName
.toLogString()+"|CNAME cache entry");
1207 newTarget
= cnameContent
->getTarget();
1210 set
<GetBestNSAnswer
>beenthere
;
1211 vState cnameState
= Indeterminate
;
1212 res
= doResolve(newTarget
, qtype
, ret
, depth
+1, beenthere
, cnameState
);
1213 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the DNAME/CNAME quest: "<<vStates
[cnameState
]<<endl
);
1214 updateValidationState(state
, cnameState
);
1219 throw ImmediateServFailException("Could not determine whether or not there was a CNAME or DNAME in cache for '" + qname
.toLogString() + "'");
1225 vector
<DNSRecord
> records
;
1226 vector
<shared_ptr
<RRSIGRecordContent
>> signatures
;
1227 uint32_t signaturesTTL
{std::numeric_limits
<uint32_t>::max()};
1233 DNSResourceRecord::Place place
;
1234 bool operator<(const CacheKey
& rhs
) const {
1235 return tie(type
, place
, name
) < tie(rhs
.type
, rhs
.place
, rhs
.name
);
1238 typedef map
<CacheKey
, CacheEntry
> tcache_t
;
1241 static void reapRecordsFromNegCacheEntryForValidation(tcache_t
& tcache
, const vector
<DNSRecord
>& records
)
1243 for (const auto& rec
: records
) {
1244 if (rec
.d_type
== QType::RRSIG
) {
1245 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1247 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
1250 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(rec
);
1256 * Convience function to push the records from records into ret with a new TTL
1258 * \param records DNSRecords that need to go into ret
1259 * \param ttl The new TTL for these records
1260 * \param ret The vector of DNSRecords that should contian the records with the modified TTL
1262 static void addTTLModifiedRecords(const vector
<DNSRecord
>& records
, const uint32_t ttl
, vector
<DNSRecord
>& ret
) {
1263 for (const auto& rec
: records
) {
1270 void SyncRes::computeNegCacheValidationStatus(const NegCache::NegCacheEntry
* ne
, const DNSName
& qname
, const QType
& qtype
, const int res
, vState
& state
, unsigned int depth
)
1272 DNSName
subdomain(qname
);
1273 /* if we are retrieving a DS, we only care about the state of the parent zone */
1274 if(qtype
== QType::DS
)
1275 subdomain
.chopOff();
1277 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1280 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->authoritySOA
.records
);
1281 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->authoritySOA
.signatures
);
1282 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->DNSSECRecords
.records
);
1283 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->DNSSECRecords
.signatures
);
1285 for (const auto& entry
: tcache
) {
1286 // this happens when we did store signatures, but passed on the records themselves
1287 if (entry
.second
.records
.empty()) {
1291 const DNSName
& owner
= entry
.first
.name
;
1293 vState recordState
= getValidationStatus(owner
, false);
1294 if (state
== Indeterminate
) {
1295 state
= recordState
;
1298 if (recordState
== Secure
) {
1299 recordState
= SyncRes::validateRecordsWithSigs(depth
, qname
, qtype
, owner
, entry
.second
.records
, entry
.second
.signatures
);
1302 if (recordState
!= Indeterminate
&& recordState
!= state
) {
1303 updateValidationState(state
, recordState
);
1304 if (state
!= Secure
) {
1310 if (state
== Secure
) {
1311 vState neValidationState
= ne
->d_validationState
;
1312 dState expectedState
= res
== RCode::NXDomain
? NXDOMAIN
: NXQTYPE
;
1313 dState denialState
= getDenialValidationState(*ne
, state
, expectedState
, false);
1314 updateDenialValidationState(neValidationState
, ne
->d_name
, state
, denialState
, expectedState
, qtype
== QType::DS
);
1316 if (state
!= Indeterminate
) {
1317 /* validation succeeded, let's update the cache entry so we don't have to validate again */
1318 boost::optional
<uint32_t> capTTD
= boost::none
;
1319 if (state
== Bogus
) {
1320 capTTD
= d_now
.tv_sec
+ s_maxbogusttl
;
1322 t_sstorage
.negcache
.updateValidationStatus(ne
->d_name
, ne
->d_qtype
, state
, capTTD
);
1326 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
)
1328 bool giveNegative
=false;
1333 prefix
.append(depth
, ' ');
1336 // 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)
1337 DNSName
sqname(qname
);
1340 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
1342 const NegCache::NegCacheEntry
* ne
= nullptr;
1345 t_sstorage
.negcache
.getRootNXTrust(qname
, d_now
, &ne
) &&
1346 ne
->d_auth
.isRoot() &&
1347 !(wasForwardedOrAuthZone
&& !authname
.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
1348 sttl
= ne
->d_ttd
- d_now
.tv_sec
;
1349 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
->d_auth
<<"' & '"<<ne
->d_name
<<"' for another "<<sttl
<<" seconds"<<endl
);
1350 res
= RCode::NXDomain
;
1351 giveNegative
= true;
1352 cachedState
= ne
->d_validationState
;
1354 else if (t_sstorage
.negcache
.get(qname
, qtype
, d_now
, &ne
)) {
1355 /* If we are looking for a DS, discard NXD if auth == qname
1356 and ask for a specific denial instead */
1357 if (qtype
!= QType::DS
|| ne
->d_qtype
.getCode() || ne
->d_auth
!= qname
||
1358 t_sstorage
.negcache
.get(qname
, qtype
, d_now
, &ne
, true))
1361 sttl
= ne
->d_ttd
- d_now
.tv_sec
;
1362 giveNegative
= true;
1363 cachedState
= ne
->d_validationState
;
1364 if(ne
->d_qtype
.getCode()) {
1365 LOG(prefix
<<qname
<<": "<<qtype
.getName()<<" is negatively cached via '"<<ne
->d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1366 res
= RCode::NoError
;
1369 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
->d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1370 res
= RCode::NXDomain
;
1377 state
= cachedState
;
1379 if (!wasAuthZone
&& shouldValidate() && state
== Indeterminate
) {
1380 LOG(prefix
<<qname
<<": got Indeterminate state for records retrieved from the negative cache, validating.."<<endl
);
1381 computeNegCacheValidationStatus(ne
, qname
, qtype
, res
, state
, depth
);
1383 if (state
!= cachedState
&& state
== Bogus
) {
1384 sttl
= std::min(sttl
, s_maxbogusttl
);
1388 // Transplant SOA to the returned packet
1389 addTTLModifiedRecords(ne
->authoritySOA
.records
, sttl
, ret
);
1391 addTTLModifiedRecords(ne
->authoritySOA
.signatures
, sttl
, ret
);
1392 addTTLModifiedRecords(ne
->DNSSECRecords
.records
, sttl
, ret
);
1393 addTTLModifiedRecords(ne
->DNSSECRecords
.signatures
, sttl
, ret
);
1396 LOG(prefix
<<qname
<<": updating validation state with negative cache content for "<<qname
<<" to "<<vStates
[state
]<<endl
);
1400 vector
<DNSRecord
> cset
;
1401 bool found
=false, expired
=false;
1402 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
1403 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1405 uint32_t capTTL
= std::numeric_limits
<uint32_t>::max();
1407 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) {
1409 LOG(prefix
<<sqname
<<": Found cache hit for "<<sqt
.getName()<<": ");
1411 if (!wasAuthZone
&& shouldValidate() && (wasCachedAuth
|| wasForwardRecurse
) && cachedState
== Indeterminate
&& d_requireAuthData
) {
1413 /* This means we couldn't figure out the state when this entry was cached,
1414 most likely because we hadn't computed the zone cuts yet. */
1415 /* make sure they are computed before validating */
1416 DNSName
subdomain(sqname
);
1417 /* if we are retrieving a DS, we only care about the state of the parent zone */
1418 if(qtype
== QType::DS
)
1419 subdomain
.chopOff();
1421 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1423 vState recordState
= getValidationStatus(qname
, false);
1424 if (recordState
== Secure
) {
1425 LOG(prefix
<<sqname
<<": got Indeterminate state from the cache, validating.."<<endl
);
1426 cachedState
= SyncRes::validateRecordsWithSigs(depth
, sqname
, sqt
, sqname
, cset
, signatures
);
1429 cachedState
= recordState
;
1432 if (cachedState
!= Indeterminate
) {
1433 LOG(prefix
<<qname
<<": got Indeterminate state from the cache, validation result is "<<vStates
[cachedState
]<<endl
);
1434 if (cachedState
== Bogus
) {
1435 capTTL
= s_maxbogusttl
;
1437 updateValidationStatusInCache(sqname
, sqt
, wasCachedAuth
, cachedState
);
1441 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
1443 LOG(j
->d_content
->getZoneRepresentation());
1445 if (j
->d_class
!= QClass::IN
) {
1449 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
1451 dr
.d_ttl
-= d_now
.tv_sec
;
1452 dr
.d_ttl
= std::min(dr
.d_ttl
, capTTL
);
1455 LOG("[ttl="<<dr
.d_ttl
<<"] ");
1464 ret
.reserve(ret
.size() + signatures
.size() + authorityRecs
.size());
1466 for(const auto& signature
: signatures
) {
1468 dr
.d_type
=QType::RRSIG
;
1471 dr
.d_content
=signature
;
1472 dr
.d_place
= DNSResourceRecord::ANSWER
;
1473 dr
.d_class
=QClass::IN
;
1477 for(const auto& rec
: authorityRecs
) {
1484 if(found
&& !expired
) {
1487 LOG(prefix
<<qname
<<": updating validation state with cache content for "<<qname
<<" to "<<vStates
[cachedState
]<<endl
);
1488 state
= cachedState
;
1492 LOG(prefix
<<qname
<<": cache had only stale entries"<<endl
);
1498 bool SyncRes::moreSpecificThan(const DNSName
& a
, const DNSName
&b
) const
1500 return (a
.isPartOf(b
) && a
.countLabels() > b
.countLabels());
1505 bool operator()(const std::pair
<DNSName
, double> &a
, const std::pair
<DNSName
, double> &b
) const
1507 return a
.second
< b
.second
;
1511 inline std::vector
<std::pair
<DNSName
, double>> SyncRes::shuffleInSpeedOrder(NsSet
&tnameservers
, const string
&prefix
)
1513 std::vector
<std::pair
<DNSName
, double>> rnameservers
;
1514 rnameservers
.reserve(tnameservers
.size());
1515 for(const auto& tns
: tnameservers
) {
1516 double speed
= t_sstorage
.nsSpeeds
[tns
.first
].get(&d_now
);
1517 rnameservers
.push_back({tns
.first
, speed
});
1518 if(tns
.first
.empty()) // this was an authoritative OOB zone, don't pollute the nsSpeeds with that
1519 return rnameservers
;
1522 random_shuffle(rnameservers
.begin(),rnameservers
.end());
1524 stable_sort(rnameservers
.begin(),rnameservers
.end(), so
);
1527 LOG(prefix
<<"Nameservers: ");
1528 for(auto i
=rnameservers
.begin();i
!=rnameservers
.end();++i
) {
1529 if(i
!=rnameservers
.begin()) {
1531 if(!((i
-rnameservers
.begin())%3)) {
1532 LOG(endl
<<prefix
<<" ");
1535 LOG(i
->first
.toLogString()<<"(" << (boost::format("%0.2f") % (i
->second
/1000.0)).str() <<"ms)");
1539 return rnameservers
;
1542 inline vector
<ComboAddress
> SyncRes::shuffleForwardSpeed(const vector
<ComboAddress
> &rnameservers
, const string
&prefix
, const bool wasRd
)
1544 vector
<ComboAddress
> nameservers
= rnameservers
;
1545 map
<ComboAddress
, double> speeds
;
1547 for(const auto& val
: nameservers
) {
1549 DNSName nsName
= DNSName(val
.toStringWithPort());
1550 speed
=t_sstorage
.nsSpeeds
[nsName
].get(&d_now
);
1553 random_shuffle(nameservers
.begin(),nameservers
.end());
1554 speedOrderCA
so(speeds
);
1555 stable_sort(nameservers
.begin(),nameservers
.end(), so
);
1558 LOG(prefix
<<"Nameservers: ");
1559 for(vector
<ComboAddress
>::const_iterator i
=nameservers
.cbegin();i
!=nameservers
.cend();++i
) {
1560 if(i
!=nameservers
.cbegin()) {
1562 if(!((i
-nameservers
.cbegin())%3)) {
1563 LOG(endl
<<prefix
<<" ");
1566 LOG((wasRd
? string("+") : string("-")) << i
->toStringWithPort() <<"(" << (boost::format("%0.2f") % (speeds
[*i
]/1000.0)).str() <<"ms)");
1573 static uint32_t getRRSIGTTL(const time_t now
, const std::shared_ptr
<RRSIGRecordContent
>& rrsig
)
1576 if (now
< rrsig
->d_sigexpire
) {
1577 res
= static_cast<uint32_t>(rrsig
->d_sigexpire
) - now
;
1582 static const set
<uint16_t> nsecTypes
= {QType::NSEC
, QType::NSEC3
};
1584 /* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
1586 * \param records The records to parse for the authority SOA and NSEC(3) records
1587 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
1589 static void harvestNXRecords(const vector
<DNSRecord
>& records
, NegCache::NegCacheEntry
& ne
, const time_t now
, uint32_t* lowestTTL
) {
1590 for(const auto& rec
: records
) {
1591 if(rec
.d_place
!= DNSResourceRecord::AUTHORITY
)
1592 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
1593 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
1594 // records MUST be in the same section as the records they cover.
1595 // Hence, we ignore all records outside of the AUTHORITY section.
1598 if(rec
.d_type
== QType::RRSIG
) {
1599 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1601 if(rrsig
->d_type
== QType::SOA
) {
1602 ne
.authoritySOA
.signatures
.push_back(rec
);
1603 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1604 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1605 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1608 if(nsecTypes
.count(rrsig
->d_type
)) {
1609 ne
.DNSSECRecords
.signatures
.push_back(rec
);
1610 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1611 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1612 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1618 if(rec
.d_type
== QType::SOA
) {
1619 ne
.authoritySOA
.records
.push_back(rec
);
1621 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1625 if(nsecTypes
.count(rec
.d_type
)) {
1626 ne
.DNSSECRecords
.records
.push_back(rec
);
1628 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1635 static cspmap_t
harvestCSPFromNE(const NegCache::NegCacheEntry
& ne
)
1638 for(const auto& rec
: ne
.DNSSECRecords
.signatures
) {
1639 if(rec
.d_type
== QType::RRSIG
) {
1640 auto rrc
= getRR
<RRSIGRecordContent
>(rec
);
1642 cspmap
[{rec
.d_name
,rrc
->d_type
}].signatures
.push_back(rrc
);
1646 for(const auto& rec
: ne
.DNSSECRecords
.records
) {
1647 cspmap
[{rec
.d_name
, rec
.d_type
}].records
.push_back(rec
.d_content
);
1652 // TODO remove after processRecords is fixed!
1653 // Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
1654 static void addNXNSECS(vector
<DNSRecord
>&ret
, const vector
<DNSRecord
>& records
)
1656 NegCache::NegCacheEntry ne
;
1657 harvestNXRecords(records
, ne
, 0, nullptr);
1658 ret
.insert(ret
.end(), ne
.authoritySOA
.signatures
.begin(), ne
.authoritySOA
.signatures
.end());
1659 ret
.insert(ret
.end(), ne
.DNSSECRecords
.records
.begin(), ne
.DNSSECRecords
.records
.end());
1660 ret
.insert(ret
.end(), ne
.DNSSECRecords
.signatures
.begin(), ne
.DNSSECRecords
.signatures
.end());
1663 bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine
& dfe
, const NsSet
& nameservers
)
1666 for (auto const &ns
: nameservers
) {
1667 d_appliedPolicy
= dfe
.getProcessingPolicy(ns
.first
, d_discardedPolicies
);
1668 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1669 LOG(", however nameserver "<<ns
.first
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1673 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1674 for (auto const &address
: ns
.second
.first
) {
1675 d_appliedPolicy
= dfe
.getProcessingPolicy(address
, d_discardedPolicies
);
1676 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1677 LOG(", however nameserver "<<ns
.first
<<" IP address "<<address
.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1686 bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine
& dfe
, const ComboAddress
& remoteIP
)
1689 d_appliedPolicy
= dfe
.getProcessingPolicy(remoteIP
, d_discardedPolicies
);
1690 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) {
1691 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")+"')");
1698 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
)
1700 vector
<ComboAddress
> result
;
1702 if(!tns
->first
.empty()) {
1703 LOG(prefix
<<qname
<<": Trying to resolve NS '"<<tns
->first
<< "' ("<<1+tns
-rnameservers
.begin()<<"/"<<(unsigned int)rnameservers
.size()<<")"<<endl
);
1704 result
= getAddrs(tns
->first
, depth
+2, beenthere
, cacheOnly
);
1705 pierceDontQuery
=false;
1708 LOG(prefix
<<qname
<<": Domain has hardcoded nameserver");
1710 if(nameservers
[tns
->first
].first
.size() > 1) {
1715 sendRDQuery
= nameservers
[tns
->first
].second
;
1716 result
= shuffleForwardSpeed(nameservers
[tns
->first
].first
, doLog() ? (prefix
+qname
.toString()+": ") : string(), sendRDQuery
);
1717 pierceDontQuery
=true;
1722 bool SyncRes::throttledOrBlocked(const std::string
& prefix
, const ComboAddress
& remoteIP
, const DNSName
& qname
, const QType
& qtype
, bool pierceDontQuery
)
1724 if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0))) {
1725 LOG(prefix
<<qname
<<": server throttled "<<endl
);
1726 s_throttledqueries
++; d_throttledqueries
++;
1729 else if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()))) {
1730 LOG(prefix
<<qname
<<": query throttled "<<remoteIP
.toString()<<", "<<qname
<<"; "<<qtype
.getName()<<endl
);
1731 s_throttledqueries
++; d_throttledqueries
++;
1734 else if(!pierceDontQuery
&& s_dontQuery
&& s_dontQuery
->match(&remoteIP
)) {
1735 LOG(prefix
<<qname
<<": not sending query to " << remoteIP
.toString() << ", blocked by 'dont-query' setting" << endl
);
1742 bool SyncRes::validationEnabled() const
1744 return g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
;
1747 uint32_t SyncRes::computeLowestTTD(const std::vector
<DNSRecord
>& records
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, uint32_t signaturesTTL
) const
1749 uint32_t lowestTTD
= std::numeric_limits
<uint32_t>::max();
1750 for(const auto& record
: records
)
1751 lowestTTD
= min(lowestTTD
, record
.d_ttl
);
1753 /* even if it was not requested for that request (Process, and neither AD nor DO set),
1754 it might be requested at a later time so we need to be careful with the TTL. */
1755 if (validationEnabled() && !signatures
.empty()) {
1756 /* if we are validating, we don't want to cache records after their signatures expire. */
1757 /* records TTL are now TTD, let's add 'now' to the signatures lowest TTL */
1758 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(signaturesTTL
+ d_now
.tv_sec
));
1760 for(const auto& sig
: signatures
) {
1761 if (isRRSIGNotExpired(d_now
.tv_sec
, sig
)) {
1762 // we don't decerement d_sigexpire by 'now' because we actually want a TTD, not a TTL */
1763 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(sig
->d_sigexpire
));
1771 void SyncRes::updateValidationState(vState
& state
, const vState stateUpdate
)
1773 LOG(d_prefix
<<"validation state was "<<std::string(vStates
[state
])<<", state update is "<<std::string(vStates
[stateUpdate
]));
1775 if (stateUpdate
== TA
) {
1778 else if (stateUpdate
== NTA
) {
1781 else if (stateUpdate
== Bogus
) {
1784 else if (state
== Indeterminate
) {
1785 state
= stateUpdate
;
1787 else if (stateUpdate
== Insecure
) {
1788 if (state
!= Bogus
) {
1792 LOG(", validation state is now "<<std::string(vStates
[state
])<<endl
);
1795 vState
SyncRes::getTA(const DNSName
& zone
, dsmap_t
& ds
)
1797 auto luaLocal
= g_luaconfs
.getLocal();
1799 if (luaLocal
->dsAnchors
.empty()) {
1800 LOG(d_prefix
<<": No trust anchors configured, everything is Insecure"<<endl
);
1801 /* We have no TA, everything is insecure */
1806 if (haveNegativeTrustAnchor(luaLocal
->negAnchors
, zone
, reason
)) {
1807 LOG(d_prefix
<<": got NTA for '"<<zone
<<"'"<<endl
);
1811 if (getTrustAnchor(luaLocal
->dsAnchors
, zone
, ds
)) {
1812 LOG(d_prefix
<<": got TA for '"<<zone
<<"'"<<endl
);
1816 LOG(d_prefix
<<": no TA found for '"<<zone
<<"' among "<< luaLocal
->dsAnchors
.size()<<endl
);
1819 if (zone
.isRoot()) {
1820 /* No TA for the root */
1824 return Indeterminate
;
1827 static size_t countSupportedDS(const dsmap_t
& dsmap
)
1831 for (const auto& ds
: dsmap
) {
1832 if (isSupportedDS(ds
)) {
1840 vState
SyncRes::getDSRecords(const DNSName
& zone
, dsmap_t
& ds
, bool taOnly
, unsigned int depth
, bool bogusOnNXD
, bool* foundCut
)
1842 vState result
= getTA(zone
, ds
);
1844 if (result
!= Indeterminate
|| taOnly
) {
1846 *foundCut
= (result
!= Indeterminate
);
1850 if (countSupportedDS(ds
) == 0) {
1858 else if (result
== NTA
) {
1865 bool oldSkipCNAME
= d_skipCNAMECheck
;
1866 d_skipCNAMECheck
= true;
1868 std::set
<GetBestNSAnswer
> beenthere
;
1869 std::vector
<DNSRecord
> dsrecords
;
1871 vState state
= Indeterminate
;
1872 int rcode
= doResolve(zone
, QType(QType::DS
), dsrecords
, depth
+ 1, beenthere
, state
);
1873 d_skipCNAMECheck
= oldSkipCNAME
;
1875 if (rcode
== RCode::NoError
|| (rcode
== RCode::NXDomain
&& !bogusOnNXD
)) {
1876 uint8_t bestDigestType
= 0;
1878 bool gotCNAME
= false;
1879 for (const auto& record
: dsrecords
) {
1880 if (record
.d_type
== QType::DS
) {
1881 const auto dscontent
= getRR
<DSRecordContent
>(record
);
1882 if (dscontent
&& isSupportedDS(*dscontent
)) {
1883 // Make GOST a lower prio than SHA256
1884 if (dscontent
->d_digesttype
== DNSSECKeeper::GOST
&& bestDigestType
== DNSSECKeeper::SHA256
) {
1887 if (dscontent
->d_digesttype
> bestDigestType
|| (bestDigestType
== DNSSECKeeper::GOST
&& dscontent
->d_digesttype
== DNSSECKeeper::SHA256
)) {
1888 bestDigestType
= dscontent
->d_digesttype
;
1890 ds
.insert(*dscontent
);
1893 else if (record
.d_type
== QType::CNAME
&& record
.d_name
== zone
) {
1898 /* RFC 4509 section 3: "Validator implementations SHOULD ignore DS RRs containing SHA-1
1899 * digests if DS RRs with SHA-256 digests are present in the DS RRset."
1900 * As SHA348 is specified as well, the spirit of the this line is "use the best algorithm".
1902 for (auto dsrec
= ds
.begin(); dsrec
!= ds
.end(); ) {
1903 if (dsrec
->d_digesttype
!= bestDigestType
) {
1904 dsrec
= ds
.erase(dsrec
);
1911 if (rcode
== RCode::NoError
) {
1913 /* we have no DS, it's either:
1914 - a delegation to a non-DNSSEC signed zone
1915 - no delegation, we stay in the same zone
1917 if (gotCNAME
|| denialProvesNoDelegation(zone
, dsrecords
)) {
1918 /* we are still inside the same zone */
1926 /* delegation with no DS, might be Secure -> Insecure */
1931 /* a delegation with no DS is either:
1932 - a signed zone (Secure) to an unsigned one (Insecure)
1933 - an unsigned zone to another unsigned one (Insecure stays Insecure, Bogus stays Bogus)
1935 return state
== Secure
? Insecure
: state
;
1947 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
1951 bool SyncRes::haveExactValidationStatus(const DNSName
& domain
)
1953 if (!shouldValidate()) {
1956 const auto& it
= d_cutStates
.find(domain
);
1957 if (it
!= d_cutStates
.cend()) {
1963 vState
SyncRes::getValidationStatus(const DNSName
& subdomain
, bool allowIndeterminate
)
1965 vState result
= Indeterminate
;
1967 if (!shouldValidate()) {
1970 DNSName
name(subdomain
);
1972 const auto& it
= d_cutStates
.find(name
);
1973 if (it
!= d_cutStates
.cend()) {
1974 if (allowIndeterminate
|| it
->second
!= Indeterminate
) {
1975 LOG(d_prefix
<<": got status "<<vStates
[it
->second
]<<" for name "<<subdomain
<<" (from "<<name
<<")"<<endl
);
1980 while (name
.chopOff());
1985 bool SyncRes::lookForCut(const DNSName
& qname
, unsigned int depth
, const vState existingState
, vState
& newState
)
1987 bool foundCut
= false;
1989 vState dsState
= getDSRecords(qname
, ds
, newState
== Bogus
|| existingState
== Insecure
|| existingState
== Bogus
, depth
, false, &foundCut
);
1991 if (dsState
!= Indeterminate
) {
1998 void SyncRes::computeZoneCuts(const DNSName
& begin
, const DNSName
& end
, unsigned int depth
)
2000 if(!begin
.isPartOf(end
)) {
2001 LOG(d_prefix
<<" "<<begin
.toLogString()<<" is not part of "<<end
.toLogString()<<endl
);
2002 throw PDNSException(begin
.toLogString() + " is not part of " + end
.toLogString());
2005 if (d_cutStates
.count(begin
) != 0) {
2010 vState cutState
= getDSRecords(end
, ds
, false, depth
);
2011 LOG(d_prefix
<<": setting cut state for "<<end
<<" to "<<vStates
[cutState
]<<endl
);
2012 d_cutStates
[end
] = cutState
;
2014 if (!shouldValidate()) {
2019 std::vector
<string
> labelsToAdd
= begin
.makeRelative(end
).getRawLabels();
2021 bool oldSkipCNAME
= d_skipCNAMECheck
;
2022 d_skipCNAMECheck
= true;
2024 while(qname
!= begin
) {
2025 if (labelsToAdd
.empty())
2028 qname
.prependRawLabel(labelsToAdd
.back());
2029 labelsToAdd
.pop_back();
2030 LOG(d_prefix
<<": - Looking for a cut at "<<qname
<<endl
);
2032 const auto cutIt
= d_cutStates
.find(qname
);
2033 if (cutIt
!= d_cutStates
.cend()) {
2034 if (cutIt
->second
!= Indeterminate
) {
2035 LOG(d_prefix
<<": - Cut already known at "<<qname
<<endl
);
2036 cutState
= cutIt
->second
;
2041 /* no need to look for NS and DS if we are already insecure or bogus,
2044 if (cutState
== Insecure
|| cutState
== Bogus
) {
2046 vState newState
= getDSRecords(qname
, cutDS
, true, depth
);
2047 if (newState
== Indeterminate
) {
2051 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[newState
]<<endl
);
2052 cutState
= newState
;
2054 d_cutStates
[qname
] = cutState
;
2059 vState newState
= Indeterminate
;
2060 /* temporarily mark as Indeterminate, so that we won't enter an endless loop
2061 trying to determine that zone cut again. */
2062 d_cutStates
[qname
] = newState
;
2063 bool foundCut
= lookForCut(qname
, depth
+ 1, cutState
, newState
);
2065 LOG(d_prefix
<<": - Found cut at "<<qname
<<endl
);
2066 if (newState
!= Indeterminate
) {
2067 cutState
= newState
;
2069 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[cutState
]<<endl
);
2070 d_cutStates
[qname
] = cutState
;
2073 /* remove the temporary cut */
2074 LOG(d_prefix
<<qname
<<": removing cut state for "<<qname
<<endl
);
2075 d_cutStates
.erase(qname
);
2079 d_skipCNAMECheck
= oldSkipCNAME
;
2081 LOG(d_prefix
<<": list of cuts from "<<begin
<<" to "<<end
<<endl
);
2082 for (const auto& cut
: d_cutStates
) {
2083 if (cut
.first
.isRoot() || (begin
.isPartOf(cut
.first
) && cut
.first
.isPartOf(end
))) {
2084 LOG(" - "<<cut
.first
<<": "<<vStates
[cut
.second
]<<endl
);
2089 vState
SyncRes::validateDNSKeys(const DNSName
& zone
, const std::vector
<DNSRecord
>& dnskeys
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, unsigned int depth
)
2092 if (!signatures
.empty()) {
2093 DNSName signer
= getSigner(signatures
);
2095 if (!signer
.empty() && zone
.isPartOf(signer
)) {
2096 vState state
= getDSRecords(signer
, ds
, false, depth
);
2098 if (state
!= Secure
) {
2104 skeyset_t tentativeKeys
;
2105 std::vector
<shared_ptr
<DNSRecordContent
> > toSign
;
2107 for (const auto& dnskey
: dnskeys
) {
2108 if (dnskey
.d_type
== QType::DNSKEY
) {
2109 auto content
= getRR
<DNSKEYRecordContent
>(dnskey
);
2111 tentativeKeys
.insert(content
);
2112 toSign
.push_back(content
);
2117 LOG(d_prefix
<<": trying to validate "<<std::to_string(tentativeKeys
.size())<<" DNSKEYs with "<<std::to_string(ds
.size())<<" DS"<<endl
);
2118 skeyset_t validatedKeys
;
2119 validateDNSKeysAgainstDS(d_now
.tv_sec
, zone
, ds
, tentativeKeys
, toSign
, signatures
, validatedKeys
);
2121 LOG(d_prefix
<<": we now have "<<std::to_string(validatedKeys
.size())<<" DNSKEYs"<<endl
);
2123 /* if we found at least one valid RRSIG covering the set,
2124 all tentative keys are validated keys. Otherwise it means
2125 we haven't found at least one DNSKEY and a matching RRSIG
2126 covering this set, this looks Bogus. */
2127 if (validatedKeys
.size() != tentativeKeys
.size()) {
2128 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
2135 vState
SyncRes::getDNSKeys(const DNSName
& signer
, skeyset_t
& keys
, unsigned int depth
)
2137 std::vector
<DNSRecord
> records
;
2138 std::set
<GetBestNSAnswer
> beenthere
;
2139 LOG(d_prefix
<<"Retrieving DNSKeys for "<<signer
<<endl
);
2141 vState state
= Indeterminate
;
2142 /* following CNAME might lead to us to the wrong DNSKEY */
2143 bool oldSkipCNAME
= d_skipCNAMECheck
;
2144 d_skipCNAMECheck
= true;
2145 int rcode
= doResolve(signer
, QType(QType::DNSKEY
), records
, depth
+ 1, beenthere
, state
);
2146 d_skipCNAMECheck
= oldSkipCNAME
;
2148 if (rcode
== RCode::NoError
) {
2149 if (state
== Secure
) {
2150 for (const auto& key
: records
) {
2151 if (key
.d_type
== QType::DNSKEY
) {
2152 auto content
= getRR
<DNSKEYRecordContent
>(key
);
2154 keys
.insert(content
);
2159 LOG(d_prefix
<<"Retrieved "<<keys
.size()<<" DNSKeys for "<<signer
<<", state is "<<vStates
[state
]<<endl
);
2163 LOG(d_prefix
<<"Returning Bogus state from "<<__func__
<<"("<<signer
<<")"<<endl
);
2167 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
)
2170 if (!signatures
.empty()) {
2171 const DNSName signer
= getSigner(signatures
);
2172 if (!signer
.empty() && name
.isPartOf(signer
)) {
2173 if ((qtype
== QType::DNSKEY
|| qtype
== QType::DS
) && signer
== qname
) {
2174 /* we are already retrieving those keys, sorry */
2175 if (qtype
== QType::DS
) {
2176 /* something is very wrong */
2177 LOG(d_prefix
<<"The DS for "<<qname
<<" is signed by itself, going Bogus"<<endl
);
2180 return Indeterminate
;
2182 vState state
= getDNSKeys(signer
, keys
, depth
);
2183 if (state
!= Secure
) {
2188 LOG(d_prefix
<<"Bogus!"<<endl
);
2192 std::vector
<std::shared_ptr
<DNSRecordContent
> > recordcontents
;
2193 for (const auto& record
: records
) {
2194 recordcontents
.push_back(record
.d_content
);
2197 LOG(d_prefix
<<"Going to validate "<<recordcontents
.size()<< " record contents with "<<signatures
.size()<<" sigs and "<<keys
.size()<<" keys for "<<name
<<endl
);
2198 if (validateWithKeySet(d_now
.tv_sec
, name
, recordcontents
, signatures
, keys
, false)) {
2199 LOG(d_prefix
<<"Secure!"<<endl
);
2203 LOG(d_prefix
<<"Bogus!"<<endl
);
2207 static bool allowAdditionalEntry(std::unordered_set
<DNSName
>& allowedAdditionals
, const DNSRecord
& rec
)
2209 switch(rec
.d_type
) {
2212 if (auto mxContent
= getRR
<MXRecordContent
>(rec
)) {
2213 allowedAdditionals
.insert(mxContent
->d_mxname
);
2219 if (auto nsContent
= getRR
<NSRecordContent
>(rec
)) {
2220 allowedAdditionals
.insert(nsContent
->getNS());
2226 if (auto srvContent
= getRR
<SRVRecordContent
>(rec
)) {
2227 allowedAdditionals
.insert(srvContent
->d_target
);
2236 void SyncRes::sanitizeRecords(const std::string
& prefix
, LWResult
& lwr
, const DNSName
& qname
, const QType
& qtype
, const DNSName
& auth
, bool wasForwarded
, bool rdQuery
)
2238 const bool wasForwardRecurse
= wasForwarded
&& rdQuery
;
2239 /* list of names for which we will allow A and AAAA records in the additional section
2241 std::unordered_set
<DNSName
> allowedAdditionals
= { qname
};
2242 bool haveAnswers
= false;
2243 bool isNXDomain
= false;
2244 bool isNXQType
= false;
2246 for(auto rec
= lwr
.d_records
.begin(); rec
!= lwr
.d_records
.end(); ) {
2248 if (rec
->d_type
== QType::OPT
) {
2253 if (rec
->d_class
!= QClass::IN
) {
2254 LOG(prefix
<<"Removing non internet-classed data received from "<<auth
<<endl
);
2255 rec
= lwr
.d_records
.erase(rec
);
2259 if (rec
->d_type
== QType::ANY
) {
2260 LOG(prefix
<<"Removing 'ANY'-typed data received from "<<auth
<<endl
);
2261 rec
= lwr
.d_records
.erase(rec
);
2265 if (!rec
->d_name
.isPartOf(auth
)) {
2266 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
);
2267 rec
= lwr
.d_records
.erase(rec
);
2271 /* dealing with the records in answer */
2272 if (!(lwr
.d_aabit
|| wasForwardRecurse
) && rec
->d_place
== DNSResourceRecord::ANSWER
) {
2273 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2274 are sending such responses */
2275 if (!(rec
->d_type
== QType::CNAME
&& qname
== rec
->d_name
)) {
2276 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
);
2277 rec
= lwr
.d_records
.erase(rec
);
2282 if (rec
->d_type
== QType::DNAME
&& (rec
->d_place
!= DNSResourceRecord::ANSWER
|| !qname
.isPartOf(rec
->d_name
))) {
2283 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
);
2284 rec
= lwr
.d_records
.erase(rec
);
2288 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
)) {
2289 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
);
2290 rec
= lwr
.d_records
.erase(rec
);
2294 if (rec
->d_place
== DNSResourceRecord::ANSWER
&& !haveAnswers
) {
2298 if (rec
->d_place
== DNSResourceRecord::ANSWER
) {
2299 allowAdditionalEntry(allowedAdditionals
, *rec
);
2302 /* dealing with the records in authority */
2303 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
) {
2304 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
);
2305 rec
= lwr
.d_records
.erase(rec
);
2309 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::SOA
) {
2310 if (!qname
.isPartOf(rec
->d_name
)) {
2311 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
);
2312 rec
= lwr
.d_records
.erase(rec
);
2316 if (!(lwr
.d_aabit
|| wasForwardRecurse
)) {
2317 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
);
2318 rec
= lwr
.d_records
.erase(rec
);
2323 if (lwr
.d_rcode
== RCode::NXDomain
) {
2326 else if (lwr
.d_rcode
== RCode::NoError
) {
2332 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::NS
&& (isNXDomain
|| isNXQType
)) {
2333 /* we don't want to pick up NS records in AUTHORITY or ADDITIONAL sections of NXDomain answers
2334 because they are somewhat easy to insert into a large, fragmented UDP response
2335 for an off-path attacker by injecting spoofed UDP fragments.
2337 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
);
2338 rec
= lwr
.d_records
.erase(rec
);
2342 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::NS
) {
2343 allowAdditionalEntry(allowedAdditionals
, *rec
);
2346 /* dealing with the records in additional */
2347 if (rec
->d_place
== DNSResourceRecord::ADDITIONAL
&& rec
->d_type
!= QType::A
&& rec
->d_type
!= QType::AAAA
&& rec
->d_type
!= QType::RRSIG
) {
2348 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
);
2349 rec
= lwr
.d_records
.erase(rec
);
2353 if (rec
->d_place
== DNSResourceRecord::ADDITIONAL
&& allowedAdditionals
.count(rec
->d_name
) == 0) {
2354 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
);
2355 rec
= lwr
.d_records
.erase(rec
);
2363 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
)
2365 bool wasForwardRecurse
= wasForwarded
&& rdQuery
;
2371 prefix
.append(depth
, ' ');
2374 sanitizeRecords(prefix
, lwr
, qname
, qtype
, auth
, wasForwarded
, rdQuery
);
2376 std::vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
2377 const unsigned int labelCount
= qname
.countLabels();
2378 bool isCNAMEAnswer
= false;
2379 bool isDNAMEAnswer
= false;
2380 for(const auto& rec
: lwr
.d_records
) {
2381 if (rec
.d_class
!= QClass::IN
) {
2385 if(!isCNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
&& !isDNAMEAnswer
) {
2386 isCNAMEAnswer
= true;
2388 if(!isDNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::DNAME
&& qtype
!= QType(QType::DNAME
) && qname
.isPartOf(rec
.d_name
)) {
2389 isDNAMEAnswer
= true;
2390 isCNAMEAnswer
= false;
2393 /* if we have a positive answer synthetized from a wildcard,
2394 we need to store the corresponding NSEC/NSEC3 records proving
2395 that the exact name did not exist in the negative cache */
2396 if(gatherWildcardProof
) {
2397 if (nsecTypes
.count(rec
.d_type
)) {
2398 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
2400 else if (rec
.d_type
== QType::RRSIG
) {
2401 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
2402 if (rrsig
&& nsecTypes
.count(rrsig
->d_type
)) {
2403 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
2407 if(rec
.d_type
== QType::RRSIG
) {
2408 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
2410 /* As illustrated in rfc4035's Appendix B.6, the RRSIG label
2411 count can be lower than the name's label count if it was
2412 synthetized from the wildcard. Note that the difference might
2414 if (rec
.d_name
== qname
&& isWildcardExpanded(labelCount
, rrsig
)) {
2415 gatherWildcardProof
= true;
2416 if (!isWildcardExpandedOntoItself(rec
.d_name
, labelCount
, rrsig
)) {
2417 /* if we have a wildcard expanded onto itself, we don't need to prove
2418 that the exact name doesn't exist because it actually does.
2419 We still want to gather the corresponding NSEC/NSEC3 records
2420 to pass them to our client in case it wants to validate by itself.
2422 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthetized from a wildcard, we need a wildcard proof"<<endl
);
2423 needWildcardProof
= true;
2426 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthetized from a wildcard expanded onto itself, we need to gather wildcard proof"<<endl
);
2428 wildcardLabelsCount
= rrsig
->d_labels
;
2431 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
2432 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
2433 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
);
2438 // reap all answers from this packet that are acceptable
2439 for(auto& rec
: lwr
.d_records
) {
2440 if(rec
.d_type
== QType::OPT
) {
2441 LOG(prefix
<<qname
<<": OPT answer '"<<rec
.d_name
<<"' from '"<<auth
<<"' nameservers" <<endl
);
2444 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
<<" ");
2445 if(rec
.d_type
== QType::ANY
) {
2446 LOG("NO! - we don't accept 'ANY'-typed data"<<endl
);
2450 if(rec
.d_class
!= QClass::IN
) {
2451 LOG("NO! - we don't accept records for any other class than 'IN'"<<endl
);
2455 if (!(lwr
.d_aabit
|| wasForwardRecurse
) && rec
.d_place
== DNSResourceRecord::ANSWER
) {
2456 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2457 are sending such responses */
2458 if (!(rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
)) {
2459 LOG("NO! - we don't accept records in the answers section without the AA bit set"<<endl
);
2464 if(rec
.d_name
.isPartOf(auth
)) {
2465 if(rec
.d_type
== QType::RRSIG
) {
2466 LOG("RRSIG - separate"<<endl
);
2468 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
)) {
2469 LOG("NO! Is from delegation-only zone"<<endl
);
2471 return RCode::NXDomain
;
2474 bool haveLogged
= false;
2475 if (isDNAMEAnswer
&& rec
.d_type
== QType::CNAME
) {
2476 LOG("NO - we already have a DNAME answer for this domain");
2479 if (!t_sstorage
.domainmap
->empty()) {
2480 // Check if we are authoritative for a zone in this answer
2481 DNSName
tmp_qname(rec
.d_name
);
2482 auto auth_domain_iter
=getBestAuthZone(&tmp_qname
);
2483 if(auth_domain_iter
!=t_sstorage
.domainmap
->end() &&
2484 auth
.countLabels() <= auth_domain_iter
->first
.countLabels()) {
2485 if (auth_domain_iter
->first
!= auth
) {
2486 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter
->first
<<endl
);
2489 LOG("YES! - This answer was ");
2490 if (!wasForwarded
) {
2491 LOG("retrieved from the local auth store.");
2493 LOG("received from a server we forward to.");
2504 rec
.d_ttl
=min(s_maxcachettl
, rec
.d_ttl
);
2507 dr
.d_ttl
+= d_now
.tv_sec
;
2508 dr
.d_place
=DNSResourceRecord::ANSWER
;
2509 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(dr
);
2517 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2518 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)
2519 uint32_t lowestTTD
=computeLowestTTD(i
->second
.records
, i
->second
.signatures
, i
->second
.signaturesTTL
);
2521 for(auto& record
: i
->second
.records
)
2522 record
.d_ttl
= lowestTTD
; // boom
2525 // cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
2526 // cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
2529 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2531 if(i
->second
.records
.empty()) // this happens when we did store signatures, but passed on the records themselves
2534 /* Even if the AA bit is set, additional data cannot be considered
2535 as authoritative. This is especially important during validation
2536 because keeping records in the additional section is allowed even
2537 if the corresponding RRSIGs are not included, without setting the TC
2538 bit, as stated in rfc4035's section 3.1.1. Including RRSIG RRs in a Response:
2539 "When placing a signed RRset in the Additional section, the name
2540 server MUST also place its RRSIG RRs in the Additional section.
2541 If space does not permit inclusion of both the RRset and its
2542 associated RRSIG RRs, the name server MAY retain the RRset while
2543 dropping the RRSIG RRs. If this happens, the name server MUST NOT
2544 set the TC bit solely because these RRSIG RRs didn't fit."
2546 bool isAA
= lwr
.d_aabit
&& i
->first
.place
!= DNSResourceRecord::ADDITIONAL
;
2547 /* if we forwarded the query to a recursor, we can expect the answer to be signed,
2548 even if the answer is not AA. Of course that's not only true inside a Secure
2549 zone, but we check that below. */
2550 bool expectSignature
= i
->first
.place
== DNSResourceRecord::ANSWER
|| ((lwr
.d_aabit
|| wasForwardRecurse
) && i
->first
.place
!= DNSResourceRecord::ADDITIONAL
);
2551 if (isCNAMEAnswer
&& (i
->first
.place
!= DNSResourceRecord::ANSWER
|| i
->first
.type
!= QType::CNAME
|| i
->first
.name
!= qname
)) {
2554 Note that the answer section of an authoritative answer normally
2555 contains only authoritative data. However when the name sought is an
2556 alias (see section 10.1.1) only the record describing that alias is
2557 necessarily authoritative. Clients should assume that other records
2558 may have come from the server's cache. Where authoritative answers
2559 are required, the client should query again, using the canonical name
2560 associated with the alias.
2563 expectSignature
= false;
2566 if (isCNAMEAnswer
&& i
->first
.place
== DNSResourceRecord::AUTHORITY
&& i
->first
.type
== QType::NS
&& auth
== i
->first
.name
) {
2567 /* These NS can't be authoritative since we have a CNAME answer for which (see above) only the
2568 record describing that alias is necessarily authoritative.
2569 But if we allow the current auth, which might be serving the child zone, to raise the TTL
2570 of non-authoritative NS in the cache, they might be able to keep a "ghost" zone alive forever,
2571 even after the delegation is gone from the parent.
2572 So let's just do nothing with them, we can fetch them directly if we need them.
2574 LOG(d_prefix
<<": skipping authority NS from '"<<auth
<<"' nameservers in CNAME answer "<<i
->first
.name
<<"|"<<DNSRecordContent::NumberToType(i
->first
.type
)<<endl
);
2578 vState recordState
= getValidationStatus(i
->first
.name
, false);
2579 LOG(d_prefix
<<": got initial zone status "<<vStates
[recordState
]<<" for record "<<i
->first
.name
<<"|"<<DNSRecordContent::NumberToType(i
->first
.type
)<<endl
);
2581 if (shouldValidate() && recordState
== Secure
) {
2582 vState initialState
= recordState
;
2584 if (expectSignature
) {
2585 if (i
->first
.place
!= DNSResourceRecord::ADDITIONAL
) {
2586 /* the additional entries can be insecure,
2588 "Glue address RRsets associated with delegations MUST NOT be signed"
2590 if (i
->first
.type
== QType::DNSKEY
&& i
->first
.place
== DNSResourceRecord::ANSWER
) {
2591 LOG(d_prefix
<<"Validating DNSKEY for "<<i
->first
.name
<<endl
);
2592 recordState
= validateDNSKeys(i
->first
.name
, i
->second
.records
, i
->second
.signatures
, depth
);
2596 * RFC 6672 section 5.3.1
2597 * In any response, a signed DNAME RR indicates a non-terminal
2598 * redirection of the query. There might or might not be a server-
2599 * synthesized CNAME in the answer section; if there is, the CNAME will
2600 * never be signed. For a DNSSEC validator, verification of the DNAME
2601 * RR and then that the CNAME was properly synthesized is sufficient
2604 * We do the synthesis check in processRecords, here we make sure we
2605 * don't validate the CNAME.
2607 if (!(isDNAMEAnswer
&& i
->first
.type
== QType::CNAME
)) {
2608 LOG(d_prefix
<<"Validating non-additional record for "<<i
->first
.name
<<endl
);
2609 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2610 /* 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 */
2611 if (qtype
== QType::NS
&& i
->second
.signatures
.empty() && recordState
== Bogus
&& haveExactValidationStatus(i
->first
.name
) && getValidationStatus(i
->first
.name
) == Indeterminate
) {
2612 recordState
= Indeterminate
;
2619 recordState
= Indeterminate
;
2621 /* in a non authoritative answer, we only care about the DS record (or lack of) */
2622 if ((i
->first
.type
== QType::DS
|| i
->first
.type
== QType::NSEC
|| i
->first
.type
== QType::NSEC3
) && i
->first
.place
== DNSResourceRecord::AUTHORITY
) {
2623 LOG(d_prefix
<<"Validating DS record for "<<i
->first
.name
<<endl
);
2624 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2628 if (initialState
== Secure
&& state
!= recordState
&& expectSignature
) {
2629 updateValidationState(state
, recordState
);
2633 if (shouldValidate()) {
2634 LOG(d_prefix
<<"Skipping validation because the current state is "<<vStates
[recordState
]<<endl
);
2638 if (recordState
== Bogus
) {
2639 /* this is a TTD by now, be careful */
2640 for(auto& record
: i
->second
.records
) {
2641 record
.d_ttl
= std::min(record
.d_ttl
, static_cast<uint32_t>(s_maxbogusttl
+ d_now
.tv_sec
));
2645 /* We don't need to store NSEC3 records in the positive cache because:
2646 - we don't allow direct NSEC3 queries
2647 - denial of existence proofs in wildcard expanded positive responses are stored in authorityRecs
2648 - denial of existence proofs for negative responses are stored in the negative cache
2649 We also don't want to cache non-authoritative data except for:
2650 - records coming from non forward-recurse servers (those will never be AA)
2652 - NS, A and AAAA (used for infra queries)
2654 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
)) {
2656 bool doCache
= true;
2657 if (i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
) {
2658 // If ednsmask is relevant, we do not want to cache if the scope prefix length is large and TTL is small
2659 if (SyncRes::s_ecscachelimitttl
> 0) {
2660 bool manyMaskBits
= (ednsmask
->isIpv4() && ednsmask
->getBits() > SyncRes::s_ecsipv4cachelimit
) ||
2661 (ednsmask
->isIpv6() && ednsmask
->getBits() > SyncRes::s_ecsipv6cachelimit
);
2664 uint32_t minttl
= UINT32_MAX
;
2665 for (const auto &it
: i
->second
.records
) {
2666 if (it
.d_ttl
< minttl
)
2669 bool ttlIsSmall
= minttl
< SyncRes::s_ecscachelimitttl
+ d_now
.tv_sec
;
2671 // Case: many bits and ttlIsSmall
2678 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
);
2682 if(i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
)
2686 return RCode::NoError
;
2689 void SyncRes::updateDenialValidationState(vState
& neValidationState
, const DNSName
& neName
, vState
& state
, const dState denialState
, const dState expectedState
, bool allowOptOut
)
2691 if (denialState
== expectedState
) {
2692 neValidationState
= Secure
;
2695 if (denialState
== OPTOUT
&& allowOptOut
) {
2696 LOG(d_prefix
<<"OPT-out denial found for "<<neName
<<endl
);
2697 neValidationState
= Secure
;
2700 else if (denialState
== INSECURE
) {
2701 LOG(d_prefix
<<"Insecure denial found for "<<neName
<<", returning Insecure"<<endl
);
2702 neValidationState
= Insecure
;
2705 LOG(d_prefix
<<"Invalid denial found for "<<neName
<<", returning Bogus, res="<<denialState
<<", expectedState="<<expectedState
<<endl
);
2706 neValidationState
= Bogus
;
2708 updateValidationState(state
, neValidationState
);
2712 dState
SyncRes::getDenialValidationState(const NegCache::NegCacheEntry
& ne
, const vState state
, const dState expectedState
, bool referralToUnsigned
)
2714 cspmap_t csp
= harvestCSPFromNE(ne
);
2715 return getDenial(csp
, ne
.d_name
, ne
.d_qtype
.getCode(), referralToUnsigned
, expectedState
== NXQTYPE
);
2718 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
)
2721 DNSName dnameTarget
, dnameOwner
;
2722 uint32_t dnameTTL
= 0;
2724 for(auto& rec
: lwr
.d_records
) {
2725 if (rec
.d_type
!=QType::OPT
&& rec
.d_class
!=QClass::IN
)
2728 if (rec
.d_place
==DNSResourceRecord::ANSWER
&& !(lwr
.d_aabit
|| sendRDQuery
)) {
2729 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2730 are sending such responses */
2731 if (!(rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
)) {
2736 if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2737 lwr
.d_rcode
==RCode::NXDomain
&& qname
.isPartOf(rec
.d_name
) && rec
.d_name
.isPartOf(auth
)) {
2738 LOG(prefix
<<qname
<<": got negative caching indication for name '"<<qname
<<"' (accept="<<rec
.d_name
.isPartOf(auth
)<<"), newtarget='"<<newtarget
<<"'"<<endl
);
2740 rec
.d_ttl
= min(rec
.d_ttl
, s_maxnegttl
);
2741 if(newtarget
.empty()) // only add a SOA if we're not going anywhere after this
2744 NegCache::NegCacheEntry ne
;
2746 uint32_t lowestTTL
= rec
.d_ttl
;
2747 /* if we get an NXDomain answer with a CNAME, the name
2748 does exist but the target does not */
2749 ne
.d_name
= newtarget
.empty() ? qname
: newtarget
;
2750 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2751 ne
.d_auth
= rec
.d_name
;
2752 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2754 if (state
== Secure
) {
2755 dState denialState
= getDenialValidationState(ne
, state
, NXDOMAIN
, false);
2756 updateDenialValidationState(ne
.d_validationState
, ne
.d_name
, state
, denialState
, NXDOMAIN
, false);
2759 ne
.d_validationState
= state
;
2762 if (ne
.d_validationState
== Bogus
) {
2763 lowestTTL
= min(lowestTTL
, s_maxbogusttl
);
2766 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2767 /* if we get an NXDomain answer with a CNAME, let's not cache the
2768 target, even the server was authoritative for it,
2769 and do an additional query for the CNAME target.
2770 We have a regression test making sure we do exactly that.
2772 if(!wasVariable() && newtarget
.empty()) {
2773 t_sstorage
.negcache
.add(ne
);
2774 if(s_rootNXTrust
&& ne
.d_auth
.isRoot() && auth
.isRoot() && lwr
.d_aabit
) {
2775 ne
.d_name
= ne
.d_name
.getLastLabel();
2776 t_sstorage
.negcache
.add(ne
);
2782 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& s_redirectionQTypes
.count(rec
.d_type
) > 0 && // CNAME or DNAME answer
2783 s_redirectionQTypes
.count(qtype
.getCode()) == 0) { // But not in response to a CNAME or DNAME query
2784 if (rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
) {
2785 if (!dnameOwner
.empty()) { // We synthesize ourselves
2789 if (auto content
= getRR
<CNAMERecordContent
>(rec
)) {
2790 newtarget
=content
->getTarget();
2792 } else if (rec
.d_type
== QType::DNAME
&& qname
.isPartOf(rec
.d_name
)) { // DNAME
2794 if (auto content
= getRR
<DNAMERecordContent
>(rec
)) {
2795 dnameOwner
= rec
.d_name
;
2796 dnameTarget
= content
->getTarget();
2797 dnameTTL
= rec
.d_ttl
;
2798 if (!newtarget
.empty()) { // We had a CNAME before, remove it from ret so we don't cache it
2799 ret
.erase(std::remove_if(
2802 [&qname
](DNSRecord
& rr
) {
2803 return (rr
.d_place
== DNSResourceRecord::ANSWER
&& rr
.d_type
== QType::CNAME
&& rr
.d_name
== qname
);
2808 newtarget
= qname
.makeRelative(dnameOwner
) + dnameTarget
;
2809 } catch (const std::exception
&e
) {
2810 // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
2811 // But there is no way to set the RCODE from this function
2812 throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + dnameOwner
.toLogString() +
2813 "', DNAME target: '" + dnameTarget
.toLogString() + "', substituted name: '" +
2814 qname
.makeRelative(dnameOwner
).toLogString() + "." + dnameTarget
.toLogString() +
2820 /* if we have a positive answer synthetized from a wildcard, we need to
2821 return the corresponding NSEC/NSEC3 records from the AUTHORITY section
2822 proving that the exact name did not exist */
2823 else if(gatherWildcardProof
&& (rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::AUTHORITY
) {
2824 ret
.push_back(rec
); // enjoy your DNSSEC
2826 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
2827 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&&
2829 rec
.d_type
==qtype
.getCode() || ((lwr
.d_aabit
|| sendRDQuery
) && qtype
== QType(QType::ANY
))
2833 LOG(prefix
<<qname
<<": answer is in: resolved to '"<< rec
.d_content
->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"'"<<endl
);
2837 if (state
== Secure
&& needWildcardProof
) {
2838 /* We have a positive answer synthetized from a wildcard, we need to check that we have
2839 proof that the exact name doesn't exist so the wildcard can be used,
2840 as described in section 5.3.4 of RFC 4035 and 5.3 of FRC 7129.
2842 NegCache::NegCacheEntry ne
;
2844 uint32_t lowestTTL
= rec
.d_ttl
;
2846 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2847 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2849 cspmap_t csp
= harvestCSPFromNE(ne
);
2850 dState res
= getDenial(csp
, qname
, ne
.d_qtype
.getCode(), false, false, false, wildcardLabelsCount
);
2851 if (res
!= NXDOMAIN
) {
2853 if (res
== INSECURE
) {
2854 /* Some part could not be validated, for example a NSEC3 record with a too large number of iterations,
2855 this is not enough to warrant a Bogus, but go Insecure. */
2857 LOG(d_prefix
<<"Unable to validate denial in wildcard expanded positive response found for "<<qname
<<", returning Insecure, res="<<res
<<endl
);
2860 LOG(d_prefix
<<"Invalid denial in wildcard expanded positive response found for "<<qname
<<", returning Bogus, res="<<res
<<endl
);
2861 rec
.d_ttl
= std::min(rec
.d_ttl
, s_maxbogusttl
);
2864 updateValidationState(state
, st
);
2865 /* we already stored the record with a different validation status, let's fix it */
2866 updateValidationStatusInCache(qname
, qtype
, lwr
.d_aabit
, st
);
2871 else if((rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::ANSWER
) {
2872 if(rec
.d_type
!= QType::RRSIG
|| rec
.d_name
== qname
) {
2873 ret
.push_back(rec
); // enjoy your DNSSEC
2874 } else if(rec
.d_type
== QType::RRSIG
&& qname
.isPartOf(rec
.d_name
)) {
2875 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
2876 if (rrsig
!= nullptr && rrsig
->d_type
== QType::DNAME
) {
2881 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::NS
&& qname
.isPartOf(rec
.d_name
)) {
2882 if(moreSpecificThan(rec
.d_name
,auth
)) {
2884 LOG(prefix
<<qname
<<": got NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2888 LOG(prefix
<<qname
<<": got upwards/level NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"', had '"<<auth
<<"'"<<endl
);
2890 if (auto content
= getRR
<NSRecordContent
>(rec
)) {
2891 nsset
.insert(content
->getNS());
2894 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::DS
&& qname
.isPartOf(rec
.d_name
)) {
2895 LOG(prefix
<<qname
<<": got DS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2897 else if(realreferral
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& (rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && newauth
.isPartOf(auth
)) {
2898 /* we might have received a denial of the DS, let's check */
2899 if (state
== Secure
) {
2900 NegCache::NegCacheEntry ne
;
2902 ne
.d_name
= newauth
;
2903 ne
.d_qtype
= QType::DS
;
2904 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2905 uint32_t lowestTTL
= rec
.d_ttl
;
2906 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2908 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, true);
2910 if (denialState
== NXQTYPE
|| denialState
== OPTOUT
|| denialState
== INSECURE
) {
2911 ne
.d_ttd
= lowestTTL
+ d_now
.tv_sec
;
2912 ne
.d_validationState
= Secure
;
2913 LOG(prefix
<<qname
<<": got negative indication of DS record for '"<<newauth
<<"'"<<endl
);
2915 if(!wasVariable()) {
2916 t_sstorage
.negcache
.add(ne
);
2919 if (qname
== newauth
&& qtype
== QType::DS
) {
2920 /* we are actually done! */
2927 else if(!done
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2928 lwr
.d_rcode
==RCode::NoError
&& qname
.isPartOf(rec
.d_name
)) {
2929 LOG(prefix
<<qname
<<": got negative caching indication for '"<< qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
2931 if(!newtarget
.empty()) {
2932 LOG(prefix
<<qname
<<": Hang on! Got a redirect to '"<<newtarget
<<"' already"<<endl
);
2935 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2937 NegCache::NegCacheEntry ne
;
2938 ne
.d_auth
= rec
.d_name
;
2939 uint32_t lowestTTL
= rec
.d_ttl
;
2942 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2944 if (state
== Secure
) {
2945 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, false);
2946 updateDenialValidationState(ne
.d_validationState
, ne
.d_name
, state
, denialState
, NXQTYPE
, qtype
== QType::DS
);
2948 ne
.d_validationState
= state
;
2951 if (ne
.d_validationState
== Bogus
) {
2952 lowestTTL
= min(lowestTTL
, s_maxbogusttl
);
2953 rec
.d_ttl
= min(rec
.d_ttl
, s_maxbogusttl
);
2955 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2957 if(!wasVariable()) {
2958 if(qtype
.getCode()) { // prevents us from blacking out a whole domain
2959 t_sstorage
.negcache
.add(ne
);
2969 if (!dnameTarget
.empty()) {
2970 // Synthesize a CNAME
2971 auto cnamerec
= DNSRecord();
2972 cnamerec
.d_name
= qname
;
2973 cnamerec
.d_type
= QType::CNAME
;
2974 cnamerec
.d_ttl
= dnameTTL
;
2975 cnamerec
.d_content
= std::make_shared
<CNAMERecordContent
>(CNAMERecordContent(newtarget
));
2976 ret
.push_back(cnamerec
);
2981 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
)
2983 bool chained
= false;
2984 int resolveret
= RCode::NoError
;
2988 if(d_outqueries
+ d_throttledqueries
> s_maxqperq
) {
2989 throw ImmediateServFailException("more than "+std::to_string(s_maxqperq
)+" (max-qperq) queries sent while resolving "+qname
.toLogString());
2992 if(s_maxtotusec
&& d_totUsec
> s_maxtotusec
) {
2993 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");
2997 LOG(prefix
<<qname
<<": using TCP with "<< remoteIP
.toStringWithPort() <<endl
);
3002 if(d_pdl
&& d_pdl
->preoutquery(remoteIP
, d_requestor
, qname
, qtype
, doTCP
, lwr
.d_records
, resolveret
)) {
3003 LOG(prefix
<<qname
<<": query handled by Lua"<<endl
);
3006 ednsmask
=getEDNSSubnetMask(qname
, remoteIP
);
3008 LOG(prefix
<<qname
<<": Adding EDNS Client Subnet Mask "<<ednsmask
->toString()<<" to query"<<endl
);
3011 resolveret
= asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, auth
, qtype
.getCode(),
3012 doTCP
, sendRDQuery
, &d_now
, ednsmask
, &lwr
, &chained
); // <- we go out on the wire!
3015 LOG(prefix
<<qname
<<": Received EDNS Client Subnet Mask "<<ednsmask
->toString()<<" on response"<<endl
);
3016 if (ednsmask
->getBits() > 0) {
3017 if (ednsmask
->isIpv4()) {
3018 ++SyncRes::s_ecsResponsesBySubnetSize4
.at(ednsmask
->getBits()-1);
3021 ++SyncRes::s_ecsResponsesBySubnetSize6
.at(ednsmask
->getBits()-1);
3027 /* preoutquery killed the query by setting dq.rcode to -3 */
3028 if(resolveret
==-3) {
3029 throw ImmediateServFailException("Query killed by policy");
3032 d_totUsec
+= lwr
.d_usec
;
3033 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
3035 bool dontThrottle
= false;
3037 auto dontThrottleNames
= g_dontThrottleNames
.getLocal();
3038 auto dontThrottleNetmasks
= g_dontThrottleNetmasks
.getLocal();
3039 dontThrottle
= dontThrottleNames
->check(nsName
) || dontThrottleNetmasks
->match(remoteIP
);
3042 if(resolveret
!= 1) {
3043 /* Error while resolving */
3044 if(resolveret
== 0) {
3047 LOG(prefix
<<qname
<<": timeout resolving after "<<lwr
.d_usec
/1000.0<<"msec "<< (doTCP
? "over TCP" : "")<<endl
);
3049 s_outgoingtimeouts
++;
3051 if(remoteIP
.sin4
.sin_family
== AF_INET
)
3052 s_outgoing4timeouts
++;
3054 s_outgoing6timeouts
++;
3057 t_timeouts
->push_back(remoteIP
);
3059 else if(resolveret
== -2) {
3060 /* OS resource limit reached */
3061 LOG(prefix
<<qname
<<": hit a local resource limit resolving"<< (doTCP
? " over TCP" : "")<<", probable error: "<<stringerror()<<endl
);
3062 g_stats
.resourceLimits
++;
3065 /* -1 means server unreachable */
3068 LOG(prefix
<<qname
<<": error resolving from "<<remoteIP
.toString()<< (doTCP
? " over TCP" : "") <<", possible error: "<<strerror(errno
)<< endl
);
3071 if(resolveret
!= -2 && !chained
&& !dontThrottle
) {
3072 // don't account for resource limits, they are our own fault
3073 // And don't throttle when the IP address is on the dontThrottleNetmasks list or the name is part of dontThrottleNames
3074 t_sstorage
.nsSpeeds
[nsName
.empty()? DNSName(remoteIP
.toStringWithPort()) : nsName
].submit(remoteIP
, 1000000, &d_now
); // 1 sec
3076 // code below makes sure we don't filter COM or the root
3077 if (s_serverdownmaxfails
> 0 && (auth
!= g_rootdnsname
) && t_sstorage
.fails
.incr(remoteIP
) >= s_serverdownmaxfails
) {
3078 LOG(prefix
<<qname
<<": Max fails reached resolving on "<< remoteIP
.toString() <<". Going full throttle for "<< s_serverdownthrottletime
<<" seconds" <<endl
);
3079 // mark server as down
3080 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0), s_serverdownthrottletime
, 10000);
3082 else if (resolveret
== -1) {
3083 // unreachable, 1 minute or 100 queries
3084 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 100);
3087 // timeout, 10 seconds or 5 queries
3088 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 10, 5);
3095 /* we got an answer */
3096 if(lwr
.d_rcode
==RCode::ServFail
|| lwr
.d_rcode
==RCode::Refused
) {
3097 LOG(prefix
<<qname
<<": "<<nsName
<<" ("<<remoteIP
.toString()<<") returned a "<< (lwr
.d_rcode
==RCode::ServFail
? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl
);
3098 if (!chained
&& !dontThrottle
) {
3099 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
3104 /* this server sent a valid answer, mark it backup up if it was down */
3105 if(s_serverdownmaxfails
> 0) {
3106 t_sstorage
.fails
.clear(remoteIP
);
3113 LOG(prefix
<<qname
<<": truncated bit set, over TCP?"<<endl
);
3114 if (!dontThrottle
) {
3115 /* let's treat that as a ServFail answer from this server */
3116 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
3120 LOG(prefix
<<qname
<<": truncated bit set, over UDP"<<endl
);
3128 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
)
3133 prefix
.append(depth
, ' ');
3137 for(auto& rec
: lwr
.d_records
) {
3138 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumTTL
);
3142 /* if the answer is ECS-specific, a minimum TTL is set for this kind of answers
3143 and it's higher than the global minimum TTL */
3144 if (ednsmask
&& s_minimumECSTTL
> 0 && (s_minimumTTL
== 0 || s_minimumECSTTL
> s_minimumTTL
)) {
3145 for(auto& rec
: lwr
.d_records
) {
3146 if (rec
.d_place
== DNSResourceRecord::ANSWER
) {
3147 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumECSTTL
);
3152 bool needWildcardProof
= false;
3153 bool gatherWildcardProof
= false;
3154 unsigned int wildcardLabelsCount
;
3155 *rcode
= updateCacheFromRecords(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, state
, needWildcardProof
, gatherWildcardProof
, wildcardLabelsCount
, sendRDQuery
);
3156 if (*rcode
!= RCode::NoError
) {
3160 LOG(prefix
<<qname
<<": determining status after receiving this packet"<<endl
);
3163 bool realreferral
=false, negindic
=false;
3167 bool done
= processRecords(prefix
, qname
, qtype
, auth
, lwr
, sendRDQuery
, ret
, nsset
, newtarget
, newauth
, realreferral
, negindic
, state
, needWildcardProof
, gatherWildcardProof
, wildcardLabelsCount
);
3170 LOG(prefix
<<qname
<<": status=got results, this level of recursion done"<<endl
);
3171 LOG(prefix
<<qname
<<": validation status is "<<vStates
[state
]<<endl
);
3172 *rcode
= RCode::NoError
;
3176 if(!newtarget
.empty()) {
3177 if(newtarget
== qname
) {
3178 LOG(prefix
<<qname
<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl
);
3179 *rcode
= RCode::ServFail
;
3184 LOG(prefix
<<qname
<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl
);
3185 *rcode
= RCode::ServFail
;
3189 if (qtype
== QType::DS
) {
3190 LOG(prefix
<<qname
<<": status=got a CNAME referral, but we are looking for a DS"<<endl
);
3193 addNXNSECS(ret
, lwr
.d_records
);
3195 *rcode
= RCode::NoError
;
3199 LOG(prefix
<<qname
<<": status=got a CNAME referral, starting over with "<<newtarget
<<endl
);
3201 set
<GetBestNSAnswer
> beenthere2
;
3202 vState cnameState
= Indeterminate
;
3203 *rcode
= doResolve(newtarget
, qtype
, ret
, depth
+ 1, beenthere2
, cnameState
);
3204 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
3205 updateValidationState(state
, cnameState
);
3210 if(lwr
.d_rcode
== RCode::NXDomain
) {
3211 LOG(prefix
<<qname
<<": status=NXDOMAIN, we are done "<<(negindic
? "(have negative SOA)" : "")<<endl
);
3214 addNXNSECS(ret
, lwr
.d_records
);
3216 *rcode
= RCode::NXDomain
;
3220 if(nsset
.empty() && !lwr
.d_rcode
&& (negindic
|| lwr
.d_aabit
|| sendRDQuery
)) {
3221 LOG(prefix
<<qname
<<": status=noerror, other types may exist, but we are done "<<(negindic
? "(have negative SOA) " : "")<<(lwr
.d_aabit
? "(have aa bit) " : "")<<endl
);
3223 if(state
== Secure
&& (lwr
.d_aabit
|| sendRDQuery
) && !negindic
) {
3224 updateValidationState(state
, Bogus
);
3228 addNXNSECS(ret
, lwr
.d_records
);
3230 *rcode
= RCode::NoError
;
3235 LOG(prefix
<<qname
<<": status=did not resolve, got "<<(unsigned int)nsset
.size()<<" NS, ");
3237 nameservers
.clear();
3238 for (auto const &nameserver
: nsset
) {
3240 d_appliedPolicy
= dfe
.getProcessingPolicy(nameserver
, d_discardedPolicies
);
3241 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
3242 LOG("however "<<nameserver
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
3247 nameservers
.insert({nameserver
, {{}, false}});
3249 LOG("looping to them"<<endl
);
3250 *gotNewServers
= true;
3260 * -1 in case of no results
3261 * -2 when a FilterEngine Policy was hit
3264 int SyncRes::doResolveAt(NsSet
&nameservers
, DNSName auth
, bool flawedNSSet
, const DNSName
&qname
, const QType
&qtype
,
3265 vector
<DNSRecord
>&ret
,
3266 unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
, vState
& state
, StopAtDelegation
* stopAtDelegation
)
3268 auto luaconfsLocal
= g_luaconfs
.getLocal();
3272 prefix
.append(depth
, ' ');
3275 LOG(prefix
<<qname
<<": Cache consultations done, have "<<(unsigned int)nameservers
.size()<<" NS to contact");
3277 if (nameserversBlockedByRPZ(luaconfsLocal
->dfe
, nameservers
)) {
3283 for(;;) { // we may get more specific nameservers
3284 auto rnameservers
= shuffleInSpeedOrder(nameservers
, doLog() ? (prefix
+qname
.toString()+": ") : string() );
3286 for(auto tns
=rnameservers
.cbegin();;++tns
) {
3287 if(tns
==rnameservers
.cend()) {
3288 LOG(prefix
<<qname
<<": Failed to resolve via any of the "<<(unsigned int)rnameservers
.size()<<" offered NS at level '"<<auth
<<"'"<<endl
);
3289 if(!auth
.isRoot() && flawedNSSet
) {
3290 LOG(prefix
<<qname
<<": Ageing nameservers for level '"<<auth
<<"', next query might succeed"<<endl
);
3292 if(t_RC
->doAgeCache(d_now
.tv_sec
, auth
, QType::NS
, 10))
3293 g_stats
.nsSetInvalidations
++;
3298 bool cacheOnly
= false;
3299 // this line needs to identify the 'self-resolving' behaviour
3300 if(qname
== tns
->first
&& (qtype
.getCode() == QType::A
|| qtype
.getCode() == QType::AAAA
)) {
3301 /* we might have a glue entry in cache so let's try this NS
3302 but only if we have enough in the cache to know how to reach it */
3303 LOG(prefix
<<qname
<<": Using NS to resolve itself, but only using what we have in cache ("<<(1+tns
-rnameservers
.cbegin())<<"/"<<rnameservers
.size()<<")"<<endl
);
3307 typedef vector
<ComboAddress
> remoteIPs_t
;
3308 remoteIPs_t remoteIPs
;
3309 remoteIPs_t::const_iterator remoteIP
;
3310 bool pierceDontQuery
=false;
3311 bool sendRDQuery
=false;
3312 boost::optional
<Netmask
> ednsmask
;
3314 const bool wasForwarded
= tns
->first
.empty() && (!nameservers
[tns
->first
].first
.empty());
3315 int rcode
= RCode::NoError
;
3316 bool gotNewServers
= false;
3318 if(tns
->first
.empty() && !wasForwarded
) {
3319 LOG(prefix
<<qname
<<": Domain is out-of-band"<<endl
);
3320 /* setting state to indeterminate since validation is disabled for local auth zone,
3321 and Insecure would be misleading. */
3322 state
= Indeterminate
;
3323 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, lwr
.d_records
, depth
, lwr
.d_rcode
);
3327 /* we have received an answer, are we done ? */
3328 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, false, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
3332 if (gotNewServers
) {
3333 if (stopAtDelegation
&& *stopAtDelegation
== Stop
) {
3334 *stopAtDelegation
= Stopped
;
3341 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
3342 remoteIPs
= retrieveAddressesForNS(prefix
, qname
, tns
, depth
, beenthere
, rnameservers
, nameservers
, sendRDQuery
, pierceDontQuery
, flawedNSSet
, cacheOnly
);
3344 if(remoteIPs
.empty()) {
3345 LOG(prefix
<<qname
<<": Failed to get IP for NS "<<tns
->first
<<", trying next if available"<<endl
);
3350 bool hitPolicy
{false};
3351 LOG(prefix
<<qname
<<": Resolved '"<<auth
<<"' NS "<<tns
->first
<<" to: ");
3352 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
3353 if(remoteIP
!= remoteIPs
.cbegin()) {
3356 LOG(remoteIP
->toString());
3357 if(nameserverIPBlockedByRPZ(luaconfsLocal
->dfe
, *remoteIP
)) {
3362 if (hitPolicy
) //implies d_wantsRPZ
3366 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
3367 LOG(prefix
<<qname
<<": Trying IP "<< remoteIP
->toStringWithPort() <<", asking '"<<qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
3369 if (throttledOrBlocked(prefix
, *remoteIP
, qname
, qtype
, pierceDontQuery
)) {
3373 bool truncated
= false;
3374 bool gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
3375 tns
->first
, *remoteIP
, false, &truncated
);
3376 if (gotAnswer
&& truncated
) {
3377 /* retry, over TCP this time */
3378 gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
3379 tns
->first
, *remoteIP
, true, &truncated
);
3386 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
);
3388 /* // for you IPv6 fanatics :-)
3389 if(remoteIP->sin4.sin_family==AF_INET6)
3392 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
3394 t_sstorage
.nsSpeeds
[tns
->first
.empty()? DNSName(remoteIP
->toStringWithPort()) : tns
->first
].submit(*remoteIP
, lwr
.d_usec
, &d_now
);
3396 /* we have received an answer, are we done ? */
3397 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
3401 if (gotNewServers
) {
3402 if (stopAtDelegation
&& *stopAtDelegation
== Stop
) {
3403 *stopAtDelegation
= Stopped
;
3409 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100);
3412 if (gotNewServers
) {
3416 if(remoteIP
== remoteIPs
.cend()) // we tried all IP addresses, none worked
3425 void SyncRes::setQuerySource(const ComboAddress
& requestor
, boost::optional
<const EDNSSubnetOpts
&> incomingECS
)
3427 d_requestor
= requestor
;
3429 if (incomingECS
&& incomingECS
->source
.getBits() > 0) {
3430 d_cacheRemote
= incomingECS
->source
.getMaskedNetwork();
3431 uint8_t bits
= std::min(incomingECS
->source
.getBits(), (incomingECS
->source
.isIpv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
3432 ComboAddress trunc
= incomingECS
->source
.getNetwork();
3433 trunc
.truncate(bits
);
3434 d_outgoingECSNetwork
= boost::optional
<Netmask
>(Netmask(trunc
, bits
));
3436 d_cacheRemote
= d_requestor
;
3437 if(!incomingECS
&& s_ednslocalsubnets
.match(d_requestor
)) {
3438 ComboAddress trunc
= d_requestor
;
3439 uint8_t bits
= d_requestor
.isIPv4() ? 32 : 128;
3440 bits
= std::min(bits
, (trunc
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
3441 trunc
.truncate(bits
);
3442 d_outgoingECSNetwork
= boost::optional
<Netmask
>(Netmask(trunc
, bits
));
3443 } else if (s_ecsScopeZero
.source
.getBits() > 0) {
3444 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0.
3445 But using an empty ECS in that case would mean inserting
3446 a non ECS-specific entry into the cache, preventing any further
3447 ECS-specific query to be sent.
3448 So instead we use the trick described in section 7.1.2:
3449 "The subsequent Recursive Resolver query to the Authoritative Nameserver
3450 will then either not include an ECS option or MAY optionally include
3451 its own address information, which is what the Authoritative
3452 Nameserver will almost certainly use to generate any Tailored
3453 Response in lieu of an option. This allows the answer to be handled
3454 by the same caching mechanism as other queries, with an explicit
3455 indicator of the applicable scope. Subsequent Stub Resolver queries
3456 for /0 can then be answered from this cached response.
3458 d_outgoingECSNetwork
= boost::optional
<Netmask
>(s_ecsScopeZero
.source
.getMaskedNetwork());
3459 d_cacheRemote
= s_ecsScopeZero
.source
.getNetwork();
3461 // ECS disabled because no scope-zero address could be derived.
3462 d_outgoingECSNetwork
= boost::none
;
3467 boost::optional
<Netmask
> SyncRes::getEDNSSubnetMask(const DNSName
& dn
, const ComboAddress
& rem
)
3469 if(d_outgoingECSNetwork
&& (s_ednsdomains
.check(dn
) || s_ednsremotesubnets
.match(rem
))) {
3470 return d_outgoingECSNetwork
;
3475 void SyncRes::parseEDNSSubnetWhitelist(const std::string
& wlist
)
3477 vector
<string
> parts
;
3478 stringtok(parts
, wlist
, ",; ");
3479 for(const auto& a
: parts
) {
3481 s_ednsremotesubnets
.addMask(Netmask(a
));
3484 s_ednsdomains
.add(DNSName(a
));
3489 void SyncRes::parseEDNSSubnetAddFor(const std::string
& subnetlist
)
3491 vector
<string
> parts
;
3492 stringtok(parts
, subnetlist
, ",; ");
3493 for(const auto& a
: parts
) {
3494 s_ednslocalsubnets
.addMask(a
);
3498 // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
3499 int directResolve(const DNSName
& qname
, const QType
& qtype
, int qclass
, vector
<DNSRecord
>& ret
)
3502 gettimeofday(&now
, 0);
3507 res
= sr
.beginResolve(qname
, QType(qtype
), qclass
, ret
);
3509 catch(const PDNSException
& e
) {
3510 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got pdns exception: "<<e
.reason
<<endl
;
3513 catch(const ImmediateServFailException
& e
) {
3514 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got ImmediateServFailException: "<<e
.reason
<<endl
;
3517 catch(const std::exception
& e
) {
3518 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got STL error: "<<e
.what()<<endl
;
3522 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got an exception"<<endl
;
3529 int SyncRes::getRootNS(struct timeval now
, asyncresolve_t asyncCallback
) {
3531 sr
.setDoEDNS0(true);
3532 sr
.setUpdatingRootNS();
3533 sr
.setDoDNSSEC(g_dnssecmode
!= DNSSECMode::Off
);
3534 sr
.setDNSSECValidationRequested(g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
);
3535 sr
.setAsyncCallback(asyncCallback
);
3537 vector
<DNSRecord
> ret
;
3540 res
=sr
.beginResolve(g_rootdnsname
, QType(QType::NS
), 1, ret
);
3541 if (g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
) {
3542 auto state
= sr
.getValidationState();
3544 throw PDNSException("Got Bogus validation result for .|NS");
3548 catch(const PDNSException
& e
) {
3549 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
3551 catch(const ImmediateServFailException
& e
) {
3552 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
3554 catch(const std::exception
& e
) {
3555 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.what()<<endl
;
3558 g_log
<<Logger::Error
<<"Failed to update . records, got an exception"<<endl
;
3562 g_log
<<Logger::Notice
<<"Refreshed . records"<<endl
;
3565 g_log
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;