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_qnameminfallbacksuccess
;
75 std::atomic
<uint64_t> SyncRes::s_nodelegated
;
76 std::atomic
<uint64_t> SyncRes::s_unreachables
;
77 std::atomic
<uint64_t> SyncRes::s_ecsqueries
;
78 std::atomic
<uint64_t> SyncRes::s_ecsresponses
;
79 std::map
<uint8_t, std::atomic
<uint64_t>> SyncRes::s_ecsResponsesBySubnetSize4
;
80 std::map
<uint8_t, std::atomic
<uint64_t>> SyncRes::s_ecsResponsesBySubnetSize6
;
82 uint8_t SyncRes::s_ecsipv4limit
;
83 uint8_t SyncRes::s_ecsipv6limit
;
84 uint8_t SyncRes::s_ecsipv4cachelimit
;
85 uint8_t SyncRes::s_ecsipv6cachelimit
;
87 bool SyncRes::s_doIPv6
;
88 bool SyncRes::s_nopacketcache
;
89 bool SyncRes::s_rootNXTrust
;
90 bool SyncRes::s_noEDNS
;
91 bool SyncRes::s_qnameminimization
;
92 SyncRes::HardenNXD
SyncRes::s_hardenNXD
;
94 #define LOG(x) if(d_lm == Log) { g_log <<Logger::Warning << x; } else if(d_lm == Store) { d_trace << x; }
96 static void accountAuthLatency(int usec
, int family
)
98 if(family
== AF_INET
) {
100 g_stats
.auth4Answers0_1
++;
101 else if(usec
< 10000)
102 g_stats
.auth4Answers1_10
++;
103 else if(usec
< 100000)
104 g_stats
.auth4Answers10_100
++;
105 else if(usec
< 1000000)
106 g_stats
.auth4Answers100_1000
++;
108 g_stats
.auth4AnswersSlow
++;
111 g_stats
.auth6Answers0_1
++;
112 else if(usec
< 10000)
113 g_stats
.auth6Answers1_10
++;
114 else if(usec
< 100000)
115 g_stats
.auth6Answers10_100
++;
116 else if(usec
< 1000000)
117 g_stats
.auth6Answers100_1000
++;
119 g_stats
.auth6AnswersSlow
++;
125 SyncRes::SyncRes(const struct timeval
& now
) : d_authzonequeries(0), d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
126 d_totUsec(0), d_now(now
),
127 d_cacheonly(false), d_doDNSSEC(false), d_doEDNS0(false), d_qNameMinimization(s_qnameminimization
), d_lm(s_lm
)
132 /** everything begins here - this is the entry point just after receiving a packet */
133 int SyncRes::beginResolve(const DNSName
&qname
, const QType
&qtype
, uint16_t qclass
, vector
<DNSRecord
>&ret
)
135 vState state
= Indeterminate
;
138 d_wasOutOfBand
=false;
140 if (doSpecialNamesResolve(qname
, qtype
, qclass
, ret
)) {
141 d_queryValidationState
= Insecure
; // this could fool our stats into thinking a validation took place
142 return 0; // so do check before updating counters (we do now)
145 auto qtypeCode
= qtype
.getCode();
146 /* rfc6895 section 3.1 */
147 if ((qtypeCode
>= 128 && qtypeCode
<= 254) || qtypeCode
== QType::RRSIG
|| qtypeCode
== QType::NSEC3
|| qtypeCode
== QType::OPT
|| qtypeCode
== 65535) {
151 if(qclass
==QClass::ANY
)
153 else if(qclass
!=QClass::IN
)
156 set
<GetBestNSAnswer
> beenthere
;
157 int res
=doResolve(qname
, qtype
, ret
, 0, beenthere
, state
);
158 d_queryValidationState
= state
;
160 if (shouldValidate()) {
161 if (d_queryValidationState
!= Indeterminate
) {
162 g_stats
.dnssecValidations
++;
164 increaseDNSSECStateCounter(d_queryValidationState
);
170 /*! Handles all special, built-in names
171 * Fills ret with an answer and returns true if it handled the query.
173 * Handles the following queries (and their ANY variants):
176 * - localhost. IN AAAA
177 * - 1.0.0.127.in-addr.arpa. IN PTR
178 * - 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
179 * - version.bind. CH TXT
180 * - version.pdns. CH TXT
181 * - id.server. CH TXT
182 * - trustanchor.server CH TXT
183 * - negativetrustanchor.server CH TXT
185 bool SyncRes::doSpecialNamesResolve(const DNSName
&qname
, const QType
&qtype
, const uint16_t qclass
, vector
<DNSRecord
> &ret
)
187 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."),
188 localhost("localhost."), versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns."), trustanchorserver("trustanchor.server."),
189 negativetrustanchorserver("negativetrustanchor.server.");
191 bool handled
= false;
192 vector
<pair
<QType::typeenum
, string
> > answers
;
194 if ((qname
== arpa
|| qname
== ip6_arpa
) &&
195 qclass
== QClass::IN
) {
197 if (qtype
== QType::PTR
|| qtype
== QType::ANY
)
198 answers
.push_back({QType::PTR
, "localhost."});
201 if (qname
== localhost
&&
202 qclass
== QClass::IN
) {
204 if (qtype
== QType::A
|| qtype
== QType::ANY
)
205 answers
.push_back({QType::A
, "127.0.0.1"});
206 if (qtype
== QType::AAAA
|| qtype
== QType::ANY
)
207 answers
.push_back({QType::AAAA
, "::1"});
210 if ((qname
== versionbind
|| qname
== idserver
|| qname
== versionpdns
) &&
211 qclass
== QClass::CHAOS
) {
213 if (qtype
== QType::TXT
|| qtype
== QType::ANY
) {
214 if(qname
== versionbind
|| qname
== versionpdns
)
215 answers
.push_back({QType::TXT
, "\""+::arg()["version-string"]+"\""});
216 else if (s_serverID
!= "disabled")
217 answers
.push_back({QType::TXT
, "\""+s_serverID
+"\""});
221 if (qname
== trustanchorserver
&& qclass
== QClass::CHAOS
&&
222 ::arg().mustDo("allow-trust-anchor-query")) {
224 if (qtype
== QType::TXT
|| qtype
== QType::ANY
) {
225 auto luaLocal
= g_luaconfs
.getLocal();
226 for (auto const &dsAnchor
: luaLocal
->dsAnchors
) {
229 ans
<<dsAnchor
.first
.toString(); // Explicit toString to have a trailing dot
230 for (auto const &dsRecord
: dsAnchor
.second
) {
235 answers
.push_back({QType::TXT
, ans
.str()});
240 if (qname
== negativetrustanchorserver
&& qclass
== QClass::CHAOS
&&
241 ::arg().mustDo("allow-trust-anchor-query")) {
243 if (qtype
== QType::TXT
|| qtype
== QType::ANY
) {
244 auto luaLocal
= g_luaconfs
.getLocal();
245 for (auto const &negAnchor
: luaLocal
->negAnchors
) {
248 ans
<<negAnchor
.first
.toString(); // Explicit toString to have a trailing dot
249 if (negAnchor
.second
.length())
250 ans
<<" "<<negAnchor
.second
;
252 answers
.push_back({QType::TXT
, ans
.str()});
257 if (handled
&& !answers
.empty()) {
263 dr
.d_place
= DNSResourceRecord::ANSWER
;
266 for (const auto& ans
: answers
) {
267 dr
.d_type
= ans
.first
;
268 dr
.d_content
= DNSRecordContent::mastermake(ans
.first
, qclass
, ans
.second
);
277 //! This is the 'out of band resolver', in other words, the authoritative server
278 void SyncRes::AuthDomain::addSOA(std::vector
<DNSRecord
>& records
) const
280 SyncRes::AuthDomain::records_t::const_iterator ziter
= d_records
.find(boost::make_tuple(getName(), QType::SOA
));
281 if (ziter
!= d_records
.end()) {
282 DNSRecord dr
= *ziter
;
283 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
284 records
.push_back(dr
);
287 // cerr<<qname<<": can't find SOA record '"<<getName()<<"' in our zone!"<<endl;
291 int SyncRes::AuthDomain::getRecords(const DNSName
& qname
, uint16_t qtype
, std::vector
<DNSRecord
>& records
) const
293 int result
= RCode::NoError
;
297 std::pair
<records_t::const_iterator
,records_t::const_iterator
> range
= d_records
.equal_range(tie(qname
));
299 SyncRes::AuthDomain::records_t::const_iterator ziter
;
300 bool somedata
= false;
302 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
305 if(qtype
== QType::ANY
|| ziter
->d_type
== qtype
|| ziter
->d_type
== QType::CNAME
) {
306 // let rest of nameserver do the legwork on this one
307 records
.push_back(*ziter
);
309 else if (ziter
->d_type
== QType::NS
&& ziter
->d_name
.countLabels() > getName().countLabels()) {
310 // we hit a delegation point!
311 DNSRecord dr
= *ziter
;
312 dr
.d_place
=DNSResourceRecord::AUTHORITY
;
313 records
.push_back(dr
);
317 if (!records
.empty()) {
318 /* We have found an exact match, we're done */
319 // cerr<<qname<<": exact match in zone '"<<getName()<<"'"<<endl;
324 /* We have records for that name, but not of the wanted qtype */
325 // cerr<<qname<<": found record in '"<<getName()<<"', but nothing of the right type, sending SOA"<<endl;
331 // cerr<<qname<<": nothing found so far in '"<<getName()<<"', trying wildcards"<<endl;
332 DNSName
wcarddomain(qname
);
333 while(wcarddomain
!= getName() && wcarddomain
.chopOff()) {
334 // cerr<<qname<<": trying '*."<<wcarddomain<<"' in "<<getName()<<endl;
335 range
= d_records
.equal_range(boost::make_tuple(g_wildcarddnsname
+ wcarddomain
));
336 if (range
.first
==range
.second
)
339 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
340 DNSRecord dr
= *ziter
;
341 // if we hit a CNAME, just answer that - rest of recursor will do the needful & follow
342 if(dr
.d_type
== qtype
|| qtype
== QType::ANY
|| dr
.d_type
== QType::CNAME
) {
344 dr
.d_place
= DNSResourceRecord::ANSWER
;
345 records
.push_back(dr
);
349 if (records
.empty()) {
353 // cerr<<qname<<": in '"<<getName()<<"', had wildcard match on '*."<<wcarddomain<<"'"<<endl;
357 /* Nothing for this name, no wildcard, let's see if there is some NS */
358 DNSName
nsdomain(qname
);
359 while (nsdomain
.chopOff() && nsdomain
!= getName()) {
360 range
= d_records
.equal_range(boost::make_tuple(nsdomain
,QType::NS
));
361 if(range
.first
== range
.second
)
364 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
365 DNSRecord dr
= *ziter
;
366 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
367 records
.push_back(dr
);
371 if(records
.empty()) {
372 // cerr<<qname<<": no NS match in zone '"<<getName()<<"' either, handing out SOA"<<endl;
374 result
= RCode::NXDomain
;
380 bool SyncRes::doOOBResolve(const AuthDomain
& domain
, const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, int& res
)
385 res
= domain
.getRecords(qname
, qtype
.getCode(), ret
);
389 bool SyncRes::doOOBResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int& res
)
394 prefix
.append(depth
, ' ');
397 DNSName
authdomain(qname
);
398 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
399 if(iter
==t_sstorage
.domainmap
->end() || !iter
->second
.isAuth()) {
400 LOG(prefix
<<qname
<<": auth storage has no zone for this query!"<<endl
);
404 LOG(prefix
<<qname
<<": auth storage has data, zone='"<<authdomain
<<"'"<<endl
);
405 return doOOBResolve(iter
->second
, qname
, qtype
, ret
, res
);
408 bool SyncRes::isForwardOrAuth(const DNSName
&qname
) const {
409 DNSName
authname(qname
);
410 domainmap_t::const_iterator iter
= getBestAuthZone(&authname
);
411 return iter
!= t_sstorage
.domainmap
->end();
414 uint64_t SyncRes::doEDNSDump(int fd
)
420 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(newfd
, "w"), fclose
);
427 fprintf(fp
.get(),"; edns from thread follows\n;\n");
428 for(const auto& eds
: t_sstorage
.ednsstatus
) {
431 fprintf(fp
.get(), "%s\t%d\t%s", eds
.address
.toString().c_str(), (int)eds
.mode
, ctime_r(&eds
.modeSetAt
, tmp
));
436 uint64_t SyncRes::doDumpNSSpeeds(int fd
)
442 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(newfd
, "w"), fclose
);
447 fprintf(fp
.get(), "; nsspeed dump from thread follows\n;\n");
450 for(const auto& i
: t_sstorage
.nsSpeeds
)
454 // an <empty> can appear hear in case of authoritative (hosted) zones
455 fprintf(fp
.get(), "%s -> ", i
.first
.toLogString().c_str());
456 for(const auto& j
: i
.second
.d_collection
)
458 // typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
459 fprintf(fp
.get(), "%s/%f ", j
.first
.toString().c_str(), j
.second
.peek());
461 fprintf(fp
.get(), "\n");
466 uint64_t SyncRes::doDumpThrottleMap(int fd
)
472 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(newfd
, "w"), fclose
);
477 fprintf(fp
.get(), "; throttle map dump follows\n");
478 fprintf(fp
.get(), "; remote IP\tqname\tqtype\tcount\tttd\n");
481 const auto& throttleMap
= t_sstorage
.throttle
.getThrottleMap();
482 for(const auto i
: throttleMap
)
486 // remote IP, dns name, qtype, count, ttd
487 fprintf(fp
.get(), "%s\t%s\t%d\t%u\t%s", i
.thing
.get
<0>().toString().c_str(), i
.thing
.get
<1>().toLogString().c_str(), i
.thing
.get
<2>(), i
.count
, ctime_r(&i
.ttd
, tmp
));
493 uint64_t SyncRes::doDumpFailedServers(int fd
)
499 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(newfd
, "w"), fclose
);
504 fprintf(fp
.get(), "; failed servers dump follows\n");
505 fprintf(fp
.get(), "; remote IP\tcount\ttimestamp\n");
508 for(const auto& i
: t_sstorage
.fails
.getMap())
512 ctime_r(&i
.last
, tmp
);
513 fprintf(fp
.get(), "%s\t%lld\t%s", i
.address
.toString().c_str(),
514 static_cast<long long>(i
.value
), tmp
);
520 /* so here is the story. First we complete the full resolution process for a domain name. And only THEN do we decide
521 to also do DNSSEC validation, which leads to new queries. To make this simple, we *always* ask for DNSSEC records
522 so that if there are RRSIGs for a name, we'll have them.
524 However, some hosts simply can't answer questions which ask for DNSSEC. This can manifest itself as:
529 The cause of "No answer" may be fragmentation, and it is tempting to probe if smaller answers would get through.
530 Another cause of "No answer" may simply be a network condition.
531 Nonsense answers are a clearer indication this host won't be able to do DNSSEC evah.
533 Previous implementations have suffered from turning off DNSSEC questions for an authoritative server based on timeouts.
534 A clever idea is to only turn off DNSSEC if we know a domain isn't signed anyhow. The problem with that really
535 clever idea however is that at this point in PowerDNS, we may simply not know that yet. All the DNSSEC thinking happens
536 elsewhere. It may not have happened yet.
538 For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish.
541 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
543 /* what is your QUEST?
544 the goal is to get as many remotes as possible on the highest level of EDNS support
547 0) UNKNOWN Unknown state
548 1) EDNS: Honors EDNS0
549 2) EDNSIGNORANT: Ignores EDNS0, gives replies without EDNS0
550 3) NOEDNS: Generates FORMERR on EDNS queries
552 Everybody starts out assumed to be '0'.
553 If '0', send out EDNS0
554 If you FORMERR us, go to '3',
555 If no EDNS in response, go to '2'
556 If '1', send out EDNS0
557 If FORMERR, downgrade to 3
558 If '2', keep on including EDNS0, see what happens
560 If '3', send bare queries
563 auto ednsstatus
= t_sstorage
.ednsstatus
.insert(ip
).first
; // does this include port? YES
564 auto &ind
= t_sstorage
.ednsstatus
.get
<ComboAddress
>();
565 if (ednsstatus
->modeSetAt
&& ednsstatus
->modeSetAt
+ 3600 < d_now
.tv_sec
) {
566 t_sstorage
.ednsstatus
.reset(ind
, ednsstatus
);
567 // cerr<<"Resetting EDNS Status for "<<ip.toString()<<endl);
570 const SyncRes::EDNSStatus::EDNSMode
*mode
= &ednsstatus
->mode
;
571 const SyncRes::EDNSStatus::EDNSMode oldmode
= *mode
;
573 auto luaconfsLocal
= g_luaconfs
.getLocal();
576 ctx
.d_initialRequestId
= d_initialRequestId
;
583 for(int tries
= 0; tries
< 3; ++tries
) {
584 // cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl;
586 if (*mode
== EDNSStatus::NOEDNS
) {
587 g_stats
.noEdnsOutQueries
++;
588 EDNSLevel
= 0; // level != mode
590 else if (ednsMANDATORY
|| *mode
== EDNSStatus::UNKNOWN
|| *mode
== EDNSStatus::EDNSOK
|| *mode
== EDNSStatus::EDNSIGNORANT
)
593 DNSName
sendQname(domain
);
594 if (g_lowercaseOutgoing
)
595 sendQname
.makeUsLowerCase();
597 if (d_asyncResolve
) {
598 ret
= d_asyncResolve(ip
, sendQname
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, res
, chained
);
601 ret
=asyncresolve(ip
, sendQname
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, d_outgoingProtobufServers
, d_frameStreamServers
, luaconfsLocal
->outgoingProtobufExportConfig
.exportTypes
, res
, chained
);
603 // ednsstatus might be cleared, so do a new lookup
604 ednsstatus
= t_sstorage
.ednsstatus
.insert(ip
).first
;
605 mode
= &ednsstatus
->mode
;
607 return ret
; // transport error, nothing to learn here
610 if(ret
== 0) { // timeout, not doing anything with it now
613 else if (*mode
== EDNSStatus::UNKNOWN
|| *mode
== EDNSStatus::EDNSOK
|| *mode
== EDNSStatus::EDNSIGNORANT
) {
614 if(res
->d_validpacket
&& !res
->d_haveEDNS
&& res
->d_rcode
== RCode::FormErr
) {
615 // cerr<<"Downgrading to NOEDNS because of "<<RCode::to_s(res->d_rcode)<<" for query to "<<ip.toString()<<" for '"<<domain<<"'"<<endl;
616 t_sstorage
.ednsstatus
.setMode(ind
, ednsstatus
, EDNSStatus::NOEDNS
);
619 else if(!res
->d_haveEDNS
) {
620 if (*mode
!= EDNSStatus::EDNSIGNORANT
) {
621 t_sstorage
.ednsstatus
.setMode(ind
, ednsstatus
, EDNSStatus::EDNSIGNORANT
);
622 // cerr<<"We find that "<<ip.toString()<<" is an EDNS-ignorer for '"<<domain<<"', moving to mode 2"<<endl;
626 t_sstorage
.ednsstatus
.setMode(ind
, ednsstatus
, EDNSStatus::EDNSOK
);
627 // cerr<<"We find that "<<ip.toString()<<" is EDNS OK!"<<endl;
631 if (oldmode
!= *mode
|| !ednsstatus
->modeSetAt
)
632 t_sstorage
.ednsstatus
.setTS(ind
, ednsstatus
, d_now
.tv_sec
);
633 // cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", new mode: "<<mode<<endl;
639 #define QLOG(x) LOG(prefix << " child=" << child << ": " << x << endl)
641 int SyncRes::doResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, vState
& state
) {
643 if (!getQNameMinimization() || isForwardOrAuth(qname
)) {
644 return doResolveNoQNameMinimization(qname
, qtype
, ret
, depth
, beenthere
, state
);
647 // The qname minimization algorithm is a simplified version of the one in RFC 7816 (bis).
648 // It could be simplified because the cache maintenance (both positive and negative)
649 // is already done by doResolveNoQNameMinimization().
651 // Sketch of algorithm:
653 // If result found: done
654 // Otherwise determine closes ancestor from cache data
655 // Repeat querying A, adding more labels of the original qname
656 // If we get a delegation continue at ancestor determination
657 // Until we have the full name.
659 // The algorithm starts with adding a single label per iteration, and
660 // moves to three labels per iteration after three iterations.
663 string prefix
= d_prefix
;
664 prefix
.append(depth
, ' ');
665 prefix
.append(string("QM ") + qname
.toString() + "|" + qtype
.getName());
669 // Look in cache only
670 vector
<DNSRecord
> retq
;
671 bool old
= setCacheOnly(true);
672 bool fromCache
= false;
673 int res
= doResolveNoQNameMinimization(qname
, qtype
, retq
, depth
+ 1, beenthere
, state
, &fromCache
);
676 QLOG("Step0 Found in cache");
677 ret
.insert(ret
.end(), retq
.begin(), retq
.end());
680 QLOG("Step0 Not cached");
682 const unsigned int qnamelen
= qname
.countLabels();
684 for (unsigned int i
= 0; i
<= qnamelen
; ) {
687 vector
<DNSRecord
> bestns
;
688 DNSName
nsdomain(qname
);
689 if (qtype
== QType::DS
) {
692 // the two retries allow getBestNSFromCache&co to reprime the root
693 // hints, in case they ever go missing
694 for (int tries
= 0; tries
< 2 && bestns
.empty(); ++tries
) {
695 bool flawedNSSet
= false;
696 set
<GetBestNSAnswer
> beenthereIgnored
;
697 getBestNSFromCache(nsdomain
, qtype
, bestns
, &flawedNSSet
, depth
+ 1, beenthereIgnored
);
700 if (bestns
.size() == 0) {
701 // Something terrible is wrong
702 QLOG("Step1 No ancestor found return ServFail");
703 return RCode::ServFail
;
706 const DNSName
& ancestor(bestns
[0].d_name
);
707 QLOG("Step1 Ancestor from cache is " << ancestor
.toString());
710 unsigned int targetlen
= std::min(child
.countLabels() + (i
> 3 ? 3 : 1), qnamelen
);
712 for (; i
<= qnamelen
; i
++) {
714 while (child
.countLabels() < targetlen
) {
715 child
.prependRawLabel(qname
.getRawLabel(qnamelen
- child
.countLabels() - 1));
717 targetlen
+= i
> 3 ? 3 : 1;
718 targetlen
= std::min(targetlen
, qnamelen
);
720 QLOG("Step2 New child");
723 if (child
== qname
) {
724 QLOG("Step3 Going to do final resolve");
725 res
= doResolveNoQNameMinimization(qname
, qtype
, ret
, depth
+ 1, beenthere
, state
);
726 QLOG("Step3 Final resolve: " << RCode::to_s(res
) << "/" << ret
.size());
731 QLOG("Step4 Resolve A for child");
733 StopAtDelegation stopAtDelegation
= Stop
;
734 res
= doResolveNoQNameMinimization(child
, QType::A
, retq
, depth
+ 1, beenthere
, state
, NULL
, &stopAtDelegation
);
735 QLOG("Step4 Resolve A result is " << RCode::to_s(res
) << "/" << retq
.size() << "/" << stopAtDelegation
);
736 if (stopAtDelegation
== Stopped
) {
737 QLOG("Delegation seen, continue at step 1");
741 if (res
!= RCode::NoError
) {
742 // Case 5: unexpected answer
743 QLOG("Step5: other rcode, last effort final resolve");
744 setQNameMinimization(false);
745 res
= doResolveNoQNameMinimization(qname
, qtype
, ret
, depth
+ 1, beenthere
, state
);
747 if(res
== RCode::NoError
) {
748 s_qnameminfallbacksuccess
++;
751 QLOG("Step5 End resolve: " << RCode::to_s(res
) << "/" << ret
.size());
757 // Should not be reached
758 QLOG("Max iterations reached, return ServFail");
759 return RCode::ServFail
;
762 /*! This function will check the cache and go out to the internet if the answer is not in cache
764 * \param qname The name we need an answer for
766 * \param ret The vector of DNSRecords we need to fill with the answers
767 * \param depth The recursion depth we are in
769 * \param fromCache tells the caller the result came from the cache, may be nullptr
770 * \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
771 * \return DNS RCODE or -1 (Error)
773 int SyncRes::doResolveNoQNameMinimization(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, vState
& state
, bool *fromCache
, StopAtDelegation
*stopAtDelegation
)
778 prefix
.append(depth
, ' ');
781 LOG(prefix
<<qname
<<": Wants "<< (d_doDNSSEC
? "" : "NO ") << "DNSSEC processing, "<<(d_requireAuthData
? "" : "NO ")<<"auth data in query for "<<qtype
.getName()<<endl
);
783 state
= Indeterminate
;
785 if(s_maxdepth
&& depth
> s_maxdepth
)
786 throw ImmediateServFailException("More than "+std::to_string(s_maxdepth
)+" (max-recursion-depth) levels of recursion needed while resolving "+qname
.toLogString());
790 // This is a difficult way of expressing "this is a normal query", i.e. not getRootNS.
791 if(!(d_updatingRootNS
&& qtype
.getCode()==QType::NS
&& qname
.isRoot())) {
792 if(d_cacheonly
) { // very limited OOB support
794 LOG(prefix
<<qname
<<": Recursion not requested for '"<<qname
<<"|"<<qtype
.getName()<<"', peeking at auth/forward zones"<<endl
);
795 DNSName
authname(qname
);
796 domainmap_t::const_iterator iter
=getBestAuthZone(&authname
);
797 if(iter
!= t_sstorage
.domainmap
->end()) {
798 if(iter
->second
.isAuth()) {
800 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, ret
, depth
, res
);
802 *fromCache
= d_wasOutOfBand
;
806 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
807 const ComboAddress remoteIP
= servers
.front();
808 LOG(prefix
<<qname
<<": forwarding query to hardcoded nameserver '"<< remoteIP
.toStringWithPort()<<"' for zone '"<<authname
<<"'"<<endl
);
810 boost::optional
<Netmask
> nm
;
811 bool chained
= false;
812 res
=asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, authname
, qtype
.getCode(), false, false, &d_now
, nm
, &lwr
, &chained
);
814 d_totUsec
+= lwr
.d_usec
;
815 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
819 // filter out the good stuff from lwr.result()
821 for(const auto& rec
: lwr
.d_records
) {
822 if(rec
.d_place
== DNSResourceRecord::ANSWER
)
828 return RCode::ServFail
;
834 DNSName
authname(qname
);
835 bool wasForwardedOrAuthZone
= false;
836 bool wasAuthZone
= false;
837 bool wasForwardRecurse
= false;
838 domainmap_t::const_iterator iter
= getBestAuthZone(&authname
);
839 if(iter
!= t_sstorage
.domainmap
->end()) {
840 const auto& domain
= iter
->second
;
841 wasForwardedOrAuthZone
= true;
843 if (domain
.isAuth()) {
845 } else if (domain
.shouldRecurse()) {
846 wasForwardRecurse
= true;
850 if(!d_skipCNAMECheck
&& doCNAMECacheCheck(qname
, qtype
, ret
, depth
, res
, state
, wasAuthZone
, wasForwardRecurse
)) { // will reroute us if needed
851 d_wasOutOfBand
= wasAuthZone
;
855 if(doCacheCheck(qname
, authname
, wasForwardedOrAuthZone
, wasAuthZone
, wasForwardRecurse
, qtype
, ret
, depth
, res
, state
)) {
857 d_wasOutOfBand
= wasAuthZone
;
867 LOG(prefix
<<qname
<<": No cache hit for '"<<qname
<<"|"<<qtype
.getName()<<"', trying to find an appropriate NS record"<<endl
);
869 DNSName
subdomain(qname
);
870 if(qtype
== QType::DS
) subdomain
.chopOff();
873 bool flawedNSSet
=false;
875 /* we use subdomain here instead of qname because for DS queries we only care about the state of the parent zone */
876 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
878 // the two retries allow getBestNSNamesFromCache&co to reprime the root
879 // hints, in case they ever go missing
880 for(int tries
=0;tries
<2 && nsset
.empty();++tries
) {
881 subdomain
=getBestNSNamesFromCache(subdomain
, qtype
, nsset
, &flawedNSSet
, depth
, beenthere
); // pass beenthere to both occasions
884 state
= getValidationStatus(qname
, false);
886 LOG(prefix
<<qname
<<": initial validation status for "<<qname
<<" is "<<vStates
[state
]<<endl
);
888 if(!(res
=doResolveAt(nsset
, subdomain
, flawedNSSet
, qname
, qtype
, ret
, depth
, beenthere
, state
, stopAtDelegation
)))
891 LOG(prefix
<<qname
<<": failed (res="<<res
<<")"<<endl
);
893 return res
<0 ? RCode::ServFail
: res
;
897 // for testing purposes
898 static bool ipv6First(const ComboAddress
& a
, const ComboAddress
& b
)
900 return !(a
.sin4
.sin_family
< a
.sin4
.sin_family
);
906 speedOrderCA(std::map
<ComboAddress
,float>& speeds
): d_speeds(speeds
) {}
907 bool operator()(const ComboAddress
& a
, const ComboAddress
& b
) const
909 return d_speeds
[a
] < d_speeds
[b
];
911 std::map
<ComboAddress
, float>& d_speeds
;
914 /** This function explicitly goes out for A or AAAA addresses
916 vector
<ComboAddress
> SyncRes::getAddrs(const DNSName
&qname
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, bool cacheOnly
)
918 typedef vector
<DNSRecord
> res_t
;
919 typedef vector
<ComboAddress
> ret_t
;
922 bool oldCacheOnly
= setCacheOnly(cacheOnly
);
923 bool oldRequireAuthData
= d_requireAuthData
;
924 bool oldValidationRequested
= d_DNSSECValidationRequested
;
925 d_requireAuthData
= false;
926 d_DNSSECValidationRequested
= false;
929 vState newState
= Indeterminate
;
931 // If IPv4 ever becomes second class, we should revisit this
932 if (doResolve(qname
, QType::A
, resv4
, depth
+1, beenthere
, newState
) == 0) { // this consults cache, OR goes out
933 for (auto const &i
: resv4
) {
934 if (i
.d_type
== QType::A
) {
935 if (auto rec
= getRR
<ARecordContent
>(i
)) {
936 ret
.push_back(rec
->getCA(53));
943 // We did not find IPv4 addresses, try to get IPv6 ones
944 newState
= Indeterminate
;
946 if (doResolve(qname
, QType::AAAA
, resv6
, depth
+1, beenthere
, newState
) == 0) { // this consults cache, OR goes out
947 for (const auto &i
: resv6
) {
948 if (i
.d_type
== QType::AAAA
) {
949 if (auto rec
= getRR
<AAAARecordContent
>(i
))
950 ret
.push_back(rec
->getCA(53));
956 // We have some IPv4 records, don't bother with going out to get IPv6, but do consult the cache
957 // Once IPv6 adoption matters, this needs to be revisited
959 if (s_RC
->get(d_now
.tv_sec
, qname
, QType(QType::AAAA
), false, &cset
, d_cacheRemote
) > 0) {
960 for (const auto &i
: cset
) {
961 if (i
.d_ttl
> (unsigned int)d_now
.tv_sec
) {
962 if (auto rec
= getRR
<AAAARecordContent
>(i
)) {
963 ret
.push_back(rec
->getCA(53));
970 catch (const PolicyHitException
& e
) {
971 /* we ignore a policy hit while trying to retrieve the addresses
972 of a NS and keep processing the current query */
975 d_requireAuthData
= oldRequireAuthData
;
976 d_DNSSECValidationRequested
= oldValidationRequested
;
977 setCacheOnly(oldCacheOnly
);
979 /* we need to remove from the nsSpeeds collection the existing IPs
980 for this nameserver that are no longer in the set, even if there
981 is only one or none at all in the current set.
983 map
<ComboAddress
, float> speeds
;
984 auto& collection
= t_sstorage
.nsSpeeds
[qname
];
985 float factor
= collection
.getFactor(d_now
);
986 for(const auto& val
: ret
) {
987 speeds
[val
] = collection
.d_collection
[val
].get(factor
);
990 t_sstorage
.nsSpeeds
[qname
].purge(speeds
);
993 random_shuffle(ret
.begin(), ret
.end());
994 speedOrderCA
so(speeds
);
995 stable_sort(ret
.begin(), ret
.end(), so
);
998 string prefix
=d_prefix
;
999 prefix
.append(depth
, ' ');
1000 LOG(prefix
<<"Nameserver "<<qname
<<" IPs: ");
1002 for(const auto& addr
: ret
) {
1009 LOG((addr
.toString())<<"(" << (boost::format("%0.2f") % (speeds
[addr
]/1000.0)).str() <<"ms)");
1018 void SyncRes::getBestNSFromCache(const DNSName
&qname
, const QType
& qtype
, vector
<DNSRecord
>& bestns
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
)
1021 DNSName
subdomain(qname
);
1024 prefix
.append(depth
, ' ');
1030 LOG(prefix
<<qname
<<": Checking if we have NS in cache for '"<<subdomain
<<"'"<<endl
);
1031 vector
<DNSRecord
> ns
;
1032 *flawedNSSet
= false;
1034 if(s_RC
->get(d_now
.tv_sec
, subdomain
, QType(QType::NS
), false, &ns
, d_cacheRemote
) > 0) {
1035 bestns
.reserve(ns
.size());
1037 for(auto k
=ns
.cbegin();k
!=ns
.cend(); ++k
) {
1038 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
1039 vector
<DNSRecord
> aset
;
1041 const DNSRecord
& dr
=*k
;
1042 auto nrr
= getRR
<NSRecordContent
>(dr
);
1043 if(nrr
&& (!nrr
->getNS().isPartOf(subdomain
) || s_RC
->get(d_now
.tv_sec
, nrr
->getNS(), s_doIPv6
? QType(QType::ADDR
) : QType(QType::A
),
1044 false, doLog() ? &aset
: 0, d_cacheRemote
) > 5)) {
1045 bestns
.push_back(dr
);
1046 LOG(prefix
<<qname
<<": NS (with ip, or non-glue) in cache for '"<<subdomain
<<"' -> '"<<nrr
->getNS()<<"'"<<endl
);
1047 LOG(prefix
<<qname
<<": within bailiwick: "<< nrr
->getNS().isPartOf(subdomain
));
1049 LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset
.begin()->d_ttl
- d_now
.tv_sec
))<<endl
);
1052 LOG(", not in cache / did not look at cache"<<endl
);
1057 LOG(prefix
<<qname
<<": NS in cache for '"<<subdomain
<<"', but needs glue ("<<nrr
->getNS()<<") which we miss or is expired"<<endl
);
1062 if(!bestns
.empty()) {
1063 GetBestNSAnswer answer
;
1065 answer
.qtype
=qtype
.getCode();
1066 for(const auto& dr
: bestns
) {
1067 if (auto nsContent
= getRR
<NSRecordContent
>(dr
)) {
1068 answer
.bestns
.insert(make_pair(dr
.d_name
, nsContent
->getNS()));
1072 auto insertionPair
= beenthere
.insert(std::move(answer
));
1073 if(!insertionPair
.second
) {
1075 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' but part of LOOP (already seen "<<answer
.qname
<<")! Trying less specific NS"<<endl
);
1078 for( set
<GetBestNSAnswer
>::const_iterator j
=beenthere
.begin();j
!=beenthere
.end();++j
) {
1079 bool neo
= (j
== insertionPair
.first
);
1080 LOG(prefix
<<qname
<<": beenthere"<<(neo
?"*":"")<<": "<<j
->qname
<<"|"<<DNSRecordContent::NumberToType(j
->qtype
)<<" ("<<(unsigned int)j
->bestns
.size()<<")"<<endl
);
1085 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' (flawedNSSet="<<*flawedNSSet
<<")"<<endl
);
1090 LOG(prefix
<<qname
<<": no valid/useful NS in cache for '"<<subdomain
<<"'"<<endl
);
1092 if(subdomain
.isRoot() && !brokeloop
) {
1093 // We lost the root NS records
1095 primeRootNSZones(g_dnssecmode
!= DNSSECMode::Off
);
1096 LOG(prefix
<<qname
<<": reprimed the root"<<endl
);
1097 /* let's prevent an infinite loop */
1098 if (!d_updatingRootNS
) {
1099 getRootNS(d_now
, d_asyncResolve
);
1102 } while(subdomain
.chopOff());
1105 SyncRes::domainmap_t::const_iterator
SyncRes::getBestAuthZone(DNSName
* qname
) const
1107 if (t_sstorage
.domainmap
->empty()) {
1108 return t_sstorage
.domainmap
->end();
1111 SyncRes::domainmap_t::const_iterator ret
;
1113 ret
=t_sstorage
.domainmap
->find(*qname
);
1114 if(ret
!=t_sstorage
.domainmap
->end())
1116 }while(qname
->chopOff());
1120 /** doesn't actually do the work, leaves that to getBestNSFromCache */
1121 DNSName
SyncRes::getBestNSNamesFromCache(const DNSName
&qname
, const QType
& qtype
, NsSet
& nsset
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
)
1123 DNSName
authdomain(qname
);
1125 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
1126 if(iter
!=t_sstorage
.domainmap
->end()) {
1127 if( iter
->second
.isAuth() )
1128 // this gets picked up in doResolveAt, the empty DNSName, combined with the
1129 // empty vector means 'we are auth for this zone'
1130 nsset
.insert({DNSName(), {{}, false}});
1132 // Again, picked up in doResolveAt. An empty DNSName, combined with a
1133 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
1134 // This is actually picked up in retrieveAddressesForNS called from doResolveAt.
1135 nsset
.insert({DNSName(), {iter
->second
.d_servers
, iter
->second
.shouldRecurse() }});
1140 DNSName
subdomain(qname
);
1141 vector
<DNSRecord
> bestns
;
1142 getBestNSFromCache(subdomain
, qtype
, bestns
, flawedNSSet
, depth
, beenthere
);
1144 for(auto k
=bestns
.cbegin() ; k
!= bestns
.cend(); ++k
) {
1145 // The actual resolver code will not even look at the ComboAddress or bool
1146 const auto nsContent
= getRR
<NSRecordContent
>(*k
);
1148 nsset
.insert({nsContent
->getNS(), {{}, false}});
1149 if(k
==bestns
.cbegin())
1150 subdomain
=k
->d_name
;
1156 void SyncRes::updateValidationStatusInCache(const DNSName
&qname
, const QType
& qt
, bool aa
, vState newState
) const
1158 if (newState
== Bogus
) {
1159 s_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qt
, d_cacheRemote
, aa
, newState
, s_maxbogusttl
+ d_now
.tv_sec
);
1162 s_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qt
, d_cacheRemote
, aa
, newState
, boost::none
);
1166 bool SyncRes::doCNAMECacheCheck(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>& ret
, unsigned int depth
, int &res
, vState
& state
, bool wasAuthZone
, bool wasForwardRecurse
)
1171 prefix
.append(depth
, ' ');
1174 if((depth
>9 && d_outqueries
>10 && d_throttledqueries
>5) || depth
> 15) {
1175 LOG(prefix
<<qname
<<": recursing (CNAME or other indirection) too deep, depth="<<depth
<<endl
);
1176 res
=RCode::ServFail
;
1180 vector
<DNSRecord
> cset
;
1181 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
1182 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1184 uint32_t capTTL
= std::numeric_limits
<uint32_t>::max();
1186 QType foundQT
= QType(0); // 0 == QTYPE::ENT
1188 LOG(prefix
<<qname
<<": Looking for CNAME cache hit of '"<<qname
<<"|CNAME"<<"'"<<endl
);
1189 /* we don't require auth data for forward-recurse lookups */
1190 if (s_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) {
1192 foundQT
= QType(QType::CNAME
);
1195 if (foundName
.empty() && qname
!= g_rootdnsname
) {
1196 // look for a DNAME cache hit
1197 auto labels
= qname
.getRawLabels();
1198 DNSName
dnameName(g_rootdnsname
);
1200 LOG(prefix
<<qname
<<": Looking for DNAME cache hit of '"<<qname
<<"|DNAME' or its ancestors"<<endl
);
1202 dnameName
.prependRawLabel(labels
.back());
1204 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
1207 if (s_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) {
1208 foundName
= dnameName
;
1209 foundQT
= QType(QType::DNAME
);
1212 } while(!labels
.empty());
1215 if (foundName
.empty()) {
1216 LOG(prefix
<<qname
<<": No CNAME or DNAME cache hit of '"<< qname
<<"' found"<<endl
);
1220 for(auto const &record
: cset
) {
1221 if (record
.d_class
!= QClass::IN
) {
1225 if(record
.d_ttl
> (unsigned int) d_now
.tv_sec
) {
1227 if (!wasAuthZone
&& shouldValidate() && (wasAuth
|| wasForwardRecurse
) && state
== Indeterminate
&& d_requireAuthData
) {
1228 /* This means we couldn't figure out the state when this entry was cached,
1229 most likely because we hadn't computed the zone cuts yet. */
1230 /* make sure they are computed before validating */
1231 DNSName
subdomain(foundName
);
1232 /* if we are retrieving a DS, we only care about the state of the parent zone */
1233 if(qtype
== QType::DS
)
1234 subdomain
.chopOff();
1236 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1238 vState recordState
= getValidationStatus(foundName
, false);
1239 if (recordState
== Secure
) {
1240 LOG(prefix
<<qname
<<": got Indeterminate state from the "<<foundQT
.getName()<<" cache, validating.."<<endl
);
1241 state
= SyncRes::validateRecordsWithSigs(depth
, foundName
, foundQT
, foundName
, cset
, signatures
);
1242 if (state
!= Indeterminate
) {
1243 LOG(prefix
<<qname
<<": got Indeterminate state from the CNAME cache, new validation result is "<<vStates
[state
]<<endl
);
1244 if (state
== Bogus
) {
1245 capTTL
= s_maxbogusttl
;
1247 updateValidationStatusInCache(foundName
, foundQT
, wasAuth
, state
);
1252 LOG(prefix
<<qname
<<": Found cache "<<foundQT
.getName()<<" hit for '"<< foundName
<< "|"<<foundQT
.getName()<<"' to '"<<record
.d_content
->getZoneRepresentation()<<"', validation state is "<<vStates
[state
]<<endl
);
1254 DNSRecord dr
= record
;
1255 dr
.d_ttl
-= d_now
.tv_sec
;
1256 dr
.d_ttl
= std::min(dr
.d_ttl
, capTTL
);
1257 const uint32_t ttl
= dr
.d_ttl
;
1258 ret
.reserve(ret
.size() + 2 + signatures
.size() + authorityRecs
.size());
1261 for(const auto& signature
: signatures
) {
1263 sigdr
.d_type
=QType::RRSIG
;
1264 sigdr
.d_name
=foundName
;
1266 sigdr
.d_content
=signature
;
1267 sigdr
.d_place
=DNSResourceRecord::ANSWER
;
1268 sigdr
.d_class
=QClass::IN
;
1269 ret
.push_back(sigdr
);
1272 for(const auto& rec
: authorityRecs
) {
1273 DNSRecord
authDR(*rec
);
1275 ret
.push_back(authDR
);
1279 if (foundQT
== QType::DNAME
) {
1280 if (qtype
== QType::DNAME
&& qname
== foundName
) { // client wanted the DNAME, no need to synthesize a CNAME
1284 // Synthesize a CNAME
1285 auto dnameRR
= getRR
<DNAMERecordContent
>(record
);
1286 if (dnameRR
== nullptr) {
1287 throw ImmediateServFailException("Unable to get record content for "+foundName
.toLogString()+"|DNAME cache entry");
1289 const auto& dnameSuffix
= dnameRR
->getTarget();
1290 DNSName targetPrefix
= qname
.makeRelative(foundName
);
1292 dr
.d_type
= QType::CNAME
;
1293 dr
.d_name
= targetPrefix
+ foundName
;
1294 newTarget
= targetPrefix
+ dnameSuffix
;
1295 dr
.d_content
= std::make_shared
<CNAMERecordContent
>(CNAMERecordContent(newTarget
));
1297 } catch (const std::exception
&e
) {
1298 // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
1299 // But this is consistent with processRecords
1300 throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + foundName
.toLogString() +
1301 "', DNAME target: '" + dnameSuffix
.toLogString() + "', substituted name: '" +
1302 targetPrefix
.toLogString() + "." + dnameSuffix
.toLogString() +
1306 LOG(prefix
<<qname
<<": Synthesized "<<dr
.d_name
<<"|CNAME "<<newTarget
<<endl
);
1309 if(qtype
== QType::CNAME
) { // perhaps they really wanted a CNAME!
1314 // We have a DNAME _or_ CNAME cache hit and the client wants something else than those two.
1315 // Let's find the answer!
1316 if (foundQT
== QType::CNAME
) {
1317 const auto cnameContent
= getRR
<CNAMERecordContent
>(record
);
1318 if (cnameContent
== nullptr) {
1319 throw ImmediateServFailException("Unable to get record content for "+foundName
.toLogString()+"|CNAME cache entry");
1321 newTarget
= cnameContent
->getTarget();
1324 set
<GetBestNSAnswer
>beenthere
;
1325 vState cnameState
= Indeterminate
;
1326 res
= doResolve(newTarget
, qtype
, ret
, depth
+1, beenthere
, cnameState
);
1327 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the DNAME/CNAME quest: "<<vStates
[cnameState
]<<endl
);
1328 updateValidationState(state
, cnameState
);
1333 throw ImmediateServFailException("Could not determine whether or not there was a CNAME or DNAME in cache for '" + qname
.toLogString() + "'");
1339 vector
<DNSRecord
> records
;
1340 vector
<shared_ptr
<RRSIGRecordContent
>> signatures
;
1341 uint32_t signaturesTTL
{std::numeric_limits
<uint32_t>::max()};
1347 DNSResourceRecord::Place place
;
1348 bool operator<(const CacheKey
& rhs
) const {
1349 return tie(type
, place
, name
) < tie(rhs
.type
, rhs
.place
, rhs
.name
);
1352 typedef map
<CacheKey
, CacheEntry
> tcache_t
;
1355 static void reapRecordsFromNegCacheEntryForValidation(tcache_t
& tcache
, const vector
<DNSRecord
>& records
)
1357 for (const auto& rec
: records
) {
1358 if (rec
.d_type
== QType::RRSIG
) {
1359 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1361 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
1364 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(rec
);
1370 * Convience function to push the records from records into ret with a new TTL
1372 * \param records DNSRecords that need to go into ret
1373 * \param ttl The new TTL for these records
1374 * \param ret The vector of DNSRecords that should contian the records with the modified TTL
1376 static void addTTLModifiedRecords(const vector
<DNSRecord
>& records
, const uint32_t ttl
, vector
<DNSRecord
>& ret
) {
1377 for (const auto& rec
: records
) {
1384 void SyncRes::computeNegCacheValidationStatus(const NegCache::NegCacheEntry
* ne
, const DNSName
& qname
, const QType
& qtype
, const int res
, vState
& state
, unsigned int depth
)
1386 DNSName
subdomain(qname
);
1387 /* if we are retrieving a DS, we only care about the state of the parent zone */
1388 if(qtype
== QType::DS
)
1389 subdomain
.chopOff();
1391 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1394 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->authoritySOA
.records
);
1395 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->authoritySOA
.signatures
);
1396 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->DNSSECRecords
.records
);
1397 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->DNSSECRecords
.signatures
);
1399 for (const auto& entry
: tcache
) {
1400 // this happens when we did store signatures, but passed on the records themselves
1401 if (entry
.second
.records
.empty()) {
1405 const DNSName
& owner
= entry
.first
.name
;
1407 vState recordState
= getValidationStatus(owner
, false);
1408 if (state
== Indeterminate
) {
1409 state
= recordState
;
1412 if (recordState
== Secure
) {
1413 recordState
= SyncRes::validateRecordsWithSigs(depth
, qname
, qtype
, owner
, entry
.second
.records
, entry
.second
.signatures
);
1416 if (recordState
!= Indeterminate
&& recordState
!= state
) {
1417 updateValidationState(state
, recordState
);
1418 if (state
!= Secure
) {
1424 if (state
== Secure
) {
1425 vState neValidationState
= ne
->d_validationState
;
1426 dState expectedState
= res
== RCode::NXDomain
? NXDOMAIN
: NXQTYPE
;
1427 dState denialState
= getDenialValidationState(*ne
, state
, expectedState
, false);
1428 updateDenialValidationState(neValidationState
, ne
->d_name
, state
, denialState
, expectedState
, qtype
== QType::DS
|| expectedState
== NXDOMAIN
);
1430 if (state
!= Indeterminate
) {
1431 /* validation succeeded, let's update the cache entry so we don't have to validate again */
1432 boost::optional
<uint32_t> capTTD
= boost::none
;
1433 if (state
== Bogus
) {
1434 capTTD
= d_now
.tv_sec
+ s_maxbogusttl
;
1436 t_sstorage
.negcache
.updateValidationStatus(ne
->d_name
, ne
->d_qtype
, state
, capTTD
);
1440 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
)
1442 bool giveNegative
=false;
1447 prefix
.append(depth
, ' ');
1450 // 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)
1451 DNSName
sqname(qname
);
1454 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
1456 const NegCache::NegCacheEntry
* ne
= nullptr;
1459 t_sstorage
.negcache
.getRootNXTrust(qname
, d_now
, &ne
) &&
1460 ne
->d_auth
.isRoot() &&
1461 !(wasForwardedOrAuthZone
&& !authname
.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
1462 sttl
= ne
->d_ttd
- d_now
.tv_sec
;
1463 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
->d_auth
<<"' & '"<<ne
->d_name
<<"' for another "<<sttl
<<" seconds"<<endl
);
1464 res
= RCode::NXDomain
;
1465 giveNegative
= true;
1466 cachedState
= ne
->d_validationState
;
1467 } else if (t_sstorage
.negcache
.get(qname
, qtype
, d_now
, &ne
)) {
1468 /* If we are looking for a DS, discard NXD if auth == qname
1469 and ask for a specific denial instead */
1470 if (qtype
!= QType::DS
|| ne
->d_qtype
.getCode() || ne
->d_auth
!= qname
||
1471 t_sstorage
.negcache
.get(qname
, qtype
, d_now
, &ne
, true))
1473 res
= RCode::NXDomain
;
1474 sttl
= ne
->d_ttd
- d_now
.tv_sec
;
1475 giveNegative
= true;
1476 cachedState
= ne
->d_validationState
;
1477 if (ne
->d_qtype
.getCode()) {
1478 LOG(prefix
<<qname
<<": "<<qtype
.getName()<<" is negatively cached via '"<<ne
->d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1479 res
= RCode::NoError
;
1481 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<" is negatively cached via '"<<ne
->d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1484 } else if (s_hardenNXD
!= HardenNXD::No
&& !qname
.isRoot() && !wasForwardedOrAuthZone
) {
1485 auto labels
= qname
.getRawLabels();
1486 DNSName
negCacheName(g_rootdnsname
);
1487 negCacheName
.prependRawLabel(labels
.back());
1489 while(!labels
.empty()) {
1490 if (t_sstorage
.negcache
.get(negCacheName
, QType(0), d_now
, &ne
, true)) {
1491 if (ne
->d_validationState
== Indeterminate
&& validationEnabled()) {
1492 // LOG(prefix << negCacheName << " negatively cached and Indeterminate, trying to validate NXDOMAIN" << endl);
1494 // And get the updated ne struct
1495 //t_sstorage.negcache.get(negCacheName, QType(0), d_now, &ne, true);
1497 if ((s_hardenNXD
== HardenNXD::Yes
&& ne
->d_validationState
!= Bogus
) || ne
->d_validationState
== Secure
) {
1498 res
= RCode::NXDomain
;
1499 sttl
= ne
->d_ttd
- d_now
.tv_sec
;
1500 giveNegative
= true;
1501 cachedState
= ne
->d_validationState
;
1502 LOG(prefix
<<qname
<<": Name '"<<negCacheName
<<"' and below, is negatively cached via '"<<ne
->d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1506 negCacheName
.prependRawLabel(labels
.back());
1513 state
= cachedState
;
1515 if (!wasAuthZone
&& shouldValidate() && state
== Indeterminate
) {
1516 LOG(prefix
<<qname
<<": got Indeterminate state for records retrieved from the negative cache, validating.."<<endl
);
1517 computeNegCacheValidationStatus(ne
, qname
, qtype
, res
, state
, depth
);
1519 if (state
!= cachedState
&& state
== Bogus
) {
1520 sttl
= std::min(sttl
, s_maxbogusttl
);
1524 // Transplant SOA to the returned packet
1525 addTTLModifiedRecords(ne
->authoritySOA
.records
, sttl
, ret
);
1527 addTTLModifiedRecords(ne
->authoritySOA
.signatures
, sttl
, ret
);
1528 addTTLModifiedRecords(ne
->DNSSECRecords
.records
, sttl
, ret
);
1529 addTTLModifiedRecords(ne
->DNSSECRecords
.signatures
, sttl
, ret
);
1532 LOG(prefix
<<qname
<<": updating validation state with negative cache content for "<<qname
<<" to "<<vStates
[state
]<<endl
);
1536 vector
<DNSRecord
> cset
;
1537 bool found
=false, expired
=false;
1538 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
1539 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1541 uint32_t capTTL
= std::numeric_limits
<uint32_t>::max();
1543 if(s_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) {
1545 LOG(prefix
<<sqname
<<": Found cache hit for "<<sqt
.getName()<<": ");
1547 if (!wasAuthZone
&& shouldValidate() && (wasCachedAuth
|| wasForwardRecurse
) && cachedState
== Indeterminate
&& d_requireAuthData
) {
1549 /* This means we couldn't figure out the state when this entry was cached,
1550 most likely because we hadn't computed the zone cuts yet. */
1551 /* make sure they are computed before validating */
1552 DNSName
subdomain(sqname
);
1553 /* if we are retrieving a DS, we only care about the state of the parent zone */
1554 if(qtype
== QType::DS
)
1555 subdomain
.chopOff();
1557 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1559 vState recordState
= getValidationStatus(qname
, false);
1560 if (recordState
== Secure
) {
1561 LOG(prefix
<<sqname
<<": got Indeterminate state from the cache, validating.."<<endl
);
1562 cachedState
= SyncRes::validateRecordsWithSigs(depth
, sqname
, sqt
, sqname
, cset
, signatures
);
1565 cachedState
= recordState
;
1568 if (cachedState
!= Indeterminate
) {
1569 LOG(prefix
<<qname
<<": got Indeterminate state from the cache, validation result is "<<vStates
[cachedState
]<<endl
);
1570 if (cachedState
== Bogus
) {
1571 capTTL
= s_maxbogusttl
;
1573 updateValidationStatusInCache(sqname
, sqt
, wasCachedAuth
, cachedState
);
1577 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
1579 LOG(j
->d_content
->getZoneRepresentation());
1581 if (j
->d_class
!= QClass::IN
) {
1585 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
1587 dr
.d_ttl
-= d_now
.tv_sec
;
1588 dr
.d_ttl
= std::min(dr
.d_ttl
, capTTL
);
1591 LOG("[ttl="<<dr
.d_ttl
<<"] ");
1600 ret
.reserve(ret
.size() + signatures
.size() + authorityRecs
.size());
1602 for(const auto& signature
: signatures
) {
1604 dr
.d_type
=QType::RRSIG
;
1607 dr
.d_content
=signature
;
1608 dr
.d_place
= DNSResourceRecord::ANSWER
;
1609 dr
.d_class
=QClass::IN
;
1613 for(const auto& rec
: authorityRecs
) {
1620 if(found
&& !expired
) {
1623 LOG(prefix
<<qname
<<": updating validation state with cache content for "<<qname
<<" to "<<vStates
[cachedState
]<<endl
);
1624 state
= cachedState
;
1628 LOG(prefix
<<qname
<<": cache had only stale entries"<<endl
);
1634 bool SyncRes::moreSpecificThan(const DNSName
& a
, const DNSName
&b
) const
1636 return (a
.isPartOf(b
) && a
.countLabels() > b
.countLabels());
1641 bool operator()(const std::pair
<DNSName
, float> &a
, const std::pair
<DNSName
, float> &b
) const
1643 return a
.second
< b
.second
;
1647 inline std::vector
<std::pair
<DNSName
, float>> SyncRes::shuffleInSpeedOrder(NsSet
&tnameservers
, const string
&prefix
)
1649 std::vector
<std::pair
<DNSName
, float>> rnameservers
;
1650 rnameservers
.reserve(tnameservers
.size());
1651 for(const auto& tns
: tnameservers
) {
1652 float speed
= t_sstorage
.nsSpeeds
[tns
.first
].get(d_now
);
1653 rnameservers
.push_back({tns
.first
, speed
});
1654 if(tns
.first
.empty()) // this was an authoritative OOB zone, don't pollute the nsSpeeds with that
1655 return rnameservers
;
1658 random_shuffle(rnameservers
.begin(),rnameservers
.end());
1660 stable_sort(rnameservers
.begin(),rnameservers
.end(), so
);
1663 LOG(prefix
<<"Nameservers: ");
1664 for(auto i
=rnameservers
.begin();i
!=rnameservers
.end();++i
) {
1665 if(i
!=rnameservers
.begin()) {
1667 if(!((i
-rnameservers
.begin())%3)) {
1668 LOG(endl
<<prefix
<<" ");
1671 LOG(i
->first
.toLogString()<<"(" << (boost::format("%0.2f") % (i
->second
/1000.0)).str() <<"ms)");
1675 return rnameservers
;
1678 inline vector
<ComboAddress
> SyncRes::shuffleForwardSpeed(const vector
<ComboAddress
> &rnameservers
, const string
&prefix
, const bool wasRd
)
1680 vector
<ComboAddress
> nameservers
= rnameservers
;
1681 map
<ComboAddress
, float> speeds
;
1683 for(const auto& val
: nameservers
) {
1685 DNSName nsName
= DNSName(val
.toStringWithPort());
1686 speed
=t_sstorage
.nsSpeeds
[nsName
].get(d_now
);
1689 random_shuffle(nameservers
.begin(),nameservers
.end());
1690 speedOrderCA
so(speeds
);
1691 stable_sort(nameservers
.begin(),nameservers
.end(), so
);
1694 LOG(prefix
<<"Nameservers: ");
1695 for(vector
<ComboAddress
>::const_iterator i
=nameservers
.cbegin();i
!=nameservers
.cend();++i
) {
1696 if(i
!=nameservers
.cbegin()) {
1698 if(!((i
-nameservers
.cbegin())%3)) {
1699 LOG(endl
<<prefix
<<" ");
1702 LOG((wasRd
? string("+") : string("-")) << i
->toStringWithPort() <<"(" << (boost::format("%0.2f") % (speeds
[*i
]/1000.0)).str() <<"ms)");
1709 static uint32_t getRRSIGTTL(const time_t now
, const std::shared_ptr
<RRSIGRecordContent
>& rrsig
)
1712 if (now
< rrsig
->d_sigexpire
) {
1713 res
= static_cast<uint32_t>(rrsig
->d_sigexpire
) - now
;
1718 static const set
<uint16_t> nsecTypes
= {QType::NSEC
, QType::NSEC3
};
1720 /* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
1722 * \param records The records to parse for the authority SOA and NSEC(3) records
1723 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
1725 static void harvestNXRecords(const vector
<DNSRecord
>& records
, NegCache::NegCacheEntry
& ne
, const time_t now
, uint32_t* lowestTTL
) {
1726 for(const auto& rec
: records
) {
1727 if(rec
.d_place
!= DNSResourceRecord::AUTHORITY
)
1728 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
1729 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
1730 // records MUST be in the same section as the records they cover.
1731 // Hence, we ignore all records outside of the AUTHORITY section.
1734 if(rec
.d_type
== QType::RRSIG
) {
1735 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1737 if(rrsig
->d_type
== QType::SOA
) {
1738 ne
.authoritySOA
.signatures
.push_back(rec
);
1739 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1740 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1741 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1744 if(nsecTypes
.count(rrsig
->d_type
)) {
1745 ne
.DNSSECRecords
.signatures
.push_back(rec
);
1746 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1747 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1748 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1754 if(rec
.d_type
== QType::SOA
) {
1755 ne
.authoritySOA
.records
.push_back(rec
);
1757 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1761 if(nsecTypes
.count(rec
.d_type
)) {
1762 ne
.DNSSECRecords
.records
.push_back(rec
);
1764 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1771 static cspmap_t
harvestCSPFromNE(const NegCache::NegCacheEntry
& ne
)
1774 for(const auto& rec
: ne
.DNSSECRecords
.signatures
) {
1775 if(rec
.d_type
== QType::RRSIG
) {
1776 auto rrc
= getRR
<RRSIGRecordContent
>(rec
);
1778 cspmap
[{rec
.d_name
,rrc
->d_type
}].signatures
.push_back(rrc
);
1782 for(const auto& rec
: ne
.DNSSECRecords
.records
) {
1783 cspmap
[{rec
.d_name
, rec
.d_type
}].records
.insert(rec
.d_content
);
1788 // TODO remove after processRecords is fixed!
1789 // Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
1790 static void addNXNSECS(vector
<DNSRecord
>&ret
, const vector
<DNSRecord
>& records
)
1792 NegCache::NegCacheEntry ne
;
1793 harvestNXRecords(records
, ne
, 0, nullptr);
1794 ret
.insert(ret
.end(), ne
.authoritySOA
.signatures
.begin(), ne
.authoritySOA
.signatures
.end());
1795 ret
.insert(ret
.end(), ne
.DNSSECRecords
.records
.begin(), ne
.DNSSECRecords
.records
.end());
1796 ret
.insert(ret
.end(), ne
.DNSSECRecords
.signatures
.begin(), ne
.DNSSECRecords
.signatures
.end());
1799 bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine
& dfe
, const NsSet
& nameservers
)
1801 /* we skip RPZ processing if:
1802 - it was disabled (d_wantsRPZ is false) ;
1803 - we already got a RPZ hit (d_appliedPolicy.d_type != DNSFilterEngine::PolicyType::None) since
1804 the only way we can get back here is that it was a 'pass-thru' (NoAction) meaning that we should not
1805 process any further RPZ rules.
1807 if (d_wantsRPZ
&& (d_appliedPolicy
.d_type
== DNSFilterEngine::PolicyType::None
|| d_appliedPolicy
.d_kind
== DNSFilterEngine::PolicyKind::NoAction
)) {
1808 for (auto const &ns
: nameservers
) {
1809 bool match
= dfe
.getProcessingPolicy(ns
.first
, d_discardedPolicies
, d_appliedPolicy
);
1810 if (match
&& d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1811 LOG(", however nameserver "<<ns
.first
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1815 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1816 for (auto const &address
: ns
.second
.first
) {
1817 match
= dfe
.getProcessingPolicy(address
, d_discardedPolicies
, d_appliedPolicy
);
1818 if (match
&& d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1819 LOG(", however nameserver "<<ns
.first
<<" IP address "<<address
.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1828 bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine
& dfe
, const ComboAddress
& remoteIP
)
1830 /* we skip RPZ processing if:
1831 - it was disabled (d_wantsRPZ is false) ;
1832 - we already got a RPZ hit (d_appliedPolicy.d_type != DNSFilterEngine::PolicyType::None) since
1833 the only way we can get back here is that it was a 'pass-thru' (NoAction) meaning that we should not
1834 process any further RPZ rules.
1836 if (d_wantsRPZ
&& (d_appliedPolicy
.d_type
== DNSFilterEngine::PolicyType::None
|| d_appliedPolicy
.d_kind
== DNSFilterEngine::PolicyKind::NoAction
)) {
1837 bool match
= dfe
.getProcessingPolicy(remoteIP
, d_discardedPolicies
, d_appliedPolicy
);
1838 if (match
&& d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) {
1839 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")+"')");
1846 vector
<ComboAddress
> SyncRes::retrieveAddressesForNS(const std::string
& prefix
, const DNSName
& qname
, std::vector
<std::pair
<DNSName
, float>>::const_iterator
& tns
, const unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, const vector
<std::pair
<DNSName
, float>>& rnameservers
, NsSet
& nameservers
, bool& sendRDQuery
, bool& pierceDontQuery
, bool& flawedNSSet
, bool cacheOnly
)
1848 vector
<ComboAddress
> result
;
1850 if(!tns
->first
.empty()) {
1851 LOG(prefix
<<qname
<<": Trying to resolve NS '"<<tns
->first
<< "' ("<<1+tns
-rnameservers
.begin()<<"/"<<(unsigned int)rnameservers
.size()<<")"<<endl
);
1852 result
= getAddrs(tns
->first
, depth
+2, beenthere
, cacheOnly
);
1853 pierceDontQuery
=false;
1856 LOG(prefix
<<qname
<<": Domain has hardcoded nameserver");
1858 if(nameservers
[tns
->first
].first
.size() > 1) {
1863 sendRDQuery
= nameservers
[tns
->first
].second
;
1864 result
= shuffleForwardSpeed(nameservers
[tns
->first
].first
, doLog() ? (prefix
+qname
.toString()+": ") : string(), sendRDQuery
);
1865 pierceDontQuery
=true;
1870 bool SyncRes::throttledOrBlocked(const std::string
& prefix
, const ComboAddress
& remoteIP
, const DNSName
& qname
, const QType
& qtype
, bool pierceDontQuery
)
1872 if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0))) {
1873 LOG(prefix
<<qname
<<": server throttled "<<endl
);
1874 s_throttledqueries
++; d_throttledqueries
++;
1877 else if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()))) {
1878 LOG(prefix
<<qname
<<": query throttled "<<remoteIP
.toString()<<", "<<qname
<<"; "<<qtype
.getName()<<endl
);
1879 s_throttledqueries
++; d_throttledqueries
++;
1882 else if(!pierceDontQuery
&& s_dontQuery
&& s_dontQuery
->match(&remoteIP
)) {
1883 LOG(prefix
<<qname
<<": not sending query to " << remoteIP
.toString() << ", blocked by 'dont-query' setting" << endl
);
1890 bool SyncRes::validationEnabled() const
1892 return g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
;
1895 uint32_t SyncRes::computeLowestTTD(const std::vector
<DNSRecord
>& records
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, uint32_t signaturesTTL
) const
1897 uint32_t lowestTTD
= std::numeric_limits
<uint32_t>::max();
1898 for(const auto& record
: records
)
1899 lowestTTD
= min(lowestTTD
, record
.d_ttl
);
1901 /* even if it was not requested for that request (Process, and neither AD nor DO set),
1902 it might be requested at a later time so we need to be careful with the TTL. */
1903 if (validationEnabled() && !signatures
.empty()) {
1904 /* if we are validating, we don't want to cache records after their signatures expire. */
1905 /* records TTL are now TTD, let's add 'now' to the signatures lowest TTL */
1906 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(signaturesTTL
+ d_now
.tv_sec
));
1908 for(const auto& sig
: signatures
) {
1909 if (isRRSIGNotExpired(d_now
.tv_sec
, sig
)) {
1910 // we don't decerement d_sigexpire by 'now' because we actually want a TTD, not a TTL */
1911 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(sig
->d_sigexpire
));
1919 void SyncRes::updateValidationState(vState
& state
, const vState stateUpdate
)
1921 LOG(d_prefix
<<"validation state was "<<std::string(vStates
[state
])<<", state update is "<<std::string(vStates
[stateUpdate
]));
1923 if (stateUpdate
== TA
) {
1926 else if (stateUpdate
== NTA
) {
1929 else if (stateUpdate
== Bogus
) {
1932 else if (state
== Indeterminate
) {
1933 state
= stateUpdate
;
1935 else if (stateUpdate
== Insecure
) {
1936 if (state
!= Bogus
) {
1940 LOG(", validation state is now "<<std::string(vStates
[state
])<<endl
);
1943 vState
SyncRes::getTA(const DNSName
& zone
, dsmap_t
& ds
)
1945 auto luaLocal
= g_luaconfs
.getLocal();
1947 if (luaLocal
->dsAnchors
.empty()) {
1948 LOG(d_prefix
<<": No trust anchors configured, everything is Insecure"<<endl
);
1949 /* We have no TA, everything is insecure */
1954 if (haveNegativeTrustAnchor(luaLocal
->negAnchors
, zone
, reason
)) {
1955 LOG(d_prefix
<<": got NTA for '"<<zone
<<"'"<<endl
);
1959 if (getTrustAnchor(luaLocal
->dsAnchors
, zone
, ds
)) {
1960 LOG(d_prefix
<<": got TA for '"<<zone
<<"'"<<endl
);
1964 LOG(d_prefix
<<": no TA found for '"<<zone
<<"' among "<< luaLocal
->dsAnchors
.size()<<endl
);
1967 if (zone
.isRoot()) {
1968 /* No TA for the root */
1972 return Indeterminate
;
1975 static size_t countSupportedDS(const dsmap_t
& dsmap
)
1979 for (const auto& ds
: dsmap
) {
1980 if (isSupportedDS(ds
)) {
1988 vState
SyncRes::getDSRecords(const DNSName
& zone
, dsmap_t
& ds
, bool taOnly
, unsigned int depth
, bool bogusOnNXD
, bool* foundCut
)
1990 vState result
= getTA(zone
, ds
);
1992 if (result
!= Indeterminate
|| taOnly
) {
1994 *foundCut
= (result
!= Indeterminate
);
1998 if (countSupportedDS(ds
) == 0) {
2006 else if (result
== NTA
) {
2013 bool oldSkipCNAME
= d_skipCNAMECheck
;
2014 d_skipCNAMECheck
= true;
2016 std::set
<GetBestNSAnswer
> beenthere
;
2017 std::vector
<DNSRecord
> dsrecords
;
2019 vState state
= Indeterminate
;
2020 int rcode
= doResolve(zone
, QType(QType::DS
), dsrecords
, depth
+ 1, beenthere
, state
);
2021 d_skipCNAMECheck
= oldSkipCNAME
;
2023 if (rcode
== RCode::NoError
|| (rcode
== RCode::NXDomain
&& !bogusOnNXD
)) {
2024 uint8_t bestDigestType
= 0;
2026 bool gotCNAME
= false;
2027 for (const auto& record
: dsrecords
) {
2028 if (record
.d_type
== QType::DS
) {
2029 const auto dscontent
= getRR
<DSRecordContent
>(record
);
2030 if (dscontent
&& isSupportedDS(*dscontent
)) {
2031 // Make GOST a lower prio than SHA256
2032 if (dscontent
->d_digesttype
== DNSSECKeeper::DIGEST_GOST
&& bestDigestType
== DNSSECKeeper::DIGEST_SHA256
) {
2035 if (dscontent
->d_digesttype
> bestDigestType
|| (bestDigestType
== DNSSECKeeper::DIGEST_GOST
&& dscontent
->d_digesttype
== DNSSECKeeper::DIGEST_SHA256
)) {
2036 bestDigestType
= dscontent
->d_digesttype
;
2038 ds
.insert(*dscontent
);
2041 else if (record
.d_type
== QType::CNAME
&& record
.d_name
== zone
) {
2046 /* RFC 4509 section 3: "Validator implementations SHOULD ignore DS RRs containing SHA-1
2047 * digests if DS RRs with SHA-256 digests are present in the DS RRset."
2048 * As SHA348 is specified as well, the spirit of the this line is "use the best algorithm".
2050 for (auto dsrec
= ds
.begin(); dsrec
!= ds
.end(); ) {
2051 if (dsrec
->d_digesttype
!= bestDigestType
) {
2052 dsrec
= ds
.erase(dsrec
);
2059 if (rcode
== RCode::NoError
) {
2061 /* we have no DS, it's either:
2062 - a delegation to a non-DNSSEC signed zone
2063 - no delegation, we stay in the same zone
2065 if (gotCNAME
|| denialProvesNoDelegation(zone
, dsrecords
)) {
2066 /* we are still inside the same zone */
2074 /* delegation with no DS, might be Secure -> Insecure */
2079 /* a delegation with no DS is either:
2080 - a signed zone (Secure) to an unsigned one (Insecure)
2081 - an unsigned zone to another unsigned one (Insecure stays Insecure, Bogus stays Bogus)
2083 return state
== Secure
? Insecure
: state
;
2095 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
2099 bool SyncRes::haveExactValidationStatus(const DNSName
& domain
)
2101 if (!shouldValidate()) {
2104 const auto& it
= d_cutStates
.find(domain
);
2105 if (it
!= d_cutStates
.cend()) {
2111 vState
SyncRes::getValidationStatus(const DNSName
& subdomain
, bool allowIndeterminate
)
2113 vState result
= Indeterminate
;
2115 if (!shouldValidate()) {
2118 DNSName
name(subdomain
);
2120 const auto& it
= d_cutStates
.find(name
);
2121 if (it
!= d_cutStates
.cend()) {
2122 if (allowIndeterminate
|| it
->second
!= Indeterminate
) {
2123 LOG(d_prefix
<<": got status "<<vStates
[it
->second
]<<" for name "<<subdomain
<<" (from "<<name
<<")"<<endl
);
2128 while (name
.chopOff());
2133 bool SyncRes::lookForCut(const DNSName
& qname
, unsigned int depth
, const vState existingState
, vState
& newState
)
2135 bool foundCut
= false;
2137 vState dsState
= getDSRecords(qname
, ds
, newState
== Bogus
|| existingState
== Insecure
|| existingState
== Bogus
, depth
, false, &foundCut
);
2139 if (dsState
!= Indeterminate
) {
2146 void SyncRes::computeZoneCuts(const DNSName
& begin
, const DNSName
& end
, unsigned int depth
)
2148 if(!begin
.isPartOf(end
)) {
2149 LOG(d_prefix
<<" "<<begin
.toLogString()<<" is not part of "<<end
.toLogString()<<endl
);
2150 throw PDNSException(begin
.toLogString() + " is not part of " + end
.toLogString());
2153 if (d_cutStates
.count(begin
) != 0) {
2157 const bool oldCacheOnly
= setCacheOnly(false);
2160 vState cutState
= getDSRecords(end
, ds
, false, depth
);
2161 LOG(d_prefix
<<": setting cut state for "<<end
<<" to "<<vStates
[cutState
]<<endl
);
2162 d_cutStates
[end
] = cutState
;
2164 if (!shouldValidate()) {
2165 setCacheOnly(oldCacheOnly
);
2170 std::vector
<string
> labelsToAdd
= begin
.makeRelative(end
).getRawLabels();
2172 bool oldSkipCNAME
= d_skipCNAMECheck
;
2173 d_skipCNAMECheck
= true;
2175 while(qname
!= begin
) {
2176 if (labelsToAdd
.empty())
2179 qname
.prependRawLabel(labelsToAdd
.back());
2180 labelsToAdd
.pop_back();
2181 LOG(d_prefix
<<": - Looking for a cut at "<<qname
<<endl
);
2183 const auto cutIt
= d_cutStates
.find(qname
);
2184 if (cutIt
!= d_cutStates
.cend()) {
2185 if (cutIt
->second
!= Indeterminate
) {
2186 LOG(d_prefix
<<": - Cut already known at "<<qname
<<endl
);
2187 cutState
= cutIt
->second
;
2192 /* no need to look for NS and DS if we are already insecure or bogus,
2195 if (cutState
== Insecure
|| cutState
== Bogus
) {
2197 vState newState
= getDSRecords(qname
, cutDS
, true, depth
);
2198 if (newState
== Indeterminate
) {
2202 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[newState
]<<endl
);
2203 cutState
= newState
;
2205 d_cutStates
[qname
] = cutState
;
2210 vState newState
= Indeterminate
;
2211 /* temporarily mark as Indeterminate, so that we won't enter an endless loop
2212 trying to determine that zone cut again. */
2213 d_cutStates
[qname
] = newState
;
2214 bool foundCut
= lookForCut(qname
, depth
+ 1, cutState
, newState
);
2216 LOG(d_prefix
<<": - Found cut at "<<qname
<<endl
);
2217 if (newState
!= Indeterminate
) {
2218 cutState
= newState
;
2220 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[cutState
]<<endl
);
2221 d_cutStates
[qname
] = cutState
;
2224 /* remove the temporary cut */
2225 LOG(d_prefix
<<qname
<<": removing cut state for "<<qname
<<endl
);
2226 d_cutStates
.erase(qname
);
2230 d_skipCNAMECheck
= oldSkipCNAME
;
2232 LOG(d_prefix
<<": list of cuts from "<<begin
<<" to "<<end
<<endl
);
2233 for (const auto& cut
: d_cutStates
) {
2234 if (cut
.first
.isRoot() || (begin
.isPartOf(cut
.first
) && cut
.first
.isPartOf(end
))) {
2235 LOG(" - "<<cut
.first
<<": "<<vStates
[cut
.second
]<<endl
);
2238 setCacheOnly(oldCacheOnly
);
2241 vState
SyncRes::validateDNSKeys(const DNSName
& zone
, const std::vector
<DNSRecord
>& dnskeys
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, unsigned int depth
)
2244 if (!signatures
.empty()) {
2245 DNSName signer
= getSigner(signatures
);
2247 if (!signer
.empty() && zone
.isPartOf(signer
)) {
2248 vState state
= getDSRecords(signer
, ds
, false, depth
);
2250 if (state
!= Secure
) {
2256 skeyset_t tentativeKeys
;
2257 sortedRecords_t toSign
;
2259 for (const auto& dnskey
: dnskeys
) {
2260 if (dnskey
.d_type
== QType::DNSKEY
) {
2261 auto content
= getRR
<DNSKEYRecordContent
>(dnskey
);
2263 tentativeKeys
.insert(content
);
2264 toSign
.insert(content
);
2269 LOG(d_prefix
<<": trying to validate "<<std::to_string(tentativeKeys
.size())<<" DNSKEYs with "<<std::to_string(ds
.size())<<" DS"<<endl
);
2270 skeyset_t validatedKeys
;
2271 validateDNSKeysAgainstDS(d_now
.tv_sec
, zone
, ds
, tentativeKeys
, toSign
, signatures
, validatedKeys
);
2273 LOG(d_prefix
<<": we now have "<<std::to_string(validatedKeys
.size())<<" DNSKEYs"<<endl
);
2275 /* if we found at least one valid RRSIG covering the set,
2276 all tentative keys are validated keys. Otherwise it means
2277 we haven't found at least one DNSKEY and a matching RRSIG
2278 covering this set, this looks Bogus. */
2279 if (validatedKeys
.size() != tentativeKeys
.size()) {
2280 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
2287 vState
SyncRes::getDNSKeys(const DNSName
& signer
, skeyset_t
& keys
, unsigned int depth
)
2289 std::vector
<DNSRecord
> records
;
2290 std::set
<GetBestNSAnswer
> beenthere
;
2291 LOG(d_prefix
<<"Retrieving DNSKeys for "<<signer
<<endl
);
2293 vState state
= Indeterminate
;
2294 /* following CNAME might lead to us to the wrong DNSKEY */
2295 bool oldSkipCNAME
= d_skipCNAMECheck
;
2296 d_skipCNAMECheck
= true;
2297 int rcode
= doResolve(signer
, QType(QType::DNSKEY
), records
, depth
+ 1, beenthere
, state
);
2298 d_skipCNAMECheck
= oldSkipCNAME
;
2300 if (rcode
== RCode::NoError
) {
2301 if (state
== Secure
) {
2302 for (const auto& key
: records
) {
2303 if (key
.d_type
== QType::DNSKEY
) {
2304 auto content
= getRR
<DNSKEYRecordContent
>(key
);
2306 keys
.insert(content
);
2311 LOG(d_prefix
<<"Retrieved "<<keys
.size()<<" DNSKeys for "<<signer
<<", state is "<<vStates
[state
]<<endl
);
2315 LOG(d_prefix
<<"Returning Bogus state from "<<__func__
<<"("<<signer
<<")"<<endl
);
2319 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
)
2322 if (!signatures
.empty()) {
2323 const DNSName signer
= getSigner(signatures
);
2324 if (!signer
.empty() && name
.isPartOf(signer
)) {
2325 if ((qtype
== QType::DNSKEY
|| qtype
== QType::DS
) && signer
== qname
) {
2326 /* we are already retrieving those keys, sorry */
2327 if (qtype
== QType::DS
) {
2328 /* something is very wrong */
2329 LOG(d_prefix
<<"The DS for "<<qname
<<" is signed by itself, going Bogus"<<endl
);
2332 return Indeterminate
;
2334 vState state
= getDNSKeys(signer
, keys
, depth
);
2335 if (state
!= Secure
) {
2340 LOG(d_prefix
<<"Bogus!"<<endl
);
2344 sortedRecords_t recordcontents
;
2345 for (const auto& record
: records
) {
2346 recordcontents
.insert(record
.d_content
);
2349 LOG(d_prefix
<<"Going to validate "<<recordcontents
.size()<< " record contents with "<<signatures
.size()<<" sigs and "<<keys
.size()<<" keys for "<<name
<<endl
);
2350 if (validateWithKeySet(d_now
.tv_sec
, name
, recordcontents
, signatures
, keys
, false)) {
2351 LOG(d_prefix
<<"Secure!"<<endl
);
2355 LOG(d_prefix
<<"Bogus!"<<endl
);
2359 static bool allowAdditionalEntry(std::unordered_set
<DNSName
>& allowedAdditionals
, const DNSRecord
& rec
)
2361 switch(rec
.d_type
) {
2364 if (auto mxContent
= getRR
<MXRecordContent
>(rec
)) {
2365 allowedAdditionals
.insert(mxContent
->d_mxname
);
2371 if (auto nsContent
= getRR
<NSRecordContent
>(rec
)) {
2372 allowedAdditionals
.insert(nsContent
->getNS());
2378 if (auto srvContent
= getRR
<SRVRecordContent
>(rec
)) {
2379 allowedAdditionals
.insert(srvContent
->d_target
);
2388 void SyncRes::sanitizeRecords(const std::string
& prefix
, LWResult
& lwr
, const DNSName
& qname
, const QType
& qtype
, const DNSName
& auth
, bool wasForwarded
, bool rdQuery
)
2390 const bool wasForwardRecurse
= wasForwarded
&& rdQuery
;
2391 /* list of names for which we will allow A and AAAA records in the additional section
2393 std::unordered_set
<DNSName
> allowedAdditionals
= { qname
};
2394 bool haveAnswers
= false;
2395 bool isNXDomain
= false;
2396 bool isNXQType
= false;
2398 for(auto rec
= lwr
.d_records
.begin(); rec
!= lwr
.d_records
.end(); ) {
2400 if (rec
->d_type
== QType::OPT
) {
2405 if (rec
->d_class
!= QClass::IN
) {
2406 LOG(prefix
<<"Removing non internet-classed data received from "<<auth
<<endl
);
2407 rec
= lwr
.d_records
.erase(rec
);
2411 if (rec
->d_type
== QType::ANY
) {
2412 LOG(prefix
<<"Removing 'ANY'-typed data received from "<<auth
<<endl
);
2413 rec
= lwr
.d_records
.erase(rec
);
2417 if (!rec
->d_name
.isPartOf(auth
)) {
2418 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
);
2419 rec
= lwr
.d_records
.erase(rec
);
2423 /* dealing with the records in answer */
2424 if (!(lwr
.d_aabit
|| wasForwardRecurse
) && rec
->d_place
== DNSResourceRecord::ANSWER
) {
2425 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2426 are sending such responses */
2427 if (!(rec
->d_type
== QType::CNAME
&& qname
== rec
->d_name
)) {
2428 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
);
2429 rec
= lwr
.d_records
.erase(rec
);
2434 if (rec
->d_type
== QType::DNAME
&& (rec
->d_place
!= DNSResourceRecord::ANSWER
|| !qname
.isPartOf(rec
->d_name
))) {
2435 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
);
2436 rec
= lwr
.d_records
.erase(rec
);
2440 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
)) {
2441 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
);
2442 rec
= lwr
.d_records
.erase(rec
);
2446 if (rec
->d_place
== DNSResourceRecord::ANSWER
&& !haveAnswers
) {
2450 if (rec
->d_place
== DNSResourceRecord::ANSWER
) {
2451 allowAdditionalEntry(allowedAdditionals
, *rec
);
2454 /* dealing with the records in authority */
2455 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
) {
2456 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
);
2457 rec
= lwr
.d_records
.erase(rec
);
2461 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::SOA
) {
2462 if (!qname
.isPartOf(rec
->d_name
)) {
2463 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
);
2464 rec
= lwr
.d_records
.erase(rec
);
2468 if (!(lwr
.d_aabit
|| wasForwardRecurse
)) {
2469 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
);
2470 rec
= lwr
.d_records
.erase(rec
);
2475 if (lwr
.d_rcode
== RCode::NXDomain
) {
2478 else if (lwr
.d_rcode
== RCode::NoError
) {
2484 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::NS
&& (isNXDomain
|| isNXQType
)) {
2485 /* we don't want to pick up NS records in AUTHORITY or ADDITIONAL sections of NXDomain answers
2486 because they are somewhat easy to insert into a large, fragmented UDP response
2487 for an off-path attacker by injecting spoofed UDP fragments.
2489 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
);
2490 rec
= lwr
.d_records
.erase(rec
);
2494 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::NS
) {
2495 allowAdditionalEntry(allowedAdditionals
, *rec
);
2498 /* dealing with the records in additional */
2499 if (rec
->d_place
== DNSResourceRecord::ADDITIONAL
&& rec
->d_type
!= QType::A
&& rec
->d_type
!= QType::AAAA
&& rec
->d_type
!= QType::RRSIG
) {
2500 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
);
2501 rec
= lwr
.d_records
.erase(rec
);
2505 if (rec
->d_place
== DNSResourceRecord::ADDITIONAL
&& allowedAdditionals
.count(rec
->d_name
) == 0) {
2506 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
);
2507 rec
= lwr
.d_records
.erase(rec
);
2515 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
)
2517 bool wasForwardRecurse
= wasForwarded
&& rdQuery
;
2523 prefix
.append(depth
, ' ');
2526 sanitizeRecords(prefix
, lwr
, qname
, qtype
, auth
, wasForwarded
, rdQuery
);
2528 std::vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
2529 const unsigned int labelCount
= qname
.countLabels();
2530 bool isCNAMEAnswer
= false;
2531 bool isDNAMEAnswer
= false;
2532 for(const auto& rec
: lwr
.d_records
) {
2533 if (rec
.d_class
!= QClass::IN
) {
2537 if(!isCNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
&& !isDNAMEAnswer
) {
2538 isCNAMEAnswer
= true;
2540 if(!isDNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::DNAME
&& qtype
!= QType(QType::DNAME
) && qname
.isPartOf(rec
.d_name
)) {
2541 isDNAMEAnswer
= true;
2542 isCNAMEAnswer
= false;
2545 /* if we have a positive answer synthetized from a wildcard,
2546 we need to store the corresponding NSEC/NSEC3 records proving
2547 that the exact name did not exist in the negative cache */
2548 if(gatherWildcardProof
) {
2549 if (nsecTypes
.count(rec
.d_type
)) {
2550 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
2552 else if (rec
.d_type
== QType::RRSIG
) {
2553 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
2554 if (rrsig
&& nsecTypes
.count(rrsig
->d_type
)) {
2555 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
2559 if(rec
.d_type
== QType::RRSIG
) {
2560 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
2562 /* As illustrated in rfc4035's Appendix B.6, the RRSIG label
2563 count can be lower than the name's label count if it was
2564 synthetized from the wildcard. Note that the difference might
2566 if (rec
.d_name
== qname
&& isWildcardExpanded(labelCount
, rrsig
)) {
2567 gatherWildcardProof
= true;
2568 if (!isWildcardExpandedOntoItself(rec
.d_name
, labelCount
, rrsig
)) {
2569 /* if we have a wildcard expanded onto itself, we don't need to prove
2570 that the exact name doesn't exist because it actually does.
2571 We still want to gather the corresponding NSEC/NSEC3 records
2572 to pass them to our client in case it wants to validate by itself.
2574 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthetized from a wildcard, we need a wildcard proof"<<endl
);
2575 needWildcardProof
= true;
2578 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthetized from a wildcard expanded onto itself, we need to gather wildcard proof"<<endl
);
2580 wildcardLabelsCount
= rrsig
->d_labels
;
2583 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
2584 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
2585 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
);
2590 // reap all answers from this packet that are acceptable
2591 for(auto& rec
: lwr
.d_records
) {
2592 if(rec
.d_type
== QType::OPT
) {
2593 LOG(prefix
<<qname
<<": OPT answer '"<<rec
.d_name
<<"' from '"<<auth
<<"' nameservers" <<endl
);
2596 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
<<" ");
2597 if(rec
.d_type
== QType::ANY
) {
2598 LOG("NO! - we don't accept 'ANY'-typed data"<<endl
);
2602 if(rec
.d_class
!= QClass::IN
) {
2603 LOG("NO! - we don't accept records for any other class than 'IN'"<<endl
);
2607 if (!(lwr
.d_aabit
|| wasForwardRecurse
) && rec
.d_place
== DNSResourceRecord::ANSWER
) {
2608 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2609 are sending such responses */
2610 if (!(rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
)) {
2611 LOG("NO! - we don't accept records in the answers section without the AA bit set"<<endl
);
2616 if(rec
.d_name
.isPartOf(auth
)) {
2617 if(rec
.d_type
== QType::RRSIG
) {
2618 LOG("RRSIG - separate"<<endl
);
2620 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
)) {
2621 LOG("NO! Is from delegation-only zone"<<endl
);
2623 return RCode::NXDomain
;
2626 bool haveLogged
= false;
2627 if (isDNAMEAnswer
&& rec
.d_type
== QType::CNAME
) {
2628 LOG("NO - we already have a DNAME answer for this domain");
2631 if (!t_sstorage
.domainmap
->empty()) {
2632 // Check if we are authoritative for a zone in this answer
2633 DNSName
tmp_qname(rec
.d_name
);
2634 auto auth_domain_iter
=getBestAuthZone(&tmp_qname
);
2635 if(auth_domain_iter
!=t_sstorage
.domainmap
->end() &&
2636 auth
.countLabels() <= auth_domain_iter
->first
.countLabels()) {
2637 if (auth_domain_iter
->first
!= auth
) {
2638 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter
->first
<<endl
);
2641 LOG("YES! - This answer was ");
2642 if (!wasForwarded
) {
2643 LOG("retrieved from the local auth store.");
2645 LOG("received from a server we forward to.");
2656 rec
.d_ttl
=min(s_maxcachettl
, rec
.d_ttl
);
2659 dr
.d_ttl
+= d_now
.tv_sec
;
2660 dr
.d_place
=DNSResourceRecord::ANSWER
;
2661 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(dr
);
2669 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2670 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)
2671 uint32_t lowestTTD
=computeLowestTTD(i
->second
.records
, i
->second
.signatures
, i
->second
.signaturesTTL
);
2673 for(auto& record
: i
->second
.records
)
2674 record
.d_ttl
= lowestTTD
; // boom
2677 // cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
2678 // cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
2681 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2683 if(i
->second
.records
.empty()) // this happens when we did store signatures, but passed on the records themselves
2686 /* Even if the AA bit is set, additional data cannot be considered
2687 as authoritative. This is especially important during validation
2688 because keeping records in the additional section is allowed even
2689 if the corresponding RRSIGs are not included, without setting the TC
2690 bit, as stated in rfc4035's section 3.1.1. Including RRSIG RRs in a Response:
2691 "When placing a signed RRset in the Additional section, the name
2692 server MUST also place its RRSIG RRs in the Additional section.
2693 If space does not permit inclusion of both the RRset and its
2694 associated RRSIG RRs, the name server MAY retain the RRset while
2695 dropping the RRSIG RRs. If this happens, the name server MUST NOT
2696 set the TC bit solely because these RRSIG RRs didn't fit."
2698 bool isAA
= lwr
.d_aabit
&& i
->first
.place
!= DNSResourceRecord::ADDITIONAL
;
2699 /* if we forwarded the query to a recursor, we can expect the answer to be signed,
2700 even if the answer is not AA. Of course that's not only true inside a Secure
2701 zone, but we check that below. */
2702 bool expectSignature
= i
->first
.place
== DNSResourceRecord::ANSWER
|| ((lwr
.d_aabit
|| wasForwardRecurse
) && i
->first
.place
!= DNSResourceRecord::ADDITIONAL
);
2703 if (isCNAMEAnswer
&& (i
->first
.place
!= DNSResourceRecord::ANSWER
|| i
->first
.type
!= QType::CNAME
|| i
->first
.name
!= qname
)) {
2706 Note that the answer section of an authoritative answer normally
2707 contains only authoritative data. However when the name sought is an
2708 alias (see section 10.1.1) only the record describing that alias is
2709 necessarily authoritative. Clients should assume that other records
2710 may have come from the server's cache. Where authoritative answers
2711 are required, the client should query again, using the canonical name
2712 associated with the alias.
2715 expectSignature
= false;
2718 if (isCNAMEAnswer
&& i
->first
.place
== DNSResourceRecord::AUTHORITY
&& i
->first
.type
== QType::NS
&& auth
== i
->first
.name
) {
2719 /* These NS can't be authoritative since we have a CNAME answer for which (see above) only the
2720 record describing that alias is necessarily authoritative.
2721 But if we allow the current auth, which might be serving the child zone, to raise the TTL
2722 of non-authoritative NS in the cache, they might be able to keep a "ghost" zone alive forever,
2723 even after the delegation is gone from the parent.
2724 So let's just do nothing with them, we can fetch them directly if we need them.
2726 LOG(d_prefix
<<": skipping authority NS from '"<<auth
<<"' nameservers in CNAME answer "<<i
->first
.name
<<"|"<<DNSRecordContent::NumberToType(i
->first
.type
)<<endl
);
2730 vState recordState
= getValidationStatus(i
->first
.name
, false);
2731 LOG(d_prefix
<<": got initial zone status "<<vStates
[recordState
]<<" for record "<<i
->first
.name
<<"|"<<DNSRecordContent::NumberToType(i
->first
.type
)<<endl
);
2733 if (shouldValidate() && recordState
== Secure
) {
2734 vState initialState
= recordState
;
2736 if (expectSignature
) {
2737 if (i
->first
.place
!= DNSResourceRecord::ADDITIONAL
) {
2738 /* the additional entries can be insecure,
2740 "Glue address RRsets associated with delegations MUST NOT be signed"
2742 if (i
->first
.type
== QType::DNSKEY
&& i
->first
.place
== DNSResourceRecord::ANSWER
) {
2743 LOG(d_prefix
<<"Validating DNSKEY for "<<i
->first
.name
<<endl
);
2744 recordState
= validateDNSKeys(i
->first
.name
, i
->second
.records
, i
->second
.signatures
, depth
);
2748 * RFC 6672 section 5.3.1
2749 * In any response, a signed DNAME RR indicates a non-terminal
2750 * redirection of the query. There might or might not be a server-
2751 * synthesized CNAME in the answer section; if there is, the CNAME will
2752 * never be signed. For a DNSSEC validator, verification of the DNAME
2753 * RR and then that the CNAME was properly synthesized is sufficient
2756 * We do the synthesis check in processRecords, here we make sure we
2757 * don't validate the CNAME.
2759 if (!(isDNAMEAnswer
&& i
->first
.type
== QType::CNAME
)) {
2760 LOG(d_prefix
<<"Validating non-additional record for "<<i
->first
.name
<<endl
);
2761 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2762 /* 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 */
2763 if (qtype
== QType::NS
&& i
->second
.signatures
.empty() && recordState
== Bogus
&& haveExactValidationStatus(i
->first
.name
) && getValidationStatus(i
->first
.name
) == Indeterminate
) {
2764 recordState
= Indeterminate
;
2771 recordState
= Indeterminate
;
2773 /* in a non authoritative answer, we only care about the DS record (or lack of) */
2774 if ((i
->first
.type
== QType::DS
|| i
->first
.type
== QType::NSEC
|| i
->first
.type
== QType::NSEC3
) && i
->first
.place
== DNSResourceRecord::AUTHORITY
) {
2775 LOG(d_prefix
<<"Validating DS record for "<<i
->first
.name
<<endl
);
2776 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2780 if (initialState
== Secure
&& state
!= recordState
&& expectSignature
) {
2781 updateValidationState(state
, recordState
);
2785 if (shouldValidate()) {
2786 LOG(d_prefix
<<"Skipping validation because the current state is "<<vStates
[recordState
]<<endl
);
2790 if (recordState
== Bogus
) {
2791 /* this is a TTD by now, be careful */
2792 for(auto& record
: i
->second
.records
) {
2793 record
.d_ttl
= std::min(record
.d_ttl
, static_cast<uint32_t>(s_maxbogusttl
+ d_now
.tv_sec
));
2797 /* We don't need to store NSEC3 records in the positive cache because:
2798 - we don't allow direct NSEC3 queries
2799 - denial of existence proofs in wildcard expanded positive responses are stored in authorityRecs
2800 - denial of existence proofs for negative responses are stored in the negative cache
2801 We also don't want to cache non-authoritative data except for:
2802 - records coming from non forward-recurse servers (those will never be AA)
2804 - NS, A and AAAA (used for infra queries)
2806 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
)) {
2808 bool doCache
= true;
2809 if (i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
) {
2810 // If ednsmask is relevant, we do not want to cache if the scope prefix length is large and TTL is small
2811 if (SyncRes::s_ecscachelimitttl
> 0) {
2812 bool manyMaskBits
= (ednsmask
->isIPv4() && ednsmask
->getBits() > SyncRes::s_ecsipv4cachelimit
) ||
2813 (ednsmask
->isIPv6() && ednsmask
->getBits() > SyncRes::s_ecsipv6cachelimit
);
2816 uint32_t minttl
= UINT32_MAX
;
2817 for (const auto &it
: i
->second
.records
) {
2818 if (it
.d_ttl
< minttl
)
2821 bool ttlIsSmall
= minttl
< SyncRes::s_ecscachelimitttl
+ d_now
.tv_sec
;
2823 // Case: many bits and ttlIsSmall
2830 s_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
);
2834 if(i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
)
2838 return RCode::NoError
;
2841 void SyncRes::updateDenialValidationState(vState
& neValidationState
, const DNSName
& neName
, vState
& state
, const dState denialState
, const dState expectedState
, bool allowOptOut
)
2843 if (denialState
== expectedState
) {
2844 neValidationState
= Secure
;
2847 if (denialState
== OPTOUT
&& allowOptOut
) {
2848 LOG(d_prefix
<<"OPT-out denial found for "<<neName
<<endl
);
2850 "The AD bit, as defined by [RFC4035], MUST NOT be set when returning a
2851 response containing a closest (provable) encloser proof in which the
2852 NSEC3 RR that covers the "next closer" name has the Opt-Out bit set.
2854 This rule is based on what this closest encloser proof actually
2855 proves: names that would be covered by the Opt-Out NSEC3 RR may or
2856 may not exist as insecure delegations. As such, not all the data in
2857 responses containing such closest encloser proofs will have been
2858 cryptographically verified, so the AD bit cannot be set."
2860 At best the Opt-Out NSEC3 RR proves that there is no signed DS (so no
2863 neValidationState
= Insecure
;
2865 else if (denialState
== INSECURE
) {
2866 LOG(d_prefix
<<"Insecure denial found for "<<neName
<<", returning Insecure"<<endl
);
2867 neValidationState
= Insecure
;
2870 LOG(d_prefix
<<"Invalid denial found for "<<neName
<<", returning Bogus, res="<<denialState
<<", expectedState="<<expectedState
<<endl
);
2871 neValidationState
= Bogus
;
2873 updateValidationState(state
, neValidationState
);
2877 dState
SyncRes::getDenialValidationState(const NegCache::NegCacheEntry
& ne
, const vState state
, const dState expectedState
, bool referralToUnsigned
)
2879 cspmap_t csp
= harvestCSPFromNE(ne
);
2880 return getDenial(csp
, ne
.d_name
, ne
.d_qtype
.getCode(), referralToUnsigned
, expectedState
== NXQTYPE
);
2883 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
)
2886 DNSName dnameTarget
, dnameOwner
;
2887 uint32_t dnameTTL
= 0;
2889 for(auto& rec
: lwr
.d_records
) {
2890 if (rec
.d_type
!=QType::OPT
&& rec
.d_class
!=QClass::IN
)
2893 if (rec
.d_place
==DNSResourceRecord::ANSWER
&& !(lwr
.d_aabit
|| sendRDQuery
)) {
2894 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2895 are sending such responses */
2896 if (!(rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
)) {
2901 if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2902 lwr
.d_rcode
==RCode::NXDomain
&& qname
.isPartOf(rec
.d_name
) && rec
.d_name
.isPartOf(auth
)) {
2903 LOG(prefix
<<qname
<<": got negative caching indication for name '"<<qname
<<"' (accept="<<rec
.d_name
.isPartOf(auth
)<<"), newtarget='"<<newtarget
<<"'"<<endl
);
2905 rec
.d_ttl
= min(rec
.d_ttl
, s_maxnegttl
);
2906 if(newtarget
.empty()) // only add a SOA if we're not going anywhere after this
2909 NegCache::NegCacheEntry ne
;
2911 uint32_t lowestTTL
= rec
.d_ttl
;
2912 /* if we get an NXDomain answer with a CNAME, the name
2913 does exist but the target does not */
2914 ne
.d_name
= newtarget
.empty() ? qname
: newtarget
;
2915 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2916 ne
.d_auth
= rec
.d_name
;
2917 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2919 if (state
== Secure
) {
2920 dState denialState
= getDenialValidationState(ne
, state
, NXDOMAIN
, false);
2921 updateDenialValidationState(ne
.d_validationState
, ne
.d_name
, state
, denialState
, NXDOMAIN
, true);
2924 ne
.d_validationState
= state
;
2927 if (ne
.d_validationState
== Bogus
) {
2928 lowestTTL
= min(lowestTTL
, s_maxbogusttl
);
2931 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2932 /* if we get an NXDomain answer with a CNAME, let's not cache the
2933 target, even the server was authoritative for it,
2934 and do an additional query for the CNAME target.
2935 We have a regression test making sure we do exactly that.
2937 if(!wasVariable() && newtarget
.empty()) {
2938 t_sstorage
.negcache
.add(ne
);
2939 if(s_rootNXTrust
&& ne
.d_auth
.isRoot() && auth
.isRoot() && lwr
.d_aabit
) {
2940 ne
.d_name
= ne
.d_name
.getLastLabel();
2941 t_sstorage
.negcache
.add(ne
);
2947 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& s_redirectionQTypes
.count(rec
.d_type
) > 0 && // CNAME or DNAME answer
2948 s_redirectionQTypes
.count(qtype
.getCode()) == 0) { // But not in response to a CNAME or DNAME query
2949 if (rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
) {
2950 if (!dnameOwner
.empty()) { // We synthesize ourselves
2954 if (auto content
= getRR
<CNAMERecordContent
>(rec
)) {
2955 newtarget
=content
->getTarget();
2957 } else if (rec
.d_type
== QType::DNAME
&& qname
.isPartOf(rec
.d_name
)) { // DNAME
2959 if (auto content
= getRR
<DNAMERecordContent
>(rec
)) {
2960 dnameOwner
= rec
.d_name
;
2961 dnameTarget
= content
->getTarget();
2962 dnameTTL
= rec
.d_ttl
;
2963 if (!newtarget
.empty()) { // We had a CNAME before, remove it from ret so we don't cache it
2964 ret
.erase(std::remove_if(
2967 [&qname
](DNSRecord
& rr
) {
2968 return (rr
.d_place
== DNSResourceRecord::ANSWER
&& rr
.d_type
== QType::CNAME
&& rr
.d_name
== qname
);
2973 newtarget
= qname
.makeRelative(dnameOwner
) + dnameTarget
;
2974 } catch (const std::exception
&e
) {
2975 // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
2976 // But there is no way to set the RCODE from this function
2977 throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + dnameOwner
.toLogString() +
2978 "', DNAME target: '" + dnameTarget
.toLogString() + "', substituted name: '" +
2979 qname
.makeRelative(dnameOwner
).toLogString() + "." + dnameTarget
.toLogString() +
2985 /* if we have a positive answer synthetized from a wildcard, we need to
2986 return the corresponding NSEC/NSEC3 records from the AUTHORITY section
2987 proving that the exact name did not exist */
2988 else if(gatherWildcardProof
&& (rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::AUTHORITY
) {
2989 ret
.push_back(rec
); // enjoy your DNSSEC
2991 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
2992 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&&
2994 rec
.d_type
==qtype
.getCode() || ((lwr
.d_aabit
|| sendRDQuery
) && qtype
== QType(QType::ANY
))
2998 LOG(prefix
<<qname
<<": answer is in: resolved to '"<< rec
.d_content
->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"'"<<endl
);
3002 if (state
== Secure
&& needWildcardProof
) {
3003 /* We have a positive answer synthetized from a wildcard, we need to check that we have
3004 proof that the exact name doesn't exist so the wildcard can be used,
3005 as described in section 5.3.4 of RFC 4035 and 5.3 of RFC 7129.
3007 NegCache::NegCacheEntry ne
;
3009 uint32_t lowestTTL
= rec
.d_ttl
;
3011 ne
.d_qtype
= QType(0); // this encodes 'whole record'
3012 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
3014 cspmap_t csp
= harvestCSPFromNE(ne
);
3015 dState res
= getDenial(csp
, qname
, ne
.d_qtype
.getCode(), false, false, false, wildcardLabelsCount
);
3016 if (res
!= NXDOMAIN
) {
3018 if (res
== INSECURE
) {
3019 /* Some part could not be validated, for example a NSEC3 record with a too large number of iterations,
3020 this is not enough to warrant a Bogus, but go Insecure. */
3022 LOG(d_prefix
<<"Unable to validate denial in wildcard expanded positive response found for "<<qname
<<", returning Insecure, res="<<res
<<endl
);
3025 LOG(d_prefix
<<"Invalid denial in wildcard expanded positive response found for "<<qname
<<", returning Bogus, res="<<res
<<endl
);
3026 rec
.d_ttl
= std::min(rec
.d_ttl
, s_maxbogusttl
);
3029 updateValidationState(state
, st
);
3030 /* we already stored the record with a different validation status, let's fix it */
3031 updateValidationStatusInCache(qname
, qtype
, lwr
.d_aabit
, st
);
3036 else if((rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::ANSWER
) {
3037 if(rec
.d_type
!= QType::RRSIG
|| rec
.d_name
== qname
) {
3038 ret
.push_back(rec
); // enjoy your DNSSEC
3039 } else if(rec
.d_type
== QType::RRSIG
&& qname
.isPartOf(rec
.d_name
)) {
3040 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
3041 if (rrsig
!= nullptr && rrsig
->d_type
== QType::DNAME
) {
3046 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::NS
&& qname
.isPartOf(rec
.d_name
)) {
3047 if(moreSpecificThan(rec
.d_name
,auth
)) {
3049 LOG(prefix
<<qname
<<": got NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
3053 LOG(prefix
<<qname
<<": got upwards/level NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"', had '"<<auth
<<"'"<<endl
);
3055 if (auto content
= getRR
<NSRecordContent
>(rec
)) {
3056 nsset
.insert(content
->getNS());
3059 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::DS
&& qname
.isPartOf(rec
.d_name
)) {
3060 LOG(prefix
<<qname
<<": got DS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
3062 else if(realreferral
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& (rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && newauth
.isPartOf(auth
)) {
3063 /* we might have received a denial of the DS, let's check */
3064 if (state
== Secure
) {
3065 NegCache::NegCacheEntry ne
;
3067 ne
.d_name
= newauth
;
3068 ne
.d_qtype
= QType::DS
;
3069 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
3070 uint32_t lowestTTL
= rec
.d_ttl
;
3071 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
3073 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, true);
3075 if (denialState
== NXQTYPE
|| denialState
== OPTOUT
|| denialState
== INSECURE
) {
3076 ne
.d_ttd
= lowestTTL
+ d_now
.tv_sec
;
3077 ne
.d_validationState
= Secure
;
3078 if (denialState
== OPTOUT
) {
3079 ne
.d_validationState
= Insecure
;
3081 LOG(prefix
<<qname
<<": got negative indication of DS record for '"<<newauth
<<"'"<<endl
);
3083 if(!wasVariable()) {
3084 t_sstorage
.negcache
.add(ne
);
3087 if (qname
== newauth
&& qtype
== QType::DS
) {
3088 /* we are actually done! */
3095 else if(!done
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
3096 lwr
.d_rcode
==RCode::NoError
&& qname
.isPartOf(rec
.d_name
)) {
3097 LOG(prefix
<<qname
<<": got negative caching indication for '"<< qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
3099 if(!newtarget
.empty()) {
3100 LOG(prefix
<<qname
<<": Hang on! Got a redirect to '"<<newtarget
<<"' already"<<endl
);
3103 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
3105 NegCache::NegCacheEntry ne
;
3106 ne
.d_auth
= rec
.d_name
;
3107 uint32_t lowestTTL
= rec
.d_ttl
;
3110 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
3112 if (state
== Secure
) {
3113 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, false);
3114 updateDenialValidationState(ne
.d_validationState
, ne
.d_name
, state
, denialState
, NXQTYPE
, qtype
== QType::DS
);
3116 ne
.d_validationState
= state
;
3119 if (ne
.d_validationState
== Bogus
) {
3120 lowestTTL
= min(lowestTTL
, s_maxbogusttl
);
3121 rec
.d_ttl
= min(rec
.d_ttl
, s_maxbogusttl
);
3123 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
3125 if(!wasVariable()) {
3126 if(qtype
.getCode()) { // prevents us from blacking out a whole domain
3127 t_sstorage
.negcache
.add(ne
);
3137 if (!dnameTarget
.empty()) {
3138 // Synthesize a CNAME
3139 auto cnamerec
= DNSRecord();
3140 cnamerec
.d_name
= qname
;
3141 cnamerec
.d_type
= QType::CNAME
;
3142 cnamerec
.d_ttl
= dnameTTL
;
3143 cnamerec
.d_content
= std::make_shared
<CNAMERecordContent
>(CNAMERecordContent(newtarget
));
3144 ret
.push_back(cnamerec
);
3149 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
)
3151 bool chained
= false;
3152 int resolveret
= RCode::NoError
;
3156 if(d_outqueries
+ d_throttledqueries
> s_maxqperq
) {
3157 throw ImmediateServFailException("more than "+std::to_string(s_maxqperq
)+" (max-qperq) queries sent while resolving "+qname
.toLogString());
3160 if(s_maxtotusec
&& d_totUsec
> s_maxtotusec
) {
3161 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");
3165 LOG(prefix
<<qname
<<": using TCP with "<< remoteIP
.toStringWithPort() <<endl
);
3170 if(d_pdl
&& d_pdl
->preoutquery(remoteIP
, d_requestor
, qname
, qtype
, doTCP
, lwr
.d_records
, resolveret
)) {
3171 LOG(prefix
<<qname
<<": query handled by Lua"<<endl
);
3174 ednsmask
=getEDNSSubnetMask(qname
, remoteIP
);
3176 LOG(prefix
<<qname
<<": Adding EDNS Client Subnet Mask "<<ednsmask
->toString()<<" to query"<<endl
);
3179 resolveret
= asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, auth
, qtype
.getCode(),
3180 doTCP
, sendRDQuery
, &d_now
, ednsmask
, &lwr
, &chained
); // <- we go out on the wire!
3183 LOG(prefix
<<qname
<<": Received EDNS Client Subnet Mask "<<ednsmask
->toString()<<" on response"<<endl
);
3184 if (ednsmask
->getBits() > 0) {
3185 if (ednsmask
->isIPv4()) {
3186 ++SyncRes::s_ecsResponsesBySubnetSize4
.at(ednsmask
->getBits()-1);
3189 ++SyncRes::s_ecsResponsesBySubnetSize6
.at(ednsmask
->getBits()-1);
3195 /* preoutquery killed the query by setting dq.rcode to -3 */
3196 if(resolveret
==-3) {
3197 throw ImmediateServFailException("Query killed by policy");
3200 d_totUsec
+= lwr
.d_usec
;
3201 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
3203 bool dontThrottle
= false;
3205 auto dontThrottleNames
= g_dontThrottleNames
.getLocal();
3206 auto dontThrottleNetmasks
= g_dontThrottleNetmasks
.getLocal();
3207 dontThrottle
= dontThrottleNames
->check(nsName
) || dontThrottleNetmasks
->match(remoteIP
);
3210 if(resolveret
!= 1) {
3211 /* Error while resolving */
3212 if(resolveret
== 0) {
3215 LOG(prefix
<<qname
<<": timeout resolving after "<<lwr
.d_usec
/1000.0<<"msec "<< (doTCP
? "over TCP" : "")<<endl
);
3217 s_outgoingtimeouts
++;
3219 if(remoteIP
.sin4
.sin_family
== AF_INET
)
3220 s_outgoing4timeouts
++;
3222 s_outgoing6timeouts
++;
3225 t_timeouts
->push_back(remoteIP
);
3227 else if(resolveret
== -2) {
3228 /* OS resource limit reached */
3229 LOG(prefix
<<qname
<<": hit a local resource limit resolving"<< (doTCP
? " over TCP" : "")<<", probable error: "<<stringerror()<<endl
);
3230 g_stats
.resourceLimits
++;
3233 /* -1 means server unreachable */
3236 // XXX questionable use of errno
3237 LOG(prefix
<<qname
<<": error resolving from "<<remoteIP
.toString()<< (doTCP
? " over TCP" : "") <<", possible error: "<<stringerror()<< endl
);
3240 if(resolveret
!= -2 && !chained
&& !dontThrottle
) {
3241 // don't account for resource limits, they are our own fault
3242 // And don't throttle when the IP address is on the dontThrottleNetmasks list or the name is part of dontThrottleNames
3243 t_sstorage
.nsSpeeds
[nsName
.empty()? DNSName(remoteIP
.toStringWithPort()) : nsName
].submit(remoteIP
, 1000000, d_now
); // 1 sec
3245 // code below makes sure we don't filter COM or the root
3246 if (s_serverdownmaxfails
> 0 && (auth
!= g_rootdnsname
) && t_sstorage
.fails
.incr(remoteIP
, d_now
) >= s_serverdownmaxfails
) {
3247 LOG(prefix
<<qname
<<": Max fails reached resolving on "<< remoteIP
.toString() <<". Going full throttle for "<< s_serverdownthrottletime
<<" seconds" <<endl
);
3248 // mark server as down
3249 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0), s_serverdownthrottletime
, 10000);
3251 else if (resolveret
== -1) {
3252 // unreachable, 1 minute or 100 queries
3253 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 100);
3256 // timeout, 10 seconds or 5 queries
3257 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 10, 5);
3264 /* we got an answer */
3265 if(lwr
.d_rcode
==RCode::ServFail
|| lwr
.d_rcode
==RCode::Refused
) {
3266 LOG(prefix
<<qname
<<": "<<nsName
<<" ("<<remoteIP
.toString()<<") returned a "<< (lwr
.d_rcode
==RCode::ServFail
? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl
);
3267 if (!chained
&& !dontThrottle
) {
3268 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
3273 /* this server sent a valid answer, mark it backup up if it was down */
3274 if(s_serverdownmaxfails
> 0) {
3275 t_sstorage
.fails
.clear(remoteIP
);
3282 LOG(prefix
<<qname
<<": truncated bit set, over TCP?"<<endl
);
3283 if (!dontThrottle
) {
3284 /* let's treat that as a ServFail answer from this server */
3285 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
3289 LOG(prefix
<<qname
<<": truncated bit set, over UDP"<<endl
);
3297 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
)
3302 prefix
.append(depth
, ' ');
3306 for(auto& rec
: lwr
.d_records
) {
3307 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumTTL
);
3311 /* if the answer is ECS-specific, a minimum TTL is set for this kind of answers
3312 and it's higher than the global minimum TTL */
3313 if (ednsmask
&& s_minimumECSTTL
> 0 && (s_minimumTTL
== 0 || s_minimumECSTTL
> s_minimumTTL
)) {
3314 for(auto& rec
: lwr
.d_records
) {
3315 if (rec
.d_place
== DNSResourceRecord::ANSWER
) {
3316 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumECSTTL
);
3321 bool needWildcardProof
= false;
3322 bool gatherWildcardProof
= false;
3323 unsigned int wildcardLabelsCount
;
3324 *rcode
= updateCacheFromRecords(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, state
, needWildcardProof
, gatherWildcardProof
, wildcardLabelsCount
, sendRDQuery
);
3325 if (*rcode
!= RCode::NoError
) {
3329 LOG(prefix
<<qname
<<": determining status after receiving this packet"<<endl
);
3332 bool realreferral
=false, negindic
=false;
3336 bool done
= processRecords(prefix
, qname
, qtype
, auth
, lwr
, sendRDQuery
, ret
, nsset
, newtarget
, newauth
, realreferral
, negindic
, state
, needWildcardProof
, gatherWildcardProof
, wildcardLabelsCount
);
3339 LOG(prefix
<<qname
<<": status=got results, this level of recursion done"<<endl
);
3340 LOG(prefix
<<qname
<<": validation status is "<<vStates
[state
]<<endl
);
3341 *rcode
= RCode::NoError
;
3345 if(!newtarget
.empty()) {
3346 if(newtarget
== qname
) {
3347 LOG(prefix
<<qname
<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl
);
3348 *rcode
= RCode::ServFail
;
3353 LOG(prefix
<<qname
<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl
);
3354 *rcode
= RCode::ServFail
;
3358 if (qtype
== QType::DS
) {
3359 LOG(prefix
<<qname
<<": status=got a CNAME referral, but we are looking for a DS"<<endl
);
3362 addNXNSECS(ret
, lwr
.d_records
);
3364 *rcode
= RCode::NoError
;
3368 LOG(prefix
<<qname
<<": status=got a CNAME referral, starting over with "<<newtarget
<<endl
);
3370 set
<GetBestNSAnswer
> beenthere2
;
3371 vState cnameState
= Indeterminate
;
3372 *rcode
= doResolve(newtarget
, qtype
, ret
, depth
+ 1, beenthere2
, cnameState
);
3373 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
3374 updateValidationState(state
, cnameState
);
3379 if(lwr
.d_rcode
== RCode::NXDomain
) {
3380 LOG(prefix
<<qname
<<": status=NXDOMAIN, we are done "<<(negindic
? "(have negative SOA)" : "")<<endl
);
3383 addNXNSECS(ret
, lwr
.d_records
);
3385 *rcode
= RCode::NXDomain
;
3389 if(nsset
.empty() && !lwr
.d_rcode
&& (negindic
|| lwr
.d_aabit
|| sendRDQuery
)) {
3390 LOG(prefix
<<qname
<<": status=noerror, other types may exist, but we are done "<<(negindic
? "(have negative SOA) " : "")<<(lwr
.d_aabit
? "(have aa bit) " : "")<<endl
);
3392 if(state
== Secure
&& (lwr
.d_aabit
|| sendRDQuery
) && !negindic
) {
3393 updateValidationState(state
, Bogus
);
3397 addNXNSECS(ret
, lwr
.d_records
);
3399 *rcode
= RCode::NoError
;
3404 LOG(prefix
<<qname
<<": status=did not resolve, got "<<(unsigned int)nsset
.size()<<" NS, ");
3406 nameservers
.clear();
3407 for (auto const &nameserver
: nsset
) {
3408 if (d_wantsRPZ
&& (d_appliedPolicy
.d_type
== DNSFilterEngine::PolicyType::None
|| d_appliedPolicy
.d_kind
== DNSFilterEngine::PolicyKind::NoAction
)) {
3409 bool match
= dfe
.getProcessingPolicy(nameserver
, d_discardedPolicies
, d_appliedPolicy
);
3410 if (match
&& d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
3411 LOG("however "<<nameserver
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
3412 throw PolicyHitException();
3415 nameservers
.insert({nameserver
, {{}, false}});
3417 LOG("looping to them"<<endl
);
3418 *gotNewServers
= true;
3428 * -1 in case of no results
3431 int SyncRes::doResolveAt(NsSet
&nameservers
, DNSName auth
, bool flawedNSSet
, const DNSName
&qname
, const QType
&qtype
,
3432 vector
<DNSRecord
>&ret
,
3433 unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
, vState
& state
, StopAtDelegation
* stopAtDelegation
)
3435 auto luaconfsLocal
= g_luaconfs
.getLocal();
3439 prefix
.append(depth
, ' ');
3442 LOG(prefix
<<qname
<<": Cache consultations done, have "<<(unsigned int)nameservers
.size()<<" NS to contact");
3444 if (nameserversBlockedByRPZ(luaconfsLocal
->dfe
, nameservers
)) {
3446 throw PolicyHitException();
3451 for(;;) { // we may get more specific nameservers
3452 auto rnameservers
= shuffleInSpeedOrder(nameservers
, doLog() ? (prefix
+qname
.toString()+": ") : string() );
3454 for(auto tns
=rnameservers
.cbegin();;++tns
) {
3455 if(tns
==rnameservers
.cend()) {
3456 LOG(prefix
<<qname
<<": Failed to resolve via any of the "<<(unsigned int)rnameservers
.size()<<" offered NS at level '"<<auth
<<"'"<<endl
);
3457 if(!auth
.isRoot() && flawedNSSet
) {
3458 LOG(prefix
<<qname
<<": Ageing nameservers for level '"<<auth
<<"', next query might succeed"<<endl
);
3460 if(s_RC
->doAgeCache(d_now
.tv_sec
, auth
, QType::NS
, 10))
3461 g_stats
.nsSetInvalidations
++;
3466 bool cacheOnly
= false;
3467 // this line needs to identify the 'self-resolving' behaviour
3468 if(qname
== tns
->first
&& (qtype
.getCode() == QType::A
|| qtype
.getCode() == QType::AAAA
)) {
3469 /* we might have a glue entry in cache so let's try this NS
3470 but only if we have enough in the cache to know how to reach it */
3471 LOG(prefix
<<qname
<<": Using NS to resolve itself, but only using what we have in cache ("<<(1+tns
-rnameservers
.cbegin())<<"/"<<rnameservers
.size()<<")"<<endl
);
3475 typedef vector
<ComboAddress
> remoteIPs_t
;
3476 remoteIPs_t remoteIPs
;
3477 remoteIPs_t::const_iterator remoteIP
;
3478 bool pierceDontQuery
=false;
3479 bool sendRDQuery
=false;
3480 boost::optional
<Netmask
> ednsmask
;
3482 const bool wasForwarded
= tns
->first
.empty() && (!nameservers
[tns
->first
].first
.empty());
3483 int rcode
= RCode::NoError
;
3484 bool gotNewServers
= false;
3486 if(tns
->first
.empty() && !wasForwarded
) {
3487 LOG(prefix
<<qname
<<": Domain is out-of-band"<<endl
);
3488 /* setting state to indeterminate since validation is disabled for local auth zone,
3489 and Insecure would be misleading. */
3490 state
= Indeterminate
;
3491 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, lwr
.d_records
, depth
, lwr
.d_rcode
);
3495 /* we have received an answer, are we done ? */
3496 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, false, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
3500 if (gotNewServers
) {
3501 if (stopAtDelegation
&& *stopAtDelegation
== Stop
) {
3502 *stopAtDelegation
= Stopped
;
3509 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
3510 remoteIPs
= retrieveAddressesForNS(prefix
, qname
, tns
, depth
, beenthere
, rnameservers
, nameservers
, sendRDQuery
, pierceDontQuery
, flawedNSSet
, cacheOnly
);
3512 if(remoteIPs
.empty()) {
3513 LOG(prefix
<<qname
<<": Failed to get IP for NS "<<tns
->first
<<", trying next if available"<<endl
);
3518 bool hitPolicy
{false};
3519 LOG(prefix
<<qname
<<": Resolved '"<<auth
<<"' NS "<<tns
->first
<<" to: ");
3520 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
3521 if(remoteIP
!= remoteIPs
.cbegin()) {
3524 LOG(remoteIP
->toString());
3525 if(nameserverIPBlockedByRPZ(luaconfsLocal
->dfe
, *remoteIP
)) {
3530 if (hitPolicy
) { //implies d_wantsRPZ
3532 throw PolicyHitException();
3536 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
3537 LOG(prefix
<<qname
<<": Trying IP "<< remoteIP
->toStringWithPort() <<", asking '"<<qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
3539 if (throttledOrBlocked(prefix
, *remoteIP
, qname
, qtype
, pierceDontQuery
)) {
3543 bool truncated
= false;
3544 bool gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
3545 tns
->first
, *remoteIP
, false, &truncated
);
3546 if (gotAnswer
&& truncated
) {
3547 /* retry, over TCP this time */
3548 gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
3549 tns
->first
, *remoteIP
, true, &truncated
);
3556 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
);
3558 /* // for you IPv6 fanatics :-)
3559 if(remoteIP->sin4.sin_family==AF_INET6)
3562 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
3564 t_sstorage
.nsSpeeds
[tns
->first
.empty()? DNSName(remoteIP
->toStringWithPort()) : tns
->first
].submit(*remoteIP
, lwr
.d_usec
, d_now
);
3566 /* we have received an answer, are we done ? */
3567 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
3571 if (gotNewServers
) {
3572 if (stopAtDelegation
&& *stopAtDelegation
== Stop
) {
3573 *stopAtDelegation
= Stopped
;
3579 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100);
3582 if (gotNewServers
) {
3586 if(remoteIP
== remoteIPs
.cend()) // we tried all IP addresses, none worked
3595 void SyncRes::setQuerySource(const ComboAddress
& requestor
, boost::optional
<const EDNSSubnetOpts
&> incomingECS
)
3597 d_requestor
= requestor
;
3599 if (incomingECS
&& incomingECS
->source
.getBits() > 0) {
3600 d_cacheRemote
= incomingECS
->source
.getMaskedNetwork();
3601 uint8_t bits
= std::min(incomingECS
->source
.getBits(), (incomingECS
->source
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
3602 ComboAddress trunc
= incomingECS
->source
.getNetwork();
3603 trunc
.truncate(bits
);
3604 d_outgoingECSNetwork
= boost::optional
<Netmask
>(Netmask(trunc
, bits
));
3606 d_cacheRemote
= d_requestor
;
3607 if(!incomingECS
&& s_ednslocalsubnets
.match(d_requestor
)) {
3608 ComboAddress trunc
= d_requestor
;
3609 uint8_t bits
= d_requestor
.isIPv4() ? 32 : 128;
3610 bits
= std::min(bits
, (trunc
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
3611 trunc
.truncate(bits
);
3612 d_outgoingECSNetwork
= boost::optional
<Netmask
>(Netmask(trunc
, bits
));
3613 } else if (s_ecsScopeZero
.source
.getBits() > 0) {
3614 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0.
3615 But using an empty ECS in that case would mean inserting
3616 a non ECS-specific entry into the cache, preventing any further
3617 ECS-specific query to be sent.
3618 So instead we use the trick described in section 7.1.2:
3619 "The subsequent Recursive Resolver query to the Authoritative Nameserver
3620 will then either not include an ECS option or MAY optionally include
3621 its own address information, which is what the Authoritative
3622 Nameserver will almost certainly use to generate any Tailored
3623 Response in lieu of an option. This allows the answer to be handled
3624 by the same caching mechanism as other queries, with an explicit
3625 indicator of the applicable scope. Subsequent Stub Resolver queries
3626 for /0 can then be answered from this cached response.
3628 d_outgoingECSNetwork
= boost::optional
<Netmask
>(s_ecsScopeZero
.source
.getMaskedNetwork());
3629 d_cacheRemote
= s_ecsScopeZero
.source
.getNetwork();
3631 // ECS disabled because no scope-zero address could be derived.
3632 d_outgoingECSNetwork
= boost::none
;
3637 boost::optional
<Netmask
> SyncRes::getEDNSSubnetMask(const DNSName
& dn
, const ComboAddress
& rem
)
3639 if(d_outgoingECSNetwork
&& (s_ednsdomains
.check(dn
) || s_ednsremotesubnets
.match(rem
))) {
3640 return d_outgoingECSNetwork
;
3645 void SyncRes::parseEDNSSubnetWhitelist(const std::string
& wlist
)
3647 vector
<string
> parts
;
3648 stringtok(parts
, wlist
, ",; ");
3649 for(const auto& a
: parts
) {
3651 s_ednsremotesubnets
.addMask(Netmask(a
));
3654 s_ednsdomains
.add(DNSName(a
));
3659 void SyncRes::parseEDNSSubnetAddFor(const std::string
& subnetlist
)
3661 vector
<string
> parts
;
3662 stringtok(parts
, subnetlist
, ",; ");
3663 for(const auto& a
: parts
) {
3664 s_ednslocalsubnets
.addMask(a
);
3668 // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
3669 int directResolve(const DNSName
& qname
, const QType
& qtype
, int qclass
, vector
<DNSRecord
>& ret
)
3672 gettimeofday(&now
, 0);
3677 res
= sr
.beginResolve(qname
, QType(qtype
), qclass
, ret
);
3679 catch(const PDNSException
& e
) {
3680 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got pdns exception: "<<e
.reason
<<endl
;
3683 catch(const ImmediateServFailException
& e
) {
3684 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got ImmediateServFailException: "<<e
.reason
<<endl
;
3687 catch(const PolicyHitException
& e
) {
3688 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got a policy hit"<<endl
;
3691 catch(const std::exception
& e
) {
3692 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got STL error: "<<e
.what()<<endl
;
3696 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got an exception"<<endl
;
3703 int SyncRes::getRootNS(struct timeval now
, asyncresolve_t asyncCallback
) {
3705 sr
.setDoEDNS0(true);
3706 sr
.setUpdatingRootNS();
3707 sr
.setDoDNSSEC(g_dnssecmode
!= DNSSECMode::Off
);
3708 sr
.setDNSSECValidationRequested(g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
);
3709 sr
.setAsyncCallback(asyncCallback
);
3711 vector
<DNSRecord
> ret
;
3714 res
=sr
.beginResolve(g_rootdnsname
, QType(QType::NS
), 1, ret
);
3715 if (g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
) {
3716 auto state
= sr
.getValidationState();
3718 throw PDNSException("Got Bogus validation result for .|NS");
3722 catch(const PDNSException
& e
) {
3723 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
3725 catch(const ImmediateServFailException
& e
) {
3726 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
3728 catch(const PolicyHitException
& e
) {
3729 g_log
<<Logger::Error
<<"Failed to update . records, got a policy hit"<<endl
;
3732 catch(const std::exception
& e
) {
3733 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.what()<<endl
;
3736 g_log
<<Logger::Error
<<"Failed to update . records, got an exception"<<endl
;
3740 g_log
<<Logger::Notice
<<"Refreshed . records"<<endl
;
3743 g_log
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;