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 string msg
= "More than " + std::to_string(s_maxdepth
) + " (max-recursion-depth) levels of recursion needed while resolving " + qname
.toLogString();
787 LOG(prefix
<< qname
<< ": " << msg
<< endl
);
788 throw ImmediateServFailException(msg
);
792 // This is a difficult way of expressing "this is a normal query", i.e. not getRootNS.
793 if(!(d_updatingRootNS
&& qtype
.getCode()==QType::NS
&& qname
.isRoot())) {
794 if(d_cacheonly
) { // very limited OOB support
796 LOG(prefix
<<qname
<<": Recursion not requested for '"<<qname
<<"|"<<qtype
.getName()<<"', peeking at auth/forward zones"<<endl
);
797 DNSName
authname(qname
);
798 domainmap_t::const_iterator iter
=getBestAuthZone(&authname
);
799 if(iter
!= t_sstorage
.domainmap
->end()) {
800 if(iter
->second
.isAuth()) {
802 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, ret
, depth
, res
);
804 *fromCache
= d_wasOutOfBand
;
808 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
809 const ComboAddress remoteIP
= servers
.front();
810 LOG(prefix
<<qname
<<": forwarding query to hardcoded nameserver '"<< remoteIP
.toStringWithPort()<<"' for zone '"<<authname
<<"'"<<endl
);
812 boost::optional
<Netmask
> nm
;
813 bool chained
= false;
814 res
=asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, authname
, qtype
.getCode(), false, false, &d_now
, nm
, &lwr
, &chained
);
816 d_totUsec
+= lwr
.d_usec
;
817 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
821 // filter out the good stuff from lwr.result()
823 for(const auto& rec
: lwr
.d_records
) {
824 if(rec
.d_place
== DNSResourceRecord::ANSWER
)
830 return RCode::ServFail
;
836 DNSName
authname(qname
);
837 bool wasForwardedOrAuthZone
= false;
838 bool wasAuthZone
= false;
839 bool wasForwardRecurse
= false;
840 domainmap_t::const_iterator iter
= getBestAuthZone(&authname
);
841 if(iter
!= t_sstorage
.domainmap
->end()) {
842 const auto& domain
= iter
->second
;
843 wasForwardedOrAuthZone
= true;
845 if (domain
.isAuth()) {
847 } else if (domain
.shouldRecurse()) {
848 wasForwardRecurse
= true;
852 if(!d_skipCNAMECheck
&& doCNAMECacheCheck(qname
, qtype
, ret
, depth
, res
, state
, wasAuthZone
, wasForwardRecurse
)) { // will reroute us if needed
853 d_wasOutOfBand
= wasAuthZone
;
857 if(doCacheCheck(qname
, authname
, wasForwardedOrAuthZone
, wasAuthZone
, wasForwardRecurse
, qtype
, ret
, depth
, res
, state
)) {
859 d_wasOutOfBand
= wasAuthZone
;
869 LOG(prefix
<<qname
<<": No cache hit for '"<<qname
<<"|"<<qtype
.getName()<<"', trying to find an appropriate NS record"<<endl
);
871 DNSName
subdomain(qname
);
872 if(qtype
== QType::DS
) subdomain
.chopOff();
875 bool flawedNSSet
=false;
877 /* we use subdomain here instead of qname because for DS queries we only care about the state of the parent zone */
878 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
880 // the two retries allow getBestNSNamesFromCache&co to reprime the root
881 // hints, in case they ever go missing
882 for(int tries
=0;tries
<2 && nsset
.empty();++tries
) {
883 subdomain
=getBestNSNamesFromCache(subdomain
, qtype
, nsset
, &flawedNSSet
, depth
, beenthere
); // pass beenthere to both occasions
886 state
= getValidationStatus(qname
, false);
888 LOG(prefix
<<qname
<<": initial validation status for "<<qname
<<" is "<<vStates
[state
]<<endl
);
890 if(!(res
=doResolveAt(nsset
, subdomain
, flawedNSSet
, qname
, qtype
, ret
, depth
, beenthere
, state
, stopAtDelegation
)))
893 LOG(prefix
<<qname
<<": failed (res="<<res
<<")"<<endl
);
895 return res
<0 ? RCode::ServFail
: res
;
899 // for testing purposes
900 static bool ipv6First(const ComboAddress
& a
, const ComboAddress
& b
)
902 return !(a
.sin4
.sin_family
< a
.sin4
.sin_family
);
908 speedOrderCA(std::map
<ComboAddress
,float>& speeds
): d_speeds(speeds
) {}
909 bool operator()(const ComboAddress
& a
, const ComboAddress
& b
) const
911 return d_speeds
[a
] < d_speeds
[b
];
913 std::map
<ComboAddress
, float>& d_speeds
;
916 /** This function explicitly goes out for A or AAAA addresses
918 vector
<ComboAddress
> SyncRes::getAddrs(const DNSName
&qname
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, bool cacheOnly
)
920 typedef vector
<DNSRecord
> res_t
;
921 typedef vector
<ComboAddress
> ret_t
;
924 bool oldCacheOnly
= setCacheOnly(cacheOnly
);
925 bool oldRequireAuthData
= d_requireAuthData
;
926 bool oldValidationRequested
= d_DNSSECValidationRequested
;
927 d_requireAuthData
= false;
928 d_DNSSECValidationRequested
= false;
931 vState newState
= Indeterminate
;
933 // If IPv4 ever becomes second class, we should revisit this
934 if (doResolve(qname
, QType::A
, resv4
, depth
+1, beenthere
, newState
) == 0) { // this consults cache, OR goes out
935 for (auto const &i
: resv4
) {
936 if (i
.d_type
== QType::A
) {
937 if (auto rec
= getRR
<ARecordContent
>(i
)) {
938 ret
.push_back(rec
->getCA(53));
945 // We did not find IPv4 addresses, try to get IPv6 ones
946 newState
= Indeterminate
;
948 if (doResolve(qname
, QType::AAAA
, resv6
, depth
+1, beenthere
, newState
) == 0) { // this consults cache, OR goes out
949 for (const auto &i
: resv6
) {
950 if (i
.d_type
== QType::AAAA
) {
951 if (auto rec
= getRR
<AAAARecordContent
>(i
))
952 ret
.push_back(rec
->getCA(53));
957 // We have some IPv4 records, don't bother with going out to get IPv6, but do consult the cache
958 // Once IPv6 adoption matters, this needs to be revisited
960 if (s_RC
->get(d_now
.tv_sec
, qname
, QType(QType::AAAA
), false, &cset
, d_cacheRemote
) > 0) {
961 for (const auto &i
: cset
) {
962 if (i
.d_ttl
> (unsigned int)d_now
.tv_sec
) {
963 if (auto rec
= getRR
<AAAARecordContent
>(i
)) {
964 ret
.push_back(rec
->getCA(53));
972 catch (const PolicyHitException
& e
) {
973 /* we ignore a policy hit while trying to retrieve the addresses
974 of a NS and keep processing the current query */
977 d_requireAuthData
= oldRequireAuthData
;
978 d_DNSSECValidationRequested
= oldValidationRequested
;
979 setCacheOnly(oldCacheOnly
);
981 /* we need to remove from the nsSpeeds collection the existing IPs
982 for this nameserver that are no longer in the set, even if there
983 is only one or none at all in the current set.
985 map
<ComboAddress
, float> speeds
;
986 auto& collection
= t_sstorage
.nsSpeeds
[qname
];
987 float factor
= collection
.getFactor(d_now
);
988 for(const auto& val
: ret
) {
989 speeds
[val
] = collection
.d_collection
[val
].get(factor
);
992 t_sstorage
.nsSpeeds
[qname
].purge(speeds
);
995 random_shuffle(ret
.begin(), ret
.end());
996 speedOrderCA
so(speeds
);
997 stable_sort(ret
.begin(), ret
.end(), so
);
1000 string prefix
=d_prefix
;
1001 prefix
.append(depth
, ' ');
1002 LOG(prefix
<<"Nameserver "<<qname
<<" IPs: ");
1004 for(const auto& addr
: ret
) {
1011 LOG((addr
.toString())<<"(" << (boost::format("%0.2f") % (speeds
[addr
]/1000.0)).str() <<"ms)");
1020 void SyncRes::getBestNSFromCache(const DNSName
&qname
, const QType
& qtype
, vector
<DNSRecord
>& bestns
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
)
1023 DNSName
subdomain(qname
);
1026 prefix
.append(depth
, ' ');
1032 LOG(prefix
<<qname
<<": Checking if we have NS in cache for '"<<subdomain
<<"'"<<endl
);
1033 vector
<DNSRecord
> ns
;
1034 *flawedNSSet
= false;
1036 if(s_RC
->get(d_now
.tv_sec
, subdomain
, QType(QType::NS
), false, &ns
, d_cacheRemote
) > 0) {
1037 bestns
.reserve(ns
.size());
1039 for(auto k
=ns
.cbegin();k
!=ns
.cend(); ++k
) {
1040 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
1041 vector
<DNSRecord
> aset
;
1043 const DNSRecord
& dr
=*k
;
1044 auto nrr
= getRR
<NSRecordContent
>(dr
);
1045 if(nrr
&& (!nrr
->getNS().isPartOf(subdomain
) || s_RC
->get(d_now
.tv_sec
, nrr
->getNS(), s_doIPv6
? QType(QType::ADDR
) : QType(QType::A
),
1046 false, doLog() ? &aset
: 0, d_cacheRemote
) > 5)) {
1047 bestns
.push_back(dr
);
1048 LOG(prefix
<<qname
<<": NS (with ip, or non-glue) in cache for '"<<subdomain
<<"' -> '"<<nrr
->getNS()<<"'"<<endl
);
1049 LOG(prefix
<<qname
<<": within bailiwick: "<< nrr
->getNS().isPartOf(subdomain
));
1051 LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset
.begin()->d_ttl
- d_now
.tv_sec
))<<endl
);
1054 LOG(", not in cache / did not look at cache"<<endl
);
1059 LOG(prefix
<<qname
<<": NS in cache for '"<<subdomain
<<"', but needs glue ("<<nrr
->getNS()<<") which we miss or is expired"<<endl
);
1064 if(!bestns
.empty()) {
1065 GetBestNSAnswer answer
;
1067 answer
.qtype
=qtype
.getCode();
1068 for(const auto& dr
: bestns
) {
1069 if (auto nsContent
= getRR
<NSRecordContent
>(dr
)) {
1070 answer
.bestns
.insert(make_pair(dr
.d_name
, nsContent
->getNS()));
1074 auto insertionPair
= beenthere
.insert(std::move(answer
));
1075 if(!insertionPair
.second
) {
1077 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' but part of LOOP (already seen "<<answer
.qname
<<")! Trying less specific NS"<<endl
);
1080 for( set
<GetBestNSAnswer
>::const_iterator j
=beenthere
.begin();j
!=beenthere
.end();++j
) {
1081 bool neo
= (j
== insertionPair
.first
);
1082 LOG(prefix
<<qname
<<": beenthere"<<(neo
?"*":"")<<": "<<j
->qname
<<"|"<<DNSRecordContent::NumberToType(j
->qtype
)<<" ("<<(unsigned int)j
->bestns
.size()<<")"<<endl
);
1087 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' (flawedNSSet="<<*flawedNSSet
<<")"<<endl
);
1092 LOG(prefix
<<qname
<<": no valid/useful NS in cache for '"<<subdomain
<<"'"<<endl
);
1094 if(subdomain
.isRoot() && !brokeloop
) {
1095 // We lost the root NS records
1097 primeRootNSZones(g_dnssecmode
!= DNSSECMode::Off
);
1098 LOG(prefix
<<qname
<<": reprimed the root"<<endl
);
1099 /* let's prevent an infinite loop */
1100 if (!d_updatingRootNS
) {
1101 getRootNS(d_now
, d_asyncResolve
);
1104 } while(subdomain
.chopOff());
1107 SyncRes::domainmap_t::const_iterator
SyncRes::getBestAuthZone(DNSName
* qname
) const
1109 if (t_sstorage
.domainmap
->empty()) {
1110 return t_sstorage
.domainmap
->end();
1113 SyncRes::domainmap_t::const_iterator ret
;
1115 ret
=t_sstorage
.domainmap
->find(*qname
);
1116 if(ret
!=t_sstorage
.domainmap
->end())
1118 }while(qname
->chopOff());
1122 /** doesn't actually do the work, leaves that to getBestNSFromCache */
1123 DNSName
SyncRes::getBestNSNamesFromCache(const DNSName
&qname
, const QType
& qtype
, NsSet
& nsset
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
)
1125 DNSName
authdomain(qname
);
1127 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
1128 if(iter
!=t_sstorage
.domainmap
->end()) {
1129 if( iter
->second
.isAuth() )
1130 // this gets picked up in doResolveAt, the empty DNSName, combined with the
1131 // empty vector means 'we are auth for this zone'
1132 nsset
.insert({DNSName(), {{}, false}});
1134 // Again, picked up in doResolveAt. An empty DNSName, combined with a
1135 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
1136 // This is actually picked up in retrieveAddressesForNS called from doResolveAt.
1137 nsset
.insert({DNSName(), {iter
->second
.d_servers
, iter
->second
.shouldRecurse() }});
1142 DNSName
subdomain(qname
);
1143 vector
<DNSRecord
> bestns
;
1144 getBestNSFromCache(subdomain
, qtype
, bestns
, flawedNSSet
, depth
, beenthere
);
1146 for(auto k
=bestns
.cbegin() ; k
!= bestns
.cend(); ++k
) {
1147 // The actual resolver code will not even look at the ComboAddress or bool
1148 const auto nsContent
= getRR
<NSRecordContent
>(*k
);
1150 nsset
.insert({nsContent
->getNS(), {{}, false}});
1151 if(k
==bestns
.cbegin())
1152 subdomain
=k
->d_name
;
1158 void SyncRes::updateValidationStatusInCache(const DNSName
&qname
, const QType
& qt
, bool aa
, vState newState
) const
1160 if (newState
== Bogus
) {
1161 s_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qt
, d_cacheRemote
, aa
, newState
, s_maxbogusttl
+ d_now
.tv_sec
);
1164 s_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qt
, d_cacheRemote
, aa
, newState
, boost::none
);
1168 bool SyncRes::doCNAMECacheCheck(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>& ret
, unsigned int depth
, int &res
, vState
& state
, bool wasAuthZone
, bool wasForwardRecurse
)
1173 prefix
.append(depth
, ' ');
1176 if((depth
>9 && d_outqueries
>10 && d_throttledqueries
>5) || depth
> 15) {
1177 LOG(prefix
<<qname
<<": recursing (CNAME or other indirection) too deep, depth="<<depth
<<endl
);
1178 res
=RCode::ServFail
;
1182 vector
<DNSRecord
> cset
;
1183 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
1184 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1186 uint32_t capTTL
= std::numeric_limits
<uint32_t>::max();
1188 QType foundQT
= QType(0); // 0 == QTYPE::ENT
1190 LOG(prefix
<<qname
<<": Looking for CNAME cache hit of '"<<qname
<<"|CNAME"<<"'"<<endl
);
1191 /* we don't require auth data for forward-recurse lookups */
1192 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) {
1194 foundQT
= QType(QType::CNAME
);
1197 if (foundName
.empty() && qname
!= g_rootdnsname
) {
1198 // look for a DNAME cache hit
1199 auto labels
= qname
.getRawLabels();
1200 DNSName
dnameName(g_rootdnsname
);
1202 LOG(prefix
<<qname
<<": Looking for DNAME cache hit of '"<<qname
<<"|DNAME' or its ancestors"<<endl
);
1204 dnameName
.prependRawLabel(labels
.back());
1206 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
1209 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) {
1210 foundName
= dnameName
;
1211 foundQT
= QType(QType::DNAME
);
1214 } while(!labels
.empty());
1217 if (foundName
.empty()) {
1218 LOG(prefix
<<qname
<<": No CNAME or DNAME cache hit of '"<< qname
<<"' found"<<endl
);
1222 for(auto const &record
: cset
) {
1223 if (record
.d_class
!= QClass::IN
) {
1227 if(record
.d_ttl
> (unsigned int) d_now
.tv_sec
) {
1229 if (!wasAuthZone
&& shouldValidate() && (wasAuth
|| wasForwardRecurse
) && state
== Indeterminate
&& d_requireAuthData
) {
1230 /* This means we couldn't figure out the state when this entry was cached,
1231 most likely because we hadn't computed the zone cuts yet. */
1232 /* make sure they are computed before validating */
1233 DNSName
subdomain(foundName
);
1234 /* if we are retrieving a DS, we only care about the state of the parent zone */
1235 if(qtype
== QType::DS
)
1236 subdomain
.chopOff();
1238 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1240 vState recordState
= getValidationStatus(foundName
, false);
1241 if (recordState
== Secure
) {
1242 LOG(prefix
<<qname
<<": got Indeterminate state from the "<<foundQT
.getName()<<" cache, validating.."<<endl
);
1243 state
= SyncRes::validateRecordsWithSigs(depth
, foundName
, foundQT
, foundName
, cset
, signatures
);
1244 if (state
!= Indeterminate
) {
1245 LOG(prefix
<<qname
<<": got Indeterminate state from the CNAME cache, new validation result is "<<vStates
[state
]<<endl
);
1246 if (state
== Bogus
) {
1247 capTTL
= s_maxbogusttl
;
1249 updateValidationStatusInCache(foundName
, foundQT
, wasAuth
, state
);
1254 LOG(prefix
<<qname
<<": Found cache "<<foundQT
.getName()<<" hit for '"<< foundName
<< "|"<<foundQT
.getName()<<"' to '"<<record
.d_content
->getZoneRepresentation()<<"', validation state is "<<vStates
[state
]<<endl
);
1256 DNSRecord dr
= record
;
1257 dr
.d_ttl
-= d_now
.tv_sec
;
1258 dr
.d_ttl
= std::min(dr
.d_ttl
, capTTL
);
1259 const uint32_t ttl
= dr
.d_ttl
;
1260 ret
.reserve(ret
.size() + 2 + signatures
.size() + authorityRecs
.size());
1263 for(const auto& signature
: signatures
) {
1265 sigdr
.d_type
=QType::RRSIG
;
1266 sigdr
.d_name
=foundName
;
1268 sigdr
.d_content
=signature
;
1269 sigdr
.d_place
=DNSResourceRecord::ANSWER
;
1270 sigdr
.d_class
=QClass::IN
;
1271 ret
.push_back(sigdr
);
1274 for(const auto& rec
: authorityRecs
) {
1275 DNSRecord
authDR(*rec
);
1277 ret
.push_back(authDR
);
1281 if (foundQT
== QType::DNAME
) {
1282 if (qtype
== QType::DNAME
&& qname
== foundName
) { // client wanted the DNAME, no need to synthesize a CNAME
1286 // Synthesize a CNAME
1287 auto dnameRR
= getRR
<DNAMERecordContent
>(record
);
1288 if (dnameRR
== nullptr) {
1289 throw ImmediateServFailException("Unable to get record content for "+foundName
.toLogString()+"|DNAME cache entry");
1291 const auto& dnameSuffix
= dnameRR
->getTarget();
1292 DNSName targetPrefix
= qname
.makeRelative(foundName
);
1294 dr
.d_type
= QType::CNAME
;
1295 dr
.d_name
= targetPrefix
+ foundName
;
1296 newTarget
= targetPrefix
+ dnameSuffix
;
1297 dr
.d_content
= std::make_shared
<CNAMERecordContent
>(CNAMERecordContent(newTarget
));
1299 } catch (const std::exception
&e
) {
1300 // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
1301 // But this is consistent with processRecords
1302 throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + foundName
.toLogString() +
1303 "', DNAME target: '" + dnameSuffix
.toLogString() + "', substituted name: '" +
1304 targetPrefix
.toLogString() + "." + dnameSuffix
.toLogString() +
1308 LOG(prefix
<<qname
<<": Synthesized "<<dr
.d_name
<<"|CNAME "<<newTarget
<<endl
);
1311 if(qtype
== QType::CNAME
) { // perhaps they really wanted a CNAME!
1316 // We have a DNAME _or_ CNAME cache hit and the client wants something else than those two.
1317 // Let's find the answer!
1318 if (foundQT
== QType::CNAME
) {
1319 const auto cnameContent
= getRR
<CNAMERecordContent
>(record
);
1320 if (cnameContent
== nullptr) {
1321 throw ImmediateServFailException("Unable to get record content for "+foundName
.toLogString()+"|CNAME cache entry");
1323 newTarget
= cnameContent
->getTarget();
1326 set
<GetBestNSAnswer
>beenthere
;
1327 vState cnameState
= Indeterminate
;
1328 res
= doResolve(newTarget
, qtype
, ret
, depth
+1, beenthere
, cnameState
);
1329 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the DNAME/CNAME quest: "<<vStates
[cnameState
]<<endl
);
1330 updateValidationState(state
, cnameState
);
1335 throw ImmediateServFailException("Could not determine whether or not there was a CNAME or DNAME in cache for '" + qname
.toLogString() + "'");
1341 vector
<DNSRecord
> records
;
1342 vector
<shared_ptr
<RRSIGRecordContent
>> signatures
;
1343 uint32_t signaturesTTL
{std::numeric_limits
<uint32_t>::max()};
1349 DNSResourceRecord::Place place
;
1350 bool operator<(const CacheKey
& rhs
) const {
1351 return tie(type
, place
, name
) < tie(rhs
.type
, rhs
.place
, rhs
.name
);
1354 typedef map
<CacheKey
, CacheEntry
> tcache_t
;
1357 static void reapRecordsFromNegCacheEntryForValidation(tcache_t
& tcache
, const vector
<DNSRecord
>& records
)
1359 for (const auto& rec
: records
) {
1360 if (rec
.d_type
== QType::RRSIG
) {
1361 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1363 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
1366 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(rec
);
1372 * Convenience function to push the records from records into ret with a new TTL
1374 * \param records DNSRecords that need to go into ret
1375 * \param ttl The new TTL for these records
1376 * \param ret The vector of DNSRecords that should contain the records with the modified TTL
1378 static void addTTLModifiedRecords(const vector
<DNSRecord
>& records
, const uint32_t ttl
, vector
<DNSRecord
>& ret
) {
1379 for (const auto& rec
: records
) {
1386 void SyncRes::computeNegCacheValidationStatus(const NegCache::NegCacheEntry
* ne
, const DNSName
& qname
, const QType
& qtype
, const int res
, vState
& state
, unsigned int depth
)
1388 DNSName
subdomain(qname
);
1389 /* if we are retrieving a DS, we only care about the state of the parent zone */
1390 if(qtype
== QType::DS
)
1391 subdomain
.chopOff();
1393 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1396 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->authoritySOA
.records
);
1397 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->authoritySOA
.signatures
);
1398 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->DNSSECRecords
.records
);
1399 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->DNSSECRecords
.signatures
);
1401 for (const auto& entry
: tcache
) {
1402 // this happens when we did store signatures, but passed on the records themselves
1403 if (entry
.second
.records
.empty()) {
1407 const DNSName
& owner
= entry
.first
.name
;
1409 vState recordState
= getValidationStatus(owner
, false);
1410 if (state
== Indeterminate
) {
1411 state
= recordState
;
1414 if (recordState
== Secure
) {
1415 recordState
= SyncRes::validateRecordsWithSigs(depth
, qname
, qtype
, owner
, entry
.second
.records
, entry
.second
.signatures
);
1418 if (recordState
!= Indeterminate
&& recordState
!= state
) {
1419 updateValidationState(state
, recordState
);
1420 if (state
!= Secure
) {
1426 if (state
== Secure
) {
1427 vState neValidationState
= ne
->d_validationState
;
1428 dState expectedState
= res
== RCode::NXDomain
? NXDOMAIN
: NXQTYPE
;
1429 dState denialState
= getDenialValidationState(*ne
, state
, expectedState
, false);
1430 updateDenialValidationState(neValidationState
, ne
->d_name
, state
, denialState
, expectedState
, qtype
== QType::DS
|| expectedState
== NXDOMAIN
);
1432 if (state
!= Indeterminate
) {
1433 /* validation succeeded, let's update the cache entry so we don't have to validate again */
1434 boost::optional
<uint32_t> capTTD
= boost::none
;
1435 if (state
== Bogus
) {
1436 capTTD
= d_now
.tv_sec
+ s_maxbogusttl
;
1438 t_sstorage
.negcache
.updateValidationStatus(ne
->d_name
, ne
->d_qtype
, state
, capTTD
);
1442 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
)
1444 bool giveNegative
=false;
1449 prefix
.append(depth
, ' ');
1452 // sqname and sqtype are used contain 'higher' names if we have them (e.g. powerdns.com|SOA when we find a negative entry for doesnotexist.powerdns.com|A)
1453 DNSName
sqname(qname
);
1456 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
1458 const NegCache::NegCacheEntry
* ne
= nullptr;
1461 t_sstorage
.negcache
.getRootNXTrust(qname
, d_now
, &ne
) &&
1462 ne
->d_auth
.isRoot() &&
1463 !(wasForwardedOrAuthZone
&& !authname
.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
1464 sttl
= ne
->d_ttd
- d_now
.tv_sec
;
1465 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
->d_auth
<<"' & '"<<ne
->d_name
<<"' for another "<<sttl
<<" seconds"<<endl
);
1466 res
= RCode::NXDomain
;
1467 giveNegative
= true;
1468 cachedState
= ne
->d_validationState
;
1469 } else if (t_sstorage
.negcache
.get(qname
, qtype
, d_now
, &ne
)) {
1470 /* If we are looking for a DS, discard NXD if auth == qname
1471 and ask for a specific denial instead */
1472 if (qtype
!= QType::DS
|| ne
->d_qtype
.getCode() || ne
->d_auth
!= qname
||
1473 t_sstorage
.negcache
.get(qname
, qtype
, d_now
, &ne
, true))
1475 res
= RCode::NXDomain
;
1476 sttl
= ne
->d_ttd
- d_now
.tv_sec
;
1477 giveNegative
= true;
1478 cachedState
= ne
->d_validationState
;
1479 if (ne
->d_qtype
.getCode()) {
1480 LOG(prefix
<<qname
<<": "<<qtype
.getName()<<" is negatively cached via '"<<ne
->d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1481 res
= RCode::NoError
;
1483 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<" is negatively cached via '"<<ne
->d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1486 } else if (s_hardenNXD
!= HardenNXD::No
&& !qname
.isRoot() && !wasForwardedOrAuthZone
) {
1487 auto labels
= qname
.getRawLabels();
1488 DNSName
negCacheName(g_rootdnsname
);
1489 negCacheName
.prependRawLabel(labels
.back());
1491 while(!labels
.empty()) {
1492 if (t_sstorage
.negcache
.get(negCacheName
, QType(0), d_now
, &ne
, true)) {
1493 if (ne
->d_validationState
== Indeterminate
&& validationEnabled()) {
1494 // LOG(prefix << negCacheName << " negatively cached and Indeterminate, trying to validate NXDOMAIN" << endl);
1496 // And get the updated ne struct
1497 //t_sstorage.negcache.get(negCacheName, QType(0), d_now, &ne, true);
1499 if ((s_hardenNXD
== HardenNXD::Yes
&& ne
->d_validationState
!= Bogus
) || ne
->d_validationState
== Secure
) {
1500 res
= RCode::NXDomain
;
1501 sttl
= ne
->d_ttd
- d_now
.tv_sec
;
1502 giveNegative
= true;
1503 cachedState
= ne
->d_validationState
;
1504 LOG(prefix
<<qname
<<": Name '"<<negCacheName
<<"' and below, is negatively cached via '"<<ne
->d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1508 negCacheName
.prependRawLabel(labels
.back());
1515 state
= cachedState
;
1517 if (!wasAuthZone
&& shouldValidate() && state
== Indeterminate
) {
1518 LOG(prefix
<<qname
<<": got Indeterminate state for records retrieved from the negative cache, validating.."<<endl
);
1519 computeNegCacheValidationStatus(ne
, qname
, qtype
, res
, state
, depth
);
1521 if (state
!= cachedState
&& state
== Bogus
) {
1522 sttl
= std::min(sttl
, s_maxbogusttl
);
1526 // Transplant SOA to the returned packet
1527 addTTLModifiedRecords(ne
->authoritySOA
.records
, sttl
, ret
);
1529 addTTLModifiedRecords(ne
->authoritySOA
.signatures
, sttl
, ret
);
1530 addTTLModifiedRecords(ne
->DNSSECRecords
.records
, sttl
, ret
);
1531 addTTLModifiedRecords(ne
->DNSSECRecords
.signatures
, sttl
, ret
);
1534 LOG(prefix
<<qname
<<": updating validation state with negative cache content for "<<qname
<<" to "<<vStates
[state
]<<endl
);
1538 vector
<DNSRecord
> cset
;
1539 bool found
=false, expired
=false;
1540 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
1541 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1543 uint32_t capTTL
= std::numeric_limits
<uint32_t>::max();
1545 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) {
1547 LOG(prefix
<<sqname
<<": Found cache hit for "<<sqt
.getName()<<": ");
1549 if (!wasAuthZone
&& shouldValidate() && (wasCachedAuth
|| wasForwardRecurse
) && cachedState
== Indeterminate
&& d_requireAuthData
) {
1551 /* This means we couldn't figure out the state when this entry was cached,
1552 most likely because we hadn't computed the zone cuts yet. */
1553 /* make sure they are computed before validating */
1554 DNSName
subdomain(sqname
);
1555 /* if we are retrieving a DS, we only care about the state of the parent zone */
1556 if(qtype
== QType::DS
)
1557 subdomain
.chopOff();
1559 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1561 vState recordState
= getValidationStatus(qname
, false);
1562 if (recordState
== Secure
) {
1563 LOG(prefix
<<sqname
<<": got Indeterminate state from the cache, validating.."<<endl
);
1564 cachedState
= SyncRes::validateRecordsWithSigs(depth
, sqname
, sqt
, sqname
, cset
, signatures
);
1567 cachedState
= recordState
;
1570 if (cachedState
!= Indeterminate
) {
1571 LOG(prefix
<<qname
<<": got Indeterminate state from the cache, validation result is "<<vStates
[cachedState
]<<endl
);
1572 if (cachedState
== Bogus
) {
1573 capTTL
= s_maxbogusttl
;
1575 updateValidationStatusInCache(sqname
, sqt
, wasCachedAuth
, cachedState
);
1579 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
1581 LOG(j
->d_content
->getZoneRepresentation());
1583 if (j
->d_class
!= QClass::IN
) {
1587 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
1589 dr
.d_ttl
-= d_now
.tv_sec
;
1590 dr
.d_ttl
= std::min(dr
.d_ttl
, capTTL
);
1593 LOG("[ttl="<<dr
.d_ttl
<<"] ");
1602 ret
.reserve(ret
.size() + signatures
.size() + authorityRecs
.size());
1604 for(const auto& signature
: signatures
) {
1606 dr
.d_type
=QType::RRSIG
;
1609 dr
.d_content
=signature
;
1610 dr
.d_place
= DNSResourceRecord::ANSWER
;
1611 dr
.d_class
=QClass::IN
;
1615 for(const auto& rec
: authorityRecs
) {
1622 if(found
&& !expired
) {
1625 LOG(prefix
<<qname
<<": updating validation state with cache content for "<<qname
<<" to "<<vStates
[cachedState
]<<endl
);
1626 state
= cachedState
;
1630 LOG(prefix
<<qname
<<": cache had only stale entries"<<endl
);
1636 bool SyncRes::moreSpecificThan(const DNSName
& a
, const DNSName
&b
) const
1638 return (a
.isPartOf(b
) && a
.countLabels() > b
.countLabels());
1643 bool operator()(const std::pair
<DNSName
, float> &a
, const std::pair
<DNSName
, float> &b
) const
1645 return a
.second
< b
.second
;
1649 inline std::vector
<std::pair
<DNSName
, float>> SyncRes::shuffleInSpeedOrder(NsSet
&tnameservers
, const string
&prefix
)
1651 std::vector
<std::pair
<DNSName
, float>> rnameservers
;
1652 rnameservers
.reserve(tnameservers
.size());
1653 for(const auto& tns
: tnameservers
) {
1654 float speed
= t_sstorage
.nsSpeeds
[tns
.first
].get(d_now
);
1655 rnameservers
.push_back({tns
.first
, speed
});
1656 if(tns
.first
.empty()) // this was an authoritative OOB zone, don't pollute the nsSpeeds with that
1657 return rnameservers
;
1660 random_shuffle(rnameservers
.begin(),rnameservers
.end());
1662 stable_sort(rnameservers
.begin(),rnameservers
.end(), so
);
1665 LOG(prefix
<<"Nameservers: ");
1666 for(auto i
=rnameservers
.begin();i
!=rnameservers
.end();++i
) {
1667 if(i
!=rnameservers
.begin()) {
1669 if(!((i
-rnameservers
.begin())%3)) {
1670 LOG(endl
<<prefix
<<" ");
1673 LOG(i
->first
.toLogString()<<"(" << (boost::format("%0.2f") % (i
->second
/1000.0)).str() <<"ms)");
1677 return rnameservers
;
1680 inline vector
<ComboAddress
> SyncRes::shuffleForwardSpeed(const vector
<ComboAddress
> &rnameservers
, const string
&prefix
, const bool wasRd
)
1682 vector
<ComboAddress
> nameservers
= rnameservers
;
1683 map
<ComboAddress
, float> speeds
;
1685 for(const auto& val
: nameservers
) {
1687 DNSName nsName
= DNSName(val
.toStringWithPort());
1688 speed
=t_sstorage
.nsSpeeds
[nsName
].get(d_now
);
1691 random_shuffle(nameservers
.begin(),nameservers
.end());
1692 speedOrderCA
so(speeds
);
1693 stable_sort(nameservers
.begin(),nameservers
.end(), so
);
1696 LOG(prefix
<<"Nameservers: ");
1697 for(vector
<ComboAddress
>::const_iterator i
=nameservers
.cbegin();i
!=nameservers
.cend();++i
) {
1698 if(i
!=nameservers
.cbegin()) {
1700 if(!((i
-nameservers
.cbegin())%3)) {
1701 LOG(endl
<<prefix
<<" ");
1704 LOG((wasRd
? string("+") : string("-")) << i
->toStringWithPort() <<"(" << (boost::format("%0.2f") % (speeds
[*i
]/1000.0)).str() <<"ms)");
1711 static uint32_t getRRSIGTTL(const time_t now
, const std::shared_ptr
<RRSIGRecordContent
>& rrsig
)
1714 if (now
< rrsig
->d_sigexpire
) {
1715 res
= static_cast<uint32_t>(rrsig
->d_sigexpire
) - now
;
1720 static const set
<uint16_t> nsecTypes
= {QType::NSEC
, QType::NSEC3
};
1722 /* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
1724 * \param records The records to parse for the authority SOA and NSEC(3) records
1725 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
1727 static void harvestNXRecords(const vector
<DNSRecord
>& records
, NegCache::NegCacheEntry
& ne
, const time_t now
, uint32_t* lowestTTL
) {
1728 for(const auto& rec
: records
) {
1729 if(rec
.d_place
!= DNSResourceRecord::AUTHORITY
)
1730 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
1731 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
1732 // records MUST be in the same section as the records they cover.
1733 // Hence, we ignore all records outside of the AUTHORITY section.
1736 if(rec
.d_type
== QType::RRSIG
) {
1737 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1739 if(rrsig
->d_type
== QType::SOA
) {
1740 ne
.authoritySOA
.signatures
.push_back(rec
);
1741 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1742 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1743 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1746 if(nsecTypes
.count(rrsig
->d_type
)) {
1747 ne
.DNSSECRecords
.signatures
.push_back(rec
);
1748 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1749 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1750 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1756 if(rec
.d_type
== QType::SOA
) {
1757 ne
.authoritySOA
.records
.push_back(rec
);
1759 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1763 if(nsecTypes
.count(rec
.d_type
)) {
1764 ne
.DNSSECRecords
.records
.push_back(rec
);
1766 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1773 static cspmap_t
harvestCSPFromNE(const NegCache::NegCacheEntry
& ne
)
1776 for(const auto& rec
: ne
.DNSSECRecords
.signatures
) {
1777 if(rec
.d_type
== QType::RRSIG
) {
1778 auto rrc
= getRR
<RRSIGRecordContent
>(rec
);
1780 cspmap
[{rec
.d_name
,rrc
->d_type
}].signatures
.push_back(rrc
);
1784 for(const auto& rec
: ne
.DNSSECRecords
.records
) {
1785 cspmap
[{rec
.d_name
, rec
.d_type
}].records
.insert(rec
.d_content
);
1790 // TODO remove after processRecords is fixed!
1791 // Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
1792 static void addNXNSECS(vector
<DNSRecord
>&ret
, const vector
<DNSRecord
>& records
)
1794 NegCache::NegCacheEntry ne
;
1795 harvestNXRecords(records
, ne
, 0, nullptr);
1796 ret
.insert(ret
.end(), ne
.authoritySOA
.signatures
.begin(), ne
.authoritySOA
.signatures
.end());
1797 ret
.insert(ret
.end(), ne
.DNSSECRecords
.records
.begin(), ne
.DNSSECRecords
.records
.end());
1798 ret
.insert(ret
.end(), ne
.DNSSECRecords
.signatures
.begin(), ne
.DNSSECRecords
.signatures
.end());
1801 bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine
& dfe
, const NsSet
& nameservers
)
1803 /* we skip RPZ processing if:
1804 - it was disabled (d_wantsRPZ is false) ;
1805 - we already got a RPZ hit (d_appliedPolicy.d_type != DNSFilterEngine::PolicyType::None) since
1806 the only way we can get back here is that it was a 'pass-thru' (NoAction) meaning that we should not
1807 process any further RPZ rules.
1809 if (d_wantsRPZ
&& (d_appliedPolicy
.d_type
== DNSFilterEngine::PolicyType::None
|| d_appliedPolicy
.d_kind
== DNSFilterEngine::PolicyKind::NoAction
)) {
1810 for (auto const &ns
: nameservers
) {
1811 bool match
= dfe
.getProcessingPolicy(ns
.first
, d_discardedPolicies
, d_appliedPolicy
);
1813 mergePolicyTags(d_policyTags
, d_appliedPolicy
.getTags());
1814 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1815 LOG(", however nameserver "<<ns
.first
<<" was blocked by RPZ policy '"<<d_appliedPolicy
.getName()<<"'"<<endl
);
1820 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1821 for (auto const &address
: ns
.second
.first
) {
1822 match
= dfe
.getProcessingPolicy(address
, d_discardedPolicies
, d_appliedPolicy
);
1824 mergePolicyTags(d_policyTags
, d_appliedPolicy
.getTags());
1825 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1826 LOG(", however nameserver "<<ns
.first
<<" IP address "<<address
.toString()<<" was blocked by RPZ policy '"<<d_appliedPolicy
.getName()<<"'"<<endl
);
1836 bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine
& dfe
, const ComboAddress
& remoteIP
)
1838 /* we skip RPZ processing if:
1839 - it was disabled (d_wantsRPZ is false) ;
1840 - we already got a RPZ hit (d_appliedPolicy.d_type != DNSFilterEngine::PolicyType::None) since
1841 the only way we can get back here is that it was a 'pass-thru' (NoAction) meaning that we should not
1842 process any further RPZ rules.
1844 if (d_wantsRPZ
&& (d_appliedPolicy
.d_type
== DNSFilterEngine::PolicyType::None
|| d_appliedPolicy
.d_kind
== DNSFilterEngine::PolicyKind::NoAction
)) {
1845 bool match
= dfe
.getProcessingPolicy(remoteIP
, d_discardedPolicies
, d_appliedPolicy
);
1847 mergePolicyTags(d_policyTags
, d_appliedPolicy
.getTags());
1848 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) {
1849 LOG(" (blocked by RPZ policy '" + d_appliedPolicy
.getName() + "')");
1857 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
)
1859 vector
<ComboAddress
> result
;
1861 if(!tns
->first
.empty()) {
1862 LOG(prefix
<<qname
<<": Trying to resolve NS '"<<tns
->first
<< "' ("<<1+tns
-rnameservers
.begin()<<"/"<<(unsigned int)rnameservers
.size()<<")"<<endl
);
1863 result
= getAddrs(tns
->first
, depth
+2, beenthere
, cacheOnly
);
1864 pierceDontQuery
=false;
1867 LOG(prefix
<<qname
<<": Domain has hardcoded nameserver");
1869 if(nameservers
[tns
->first
].first
.size() > 1) {
1874 sendRDQuery
= nameservers
[tns
->first
].second
;
1875 result
= shuffleForwardSpeed(nameservers
[tns
->first
].first
, doLog() ? (prefix
+qname
.toString()+": ") : string(), sendRDQuery
);
1876 pierceDontQuery
=true;
1881 bool SyncRes::throttledOrBlocked(const std::string
& prefix
, const ComboAddress
& remoteIP
, const DNSName
& qname
, const QType
& qtype
, bool pierceDontQuery
)
1883 if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0))) {
1884 LOG(prefix
<<qname
<<": server throttled "<<endl
);
1885 s_throttledqueries
++; d_throttledqueries
++;
1888 else if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()))) {
1889 LOG(prefix
<<qname
<<": query throttled "<<remoteIP
.toString()<<", "<<qname
<<"; "<<qtype
.getName()<<endl
);
1890 s_throttledqueries
++; d_throttledqueries
++;
1893 else if(!pierceDontQuery
&& s_dontQuery
&& s_dontQuery
->match(&remoteIP
)) {
1894 LOG(prefix
<<qname
<<": not sending query to " << remoteIP
.toString() << ", blocked by 'dont-query' setting" << endl
);
1901 bool SyncRes::validationEnabled() const
1903 return g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
;
1906 uint32_t SyncRes::computeLowestTTD(const std::vector
<DNSRecord
>& records
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, uint32_t signaturesTTL
) const
1908 uint32_t lowestTTD
= std::numeric_limits
<uint32_t>::max();
1909 for(const auto& record
: records
)
1910 lowestTTD
= min(lowestTTD
, record
.d_ttl
);
1912 /* even if it was not requested for that request (Process, and neither AD nor DO set),
1913 it might be requested at a later time so we need to be careful with the TTL. */
1914 if (validationEnabled() && !signatures
.empty()) {
1915 /* if we are validating, we don't want to cache records after their signatures expire. */
1916 /* records TTL are now TTD, let's add 'now' to the signatures lowest TTL */
1917 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(signaturesTTL
+ d_now
.tv_sec
));
1919 for(const auto& sig
: signatures
) {
1920 if (isRRSIGNotExpired(d_now
.tv_sec
, sig
)) {
1921 // we don't decerement d_sigexpire by 'now' because we actually want a TTD, not a TTL */
1922 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(sig
->d_sigexpire
));
1930 void SyncRes::updateValidationState(vState
& state
, const vState stateUpdate
)
1932 LOG(d_prefix
<<"validation state was "<<std::string(vStates
[state
])<<", state update is "<<std::string(vStates
[stateUpdate
]));
1934 if (stateUpdate
== TA
) {
1937 else if (stateUpdate
== NTA
) {
1940 else if (stateUpdate
== Bogus
) {
1943 else if (state
== Indeterminate
) {
1944 state
= stateUpdate
;
1946 else if (stateUpdate
== Insecure
) {
1947 if (state
!= Bogus
) {
1951 LOG(", validation state is now "<<std::string(vStates
[state
])<<endl
);
1954 vState
SyncRes::getTA(const DNSName
& zone
, dsmap_t
& ds
)
1956 auto luaLocal
= g_luaconfs
.getLocal();
1958 if (luaLocal
->dsAnchors
.empty()) {
1959 LOG(d_prefix
<<": No trust anchors configured, everything is Insecure"<<endl
);
1960 /* We have no TA, everything is insecure */
1965 if (haveNegativeTrustAnchor(luaLocal
->negAnchors
, zone
, reason
)) {
1966 LOG(d_prefix
<<": got NTA for '"<<zone
<<"'"<<endl
);
1970 if (getTrustAnchor(luaLocal
->dsAnchors
, zone
, ds
)) {
1971 LOG(d_prefix
<<": got TA for '"<<zone
<<"'"<<endl
);
1975 LOG(d_prefix
<<": no TA found for '"<<zone
<<"' among "<< luaLocal
->dsAnchors
.size()<<endl
);
1978 if (zone
.isRoot()) {
1979 /* No TA for the root */
1983 return Indeterminate
;
1986 static size_t countSupportedDS(const dsmap_t
& dsmap
)
1990 for (const auto& ds
: dsmap
) {
1991 if (isSupportedDS(ds
)) {
1999 vState
SyncRes::getDSRecords(const DNSName
& zone
, dsmap_t
& ds
, bool taOnly
, unsigned int depth
, bool bogusOnNXD
, bool* foundCut
)
2001 vState result
= getTA(zone
, ds
);
2003 if (result
!= Indeterminate
|| taOnly
) {
2005 *foundCut
= (result
!= Indeterminate
);
2009 if (countSupportedDS(ds
) == 0) {
2017 else if (result
== NTA
) {
2024 bool oldSkipCNAME
= d_skipCNAMECheck
;
2025 d_skipCNAMECheck
= true;
2027 std::set
<GetBestNSAnswer
> beenthere
;
2028 std::vector
<DNSRecord
> dsrecords
;
2030 vState state
= Indeterminate
;
2031 int rcode
= doResolve(zone
, QType(QType::DS
), dsrecords
, depth
+ 1, beenthere
, state
);
2032 d_skipCNAMECheck
= oldSkipCNAME
;
2034 if (rcode
== RCode::NoError
|| (rcode
== RCode::NXDomain
&& !bogusOnNXD
)) {
2035 uint8_t bestDigestType
= 0;
2037 bool gotCNAME
= false;
2038 for (const auto& record
: dsrecords
) {
2039 if (record
.d_type
== QType::DS
) {
2040 const auto dscontent
= getRR
<DSRecordContent
>(record
);
2041 if (dscontent
&& isSupportedDS(*dscontent
)) {
2042 // Make GOST a lower prio than SHA256
2043 if (dscontent
->d_digesttype
== DNSSECKeeper::DIGEST_GOST
&& bestDigestType
== DNSSECKeeper::DIGEST_SHA256
) {
2046 if (dscontent
->d_digesttype
> bestDigestType
|| (bestDigestType
== DNSSECKeeper::DIGEST_GOST
&& dscontent
->d_digesttype
== DNSSECKeeper::DIGEST_SHA256
)) {
2047 bestDigestType
= dscontent
->d_digesttype
;
2049 ds
.insert(*dscontent
);
2052 else if (record
.d_type
== QType::CNAME
&& record
.d_name
== zone
) {
2057 /* RFC 4509 section 3: "Validator implementations SHOULD ignore DS RRs containing SHA-1
2058 * digests if DS RRs with SHA-256 digests are present in the DS RRset."
2059 * As SHA348 is specified as well, the spirit of the this line is "use the best algorithm".
2061 for (auto dsrec
= ds
.begin(); dsrec
!= ds
.end(); ) {
2062 if (dsrec
->d_digesttype
!= bestDigestType
) {
2063 dsrec
= ds
.erase(dsrec
);
2070 if (rcode
== RCode::NoError
) {
2072 /* we have no DS, it's either:
2073 - a delegation to a non-DNSSEC signed zone
2074 - no delegation, we stay in the same zone
2076 if (gotCNAME
|| denialProvesNoDelegation(zone
, dsrecords
)) {
2077 /* we are still inside the same zone */
2085 /* delegation with no DS, might be Secure -> Insecure */
2090 /* a delegation with no DS is either:
2091 - a signed zone (Secure) to an unsigned one (Insecure)
2092 - an unsigned zone to another unsigned one (Insecure stays Insecure, Bogus stays Bogus)
2094 return state
== Secure
? Insecure
: state
;
2106 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
2110 bool SyncRes::haveExactValidationStatus(const DNSName
& domain
)
2112 if (!shouldValidate()) {
2115 const auto& it
= d_cutStates
.find(domain
);
2116 if (it
!= d_cutStates
.cend()) {
2122 vState
SyncRes::getValidationStatus(const DNSName
& subdomain
, bool allowIndeterminate
)
2124 vState result
= Indeterminate
;
2126 if (!shouldValidate()) {
2129 DNSName
name(subdomain
);
2131 const auto& it
= d_cutStates
.find(name
);
2132 if (it
!= d_cutStates
.cend()) {
2133 if (allowIndeterminate
|| it
->second
!= Indeterminate
) {
2134 LOG(d_prefix
<<": got status "<<vStates
[it
->second
]<<" for name "<<subdomain
<<" (from "<<name
<<")"<<endl
);
2139 while (name
.chopOff());
2144 bool SyncRes::lookForCut(const DNSName
& qname
, unsigned int depth
, const vState existingState
, vState
& newState
)
2146 bool foundCut
= false;
2148 vState dsState
= getDSRecords(qname
, ds
, newState
== Bogus
|| existingState
== Insecure
|| existingState
== Bogus
, depth
, false, &foundCut
);
2150 if (dsState
!= Indeterminate
) {
2157 void SyncRes::computeZoneCuts(const DNSName
& begin
, const DNSName
& end
, unsigned int depth
)
2159 if(!begin
.isPartOf(end
)) {
2160 LOG(d_prefix
<<" "<<begin
.toLogString()<<" is not part of "<<end
.toLogString()<<endl
);
2161 throw PDNSException(begin
.toLogString() + " is not part of " + end
.toLogString());
2164 if (d_cutStates
.count(begin
) != 0) {
2168 const bool oldCacheOnly
= setCacheOnly(false);
2171 vState cutState
= getDSRecords(end
, ds
, false, depth
);
2172 LOG(d_prefix
<<": setting cut state for "<<end
<<" to "<<vStates
[cutState
]<<endl
);
2173 d_cutStates
[end
] = cutState
;
2175 if (!shouldValidate()) {
2176 setCacheOnly(oldCacheOnly
);
2181 std::vector
<string
> labelsToAdd
= begin
.makeRelative(end
).getRawLabels();
2183 bool oldSkipCNAME
= d_skipCNAMECheck
;
2184 d_skipCNAMECheck
= true;
2186 while(qname
!= begin
) {
2187 if (labelsToAdd
.empty())
2190 qname
.prependRawLabel(labelsToAdd
.back());
2191 labelsToAdd
.pop_back();
2192 LOG(d_prefix
<<": - Looking for a cut at "<<qname
<<endl
);
2194 const auto cutIt
= d_cutStates
.find(qname
);
2195 if (cutIt
!= d_cutStates
.cend()) {
2196 if (cutIt
->second
!= Indeterminate
) {
2197 LOG(d_prefix
<<": - Cut already known at "<<qname
<<endl
);
2198 cutState
= cutIt
->second
;
2203 /* no need to look for NS and DS if we are already insecure or bogus,
2206 if (cutState
== Insecure
|| cutState
== Bogus
) {
2208 vState newState
= getDSRecords(qname
, cutDS
, true, depth
);
2209 if (newState
== Indeterminate
) {
2213 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[newState
]<<endl
);
2214 cutState
= newState
;
2216 d_cutStates
[qname
] = cutState
;
2221 vState newState
= Indeterminate
;
2222 /* temporarily mark as Indeterminate, so that we won't enter an endless loop
2223 trying to determine that zone cut again. */
2224 d_cutStates
[qname
] = newState
;
2225 bool foundCut
= lookForCut(qname
, depth
+ 1, cutState
, newState
);
2227 LOG(d_prefix
<<": - Found cut at "<<qname
<<endl
);
2228 if (newState
!= Indeterminate
) {
2229 cutState
= newState
;
2231 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[cutState
]<<endl
);
2232 d_cutStates
[qname
] = cutState
;
2235 /* remove the temporary cut */
2236 LOG(d_prefix
<<qname
<<": removing cut state for "<<qname
<<endl
);
2237 d_cutStates
.erase(qname
);
2241 d_skipCNAMECheck
= oldSkipCNAME
;
2243 LOG(d_prefix
<<": list of cuts from "<<begin
<<" to "<<end
<<endl
);
2244 for (const auto& cut
: d_cutStates
) {
2245 if (cut
.first
.isRoot() || (begin
.isPartOf(cut
.first
) && cut
.first
.isPartOf(end
))) {
2246 LOG(" - "<<cut
.first
<<": "<<vStates
[cut
.second
]<<endl
);
2249 setCacheOnly(oldCacheOnly
);
2252 vState
SyncRes::validateDNSKeys(const DNSName
& zone
, const std::vector
<DNSRecord
>& dnskeys
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, unsigned int depth
)
2255 if (!signatures
.empty()) {
2256 DNSName signer
= getSigner(signatures
);
2258 if (!signer
.empty() && zone
.isPartOf(signer
)) {
2259 vState state
= getDSRecords(signer
, ds
, false, depth
);
2261 if (state
!= Secure
) {
2267 skeyset_t tentativeKeys
;
2268 sortedRecords_t toSign
;
2270 for (const auto& dnskey
: dnskeys
) {
2271 if (dnskey
.d_type
== QType::DNSKEY
) {
2272 auto content
= getRR
<DNSKEYRecordContent
>(dnskey
);
2274 tentativeKeys
.insert(content
);
2275 toSign
.insert(content
);
2280 LOG(d_prefix
<<": trying to validate "<<std::to_string(tentativeKeys
.size())<<" DNSKEYs with "<<std::to_string(ds
.size())<<" DS"<<endl
);
2281 skeyset_t validatedKeys
;
2282 validateDNSKeysAgainstDS(d_now
.tv_sec
, zone
, ds
, tentativeKeys
, toSign
, signatures
, validatedKeys
);
2284 LOG(d_prefix
<<": we now have "<<std::to_string(validatedKeys
.size())<<" DNSKEYs"<<endl
);
2286 /* if we found at least one valid RRSIG covering the set,
2287 all tentative keys are validated keys. Otherwise it means
2288 we haven't found at least one DNSKEY and a matching RRSIG
2289 covering this set, this looks Bogus. */
2290 if (validatedKeys
.size() != tentativeKeys
.size()) {
2291 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
2298 vState
SyncRes::getDNSKeys(const DNSName
& signer
, skeyset_t
& keys
, unsigned int depth
)
2300 std::vector
<DNSRecord
> records
;
2301 std::set
<GetBestNSAnswer
> beenthere
;
2302 LOG(d_prefix
<<"Retrieving DNSKeys for "<<signer
<<endl
);
2304 vState state
= Indeterminate
;
2305 /* following CNAME might lead to us to the wrong DNSKEY */
2306 bool oldSkipCNAME
= d_skipCNAMECheck
;
2307 d_skipCNAMECheck
= true;
2308 int rcode
= doResolve(signer
, QType(QType::DNSKEY
), records
, depth
+ 1, beenthere
, state
);
2309 d_skipCNAMECheck
= oldSkipCNAME
;
2311 if (rcode
== RCode::NoError
) {
2312 if (state
== Secure
) {
2313 for (const auto& key
: records
) {
2314 if (key
.d_type
== QType::DNSKEY
) {
2315 auto content
= getRR
<DNSKEYRecordContent
>(key
);
2317 keys
.insert(content
);
2322 LOG(d_prefix
<<"Retrieved "<<keys
.size()<<" DNSKeys for "<<signer
<<", state is "<<vStates
[state
]<<endl
);
2326 LOG(d_prefix
<<"Returning Bogus state from "<<__func__
<<"("<<signer
<<")"<<endl
);
2330 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
)
2333 if (!signatures
.empty()) {
2334 const DNSName signer
= getSigner(signatures
);
2335 if (!signer
.empty() && name
.isPartOf(signer
)) {
2336 if ((qtype
== QType::DNSKEY
|| qtype
== QType::DS
) && signer
== qname
) {
2337 /* we are already retrieving those keys, sorry */
2338 if (qtype
== QType::DS
) {
2339 /* something is very wrong */
2340 LOG(d_prefix
<<"The DS for "<<qname
<<" is signed by itself, going Bogus"<<endl
);
2343 return Indeterminate
;
2345 vState state
= getDNSKeys(signer
, keys
, depth
);
2346 if (state
!= Secure
) {
2351 LOG(d_prefix
<<"Bogus!"<<endl
);
2355 sortedRecords_t recordcontents
;
2356 for (const auto& record
: records
) {
2357 recordcontents
.insert(record
.d_content
);
2360 LOG(d_prefix
<<"Going to validate "<<recordcontents
.size()<< " record contents with "<<signatures
.size()<<" sigs and "<<keys
.size()<<" keys for "<<name
<<endl
);
2361 if (validateWithKeySet(d_now
.tv_sec
, name
, recordcontents
, signatures
, keys
, false)) {
2362 LOG(d_prefix
<<"Secure!"<<endl
);
2366 LOG(d_prefix
<<"Bogus!"<<endl
);
2370 static bool allowAdditionalEntry(std::unordered_set
<DNSName
>& allowedAdditionals
, const DNSRecord
& rec
)
2372 switch(rec
.d_type
) {
2375 if (auto mxContent
= getRR
<MXRecordContent
>(rec
)) {
2376 allowedAdditionals
.insert(mxContent
->d_mxname
);
2382 if (auto nsContent
= getRR
<NSRecordContent
>(rec
)) {
2383 allowedAdditionals
.insert(nsContent
->getNS());
2389 if (auto srvContent
= getRR
<SRVRecordContent
>(rec
)) {
2390 allowedAdditionals
.insert(srvContent
->d_target
);
2399 void SyncRes::sanitizeRecords(const std::string
& prefix
, LWResult
& lwr
, const DNSName
& qname
, const QType
& qtype
, const DNSName
& auth
, bool wasForwarded
, bool rdQuery
)
2401 const bool wasForwardRecurse
= wasForwarded
&& rdQuery
;
2402 /* list of names for which we will allow A and AAAA records in the additional section
2404 std::unordered_set
<DNSName
> allowedAdditionals
= { qname
};
2405 bool haveAnswers
= false;
2406 bool isNXDomain
= false;
2407 bool isNXQType
= false;
2409 for(auto rec
= lwr
.d_records
.begin(); rec
!= lwr
.d_records
.end(); ) {
2411 if (rec
->d_type
== QType::OPT
) {
2416 if (rec
->d_class
!= QClass::IN
) {
2417 LOG(prefix
<<"Removing non internet-classed data received from "<<auth
<<endl
);
2418 rec
= lwr
.d_records
.erase(rec
);
2422 if (rec
->d_type
== QType::ANY
) {
2423 LOG(prefix
<<"Removing 'ANY'-typed data received from "<<auth
<<endl
);
2424 rec
= lwr
.d_records
.erase(rec
);
2428 if (!rec
->d_name
.isPartOf(auth
)) {
2429 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
);
2430 rec
= lwr
.d_records
.erase(rec
);
2434 /* dealing with the records in answer */
2435 if (!(lwr
.d_aabit
|| wasForwardRecurse
) && rec
->d_place
== DNSResourceRecord::ANSWER
) {
2436 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2437 are sending such responses */
2438 if (!(rec
->d_type
== QType::CNAME
&& qname
== rec
->d_name
)) {
2439 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
);
2440 rec
= lwr
.d_records
.erase(rec
);
2445 if (rec
->d_type
== QType::DNAME
&& (rec
->d_place
!= DNSResourceRecord::ANSWER
|| !qname
.isPartOf(rec
->d_name
))) {
2446 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
);
2447 rec
= lwr
.d_records
.erase(rec
);
2451 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
)) {
2452 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
);
2453 rec
= lwr
.d_records
.erase(rec
);
2457 if (rec
->d_place
== DNSResourceRecord::ANSWER
&& !haveAnswers
) {
2461 if (rec
->d_place
== DNSResourceRecord::ANSWER
) {
2462 allowAdditionalEntry(allowedAdditionals
, *rec
);
2465 /* dealing with the records in authority */
2466 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
) {
2467 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
);
2468 rec
= lwr
.d_records
.erase(rec
);
2472 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::SOA
) {
2473 if (!qname
.isPartOf(rec
->d_name
)) {
2474 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
);
2475 rec
= lwr
.d_records
.erase(rec
);
2479 if (!(lwr
.d_aabit
|| wasForwardRecurse
)) {
2480 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
);
2481 rec
= lwr
.d_records
.erase(rec
);
2486 if (lwr
.d_rcode
== RCode::NXDomain
) {
2489 else if (lwr
.d_rcode
== RCode::NoError
) {
2495 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::NS
&& (isNXDomain
|| isNXQType
)) {
2496 /* we don't want to pick up NS records in AUTHORITY or ADDITIONAL sections of NXDomain answers
2497 because they are somewhat easy to insert into a large, fragmented UDP response
2498 for an off-path attacker by injecting spoofed UDP fragments.
2500 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
);
2501 rec
= lwr
.d_records
.erase(rec
);
2505 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::NS
) {
2506 allowAdditionalEntry(allowedAdditionals
, *rec
);
2509 /* dealing with the records in additional */
2510 if (rec
->d_place
== DNSResourceRecord::ADDITIONAL
&& rec
->d_type
!= QType::A
&& rec
->d_type
!= QType::AAAA
&& rec
->d_type
!= QType::RRSIG
) {
2511 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
);
2512 rec
= lwr
.d_records
.erase(rec
);
2516 if (rec
->d_place
== DNSResourceRecord::ADDITIONAL
&& allowedAdditionals
.count(rec
->d_name
) == 0) {
2517 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
);
2518 rec
= lwr
.d_records
.erase(rec
);
2526 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
)
2528 bool wasForwardRecurse
= wasForwarded
&& rdQuery
;
2534 prefix
.append(depth
, ' ');
2537 sanitizeRecords(prefix
, lwr
, qname
, qtype
, auth
, wasForwarded
, rdQuery
);
2539 std::vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
2540 const unsigned int labelCount
= qname
.countLabels();
2541 bool isCNAMEAnswer
= false;
2542 bool isDNAMEAnswer
= false;
2543 for(const auto& rec
: lwr
.d_records
) {
2544 if (rec
.d_class
!= QClass::IN
) {
2548 if(!isCNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
&& !isDNAMEAnswer
) {
2549 isCNAMEAnswer
= true;
2551 if(!isDNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::DNAME
&& qtype
!= QType(QType::DNAME
) && qname
.isPartOf(rec
.d_name
)) {
2552 isDNAMEAnswer
= true;
2553 isCNAMEAnswer
= false;
2556 /* if we have a positive answer synthesized from a wildcard,
2557 we need to store the corresponding NSEC/NSEC3 records proving
2558 that the exact name did not exist in the negative cache */
2559 if(gatherWildcardProof
) {
2560 if (nsecTypes
.count(rec
.d_type
)) {
2561 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
2563 else if (rec
.d_type
== QType::RRSIG
) {
2564 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
2565 if (rrsig
&& nsecTypes
.count(rrsig
->d_type
)) {
2566 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
2570 if(rec
.d_type
== QType::RRSIG
) {
2571 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
2573 /* As illustrated in rfc4035's Appendix B.6, the RRSIG label
2574 count can be lower than the name's label count if it was
2575 synthesized from the wildcard. Note that the difference might
2577 if (rec
.d_name
== qname
&& isWildcardExpanded(labelCount
, rrsig
)) {
2578 gatherWildcardProof
= true;
2579 if (!isWildcardExpandedOntoItself(rec
.d_name
, labelCount
, rrsig
)) {
2580 /* if we have a wildcard expanded onto itself, we don't need to prove
2581 that the exact name doesn't exist because it actually does.
2582 We still want to gather the corresponding NSEC/NSEC3 records
2583 to pass them to our client in case it wants to validate by itself.
2585 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthesized from a wildcard, we need a wildcard proof"<<endl
);
2586 needWildcardProof
= true;
2589 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthesized from a wildcard expanded onto itself, we need to gather wildcard proof"<<endl
);
2591 wildcardLabelsCount
= rrsig
->d_labels
;
2594 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
2595 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
2596 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
);
2601 // reap all answers from this packet that are acceptable
2602 for(auto& rec
: lwr
.d_records
) {
2603 if(rec
.d_type
== QType::OPT
) {
2604 LOG(prefix
<<qname
<<": OPT answer '"<<rec
.d_name
<<"' from '"<<auth
<<"' nameservers" <<endl
);
2607 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
<<" ");
2608 if(rec
.d_type
== QType::ANY
) {
2609 LOG("NO! - we don't accept 'ANY'-typed data"<<endl
);
2613 if(rec
.d_class
!= QClass::IN
) {
2614 LOG("NO! - we don't accept records for any other class than 'IN'"<<endl
);
2618 if (!(lwr
.d_aabit
|| wasForwardRecurse
) && rec
.d_place
== DNSResourceRecord::ANSWER
) {
2619 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2620 are sending such responses */
2621 if (!(rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
)) {
2622 LOG("NO! - we don't accept records in the answers section without the AA bit set"<<endl
);
2627 if(rec
.d_name
.isPartOf(auth
)) {
2628 if(rec
.d_type
== QType::RRSIG
) {
2629 LOG("RRSIG - separate"<<endl
);
2631 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
)) {
2632 LOG("NO! Is from delegation-only zone"<<endl
);
2634 return RCode::NXDomain
;
2637 bool haveLogged
= false;
2638 if (isDNAMEAnswer
&& rec
.d_type
== QType::CNAME
) {
2639 LOG("NO - we already have a DNAME answer for this domain");
2642 if (!t_sstorage
.domainmap
->empty()) {
2643 // Check if we are authoritative for a zone in this answer
2644 DNSName
tmp_qname(rec
.d_name
);
2645 auto auth_domain_iter
=getBestAuthZone(&tmp_qname
);
2646 if(auth_domain_iter
!=t_sstorage
.domainmap
->end() &&
2647 auth
.countLabels() <= auth_domain_iter
->first
.countLabels()) {
2648 if (auth_domain_iter
->first
!= auth
) {
2649 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter
->first
<<endl
);
2652 LOG("YES! - This answer was ");
2653 if (!wasForwarded
) {
2654 LOG("retrieved from the local auth store.");
2656 LOG("received from a server we forward to.");
2667 rec
.d_ttl
=min(s_maxcachettl
, rec
.d_ttl
);
2670 dr
.d_ttl
+= d_now
.tv_sec
;
2671 dr
.d_place
=DNSResourceRecord::ANSWER
;
2672 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(dr
);
2680 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2681 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)
2682 uint32_t lowestTTD
=computeLowestTTD(i
->second
.records
, i
->second
.signatures
, i
->second
.signaturesTTL
);
2684 for(auto& record
: i
->second
.records
)
2685 record
.d_ttl
= lowestTTD
; // boom
2688 // cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
2689 // cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
2692 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2694 if(i
->second
.records
.empty()) // this happens when we did store signatures, but passed on the records themselves
2697 /* Even if the AA bit is set, additional data cannot be considered
2698 as authoritative. This is especially important during validation
2699 because keeping records in the additional section is allowed even
2700 if the corresponding RRSIGs are not included, without setting the TC
2701 bit, as stated in rfc4035's section 3.1.1. Including RRSIG RRs in a Response:
2702 "When placing a signed RRset in the Additional section, the name
2703 server MUST also place its RRSIG RRs in the Additional section.
2704 If space does not permit inclusion of both the RRset and its
2705 associated RRSIG RRs, the name server MAY retain the RRset while
2706 dropping the RRSIG RRs. If this happens, the name server MUST NOT
2707 set the TC bit solely because these RRSIG RRs didn't fit."
2709 bool isAA
= lwr
.d_aabit
&& i
->first
.place
!= DNSResourceRecord::ADDITIONAL
;
2710 /* if we forwarded the query to a recursor, we can expect the answer to be signed,
2711 even if the answer is not AA. Of course that's not only true inside a Secure
2712 zone, but we check that below. */
2713 bool expectSignature
= i
->first
.place
== DNSResourceRecord::ANSWER
|| ((lwr
.d_aabit
|| wasForwardRecurse
) && i
->first
.place
!= DNSResourceRecord::ADDITIONAL
);
2714 if (isCNAMEAnswer
&& (i
->first
.place
!= DNSResourceRecord::ANSWER
|| i
->first
.type
!= QType::CNAME
|| i
->first
.name
!= qname
)) {
2717 Note that the answer section of an authoritative answer normally
2718 contains only authoritative data. However when the name sought is an
2719 alias (see section 10.1.1) only the record describing that alias is
2720 necessarily authoritative. Clients should assume that other records
2721 may have come from the server's cache. Where authoritative answers
2722 are required, the client should query again, using the canonical name
2723 associated with the alias.
2726 expectSignature
= false;
2729 if (isCNAMEAnswer
&& i
->first
.place
== DNSResourceRecord::AUTHORITY
&& i
->first
.type
== QType::NS
&& auth
== i
->first
.name
) {
2730 /* These NS can't be authoritative since we have a CNAME answer for which (see above) only the
2731 record describing that alias is necessarily authoritative.
2732 But if we allow the current auth, which might be serving the child zone, to raise the TTL
2733 of non-authoritative NS in the cache, they might be able to keep a "ghost" zone alive forever,
2734 even after the delegation is gone from the parent.
2735 So let's just do nothing with them, we can fetch them directly if we need them.
2737 LOG(d_prefix
<<": skipping authority NS from '"<<auth
<<"' nameservers in CNAME answer "<<i
->first
.name
<<"|"<<DNSRecordContent::NumberToType(i
->first
.type
)<<endl
);
2741 vState recordState
= getValidationStatus(i
->first
.name
, false);
2742 LOG(d_prefix
<<": got initial zone status "<<vStates
[recordState
]<<" for record "<<i
->first
.name
<<"|"<<DNSRecordContent::NumberToType(i
->first
.type
)<<endl
);
2744 if (shouldValidate() && recordState
== Secure
) {
2745 vState initialState
= recordState
;
2747 if (expectSignature
) {
2748 if (i
->first
.place
!= DNSResourceRecord::ADDITIONAL
) {
2749 /* the additional entries can be insecure,
2751 "Glue address RRsets associated with delegations MUST NOT be signed"
2753 if (i
->first
.type
== QType::DNSKEY
&& i
->first
.place
== DNSResourceRecord::ANSWER
) {
2754 LOG(d_prefix
<<"Validating DNSKEY for "<<i
->first
.name
<<endl
);
2755 recordState
= validateDNSKeys(i
->first
.name
, i
->second
.records
, i
->second
.signatures
, depth
);
2759 * RFC 6672 section 5.3.1
2760 * In any response, a signed DNAME RR indicates a non-terminal
2761 * redirection of the query. There might or might not be a server-
2762 * synthesized CNAME in the answer section; if there is, the CNAME will
2763 * never be signed. For a DNSSEC validator, verification of the DNAME
2764 * RR and then that the CNAME was properly synthesized is sufficient
2767 * We do the synthesis check in processRecords, here we make sure we
2768 * don't validate the CNAME.
2770 if (!(isDNAMEAnswer
&& i
->first
.type
== QType::CNAME
)) {
2771 LOG(d_prefix
<<"Validating non-additional record for "<<i
->first
.name
<<endl
);
2772 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2773 /* 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 */
2774 if (qtype
== QType::NS
&& i
->second
.signatures
.empty() && recordState
== Bogus
&& haveExactValidationStatus(i
->first
.name
) && getValidationStatus(i
->first
.name
) == Indeterminate
) {
2775 recordState
= Indeterminate
;
2782 recordState
= Indeterminate
;
2784 /* in a non authoritative answer, we only care about the DS record (or lack of) */
2785 if ((i
->first
.type
== QType::DS
|| i
->first
.type
== QType::NSEC
|| i
->first
.type
== QType::NSEC3
) && i
->first
.place
== DNSResourceRecord::AUTHORITY
) {
2786 LOG(d_prefix
<<"Validating DS record for "<<i
->first
.name
<<endl
);
2787 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2791 if (initialState
== Secure
&& state
!= recordState
&& expectSignature
) {
2792 updateValidationState(state
, recordState
);
2796 if (shouldValidate()) {
2797 LOG(d_prefix
<<"Skipping validation because the current state is "<<vStates
[recordState
]<<endl
);
2801 if (recordState
== Bogus
) {
2802 /* this is a TTD by now, be careful */
2803 for(auto& record
: i
->second
.records
) {
2804 record
.d_ttl
= std::min(record
.d_ttl
, static_cast<uint32_t>(s_maxbogusttl
+ d_now
.tv_sec
));
2808 /* We don't need to store NSEC3 records in the positive cache because:
2809 - we don't allow direct NSEC3 queries
2810 - denial of existence proofs in wildcard expanded positive responses are stored in authorityRecs
2811 - denial of existence proofs for negative responses are stored in the negative cache
2812 We also don't want to cache non-authoritative data except for:
2813 - records coming from non forward-recurse servers (those will never be AA)
2815 - NS, A and AAAA (used for infra queries)
2817 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
)) {
2819 bool doCache
= true;
2820 if (i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
) {
2821 // If ednsmask is relevant, we do not want to cache if the scope prefix length is large and TTL is small
2822 if (SyncRes::s_ecscachelimitttl
> 0) {
2823 bool manyMaskBits
= (ednsmask
->isIPv4() && ednsmask
->getBits() > SyncRes::s_ecsipv4cachelimit
) ||
2824 (ednsmask
->isIPv6() && ednsmask
->getBits() > SyncRes::s_ecsipv6cachelimit
);
2827 uint32_t minttl
= UINT32_MAX
;
2828 for (const auto &it
: i
->second
.records
) {
2829 if (it
.d_ttl
< minttl
)
2832 bool ttlIsSmall
= minttl
< SyncRes::s_ecscachelimitttl
+ d_now
.tv_sec
;
2834 // Case: many bits and ttlIsSmall
2841 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
);
2845 if(i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
)
2849 return RCode::NoError
;
2852 void SyncRes::updateDenialValidationState(vState
& neValidationState
, const DNSName
& neName
, vState
& state
, const dState denialState
, const dState expectedState
, bool allowOptOut
)
2854 if (denialState
== expectedState
) {
2855 neValidationState
= Secure
;
2858 if (denialState
== OPTOUT
&& allowOptOut
) {
2859 LOG(d_prefix
<<"OPT-out denial found for "<<neName
<<endl
);
2861 "The AD bit, as defined by [RFC4035], MUST NOT be set when returning a
2862 response containing a closest (provable) encloser proof in which the
2863 NSEC3 RR that covers the "next closer" name has the Opt-Out bit set.
2865 This rule is based on what this closest encloser proof actually
2866 proves: names that would be covered by the Opt-Out NSEC3 RR may or
2867 may not exist as insecure delegations. As such, not all the data in
2868 responses containing such closest encloser proofs will have been
2869 cryptographically verified, so the AD bit cannot be set."
2871 At best the Opt-Out NSEC3 RR proves that there is no signed DS (so no
2874 neValidationState
= Insecure
;
2876 else if (denialState
== INSECURE
) {
2877 LOG(d_prefix
<<"Insecure denial found for "<<neName
<<", returning Insecure"<<endl
);
2878 neValidationState
= Insecure
;
2881 LOG(d_prefix
<<"Invalid denial found for "<<neName
<<", returning Bogus, res="<<denialState
<<", expectedState="<<expectedState
<<endl
);
2882 neValidationState
= Bogus
;
2884 updateValidationState(state
, neValidationState
);
2888 dState
SyncRes::getDenialValidationState(const NegCache::NegCacheEntry
& ne
, const vState state
, const dState expectedState
, bool referralToUnsigned
)
2890 cspmap_t csp
= harvestCSPFromNE(ne
);
2891 return getDenial(csp
, ne
.d_name
, ne
.d_qtype
.getCode(), referralToUnsigned
, expectedState
== NXQTYPE
);
2894 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
)
2897 DNSName dnameTarget
, dnameOwner
;
2898 uint32_t dnameTTL
= 0;
2900 for(auto& rec
: lwr
.d_records
) {
2901 if (rec
.d_type
!=QType::OPT
&& rec
.d_class
!=QClass::IN
)
2904 if (rec
.d_place
==DNSResourceRecord::ANSWER
&& !(lwr
.d_aabit
|| sendRDQuery
)) {
2905 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2906 are sending such responses */
2907 if (!(rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
)) {
2912 if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2913 lwr
.d_rcode
==RCode::NXDomain
&& qname
.isPartOf(rec
.d_name
) && rec
.d_name
.isPartOf(auth
)) {
2914 LOG(prefix
<<qname
<<": got negative caching indication for name '"<<qname
<<"' (accept="<<rec
.d_name
.isPartOf(auth
)<<"), newtarget='"<<newtarget
<<"'"<<endl
);
2916 rec
.d_ttl
= min(rec
.d_ttl
, s_maxnegttl
);
2917 if(newtarget
.empty()) // only add a SOA if we're not going anywhere after this
2920 NegCache::NegCacheEntry ne
;
2922 uint32_t lowestTTL
= rec
.d_ttl
;
2923 /* if we get an NXDomain answer with a CNAME, the name
2924 does exist but the target does not */
2925 ne
.d_name
= newtarget
.empty() ? qname
: newtarget
;
2926 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2927 ne
.d_auth
= rec
.d_name
;
2928 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2930 if (state
== Secure
) {
2931 dState denialState
= getDenialValidationState(ne
, state
, NXDOMAIN
, false);
2932 updateDenialValidationState(ne
.d_validationState
, ne
.d_name
, state
, denialState
, NXDOMAIN
, true);
2935 ne
.d_validationState
= state
;
2938 if (ne
.d_validationState
== Bogus
) {
2939 lowestTTL
= min(lowestTTL
, s_maxbogusttl
);
2942 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2943 /* if we get an NXDomain answer with a CNAME, let's not cache the
2944 target, even the server was authoritative for it,
2945 and do an additional query for the CNAME target.
2946 We have a regression test making sure we do exactly that.
2948 if(!wasVariable() && newtarget
.empty()) {
2949 t_sstorage
.negcache
.add(ne
);
2950 if(s_rootNXTrust
&& ne
.d_auth
.isRoot() && auth
.isRoot() && lwr
.d_aabit
) {
2951 ne
.d_name
= ne
.d_name
.getLastLabel();
2952 t_sstorage
.negcache
.add(ne
);
2958 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& s_redirectionQTypes
.count(rec
.d_type
) > 0 && // CNAME or DNAME answer
2959 s_redirectionQTypes
.count(qtype
.getCode()) == 0) { // But not in response to a CNAME or DNAME query
2960 if (rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
) {
2961 if (!dnameOwner
.empty()) { // We synthesize ourselves
2965 if (auto content
= getRR
<CNAMERecordContent
>(rec
)) {
2966 newtarget
=content
->getTarget();
2968 } else if (rec
.d_type
== QType::DNAME
&& qname
.isPartOf(rec
.d_name
)) { // DNAME
2970 if (auto content
= getRR
<DNAMERecordContent
>(rec
)) {
2971 dnameOwner
= rec
.d_name
;
2972 dnameTarget
= content
->getTarget();
2973 dnameTTL
= rec
.d_ttl
;
2974 if (!newtarget
.empty()) { // We had a CNAME before, remove it from ret so we don't cache it
2975 ret
.erase(std::remove_if(
2978 [&qname
](DNSRecord
& rr
) {
2979 return (rr
.d_place
== DNSResourceRecord::ANSWER
&& rr
.d_type
== QType::CNAME
&& rr
.d_name
== qname
);
2984 newtarget
= qname
.makeRelative(dnameOwner
) + dnameTarget
;
2985 } catch (const std::exception
&e
) {
2986 // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
2987 // But there is no way to set the RCODE from this function
2988 throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + dnameOwner
.toLogString() +
2989 "', DNAME target: '" + dnameTarget
.toLogString() + "', substituted name: '" +
2990 qname
.makeRelative(dnameOwner
).toLogString() + "." + dnameTarget
.toLogString() +
2996 /* if we have a positive answer synthesized from a wildcard, we need to
2997 return the corresponding NSEC/NSEC3 records from the AUTHORITY section
2998 proving that the exact name did not exist */
2999 else if(gatherWildcardProof
&& (rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::AUTHORITY
) {
3000 ret
.push_back(rec
); // enjoy your DNSSEC
3002 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
3003 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&&
3005 rec
.d_type
==qtype
.getCode() || ((lwr
.d_aabit
|| sendRDQuery
) && qtype
== QType(QType::ANY
))
3009 LOG(prefix
<<qname
<<": answer is in: resolved to '"<< rec
.d_content
->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"'"<<endl
);
3013 if (state
== Secure
&& needWildcardProof
) {
3014 /* We have a positive answer synthesized from a wildcard, we need to check that we have
3015 proof that the exact name doesn't exist so the wildcard can be used,
3016 as described in section 5.3.4 of RFC 4035 and 5.3 of RFC 7129.
3018 NegCache::NegCacheEntry ne
;
3020 uint32_t lowestTTL
= rec
.d_ttl
;
3022 ne
.d_qtype
= QType(0); // this encodes 'whole record'
3023 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
3025 cspmap_t csp
= harvestCSPFromNE(ne
);
3026 dState res
= getDenial(csp
, qname
, ne
.d_qtype
.getCode(), false, false, false, wildcardLabelsCount
);
3027 if (res
!= NXDOMAIN
) {
3029 if (res
== INSECURE
) {
3030 /* Some part could not be validated, for example a NSEC3 record with a too large number of iterations,
3031 this is not enough to warrant a Bogus, but go Insecure. */
3033 LOG(d_prefix
<<"Unable to validate denial in wildcard expanded positive response found for "<<qname
<<", returning Insecure, res="<<res
<<endl
);
3036 LOG(d_prefix
<<"Invalid denial in wildcard expanded positive response found for "<<qname
<<", returning Bogus, res="<<res
<<endl
);
3037 rec
.d_ttl
= std::min(rec
.d_ttl
, s_maxbogusttl
);
3040 updateValidationState(state
, st
);
3041 /* we already stored the record with a different validation status, let's fix it */
3042 updateValidationStatusInCache(qname
, qtype
, lwr
.d_aabit
, st
);
3047 else if((rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::ANSWER
) {
3048 if(rec
.d_type
!= QType::RRSIG
|| rec
.d_name
== qname
) {
3049 ret
.push_back(rec
); // enjoy your DNSSEC
3050 } else if(rec
.d_type
== QType::RRSIG
&& qname
.isPartOf(rec
.d_name
)) {
3051 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
3052 if (rrsig
!= nullptr && rrsig
->d_type
== QType::DNAME
) {
3057 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::NS
&& qname
.isPartOf(rec
.d_name
)) {
3058 if(moreSpecificThan(rec
.d_name
,auth
)) {
3060 LOG(prefix
<<qname
<<": got NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
3064 LOG(prefix
<<qname
<<": got upwards/level NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"', had '"<<auth
<<"'"<<endl
);
3066 if (auto content
= getRR
<NSRecordContent
>(rec
)) {
3067 nsset
.insert(content
->getNS());
3070 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::DS
&& qname
.isPartOf(rec
.d_name
)) {
3071 LOG(prefix
<<qname
<<": got DS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
3073 else if(realreferral
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& (rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && newauth
.isPartOf(auth
)) {
3074 /* we might have received a denial of the DS, let's check */
3075 if (state
== Secure
) {
3076 NegCache::NegCacheEntry ne
;
3078 ne
.d_name
= newauth
;
3079 ne
.d_qtype
= QType::DS
;
3080 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
3081 uint32_t lowestTTL
= rec
.d_ttl
;
3082 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
3084 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, true);
3086 if (denialState
== NXQTYPE
|| denialState
== OPTOUT
|| denialState
== INSECURE
) {
3087 ne
.d_ttd
= lowestTTL
+ d_now
.tv_sec
;
3088 ne
.d_validationState
= Secure
;
3089 if (denialState
== OPTOUT
) {
3090 ne
.d_validationState
= Insecure
;
3092 LOG(prefix
<<qname
<<": got negative indication of DS record for '"<<newauth
<<"'"<<endl
);
3094 if(!wasVariable()) {
3095 t_sstorage
.negcache
.add(ne
);
3098 if (qname
== newauth
&& qtype
== QType::DS
) {
3099 /* we are actually done! */
3106 else if(!done
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
3107 lwr
.d_rcode
==RCode::NoError
&& qname
.isPartOf(rec
.d_name
)) {
3108 LOG(prefix
<<qname
<<": got negative caching indication for '"<< qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
3110 if(!newtarget
.empty()) {
3111 LOG(prefix
<<qname
<<": Hang on! Got a redirect to '"<<newtarget
<<"' already"<<endl
);
3114 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
3116 NegCache::NegCacheEntry ne
;
3117 ne
.d_auth
= rec
.d_name
;
3118 uint32_t lowestTTL
= rec
.d_ttl
;
3121 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
3123 if (state
== Secure
) {
3124 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, false);
3125 updateDenialValidationState(ne
.d_validationState
, ne
.d_name
, state
, denialState
, NXQTYPE
, qtype
== QType::DS
);
3127 ne
.d_validationState
= state
;
3130 if (ne
.d_validationState
== Bogus
) {
3131 lowestTTL
= min(lowestTTL
, s_maxbogusttl
);
3132 rec
.d_ttl
= min(rec
.d_ttl
, s_maxbogusttl
);
3134 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
3136 if(!wasVariable()) {
3137 if(qtype
.getCode()) { // prevents us from blacking out a whole domain
3138 t_sstorage
.negcache
.add(ne
);
3148 if (!dnameTarget
.empty()) {
3149 // Synthesize a CNAME
3150 auto cnamerec
= DNSRecord();
3151 cnamerec
.d_name
= qname
;
3152 cnamerec
.d_type
= QType::CNAME
;
3153 cnamerec
.d_ttl
= dnameTTL
;
3154 cnamerec
.d_content
= std::make_shared
<CNAMERecordContent
>(CNAMERecordContent(newtarget
));
3155 ret
.push_back(cnamerec
);
3160 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
)
3162 bool chained
= false;
3163 int resolveret
= RCode::NoError
;
3167 if(d_outqueries
+ d_throttledqueries
> s_maxqperq
) {
3168 throw ImmediateServFailException("more than "+std::to_string(s_maxqperq
)+" (max-qperq) queries sent while resolving "+qname
.toLogString());
3171 if(s_maxtotusec
&& d_totUsec
> s_maxtotusec
) {
3172 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");
3176 LOG(prefix
<<qname
<<": using TCP with "<< remoteIP
.toStringWithPort() <<endl
);
3181 if(d_pdl
&& d_pdl
->preoutquery(remoteIP
, d_requestor
, qname
, qtype
, doTCP
, lwr
.d_records
, resolveret
)) {
3182 LOG(prefix
<<qname
<<": query handled by Lua"<<endl
);
3185 ednsmask
=getEDNSSubnetMask(qname
, remoteIP
);
3187 LOG(prefix
<<qname
<<": Adding EDNS Client Subnet Mask "<<ednsmask
->toString()<<" to query"<<endl
);
3190 resolveret
= asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, auth
, qtype
.getCode(),
3191 doTCP
, sendRDQuery
, &d_now
, ednsmask
, &lwr
, &chained
); // <- we go out on the wire!
3194 LOG(prefix
<<qname
<<": Received EDNS Client Subnet Mask "<<ednsmask
->toString()<<" on response"<<endl
);
3195 if (ednsmask
->getBits() > 0) {
3196 if (ednsmask
->isIPv4()) {
3197 ++SyncRes::s_ecsResponsesBySubnetSize4
.at(ednsmask
->getBits()-1);
3200 ++SyncRes::s_ecsResponsesBySubnetSize6
.at(ednsmask
->getBits()-1);
3206 /* preoutquery killed the query by setting dq.rcode to -3 */
3207 if(resolveret
==-3) {
3208 throw ImmediateServFailException("Query killed by policy");
3211 d_totUsec
+= lwr
.d_usec
;
3212 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
3214 bool dontThrottle
= false;
3216 auto dontThrottleNames
= g_dontThrottleNames
.getLocal();
3217 auto dontThrottleNetmasks
= g_dontThrottleNetmasks
.getLocal();
3218 dontThrottle
= dontThrottleNames
->check(nsName
) || dontThrottleNetmasks
->match(remoteIP
);
3221 if(resolveret
!= 1) {
3222 /* Error while resolving */
3223 if(resolveret
== 0) {
3226 LOG(prefix
<<qname
<<": timeout resolving after "<<lwr
.d_usec
/1000.0<<"msec "<< (doTCP
? "over TCP" : "")<<endl
);
3228 s_outgoingtimeouts
++;
3230 if(remoteIP
.sin4
.sin_family
== AF_INET
)
3231 s_outgoing4timeouts
++;
3233 s_outgoing6timeouts
++;
3236 t_timeouts
->push_back(remoteIP
);
3238 else if(resolveret
== -2) {
3239 /* OS resource limit reached */
3240 LOG(prefix
<<qname
<<": hit a local resource limit resolving"<< (doTCP
? " over TCP" : "")<<", probable error: "<<stringerror()<<endl
);
3241 g_stats
.resourceLimits
++;
3244 /* -1 means server unreachable */
3247 // XXX questionable use of errno
3248 LOG(prefix
<<qname
<<": error resolving from "<<remoteIP
.toString()<< (doTCP
? " over TCP" : "") <<", possible error: "<<stringerror()<< endl
);
3251 if(resolveret
!= -2 && !chained
&& !dontThrottle
) {
3252 // don't account for resource limits, they are our own fault
3253 // And don't throttle when the IP address is on the dontThrottleNetmasks list or the name is part of dontThrottleNames
3254 t_sstorage
.nsSpeeds
[nsName
.empty()? DNSName(remoteIP
.toStringWithPort()) : nsName
].submit(remoteIP
, 1000000, d_now
); // 1 sec
3256 // code below makes sure we don't filter COM or the root
3257 if (s_serverdownmaxfails
> 0 && (auth
!= g_rootdnsname
) && t_sstorage
.fails
.incr(remoteIP
, d_now
) >= s_serverdownmaxfails
) {
3258 LOG(prefix
<<qname
<<": Max fails reached resolving on "<< remoteIP
.toString() <<". Going full throttle for "<< s_serverdownthrottletime
<<" seconds" <<endl
);
3259 // mark server as down
3260 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0), s_serverdownthrottletime
, 10000);
3262 else if (resolveret
== -1) {
3263 // unreachable, 1 minute or 100 queries
3264 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 100);
3267 // timeout, 10 seconds or 5 queries
3268 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 10, 5);
3275 /* we got an answer */
3276 if(lwr
.d_rcode
==RCode::ServFail
|| lwr
.d_rcode
==RCode::Refused
) {
3277 LOG(prefix
<<qname
<<": "<<nsName
<<" ("<<remoteIP
.toString()<<") returned a "<< (lwr
.d_rcode
==RCode::ServFail
? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl
);
3278 if (!chained
&& !dontThrottle
) {
3279 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
3284 /* this server sent a valid answer, mark it backup up if it was down */
3285 if(s_serverdownmaxfails
> 0) {
3286 t_sstorage
.fails
.clear(remoteIP
);
3293 LOG(prefix
<<qname
<<": truncated bit set, over TCP?"<<endl
);
3294 if (!dontThrottle
) {
3295 /* let's treat that as a ServFail answer from this server */
3296 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
3300 LOG(prefix
<<qname
<<": truncated bit set, over UDP"<<endl
);
3308 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
)
3313 prefix
.append(depth
, ' ');
3317 for(auto& rec
: lwr
.d_records
) {
3318 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumTTL
);
3322 /* if the answer is ECS-specific, a minimum TTL is set for this kind of answers
3323 and it's higher than the global minimum TTL */
3324 if (ednsmask
&& s_minimumECSTTL
> 0 && (s_minimumTTL
== 0 || s_minimumECSTTL
> s_minimumTTL
)) {
3325 for(auto& rec
: lwr
.d_records
) {
3326 if (rec
.d_place
== DNSResourceRecord::ANSWER
) {
3327 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumECSTTL
);
3332 bool needWildcardProof
= false;
3333 bool gatherWildcardProof
= false;
3334 unsigned int wildcardLabelsCount
;
3335 *rcode
= updateCacheFromRecords(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, state
, needWildcardProof
, gatherWildcardProof
, wildcardLabelsCount
, sendRDQuery
);
3336 if (*rcode
!= RCode::NoError
) {
3340 LOG(prefix
<<qname
<<": determining status after receiving this packet"<<endl
);
3343 bool realreferral
=false, negindic
=false;
3347 bool done
= processRecords(prefix
, qname
, qtype
, auth
, lwr
, sendRDQuery
, ret
, nsset
, newtarget
, newauth
, realreferral
, negindic
, state
, needWildcardProof
, gatherWildcardProof
, wildcardLabelsCount
);
3350 LOG(prefix
<<qname
<<": status=got results, this level of recursion done"<<endl
);
3351 LOG(prefix
<<qname
<<": validation status is "<<vStates
[state
]<<endl
);
3352 *rcode
= RCode::NoError
;
3356 if(!newtarget
.empty()) {
3357 if(newtarget
== qname
) {
3358 LOG(prefix
<<qname
<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl
);
3359 *rcode
= RCode::ServFail
;
3364 LOG(prefix
<<qname
<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl
);
3365 *rcode
= RCode::ServFail
;
3369 if (qtype
== QType::DS
) {
3370 LOG(prefix
<<qname
<<": status=got a CNAME referral, but we are looking for a DS"<<endl
);
3373 addNXNSECS(ret
, lwr
.d_records
);
3375 *rcode
= RCode::NoError
;
3379 LOG(prefix
<<qname
<<": status=got a CNAME referral, starting over with "<<newtarget
<<endl
);
3381 set
<GetBestNSAnswer
> beenthere2
;
3382 vState cnameState
= Indeterminate
;
3383 *rcode
= doResolve(newtarget
, qtype
, ret
, depth
+ 1, beenthere2
, cnameState
);
3384 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
3385 updateValidationState(state
, cnameState
);
3390 if(lwr
.d_rcode
== RCode::NXDomain
) {
3391 LOG(prefix
<<qname
<<": status=NXDOMAIN, we are done "<<(negindic
? "(have negative SOA)" : "")<<endl
);
3394 addNXNSECS(ret
, lwr
.d_records
);
3396 *rcode
= RCode::NXDomain
;
3400 if(nsset
.empty() && !lwr
.d_rcode
&& (negindic
|| lwr
.d_aabit
|| sendRDQuery
)) {
3401 LOG(prefix
<<qname
<<": status=noerror, other types may exist, but we are done "<<(negindic
? "(have negative SOA) " : "")<<(lwr
.d_aabit
? "(have aa bit) " : "")<<endl
);
3403 if(state
== Secure
&& (lwr
.d_aabit
|| sendRDQuery
) && !negindic
) {
3404 updateValidationState(state
, Bogus
);
3408 addNXNSECS(ret
, lwr
.d_records
);
3410 *rcode
= RCode::NoError
;
3415 LOG(prefix
<<qname
<<": status=did not resolve, got "<<(unsigned int)nsset
.size()<<" NS, ");
3417 nameservers
.clear();
3418 for (auto const &nameserver
: nsset
) {
3419 if (d_wantsRPZ
&& (d_appliedPolicy
.d_type
== DNSFilterEngine::PolicyType::None
|| d_appliedPolicy
.d_kind
== DNSFilterEngine::PolicyKind::NoAction
)) {
3420 bool match
= dfe
.getProcessingPolicy(nameserver
, d_discardedPolicies
, d_appliedPolicy
);
3422 mergePolicyTags(d_policyTags
, d_appliedPolicy
.getTags());
3423 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
3424 LOG("however "<<nameserver
<<" was blocked by RPZ policy '"<<d_appliedPolicy
.getName()<<"'"<<endl
);
3425 throw PolicyHitException();
3429 nameservers
.insert({nameserver
, {{}, false}});
3431 LOG("looping to them"<<endl
);
3432 *gotNewServers
= true;
3442 * -1 in case of no results
3445 int SyncRes::doResolveAt(NsSet
&nameservers
, DNSName auth
, bool flawedNSSet
, const DNSName
&qname
, const QType
&qtype
,
3446 vector
<DNSRecord
>&ret
,
3447 unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
, vState
& state
, StopAtDelegation
* stopAtDelegation
)
3449 auto luaconfsLocal
= g_luaconfs
.getLocal();
3453 prefix
.append(depth
, ' ');
3456 LOG(prefix
<<qname
<<": Cache consultations done, have "<<(unsigned int)nameservers
.size()<<" NS to contact");
3458 if (nameserversBlockedByRPZ(luaconfsLocal
->dfe
, nameservers
)) {
3460 throw PolicyHitException();
3465 for(;;) { // we may get more specific nameservers
3466 auto rnameservers
= shuffleInSpeedOrder(nameservers
, doLog() ? (prefix
+qname
.toString()+": ") : string() );
3468 for(auto tns
=rnameservers
.cbegin();;++tns
) {
3469 if(tns
==rnameservers
.cend()) {
3470 LOG(prefix
<<qname
<<": Failed to resolve via any of the "<<(unsigned int)rnameservers
.size()<<" offered NS at level '"<<auth
<<"'"<<endl
);
3471 if(!auth
.isRoot() && flawedNSSet
) {
3472 LOG(prefix
<<qname
<<": Ageing nameservers for level '"<<auth
<<"', next query might succeed"<<endl
);
3474 if(s_RC
->doAgeCache(d_now
.tv_sec
, auth
, QType::NS
, 10))
3475 g_stats
.nsSetInvalidations
++;
3480 bool cacheOnly
= false;
3481 // this line needs to identify the 'self-resolving' behaviour
3482 if(qname
== tns
->first
&& (qtype
.getCode() == QType::A
|| qtype
.getCode() == QType::AAAA
)) {
3483 /* we might have a glue entry in cache so let's try this NS
3484 but only if we have enough in the cache to know how to reach it */
3485 LOG(prefix
<<qname
<<": Using NS to resolve itself, but only using what we have in cache ("<<(1+tns
-rnameservers
.cbegin())<<"/"<<rnameservers
.size()<<")"<<endl
);
3489 typedef vector
<ComboAddress
> remoteIPs_t
;
3490 remoteIPs_t remoteIPs
;
3491 remoteIPs_t::const_iterator remoteIP
;
3492 bool pierceDontQuery
=false;
3493 bool sendRDQuery
=false;
3494 boost::optional
<Netmask
> ednsmask
;
3496 const bool wasForwarded
= tns
->first
.empty() && (!nameservers
[tns
->first
].first
.empty());
3497 int rcode
= RCode::NoError
;
3498 bool gotNewServers
= false;
3500 if(tns
->first
.empty() && !wasForwarded
) {
3501 LOG(prefix
<<qname
<<": Domain is out-of-band"<<endl
);
3502 /* setting state to indeterminate since validation is disabled for local auth zone,
3503 and Insecure would be misleading. */
3504 state
= Indeterminate
;
3505 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, lwr
.d_records
, depth
, lwr
.d_rcode
);
3509 /* we have received an answer, are we done ? */
3510 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, false, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
3514 if (gotNewServers
) {
3515 if (stopAtDelegation
&& *stopAtDelegation
== Stop
) {
3516 *stopAtDelegation
= Stopped
;
3523 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
3524 remoteIPs
= retrieveAddressesForNS(prefix
, qname
, tns
, depth
, beenthere
, rnameservers
, nameservers
, sendRDQuery
, pierceDontQuery
, flawedNSSet
, cacheOnly
);
3526 if(remoteIPs
.empty()) {
3527 LOG(prefix
<<qname
<<": Failed to get IP for NS "<<tns
->first
<<", trying next if available"<<endl
);
3532 bool hitPolicy
{false};
3533 LOG(prefix
<<qname
<<": Resolved '"<<auth
<<"' NS "<<tns
->first
<<" to: ");
3534 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
3535 if(remoteIP
!= remoteIPs
.cbegin()) {
3538 LOG(remoteIP
->toString());
3539 if(nameserverIPBlockedByRPZ(luaconfsLocal
->dfe
, *remoteIP
)) {
3544 if (hitPolicy
) { //implies d_wantsRPZ
3546 throw PolicyHitException();
3550 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
3551 LOG(prefix
<<qname
<<": Trying IP "<< remoteIP
->toStringWithPort() <<", asking '"<<qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
3553 if (throttledOrBlocked(prefix
, *remoteIP
, qname
, qtype
, pierceDontQuery
)) {
3557 bool truncated
= false;
3558 bool gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
3559 tns
->first
, *remoteIP
, false, &truncated
);
3560 if (gotAnswer
&& truncated
) {
3561 /* retry, over TCP this time */
3562 gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
3563 tns
->first
, *remoteIP
, true, &truncated
);
3570 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
);
3572 /* // for you IPv6 fanatics :-)
3573 if(remoteIP->sin4.sin_family==AF_INET6)
3576 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
3578 t_sstorage
.nsSpeeds
[tns
->first
.empty()? DNSName(remoteIP
->toStringWithPort()) : tns
->first
].submit(*remoteIP
, lwr
.d_usec
, d_now
);
3580 /* we have received an answer, are we done ? */
3581 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
3585 if (gotNewServers
) {
3586 if (stopAtDelegation
&& *stopAtDelegation
== Stop
) {
3587 *stopAtDelegation
= Stopped
;
3593 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100);
3596 if (gotNewServers
) {
3600 if(remoteIP
== remoteIPs
.cend()) // we tried all IP addresses, none worked
3609 void SyncRes::setQuerySource(const ComboAddress
& requestor
, boost::optional
<const EDNSSubnetOpts
&> incomingECS
)
3611 d_requestor
= requestor
;
3613 if (incomingECS
&& incomingECS
->source
.getBits() > 0) {
3614 d_cacheRemote
= incomingECS
->source
.getMaskedNetwork();
3615 uint8_t bits
= std::min(incomingECS
->source
.getBits(), (incomingECS
->source
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
3616 ComboAddress trunc
= incomingECS
->source
.getNetwork();
3617 trunc
.truncate(bits
);
3618 d_outgoingECSNetwork
= boost::optional
<Netmask
>(Netmask(trunc
, bits
));
3620 d_cacheRemote
= d_requestor
;
3621 if(!incomingECS
&& s_ednslocalsubnets
.match(d_requestor
)) {
3622 ComboAddress trunc
= d_requestor
;
3623 uint8_t bits
= d_requestor
.isIPv4() ? 32 : 128;
3624 bits
= std::min(bits
, (trunc
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
3625 trunc
.truncate(bits
);
3626 d_outgoingECSNetwork
= boost::optional
<Netmask
>(Netmask(trunc
, bits
));
3627 } else if (s_ecsScopeZero
.source
.getBits() > 0) {
3628 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0.
3629 But using an empty ECS in that case would mean inserting
3630 a non ECS-specific entry into the cache, preventing any further
3631 ECS-specific query to be sent.
3632 So instead we use the trick described in section 7.1.2:
3633 "The subsequent Recursive Resolver query to the Authoritative Nameserver
3634 will then either not include an ECS option or MAY optionally include
3635 its own address information, which is what the Authoritative
3636 Nameserver will almost certainly use to generate any Tailored
3637 Response in lieu of an option. This allows the answer to be handled
3638 by the same caching mechanism as other queries, with an explicit
3639 indicator of the applicable scope. Subsequent Stub Resolver queries
3640 for /0 can then be answered from this cached response.
3642 d_outgoingECSNetwork
= boost::optional
<Netmask
>(s_ecsScopeZero
.source
.getMaskedNetwork());
3643 d_cacheRemote
= s_ecsScopeZero
.source
.getNetwork();
3645 // ECS disabled because no scope-zero address could be derived.
3646 d_outgoingECSNetwork
= boost::none
;
3651 boost::optional
<Netmask
> SyncRes::getEDNSSubnetMask(const DNSName
& dn
, const ComboAddress
& rem
)
3653 if(d_outgoingECSNetwork
&& (s_ednsdomains
.check(dn
) || s_ednsremotesubnets
.match(rem
))) {
3654 return d_outgoingECSNetwork
;
3659 void SyncRes::parseEDNSSubnetWhitelist(const std::string
& wlist
)
3661 vector
<string
> parts
;
3662 stringtok(parts
, wlist
, ",; ");
3663 for(const auto& a
: parts
) {
3665 s_ednsremotesubnets
.addMask(Netmask(a
));
3668 s_ednsdomains
.add(DNSName(a
));
3673 void SyncRes::parseEDNSSubnetAddFor(const std::string
& subnetlist
)
3675 vector
<string
> parts
;
3676 stringtok(parts
, subnetlist
, ",; ");
3677 for(const auto& a
: parts
) {
3678 s_ednslocalsubnets
.addMask(a
);
3682 // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
3683 int directResolve(const DNSName
& qname
, const QType
& qtype
, int qclass
, vector
<DNSRecord
>& ret
)
3686 gettimeofday(&now
, 0);
3691 res
= sr
.beginResolve(qname
, QType(qtype
), qclass
, ret
);
3693 catch(const PDNSException
& e
) {
3694 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got pdns exception: "<<e
.reason
<<endl
;
3697 catch(const ImmediateServFailException
& e
) {
3698 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got ImmediateServFailException: "<<e
.reason
<<endl
;
3701 catch(const PolicyHitException
& e
) {
3702 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got a policy hit"<<endl
;
3705 catch(const std::exception
& e
) {
3706 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got STL error: "<<e
.what()<<endl
;
3710 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got an exception"<<endl
;
3717 int SyncRes::getRootNS(struct timeval now
, asyncresolve_t asyncCallback
) {
3719 sr
.setDoEDNS0(true);
3720 sr
.setUpdatingRootNS();
3721 sr
.setDoDNSSEC(g_dnssecmode
!= DNSSECMode::Off
);
3722 sr
.setDNSSECValidationRequested(g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
);
3723 sr
.setAsyncCallback(asyncCallback
);
3725 vector
<DNSRecord
> ret
;
3728 res
=sr
.beginResolve(g_rootdnsname
, QType(QType::NS
), 1, ret
);
3729 if (g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
) {
3730 auto state
= sr
.getValidationState();
3732 throw PDNSException("Got Bogus validation result for .|NS");
3736 catch(const PDNSException
& e
) {
3737 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
3739 catch(const ImmediateServFailException
& e
) {
3740 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
3742 catch(const PolicyHitException
& e
) {
3743 g_log
<<Logger::Error
<<"Failed to update . records, got a policy hit"<<endl
;
3746 catch(const std::exception
& e
) {
3747 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.what()<<endl
;
3750 g_log
<<Logger::Error
<<"Failed to update . records, got an exception"<<endl
;
3754 g_log
<<Logger::Notice
<<"Refreshed . records"<<endl
;
3757 g_log
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;