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 "aggressive_nsec.hh"
28 #include "cachecleaner.hh"
29 #include "dns_random.hh"
30 #include "dnsparser.hh"
31 #include "dnsrecords.hh"
32 #include "ednssubnet.hh"
34 #include "lua-recursor4.hh"
35 #include "rec-lua-conf.hh"
37 #include "dnsseckeeper.hh"
38 #include "validate-recursor.hh"
39 #include "rec-taskqueue.hh"
41 thread_local
SyncRes::ThreadLocalStorage
SyncRes::t_sstorage
;
42 thread_local
std::unique_ptr
<addrringbuf_t
> t_timeouts
;
44 std::unique_ptr
<NetmaskGroup
> SyncRes::s_dontQuery
{nullptr};
45 NetmaskGroup
SyncRes::s_ednslocalsubnets
;
46 NetmaskGroup
SyncRes::s_ednsremotesubnets
;
47 SuffixMatchNode
SyncRes::s_ednsdomains
;
48 EDNSSubnetOpts
SyncRes::s_ecsScopeZero
;
49 string
SyncRes::s_serverID
;
50 SyncRes::LogMode
SyncRes::s_lm
;
51 const std::unordered_set
<QType
> SyncRes::s_redirectionQTypes
= {QType::CNAME
, QType::DNAME
};
52 LockGuarded
<fails_t
<ComboAddress
>> SyncRes::s_fails
;
53 LockGuarded
<fails_t
<DNSName
>> SyncRes::s_nonresolving
;
55 unsigned int SyncRes::s_maxnegttl
;
56 unsigned int SyncRes::s_maxbogusttl
;
57 unsigned int SyncRes::s_maxcachettl
;
58 unsigned int SyncRes::s_maxqperq
;
59 unsigned int SyncRes::s_maxnsaddressqperq
;
60 unsigned int SyncRes::s_maxtotusec
;
61 unsigned int SyncRes::s_maxdepth
;
62 unsigned int SyncRes::s_minimumTTL
;
63 unsigned int SyncRes::s_minimumECSTTL
;
64 unsigned int SyncRes::s_packetcachettl
;
65 unsigned int SyncRes::s_packetcacheservfailttl
;
66 unsigned int SyncRes::s_serverdownmaxfails
;
67 unsigned int SyncRes::s_serverdownthrottletime
;
68 unsigned int SyncRes::s_nonresolvingnsmaxfails
;
69 unsigned int SyncRes::s_nonresolvingnsthrottletime
;
70 unsigned int SyncRes::s_ecscachelimitttl
;
71 pdns::stat_t
SyncRes::s_authzonequeries
;
72 pdns::stat_t
SyncRes::s_queries
;
73 pdns::stat_t
SyncRes::s_outgoingtimeouts
;
74 pdns::stat_t
SyncRes::s_outgoing4timeouts
;
75 pdns::stat_t
SyncRes::s_outgoing6timeouts
;
76 pdns::stat_t
SyncRes::s_outqueries
;
77 pdns::stat_t
SyncRes::s_tcpoutqueries
;
78 pdns::stat_t
SyncRes::s_dotoutqueries
;
79 pdns::stat_t
SyncRes::s_throttledqueries
;
80 pdns::stat_t
SyncRes::s_dontqueries
;
81 pdns::stat_t
SyncRes::s_qnameminfallbacksuccess
;
82 pdns::stat_t
SyncRes::s_unreachables
;
83 pdns::stat_t
SyncRes::s_ecsqueries
;
84 pdns::stat_t
SyncRes::s_ecsresponses
;
85 std::map
<uint8_t, pdns::stat_t
> SyncRes::s_ecsResponsesBySubnetSize4
;
86 std::map
<uint8_t, pdns::stat_t
> SyncRes::s_ecsResponsesBySubnetSize6
;
88 uint8_t SyncRes::s_ecsipv4limit
;
89 uint8_t SyncRes::s_ecsipv6limit
;
90 uint8_t SyncRes::s_ecsipv4cachelimit
;
91 uint8_t SyncRes::s_ecsipv6cachelimit
;
92 bool SyncRes::s_ecsipv4nevercache
;
93 bool SyncRes::s_ecsipv6nevercache
;
95 bool SyncRes::s_doIPv4
;
96 bool SyncRes::s_doIPv6
;
97 bool SyncRes::s_nopacketcache
;
98 bool SyncRes::s_rootNXTrust
;
99 bool SyncRes::s_noEDNS
;
100 bool SyncRes::s_qnameminimization
;
101 SyncRes::HardenNXD
SyncRes::s_hardenNXD
;
102 unsigned int SyncRes::s_refresh_ttlperc
;
103 int SyncRes::s_tcp_fast_open
;
104 bool SyncRes::s_tcp_fast_open_connect
;
105 bool SyncRes::s_dot_to_port_853
;
106 int SyncRes::s_event_trace_enabled
;
108 #define LOG(x) if(d_lm == Log) { g_log <<Logger::Warning << x; } else if(d_lm == Store) { d_trace << x; }
110 // A helper function to print a double with specific printf format.
111 // Not using boost::format since it is not thread safe while calling
112 // into locale handling code according to tsan.
113 // This allocates a string, but that's nothing compared to what
114 // boost::format is doing and may even be optimized away anyway.
115 static inline std::string
fmtfloat(const char* fmt
, double f
)
118 int ret
= snprintf(buf
, sizeof(buf
), fmt
, f
);
119 if (ret
< 0 || ret
>= static_cast<int>(sizeof(buf
))) {
122 return std::string(buf
, ret
);
125 static inline void accountAuthLatency(uint64_t usec
, int family
)
127 if (family
== AF_INET
) {
128 g_stats
.auth4Answers(usec
);
129 g_stats
.cumulativeAuth4Answers(usec
);
131 g_stats
.auth6Answers(usec
);
132 g_stats
.cumulativeAuth6Answers(usec
);
137 SyncRes::SyncRes(const struct timeval
& now
) : d_authzonequeries(0), d_outqueries(0), d_tcpoutqueries(0), d_dotoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
138 d_totUsec(0), d_now(now
),
139 d_cacheonly(false), d_doDNSSEC(false), d_doEDNS0(false), d_qNameMinimization(s_qnameminimization
), d_lm(s_lm
)
144 static void allowAdditionalEntry(std::unordered_set
<DNSName
>& allowedAdditionals
, const DNSRecord
& rec
);
146 void SyncRes::resolveAdditionals(const DNSName
& qname
, QType qtype
, AdditionalMode mode
, std::vector
<DNSRecord
>& additionals
, unsigned int depth
)
148 vector
<DNSRecord
> addRecords
;
150 vState state
= vState::Indeterminate
;
152 case AdditionalMode::ResolveImmediately
: {
153 set
<GetBestNSAnswer
> beenthere
;
154 int res
= doResolve(qname
, qtype
, addRecords
, depth
, beenthere
, state
);
158 // We're conservative here. We do not add Bogus records in any circumstance, we add Indeterminates only if no
159 // validation is required.
160 if (vStateIsBogus(state
)) {
163 if (shouldValidate() && state
!= vState::Secure
&& state
!= vState::Insecure
) {
166 for (auto& rec
: addRecords
) {
167 if (rec
.d_place
== DNSResourceRecord::ANSWER
) {
168 additionals
.push_back(std::move(rec
));
173 case AdditionalMode::CacheOnly
:
174 case AdditionalMode::CacheOnlyRequireAuth
: {
176 if (g_recCache
->get(d_now
.tv_sec
, qname
, qtype
, mode
== AdditionalMode::CacheOnlyRequireAuth
, &addRecords
, d_cacheRemote
, false, d_routingTag
, nullptr, nullptr, nullptr, &state
) <= 0) {
179 // See the comment for the ResolveImmediately case
180 if (vStateIsBogus(state
)) {
183 if (shouldValidate() && state
!= vState::Secure
&& state
!= vState::Insecure
) {
186 for (auto& rec
: addRecords
) {
187 if (rec
.d_place
== DNSResourceRecord::ANSWER
) {
188 rec
.d_ttl
-= d_now
.tv_sec
;
189 additionals
.push_back(std::move(rec
));
194 case AdditionalMode::ResolveDeferred
:
195 // FIXME: Not yet implemented
196 // Look in cache for authoritative answer, if available return it
197 // If not, look in nergache and submit if not there as well. The logic should be the same as
198 // #11294, which is in review atm.
200 case AdditionalMode::Ignore
:
205 // The main (recursive) function to add additionals
206 // qtype: the original query type to expand
207 // start: records to start from
208 // This function uses to state sets to avoid infinite recursion and allow depulication
209 // depth is the main recursion depth
210 // additionaldepth is the depth for addAdditionals itself
211 void SyncRes::addAdditionals(QType qtype
, const vector
<DNSRecord
>&start
, vector
<DNSRecord
>&additionals
, std::set
<std::pair
<DNSName
, QType
>>& uniqueCalls
, std::set
<std::tuple
<DNSName
, QType
, QType
>>& uniqueResults
, unsigned int depth
, unsigned additionaldepth
)
213 if (additionaldepth
>= 5 || start
.empty()) {
217 auto luaLocal
= g_luaconfs
.getLocal();
218 const auto it
= luaLocal
->allowAdditionalQTypes
.find(qtype
);
219 if (it
== luaLocal
->allowAdditionalQTypes
.end()) {
222 std::unordered_set
<DNSName
> addnames
;
223 for (const auto& rec
: start
) {
224 if (rec
.d_place
== DNSResourceRecord::ANSWER
) {
225 // currently, this function only knows about names, we could also take the target types that are dependent on
226 // record contents into account
227 // e.g. for NAPTR records, go only for SRV for flag value "s", or A/AAAA for flag value "a"
228 allowAdditionalEntry(addnames
, rec
);
232 // We maintain two sets for deduplication:
233 // - uniqueCalls makes sure we never resolve a qname/qtype twice
234 // - uniqueResults makes sure we never add the same qname/qytype RRSet to the result twice,
235 // but note that that set might contain multiple elements.
237 auto mode
= it
->second
.second
;
238 for (const auto& targettype
: it
->second
.first
) {
239 for (const auto& addname
: addnames
) {
240 std::vector
<DNSRecord
> records
;
241 bool inserted
= uniqueCalls
.emplace(addname
, targettype
).second
;
243 resolveAdditionals(addname
, targettype
, mode
, records
, depth
);
245 if (!records
.empty()) {
246 for (auto r
= records
.begin(); r
!= records
.end(); ) {
247 QType covered
= QType::ENT
;
248 if (r
->d_type
== QType::RRSIG
) {
249 if (auto rsig
= getRR
<RRSIGRecordContent
>(*r
); rsig
!= nullptr) {
250 covered
= rsig
->d_type
;
253 if (uniqueResults
.count(std::tuple(r
->d_name
, QType(r
->d_type
), covered
)) > 0) {
254 // A bit expensive for vectors, but they are small
255 r
= records
.erase(r
);
260 for (const auto& r
: records
) {
261 additionals
.push_back(r
);
262 QType covered
= QType::ENT
;
263 if (r
.d_type
== QType::RRSIG
) {
264 if (auto rsig
= getRR
<RRSIGRecordContent
>(r
); rsig
!= nullptr) {
265 covered
= rsig
->d_type
;
268 uniqueResults
.emplace(r
.d_name
, r
.d_type
, covered
);
270 addAdditionals(targettype
, records
, additionals
, uniqueCalls
, uniqueResults
, depth
, additionaldepth
+ 1);
276 // The entry point for other code
277 void SyncRes::addAdditionals(QType qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
)
279 // The additional records of interest
280 std::vector
<DNSRecord
> additionals
;
282 // We only call resolve for a specific name/type combo once
283 std::set
<std::pair
<DNSName
, QType
>> uniqueCalls
;
285 // Collect multiple name/qtype from a single resolve but do not add a new set from new resolve calls
286 // For RRSIGs, the type covered is stored in the second Qtype
287 std::set
<std::tuple
<DNSName
, QType
, QType
>> uniqueResults
;
289 addAdditionals(qtype
, ret
, additionals
, uniqueCalls
, uniqueResults
, depth
, 0);
291 for (auto& rec
: additionals
) {
292 rec
.d_place
= DNSResourceRecord::ADDITIONAL
;
293 ret
.push_back(std::move(rec
));
297 /** everything begins here - this is the entry point just after receiving a packet */
298 int SyncRes::beginResolve(const DNSName
&qname
, const QType qtype
, QClass qclass
, vector
<DNSRecord
>&ret
, unsigned int depth
)
300 d_eventTrace
.add(RecEventTrace::SyncRes
);
301 vState state
= vState::Indeterminate
;
304 d_wasOutOfBand
=false;
307 if (doSpecialNamesResolve(qname
, qtype
, qclass
, ret
)) {
308 d_queryValidationState
= vState::Insecure
; // this could fool our stats into thinking a validation took place
309 return 0; // so do check before updating counters (we do now)
312 auto qtypeCode
= qtype
.getCode();
313 /* rfc6895 section 3.1 */
314 if (qtypeCode
== 0 || (qtypeCode
>= 128 && qtypeCode
<= 254) || qtypeCode
== QType::RRSIG
|| qtypeCode
== QType::NSEC3
|| qtypeCode
== QType::OPT
|| qtypeCode
== 65535) {
318 if(qclass
==QClass::ANY
)
320 else if(qclass
!=QClass::IN
)
323 if (qtype
== QType::DS
) {
324 d_externalDSQuery
= qname
;
327 d_externalDSQuery
.clear();
330 set
<GetBestNSAnswer
> beenthere
;
331 int res
=doResolve(qname
, qtype
, ret
, depth
, beenthere
, state
);
332 d_queryValidationState
= state
;
334 if (shouldValidate()) {
335 if (d_queryValidationState
!= vState::Indeterminate
) {
336 g_stats
.dnssecValidations
++;
338 auto xdnssec
= g_xdnssec
.getLocal();
339 if (xdnssec
->check(qname
)) {
340 increaseXDNSSECStateCounter(d_queryValidationState
);
342 increaseDNSSECStateCounter(d_queryValidationState
);
346 // Avoid calling addAdditionals() if we know we won't find anything
347 auto luaLocal
= g_luaconfs
.getLocal();
348 if (res
== 0 && qclass
== QClass::IN
&& luaLocal
->allowAdditionalQTypes
.find(qtype
) != luaLocal
->allowAdditionalQTypes
.end()) {
349 addAdditionals(qtype
, ret
, depth
);
351 d_eventTrace
.add(RecEventTrace::SyncRes
, res
, false);
355 /*! Handles all special, built-in names
356 * Fills ret with an answer and returns true if it handled the query.
358 * Handles the following queries (and their ANY variants):
361 * - localhost. IN AAAA
362 * - 1.0.0.127.in-addr.arpa. IN PTR
363 * - 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
364 * - version.bind. CH TXT
365 * - version.pdns. CH TXT
366 * - id.server. CH TXT
367 * - trustanchor.server CH TXT
368 * - negativetrustanchor.server CH TXT
370 bool SyncRes::doSpecialNamesResolve(const DNSName
&qname
, const QType qtype
, const QClass qclass
, vector
<DNSRecord
> &ret
)
372 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."),
373 localhost("localhost."), versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns."), trustanchorserver("trustanchor.server."),
374 negativetrustanchorserver("negativetrustanchor.server.");
376 bool handled
= false;
377 vector
<pair
<QType::typeenum
, string
> > answers
;
379 if ((qname
== arpa
|| qname
== ip6_arpa
) &&
380 qclass
== QClass::IN
) {
382 if (qtype
== QType::PTR
|| qtype
== QType::ANY
)
383 answers
.emplace_back(QType::PTR
, "localhost.");
386 if (qname
.isPartOf(localhost
) &&
387 qclass
== QClass::IN
) {
389 if (qtype
== QType::A
|| qtype
== QType::ANY
)
390 answers
.emplace_back(QType::A
, "127.0.0.1");
391 if (qtype
== QType::AAAA
|| qtype
== QType::ANY
)
392 answers
.emplace_back(QType::AAAA
, "::1");
395 if ((qname
== versionbind
|| qname
== idserver
|| qname
== versionpdns
) &&
396 qclass
== QClass::CHAOS
) {
398 if (qtype
== QType::TXT
|| qtype
== QType::ANY
) {
399 if(qname
== versionbind
|| qname
== versionpdns
)
400 answers
.emplace_back(QType::TXT
, "\"" + ::arg()["version-string"] + "\"");
401 else if (s_serverID
!= "disabled")
402 answers
.emplace_back(QType::TXT
, "\"" + s_serverID
+ "\"");
406 if (qname
== trustanchorserver
&& qclass
== QClass::CHAOS
&&
407 ::arg().mustDo("allow-trust-anchor-query")) {
409 if (qtype
== QType::TXT
|| qtype
== QType::ANY
) {
410 auto luaLocal
= g_luaconfs
.getLocal();
411 for (auto const &dsAnchor
: luaLocal
->dsAnchors
) {
414 ans
<<dsAnchor
.first
.toString(); // Explicit toString to have a trailing dot
415 for (auto const &dsRecord
: dsAnchor
.second
) {
420 answers
.emplace_back(QType::TXT
, ans
.str());
425 if (qname
== negativetrustanchorserver
&& qclass
== QClass::CHAOS
&&
426 ::arg().mustDo("allow-trust-anchor-query")) {
428 if (qtype
== QType::TXT
|| qtype
== QType::ANY
) {
429 auto luaLocal
= g_luaconfs
.getLocal();
430 for (auto const &negAnchor
: luaLocal
->negAnchors
) {
433 ans
<<negAnchor
.first
.toString(); // Explicit toString to have a trailing dot
434 if (negAnchor
.second
.length())
435 ans
<<" "<<negAnchor
.second
;
437 answers
.emplace_back(QType::TXT
, ans
.str());
442 if (handled
&& !answers
.empty()) {
448 dr
.d_place
= DNSResourceRecord::ANSWER
;
451 for (const auto& ans
: answers
) {
452 dr
.d_type
= ans
.first
;
453 dr
.d_content
= DNSRecordContent::mastermake(ans
.first
, qclass
, ans
.second
);
462 //! This is the 'out of band resolver', in other words, the authoritative server
463 void SyncRes::AuthDomain::addSOA(std::vector
<DNSRecord
>& records
) const
465 SyncRes::AuthDomain::records_t::const_iterator ziter
= d_records
.find(std::make_tuple(getName(), QType::SOA
));
466 if (ziter
!= d_records
.end()) {
467 DNSRecord dr
= *ziter
;
468 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
469 records
.push_back(dr
);
472 // cerr<<qname<<": can't find SOA record '"<<getName()<<"' in our zone!"<<endl;
476 int SyncRes::AuthDomain::getRecords(const DNSName
& qname
, const QType qtype
, std::vector
<DNSRecord
>& records
) const
478 int result
= RCode::NoError
;
482 std::pair
<records_t::const_iterator
,records_t::const_iterator
> range
= d_records
.equal_range(std::tie(qname
));
484 SyncRes::AuthDomain::records_t::const_iterator ziter
;
485 bool somedata
= false;
487 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
490 if(qtype
== QType::ANY
|| ziter
->d_type
== qtype
|| ziter
->d_type
== QType::CNAME
) {
491 // let rest of nameserver do the legwork on this one
492 records
.push_back(*ziter
);
494 else if (ziter
->d_type
== QType::NS
&& ziter
->d_name
.countLabels() > getName().countLabels()) {
495 // we hit a delegation point!
496 DNSRecord dr
= *ziter
;
497 dr
.d_place
=DNSResourceRecord::AUTHORITY
;
498 records
.push_back(dr
);
502 if (!records
.empty()) {
503 /* We have found an exact match, we're done */
504 // cerr<<qname<<": exact match in zone '"<<getName()<<"'"<<endl;
509 /* We have records for that name, but not of the wanted qtype */
510 // cerr<<qname<<": found record in '"<<getName()<<"', but nothing of the right type, sending SOA"<<endl;
516 // cerr<<qname<<": nothing found so far in '"<<getName()<<"', trying wildcards"<<endl;
517 DNSName
wcarddomain(qname
);
518 while(wcarddomain
!= getName() && wcarddomain
.chopOff()) {
519 // cerr<<qname<<": trying '*."<<wcarddomain<<"' in "<<getName()<<endl;
520 range
= d_records
.equal_range(std::make_tuple(g_wildcarddnsname
+ wcarddomain
));
521 if (range
.first
==range
.second
)
524 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
525 DNSRecord dr
= *ziter
;
526 // if we hit a CNAME, just answer that - rest of recursor will do the needful & follow
527 if(dr
.d_type
== qtype
|| qtype
== QType::ANY
|| dr
.d_type
== QType::CNAME
) {
529 dr
.d_place
= DNSResourceRecord::ANSWER
;
530 records
.push_back(dr
);
534 if (records
.empty()) {
538 // cerr<<qname<<": in '"<<getName()<<"', had wildcard match on '*."<<wcarddomain<<"'"<<endl;
542 /* Nothing for this name, no wildcard, let's see if there is some NS */
543 DNSName
nsdomain(qname
);
544 while (nsdomain
.chopOff() && nsdomain
!= getName()) {
545 range
= d_records
.equal_range(std::make_tuple(nsdomain
,QType::NS
));
546 if(range
.first
== range
.second
)
549 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
550 DNSRecord dr
= *ziter
;
551 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
552 records
.push_back(dr
);
556 if(records
.empty()) {
557 // cerr<<qname<<": no NS match in zone '"<<getName()<<"' either, handing out SOA"<<endl;
559 result
= RCode::NXDomain
;
565 bool SyncRes::doOOBResolve(const AuthDomain
& domain
, const DNSName
&qname
, const QType qtype
, vector
<DNSRecord
>&ret
, int& res
)
570 res
= domain
.getRecords(qname
, qtype
, ret
);
574 bool SyncRes::doOOBResolve(const DNSName
&qname
, const QType qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int& res
)
579 prefix
.append(depth
, ' ');
582 DNSName
authdomain(qname
);
583 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
584 if(iter
==t_sstorage
.domainmap
->end() || !iter
->second
.isAuth()) {
585 LOG(prefix
<<qname
<<": auth storage has no zone for this query!"<<endl
);
589 LOG(prefix
<<qname
<<": auth storage has data, zone='"<<authdomain
<<"'"<<endl
);
590 return doOOBResolve(iter
->second
, qname
, qtype
, ret
, res
);
593 bool SyncRes::isRecursiveForwardOrAuth(const DNSName
&qname
) const {
594 DNSName
authname(qname
);
595 domainmap_t::const_iterator iter
= getBestAuthZone(&authname
);
596 return iter
!= t_sstorage
.domainmap
->end() && (iter
->second
.isAuth() || iter
->second
.shouldRecurse());
599 bool SyncRes::isForwardOrAuth(const DNSName
&qname
) const {
600 DNSName
authname(qname
);
601 domainmap_t::const_iterator iter
= getBestAuthZone(&authname
);
602 return iter
!= t_sstorage
.domainmap
->end() && (iter
->second
.isAuth() || !iter
->second
.shouldRecurse());
605 uint64_t SyncRes::doEDNSDump(int fd
)
611 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(newfd
, "w"), fclose
);
618 fprintf(fp
.get(),"; edns from thread follows\n;\n");
619 for(const auto& eds
: t_sstorage
.ednsstatus
) {
622 fprintf(fp
.get(), "%s\t%d\t%s", eds
.address
.toString().c_str(), (int)eds
.mode
, ctime_r(&eds
.modeSetAt
, tmp
));
627 uint64_t SyncRes::doDumpNSSpeeds(int fd
)
633 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(newfd
, "w"), fclose
);
638 fprintf(fp
.get(), "; nsspeed dump from thread follows\n;\n");
641 for(const auto& i
: t_sstorage
.nsSpeeds
)
645 // an <empty> can appear hear in case of authoritative (hosted) zones
646 fprintf(fp
.get(), "%s -> ", i
.first
.toLogString().c_str());
647 for(const auto& j
: i
.second
.d_collection
)
649 // typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
650 fprintf(fp
.get(), "%s/%f ", j
.first
.toString().c_str(), j
.second
.peek());
652 fprintf(fp
.get(), "\n");
657 uint64_t SyncRes::doDumpThrottleMap(int fd
)
663 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(newfd
, "w"), fclose
);
668 fprintf(fp
.get(), "; throttle map dump follows\n");
669 fprintf(fp
.get(), "; remote IP\tqname\tqtype\tcount\tttd\n");
672 const auto& throttleMap
= t_sstorage
.throttle
.getThrottleMap();
673 for(const auto& i
: throttleMap
)
677 // remote IP, dns name, qtype, count, ttd
678 fprintf(fp
.get(), "%s\t%s\t%d\t%u\t%s", std::get
<0>(i
.thing
).toString().c_str(), std::get
<1>(i
.thing
).toLogString().c_str(), std::get
<2>(i
.thing
), i
.count
, ctime_r(&i
.ttd
, tmp
));
684 uint64_t SyncRes::doDumpFailedServers(int fd
)
690 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(newfd
, "w"), fclose
);
695 fprintf(fp
.get(), "; failed servers dump follows\n");
696 fprintf(fp
.get(), "; remote IP\tcount\ttimestamp\n");
699 // We get a copy, so the I/O does not need to happen while holding the lock
700 for (const auto& i
: s_fails
.lock()->getMapCopy())
704 ctime_r(&i
.last
, tmp
);
705 fprintf(fp
.get(), "%s\t%llu\t%s", i
.key
.toString().c_str(), i
.value
, tmp
);
711 uint64_t SyncRes::doDumpNonResolvingNS(int fd
)
717 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(newfd
, "w"), fclose
);
722 fprintf(fp
.get(), "; non-resolving nameserver dump follows\n");
723 fprintf(fp
.get(), "; name\tcount\ttimestamp\n");
726 // We get a copy, so the I/O does not need to happen while holding the lock
727 for (const auto& i
: s_nonresolving
.lock()->getMapCopy())
731 ctime_r(&i
.last
, tmp
);
732 fprintf(fp
.get(), "%s\t%llu\t%s", i
.key
.toString().c_str(), i
.value
, tmp
);
738 /* so here is the story. First we complete the full resolution process for a domain name. And only THEN do we decide
739 to also do DNSSEC validation, which leads to new queries. To make this simple, we *always* ask for DNSSEC records
740 so that if there are RRSIGs for a name, we'll have them.
742 However, some hosts simply can't answer questions which ask for DNSSEC. This can manifest itself as:
747 The cause of "No answer" may be fragmentation, and it is tempting to probe if smaller answers would get through.
748 Another cause of "No answer" may simply be a network condition.
749 Nonsense answers are a clearer indication this host won't be able to do DNSSEC evah.
751 Previous implementations have suffered from turning off DNSSEC questions for an authoritative server based on timeouts.
752 A clever idea is to only turn off DNSSEC if we know a domain isn't signed anyhow. The problem with that really
753 clever idea however is that at this point in PowerDNS, we may simply not know that yet. All the DNSSEC thinking happens
754 elsewhere. It may not have happened yet.
756 For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish.
759 LWResult::Result
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 DNSName
& nsName
) const
761 /* what is your QUEST?
762 the goal is to get as many remotes as possible on the highest level of EDNS support
765 0) UNKNOWN Unknown state
766 1) EDNS: Honors EDNS0
767 2) EDNSIGNORANT: Ignores EDNS0, gives replies without EDNS0
768 3) NOEDNS: Generates FORMERR on EDNS queries
770 Everybody starts out assumed to be '0'.
771 If '0', send out EDNS0
772 If you FORMERR us, go to '3',
773 If no EDNS in response, go to '2'
774 If '1', send out EDNS0
775 If FORMERR, downgrade to 3
776 If '2', keep on including EDNS0, see what happens
778 If '3', send bare queries
781 auto ednsstatus
= t_sstorage
.ednsstatus
.insert(ip
).first
; // does this include port? YES
782 auto &ind
= t_sstorage
.ednsstatus
.get
<ComboAddress
>();
783 if (ednsstatus
->modeSetAt
&& ednsstatus
->modeSetAt
+ 3600 < d_now
.tv_sec
) {
784 t_sstorage
.ednsstatus
.reset(ind
, ednsstatus
);
785 // cerr<<"Resetting EDNS Status for "<<ip.toString()<<endl);
788 const SyncRes::EDNSStatus::EDNSMode
*mode
= &ednsstatus
->mode
;
789 const SyncRes::EDNSStatus::EDNSMode oldmode
= *mode
;
791 auto luaconfsLocal
= g_luaconfs
.getLocal();
793 ctx
.d_initialRequestId
= d_initialRequestId
;
794 ctx
.d_nsName
= nsName
;
799 LWResult::Result ret
;
800 for(int tries
= 0; tries
< 3; ++tries
) {
801 // cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl;
803 if (*mode
== EDNSStatus::NOEDNS
) {
804 g_stats
.noEdnsOutQueries
++;
805 EDNSLevel
= 0; // level != mode
807 else if (ednsMANDATORY
|| *mode
== EDNSStatus::UNKNOWN
|| *mode
== EDNSStatus::EDNSOK
|| *mode
== EDNSStatus::EDNSIGNORANT
)
810 DNSName
sendQname(domain
);
811 if (g_lowercaseOutgoing
)
812 sendQname
.makeUsLowerCase();
814 if (d_asyncResolve
) {
815 ret
= d_asyncResolve(ip
, sendQname
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, res
, chained
);
818 ret
= asyncresolve(ip
, sendQname
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, d_outgoingProtobufServers
, d_frameStreamServers
, luaconfsLocal
->outgoingProtobufExportConfig
.exportTypes
, res
, chained
);
820 // ednsstatus might be cleared, so do a new lookup
821 ednsstatus
= t_sstorage
.ednsstatus
.insert(ip
).first
;
822 mode
= &ednsstatus
->mode
;
823 if (ret
== LWResult::Result::PermanentError
|| ret
== LWResult::Result::OSLimitError
|| ret
== LWResult::Result::Spoofed
) {
824 return ret
; // transport error, nothing to learn here
827 if (ret
== LWResult::Result::Timeout
) { // timeout, not doing anything with it now
830 else if (*mode
== EDNSStatus::UNKNOWN
|| *mode
== EDNSStatus::EDNSOK
|| *mode
== EDNSStatus::EDNSIGNORANT
) {
831 if(res
->d_validpacket
&& !res
->d_haveEDNS
&& res
->d_rcode
== RCode::FormErr
) {
832 // cerr<<"Downgrading to NOEDNS because of "<<RCode::to_s(res->d_rcode)<<" for query to "<<ip.toString()<<" for '"<<domain<<"'"<<endl;
833 t_sstorage
.ednsstatus
.setMode(ind
, ednsstatus
, EDNSStatus::NOEDNS
);
836 else if(!res
->d_haveEDNS
) {
837 if (*mode
!= EDNSStatus::EDNSIGNORANT
) {
838 t_sstorage
.ednsstatus
.setMode(ind
, ednsstatus
, EDNSStatus::EDNSIGNORANT
);
839 // cerr<<"We find that "<<ip.toString()<<" is an EDNS-ignorer for '"<<domain<<"', moving to mode 2"<<endl;
843 t_sstorage
.ednsstatus
.setMode(ind
, ednsstatus
, EDNSStatus::EDNSOK
);
844 // cerr<<"We find that "<<ip.toString()<<" is EDNS OK!"<<endl;
848 if (oldmode
!= *mode
|| !ednsstatus
->modeSetAt
) {
849 t_sstorage
.ednsstatus
.setTS(ind
, ednsstatus
, d_now
.tv_sec
);
851 // cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", new mode: "<<mode<<endl;
852 return LWResult::Result::Success
;
857 #define QLOG(x) LOG(prefix << " child=" << child << ": " << x << endl)
859 /* The parameters from rfc9156. */
860 /* maximum number of QNAME minimisation iterations */
861 static const unsigned int s_max_minimise_count
= 10;
862 /* number of queries that should only have one label appended */
863 static const unsigned int s_minimise_one_lab
= 4;
865 static unsigned int qmStepLen(unsigned int labels
, unsigned int qnamelen
, unsigned int i
)
869 if (i
< s_minimise_one_lab
) {
871 } else if (i
< s_max_minimise_count
) {
872 step
= std::max(1U, (qnamelen
- labels
) / (10 - i
));
874 step
= qnamelen
- labels
;
876 unsigned int targetlen
= std::min(labels
+ step
, qnamelen
);
880 int SyncRes::doResolve(const DNSName
&qname
, const QType qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, vState
& state
) {
882 string prefix
= d_prefix
;
883 prefix
.append(depth
, ' ');
884 auto luaconfsLocal
= g_luaconfs
.getLocal();
886 /* Apply qname (including CNAME chain) filtering policies */
887 if (d_wantsRPZ
&& !d_appliedPolicy
.wasHit()) {
888 if (luaconfsLocal
->dfe
.getQueryPolicy(qname
, d_discardedPolicies
, d_appliedPolicy
)) {
889 mergePolicyTags(d_policyTags
, d_appliedPolicy
.getTags());
891 int rcode
= RCode::NoError
;
892 handlePolicyHit(prefix
, qname
, qtype
, ret
, done
, rcode
, depth
);
899 initZoneCutsFromTA(qname
);
901 // In the auth or recursive forward case, it does not make sense to do qname-minimization
902 if (!getQNameMinimization() || isRecursiveForwardOrAuth(qname
)) {
903 return doResolveNoQNameMinimization(qname
, qtype
, ret
, depth
, beenthere
, state
);
906 // The qname minimization algorithm is a simplified version of the one in RFC 7816 (bis).
907 // It could be simplified because the cache maintenance (both positive and negative)
908 // is already done by doResolveNoQNameMinimization().
910 // Sketch of algorithm:
912 // If result found: done
913 // Otherwise determine closes ancestor from cache data
914 // Repeat querying A, adding more labels of the original qname
915 // If we get a delegation continue at ancestor determination
916 // Until we have the full name.
918 // The algorithm starts with adding a single label per iteration, and
919 // moves to three labels per iteration after three iterations.
922 prefix
.append(string("QM ") + qname
.toString() + "|" + qtype
.toString());
926 // Look in cache only
927 vector
<DNSRecord
> retq
;
928 bool old
= setCacheOnly(true);
929 bool fromCache
= false;
930 // For cache peeking, we tell doResolveNoQNameMinimization not to consider the (non-recursive) forward case.
931 // Otherwise all queries in a forward domain will be forwarded, while we want to consult the cache.
932 // The out-of-band cases for doResolveNoQNameMinimization() should be reconsidered and redone some day.
933 int res
= doResolveNoQNameMinimization(qname
, qtype
, retq
, depth
, beenthere
, state
, &fromCache
, nullptr, false);
936 QLOG("Step0 Found in cache");
937 if (d_appliedPolicy
.d_type
!= DNSFilterEngine::PolicyType::None
&& (d_appliedPolicy
.d_kind
== DNSFilterEngine::PolicyKind::NXDOMAIN
|| d_appliedPolicy
.d_kind
== DNSFilterEngine::PolicyKind::NODATA
)) {
940 ret
.insert(ret
.end(), retq
.begin(), retq
.end());
944 QLOG("Step0 Not cached");
946 const unsigned int qnamelen
= qname
.countLabels();
948 DNSName
fwdomain(qname
);
949 const bool forwarded
= getBestAuthZone(&fwdomain
) != t_sstorage
.domainmap
->end();
951 QLOG("Step0 qname is in a forwarded domain " << fwdomain
);
954 for (unsigned int i
= 0; i
<= qnamelen
; ) {
957 vector
<DNSRecord
> bestns
;
958 DNSName
nsdomain(qname
);
959 if (qtype
== QType::DS
) {
962 // the two retries allow getBestNSFromCache&co to reprime the root
963 // hints, in case they ever go missing
964 for (int tries
= 0; tries
< 2 && bestns
.empty(); ++tries
) {
965 bool flawedNSSet
= false;
966 set
<GetBestNSAnswer
> beenthereIgnored
;
967 getBestNSFromCache(nsdomain
, qtype
, bestns
, &flawedNSSet
, depth
, beenthereIgnored
, boost::make_optional(forwarded
, fwdomain
));
973 if (bestns
.size() == 0) {
975 // Something terrible is wrong
976 QLOG("Step1 No ancestor found return ServFail");
977 return RCode::ServFail
;
981 QLOG("Step1 Ancestor from cache is " << bestns
[0].d_name
);
983 child
= bestns
[0].d_name
.isPartOf(fwdomain
) ? bestns
[0].d_name
: fwdomain
;
984 QLOG("Step1 Final Ancestor (using forwarding info) is " << child
);
986 child
= bestns
[0].d_name
;
989 for (; i
<= qnamelen
; i
++) {
991 unsigned int labels
= child
.countLabels();
992 unsigned int targetlen
= qmStepLen(labels
, qnamelen
, i
);
994 while (labels
< targetlen
) {
995 child
.prependRawLabel(qname
.getRawLabel(qnamelen
- labels
- 1));
998 // rfc9156 section-2.3, append labels if they start with an underscore
999 while (labels
< qnamelen
) {
1000 auto prependLabel
= qname
.getRawLabel(qnamelen
- labels
- 1);
1001 if (prependLabel
.at(0) != '_') {
1004 child
.prependRawLabel(prependLabel
);
1008 QLOG("Step2 New child");
1011 if (child
== qname
) {
1012 QLOG("Step3 Going to do final resolve");
1013 res
= doResolveNoQNameMinimization(qname
, qtype
, ret
, depth
, beenthere
, state
);
1014 QLOG("Step3 Final resolve: " << RCode::to_s(res
) << "/" << ret
.size());
1019 QLOG("Step4 Resolve A for child");
1020 bool oldFollowCNAME
= d_followCNAME
;
1021 d_followCNAME
= false;
1023 StopAtDelegation stopAtDelegation
= Stop
;
1024 res
= doResolveNoQNameMinimization(child
, QType::A
, retq
, depth
, beenthere
, state
, nullptr, &stopAtDelegation
);
1025 d_followCNAME
= oldFollowCNAME
;
1026 QLOG("Step4 Resolve A result is " << RCode::to_s(res
) << "/" << retq
.size() << "/" << stopAtDelegation
);
1027 if (stopAtDelegation
== Stopped
) {
1028 QLOG("Delegation seen, continue at step 1");
1032 if (res
!= RCode::NoError
) {
1033 // Case 5: unexpected answer
1034 QLOG("Step5: other rcode, last effort final resolve");
1035 setQNameMinimization(false);
1036 // We might have hit a depth level check, but we still want to allow some recursion levels in the fallback
1037 // no-qname-minimization case. This has the effect that a qname minimization fallback case might reach 150% of
1039 res
= doResolveNoQNameMinimization(qname
, qtype
, ret
, depth
/2, beenthere
, state
);
1041 if(res
== RCode::NoError
) {
1042 s_qnameminfallbacksuccess
++;
1045 QLOG("Step5 End resolve: " << RCode::to_s(res
) << "/" << ret
.size());
1051 // Should not be reached
1052 QLOG("Max iterations reached, return ServFail");
1053 return RCode::ServFail
;
1056 /*! This function will check the cache and go out to the internet if the answer is not in cache
1058 * \param qname The name we need an answer for
1060 * \param ret The vector of DNSRecords we need to fill with the answers
1061 * \param depth The recursion depth we are in
1063 * \param fromCache tells the caller the result came from the cache, may be nullptr
1064 * \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
1065 * \return DNS RCODE or -1 (Error)
1067 int SyncRes::doResolveNoQNameMinimization(const DNSName
&qname
, const QType qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, vState
& state
, bool *fromCache
, StopAtDelegation
*stopAtDelegation
, bool considerforwards
)
1072 prefix
.append(depth
, ' ');
1075 LOG(prefix
<<qname
<<": Wants "<< (d_doDNSSEC
? "" : "NO ") << "DNSSEC processing, "<<(d_requireAuthData
? "" : "NO ")<<"auth data in query for "<<qtype
<<endl
);
1077 if (s_maxdepth
&& depth
> s_maxdepth
) {
1078 string msg
= "More than " + std::to_string(s_maxdepth
) + " (max-recursion-depth) levels of recursion needed while resolving " + qname
.toLogString();
1079 LOG(prefix
<< qname
<< ": " << msg
<< endl
);
1080 throw ImmediateServFailException(msg
);
1084 // This is a difficult way of expressing "this is a normal query", i.e. not getRootNS.
1085 if(!(d_updatingRootNS
&& qtype
.getCode()==QType::NS
&& qname
.isRoot())) {
1086 if(d_cacheonly
) { // very limited OOB support
1088 LOG(prefix
<<qname
<<": Recursion not requested for '"<<qname
<<"|"<<qtype
<<"', peeking at auth/forward zones"<<endl
);
1089 DNSName
authname(qname
);
1090 domainmap_t::const_iterator iter
=getBestAuthZone(&authname
);
1091 if(iter
!= t_sstorage
.domainmap
->end()) {
1092 if(iter
->second
.isAuth()) {
1094 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, ret
, depth
, res
);
1096 *fromCache
= d_wasOutOfBand
;
1099 else if (considerforwards
) {
1100 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
1101 const ComboAddress remoteIP
= servers
.front();
1102 LOG(prefix
<<qname
<<": forwarding query to hardcoded nameserver '"<< remoteIP
.toStringWithPort()<<"' for zone '"<<authname
<<"'"<<endl
);
1104 boost::optional
<Netmask
> nm
;
1105 bool chained
= false;
1106 // forwardes are "anonymous", so plug in an empty name; some day we might have a fancier config language...
1107 auto resolveRet
= asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, authname
, qtype
.getCode(), false, false, &d_now
, nm
, &lwr
, &chained
, DNSName());
1109 d_totUsec
+= lwr
.d_usec
;
1110 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
1114 // filter out the good stuff from lwr.result()
1115 if (resolveRet
== LWResult::Result::Success
) {
1116 for(const auto& rec
: lwr
.d_records
) {
1117 if(rec
.d_place
== DNSResourceRecord::ANSWER
)
1123 return RCode::ServFail
;
1129 DNSName
authname(qname
);
1130 bool wasForwardedOrAuthZone
= false;
1131 bool wasAuthZone
= false;
1132 bool wasForwardRecurse
= false;
1133 domainmap_t::const_iterator iter
= getBestAuthZone(&authname
);
1134 if(iter
!= t_sstorage
.domainmap
->end()) {
1135 const auto& domain
= iter
->second
;
1136 wasForwardedOrAuthZone
= true;
1138 if (domain
.isAuth()) {
1140 } else if (domain
.shouldRecurse()) {
1141 wasForwardRecurse
= true;
1145 /* When we are looking for a DS, we want to the non-CNAME cache check first
1146 because we can actually have a DS (from the parent zone) AND a CNAME (from
1147 the child zone), and what we really want is the DS */
1148 if (qtype
!= QType::DS
&& doCNAMECacheCheck(qname
, qtype
, ret
, depth
, res
, state
, wasAuthZone
, wasForwardRecurse
)) { // will reroute us if needed
1149 d_wasOutOfBand
= wasAuthZone
;
1150 // Here we have an issue. If we were prevented from going out to the network (cache-only was set, possibly because we
1151 // are in QM Step0) we might have a CNAME but not the corresponding target.
1152 // It means that we will sometimes go to the next steps when we are in fact done, but that's fine since
1153 // we will get the records from the cache, resulting in a small overhead.
1154 // This might be a real problem if we had a RPZ hit, though, because we do not want the processing to continue, since
1155 // RPZ rules will not be evaluated anymore (we already matched).
1156 const bool stoppedByPolicyHit
= d_appliedPolicy
.wasHit();
1158 if (fromCache
&& (!d_cacheonly
|| stoppedByPolicyHit
)) {
1161 /* Apply Post filtering policies */
1163 if (d_wantsRPZ
&& !stoppedByPolicyHit
) {
1164 auto luaLocal
= g_luaconfs
.getLocal();
1165 if (luaLocal
->dfe
.getPostPolicy(ret
, d_discardedPolicies
, d_appliedPolicy
)) {
1166 mergePolicyTags(d_policyTags
, d_appliedPolicy
.getTags());
1168 handlePolicyHit(prefix
, qname
, qtype
, ret
, done
, res
, depth
);
1169 if (done
&& fromCache
) {
1178 if (doCacheCheck(qname
, authname
, wasForwardedOrAuthZone
, wasAuthZone
, wasForwardRecurse
, qtype
, ret
, depth
, res
, state
)) {
1180 d_wasOutOfBand
= wasAuthZone
;
1185 if (d_wantsRPZ
&& !d_appliedPolicy
.wasHit()) {
1186 auto luaLocal
= g_luaconfs
.getLocal();
1187 if (luaLocal
->dfe
.getPostPolicy(ret
, d_discardedPolicies
, d_appliedPolicy
)) {
1188 mergePolicyTags(d_policyTags
, d_appliedPolicy
.getTags());
1190 handlePolicyHit(prefix
, qname
, qtype
, ret
, done
, res
, depth
);
1197 /* if we have not found a cached DS (or denial of), now is the time to look for a CNAME */
1198 if (qtype
== QType::DS
&& doCNAMECacheCheck(qname
, qtype
, ret
, depth
, res
, state
, wasAuthZone
, wasForwardRecurse
)) { // will reroute us if needed
1199 d_wasOutOfBand
= wasAuthZone
;
1200 // Here we have an issue. If we were prevented from going out to the network (cache-only was set, possibly because we
1201 // are in QM Step0) we might have a CNAME but not the corresponding target.
1202 // It means that we will sometimes go to the next steps when we are in fact done, but that's fine since
1203 // we will get the records from the cache, resulting in a small overhead.
1204 // This might be a real problem if we had a RPZ hit, though, because we do not want the processing to continue, since
1205 // RPZ rules will not be evaluated anymore (we already matched).
1206 const bool stoppedByPolicyHit
= d_appliedPolicy
.wasHit();
1208 if (fromCache
&& (!d_cacheonly
|| stoppedByPolicyHit
)) {
1211 /* Apply Post filtering policies */
1213 if (d_wantsRPZ
&& !stoppedByPolicyHit
) {
1214 auto luaLocal
= g_luaconfs
.getLocal();
1215 if (luaLocal
->dfe
.getPostPolicy(ret
, d_discardedPolicies
, d_appliedPolicy
)) {
1216 mergePolicyTags(d_policyTags
, d_appliedPolicy
.getTags());
1218 handlePolicyHit(prefix
, qname
, qtype
, ret
, done
, res
, depth
);
1219 if (done
&& fromCache
) {
1233 LOG(prefix
<<qname
<<": No cache hit for '"<<qname
<<"|"<<qtype
<<"', trying to find an appropriate NS record"<<endl
);
1235 DNSName
subdomain(qname
);
1236 if (qtype
== QType::DS
) subdomain
.chopOff();
1239 bool flawedNSSet
=false;
1241 // the two retries allow getBestNSNamesFromCache&co to reprime the root
1242 // hints, in case they ever go missing
1243 for(int tries
=0;tries
<2 && nsset
.empty();++tries
) {
1244 subdomain
=getBestNSNamesFromCache(subdomain
, qtype
, nsset
, &flawedNSSet
, depth
, beenthere
); // pass beenthere to both occasions
1247 res
= doResolveAt(nsset
, subdomain
, flawedNSSet
, qname
, qtype
, ret
, depth
, beenthere
, state
, stopAtDelegation
);
1249 /* Apply Post filtering policies */
1250 if (d_wantsRPZ
&& !d_appliedPolicy
.wasHit()) {
1251 auto luaLocal
= g_luaconfs
.getLocal();
1252 if (luaLocal
->dfe
.getPostPolicy(ret
, d_discardedPolicies
, d_appliedPolicy
)) {
1253 mergePolicyTags(d_policyTags
, d_appliedPolicy
.getTags());
1255 handlePolicyHit(prefix
, qname
, qtype
, ret
, done
, res
, depth
);
1263 LOG(prefix
<<qname
<<": failed (res="<<res
<<")"<<endl
);
1265 return res
<0 ? RCode::ServFail
: res
;
1269 // for testing purposes
1270 static bool ipv6First(const ComboAddress
& a
, const ComboAddress
& b
)
1272 return !(a
.sin4
.sin_family
< a
.sin4
.sin_family
);
1278 speedOrderCA(std::map
<ComboAddress
,float>& speeds
): d_speeds(speeds
) {}
1279 bool operator()(const ComboAddress
& a
, const ComboAddress
& b
) const
1281 return d_speeds
[a
] < d_speeds
[b
];
1283 std::map
<ComboAddress
, float>& d_speeds
;
1286 /** This function explicitly goes out for A or AAAA addresses
1288 vector
<ComboAddress
> SyncRes::getAddrs(const DNSName
&qname
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, bool cacheOnly
, unsigned int& addressQueriesForNS
)
1290 typedef vector
<DNSRecord
> res_t
;
1291 typedef vector
<ComboAddress
> ret_t
;
1294 bool oldCacheOnly
= setCacheOnly(cacheOnly
);
1295 bool oldRequireAuthData
= d_requireAuthData
;
1296 bool oldValidationRequested
= d_DNSSECValidationRequested
;
1297 bool oldFollowCNAME
= d_followCNAME
;
1298 bool seenV6
= false;
1299 const unsigned int startqueries
= d_outqueries
;
1300 d_requireAuthData
= false;
1301 d_DNSSECValidationRequested
= false;
1302 d_followCNAME
= true;
1305 // First look for both A and AAAA in the cache
1307 if (s_doIPv4
&& g_recCache
->get(d_now
.tv_sec
, qname
, QType::A
, false, &cset
, d_cacheRemote
, false, d_routingTag
) > 0) {
1308 for (const auto &i
: cset
) {
1309 if (auto rec
= getRR
<ARecordContent
>(i
)) {
1310 ret
.push_back(rec
->getCA(53));
1314 if (s_doIPv6
&& g_recCache
->get(d_now
.tv_sec
, qname
, QType::AAAA
, false, &cset
, d_cacheRemote
, false, d_routingTag
) > 0) {
1315 for (const auto &i
: cset
) {
1316 if (auto rec
= getRR
<AAAARecordContent
>(i
)) {
1318 ret
.push_back(rec
->getCA(53));
1323 // Neither A nor AAAA in the cache...
1324 vState newState
= vState::Indeterminate
;
1326 // Go out to get A's
1327 if (s_doIPv4
&& doResolve(qname
, QType::A
, cset
, depth
+1, beenthere
, newState
) == 0) { // this consults cache, OR goes out
1328 for (auto const &i
: cset
) {
1329 if (i
.d_type
== QType::A
) {
1330 if (auto rec
= getRR
<ARecordContent
>(i
)) {
1331 ret
.push_back(rec
->getCA(53));
1336 if (s_doIPv6
) { // s_doIPv6 **IMPLIES** pdns::isQueryLocalAddressFamilyEnabled(AF_INET6) returned true
1338 // We only go out immediately to find IPv6 records if we did not find any IPv4 ones.
1339 newState
= vState::Indeterminate
;
1341 if (doResolve(qname
, QType::AAAA
, cset
, depth
+1, beenthere
, newState
) == 0) { // this consults cache, OR goes out
1342 for (const auto &i
: cset
) {
1343 if (i
.d_type
== QType::AAAA
) {
1344 if (auto rec
= getRR
<AAAARecordContent
>(i
)) {
1346 ret
.push_back(rec
->getCA(53));
1352 // We have some IPv4 records, consult the cache, we might have encountered some IPv6 glue
1354 if (g_recCache
->get(d_now
.tv_sec
, qname
, QType::AAAA
, false, &cset
, d_cacheRemote
, false, d_routingTag
) > 0) {
1355 for (const auto &i
: cset
) {
1356 if (auto rec
= getRR
<AAAARecordContent
>(i
)) {
1358 ret
.push_back(rec
->getCA(53));
1365 if (s_doIPv6
&& !seenV6
&& !cacheOnly
) {
1366 // No IPv6 records in cache, check negcache and submit async task if negache does not have the data
1367 // so that the next time the cache or the negcache will have data
1368 NegCache::NegCacheEntry ne
;
1369 bool inNegCache
= g_negCache
->get(qname
, QType::AAAA
, d_now
, ne
, true);
1371 pushResolveTask(qname
, QType::AAAA
, d_now
.tv_sec
, d_now
.tv_sec
+ 60);
1375 catch (const PolicyHitException
&) {
1376 // We ignore a policy hit while trying to retrieve the addresses
1377 // of a NS and keep processing the current query
1380 if (ret
.empty() && d_outqueries
> startqueries
) {
1381 // We did 1 or more outgoing queries to resolve this NS name but returned empty handed
1382 addressQueriesForNS
++;
1384 d_requireAuthData
= oldRequireAuthData
;
1385 d_DNSSECValidationRequested
= oldValidationRequested
;
1386 setCacheOnly(oldCacheOnly
);
1387 d_followCNAME
= oldFollowCNAME
;
1389 /* we need to remove from the nsSpeeds collection the existing IPs
1390 for this nameserver that are no longer in the set, even if there
1391 is only one or none at all in the current set.
1393 map
<ComboAddress
, float> speeds
;
1394 auto& collection
= t_sstorage
.nsSpeeds
[qname
];
1395 float factor
= collection
.getFactor(d_now
);
1396 for(const auto& val
: ret
) {
1397 speeds
[val
] = collection
.d_collection
[val
].get(factor
);
1400 t_sstorage
.nsSpeeds
[qname
].purge(speeds
);
1402 if (ret
.size() > 1) {
1403 shuffle(ret
.begin(), ret
.end(), pdns::dns_random_engine());
1404 speedOrderCA
so(speeds
);
1405 stable_sort(ret
.begin(), ret
.end(), so
);
1409 string prefix
=d_prefix
;
1410 prefix
.append(depth
, ' ');
1411 LOG(prefix
<<"Nameserver "<<qname
<<" IPs: ");
1413 for(const auto& addr
: ret
) {
1420 LOG((addr
.toString())<<"(" << fmtfloat("%0.2f", speeds
[addr
]/1000.0) <<"ms)");
1428 void SyncRes::getBestNSFromCache(const DNSName
&qname
, const QType qtype
, vector
<DNSRecord
>& bestns
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, const boost::optional
<DNSName
>& cutOffDomain
)
1431 DNSName
subdomain(qname
);
1434 prefix
.append(depth
, ' ');
1439 if (cutOffDomain
&& (subdomain
== *cutOffDomain
|| !subdomain
.isPartOf(*cutOffDomain
))) {
1443 LOG(prefix
<<qname
<<": Checking if we have NS in cache for '"<<subdomain
<<"'"<<endl
);
1444 vector
<DNSRecord
> ns
;
1445 *flawedNSSet
= false;
1447 if(g_recCache
->get(d_now
.tv_sec
, subdomain
, QType::NS
, false, &ns
, d_cacheRemote
, false, d_routingTag
) > 0) {
1448 bestns
.reserve(ns
.size());
1450 for(auto k
=ns
.cbegin();k
!=ns
.cend(); ++k
) {
1451 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
1452 vector
<DNSRecord
> aset
;
1453 QType nsqt
{QType::ADDR
};
1454 if (s_doIPv4
&& !s_doIPv6
) {
1456 } else if (!s_doIPv4
&& s_doIPv6
) {
1460 const DNSRecord
& dr
=*k
;
1461 auto nrr
= getRR
<NSRecordContent
>(dr
);
1462 if(nrr
&& (!nrr
->getNS().isPartOf(subdomain
) || g_recCache
->get(d_now
.tv_sec
, nrr
->getNS(), nsqt
,
1463 false, doLog() ? &aset
: 0, d_cacheRemote
, false, d_routingTag
) > 5)) {
1464 bestns
.push_back(dr
);
1465 LOG(prefix
<<qname
<<": NS (with ip, or non-glue) in cache for '"<<subdomain
<<"' -> '"<<nrr
->getNS()<<"'"<<endl
);
1466 LOG(prefix
<<qname
<<": within bailiwick: "<< nrr
->getNS().isPartOf(subdomain
));
1468 LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset
.begin()->d_ttl
- d_now
.tv_sec
))<<endl
);
1471 LOG(", not in cache / did not look at cache"<<endl
);
1476 LOG(prefix
<<qname
<<": NS in cache for '"<<subdomain
<<"', but needs glue ("<<nrr
->getNS()<<") which we miss or is expired"<<endl
);
1481 if(!bestns
.empty()) {
1482 GetBestNSAnswer answer
;
1484 answer
.qtype
=qtype
.getCode();
1485 for(const auto& dr
: bestns
) {
1486 if (auto nsContent
= getRR
<NSRecordContent
>(dr
)) {
1487 answer
.bestns
.emplace(dr
.d_name
, nsContent
->getNS());
1491 auto insertionPair
= beenthere
.insert(std::move(answer
));
1492 if(!insertionPair
.second
) {
1494 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' but part of LOOP (already seen "<<answer
.qname
<<")! Trying less specific NS"<<endl
);
1497 for( set
<GetBestNSAnswer
>::const_iterator j
=beenthere
.begin();j
!=beenthere
.end();++j
) {
1498 bool neo
= (j
== insertionPair
.first
);
1499 LOG(prefix
<<qname
<<": beenthere"<<(neo
?"*":"")<<": "<<j
->qname
<<"|"<<DNSRecordContent::NumberToType(j
->qtype
)<<" ("<<(unsigned int)j
->bestns
.size()<<")"<<endl
);
1504 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' (flawedNSSet="<<*flawedNSSet
<<")"<<endl
);
1509 LOG(prefix
<<qname
<<": no valid/useful NS in cache for '"<<subdomain
<<"'"<<endl
);
1511 if(subdomain
.isRoot() && !brokeloop
) {
1512 // We lost the root NS records
1514 LOG(prefix
<<qname
<<": reprimed the root"<<endl
);
1515 /* let's prevent an infinite loop */
1516 if (!d_updatingRootNS
) {
1517 primeRootNSZones(g_dnssecmode
, depth
);
1518 getRootNS(d_now
, d_asyncResolve
, depth
);
1521 } while(subdomain
.chopOff());
1524 SyncRes::domainmap_t::const_iterator
SyncRes::getBestAuthZone(DNSName
* qname
) const
1526 if (t_sstorage
.domainmap
->empty()) {
1527 return t_sstorage
.domainmap
->end();
1530 SyncRes::domainmap_t::const_iterator ret
;
1532 ret
=t_sstorage
.domainmap
->find(*qname
);
1533 if(ret
!=t_sstorage
.domainmap
->end())
1535 }while(qname
->chopOff());
1539 /** doesn't actually do the work, leaves that to getBestNSFromCache */
1540 DNSName
SyncRes::getBestNSNamesFromCache(const DNSName
&qname
, const QType qtype
, NsSet
& nsset
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
)
1545 prefix
.append(depth
, ' ');
1547 DNSName
authOrForwDomain(qname
);
1549 domainmap_t::const_iterator iter
= getBestAuthZone(&authOrForwDomain
);
1550 // We have an auth, forwarder of forwarder-recurse
1551 if (iter
!= t_sstorage
.domainmap
->end()) {
1552 if (iter
->second
.isAuth()) {
1553 // this gets picked up in doResolveAt, the empty DNSName, combined with the
1554 // empty vector means 'we are auth for this zone'
1555 nsset
.insert({DNSName(), {{}, false}});
1556 return authOrForwDomain
;
1559 if (iter
->second
.shouldRecurse()) {
1560 // Again, picked up in doResolveAt. An empty DNSName, combined with a
1561 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
1562 // This is actually picked up in retrieveAddressesForNS called from doResolveAt.
1563 nsset
.insert({DNSName(), {iter
->second
.d_servers
, true }});
1564 return authOrForwDomain
;
1569 // We might have a (non-recursive) forwarder, but maybe the cache already contains
1571 vector
<DNSRecord
> bestns
;
1572 DNSName
nsFromCacheDomain(g_rootdnsname
);
1573 getBestNSFromCache(qname
, qtype
, bestns
, flawedNSSet
, depth
, beenthere
);
1575 // Pick up the auth domain
1576 for (const auto& k
: bestns
) {
1577 const auto nsContent
= getRR
<NSRecordContent
>(k
);
1579 nsFromCacheDomain
= k
.d_name
;
1584 if (iter
!= t_sstorage
.domainmap
->end()) {
1586 LOG(prefix
<< qname
<< " authOrForwDomain: " << authOrForwDomain
<< " nsFromCacheDomain: " << nsFromCacheDomain
<< " isPartof: " << authOrForwDomain
.isPartOf(nsFromCacheDomain
) << endl
);
1589 // If the forwarder is better or equal to what's found in the cache, use forwarder. Note that name.isPartOf(name).
1590 // So queries that get NS for authOrForwDomain itself go to the forwarder
1591 if (authOrForwDomain
.isPartOf(nsFromCacheDomain
)) {
1593 LOG(prefix
<< qname
<< ": using forwarder as NS" << endl
);
1595 nsset
.insert({DNSName(), {iter
->second
.d_servers
, false }});
1596 return authOrForwDomain
;
1599 LOG(prefix
<< qname
<< ": using NS from cache" << endl
);
1603 for (auto k
= bestns
.cbegin(); k
!= bestns
.cend(); ++k
) {
1604 // The actual resolver code will not even look at the ComboAddress or bool
1605 const auto nsContent
= getRR
<NSRecordContent
>(*k
);
1607 nsset
.insert({nsContent
->getNS(), {{}, false}});
1610 return nsFromCacheDomain
;
1613 void SyncRes::updateValidationStatusInCache(const DNSName
&qname
, const QType qt
, bool aa
, vState newState
) const
1615 if (qt
== QType::ANY
|| qt
== QType::ADDR
) {
1620 if (vStateIsBogus(newState
)) {
1621 g_recCache
->updateValidationStatus(d_now
.tv_sec
, qname
, qt
, d_cacheRemote
, d_routingTag
, aa
, newState
, s_maxbogusttl
+ d_now
.tv_sec
);
1624 g_recCache
->updateValidationStatus(d_now
.tv_sec
, qname
, qt
, d_cacheRemote
, d_routingTag
, aa
, newState
, boost::none
);
1628 static bool scanForCNAMELoop(const DNSName
& name
, const vector
<DNSRecord
>& records
)
1630 for (const auto& record
: records
) {
1631 if (record
.d_type
== QType::CNAME
&& record
.d_place
== DNSResourceRecord::ANSWER
) {
1632 if (name
== record
.d_name
) {
1640 bool SyncRes::doCNAMECacheCheck(const DNSName
&qname
, const QType qtype
, vector
<DNSRecord
>& ret
, unsigned int depth
, int &res
, vState
& state
, bool wasAuthZone
, bool wasForwardRecurse
)
1645 prefix
.append(depth
, ' ');
1648 if((depth
>9 && d_outqueries
>10 && d_throttledqueries
>5) || depth
> 15) {
1649 LOG(prefix
<<qname
<<": recursing (CNAME or other indirection) too deep, depth="<<depth
<<endl
);
1650 res
=RCode::ServFail
;
1654 vector
<DNSRecord
> cset
;
1655 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
1656 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1658 uint32_t capTTL
= std::numeric_limits
<uint32_t>::max();
1661 QType foundQT
= QType::ENT
;
1663 /* we don't require auth data for forward-recurse lookups */
1664 if (g_recCache
->get(d_now
.tv_sec
, qname
, QType::CNAME
, !wasForwardRecurse
&& d_requireAuthData
, &cset
, d_cacheRemote
, d_refresh
, d_routingTag
, d_doDNSSEC
? &signatures
: nullptr, d_doDNSSEC
? &authorityRecs
: nullptr, &d_wasVariable
, &state
, &wasAuth
, &authZone
, &d_fromAuthIP
) > 0) {
1666 foundQT
= QType::CNAME
;
1669 if (foundName
.empty() && qname
!= g_rootdnsname
) {
1670 // look for a DNAME cache hit
1671 auto labels
= qname
.getRawLabels();
1672 DNSName
dnameName(g_rootdnsname
);
1675 dnameName
.prependRawLabel(labels
.back());
1677 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
1680 if (g_recCache
->get(d_now
.tv_sec
, dnameName
, QType::DNAME
, !wasForwardRecurse
&& d_requireAuthData
, &cset
, d_cacheRemote
, d_refresh
, d_routingTag
, d_doDNSSEC
? &signatures
: nullptr, d_doDNSSEC
? &authorityRecs
: nullptr, &d_wasVariable
, &state
, &wasAuth
, &authZone
, &d_fromAuthIP
) > 0) {
1681 foundName
= dnameName
;
1682 foundQT
= QType::DNAME
;
1685 } while(!labels
.empty());
1688 if (foundName
.empty()) {
1692 if (qtype
== QType::DS
&& authZone
== qname
) {
1693 /* CNAME at APEX of the child zone, we can't use that to prove that
1695 LOG(prefix
<<qname
<<": Found a "<<foundQT
.toString()<<" cache hit of '"<< qname
<<"' from "<<authZone
<<", but such a record at the apex of the child zone does not prove that there is no DS in the parent zone"<<endl
);
1699 for(auto const &record
: cset
) {
1700 if (record
.d_class
!= QClass::IN
) {
1704 if(record
.d_ttl
> (unsigned int) d_now
.tv_sec
) {
1706 if (!wasAuthZone
&& shouldValidate() && (wasAuth
|| wasForwardRecurse
) && state
== vState::Indeterminate
&& d_requireAuthData
) {
1707 /* This means we couldn't figure out the state when this entry was cached */
1709 vState recordState
= getValidationStatus(foundName
, !signatures
.empty(), qtype
== QType::DS
, depth
);
1710 if (recordState
== vState::Secure
) {
1711 LOG(prefix
<<qname
<<": got vState::Indeterminate state from the "<<foundQT
.toString()<<" cache, validating.."<<endl
);
1712 state
= SyncRes::validateRecordsWithSigs(depth
, qname
, qtype
, foundName
, foundQT
, cset
, signatures
);
1713 if (state
!= vState::Indeterminate
) {
1714 LOG(prefix
<<qname
<<": got vState::Indeterminate state from the "<<foundQT
.toString()<<" cache, new validation result is "<<state
<<endl
);
1715 if (vStateIsBogus(state
)) {
1716 capTTL
= s_maxbogusttl
;
1718 updateValidationStatusInCache(foundName
, foundQT
, wasAuth
, state
);
1723 LOG(prefix
<<qname
<<": Found cache "<<foundQT
.toString()<<" hit for '"<< foundName
<< "|"<<foundQT
.toString()<<"' to '"<<record
.d_content
->getZoneRepresentation()<<"', validation state is "<<state
<<endl
);
1725 DNSRecord dr
= record
;
1726 dr
.d_ttl
-= d_now
.tv_sec
;
1727 dr
.d_ttl
= std::min(dr
.d_ttl
, capTTL
);
1728 const uint32_t ttl
= dr
.d_ttl
;
1729 ret
.reserve(ret
.size() + 2 + signatures
.size() + authorityRecs
.size());
1732 for(const auto& signature
: signatures
) {
1734 sigdr
.d_type
=QType::RRSIG
;
1735 sigdr
.d_name
=foundName
;
1737 sigdr
.d_content
=signature
;
1738 sigdr
.d_place
=DNSResourceRecord::ANSWER
;
1739 sigdr
.d_class
=QClass::IN
;
1740 ret
.push_back(sigdr
);
1743 for(const auto& rec
: authorityRecs
) {
1744 DNSRecord
authDR(*rec
);
1746 ret
.push_back(authDR
);
1750 if (foundQT
== QType::DNAME
) {
1751 if (qtype
== QType::DNAME
&& qname
== foundName
) { // client wanted the DNAME, no need to synthesize a CNAME
1752 res
= RCode::NoError
;
1755 // Synthesize a CNAME
1756 auto dnameRR
= getRR
<DNAMERecordContent
>(record
);
1757 if (dnameRR
== nullptr) {
1758 throw ImmediateServFailException("Unable to get record content for "+foundName
.toLogString()+"|DNAME cache entry");
1760 const auto& dnameSuffix
= dnameRR
->getTarget();
1761 DNSName targetPrefix
= qname
.makeRelative(foundName
);
1763 dr
.d_type
= QType::CNAME
;
1764 dr
.d_name
= targetPrefix
+ foundName
;
1765 newTarget
= targetPrefix
+ dnameSuffix
;
1766 dr
.d_content
= std::make_shared
<CNAMERecordContent
>(CNAMERecordContent(newTarget
));
1768 } catch (const std::exception
&e
) {
1769 // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
1770 // But this is consistent with processRecords
1771 throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + foundName
.toLogString() +
1772 "', DNAME target: '" + dnameSuffix
.toLogString() + "', substituted name: '" +
1773 targetPrefix
.toLogString() + "." + dnameSuffix
.toLogString() +
1777 LOG(prefix
<<qname
<<": Synthesized "<<dr
.d_name
<<"|CNAME "<<newTarget
<<endl
);
1780 if(qtype
== QType::CNAME
) { // perhaps they really wanted a CNAME!
1781 res
= RCode::NoError
;
1785 if (qtype
== QType::DS
|| qtype
== QType::DNSKEY
) {
1786 res
= RCode::NoError
;
1790 // We have a DNAME _or_ CNAME cache hit and the client wants something else than those two.
1791 // Let's find the answer!
1792 if (foundQT
== QType::CNAME
) {
1793 const auto cnameContent
= getRR
<CNAMERecordContent
>(record
);
1794 if (cnameContent
== nullptr) {
1795 throw ImmediateServFailException("Unable to get record content for "+foundName
.toLogString()+"|CNAME cache entry");
1797 newTarget
= cnameContent
->getTarget();
1800 if (qname
== newTarget
) {
1801 string msg
= "got a CNAME referral (from cache) to self";
1802 LOG(prefix
<<qname
<<": "<<msg
<<endl
);
1803 throw ImmediateServFailException(msg
);
1806 if (newTarget
.isPartOf(qname
)) {
1807 // a.b.c. CNAME x.a.b.c will go to great depths with QM on
1808 string msg
= "got a CNAME referral (from cache) to child, disabling QM";
1809 LOG(prefix
<<qname
<<": "<<msg
<<endl
);
1810 setQNameMinimization(false);
1813 if (!d_followCNAME
) {
1814 res
= RCode::NoError
;
1818 // Check to see if we already have seen the new target as a previous target
1819 if (scanForCNAMELoop(newTarget
, ret
)) {
1820 string msg
= "got a CNAME referral (from cache) that causes a loop";
1821 LOG(prefix
<<qname
<<": status="<<msg
<<endl
);
1822 throw ImmediateServFailException(msg
);
1825 set
<GetBestNSAnswer
>beenthere
;
1826 vState cnameState
= vState::Indeterminate
;
1827 // Be aware that going out on the network might be disabled (cache-only), for example because we are in QM Step0,
1828 // so you can't trust that a real lookup will have been made.
1829 res
= doResolve(newTarget
, qtype
, ret
, depth
+1, beenthere
, cnameState
);
1830 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<state
<<" with the state from the DNAME/CNAME quest: "<<cnameState
<<endl
);
1831 updateValidationState(state
, cnameState
);
1836 throw ImmediateServFailException("Could not determine whether or not there was a CNAME or DNAME in cache for '" + qname
.toLogString() + "'");
1842 vector
<DNSRecord
> records
;
1843 vector
<shared_ptr
<RRSIGRecordContent
>> signatures
;
1844 uint32_t signaturesTTL
{std::numeric_limits
<uint32_t>::max()};
1850 DNSResourceRecord::Place place
;
1851 bool operator<(const CacheKey
& rhs
) const {
1852 return std::tie(type
, place
, name
) < std::tie(rhs
.type
, rhs
.place
, rhs
.name
);
1855 typedef map
<CacheKey
, CacheEntry
> tcache_t
;
1858 static void reapRecordsFromNegCacheEntryForValidation(tcache_t
& tcache
, const vector
<DNSRecord
>& records
)
1860 for (const auto& rec
: records
) {
1861 if (rec
.d_type
== QType::RRSIG
) {
1862 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1864 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
1867 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(rec
);
1872 static bool negativeCacheEntryHasSOA(const NegCache::NegCacheEntry
& ne
)
1874 return !ne
.authoritySOA
.records
.empty();
1877 static void reapRecordsForValidation(std::map
<QType
, CacheEntry
>& entries
, const vector
<DNSRecord
>& records
)
1879 for (const auto& rec
: records
) {
1880 entries
[rec
.d_type
].records
.push_back(rec
);
1884 static void reapSignaturesForValidation(std::map
<QType
, CacheEntry
>& entries
, const vector
<std::shared_ptr
<RRSIGRecordContent
>>& signatures
)
1886 for (const auto& sig
: signatures
) {
1887 entries
[sig
->d_type
].signatures
.push_back(sig
);
1892 * Convenience function to push the records from records into ret with a new TTL
1894 * \param records DNSRecords that need to go into ret
1895 * \param ttl The new TTL for these records
1896 * \param ret The vector of DNSRecords that should contain the records with the modified TTL
1898 static void addTTLModifiedRecords(vector
<DNSRecord
>& records
, const uint32_t ttl
, vector
<DNSRecord
>& ret
) {
1899 for (auto& rec
: records
) {
1901 ret
.push_back(std::move(rec
));
1905 void SyncRes::computeNegCacheValidationStatus(const NegCache::NegCacheEntry
& ne
, const DNSName
& qname
, const QType qtype
, const int res
, vState
& state
, unsigned int depth
)
1908 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.authoritySOA
.records
);
1909 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.authoritySOA
.signatures
);
1910 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.DNSSECRecords
.records
);
1911 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.DNSSECRecords
.signatures
);
1913 for (const auto& entry
: tcache
) {
1914 // this happens when we did store signatures, but passed on the records themselves
1915 if (entry
.second
.records
.empty()) {
1919 const DNSName
& owner
= entry
.first
.name
;
1921 vState recordState
= getValidationStatus(owner
, !entry
.second
.signatures
.empty(), qtype
== QType::DS
, depth
);
1922 if (state
== vState::Indeterminate
) {
1923 state
= recordState
;
1926 if (recordState
== vState::Secure
) {
1927 recordState
= SyncRes::validateRecordsWithSigs(depth
, qname
, qtype
, owner
, QType(entry
.first
.type
), entry
.second
.records
, entry
.second
.signatures
);
1930 if (recordState
!= vState::Indeterminate
&& recordState
!= state
) {
1931 updateValidationState(state
, recordState
);
1932 if (state
!= vState::Secure
) {
1938 if (state
== vState::Secure
) {
1939 vState neValidationState
= ne
.d_validationState
;
1940 dState expectedState
= res
== RCode::NXDomain
? dState::NXDOMAIN
: dState::NXQTYPE
;
1941 dState denialState
= getDenialValidationState(ne
, expectedState
, false);
1942 updateDenialValidationState(neValidationState
, ne
.d_name
, state
, denialState
, expectedState
, qtype
== QType::DS
, depth
);
1944 if (state
!= vState::Indeterminate
) {
1945 /* validation succeeded, let's update the cache entry so we don't have to validate again */
1946 boost::optional
<time_t> capTTD
= boost::none
;
1947 if (vStateIsBogus(state
)) {
1948 capTTD
= d_now
.tv_sec
+ s_maxbogusttl
;
1950 g_negCache
->updateValidationStatus(ne
.d_name
, ne
.d_qtype
, state
, capTTD
);
1954 bool SyncRes::doCacheCheck(const DNSName
&qname
, const DNSName
& authname
, bool wasForwardedOrAuthZone
, bool wasAuthZone
, bool wasForwardRecurse
, QType qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int &res
, vState
& state
)
1956 bool giveNegative
=false;
1961 prefix
.append(depth
, ' ');
1964 // 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)
1965 DNSName
sqname(qname
);
1968 // cout<<"Lookup for '"<<qname<<"|"<<qtype.toString()<<"' -> "<<getLastLabel(qname)<<endl;
1970 NegCache::NegCacheEntry ne
;
1973 g_negCache
->getRootNXTrust(qname
, d_now
, ne
) &&
1974 ne
.d_auth
.isRoot() &&
1975 !(wasForwardedOrAuthZone
&& !authname
.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
1976 sttl
= ne
.d_ttd
- d_now
.tv_sec
;
1977 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
.d_auth
<<"' & '"<<ne
.d_name
<<"' for another "<<sttl
<<" seconds"<<endl
);
1978 res
= RCode::NXDomain
;
1979 giveNegative
= true;
1980 cachedState
= ne
.d_validationState
;
1981 } else if (g_negCache
->get(qname
, qtype
, d_now
, ne
)) {
1982 /* If we are looking for a DS, discard NXD if auth == qname
1983 and ask for a specific denial instead */
1984 if (qtype
!= QType::DS
|| ne
.d_qtype
.getCode() || ne
.d_auth
!= qname
||
1985 g_negCache
->get(qname
, qtype
, d_now
, ne
, true))
1987 /* Careful! If the client is asking for a DS that does not exist, we need to provide the SOA along with the NSEC(3) proof
1988 and we might not have it if we picked up the proof from a delegation, in which case we need to keep on to do the actual DS
1990 if (qtype
== QType::DS
&& ne
.d_qtype
.getCode() && !d_externalDSQuery
.empty() && qname
== d_externalDSQuery
&& !negativeCacheEntryHasSOA(ne
)) {
1991 giveNegative
= false;
1994 res
= RCode::NXDomain
;
1995 sttl
= ne
.d_ttd
- d_now
.tv_sec
;
1996 giveNegative
= true;
1997 cachedState
= ne
.d_validationState
;
1998 if (ne
.d_qtype
.getCode()) {
1999 LOG(prefix
<<qname
<<": "<<qtype
<<" is negatively cached via '"<<ne
.d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
2000 res
= RCode::NoError
;
2002 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"' is negatively cached via '"<<ne
.d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
2006 } else if (s_hardenNXD
!= HardenNXD::No
&& !qname
.isRoot() && !wasForwardedOrAuthZone
) {
2007 auto labels
= qname
.getRawLabels();
2008 DNSName
negCacheName(g_rootdnsname
);
2009 negCacheName
.prependRawLabel(labels
.back());
2011 while(!labels
.empty()) {
2012 if (g_negCache
->get(negCacheName
, QType::ENT
, d_now
, ne
, true)) {
2013 if (ne
.d_validationState
== vState::Indeterminate
&& validationEnabled()) {
2014 // LOG(prefix << negCacheName << " negatively cached and vState::Indeterminate, trying to validate NXDOMAIN" << endl);
2016 // And get the updated ne struct
2017 //t_sstorage.negcache.get(negCacheName, QType(0), d_now, ne, true);
2019 if ((s_hardenNXD
== HardenNXD::Yes
&& !vStateIsBogus(ne
.d_validationState
)) || ne
.d_validationState
== vState::Secure
) {
2020 res
= RCode::NXDomain
;
2021 sttl
= ne
.d_ttd
- d_now
.tv_sec
;
2022 giveNegative
= true;
2023 cachedState
= ne
.d_validationState
;
2024 LOG(prefix
<<qname
<<": Name '"<<negCacheName
<<"' and below, is negatively cached via '"<<ne
.d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
2028 negCacheName
.prependRawLabel(labels
.back());
2035 state
= cachedState
;
2037 if (!wasAuthZone
&& shouldValidate() && state
== vState::Indeterminate
) {
2038 LOG(prefix
<<qname
<<": got vState::Indeterminate state for records retrieved from the negative cache, validating.."<<endl
);
2039 computeNegCacheValidationStatus(ne
, qname
, qtype
, res
, state
, depth
);
2041 if (state
!= cachedState
&& vStateIsBogus(state
)) {
2042 sttl
= std::min(sttl
, s_maxbogusttl
);
2046 // Transplant SOA to the returned packet
2047 addTTLModifiedRecords(ne
.authoritySOA
.records
, sttl
, ret
);
2049 addTTLModifiedRecords(ne
.authoritySOA
.signatures
, sttl
, ret
);
2050 addTTLModifiedRecords(ne
.DNSSECRecords
.records
, sttl
, ret
);
2051 addTTLModifiedRecords(ne
.DNSSECRecords
.signatures
, sttl
, ret
);
2054 LOG(prefix
<<qname
<<": updating validation state with negative cache content for "<<qname
<<" to "<<state
<<endl
);
2058 vector
<DNSRecord
> cset
;
2059 bool found
=false, expired
=false;
2060 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
2061 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
2063 uint32_t capTTL
= std::numeric_limits
<uint32_t>::max();
2066 if(g_recCache
->get(d_now
.tv_sec
, sqname
, sqt
, !wasForwardRecurse
&& d_requireAuthData
, &cset
, d_cacheRemote
, d_refresh
, d_routingTag
, d_doDNSSEC
? &signatures
: nullptr, d_doDNSSEC
? &authorityRecs
: nullptr, &d_wasVariable
, &cachedState
, &wasCachedAuth
, nullptr, &d_fromAuthIP
) > 0) {
2068 LOG(prefix
<<sqname
<<": Found cache hit for "<<sqt
.toString()<<": ");
2070 if (!wasAuthZone
&& shouldValidate() && (wasCachedAuth
|| wasForwardRecurse
) && cachedState
== vState::Indeterminate
&& d_requireAuthData
) {
2072 /* This means we couldn't figure out the state when this entry was cached */
2073 vState recordState
= getValidationStatus(qname
, !signatures
.empty(), qtype
== QType::DS
, depth
);
2075 if (recordState
== vState::Secure
) {
2076 LOG(prefix
<<sqname
<<": got vState::Indeterminate state from the cache, validating.."<<endl
);
2077 if (sqt
== QType::DNSKEY
&& sqname
== getSigner(signatures
)) {
2078 cachedState
= validateDNSKeys(sqname
, cset
, signatures
, depth
);
2081 if (sqt
== QType::ANY
) {
2082 std::map
<QType
, CacheEntry
> types
;
2083 reapRecordsForValidation(types
, cset
);
2084 reapSignaturesForValidation(types
, signatures
);
2086 for (const auto& type
: types
) {
2087 vState cachedRecordState
;
2088 if (type
.first
== QType::DNSKEY
&& sqname
== getSigner(type
.second
.signatures
)) {
2089 cachedRecordState
= validateDNSKeys(sqname
, type
.second
.records
, type
.second
.signatures
, depth
);
2092 cachedRecordState
= SyncRes::validateRecordsWithSigs(depth
, qname
, qtype
, sqname
, type
.first
, type
.second
.records
, type
.second
.signatures
);
2094 updateDNSSECValidationState(cachedState
, cachedRecordState
);
2098 cachedState
= SyncRes::validateRecordsWithSigs(depth
, qname
, qtype
, sqname
, sqt
, cset
, signatures
);
2103 cachedState
= recordState
;
2106 if (cachedState
!= vState::Indeterminate
) {
2107 LOG(prefix
<<qname
<<": got vState::Indeterminate state from the cache, validation result is "<<cachedState
<<endl
);
2108 if (vStateIsBogus(cachedState
)) {
2109 capTTL
= s_maxbogusttl
;
2111 if (sqt
!= QType::ANY
&& sqt
!= QType::ADDR
) {
2112 updateValidationStatusInCache(sqname
, sqt
, wasCachedAuth
, cachedState
);
2117 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
2119 LOG(j
->d_content
->getZoneRepresentation());
2121 if (j
->d_class
!= QClass::IN
) {
2125 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
2127 dr
.d_ttl
-= d_now
.tv_sec
;
2128 dr
.d_ttl
= std::min(dr
.d_ttl
, capTTL
);
2131 LOG("[ttl="<<dr
.d_ttl
<<"] ");
2140 ret
.reserve(ret
.size() + signatures
.size() + authorityRecs
.size());
2142 for(const auto& signature
: signatures
) {
2144 dr
.d_type
=QType::RRSIG
;
2147 dr
.d_content
=signature
;
2148 dr
.d_place
= DNSResourceRecord::ANSWER
;
2149 dr
.d_class
=QClass::IN
;
2153 for(const auto& rec
: authorityRecs
) {
2160 if(found
&& !expired
) {
2163 LOG(prefix
<<qname
<<": updating validation state with cache content for "<<qname
<<" to "<<cachedState
<<endl
);
2164 state
= cachedState
;
2168 LOG(prefix
<<qname
<<": cache had only stale entries"<<endl
);
2171 /* let's check if we have a NSEC covering that record */
2172 if (g_aggressiveNSECCache
&& !wasForwardedOrAuthZone
) {
2173 if (g_aggressiveNSECCache
->getDenial(d_now
.tv_sec
, qname
, qtype
, ret
, res
, d_cacheRemote
, d_routingTag
, d_doDNSSEC
)) {
2174 state
= vState::Secure
;
2182 bool SyncRes::moreSpecificThan(const DNSName
& a
, const DNSName
&b
) const
2184 return (a
.isPartOf(b
) && a
.countLabels() > b
.countLabels());
2189 bool operator()(const std::pair
<DNSName
, float> &a
, const std::pair
<DNSName
, float> &b
) const
2191 return a
.second
< b
.second
;
2195 inline std::vector
<std::pair
<DNSName
, float>> SyncRes::shuffleInSpeedOrder(NsSet
&tnameservers
, const string
&prefix
)
2197 std::vector
<std::pair
<DNSName
, float>> rnameservers
;
2198 rnameservers
.reserve(tnameservers
.size());
2199 for(const auto& tns
: tnameservers
) {
2200 float speed
= t_sstorage
.nsSpeeds
[tns
.first
].get(d_now
);
2201 rnameservers
.emplace_back(tns
.first
, speed
);
2202 if(tns
.first
.empty()) // this was an authoritative OOB zone, don't pollute the nsSpeeds with that
2203 return rnameservers
;
2206 shuffle(rnameservers
.begin(),rnameservers
.end(), pdns::dns_random_engine());
2208 stable_sort(rnameservers
.begin(),rnameservers
.end(), so
);
2211 LOG(prefix
<<"Nameservers: ");
2212 for(auto i
=rnameservers
.begin();i
!=rnameservers
.end();++i
) {
2213 if(i
!=rnameservers
.begin()) {
2215 if(!((i
-rnameservers
.begin())%3)) {
2216 LOG(endl
<<prefix
<<" ");
2219 LOG(i
->first
.toLogString()<<"(" << fmtfloat("%0.2f", i
->second
/1000.0) <<"ms)");
2223 return rnameservers
;
2226 inline vector
<ComboAddress
> SyncRes::shuffleForwardSpeed(const vector
<ComboAddress
> &rnameservers
, const string
&prefix
, const bool wasRd
)
2228 vector
<ComboAddress
> nameservers
= rnameservers
;
2229 map
<ComboAddress
, float> speeds
;
2231 for(const auto& val
: nameservers
) {
2233 DNSName nsName
= DNSName(val
.toStringWithPort());
2234 speed
=t_sstorage
.nsSpeeds
[nsName
].get(d_now
);
2237 shuffle(nameservers
.begin(),nameservers
.end(), pdns::dns_random_engine());
2238 speedOrderCA
so(speeds
);
2239 stable_sort(nameservers
.begin(),nameservers
.end(), so
);
2242 LOG(prefix
<<"Nameservers: ");
2243 for(vector
<ComboAddress
>::const_iterator i
=nameservers
.cbegin();i
!=nameservers
.cend();++i
) {
2244 if(i
!=nameservers
.cbegin()) {
2246 if(!((i
-nameservers
.cbegin())%3)) {
2247 LOG(endl
<<prefix
<<" ");
2250 LOG((wasRd
? string("+") : string("-")) << i
->toStringWithPort() <<"(" << fmtfloat("%0.2f", speeds
[*i
]/1000.0) <<"ms)");
2257 static uint32_t getRRSIGTTL(const time_t now
, const std::shared_ptr
<RRSIGRecordContent
>& rrsig
)
2260 if (now
< rrsig
->d_sigexpire
) {
2261 res
= static_cast<uint32_t>(rrsig
->d_sigexpire
) - now
;
2266 static const set
<QType
> nsecTypes
= {QType::NSEC
, QType::NSEC3
};
2268 /* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
2270 * \param records The records to parse for the authority SOA and NSEC(3) records
2271 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
2273 static void harvestNXRecords(const vector
<DNSRecord
>& records
, NegCache::NegCacheEntry
& ne
, const time_t now
, uint32_t* lowestTTL
) {
2274 for (const auto& rec
: records
) {
2275 if (rec
.d_place
!= DNSResourceRecord::AUTHORITY
) {
2276 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
2277 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
2278 // records MUST be in the same section as the records they cover.
2279 // Hence, we ignore all records outside of the AUTHORITY section.
2283 if (rec
.d_type
== QType::RRSIG
) {
2284 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
2286 if (rrsig
->d_type
== QType::SOA
) {
2287 ne
.authoritySOA
.signatures
.push_back(rec
);
2288 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
2289 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
2290 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
2293 if (nsecTypes
.count(rrsig
->d_type
)) {
2294 ne
.DNSSECRecords
.signatures
.push_back(rec
);
2295 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
2296 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
2297 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
2303 if (rec
.d_type
== QType::SOA
) {
2304 ne
.authoritySOA
.records
.push_back(rec
);
2306 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
2310 if (nsecTypes
.count(rec
.d_type
)) {
2311 ne
.DNSSECRecords
.records
.push_back(rec
);
2313 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
2320 static cspmap_t
harvestCSPFromNE(const NegCache::NegCacheEntry
& ne
)
2323 for(const auto& rec
: ne
.DNSSECRecords
.signatures
) {
2324 if(rec
.d_type
== QType::RRSIG
) {
2325 auto rrc
= getRR
<RRSIGRecordContent
>(rec
);
2327 cspmap
[{rec
.d_name
,rrc
->d_type
}].signatures
.push_back(rrc
);
2331 for(const auto& rec
: ne
.DNSSECRecords
.records
) {
2332 cspmap
[{rec
.d_name
, rec
.d_type
}].records
.insert(rec
.d_content
);
2337 // TODO remove after processRecords is fixed!
2338 // Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
2339 static void addNXNSECS(vector
<DNSRecord
>&ret
, const vector
<DNSRecord
>& records
)
2341 NegCache::NegCacheEntry ne
;
2342 harvestNXRecords(records
, ne
, 0, nullptr);
2343 ret
.insert(ret
.end(), ne
.authoritySOA
.signatures
.begin(), ne
.authoritySOA
.signatures
.end());
2344 ret
.insert(ret
.end(), ne
.DNSSECRecords
.records
.begin(), ne
.DNSSECRecords
.records
.end());
2345 ret
.insert(ret
.end(), ne
.DNSSECRecords
.signatures
.begin(), ne
.DNSSECRecords
.signatures
.end());
2348 static bool rpzHitShouldReplaceContent(const DNSName
& qname
, const QType qtype
, const std::vector
<DNSRecord
>& records
)
2350 if (qtype
== QType::CNAME
) {
2354 for (const auto& record
: records
) {
2355 if (record
.d_type
== QType::CNAME
) {
2356 if (auto content
= getRR
<CNAMERecordContent
>(record
)) {
2357 if (qname
== content
->getTarget()) {
2358 /* we have a CNAME whose target matches the entry we are about to
2359 generate, so it will complete the current records, not replace
2371 static void removeConflictingRecord(std::vector
<DNSRecord
>& records
, const DNSName
& name
, const QType dtype
)
2373 for (auto it
= records
.begin(); it
!= records
.end(); ) {
2374 bool remove
= false;
2376 if (it
->d_class
== QClass::IN
&&
2377 (it
->d_type
== QType::CNAME
|| dtype
== QType::CNAME
|| it
->d_type
== dtype
) &&
2378 it
->d_name
== name
) {
2381 else if (it
->d_class
== QClass::IN
&&
2382 it
->d_type
== QType::RRSIG
&&
2383 it
->d_name
== name
) {
2384 if (auto rrc
= getRR
<RRSIGRecordContent
>(*it
)) {
2385 if (rrc
->d_type
== QType::CNAME
|| rrc
->d_type
== dtype
) {
2386 /* also remove any RRSIG that could conflict */
2393 it
= records
.erase(it
);
2401 void SyncRes::handlePolicyHit(const std::string
& prefix
, const DNSName
& qname
, const QType qtype
, std::vector
<DNSRecord
>& ret
, bool& done
, int& rcode
, unsigned int depth
)
2403 if (d_pdl
&& d_pdl
->policyHitEventFilter(d_requestor
, qname
, qtype
, d_queryReceivedOverTCP
, d_appliedPolicy
, d_policyTags
, d_discardedPolicies
)) {
2404 /* reset to no match */
2405 d_appliedPolicy
= DNSFilterEngine::Policy();
2409 /* don't account truncate actions for TCP queries, since they are not applied */
2410 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::Truncate
|| !d_queryReceivedOverTCP
) {
2411 ++g_stats
.policyResults
[d_appliedPolicy
.d_kind
];
2412 ++(g_stats
.policyHits
.lock()->operator[](d_appliedPolicy
.getName()));
2415 if (d_appliedPolicy
.d_type
!= DNSFilterEngine::PolicyType::None
) {
2416 LOG(prefix
<< qname
<< "|" << qtype
<< d_appliedPolicy
.getLogString() << endl
);
2419 switch (d_appliedPolicy
.d_kind
) {
2421 case DNSFilterEngine::PolicyKind::NoAction
:
2424 case DNSFilterEngine::PolicyKind::Drop
:
2425 ++g_stats
.policyDrops
;
2426 throw ImmediateQueryDropException();
2428 case DNSFilterEngine::PolicyKind::NXDOMAIN
:
2430 rcode
= RCode::NXDomain
;
2434 case DNSFilterEngine::PolicyKind::NODATA
:
2436 rcode
= RCode::NoError
;
2440 case DNSFilterEngine::PolicyKind::Truncate
:
2441 if (!d_queryReceivedOverTCP
) {
2443 rcode
= RCode::NoError
;
2444 throw SendTruncatedAnswerException();
2448 case DNSFilterEngine::PolicyKind::Custom
:
2450 if (rpzHitShouldReplaceContent(qname
, qtype
, ret
)) {
2454 rcode
= RCode::NoError
;
2456 auto spoofed
= d_appliedPolicy
.getCustomRecords(qname
, qtype
.getCode());
2457 for (auto& dr
: spoofed
) {
2458 removeConflictingRecord(ret
, dr
.d_name
, dr
.d_type
);
2461 for (auto& dr
: spoofed
) {
2464 if (dr
.d_name
== qname
&& dr
.d_type
== QType::CNAME
&& qtype
!= QType::CNAME
) {
2465 if (auto content
= getRR
<CNAMERecordContent
>(dr
)) {
2466 vState newTargetState
= vState::Indeterminate
;
2467 handleNewTarget(prefix
, qname
, content
->getTarget(), qtype
.getCode(), ret
, rcode
, depth
, {}, newTargetState
);
2475 bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine
& dfe
, const NsSet
& nameservers
)
2477 /* we skip RPZ processing if:
2478 - it was disabled (d_wantsRPZ is false) ;
2479 - we already got a RPZ hit (d_appliedPolicy.d_type != DNSFilterEngine::PolicyType::None) since
2480 the only way we can get back here is that it was a 'pass-thru' (NoAction) meaning that we should not
2481 process any further RPZ rules. Except that we need to process rules of higher priority..
2483 if (d_wantsRPZ
&& !d_appliedPolicy
.wasHit()) {
2484 for (auto const &ns
: nameservers
) {
2485 bool match
= dfe
.getProcessingPolicy(ns
.first
, d_discardedPolicies
, d_appliedPolicy
);
2487 mergePolicyTags(d_policyTags
, d_appliedPolicy
.getTags());
2488 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
2489 LOG(", however nameserver "<<ns
.first
<<" was blocked by RPZ policy '"<<d_appliedPolicy
.getName()<<"'"<<endl
);
2494 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
2495 for (auto const &address
: ns
.second
.first
) {
2496 match
= dfe
.getProcessingPolicy(address
, d_discardedPolicies
, d_appliedPolicy
);
2498 mergePolicyTags(d_policyTags
, d_appliedPolicy
.getTags());
2499 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
2500 LOG(", however nameserver "<<ns
.first
<<" IP address "<<address
.toString()<<" was blocked by RPZ policy '"<<d_appliedPolicy
.getName()<<"'"<<endl
);
2510 bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine
& dfe
, const ComboAddress
& remoteIP
)
2512 /* we skip RPZ processing if:
2513 - it was disabled (d_wantsRPZ is false) ;
2514 - we already got a RPZ hit (d_appliedPolicy.d_type != DNSFilterEngine::PolicyType::None) since
2515 the only way we can get back here is that it was a 'pass-thru' (NoAction) meaning that we should not
2516 process any further RPZ rules. Except that we need to process rules of higher priority..
2518 if (d_wantsRPZ
&& !d_appliedPolicy
.wasHit()) {
2519 bool match
= dfe
.getProcessingPolicy(remoteIP
, d_discardedPolicies
, d_appliedPolicy
);
2521 mergePolicyTags(d_policyTags
, d_appliedPolicy
.getTags());
2522 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) {
2523 LOG(" (blocked by RPZ policy '" + d_appliedPolicy
.getName() + "')");
2531 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
, unsigned int &nretrieveAddressesForNS
)
2533 vector
<ComboAddress
> result
;
2535 size_t nonresolvingfails
= 0;
2536 if (!tns
->first
.empty()) {
2537 if (s_nonresolvingnsmaxfails
> 0) {
2538 nonresolvingfails
= s_nonresolving
.lock()->value(tns
->first
);
2539 if (nonresolvingfails
>= s_nonresolvingnsmaxfails
) {
2540 LOG(prefix
<<qname
<<": NS "<<tns
->first
<< " in non-resolving map, skipping"<<endl
);
2545 LOG(prefix
<<qname
<<": Trying to resolve NS '"<<tns
->first
<< "' ("<<1+tns
-rnameservers
.begin()<<"/"<<(unsigned int)rnameservers
.size()<<")"<<endl
);
2546 const unsigned int oldOutQueries
= d_outqueries
;
2548 result
= getAddrs(tns
->first
, depth
, beenthere
, cacheOnly
, nretrieveAddressesForNS
);
2550 // Other exceptions should likely not throttle...
2551 catch (const ImmediateServFailException
& ex
) {
2552 if (s_nonresolvingnsmaxfails
> 0 && d_outqueries
> oldOutQueries
) {
2553 auto dontThrottleNames
= g_dontThrottleNames
.getLocal();
2554 if (!dontThrottleNames
->check(tns
->first
)) {
2555 s_nonresolving
.lock()->incr(tns
->first
, d_now
);
2560 if (s_nonresolvingnsmaxfails
> 0 && d_outqueries
> oldOutQueries
) {
2561 if (result
.empty()) {
2562 auto dontThrottleNames
= g_dontThrottleNames
.getLocal();
2563 if (!dontThrottleNames
->check(tns
->first
)) {
2564 s_nonresolving
.lock()->incr(tns
->first
, d_now
);
2567 else if (nonresolvingfails
> 0) {
2568 // Succeeding resolve, clear memory of recent failures
2569 s_nonresolving
.lock()->clear(tns
->first
);
2572 pierceDontQuery
=false;
2575 LOG(prefix
<<qname
<<": Domain has hardcoded nameserver");
2577 if(nameservers
[tns
->first
].first
.size() > 1) {
2582 sendRDQuery
= nameservers
[tns
->first
].second
;
2583 result
= shuffleForwardSpeed(nameservers
[tns
->first
].first
, doLog() ? (prefix
+qname
.toString()+": ") : string(), sendRDQuery
);
2584 pierceDontQuery
=true;
2589 bool SyncRes::throttledOrBlocked(const std::string
& prefix
, const ComboAddress
& remoteIP
, const DNSName
& qname
, const QType qtype
, bool pierceDontQuery
)
2591 if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, std::make_tuple(remoteIP
, g_rootdnsname
, 0))) {
2592 LOG(prefix
<<qname
<<": server throttled "<<endl
);
2593 s_throttledqueries
++; d_throttledqueries
++;
2596 else if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, std::make_tuple(remoteIP
, qname
, qtype
.getCode()))) {
2597 LOG(prefix
<<qname
<<": query throttled "<<remoteIP
.toString()<<", "<<qname
<<"; "<<qtype
<<endl
);
2598 s_throttledqueries
++; d_throttledqueries
++;
2601 else if(!pierceDontQuery
&& s_dontQuery
&& s_dontQuery
->match(&remoteIP
)) {
2602 // We could have retrieved an NS from the cache in a forwarding domain
2603 // Even in the case of !pierceDontQuery we still want to allow that NS
2604 DNSName
forwardCandidate(qname
);
2605 auto it
= getBestAuthZone(&forwardCandidate
);
2606 if (it
== t_sstorage
.domainmap
->end()) {
2607 LOG(prefix
<<qname
<<": not sending query to " << remoteIP
.toString() << ", blocked by 'dont-query' setting" << endl
);
2611 // The name (from the cache) is forwarded, but is it forwarded to an IP in known forwarders?
2612 const auto& ips
= it
->second
.d_servers
;
2613 if (std::find(ips
.cbegin(), ips
.cend(), remoteIP
) == ips
.cend()) {
2614 LOG(prefix
<<qname
<<": not sending query to " << remoteIP
.toString() << ", blocked by 'dont-query' setting" << endl
);
2618 LOG(prefix
<<qname
<<": sending query to " << remoteIP
.toString() << ", blocked by 'dont-query' but a forwarding/auth case" << endl
);
2625 bool SyncRes::validationEnabled() const
2627 return g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
;
2630 uint32_t SyncRes::computeLowestTTD(const std::vector
<DNSRecord
>& records
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, uint32_t signaturesTTL
, const std::vector
<std::shared_ptr
<DNSRecord
>>& authorityRecs
) const
2632 uint32_t lowestTTD
= std::numeric_limits
<uint32_t>::max();
2633 for (const auto& record
: records
) {
2634 lowestTTD
= min(lowestTTD
, record
.d_ttl
);
2637 /* even if it was not requested for that request (Process, and neither AD nor DO set),
2638 it might be requested at a later time so we need to be careful with the TTL. */
2639 if (validationEnabled() && !signatures
.empty()) {
2640 /* if we are validating, we don't want to cache records after their signatures expire. */
2641 /* records TTL are now TTD, let's add 'now' to the signatures lowest TTL */
2642 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(signaturesTTL
+ d_now
.tv_sec
));
2644 for(const auto& sig
: signatures
) {
2645 if (isRRSIGNotExpired(d_now
.tv_sec
, sig
)) {
2646 // we don't decrement d_sigexpire by 'now' because we actually want a TTD, not a TTL */
2647 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(sig
->d_sigexpire
));
2652 for (const auto& entry
: authorityRecs
) {
2653 /* be careful, this is still a TTL here */
2654 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(entry
->d_ttl
+ d_now
.tv_sec
));
2656 if (entry
->d_type
== QType::RRSIG
&& validationEnabled()) {
2657 auto rrsig
= getRR
<RRSIGRecordContent
>(*entry
);
2659 if (isRRSIGNotExpired(d_now
.tv_sec
, rrsig
)) {
2660 // we don't decrement d_sigexpire by 'now' because we actually want a TTD, not a TTL */
2661 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(rrsig
->d_sigexpire
));
2670 void SyncRes::updateValidationState(vState
& state
, const vState stateUpdate
)
2672 LOG(d_prefix
<<"validation state was "<<state
<<", state update is "<<stateUpdate
);
2673 updateDNSSECValidationState(state
, stateUpdate
);
2674 LOG(", validation state is now "<<state
<<endl
);
2677 vState
SyncRes::getTA(const DNSName
& zone
, dsmap_t
& ds
)
2679 auto luaLocal
= g_luaconfs
.getLocal();
2681 if (luaLocal
->dsAnchors
.empty()) {
2682 LOG(d_prefix
<<": No trust anchors configured, everything is Insecure"<<endl
);
2683 /* We have no TA, everything is insecure */
2684 return vState::Insecure
;
2688 if (haveNegativeTrustAnchor(luaLocal
->negAnchors
, zone
, reason
)) {
2689 LOG(d_prefix
<<": got NTA for '"<<zone
<<"'"<<endl
);
2693 if (getTrustAnchor(luaLocal
->dsAnchors
, zone
, ds
)) {
2694 LOG(d_prefix
<<": got TA for '"<<zone
<<"'"<<endl
);
2698 LOG(d_prefix
<<": no TA found for '"<<zone
<<"' among "<< luaLocal
->dsAnchors
.size()<<endl
);
2701 if (zone
.isRoot()) {
2702 /* No TA for the root */
2703 return vState::Insecure
;
2706 return vState::Indeterminate
;
2709 static size_t countSupportedDS(const dsmap_t
& dsmap
)
2713 for (const auto& ds
: dsmap
) {
2714 if (isSupportedDS(ds
)) {
2722 void SyncRes::initZoneCutsFromTA(const DNSName
& from
)
2727 vState result
= getTA(zone
, ds
);
2728 if (result
!= vState::Indeterminate
) {
2729 if (result
== vState::TA
) {
2730 if (countSupportedDS(ds
) == 0) {
2732 result
= vState::Insecure
;
2735 result
= vState::Secure
;
2738 else if (result
== vState::NTA
) {
2739 result
= vState::Insecure
;
2742 d_cutStates
[zone
] = result
;
2745 while (zone
.chopOff());
2748 vState
SyncRes::getDSRecords(const DNSName
& zone
, dsmap_t
& ds
, bool taOnly
, unsigned int depth
, bool bogusOnNXD
, bool* foundCut
)
2750 vState result
= getTA(zone
, ds
);
2752 if (result
!= vState::Indeterminate
|| taOnly
) {
2754 *foundCut
= (result
!= vState::Indeterminate
);
2757 if (result
== vState::TA
) {
2758 if (countSupportedDS(ds
) == 0) {
2760 result
= vState::Insecure
;
2763 result
= vState::Secure
;
2766 else if (result
== vState::NTA
) {
2767 result
= vState::Insecure
;
2773 std::set
<GetBestNSAnswer
> beenthere
;
2774 std::vector
<DNSRecord
> dsrecords
;
2776 vState state
= vState::Indeterminate
;
2777 const bool oldCacheOnly
= setCacheOnly(false);
2778 int rcode
= doResolve(zone
, QType::DS
, dsrecords
, depth
+ 1, beenthere
, state
);
2779 setCacheOnly(oldCacheOnly
);
2781 if (rcode
== RCode::ServFail
) {
2782 throw ImmediateServFailException("Server Failure while retrieving DS records for " + zone
.toLogString());
2785 if (rcode
== RCode::NoError
|| (rcode
== RCode::NXDomain
&& !bogusOnNXD
)) {
2786 uint8_t bestDigestType
= 0;
2788 bool gotCNAME
= false;
2789 for (const auto& record
: dsrecords
) {
2790 if (record
.d_type
== QType::DS
) {
2791 const auto dscontent
= getRR
<DSRecordContent
>(record
);
2792 if (dscontent
&& isSupportedDS(*dscontent
)) {
2793 // Make GOST a lower prio than SHA256
2794 if (dscontent
->d_digesttype
== DNSSECKeeper::DIGEST_GOST
&& bestDigestType
== DNSSECKeeper::DIGEST_SHA256
) {
2797 if (dscontent
->d_digesttype
> bestDigestType
|| (bestDigestType
== DNSSECKeeper::DIGEST_GOST
&& dscontent
->d_digesttype
== DNSSECKeeper::DIGEST_SHA256
)) {
2798 bestDigestType
= dscontent
->d_digesttype
;
2800 ds
.insert(*dscontent
);
2803 else if (record
.d_type
== QType::CNAME
&& record
.d_name
== zone
) {
2808 /* RFC 4509 section 3: "Validator implementations SHOULD ignore DS RRs containing SHA-1
2809 * digests if DS RRs with SHA-256 digests are present in the DS RRset."
2810 * We interpret that as: do not use SHA-1 if SHA-256 or SHA-384 is available
2812 for (auto dsrec
= ds
.begin(); dsrec
!= ds
.end(); ) {
2813 if (dsrec
->d_digesttype
== DNSSECKeeper::DIGEST_SHA1
&& dsrec
->d_digesttype
!= bestDigestType
) {
2814 dsrec
= ds
.erase(dsrec
);
2821 if (rcode
== RCode::NoError
) {
2823 /* we have no DS, it's either:
2824 - a delegation to a non-DNSSEC signed zone
2825 - no delegation, we stay in the same zone
2827 if (gotCNAME
|| denialProvesNoDelegation(zone
, dsrecords
)) {
2828 /* we are still inside the same zone */
2836 d_cutStates
[zone
] = state
== vState::Secure
? vState::Insecure
: state
;
2837 /* delegation with no DS, might be Secure -> Insecure */
2842 /* a delegation with no DS is either:
2843 - a signed zone (Secure) to an unsigned one (Insecure)
2844 - an unsigned zone to another unsigned one (Insecure stays Insecure, Bogus stays Bogus)
2846 return state
== vState::Secure
? vState::Insecure
: state
;
2849 d_cutStates
[zone
] = state
;
2859 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
2860 return vState::BogusUnableToGetDSs
;
2863 vState
SyncRes::getValidationStatus(const DNSName
& name
, bool wouldBeValid
, bool typeIsDS
, unsigned int depth
)
2865 vState result
= vState::Indeterminate
;
2867 if (!shouldValidate()) {
2871 DNSName
subdomain(name
);
2873 subdomain
.chopOff();
2877 const auto& it
= d_cutStates
.find(subdomain
);
2878 if (it
!= d_cutStates
.cend()) {
2879 LOG(d_prefix
<<": got status "<<it
->second
<<" for name "<<subdomain
<<endl
);
2884 /* look for the best match we have */
2885 DNSName
best(subdomain
);
2886 while (best
.chopOff()) {
2887 const auto& it
= d_cutStates
.find(best
);
2888 if (it
!= d_cutStates
.cend()) {
2889 result
= it
->second
;
2890 if (vStateIsBogus(result
) || result
== vState::Insecure
) {
2891 LOG(d_prefix
<<": got status "<<result
<<" for name "<<best
<<endl
);
2898 /* by now we have the best match, it's likely Secure (otherwise we would not be there)
2899 but we don't know if we missed a cut (or several).
2900 We could see if we have DS (or denial of) in cache but let's not worry for now,
2901 we will if we don't have a signature, or if the signer doesn't match what we expect */
2902 if (!wouldBeValid
&& best
!= subdomain
) {
2903 /* no signatures or Bogus, we likely missed a cut, let's try to find it */
2904 LOG(d_prefix
<<": no or invalid signature/proof for "<<name
<<", we likely missed a cut between "<<best
<<" and "<<subdomain
<<", looking for it"<<endl
);
2906 std::vector
<string
> labelsToAdd
= subdomain
.makeRelative(ds
).getRawLabels();
2908 while (!labelsToAdd
.empty()) {
2910 ds
.prependRawLabel(labelsToAdd
.back());
2911 labelsToAdd
.pop_back();
2912 LOG(d_prefix
<<": - Looking for a DS at "<<ds
<<endl
);
2914 bool foundCut
= false;
2916 vState dsState
= getDSRecords(ds
, results
, false, depth
, false, &foundCut
);
2919 LOG(d_prefix
<<": - Found cut at "<<ds
<<endl
);
2920 LOG(d_prefix
<<": New state for "<<ds
<<" is "<<dsState
<<endl
);
2921 d_cutStates
[ds
] = dsState
;
2923 if (dsState
!= vState::Secure
) {
2929 /* we did not miss a cut, good luck */
2934 /* we don't need this, we actually do the right thing later */
2935 DNSName signer
= getSigner(signatures
);
2937 if (!signer
.empty() && name
.isPartOf(signer
)) {
2938 if (signer
== best
) {
2941 /* the zone cut is not the one we expected,
2942 this is fine because we will retrieve the needed DNSKEYs and DSs
2943 later, and even go Insecure if we missed a cut to Insecure (no DS)
2944 and the signatures do not validate (we should not go Bogus in that
2947 /* something is not right, but let's not worry about that for now.. */
2953 vState
SyncRes::validateDNSKeys(const DNSName
& zone
, const std::vector
<DNSRecord
>& dnskeys
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, unsigned int depth
)
2956 if (signatures
.empty()) {
2957 LOG(d_prefix
<<": we have "<<std::to_string(dnskeys
.size())<<" DNSKEYs but no signature, going Bogus!"<<endl
);
2958 return vState::BogusNoRRSIG
;
2961 DNSName signer
= getSigner(signatures
);
2963 if (!signer
.empty() && zone
.isPartOf(signer
)) {
2964 vState state
= getDSRecords(signer
, ds
, false, depth
);
2966 if (state
!= vState::Secure
) {
2971 LOG(d_prefix
<<": we have "<<std::to_string(dnskeys
.size())<<" DNSKEYs but the zone ("<<zone
<<") is not part of the signer ("<<signer
<<"), check that we did not miss a zone cut"<<endl
);
2972 /* try again to get the missed cuts, harder this time */
2973 auto zState
= getValidationStatus(zone
, false, false, depth
);
2974 if (zState
== vState::Secure
) {
2976 LOG(d_prefix
<<": after checking the zone cuts again, we still have "<<std::to_string(dnskeys
.size())<<" DNSKEYs and the zone ("<<zone
<<") is still not part of the signer ("<<signer
<<"), going Bogus!"<<endl
);
2977 return vState::BogusNoValidRRSIG
;
2984 skeyset_t tentativeKeys
;
2985 sortedRecords_t toSign
;
2987 for (const auto& dnskey
: dnskeys
) {
2988 if (dnskey
.d_type
== QType::DNSKEY
) {
2989 auto content
= getRR
<DNSKEYRecordContent
>(dnskey
);
2991 tentativeKeys
.insert(content
);
2992 toSign
.insert(content
);
2997 LOG(d_prefix
<<": trying to validate "<<std::to_string(tentativeKeys
.size())<<" DNSKEYs with "<<std::to_string(ds
.size())<<" DS"<<endl
);
2998 skeyset_t validatedKeys
;
2999 auto state
= validateDNSKeysAgainstDS(d_now
.tv_sec
, zone
, ds
, tentativeKeys
, toSign
, signatures
, validatedKeys
);
3001 LOG(d_prefix
<<": we now have "<<std::to_string(validatedKeys
.size())<<" DNSKEYs"<<endl
);
3003 /* if we found at least one valid RRSIG covering the set,
3004 all tentative keys are validated keys. Otherwise it means
3005 we haven't found at least one DNSKEY and a matching RRSIG
3006 covering this set, this looks Bogus. */
3007 if (validatedKeys
.size() != tentativeKeys
.size()) {
3008 LOG(d_prefix
<<": let's check whether we missed a zone cut before returning a Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
3009 /* try again to get the missed cuts, harder this time */
3010 auto zState
= getValidationStatus(zone
, false, false, depth
);
3011 if (zState
== vState::Secure
) {
3013 LOG(d_prefix
<<": after checking the zone cuts we are still in a Secure zone, returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
3024 vState
SyncRes::getDNSKeys(const DNSName
& signer
, skeyset_t
& keys
, unsigned int depth
)
3026 std::vector
<DNSRecord
> records
;
3027 std::set
<GetBestNSAnswer
> beenthere
;
3028 LOG(d_prefix
<<"Retrieving DNSKeys for "<<signer
<<endl
);
3030 vState state
= vState::Indeterminate
;
3031 const bool oldCacheOnly
= setCacheOnly(false);
3032 int rcode
= doResolve(signer
, QType::DNSKEY
, records
, depth
+ 1, beenthere
, state
);
3033 setCacheOnly(oldCacheOnly
);
3035 if (rcode
== RCode::ServFail
) {
3036 throw ImmediateServFailException("Server Failure while retrieving DNSKEY records for " + signer
.toLogString());
3039 if (rcode
== RCode::NoError
) {
3040 if (state
== vState::Secure
) {
3041 for (const auto& key
: records
) {
3042 if (key
.d_type
== QType::DNSKEY
) {
3043 auto content
= getRR
<DNSKEYRecordContent
>(key
);
3045 keys
.insert(content
);
3050 LOG(d_prefix
<<"Retrieved "<<keys
.size()<<" DNSKeys for "<<signer
<<", state is "<<state
<<endl
);
3054 if (state
== vState::Insecure
) {
3058 LOG(d_prefix
<<"Returning Bogus state from "<<__func__
<<"("<<signer
<<")"<<endl
);
3059 return vState::BogusUnableToGetDNSKEYs
;
3062 vState
SyncRes::validateRecordsWithSigs(unsigned int depth
, const DNSName
& qname
, const QType qtype
, const DNSName
& name
, const QType type
, const std::vector
<DNSRecord
>& records
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
)
3065 if (signatures
.empty()) {
3066 LOG(d_prefix
<<"Bogus!"<<endl
);
3067 return vState::BogusNoRRSIG
;
3070 const DNSName signer
= getSigner(signatures
);
3071 bool dsFailed
= false;
3072 if (!signer
.empty() && name
.isPartOf(signer
)) {
3073 vState state
= vState::Secure
;
3075 if ((qtype
== QType::DNSKEY
|| qtype
== QType::DS
) && signer
== qname
) {
3076 /* we are already retrieving those keys, sorry */
3077 if (type
== QType::DS
&& signer
== name
&& !signer
.isRoot()) {
3078 /* Unless we are getting the DS of the root zone, we should never see a
3079 DS (or a denial of a DS) signed by the DS itself, since we should be
3080 requesting it from the parent zone. Something is very wrong */
3081 LOG(d_prefix
<<"The DS for "<<qname
<<" is signed by itself"<<endl
);
3082 state
= vState::BogusSelfSignedDS
;
3085 else if (qtype
== QType::DS
&& signer
== qname
&& !signer
.isRoot()) {
3086 if (type
== QType::SOA
|| type
== QType::NSEC
|| type
== QType::NSEC3
) {
3087 /* if we are trying to validate the DS or more likely NSEC(3)s proving that it does not exist, we have a problem.
3088 In that case let's go Bogus (we will check later if we missed a cut)
3090 state
= vState::BogusSelfSignedDS
;
3093 else if (type
== QType::CNAME
) {
3094 state
= vState::BogusUnableToGetDSs
;
3098 else if (qtype
== QType::DNSKEY
&& signer
== qname
) {
3099 /* that actually does happen when a server returns NS records in authority
3100 along with the DNSKEY, leading us to trying to validate the RRSIGs for
3101 the NS with the DNSKEY that we are about to process. */
3102 if ((name
== signer
&& type
== QType::NSEC
) || type
== QType::NSEC3
) {
3103 /* if we are trying to validate the DNSKEY (should not happen here),
3104 or more likely NSEC(3)s proving that it does not exist, we have a problem.
3105 In that case let's see if the DS does exist, and if it does let's go Bogus
3108 vState dsState
= getDSRecords(signer
, results
, false, depth
, true);
3109 if (vStateIsBogus(dsState
) || dsState
== vState::Insecure
) {
3111 if (vStateIsBogus(dsState
)) {
3116 LOG(d_prefix
<<"Unable to get the DS for "<<signer
<<endl
);
3117 state
= vState::BogusUnableToGetDNSKEYs
;
3122 /* return immediately since looking at the cuts is not going to change the
3123 fact that we are looking at a signature done with the key we are trying to
3125 LOG(d_prefix
<<"we are looking at a signature done with the key we are trying to obtain "<<signer
<<endl
);
3126 return vState::Indeterminate
;
3130 if (state
== vState::Secure
) {
3131 LOG(d_prefix
<<"retrieving the DNSKEYs for "<<signer
<<endl
);
3132 state
= getDNSKeys(signer
, keys
, depth
);
3135 if (state
!= vState::Secure
) {
3136 if (!vStateIsBogus(state
)) {
3139 /* try again to get the missed cuts, harder this time */
3140 LOG(d_prefix
<<"checking whether we missed a zone cut for "<<signer
<<" before returning a Bogus state for "<<name
<<"|"<<type
.toString()<<endl
);
3141 auto zState
= getValidationStatus(signer
, false, dsFailed
, depth
);
3142 if (zState
== vState::Secure
) {
3144 LOG(d_prefix
<<"we are still in a Secure zone, returning "<<vStateToString(state
)<<endl
);
3153 sortedRecords_t recordcontents
;
3154 for (const auto& record
: records
) {
3155 recordcontents
.insert(record
.d_content
);
3158 LOG(d_prefix
<<"Going to validate "<<recordcontents
.size()<< " record contents with "<<signatures
.size()<<" sigs and "<<keys
.size()<<" keys for "<<name
<<"|"<<type
.toString()<<endl
);
3159 vState state
= validateWithKeySet(d_now
.tv_sec
, name
, recordcontents
, signatures
, keys
, false);
3160 if (state
== vState::Secure
) {
3161 LOG(d_prefix
<<"Secure!"<<endl
);
3162 return vState::Secure
;
3165 LOG(d_prefix
<<vStateToString(state
)<<"!"<<endl
);
3166 /* try again to get the missed cuts, harder this time */
3167 auto zState
= getValidationStatus(name
, false, type
== QType::DS
, depth
);
3168 LOG(d_prefix
<<"checking whether we missed a zone cut before returning a Bogus state"<<endl
);
3169 if (zState
== vState::Secure
) {
3171 LOG(d_prefix
<<"we are still in a Secure zone, returning "<<vStateToString(state
)<<endl
);
3179 /* This function will check whether the answer should have the AA bit set, and will set if it should be set and isn't.
3180 This is unfortunately needed to deal with very crappy so-called DNS servers */
3181 void SyncRes::fixupAnswer(const std::string
& prefix
, LWResult
& lwr
, const DNSName
& qname
, const QType qtype
, const DNSName
& auth
, bool wasForwarded
, bool rdQuery
)
3183 const bool wasForwardRecurse
= wasForwarded
&& rdQuery
;
3185 if (wasForwardRecurse
|| lwr
.d_aabit
) {
3190 for (const auto& rec
: lwr
.d_records
) {
3192 if (rec
.d_type
== QType::OPT
) {
3196 if (rec
.d_class
!= QClass::IN
) {
3200 if (rec
.d_type
== QType::ANY
) {
3204 if (rec
.d_place
== DNSResourceRecord::ANSWER
&& (rec
.d_type
== qtype
|| rec
.d_type
== QType::CNAME
|| qtype
== QType::ANY
) && rec
.d_name
== qname
&& rec
.d_name
.isPartOf(auth
)) {
3205 /* This is clearly an answer to the question we were asking, from an authoritative server that is allowed to send it.
3206 We are going to assume this server is broken and does not know it should set the AA bit, even though it is DNS 101 */
3207 LOG(prefix
<<"Received a record for "<<rec
.d_name
<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<" in the answer section from "<<auth
<<", without the AA bit set. Assuming this server is clueless and setting the AA bit."<<endl
);
3212 if (rec
.d_place
!= DNSResourceRecord::ANSWER
) {
3213 /* we have scanned all the records in the answer section, if any, we are done */
3219 static void allowAdditionalEntry(std::unordered_set
<DNSName
>& allowedAdditionals
, const DNSRecord
& rec
)
3221 switch(rec
.d_type
) {
3223 if (auto mxContent
= getRR
<MXRecordContent
>(rec
)) {
3224 allowedAdditionals
.insert(mxContent
->d_mxname
);
3228 if (auto nsContent
= getRR
<NSRecordContent
>(rec
)) {
3229 allowedAdditionals
.insert(nsContent
->getNS());
3233 if (auto srvContent
= getRR
<SRVRecordContent
>(rec
)) {
3234 allowedAdditionals
.insert(srvContent
->d_target
);
3237 case QType::SVCB
: /* fall-through */
3239 if (auto svcbContent
= getRR
<SVCBBaseRecordContent
>(rec
)) {
3240 if (svcbContent
->getPriority() > 0) {
3241 DNSName target
= svcbContent
->getTarget();
3242 if (target
.isRoot()) {
3243 target
= rec
.d_name
;
3245 allowedAdditionals
.insert(target
);
3248 // FIXME: Alias mode not implemented yet
3253 if (auto naptrContent
= getRR
<NAPTRRecordContent
>(rec
)) {
3254 auto flags
= naptrContent
->getFlags();
3255 toLowerInPlace(flags
);
3256 if (flags
.find('a') != string::npos
|| flags
.find('s') != string::npos
) {
3257 allowedAdditionals
.insert(naptrContent
->getReplacement());
3266 void SyncRes::sanitizeRecords(const std::string
& prefix
, LWResult
& lwr
, const DNSName
& qname
, const QType qtype
, const DNSName
& auth
, bool wasForwarded
, bool rdQuery
)
3268 const bool wasForwardRecurse
= wasForwarded
&& rdQuery
;
3269 /* list of names for which we will allow A and AAAA records in the additional section
3271 std::unordered_set
<DNSName
> allowedAdditionals
= { qname
};
3272 bool haveAnswers
= false;
3273 bool isNXDomain
= false;
3274 bool isNXQType
= false;
3276 for(auto rec
= lwr
.d_records
.begin(); rec
!= lwr
.d_records
.end(); ) {
3278 if (rec
->d_type
== QType::OPT
) {
3283 if (rec
->d_class
!= QClass::IN
) {
3284 LOG(prefix
<<"Removing non internet-classed data received from "<<auth
<<endl
);
3285 rec
= lwr
.d_records
.erase(rec
);
3289 if (rec
->d_type
== QType::ANY
) {
3290 LOG(prefix
<<"Removing 'ANY'-typed data received from "<<auth
<<endl
);
3291 rec
= lwr
.d_records
.erase(rec
);
3295 if (!rec
->d_name
.isPartOf(auth
)) {
3296 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
);
3297 rec
= lwr
.d_records
.erase(rec
);
3301 /* dealing with the records in answer */
3302 if (!(lwr
.d_aabit
|| wasForwardRecurse
) && rec
->d_place
== DNSResourceRecord::ANSWER
) {
3303 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
3304 are sending such responses */
3305 if (!(rec
->d_type
== QType::CNAME
&& qname
== rec
->d_name
)) {
3306 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
);
3307 rec
= lwr
.d_records
.erase(rec
);
3312 if (rec
->d_type
== QType::DNAME
&& (rec
->d_place
!= DNSResourceRecord::ANSWER
|| !qname
.isPartOf(rec
->d_name
))) {
3313 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
);
3314 rec
= lwr
.d_records
.erase(rec
);
3318 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
)) {
3319 LOG(prefix
<<"Removing irrelevant record '"<<rec
->d_name
<<"|"<<DNSRecordContent::NumberToType(rec
->d_type
)<<"|"<<rec
->d_content
->getZoneRepresentation()<<"' in the ANSWER section received from "<<auth
<<endl
);
3320 rec
= lwr
.d_records
.erase(rec
);
3324 if (rec
->d_place
== DNSResourceRecord::ANSWER
&& !haveAnswers
) {
3328 if (rec
->d_place
== DNSResourceRecord::ANSWER
) {
3329 allowAdditionalEntry(allowedAdditionals
, *rec
);
3332 /* dealing with the records in authority */
3333 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
) {
3334 LOG(prefix
<<"Removing irrelevant record '"<<rec
->d_name
<<"|"<<DNSRecordContent::NumberToType(rec
->d_type
)<<"|"<<rec
->d_content
->getZoneRepresentation()<<"' in the AUTHORITY section received from "<<auth
<<endl
);
3335 rec
= lwr
.d_records
.erase(rec
);
3339 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::SOA
) {
3340 if (!qname
.isPartOf(rec
->d_name
)) {
3341 LOG(prefix
<<"Removing irrelevant SOA record '"<<rec
->d_name
<<"|"<<rec
->d_content
->getZoneRepresentation()<<"' in the AUTHORITY section received from "<<auth
<<endl
);
3342 rec
= lwr
.d_records
.erase(rec
);
3346 if (!(lwr
.d_aabit
|| wasForwardRecurse
)) {
3347 LOG(prefix
<<"Removing irrelevant record '"<<rec
->d_name
<<"|"<<DNSRecordContent::NumberToType(rec
->d_type
)<<"|"<<rec
->d_content
->getZoneRepresentation()<<"' in the AUTHORITY section received from "<<auth
<<endl
);
3348 rec
= lwr
.d_records
.erase(rec
);
3353 if (lwr
.d_rcode
== RCode::NXDomain
) {
3356 else if (lwr
.d_rcode
== RCode::NoError
) {
3362 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::NS
&& (isNXDomain
|| isNXQType
)) {
3364 * We don't want to pick up NS records in AUTHORITY and their ADDITIONAL sections of NXDomain answers
3365 * because they are somewhat easy to insert into a large, fragmented UDP response
3366 * for an off-path attacker by injecting spoofed UDP fragments. So do not add these to allowedAdditionals.
3368 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
);
3369 rec
= lwr
.d_records
.erase(rec
);
3373 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::NS
&& !d_updatingRootNS
&& rec
->d_name
== g_rootdnsname
) {
3375 * We don't want to pick up root NS records in AUTHORITY and their associated ADDITIONAL sections of random queries.
3376 * So don't add them to allowedAdditionals.
3378 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 response received from "<<auth
<<endl
);
3379 rec
= lwr
.d_records
.erase(rec
);
3383 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::NS
) {
3384 allowAdditionalEntry(allowedAdditionals
, *rec
);
3387 /* dealing with the records in additional */
3388 if (rec
->d_place
== DNSResourceRecord::ADDITIONAL
&& rec
->d_type
!= QType::A
&& rec
->d_type
!= QType::AAAA
&& rec
->d_type
!= QType::RRSIG
) {
3389 LOG(prefix
<<"Removing irrelevant record '"<<rec
->d_name
<<"|"<<DNSRecordContent::NumberToType(rec
->d_type
)<<"|"<<rec
->d_content
->getZoneRepresentation()<<"' in the ADDITIONAL section received from "<<auth
<<endl
);
3390 rec
= lwr
.d_records
.erase(rec
);
3394 if (rec
->d_place
== DNSResourceRecord::ADDITIONAL
&& allowedAdditionals
.count(rec
->d_name
) == 0) {
3395 LOG(prefix
<<"Removing irrelevant additional record '"<<rec
->d_name
<<"|"<<DNSRecordContent::NumberToType(rec
->d_type
)<<"|"<<rec
->d_content
->getZoneRepresentation()<<"' in the ADDITIONAL section received from "<<auth
<<endl
);
3396 rec
= lwr
.d_records
.erase(rec
);
3404 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
, const ComboAddress
& remoteIP
)
3406 bool wasForwardRecurse
= wasForwarded
&& rdQuery
;
3412 prefix
.append(depth
, ' ');
3415 fixupAnswer(prefix
, lwr
, qname
, qtype
, auth
, wasForwarded
, rdQuery
);
3416 sanitizeRecords(prefix
, lwr
, qname
, qtype
, auth
, wasForwarded
, rdQuery
);
3418 std::vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
3419 const unsigned int labelCount
= qname
.countLabels();
3420 bool isCNAMEAnswer
= false;
3421 bool isDNAMEAnswer
= false;
3424 for (auto& rec
: lwr
.d_records
) {
3425 if (rec
.d_type
== QType::OPT
|| rec
.d_class
!= QClass::IN
) {
3429 rec
.d_ttl
= min(s_maxcachettl
, rec
.d_ttl
);
3431 if (!isCNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::CNAME
&& (!(qtype
==QType::CNAME
)) && rec
.d_name
== qname
&& !isDNAMEAnswer
) {
3432 isCNAMEAnswer
= true;
3434 if (!isDNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::DNAME
&& qtype
!= QType::DNAME
&& qname
.isPartOf(rec
.d_name
)) {
3435 isDNAMEAnswer
= true;
3436 isCNAMEAnswer
= false;
3439 if (rec
.d_type
== QType::SOA
&& rec
.d_place
== DNSResourceRecord::AUTHORITY
&& qname
.isPartOf(rec
.d_name
)) {
3440 seenAuth
= rec
.d_name
;
3443 if (rec
.d_type
== QType::RRSIG
) {
3444 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
3446 /* As illustrated in rfc4035's Appendix B.6, the RRSIG label
3447 count can be lower than the name's label count if it was
3448 synthesized from the wildcard. Note that the difference might
3450 if (rec
.d_name
== qname
&& isWildcardExpanded(labelCount
, rrsig
)) {
3451 gatherWildcardProof
= true;
3452 if (!isWildcardExpandedOntoItself(rec
.d_name
, labelCount
, rrsig
)) {
3453 /* if we have a wildcard expanded onto itself, we don't need to prove
3454 that the exact name doesn't exist because it actually does.
3455 We still want to gather the corresponding NSEC/NSEC3 records
3456 to pass them to our client in case it wants to validate by itself.
3458 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthesized from a wildcard, we need a wildcard proof"<<endl
);
3459 needWildcardProof
= true;
3462 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthesized from a wildcard expanded onto itself, we need to gather wildcard proof"<<endl
);
3464 wildcardLabelsCount
= rrsig
->d_labels
;
3467 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"' and place "<<rec.d_place<<endl;
3468 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
3469 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
);
3474 /* if we have a positive answer synthesized from a wildcard,
3475 we need to store the corresponding NSEC/NSEC3 records proving
3476 that the exact name did not exist in the negative cache */
3477 if (gatherWildcardProof
) {
3478 for (const auto& rec
: lwr
.d_records
) {
3479 if (rec
.d_type
== QType::OPT
|| rec
.d_class
!= QClass::IN
) {
3483 if (nsecTypes
.count(rec
.d_type
)) {
3484 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
3486 else if (rec
.d_type
== QType::RRSIG
) {
3487 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
3488 if (rrsig
&& nsecTypes
.count(rrsig
->d_type
)) {
3489 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
3495 // reap all answers from this packet that are acceptable
3496 for (auto& rec
: lwr
.d_records
) {
3497 if(rec
.d_type
== QType::OPT
) {
3498 LOG(prefix
<<qname
<<": OPT answer '"<<rec
.d_name
<<"' from '"<<auth
<<"' nameservers" <<endl
);
3502 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
<<" ");
3504 // We called sanitizeRecords before, so all ANY, non-IN and non-aa/non-forwardrecurse answer records are already removed
3506 if(rec
.d_name
.isPartOf(auth
)) {
3507 if (rec
.d_type
== QType::RRSIG
) {
3508 LOG("RRSIG - separate"<<endl
);
3510 else if (rec
.d_type
== QType::DS
&& rec
.d_name
== auth
) {
3511 LOG("NO - DS provided by child zone"<<endl
);
3514 bool haveLogged
= false;
3515 if (isDNAMEAnswer
&& rec
.d_type
== QType::CNAME
) {
3516 LOG("NO - we already have a DNAME answer for this domain"<<endl
);
3519 if (!t_sstorage
.domainmap
->empty()) {
3520 // Check if we are authoritative for a zone in this answer
3521 DNSName
tmp_qname(rec
.d_name
);
3522 // We may be auth for domain example.com, but the DS record needs to come from the parent (.com) nameserver
3523 if (rec
.d_type
== QType::DS
) {
3524 tmp_qname
.chopOff();
3526 auto auth_domain_iter
=getBestAuthZone(&tmp_qname
);
3527 if(auth_domain_iter
!=t_sstorage
.domainmap
->end() &&
3528 auth
.countLabels() <= auth_domain_iter
->first
.countLabels()) {
3529 if (auth_domain_iter
->first
!= auth
) {
3530 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter
->first
<<endl
);
3533 LOG("YES! - This answer was ");
3534 if (!wasForwarded
) {
3535 LOG("retrieved from the local auth store.");
3537 LOG("received from a server we forward to.");
3548 rec
.d_ttl
=min(s_maxcachettl
, rec
.d_ttl
);
3551 dr
.d_ttl
+= d_now
.tv_sec
;
3552 dr
.d_place
=DNSResourceRecord::ANSWER
;
3553 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(dr
);
3561 for (auto& entry
: tcache
) {
3562 if ((entry
.second
.records
.size() + entry
.second
.signatures
.size() + authorityRecs
.size()) > 1) { // need to group the ttl to be the minimum of the RRSET (RFC 2181, 5.2)
3563 uint32_t lowestTTD
= computeLowestTTD(entry
.second
.records
, entry
.second
.signatures
, entry
.second
.signaturesTTL
, authorityRecs
);
3565 for (auto& record
: entry
.second
.records
) {
3566 record
.d_ttl
= lowestTTD
; // boom
3570 // cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
3571 // cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
3574 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
3576 if (i
->second
.records
.empty()) // this happens when we did store signatures, but passed on the records themselves
3579 /* Even if the AA bit is set, additional data cannot be considered
3580 as authoritative. This is especially important during validation
3581 because keeping records in the additional section is allowed even
3582 if the corresponding RRSIGs are not included, without setting the TC
3583 bit, as stated in rfc4035's section 3.1.1. Including RRSIG RRs in a Response:
3584 "When placing a signed RRset in the Additional section, the name
3585 server MUST also place its RRSIG RRs in the Additional section.
3586 If space does not permit inclusion of both the RRset and its
3587 associated RRSIG RRs, the name server MAY retain the RRset while
3588 dropping the RRSIG RRs. If this happens, the name server MUST NOT
3589 set the TC bit solely because these RRSIG RRs didn't fit."
3591 bool isAA
= lwr
.d_aabit
&& i
->first
.place
!= DNSResourceRecord::ADDITIONAL
;
3592 /* if we forwarded the query to a recursor, we can expect the answer to be signed,
3593 even if the answer is not AA. Of course that's not only true inside a Secure
3594 zone, but we check that below. */
3595 bool expectSignature
= i
->first
.place
== DNSResourceRecord::ANSWER
|| ((lwr
.d_aabit
|| wasForwardRecurse
) && i
->first
.place
!= DNSResourceRecord::ADDITIONAL
);
3596 /* in a non authoritative answer, we only care about the DS record (or lack of) */
3597 if (!isAA
&& (i
->first
.type
== QType::DS
|| i
->first
.type
== QType::NSEC
|| i
->first
.type
== QType::NSEC3
) && i
->first
.place
== DNSResourceRecord::AUTHORITY
) {
3598 expectSignature
= true;
3601 if (isCNAMEAnswer
&& (i
->first
.place
!= DNSResourceRecord::ANSWER
|| i
->first
.type
!= QType::CNAME
|| i
->first
.name
!= qname
)) {
3604 Note that the answer section of an authoritative answer normally
3605 contains only authoritative data. However when the name sought is an
3606 alias (see section 10.1.1) only the record describing that alias is
3607 necessarily authoritative. Clients should assume that other records
3608 may have come from the server's cache. Where authoritative answers
3609 are required, the client should query again, using the canonical name
3610 associated with the alias.
3613 expectSignature
= false;
3615 else if (isDNAMEAnswer
&& (i
->first
.place
!= DNSResourceRecord::ANSWER
|| i
->first
.type
!= QType::DNAME
|| !qname
.isPartOf(i
->first
.name
))) {
3618 expectSignature
= false;
3621 if ((isCNAMEAnswer
|| isDNAMEAnswer
) && i
->first
.place
== DNSResourceRecord::AUTHORITY
&& i
->first
.type
== QType::NS
&& auth
== i
->first
.name
) {
3622 /* These NS can't be authoritative since we have a CNAME/DNAME answer for which (see above) only the
3623 record describing that alias is necessarily authoritative.
3624 But if we allow the current auth, which might be serving the child zone, to raise the TTL
3625 of non-authoritative NS in the cache, they might be able to keep a "ghost" zone alive forever,
3626 even after the delegation is gone from the parent.
3627 So let's just do nothing with them, we can fetch them directly if we need them.
3629 LOG(d_prefix
<<": skipping authority NS from '"<<auth
<<"' nameservers in CNAME/DNAME answer "<<i
->first
.name
<<"|"<<DNSRecordContent::NumberToType(i
->first
.type
)<<endl
);
3634 * RFC 6672 section 5.3.1
3635 * In any response, a signed DNAME RR indicates a non-terminal
3636 * redirection of the query. There might or might not be a server-
3637 * synthesized CNAME in the answer section; if there is, the CNAME will
3638 * never be signed. For a DNSSEC validator, verification of the DNAME
3639 * RR and then that the CNAME was properly synthesized is sufficient
3642 * We do the synthesis check in processRecords, here we make sure we
3643 * don't validate the CNAME.
3645 if (isDNAMEAnswer
&& i
->first
.type
== QType::CNAME
) {
3646 expectSignature
= false;
3649 vState recordState
= vState::Indeterminate
;
3651 if (expectSignature
&& shouldValidate()) {
3652 vState initialState
= getValidationStatus(i
->first
.name
, !i
->second
.signatures
.empty(), i
->first
.type
== QType::DS
, depth
);
3653 LOG(d_prefix
<<": got initial zone status "<<initialState
<<" for record "<<i
->first
.name
<<"|"<<DNSRecordContent::NumberToType(i
->first
.type
)<<endl
);
3655 if (initialState
== vState::Secure
) {
3656 if (i
->first
.type
== QType::DNSKEY
&& i
->first
.place
== DNSResourceRecord::ANSWER
&& i
->first
.name
== getSigner(i
->second
.signatures
)) {
3657 LOG(d_prefix
<<"Validating DNSKEY for "<<i
->first
.name
<<endl
);
3658 recordState
= validateDNSKeys(i
->first
.name
, i
->second
.records
, i
->second
.signatures
, depth
);
3661 LOG(d_prefix
<<"Validating non-additional "<<QType(i
->first
.type
).toString()<<" record for "<<i
->first
.name
<<endl
);
3662 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, QType(i
->first
.type
), i
->second
.records
, i
->second
.signatures
);
3666 recordState
= initialState
;
3667 LOG(d_prefix
<<"Skipping validation because the current state is "<<recordState
<<endl
);
3670 LOG(d_prefix
<<"Validation result is "<<recordState
<<", current state is "<<state
<<endl
);
3671 if (state
!= recordState
) {
3672 updateValidationState(state
, recordState
);
3676 if (vStateIsBogus(recordState
)) {
3677 /* this is a TTD by now, be careful */
3678 for(auto& record
: i
->second
.records
) {
3679 record
.d_ttl
= std::min(record
.d_ttl
, static_cast<uint32_t>(s_maxbogusttl
+ d_now
.tv_sec
));
3683 /* We don't need to store NSEC3 records in the positive cache because:
3684 - we don't allow direct NSEC3 queries
3685 - denial of existence proofs in wildcard expanded positive responses are stored in authorityRecs
3686 - denial of existence proofs for negative responses are stored in the negative cache
3687 We also don't want to cache non-authoritative data except for:
3688 - records coming from non forward-recurse servers (those will never be AA)
3690 - NS, A and AAAA (used for infra queries)
3692 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
)) {
3694 bool doCache
= true;
3695 if (i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
) {
3696 const bool isv4
= ednsmask
->isIPv4();
3697 if ((isv4
&& s_ecsipv4nevercache
) || (!isv4
&& s_ecsipv6nevercache
)) {
3700 // If ednsmask is relevant, we do not want to cache if the scope prefix length is large and TTL is small
3701 if (doCache
&& s_ecscachelimitttl
> 0) {
3702 bool manyMaskBits
= (isv4
&& ednsmask
->getBits() > s_ecsipv4cachelimit
) ||
3703 (!isv4
&& ednsmask
->getBits() > s_ecsipv6cachelimit
);
3706 uint32_t minttl
= UINT32_MAX
;
3707 for (const auto &it
: i
->second
.records
) {
3708 if (it
.d_ttl
< minttl
)
3711 bool ttlIsSmall
= minttl
< s_ecscachelimitttl
+ d_now
.tv_sec
;
3713 // Case: many bits and ttlIsSmall
3720 d_fromAuthIP
= remoteIP
;
3723 g_recCache
->replace(d_now
.tv_sec
, i
->first
.name
, i
->first
.type
, i
->second
.records
, i
->second
.signatures
, authorityRecs
, i
->first
.type
== QType::DS
? true : isAA
, auth
, i
->first
.place
== DNSResourceRecord::ANSWER
? ednsmask
: boost::none
, d_routingTag
, recordState
, remoteIP
);
3725 if (g_aggressiveNSECCache
&& needWildcardProof
&& recordState
== vState::Secure
&& i
->first
.place
== DNSResourceRecord::ANSWER
&& i
->first
.name
== qname
&& !i
->second
.signatures
.empty() && !d_routingTag
&& !ednsmask
) {
3726 /* we have an answer synthesized from a wildcard and aggressive NSEC is enabled, we need to store the
3727 wildcard in its non-expanded form in the cache to be able to synthesize wildcard answers later */
3728 const auto& rrsig
= i
->second
.signatures
.at(0);
3730 if (isWildcardExpanded(labelCount
, rrsig
) && !isWildcardExpandedOntoItself(i
->first
.name
, labelCount
, rrsig
)) {
3731 DNSName realOwner
= getNSECOwnerName(i
->first
.name
, i
->second
.signatures
);
3733 std::vector
<DNSRecord
> content
;
3734 content
.reserve(i
->second
.records
.size());
3735 for (const auto& record
: i
->second
.records
) {
3736 DNSRecord
nonExpandedRecord(record
);
3737 nonExpandedRecord
.d_name
= realOwner
;
3738 content
.push_back(std::move(nonExpandedRecord
));
3741 g_recCache
->replace(d_now
.tv_sec
, realOwner
, QType(i
->first
.type
), content
, i
->second
.signatures
, /* no additional records in that case */ {}, i
->first
.type
== QType::DS
? true : isAA
, auth
, boost::none
, boost::none
, recordState
, remoteIP
);
3747 if (seenAuth
.empty() && !i
->second
.signatures
.empty()) {
3748 seenAuth
= getSigner(i
->second
.signatures
);
3751 if (g_aggressiveNSECCache
&& (i
->first
.type
== QType::NSEC
|| i
->first
.type
== QType::NSEC3
) && recordState
== vState::Secure
&& !seenAuth
.empty()) {
3752 // Good candidate for NSEC{,3} caching
3753 g_aggressiveNSECCache
->insertNSEC(seenAuth
, i
->first
.name
, i
->second
.records
.at(0), i
->second
.signatures
, i
->first
.type
== QType::NSEC3
);
3756 if (i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
) {
3761 return RCode::NoError
;
3764 void SyncRes::updateDenialValidationState(vState
& neValidationState
, const DNSName
& neName
, vState
& state
, const dState denialState
, const dState expectedState
, bool isDS
, unsigned int depth
)
3766 if (denialState
== expectedState
) {
3767 neValidationState
= vState::Secure
;
3770 if (denialState
== dState::OPTOUT
) {
3771 LOG(d_prefix
<<"OPT-out denial found for "<<neName
<<endl
);
3773 "The AD bit, as defined by [RFC4035], MUST NOT be set when returning a
3774 response containing a closest (provable) encloser proof in which the
3775 NSEC3 RR that covers the "next closer" name has the Opt-Out bit set.
3777 This rule is based on what this closest encloser proof actually
3778 proves: names that would be covered by the Opt-Out NSEC3 RR may or
3779 may not exist as insecure delegations. As such, not all the data in
3780 responses containing such closest encloser proofs will have been
3781 cryptographically verified, so the AD bit cannot be set."
3783 At best the Opt-Out NSEC3 RR proves that there is no signed DS (so no
3786 neValidationState
= vState::Insecure
;
3788 else if (denialState
== dState::INSECURE
) {
3789 LOG(d_prefix
<<"Insecure denial found for "<<neName
<<", returning Insecure"<<endl
);
3790 neValidationState
= vState::Insecure
;
3793 LOG(d_prefix
<<"Invalid denial found for "<<neName
<<", res="<<denialState
<<", expectedState="<<expectedState
<<", checking whether we have missed a zone cut before returning a Bogus state"<<endl
);
3794 /* try again to get the missed cuts, harder this time */
3795 auto zState
= getValidationStatus(neName
, false, isDS
, depth
);
3796 if (zState
!= vState::Secure
) {
3797 neValidationState
= zState
;
3800 LOG(d_prefix
<<"Still in a secure zone with an invalid denial for "<<neName
<<", returning "<<vStateToString(vState::BogusInvalidDenial
)<<endl
);
3801 neValidationState
= vState::BogusInvalidDenial
;
3805 updateValidationState(state
, neValidationState
);
3808 dState
SyncRes::getDenialValidationState(const NegCache::NegCacheEntry
& ne
, const dState expectedState
, bool referralToUnsigned
)
3810 cspmap_t csp
= harvestCSPFromNE(ne
);
3811 return getDenial(csp
, ne
.d_name
, ne
.d_qtype
.getCode(), referralToUnsigned
, expectedState
== dState::NXQTYPE
);
3814 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
, int& rcode
, bool& negIndicHasSignatures
, unsigned int depth
)
3817 DNSName dnameTarget
, dnameOwner
;
3818 uint32_t dnameTTL
= 0;
3819 bool referralOnDS
= false;
3821 for (auto& rec
: lwr
.d_records
) {
3822 if (rec
.d_type
!= QType::OPT
&& rec
.d_class
!= QClass::IN
) {
3826 if (rec
.d_place
== DNSResourceRecord::ANSWER
&& !(lwr
.d_aabit
|| sendRDQuery
)) {
3827 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
3828 are sending such responses */
3829 if (!(rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
)) {
3833 const bool negCacheIndiction
= rec
.d_place
== DNSResourceRecord::AUTHORITY
&& rec
.d_type
== QType::SOA
&&
3834 lwr
.d_rcode
== RCode::NXDomain
&& qname
.isPartOf(rec
.d_name
) && rec
.d_name
.isPartOf(auth
);
3836 bool putInNegCache
= true;
3837 if (negCacheIndiction
&& qtype
== QType::DS
&& isForwardOrAuth(qname
)) {
3838 // #10189, a NXDOMAIN to a DS query for a forwarded or auth domain should not NXDOMAIN the whole domain
3839 putInNegCache
= false;
3842 if (negCacheIndiction
) {
3843 LOG(prefix
<<qname
<<": got negative caching indication for name '"<<qname
<<"' (accept="<<rec
.d_name
.isPartOf(auth
)<<"), newtarget='"<<newtarget
<<"'"<<endl
);
3845 rec
.d_ttl
= min(rec
.d_ttl
, s_maxnegttl
);
3846 // only add a SOA if we're not going anywhere after this
3847 if (newtarget
.empty()) {
3851 NegCache::NegCacheEntry ne
;
3853 uint32_t lowestTTL
= rec
.d_ttl
;
3854 /* if we get an NXDomain answer with a CNAME, the name
3855 does exist but the target does not */
3856 ne
.d_name
= newtarget
.empty() ? qname
: newtarget
;
3857 ne
.d_qtype
= QType::ENT
; // this encodes 'whole record'
3858 ne
.d_auth
= rec
.d_name
;
3859 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
3861 if (vStateIsBogus(state
)) {
3862 ne
.d_validationState
= state
;
3865 /* here we need to get the validation status of the zone telling us that the domain does not
3866 exist, ie the owner of the SOA */
3867 auto recordState
= getValidationStatus(rec
.d_name
, !ne
.authoritySOA
.signatures
.empty() || !ne
.DNSSECRecords
.signatures
.empty(), false, depth
);
3868 if (recordState
== vState::Secure
) {
3869 dState denialState
= getDenialValidationState(ne
, dState::NXDOMAIN
, false);
3870 updateDenialValidationState(ne
.d_validationState
, ne
.d_name
, state
, denialState
, dState::NXDOMAIN
, false, depth
);
3873 ne
.d_validationState
= recordState
;
3874 updateValidationState(state
, ne
.d_validationState
);
3878 if (vStateIsBogus(ne
.d_validationState
)) {
3879 lowestTTL
= min(lowestTTL
, s_maxbogusttl
);
3882 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
3883 /* if we get an NXDomain answer with a CNAME, let's not cache the
3884 target, even the server was authoritative for it,
3885 and do an additional query for the CNAME target.
3886 We have a regression test making sure we do exactly that.
3888 if (newtarget
.empty() && putInNegCache
) {
3889 g_negCache
->add(ne
);
3890 if (s_rootNXTrust
&& ne
.d_auth
.isRoot() && auth
.isRoot() && lwr
.d_aabit
) {
3891 ne
.d_name
= ne
.d_name
.getLastLabel();
3892 g_negCache
->add(ne
);
3896 negIndicHasSignatures
= !ne
.authoritySOA
.signatures
.empty() || !ne
.DNSSECRecords
.signatures
.empty();
3899 else if (rec
.d_place
== DNSResourceRecord::ANSWER
&& s_redirectionQTypes
.count(rec
.d_type
) > 0 && // CNAME or DNAME answer
3900 s_redirectionQTypes
.count(qtype
.getCode()) == 0) { // But not in response to a CNAME or DNAME query
3901 if (rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
) {
3902 if (!dnameOwner
.empty()) { // We synthesize ourselves
3906 if (auto content
= getRR
<CNAMERecordContent
>(rec
)) {
3907 newtarget
= DNSName(content
->getTarget());
3909 } else if (rec
.d_type
== QType::DNAME
&& qname
.isPartOf(rec
.d_name
)) { // DNAME
3911 if (auto content
= getRR
<DNAMERecordContent
>(rec
)) {
3912 dnameOwner
= rec
.d_name
;
3913 dnameTarget
= content
->getTarget();
3914 dnameTTL
= rec
.d_ttl
;
3915 if (!newtarget
.empty()) { // We had a CNAME before, remove it from ret so we don't cache it
3916 ret
.erase(std::remove_if(
3919 [&qname
](DNSRecord
& rr
) {
3920 return (rr
.d_place
== DNSResourceRecord::ANSWER
&& rr
.d_type
== QType::CNAME
&& rr
.d_name
== qname
);
3925 newtarget
= qname
.makeRelative(dnameOwner
) + dnameTarget
;
3926 } catch (const std::exception
&e
) {
3927 // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
3928 // But there is no way to set the RCODE from this function
3929 throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + dnameOwner
.toLogString() +
3930 "', DNAME target: '" + dnameTarget
.toLogString() + "', substituted name: '" +
3931 qname
.makeRelative(dnameOwner
).toLogString() + "." + dnameTarget
.toLogString() +
3937 /* if we have a positive answer synthesized from a wildcard, we need to
3938 return the corresponding NSEC/NSEC3 records from the AUTHORITY section
3939 proving that the exact name did not exist.
3940 Except if this is a NODATA answer because then we will gather the NXNSEC records later */
3941 else if (gatherWildcardProof
&& !negindic
&& (rec
.d_type
== QType::RRSIG
|| rec
.d_type
== QType::NSEC
|| rec
.d_type
== QType::NSEC3
) && rec
.d_place
== DNSResourceRecord::AUTHORITY
) {
3942 ret
.push_back(rec
); // enjoy your DNSSEC
3944 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
3945 else if (rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&&
3947 rec
.d_type
== qtype
.getCode() || ((lwr
.d_aabit
|| sendRDQuery
) && qtype
== QType::ANY
)
3951 LOG(prefix
<<qname
<<": answer is in: resolved to '"<< rec
.d_content
->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"'"<<endl
);
3954 rcode
= RCode::NoError
;
3956 if (needWildcardProof
) {
3957 /* positive answer synthesized from a wildcard */
3958 NegCache::NegCacheEntry ne
;
3960 ne
.d_qtype
= QType::ENT
; // this encodes 'whole record'
3961 uint32_t lowestTTL
= rec
.d_ttl
;
3962 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
3964 if (vStateIsBogus(state
)) {
3965 ne
.d_validationState
= state
;
3968 auto recordState
= getValidationStatus(qname
, !ne
.authoritySOA
.signatures
.empty() || !ne
.DNSSECRecords
.signatures
.empty(), false, depth
);
3970 if (recordState
== vState::Secure
) {
3971 /* We have a positive answer synthesized from a wildcard, we need to check that we have
3972 proof that the exact name doesn't exist so the wildcard can be used,
3973 as described in section 5.3.4 of RFC 4035 and 5.3 of RFC 7129.
3975 cspmap_t csp
= harvestCSPFromNE(ne
);
3976 dState res
= getDenial(csp
, qname
, ne
.d_qtype
.getCode(), false, false, false, wildcardLabelsCount
);
3977 if (res
!= dState::NXDOMAIN
) {
3978 vState st
= vState::BogusInvalidDenial
;
3979 if (res
== dState::INSECURE
|| res
== dState::OPTOUT
) {
3980 /* Some part could not be validated, for example a NSEC3 record with a too large number of iterations,
3981 this is not enough to warrant a Bogus, but go Insecure. */
3982 st
= vState::Insecure
;
3983 LOG(d_prefix
<<"Unable to validate denial in wildcard expanded positive response found for "<<qname
<<", returning Insecure, res="<<res
<<endl
);
3986 LOG(d_prefix
<<"Invalid denial in wildcard expanded positive response found for "<<qname
<<", returning Bogus, res="<<res
<<endl
);
3987 rec
.d_ttl
= std::min(rec
.d_ttl
, s_maxbogusttl
);
3990 updateValidationState(state
, st
);
3991 /* we already stored the record with a different validation status, let's fix it */
3992 updateValidationStatusInCache(qname
, qtype
, lwr
.d_aabit
, st
);
4000 else if ((rec
.d_type
== QType::RRSIG
|| rec
.d_type
== QType::NSEC
|| rec
.d_type
== QType::NSEC3
) && rec
.d_place
== DNSResourceRecord::ANSWER
) {
4001 if (rec
.d_type
!= QType::RRSIG
|| rec
.d_name
== qname
) {
4002 ret
.push_back(rec
); // enjoy your DNSSEC
4003 } else if (rec
.d_type
== QType::RRSIG
&& qname
.isPartOf(rec
.d_name
)) {
4004 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
4005 if (rrsig
!= nullptr && rrsig
->d_type
== QType::DNAME
) {
4010 else if (rec
.d_place
== DNSResourceRecord::AUTHORITY
&& rec
.d_type
== QType::NS
&& qname
.isPartOf(rec
.d_name
)) {
4011 if (moreSpecificThan(rec
.d_name
,auth
)) {
4012 newauth
= rec
.d_name
;
4013 LOG(prefix
<<qname
<<": got NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
4015 /* check if we have a referral from the parent zone to a child zone for a DS query, which is not right */
4016 if (qtype
== QType::DS
&& (newauth
.isPartOf(qname
) || qname
== newauth
)) {
4017 /* just got a referral from the parent zone when asking for a DS, looks like this server did not get the DNSSEC memo.. */
4018 referralOnDS
= true;
4021 realreferral
= true;
4022 if (auto content
= getRR
<NSRecordContent
>(rec
)) {
4023 nsset
.insert(content
->getNS());
4028 LOG(prefix
<<qname
<<": got upwards/level NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"', had '"<<auth
<<"'"<<endl
);
4029 if (auto content
= getRR
<NSRecordContent
>(rec
)) {
4030 nsset
.insert(content
->getNS());
4034 else if (rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::DS
&& qname
.isPartOf(rec
.d_name
)) {
4035 LOG(prefix
<<qname
<<": got DS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
4037 else if (realreferral
&& rec
.d_place
== DNSResourceRecord::AUTHORITY
&& (rec
.d_type
== QType::NSEC
|| rec
.d_type
== QType::NSEC3
) && newauth
.isPartOf(auth
)) {
4038 /* we might have received a denial of the DS, let's check */
4039 NegCache::NegCacheEntry ne
;
4040 uint32_t lowestTTL
= rec
.d_ttl
;
4041 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
4043 if (!vStateIsBogus(state
)) {
4044 auto recordState
= getValidationStatus(newauth
, !ne
.authoritySOA
.signatures
.empty() || !ne
.DNSSECRecords
.signatures
.empty(), true, depth
);
4046 if (recordState
== vState::Secure
) {
4048 ne
.d_name
= newauth
;
4049 ne
.d_qtype
= QType::DS
;
4050 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
4052 dState denialState
= getDenialValidationState(ne
, dState::NXQTYPE
, true);
4054 if (denialState
== dState::NXQTYPE
|| denialState
== dState::OPTOUT
|| denialState
== dState::INSECURE
) {
4055 ne
.d_ttd
= lowestTTL
+ d_now
.tv_sec
;
4056 ne
.d_validationState
= vState::Secure
;
4057 if (denialState
== dState::OPTOUT
) {
4058 ne
.d_validationState
= vState::Insecure
;
4060 LOG(prefix
<<qname
<<": got negative indication of DS record for '"<<newauth
<<"'"<<endl
);
4062 g_negCache
->add(ne
);
4064 /* Careful! If the client is asking for a DS that does not exist, we need to provide the SOA along with the NSEC(3) proof
4065 and we might not have it if we picked up the proof from a delegation, in which case we need to keep on to do the actual DS
4067 if (qtype
== QType::DS
&& qname
== newauth
&& (d_externalDSQuery
.empty() || qname
!= d_externalDSQuery
)) {
4068 /* we are actually done! */
4070 negIndicHasSignatures
= !ne
.authoritySOA
.signatures
.empty() || !ne
.DNSSECRecords
.signatures
.empty();
4077 else if (!done
&& rec
.d_place
== DNSResourceRecord::AUTHORITY
&& rec
.d_type
== QType::SOA
&&
4078 lwr
.d_rcode
== RCode::NoError
&& qname
.isPartOf(rec
.d_name
)) {
4079 LOG(prefix
<<qname
<<": got negative caching indication for '"<< qname
<<"|"<<qtype
<<"'"<<endl
);
4081 if (!newtarget
.empty()) {
4082 LOG(prefix
<<qname
<<": Hang on! Got a redirect to '"<<newtarget
<<"' already"<<endl
);
4085 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
4087 NegCache::NegCacheEntry ne
;
4088 ne
.d_auth
= rec
.d_name
;
4089 uint32_t lowestTTL
= rec
.d_ttl
;
4092 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
4094 if (vStateIsBogus(state
)) {
4095 ne
.d_validationState
= state
;
4098 auto recordState
= getValidationStatus(qname
, !ne
.authoritySOA
.signatures
.empty() || !ne
.DNSSECRecords
.signatures
.empty(), qtype
== QType::DS
, depth
);
4099 if (recordState
== vState::Secure
) {
4100 dState denialState
= getDenialValidationState(ne
, dState::NXQTYPE
, false);
4101 updateDenialValidationState(ne
.d_validationState
, ne
.d_name
, state
, denialState
, dState::NXQTYPE
, qtype
== QType::DS
, depth
);
4103 ne
.d_validationState
= recordState
;
4104 updateValidationState(state
, ne
.d_validationState
);
4108 if (vStateIsBogus(ne
.d_validationState
)) {
4109 lowestTTL
= min(lowestTTL
, s_maxbogusttl
);
4110 rec
.d_ttl
= min(rec
.d_ttl
, s_maxbogusttl
);
4112 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
4114 if (qtype
.getCode()) { // prevents us from NXDOMAIN'ing a whole domain
4115 g_negCache
->add(ne
);
4120 negIndicHasSignatures
= !ne
.authoritySOA
.signatures
.empty() || !ne
.DNSSECRecords
.signatures
.empty();
4125 if (!dnameTarget
.empty()) {
4126 // Synthesize a CNAME
4127 auto cnamerec
= DNSRecord();
4128 cnamerec
.d_name
= qname
;
4129 cnamerec
.d_type
= QType::CNAME
;
4130 cnamerec
.d_ttl
= dnameTTL
;
4131 cnamerec
.d_content
= std::make_shared
<CNAMERecordContent
>(CNAMERecordContent(newtarget
));
4132 ret
.push_back(std::move(cnamerec
));
4135 /* If we have seen a proper denial, let's forget that we also had a referral for a DS query.
4136 Otherwise we need to deal with it. */
4137 if (referralOnDS
&& !negindic
) {
4138 LOG(prefix
<<qname
<<": got a referral to the child zone for a DS query without a negative indication (missing SOA in authority), treating that as a NODATA"<<endl
);
4139 if (!vStateIsBogus(state
)) {
4140 auto recordState
= getValidationStatus(qname
, false, true, depth
);
4141 if (recordState
== vState::Secure
) {
4142 /* we are in a secure zone, got a referral to the child zone on a DS query, no denial, that's wrong */
4143 LOG(prefix
<<qname
<<": NODATA without a negative indication (missing SOA in authority) in a DNSSEC secure zone, going Bogus"<<endl
);
4144 updateValidationState(state
, vState::BogusMissingNegativeIndication
);
4148 negIndicHasSignatures
= false;
4154 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 bool wasForwarded
, const DNSName
& nsName
, const ComboAddress
& remoteIP
, bool doTCP
, bool doDoT
, bool& truncated
, bool& spoofed
)
4156 bool chained
= false;
4157 LWResult::Result resolveret
= LWResult::Result::Success
;
4161 if(d_outqueries
+ d_throttledqueries
> s_maxqperq
) {
4162 throw ImmediateServFailException("more than "+std::to_string(s_maxqperq
)+" (max-qperq) queries sent while resolving "+qname
.toLogString());
4165 if(s_maxtotusec
&& d_totUsec
> s_maxtotusec
) {
4166 throw ImmediateServFailException("Too much time waiting for "+qname
.toLogString()+"|"+qtype
.toString()+", 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");
4171 LOG(prefix
<<qname
<<": using DoT with "<< remoteIP
.toStringWithPort() <<endl
);
4175 LOG(prefix
<<qname
<<": using TCP with "<< remoteIP
.toStringWithPort() <<endl
);
4181 int preOutQueryRet
= RCode::NoError
;
4182 if(d_pdl
&& d_pdl
->preoutquery(remoteIP
, d_requestor
, qname
, qtype
, doTCP
, lwr
.d_records
, preOutQueryRet
, d_eventTrace
)) {
4183 LOG(prefix
<<qname
<<": query handled by Lua"<<endl
);
4186 ednsmask
=getEDNSSubnetMask(qname
, remoteIP
);
4188 LOG(prefix
<<qname
<<": Adding EDNS Client Subnet Mask "<<ednsmask
->toString()<<" to query"<<endl
);
4191 resolveret
= asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, auth
, qtype
.getCode(),
4192 doTCP
, sendRDQuery
, &d_now
, ednsmask
, &lwr
, &chained
, nsName
); // <- we go out on the wire!
4195 LOG(prefix
<<qname
<<": Received EDNS Client Subnet Mask "<<ednsmask
->toString()<<" on response"<<endl
);
4196 if (ednsmask
->getBits() > 0) {
4197 if (ednsmask
->isIPv4()) {
4198 ++SyncRes::s_ecsResponsesBySubnetSize4
.at(ednsmask
->getBits()-1);
4201 ++SyncRes::s_ecsResponsesBySubnetSize6
.at(ednsmask
->getBits()-1);
4207 /* preoutquery killed the query by setting dq.rcode to -3 */
4208 if (preOutQueryRet
== -3) {
4209 throw ImmediateServFailException("Query killed by policy");
4212 d_totUsec
+= lwr
.d_usec
;
4213 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
4215 bool dontThrottle
= false;
4217 auto dontThrottleNames
= g_dontThrottleNames
.getLocal();
4218 auto dontThrottleNetmasks
= g_dontThrottleNetmasks
.getLocal();
4219 dontThrottle
= dontThrottleNames
->check(nsName
) || dontThrottleNetmasks
->match(remoteIP
);
4222 if (resolveret
!= LWResult::Result::Success
) {
4223 /* Error while resolving */
4224 if (resolveret
== LWResult::Result::Timeout
) {
4227 LOG(prefix
<<qname
<<": timeout resolving after "<<lwr
.d_usec
/1000.0<<"msec "<< (doTCP
? "over TCP" : "")<<endl
);
4229 s_outgoingtimeouts
++;
4231 if(remoteIP
.sin4
.sin_family
== AF_INET
)
4232 s_outgoing4timeouts
++;
4234 s_outgoing6timeouts
++;
4237 t_timeouts
->push_back(remoteIP
);
4239 else if (resolveret
== LWResult::Result::OSLimitError
) {
4240 /* OS resource limit reached */
4241 LOG(prefix
<<qname
<<": hit a local resource limit resolving"<< (doTCP
? " over TCP" : "")<<", probable error: "<<stringerror()<<endl
);
4242 g_stats
.resourceLimits
++;
4244 else if (resolveret
== LWResult::Result::Spoofed
) {
4248 /* LWResult::Result::PermanentError */
4251 // XXX questionable use of errno
4252 LOG(prefix
<<qname
<<": error resolving from "<<remoteIP
.toString()<< (doTCP
? " over TCP" : "") <<", possible error: "<<stringerror()<< endl
);
4255 if (resolveret
!= LWResult::Result::OSLimitError
&& !chained
&& !dontThrottle
) {
4256 // don't account for resource limits, they are our own fault
4257 // And don't throttle when the IP address is on the dontThrottleNetmasks list or the name is part of dontThrottleNames
4258 t_sstorage
.nsSpeeds
[nsName
.empty()? DNSName(remoteIP
.toStringWithPort()) : nsName
].submit(remoteIP
, 1000000, d_now
); // 1 sec
4260 // code below makes sure we don't filter COM or the root
4261 if (s_serverdownmaxfails
> 0 && (auth
!= g_rootdnsname
) && s_fails
.lock()->incr(remoteIP
, d_now
) >= s_serverdownmaxfails
) {
4262 LOG(prefix
<<qname
<<": Max fails reached resolving on "<< remoteIP
.toString() <<". Going full throttle for "<< s_serverdownthrottletime
<<" seconds" <<endl
);
4263 // mark server as down
4264 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, std::make_tuple(remoteIP
, g_rootdnsname
, 0), s_serverdownthrottletime
, 10000);
4266 else if (resolveret
== LWResult::Result::PermanentError
) {
4267 // unreachable, 1 minute or 100 queries
4268 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, std::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 100);
4271 // timeout, 10 seconds or 5 queries
4272 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, std::make_tuple(remoteIP
, qname
, qtype
.getCode()), 10, 5);
4279 if (lwr
.d_validpacket
== false) {
4280 LOG(prefix
<<qname
<<": "<<nsName
<<" ("<<remoteIP
.toString()<<") returned a packet we could not parse over " << (doTCP
? "TCP" : "UDP") << ", trying sibling IP or NS"<<endl
);
4281 if (!chained
&& !dontThrottle
) {
4283 // let's make sure we prefer a different server for some time, if there is one available
4284 t_sstorage
.nsSpeeds
[nsName
.empty()? DNSName(remoteIP
.toStringWithPort()) : nsName
].submit(remoteIP
, 1000000, d_now
); // 1 sec
4287 // we can be more heavy-handed over TCP
4288 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, std::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 10);
4291 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, std::make_tuple(remoteIP
, qname
, qtype
.getCode()), 10, 2);
4297 /* we got an answer */
4298 if (lwr
.d_rcode
!= RCode::NoError
&& lwr
.d_rcode
!= RCode::NXDomain
) {
4299 LOG(prefix
<<qname
<<": "<<nsName
<<" ("<<remoteIP
.toString()<<") returned a "<< RCode::to_s(lwr
.d_rcode
) << ", trying sibling IP or NS"<<endl
);
4300 if (!chained
&& !dontThrottle
) {
4301 if (wasForwarded
&& lwr
.d_rcode
== RCode::ServFail
) {
4302 // rather than throttling what could be the only server we have for this destination, let's make sure we try a different one if there is one available
4303 // on the other hand, we might keep hammering a server under attack if there is no other alternative, or the alternative is overwhelmed as well, but
4304 // at the very least we will detect that if our packets stop being answered
4305 t_sstorage
.nsSpeeds
[nsName
.empty()? DNSName(remoteIP
.toStringWithPort()) : nsName
].submit(remoteIP
, 1000000, d_now
); // 1 sec
4308 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, std::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
4315 /* this server sent a valid answer, mark it backup up if it was down */
4316 if(s_serverdownmaxfails
> 0) {
4317 s_fails
.lock()->clear(remoteIP
);
4324 LOG(prefix
<<qname
<<": truncated bit set, over TCP?"<<endl
);
4325 if (!dontThrottle
) {
4326 /* let's treat that as a ServFail answer from this server */
4327 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, std::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
4331 LOG(prefix
<<qname
<<": truncated bit set, over UDP"<<endl
);
4339 void SyncRes::handleNewTarget(const std::string
& prefix
, const DNSName
& qname
, const DNSName
& newtarget
, const QType qtype
, std::vector
<DNSRecord
>& ret
, int& rcode
, int depth
, const std::vector
<DNSRecord
>& recordsFromAnswer
, vState
& state
)
4341 if (newtarget
== qname
) {
4342 LOG(prefix
<<qname
<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl
);
4344 rcode
= RCode::ServFail
;
4347 if (newtarget
.isPartOf(qname
)) {
4348 // a.b.c. CNAME x.a.b.c will go to great depths with QM on
4349 LOG(prefix
<<qname
<<": status=got a CNAME referral to child, disabling QM"<<endl
);
4350 setQNameMinimization(false);
4354 LOG(prefix
<<qname
<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl
);
4355 rcode
= RCode::ServFail
;
4359 if (!d_followCNAME
) {
4360 rcode
= RCode::NoError
;
4364 // Check to see if we already have seen the new target as a previous target
4365 if (scanForCNAMELoop(newtarget
, ret
)) {
4366 LOG(prefix
<<qname
<<": status=got a CNAME referral that causes a loop, returning SERVFAIL"<<endl
);
4368 rcode
= RCode::ServFail
;
4372 if (qtype
== QType::DS
|| qtype
== QType::DNSKEY
) {
4373 LOG(prefix
<<qname
<<": status=got a CNAME referral, but we are looking for a DS or DNSKEY"<<endl
);
4376 addNXNSECS(ret
, recordsFromAnswer
);
4379 rcode
= RCode::NoError
;
4383 LOG(prefix
<<qname
<<": status=got a CNAME referral, starting over with "<<newtarget
<<endl
);
4385 set
<GetBestNSAnswer
> beenthere
;
4386 vState cnameState
= vState::Indeterminate
;
4387 rcode
= doResolve(newtarget
, qtype
, ret
, depth
+ 1, beenthere
, cnameState
);
4388 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<state
<<" with the state from the CNAME quest: "<<cnameState
<<endl
);
4389 updateValidationState(state
, cnameState
);
4392 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
, const ComboAddress
& remoteIP
)
4397 prefix
.append(depth
, ' ');
4401 for(auto& rec
: lwr
.d_records
) {
4402 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumTTL
);
4406 /* if the answer is ECS-specific, a minimum TTL is set for this kind of answers
4407 and it's higher than the global minimum TTL */
4408 if (ednsmask
&& s_minimumECSTTL
> 0 && (s_minimumTTL
== 0 || s_minimumECSTTL
> s_minimumTTL
)) {
4409 for(auto& rec
: lwr
.d_records
) {
4410 if (rec
.d_place
== DNSResourceRecord::ANSWER
) {
4411 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumECSTTL
);
4416 bool needWildcardProof
= false;
4417 bool gatherWildcardProof
= false;
4418 unsigned int wildcardLabelsCount
;
4419 *rcode
= updateCacheFromRecords(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, state
, needWildcardProof
, gatherWildcardProof
, wildcardLabelsCount
, sendRDQuery
, remoteIP
);
4420 if (*rcode
!= RCode::NoError
) {
4424 LOG(prefix
<<qname
<<": determining status after receiving this packet"<<endl
);
4427 bool realreferral
= false;
4428 bool negindic
= false;
4429 bool negIndicHasSignatures
= false;
4433 bool done
= processRecords(prefix
, qname
, qtype
, auth
, lwr
, sendRDQuery
, ret
, nsset
, newtarget
, newauth
, realreferral
, negindic
, state
, needWildcardProof
, gatherWildcardProof
, wildcardLabelsCount
, *rcode
, negIndicHasSignatures
, depth
);
4436 LOG(prefix
<<qname
<<": status=got results, this level of recursion done"<<endl
);
4437 LOG(prefix
<<qname
<<": validation status is "<<state
<<endl
);
4441 if (!newtarget
.empty()) {
4442 handleNewTarget(prefix
, qname
, newtarget
, qtype
.getCode(), ret
, *rcode
, depth
, lwr
.d_records
, state
);
4446 if (lwr
.d_rcode
== RCode::NXDomain
) {
4447 LOG(prefix
<<qname
<<": status=NXDOMAIN, we are done "<<(negindic
? "(have negative SOA)" : "")<<endl
);
4449 auto tempState
= getValidationStatus(qname
, negIndicHasSignatures
, qtype
== QType::DS
, depth
);
4450 if (tempState
== vState::Secure
&& (lwr
.d_aabit
|| sendRDQuery
) && !negindic
) {
4451 LOG(prefix
<<qname
<<": NXDOMAIN without a negative indication (missing SOA in authority) in a DNSSEC secure zone, going Bogus"<<endl
);
4452 updateValidationState(state
, vState::BogusMissingNegativeIndication
);
4454 else if (state
== vState::Indeterminate
) {
4455 /* we might not have validated any record, because we did get a NXDOMAIN without any SOA
4456 from an insecure zone, for example */
4457 updateValidationState(state
, tempState
);
4461 addNXNSECS(ret
, lwr
.d_records
);
4464 *rcode
= RCode::NXDomain
;
4468 if (nsset
.empty() && !lwr
.d_rcode
&& (negindic
|| lwr
.d_aabit
|| sendRDQuery
)) {
4469 LOG(prefix
<<qname
<<": status=noerror, other types may exist, but we are done "<<(negindic
? "(have negative SOA) " : "")<<(lwr
.d_aabit
? "(have aa bit) " : "")<<endl
);
4471 auto tempState
= getValidationStatus(qname
, negIndicHasSignatures
, qtype
== QType::DS
, depth
);
4472 if (tempState
== vState::Secure
&& (lwr
.d_aabit
|| sendRDQuery
) && !negindic
) {
4473 LOG(prefix
<<qname
<<": NODATA without a negative indication (missing SOA in authority) in a DNSSEC secure zone, going Bogus"<<endl
);
4474 updateValidationState(state
, vState::BogusMissingNegativeIndication
);
4476 else if (state
== vState::Indeterminate
) {
4477 /* we might not have validated any record, because we did get a NODATA without any SOA
4478 from an insecure zone, for example */
4479 updateValidationState(state
, tempState
);
4483 addNXNSECS(ret
, lwr
.d_records
);
4486 *rcode
= RCode::NoError
;
4491 LOG(prefix
<<qname
<<": status=did not resolve, got "<<(unsigned int)nsset
.size()<<" NS, ");
4493 nameservers
.clear();
4494 for (auto const &nameserver
: nsset
) {
4495 if (d_wantsRPZ
&& !d_appliedPolicy
.wasHit()) {
4496 bool match
= dfe
.getProcessingPolicy(nameserver
, d_discardedPolicies
, d_appliedPolicy
);
4498 mergePolicyTags(d_policyTags
, d_appliedPolicy
.getTags());
4499 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
4500 if (d_pdl
&& d_pdl
->policyHitEventFilter(d_requestor
, qname
, qtype
, d_queryReceivedOverTCP
, d_appliedPolicy
, d_policyTags
, d_discardedPolicies
)) {
4501 /* reset to no match */
4502 d_appliedPolicy
= DNSFilterEngine::Policy();
4505 LOG("however "<<nameserver
<<" was blocked by RPZ policy '"<<d_appliedPolicy
.getName()<<"'"<<endl
);
4506 throw PolicyHitException();
4511 nameservers
.insert({nameserver
, {{}, false}});
4513 LOG("looping to them"<<endl
);
4514 *gotNewServers
= true;
4523 bool SyncRes::doDoTtoAuth(const DNSName
& ns
) const
4525 return g_DoTToAuthNames
.getLocal()->check(ns
);
4529 * -1 in case of no results
4532 int SyncRes::doResolveAt(NsSet
&nameservers
, DNSName auth
, bool flawedNSSet
, const DNSName
&qname
, const QType qtype
,
4533 vector
<DNSRecord
>&ret
,
4534 unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
, vState
& state
, StopAtDelegation
* stopAtDelegation
)
4536 auto luaconfsLocal
= g_luaconfs
.getLocal();
4540 prefix
.append(depth
, ' ');
4543 LOG(prefix
<<qname
<<": Cache consultations done, have "<<(unsigned int)nameservers
.size()<<" NS to contact");
4545 if (nameserversBlockedByRPZ(luaconfsLocal
->dfe
, nameservers
)) {
4547 if (d_pdl
&& d_pdl
->policyHitEventFilter(d_requestor
, qname
, qtype
, d_queryReceivedOverTCP
, d_appliedPolicy
, d_policyTags
, d_discardedPolicies
)) {
4548 /* reset to no match */
4549 d_appliedPolicy
= DNSFilterEngine::Policy();
4552 throw PolicyHitException();
4558 unsigned int addressQueriesForNS
= 0;
4559 for(;;) { // we may get more specific nameservers
4560 auto rnameservers
= shuffleInSpeedOrder(nameservers
, doLog() ? (prefix
+qname
.toString()+": ") : string() );
4562 // We allow s_maxnsaddressqperq (default 10) queries with empty responses when resolving NS names.
4563 // If a zone publishes many (more than s_maxnsaddressqperq) NS records, we allow less.
4564 // This is to "punish" zones that publish many non-resolving NS names.
4565 // We always allow 5 NS name resolving attempts with empty results.
4566 unsigned int nsLimit
= s_maxnsaddressqperq
;
4567 if (rnameservers
.size() > nsLimit
) {
4568 int newLimit
= static_cast<int>(nsLimit
) - (rnameservers
.size() - nsLimit
);
4569 nsLimit
= std::max(5, newLimit
);
4572 for(auto tns
=rnameservers
.cbegin();;++tns
) {
4573 if (addressQueriesForNS
>= nsLimit
) {
4574 throw ImmediateServFailException(std::to_string(nsLimit
)+" (adjusted max-ns-address-qperq) or more queries with empty results for NS addresses sent resolving "+qname
.toLogString());
4576 if(tns
==rnameservers
.cend()) {
4577 LOG(prefix
<<qname
<<": Failed to resolve via any of the "<<(unsigned int)rnameservers
.size()<<" offered NS at level '"<<auth
<<"'"<<endl
);
4578 if(!auth
.isRoot() && flawedNSSet
) {
4579 LOG(prefix
<<qname
<<": Ageing nameservers for level '"<<auth
<<"', next query might succeed"<<endl
);
4581 if(g_recCache
->doAgeCache(d_now
.tv_sec
, auth
, QType::NS
, 10))
4582 g_stats
.nsSetInvalidations
++;
4587 bool cacheOnly
= false;
4588 // this line needs to identify the 'self-resolving' behaviour
4589 if(qname
== tns
->first
&& (qtype
.getCode() == QType::A
|| qtype
.getCode() == QType::AAAA
)) {
4590 /* we might have a glue entry in cache so let's try this NS
4591 but only if we have enough in the cache to know how to reach it */
4592 LOG(prefix
<<qname
<<": Using NS to resolve itself, but only using what we have in cache ("<<(1+tns
-rnameservers
.cbegin())<<"/"<<rnameservers
.size()<<")"<<endl
);
4596 typedef vector
<ComboAddress
> remoteIPs_t
;
4597 remoteIPs_t remoteIPs
;
4598 remoteIPs_t::iterator remoteIP
;
4599 bool pierceDontQuery
=false;
4600 bool sendRDQuery
=false;
4601 boost::optional
<Netmask
> ednsmask
;
4603 const bool wasForwarded
= tns
->first
.empty() && (!nameservers
[tns
->first
].first
.empty());
4604 int rcode
= RCode::NoError
;
4605 bool gotNewServers
= false;
4607 if (tns
->first
.empty() && !wasForwarded
) {
4608 static ComboAddress
const s_oobRemote("255.255.255.255");
4609 LOG(prefix
<<qname
<<": Domain is out-of-band"<<endl
);
4610 /* setting state to indeterminate since validation is disabled for local auth zone,
4611 and Insecure would be misleading. */
4612 state
= vState::Indeterminate
;
4613 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, lwr
.d_records
, depth
, lwr
.d_rcode
);
4617 /* we have received an answer, are we done ? */
4618 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, false, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
, s_oobRemote
);
4622 if (gotNewServers
) {
4623 if (stopAtDelegation
&& *stopAtDelegation
== Stop
) {
4624 *stopAtDelegation
= Stopped
;
4631 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
4632 remoteIPs
= retrieveAddressesForNS(prefix
, qname
, tns
, depth
, beenthere
, rnameservers
, nameservers
, sendRDQuery
, pierceDontQuery
, flawedNSSet
, cacheOnly
, addressQueriesForNS
);
4634 if(remoteIPs
.empty()) {
4635 LOG(prefix
<<qname
<<": Failed to get IP for NS "<<tns
->first
<<", trying next if available"<<endl
);
4640 bool hitPolicy
{false};
4641 LOG(prefix
<<qname
<<": Resolved '"<<auth
<<"' NS "<<tns
->first
<<" to: ");
4642 for(remoteIP
= remoteIPs
.begin(); remoteIP
!= remoteIPs
.end(); ++remoteIP
) {
4643 if(remoteIP
!= remoteIPs
.begin()) {
4646 LOG(remoteIP
->toString());
4647 if(nameserverIPBlockedByRPZ(luaconfsLocal
->dfe
, *remoteIP
)) {
4652 if (hitPolicy
) { //implies d_wantsRPZ
4654 if (d_pdl
&& d_pdl
->policyHitEventFilter(d_requestor
, qname
, qtype
, d_queryReceivedOverTCP
, d_appliedPolicy
, d_policyTags
, d_discardedPolicies
)) {
4655 /* reset to no match */
4656 d_appliedPolicy
= DNSFilterEngine::Policy();
4659 throw PolicyHitException();
4664 for(remoteIP
= remoteIPs
.begin(); remoteIP
!= remoteIPs
.end(); ++remoteIP
) {
4665 LOG(prefix
<<qname
<<": Trying IP "<< remoteIP
->toStringWithPort() <<", asking '"<<qname
<<"|"<<qtype
<<"'"<<endl
);
4667 if (throttledOrBlocked(prefix
, *remoteIP
, qname
, qtype
, pierceDontQuery
)) {
4671 bool truncated
= false;
4672 bool spoofed
= false;
4673 bool gotAnswer
= false;
4676 if (doDoTtoAuth(tns
->first
)) {
4677 remoteIP
->setPort(853);
4680 if (SyncRes::s_dot_to_port_853
&& remoteIP
->getPort() == 853) {
4683 bool forceTCP
= doDoT
;
4686 gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
, wasForwarded
,
4687 tns
->first
, *remoteIP
, false, false, truncated
, spoofed
);
4689 if (forceTCP
|| (spoofed
|| (gotAnswer
&& truncated
))) {
4690 /* retry, over TCP this time */
4691 gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
, wasForwarded
,
4692 tns
->first
, *remoteIP
, true, doDoT
, truncated
, spoofed
);
4699 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
);
4701 /* // for you IPv6 fanatics :-)
4702 if(remoteIP->sin4.sin_family==AF_INET6)
4705 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
4707 t_sstorage
.nsSpeeds
[tns
->first
.empty()? DNSName(remoteIP
->toStringWithPort()) : tns
->first
].submit(*remoteIP
, lwr
.d_usec
, d_now
);
4709 /* we have received an answer, are we done ? */
4710 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
, *remoteIP
);
4714 if (gotNewServers
) {
4715 if (stopAtDelegation
&& *stopAtDelegation
== Stop
) {
4716 *stopAtDelegation
= Stopped
;
4722 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, std::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100);
4725 if (gotNewServers
) {
4729 if(remoteIP
== remoteIPs
.cend()) // we tried all IP addresses, none worked
4738 void SyncRes::setQuerySource(const ComboAddress
& requestor
, boost::optional
<const EDNSSubnetOpts
&> incomingECS
)
4740 d_requestor
= requestor
;
4742 if (incomingECS
&& incomingECS
->source
.getBits() > 0) {
4743 d_cacheRemote
= incomingECS
->source
.getMaskedNetwork();
4744 uint8_t bits
= std::min(incomingECS
->source
.getBits(), (incomingECS
->source
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
4745 ComboAddress trunc
= incomingECS
->source
.getNetwork();
4746 trunc
.truncate(bits
);
4747 d_outgoingECSNetwork
= boost::optional
<Netmask
>(Netmask(trunc
, bits
));
4749 d_cacheRemote
= d_requestor
;
4750 if(!incomingECS
&& s_ednslocalsubnets
.match(d_requestor
)) {
4751 ComboAddress trunc
= d_requestor
;
4752 uint8_t bits
= d_requestor
.isIPv4() ? 32 : 128;
4753 bits
= std::min(bits
, (trunc
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
4754 trunc
.truncate(bits
);
4755 d_outgoingECSNetwork
= boost::optional
<Netmask
>(Netmask(trunc
, bits
));
4756 } else if (s_ecsScopeZero
.source
.getBits() > 0) {
4757 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0.
4758 But using an empty ECS in that case would mean inserting
4759 a non ECS-specific entry into the cache, preventing any further
4760 ECS-specific query to be sent.
4761 So instead we use the trick described in section 7.1.2:
4762 "The subsequent Recursive Resolver query to the Authoritative Nameserver
4763 will then either not include an ECS option or MAY optionally include
4764 its own address information, which is what the Authoritative
4765 Nameserver will almost certainly use to generate any Tailored
4766 Response in lieu of an option. This allows the answer to be handled
4767 by the same caching mechanism as other queries, with an explicit
4768 indicator of the applicable scope. Subsequent Stub Resolver queries
4769 for /0 can then be answered from this cached response.
4771 d_outgoingECSNetwork
= boost::optional
<Netmask
>(s_ecsScopeZero
.source
.getMaskedNetwork());
4772 d_cacheRemote
= s_ecsScopeZero
.source
.getNetwork();
4774 // ECS disabled because no scope-zero address could be derived.
4775 d_outgoingECSNetwork
= boost::none
;
4780 boost::optional
<Netmask
> SyncRes::getEDNSSubnetMask(const DNSName
& dn
, const ComboAddress
& rem
)
4782 if(d_outgoingECSNetwork
&& (s_ednsdomains
.check(dn
) || s_ednsremotesubnets
.match(rem
))) {
4783 return d_outgoingECSNetwork
;
4788 void SyncRes::parseEDNSSubnetAllowlist(const std::string
& alist
)
4790 vector
<string
> parts
;
4791 stringtok(parts
, alist
, ",; ");
4792 for(const auto& a
: parts
) {
4794 s_ednsremotesubnets
.addMask(Netmask(a
));
4797 s_ednsdomains
.add(DNSName(a
));
4802 void SyncRes::parseEDNSSubnetAddFor(const std::string
& subnetlist
)
4804 vector
<string
> parts
;
4805 stringtok(parts
, subnetlist
, ",; ");
4806 for(const auto& a
: parts
) {
4807 s_ednslocalsubnets
.addMask(a
);
4811 // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_recursor.cc
4812 int directResolve(const DNSName
& qname
, const QType qtype
, const QClass qclass
, vector
<DNSRecord
>& ret
, shared_ptr
<RecursorLua4
> pdl
)
4814 return directResolve(qname
, qtype
, qclass
, ret
, pdl
, SyncRes::s_qnameminimization
);
4817 int directResolve(const DNSName
& qname
, const QType qtype
, const QClass qclass
, vector
<DNSRecord
>& ret
, shared_ptr
<RecursorLua4
> pdl
, bool qm
)
4820 gettimeofday(&now
, 0);
4823 sr
.setQNameMinimization(qm
);
4825 sr
.setLuaEngine(pdl
);
4830 res
= sr
.beginResolve(qname
, qtype
, qclass
, ret
, 0);
4832 catch(const PDNSException
& e
) {
4833 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
<<", got pdns exception: "<<e
.reason
<<endl
;
4836 catch(const ImmediateServFailException
& e
) {
4837 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
<<", got ImmediateServFailException: "<<e
.reason
<<endl
;
4840 catch(const PolicyHitException
& e
) {
4841 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
<<", got a policy hit"<<endl
;
4844 catch(const std::exception
& e
) {
4845 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
<<", got STL error: "<<e
.what()<<endl
;
4849 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
<<", got an exception"<<endl
;
4856 int SyncRes::getRootNS(struct timeval now
, asyncresolve_t asyncCallback
, unsigned int depth
) {
4858 sr
.setDoEDNS0(true);
4859 sr
.setUpdatingRootNS();
4860 sr
.setDoDNSSEC(g_dnssecmode
!= DNSSECMode::Off
);
4861 sr
.setDNSSECValidationRequested(g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
);
4862 sr
.setAsyncCallback(asyncCallback
);
4864 vector
<DNSRecord
> ret
;
4867 res
= sr
.beginResolve(g_rootdnsname
, QType::NS
, 1, ret
, depth
+ 1);
4868 if (g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
) {
4869 auto state
= sr
.getValidationState();
4870 if (vStateIsBogus(state
)) {
4871 throw PDNSException("Got Bogus validation result for .|NS");
4875 catch(const PDNSException
& e
) {
4876 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
4878 catch(const ImmediateServFailException
& e
) {
4879 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
4881 catch(const PolicyHitException
& e
) {
4882 g_log
<<Logger::Error
<<"Failed to update . records, got a policy hit"<<endl
;
4885 catch(const std::exception
& e
) {
4886 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.what()<<endl
;
4889 g_log
<<Logger::Error
<<"Failed to update . records, got an exception"<<endl
;
4893 g_log
<<Logger::Debug
<<"Refreshed . records"<<endl
;
4896 g_log
<<Logger::Warning
<<"Failed to update root NS records, RCODE="<<res
<<endl
;