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.
27 #include "arguments.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"
36 #include "dnsseckeeper.hh"
37 #include "validate-recursor.hh"
39 thread_local
SyncRes::ThreadLocalStorage
SyncRes::t_sstorage
;
41 std::unordered_set
<DNSName
> SyncRes::s_delegationOnly
;
42 std::unique_ptr
<NetmaskGroup
> SyncRes::s_dontQuery
{nullptr};
43 NetmaskGroup
SyncRes::s_ednssubnets
;
44 SuffixMatchNode
SyncRes::s_ednsdomains
;
45 EDNSSubnetOpts
SyncRes::s_ecsScopeZero
;
46 string
SyncRes::s_serverID
;
47 SyncRes::LogMode
SyncRes::s_lm
;
49 unsigned int SyncRes::s_maxnegttl
;
50 unsigned int SyncRes::s_maxcachettl
;
51 unsigned int SyncRes::s_maxqperq
;
52 unsigned int SyncRes::s_maxtotusec
;
53 unsigned int SyncRes::s_maxdepth
;
54 unsigned int SyncRes::s_minimumTTL
;
55 unsigned int SyncRes::s_packetcachettl
;
56 unsigned int SyncRes::s_packetcacheservfailttl
;
57 unsigned int SyncRes::s_serverdownmaxfails
;
58 unsigned int SyncRes::s_serverdownthrottletime
;
59 std::atomic
<uint64_t> SyncRes::s_authzonequeries
;
60 std::atomic
<uint64_t> SyncRes::s_queries
;
61 std::atomic
<uint64_t> SyncRes::s_outgoingtimeouts
;
62 std::atomic
<uint64_t> SyncRes::s_outgoing4timeouts
;
63 std::atomic
<uint64_t> SyncRes::s_outgoing6timeouts
;
64 std::atomic
<uint64_t> SyncRes::s_outqueries
;
65 std::atomic
<uint64_t> SyncRes::s_tcpoutqueries
;
66 std::atomic
<uint64_t> SyncRes::s_throttledqueries
;
67 std::atomic
<uint64_t> SyncRes::s_dontqueries
;
68 std::atomic
<uint64_t> SyncRes::s_nodelegated
;
69 std::atomic
<uint64_t> SyncRes::s_unreachables
;
70 std::atomic
<uint64_t> SyncRes::s_ecsqueries
;
71 std::atomic
<uint64_t> SyncRes::s_ecsresponses
;
72 uint8_t SyncRes::s_ecsipv4limit
;
73 uint8_t SyncRes::s_ecsipv6limit
;
74 bool SyncRes::s_doIPv6
;
75 bool SyncRes::s_nopacketcache
;
76 bool SyncRes::s_rootNXTrust
;
77 bool SyncRes::s_noEDNS
;
79 #define LOG(x) if(d_lm == Log) { L <<Logger::Warning << x; } else if(d_lm == Store) { d_trace << x; }
81 static void accountAuthLatency(int usec
, int family
)
83 if(family
== AF_INET
) {
85 g_stats
.auth4Answers0_1
++;
87 g_stats
.auth4Answers1_10
++;
88 else if(usec
< 100000)
89 g_stats
.auth4Answers10_100
++;
90 else if(usec
< 1000000)
91 g_stats
.auth4Answers100_1000
++;
93 g_stats
.auth4AnswersSlow
++;
96 g_stats
.auth6Answers0_1
++;
98 g_stats
.auth6Answers1_10
++;
99 else if(usec
< 100000)
100 g_stats
.auth6Answers10_100
++;
101 else if(usec
< 1000000)
102 g_stats
.auth6Answers100_1000
++;
104 g_stats
.auth6AnswersSlow
++;
110 SyncRes::SyncRes(const struct timeval
& now
) : d_authzonequeries(0), d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
111 d_totUsec(0), d_now(now
),
112 d_cacheonly(false), d_doDNSSEC(false), d_doEDNS0(false), d_lm(s_lm
)
117 /** everything begins here - this is the entry point just after receiving a packet */
118 int SyncRes::beginResolve(const DNSName
&qname
, const QType
&qtype
, uint16_t qclass
, vector
<DNSRecord
>&ret
)
120 vState state
= Indeterminate
;
123 d_wasOutOfBand
=false;
125 if (doSpecialNamesResolve(qname
, qtype
, qclass
, ret
)) {
126 d_queryValidationState
= Insecure
; // this could fool our stats into thinking a validation took place
127 return 0; // so do check before updating counters (we do now)
130 if( (qtype
.getCode() == QType::AXFR
) || (qtype
.getCode() == QType::IXFR
) || (qtype
.getCode() == QType::RRSIG
) || (qtype
.getCode() == QType::NSEC3
))
133 if(qclass
==QClass::ANY
)
135 else if(qclass
!=QClass::IN
)
138 set
<GetBestNSAnswer
> beenthere
;
139 int res
=doResolve(qname
, qtype
, ret
, 0, beenthere
, state
);
140 d_queryValidationState
= state
;
142 if (shouldValidate()) {
143 if (d_queryValidationState
!= Indeterminate
) {
144 g_stats
.dnssecValidations
++;
146 increaseDNSSECStateCounter(d_queryValidationState
);
152 /*! Handles all special, built-in names
153 * Fills ret with an answer and returns true if it handled the query.
155 * Handles the following queries (and their ANY variants):
158 * - localhost. IN AAAA
159 * - 1.0.0.127.in-addr.arpa. IN PTR
160 * - 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
161 * - version.bind. CH TXT
162 * - version.pdns. CH TXT
163 * - id.server. CH TXT
165 bool SyncRes::doSpecialNamesResolve(const DNSName
&qname
, const QType
&qtype
, const uint16_t qclass
, vector
<DNSRecord
> &ret
)
167 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."),
168 localhost("localhost."), versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns.");
170 bool handled
= false;
171 vector
<pair
<QType::typeenum
, string
> > answers
;
173 if ((qname
== arpa
|| qname
== ip6_arpa
) &&
174 qclass
== QClass::IN
) {
176 if (qtype
== QType::PTR
|| qtype
== QType::ANY
)
177 answers
.push_back({QType::PTR
, "localhost."});
180 if (qname
== localhost
&&
181 qclass
== QClass::IN
) {
183 if (qtype
== QType::A
|| qtype
== QType::ANY
)
184 answers
.push_back({QType::A
, "127.0.0.1"});
185 if (qtype
== QType::AAAA
|| qtype
== QType::ANY
)
186 answers
.push_back({QType::AAAA
, "::1"});
189 if ((qname
== versionbind
|| qname
== idserver
|| qname
== versionpdns
) &&
190 qclass
== QClass::CHAOS
) {
192 if (qtype
== QType::TXT
|| qtype
== QType::ANY
) {
193 if(qname
== versionbind
|| qname
== versionpdns
)
194 answers
.push_back({QType::TXT
, "\""+::arg()["version-string"]+"\""});
196 answers
.push_back({QType::TXT
, "\""+s_serverID
+"\""});
200 if (handled
&& !answers
.empty()) {
206 dr
.d_place
= DNSResourceRecord::ANSWER
;
209 for (const auto& ans
: answers
) {
210 dr
.d_type
= ans
.first
;
211 dr
.d_content
= DNSRecordContent::mastermake(ans
.first
, qclass
, ans
.second
);
220 //! This is the 'out of band resolver', in other words, the authoritative server
221 void SyncRes::AuthDomain::addSOA(std::vector
<DNSRecord
>& records
) const
223 SyncRes::AuthDomain::records_t::const_iterator ziter
= d_records
.find(boost::make_tuple(getName(), QType::SOA
));
224 if (ziter
!= d_records
.end()) {
225 DNSRecord dr
= *ziter
;
226 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
227 records
.push_back(dr
);
230 // cerr<<qname<<": can't find SOA record '"<<getName()<<"' in our zone!"<<endl;
234 int SyncRes::AuthDomain::getRecords(const DNSName
& qname
, uint16_t qtype
, std::vector
<DNSRecord
>& records
) const
236 int result
= RCode::NoError
;
240 std::pair
<records_t::const_iterator
,records_t::const_iterator
> range
= d_records
.equal_range(tie(qname
));
242 SyncRes::AuthDomain::records_t::const_iterator ziter
;
243 bool somedata
= false;
245 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
248 if(qtype
== QType::ANY
|| ziter
->d_type
== qtype
|| ziter
->d_type
== QType::CNAME
) {
249 // let rest of nameserver do the legwork on this one
250 records
.push_back(*ziter
);
252 else if (ziter
->d_type
== QType::NS
&& ziter
->d_name
.countLabels() > getName().countLabels()) {
253 // we hit a delegation point!
254 DNSRecord dr
= *ziter
;
255 dr
.d_place
=DNSResourceRecord::AUTHORITY
;
256 records
.push_back(dr
);
260 if (!records
.empty()) {
261 /* We have found an exact match, we're done */
262 // cerr<<qname<<": exact match in zone '"<<getName()<<"'"<<endl;
267 /* We have records for that name, but not of the wanted qtype */
268 // cerr<<qname<<": found record in '"<<getName()<<"', but nothing of the right type, sending SOA"<<endl;
274 // cerr<<qname<<": nothing found so far in '"<<getName()<<"', trying wildcards"<<endl;
275 DNSName
wcarddomain(qname
);
276 while(wcarddomain
!= getName() && wcarddomain
.chopOff()) {
277 // cerr<<qname<<": trying '*."<<wcarddomain<<"' in "<<getName()<<endl;
278 range
= d_records
.equal_range(boost::make_tuple(g_wildcarddnsname
+ wcarddomain
));
279 if (range
.first
==range
.second
)
282 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
283 DNSRecord dr
= *ziter
;
284 // if we hit a CNAME, just answer that - rest of recursor will do the needful & follow
285 if(dr
.d_type
== qtype
|| qtype
== QType::ANY
|| dr
.d_type
== QType::CNAME
) {
287 dr
.d_place
= DNSResourceRecord::ANSWER
;
288 records
.push_back(dr
);
292 if (records
.empty()) {
296 // cerr<<qname<<": in '"<<getName()<<"', had wildcard match on '*."<<wcarddomain<<"'"<<endl;
300 /* Nothing for this name, no wildcard, let's see if there is some NS */
301 DNSName
nsdomain(qname
);
302 while (nsdomain
.chopOff() && nsdomain
!= getName()) {
303 range
= d_records
.equal_range(boost::make_tuple(nsdomain
,QType::NS
));
304 if(range
.first
== range
.second
)
307 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
308 DNSRecord dr
= *ziter
;
309 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
310 records
.push_back(dr
);
314 if(records
.empty()) {
315 // cerr<<qname<<": no NS match in zone '"<<getName()<<"' either, handing out SOA"<<endl;
317 result
= RCode::NXDomain
;
323 bool SyncRes::doOOBResolve(const AuthDomain
& domain
, const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, int& res
)
328 res
= domain
.getRecords(qname
, qtype
.getCode(), ret
);
332 bool SyncRes::doOOBResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int& res
)
337 prefix
.append(depth
, ' ');
340 DNSName
authdomain(qname
);
341 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
342 if(iter
==t_sstorage
.domainmap
->end() || !iter
->second
.isAuth()) {
343 LOG(prefix
<<qname
<<": auth storage has no zone for this query!"<<endl
);
347 LOG(prefix
<<qname
<<": auth storage has data, zone='"<<authdomain
<<"'"<<endl
);
348 return doOOBResolve(iter
->second
, qname
, qtype
, ret
, res
);
351 void SyncRes::doEDNSDumpAndClose(int fd
)
353 FILE* fp
=fdopen(fd
, "w");
357 fprintf(fp
,"IP Address\tMode\tMode last updated at\n");
358 for(const auto& eds
: t_sstorage
.ednsstatus
) {
359 fprintf(fp
, "%s\t%d\t%s", eds
.first
.toString().c_str(), (int)eds
.second
.mode
, ctime(&eds
.second
.modeSetAt
));
365 uint64_t SyncRes::doDumpNSSpeeds(int fd
)
367 FILE* fp
=fdopen(dup(fd
), "w");
370 fprintf(fp
, "; nsspeed dump from thread follows\n;\n");
373 for(const auto& i
: t_sstorage
.nsSpeeds
)
377 // an <empty> can appear hear in case of authoritative (hosted) zones
378 fprintf(fp
, "%s -> ", i
.first
.toLogString().c_str());
379 for(const auto& j
: i
.second
.d_collection
)
381 // typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
382 fprintf(fp
, "%s/%f ", j
.first
.toString().c_str(), j
.second
.peek());
390 /* so here is the story. First we complete the full resolution process for a domain name. And only THEN do we decide
391 to also do DNSSEC validation, which leads to new queries. To make this simple, we *always* ask for DNSSEC records
392 so that if there are RRSIGs for a name, we'll have them.
394 However, some hosts simply can't answer questions which ask for DNSSEC. This can manifest itself as:
399 The cause of "No answer" may be fragmentation, and it is tempting to probe if smaller answers would get through.
400 Another cause of "No answer" may simply be a network condition.
401 Nonsense answers are a clearer indication this host won't be able to do DNSSEC evah.
403 Previous implementations have suffered from turning off DNSSEC questions for an authoritative server based on timeouts.
404 A clever idea is to only turn off DNSSEC if we know a domain isn't signed anyhow. The problem with that really
405 clever idea however is that at this point in PowerDNS, we may simply not know that yet. All the DNSSEC thinking happens
406 elsewhere. It may not have happened yet.
408 For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish.
411 int SyncRes::asyncresolveWrapper(const ComboAddress
& ip
, bool ednsMANDATORY
, const DNSName
& domain
, int type
, bool doTCP
, bool sendRDQuery
, struct timeval
* now
, boost::optional
<Netmask
>& srcmask
, LWResult
* res
, bool* chained
) const
413 /* what is your QUEST?
414 the goal is to get as many remotes as possible on the highest level of EDNS support
417 0) UNKNOWN Unknown state
418 1) EDNS: Honors EDNS0
419 2) EDNSIGNORANT: Ignores EDNS0, gives replies without EDNS0
420 3) NOEDNS: Generates FORMERR/NOTIMP on EDNS queries
422 Everybody starts out assumed to be '0'.
423 If '0', send out EDNS0
424 If you FORMERR us, go to '3',
425 If no EDNS in response, go to '2'
426 If '1', send out EDNS0
427 If FORMERR, downgrade to 3
428 If '2', keep on including EDNS0, see what happens
430 If '3', send bare queries
433 SyncRes::EDNSStatus
* ednsstatus
;
434 ednsstatus
= &t_sstorage
.ednsstatus
[ip
]; // does this include port? YES
436 if(ednsstatus
->modeSetAt
&& ednsstatus
->modeSetAt
+ 3600 < d_now
.tv_sec
) {
437 *ednsstatus
=SyncRes::EDNSStatus();
438 // cerr<<"Resetting EDNS Status for "<<ip.toString()<<endl);
441 SyncRes::EDNSStatus::EDNSMode
& mode
=ednsstatus
->mode
;
442 SyncRes::EDNSStatus::EDNSMode oldmode
= mode
;
444 auto luaconfsLocal
= g_luaconfs
.getLocal();
447 ctx
.d_initialRequestId
= d_initialRequestId
;
451 for(int tries
= 0; tries
< 3; ++tries
) {
452 // cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl;
454 if(mode
==EDNSStatus::NOEDNS
) {
455 g_stats
.noEdnsOutQueries
++;
456 EDNSLevel
= 0; // level != mode
458 else if(ednsMANDATORY
|| mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
==EDNSStatus::EDNSIGNORANT
)
461 DNSName
sendQname(domain
);
462 if (g_lowercaseOutgoing
)
463 sendQname
.makeUsLowerCase();
465 if (d_asyncResolve
) {
466 ret
= d_asyncResolve(ip
, sendQname
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, luaconfsLocal
->outgoingProtobufServer
, res
, chained
);
469 ret
=asyncresolve(ip
, sendQname
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, luaconfsLocal
->outgoingProtobufServer
, res
, chained
);
472 return ret
; // transport error, nothing to learn here
475 if(ret
== 0) { // timeout, not doing anything with it now
478 else if(mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
== EDNSStatus::EDNSIGNORANT
) {
479 if(res
->d_rcode
== RCode::FormErr
|| res
->d_rcode
== RCode::NotImp
) {
480 // cerr<<"Downgrading to NOEDNS because of "<<RCode::to_s(res->d_rcode)<<" for query to "<<ip.toString()<<" for '"<<domain<<"'"<<endl;
481 mode
= EDNSStatus::NOEDNS
;
484 else if(!res
->d_haveEDNS
) {
485 if(mode
!= EDNSStatus::EDNSIGNORANT
) {
486 mode
= EDNSStatus::EDNSIGNORANT
;
487 // cerr<<"We find that "<<ip.toString()<<" is an EDNS-ignorer for '"<<domain<<"', moving to mode 3"<<endl;
491 mode
= EDNSStatus::EDNSOK
;
492 // cerr<<"We find that "<<ip.toString()<<" is EDNS OK!"<<endl;
496 if(oldmode
!= mode
|| !ednsstatus
->modeSetAt
)
497 ednsstatus
->modeSetAt
=d_now
.tv_sec
;
498 // cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", new mode: "<<mode<<endl;
504 /*! This function will check the cache and go out to the internet if the answer is not in cache
506 * \param qname The name we need an answer for
508 * \param ret The vector of DNSRecords we need to fill with the answers
509 * \param depth The recursion depth we are in
511 * \return DNS RCODE or -1 (Error) or -2 (RPZ hit)
513 int SyncRes::doResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, vState
& state
)
518 prefix
.append(depth
, ' ');
521 LOG(prefix
<<qname
<<": Wants "<< (d_doDNSSEC
? "" : "NO ") << "DNSSEC processing, "<<(d_requireAuthData
? "" : "NO ")<<"auth data in query for "<<qtype
.getName()<<endl
);
523 state
= Indeterminate
;
525 if(s_maxdepth
&& depth
> s_maxdepth
)
526 throw ImmediateServFailException("More than "+std::to_string(s_maxdepth
)+" (max-recursion-depth) levels of recursion needed while resolving "+qname
.toLogString());
530 // This is a difficult way of expressing "this is a normal query", i.e. not getRootNS.
531 if(!(d_updatingRootNS
&& qtype
.getCode()==QType::NS
&& qname
.isRoot())) {
532 if(d_cacheonly
) { // very limited OOB support
534 LOG(prefix
<<qname
<<": Recursion not requested for '"<<qname
<<"|"<<qtype
.getName()<<"', peeking at auth/forward zones"<<endl
);
535 DNSName
authname(qname
);
536 domainmap_t::const_iterator iter
=getBestAuthZone(&authname
);
537 if(iter
!= t_sstorage
.domainmap
->end()) {
538 if(iter
->second
.isAuth()) {
540 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, ret
, depth
, res
);
544 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
545 const ComboAddress remoteIP
= servers
.front();
546 LOG(prefix
<<qname
<<": forwarding query to hardcoded nameserver '"<< remoteIP
.toStringWithPort()<<"' for zone '"<<authname
<<"'"<<endl
);
548 boost::optional
<Netmask
> nm
;
549 bool chained
= false;
550 res
=asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(), false, false, &d_now
, nm
, &lwr
, &chained
);
552 d_totUsec
+= lwr
.d_usec
;
553 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
555 // filter out the good stuff from lwr.result()
557 for(const auto& rec
: lwr
.d_records
) {
558 if(rec
.d_place
== DNSResourceRecord::ANSWER
)
564 return RCode::ServFail
;
570 DNSName
authname(qname
);
571 bool wasForwardedOrAuthZone
= false;
572 bool wasAuthZone
= false;
573 domainmap_t::const_iterator iter
= getBestAuthZone(&authname
);
574 if(iter
!= t_sstorage
.domainmap
->end()) {
575 wasForwardedOrAuthZone
= true;
576 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
577 if(servers
.empty()) {
582 if(!d_skipCNAMECheck
&& doCNAMECacheCheck(qname
, qtype
, ret
, depth
, res
, state
, wasAuthZone
)) { // will reroute us if needed
583 d_wasOutOfBand
= wasAuthZone
;
587 if(doCacheCheck(qname
, authname
, wasForwardedOrAuthZone
, wasAuthZone
, qtype
, ret
, depth
, res
, state
)) {
589 d_wasOutOfBand
= wasAuthZone
;
597 LOG(prefix
<<qname
<<": No cache hit for '"<<qname
<<"|"<<qtype
.getName()<<"', trying to find an appropriate NS record"<<endl
);
599 DNSName
subdomain(qname
);
600 if(qtype
== QType::DS
) subdomain
.chopOff();
603 bool flawedNSSet
=false;
605 /* we use subdomain here instead of qname because for DS queries we only care about the state of the parent zone */
606 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
608 // the two retries allow getBestNSNamesFromCache&co to reprime the root
609 // hints, in case they ever go missing
610 for(int tries
=0;tries
<2 && nsset
.empty();++tries
) {
611 subdomain
=getBestNSNamesFromCache(subdomain
, qtype
, nsset
, &flawedNSSet
, depth
, beenthere
); // pass beenthere to both occasions
614 state
= getValidationStatus(qname
, false);
616 LOG(prefix
<<qname
<<": initial validation status for "<<qname
<<" is "<<vStates
[state
]<<endl
);
618 if(!(res
=doResolveAt(nsset
, subdomain
, flawedNSSet
, qname
, qtype
, ret
, depth
, beenthere
, state
)))
621 LOG(prefix
<<qname
<<": failed (res="<<res
<<")"<<endl
);
626 return res
<0 ? RCode::ServFail
: res
;
630 // for testing purposes
631 static bool ipv6First(const ComboAddress
& a
, const ComboAddress
& b
)
633 return !(a
.sin4
.sin_family
< a
.sin4
.sin_family
);
639 speedOrderCA(std::map
<ComboAddress
,double>& speeds
): d_speeds(speeds
) {}
640 bool operator()(const ComboAddress
& a
, const ComboAddress
& b
) const
642 return d_speeds
[a
] < d_speeds
[b
];
644 std::map
<ComboAddress
, double>& d_speeds
;
647 /** This function explicitly goes out for A or AAAA addresses
649 vector
<ComboAddress
> SyncRes::getAddrs(const DNSName
&qname
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, bool cacheOnly
)
651 typedef vector
<DNSRecord
> res_t
;
654 typedef vector
<ComboAddress
> ret_t
;
658 bool oldCacheOnly
= d_cacheonly
;
659 bool oldRequireAuthData
= d_requireAuthData
;
660 bool oldValidationRequested
= d_DNSSECValidationRequested
;
661 d_requireAuthData
= false;
662 d_DNSSECValidationRequested
= false;
663 d_cacheonly
= cacheOnly
;
665 for(int j
=1; j
<2+s_doIPv6
; j
++)
680 vState newState
= Indeterminate
;
681 if(!doResolve(qname
, type
, res
,depth
+1, beenthere
, newState
) && !res
.empty()) { // this consults cache, OR goes out
682 for(res_t::const_iterator i
=res
.begin(); i
!= res
.end(); ++i
) {
683 if(i
->d_type
== QType::A
|| i
->d_type
== QType::AAAA
) {
684 if(auto rec
= getRR
<ARecordContent
>(*i
))
685 ret
.push_back(rec
->getCA(53));
686 else if(auto aaaarec
= getRR
<AAAARecordContent
>(*i
))
687 ret
.push_back(aaaarec
->getCA(53));
693 if(j
==1 && s_doIPv6
) { // we got an A record, see if we have some AAAA lying around
694 vector
<DNSRecord
> cset
;
695 if(t_RC
->get(d_now
.tv_sec
, qname
, QType(QType::AAAA
), false, &cset
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
) > 0) {
696 for(auto k
=cset
.cbegin();k
!=cset
.cend();++k
) {
697 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
698 if (auto drc
= getRR
<AAAARecordContent
>(*k
)) {
699 ComboAddress ca
=drc
->getCA(53);
710 d_requireAuthData
= oldRequireAuthData
;
711 d_DNSSECValidationRequested
= oldValidationRequested
;
712 d_cacheonly
= oldCacheOnly
;
714 /* we need to remove from the nsSpeeds collection the existing IPs
715 for this nameserver that are no longer in the set, even if there
716 is only one or none at all in the current set.
718 map
<ComboAddress
, double> speeds
;
719 auto& collection
= t_sstorage
.nsSpeeds
[qname
].d_collection
;
720 for(const auto& val
: ret
) {
721 speeds
[val
] = collection
[val
].get(&d_now
);
724 t_sstorage
.nsSpeeds
[qname
].purge(speeds
);
727 random_shuffle(ret
.begin(), ret
.end(), dns_random
);
728 speedOrderCA
so(speeds
);
729 stable_sort(ret
.begin(), ret
.end(), so
);
732 string prefix
=d_prefix
;
733 prefix
.append(depth
, ' ');
734 LOG(prefix
<<"Nameserver "<<qname
<<" IPs: ");
736 for(const auto& addr
: ret
) {
743 LOG((addr
.toString())<<"(" << (boost::format("%0.2f") % (speeds
[addr
]/1000.0)).str() <<"ms)");
752 void SyncRes::getBestNSFromCache(const DNSName
&qname
, const QType
& qtype
, vector
<DNSRecord
>& bestns
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
)
755 DNSName
subdomain(qname
);
758 prefix
.append(depth
, ' ');
764 LOG(prefix
<<qname
<<": Checking if we have NS in cache for '"<<subdomain
<<"'"<<endl
);
765 vector
<DNSRecord
> ns
;
766 *flawedNSSet
= false;
768 if(t_RC
->get(d_now
.tv_sec
, subdomain
, QType(QType::NS
), false, &ns
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
) > 0) {
769 for(auto k
=ns
.cbegin();k
!=ns
.cend(); ++k
) {
770 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
771 vector
<DNSRecord
> aset
;
773 const DNSRecord
& dr
=*k
;
774 auto nrr
= getRR
<NSRecordContent
>(dr
);
775 if(nrr
&& (!nrr
->getNS().isPartOf(subdomain
) || t_RC
->get(d_now
.tv_sec
, nrr
->getNS(), s_doIPv6
? QType(QType::ADDR
) : QType(QType::A
),
776 false, doLog() ? &aset
: 0, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
) > 5)) {
777 bestns
.push_back(dr
);
778 LOG(prefix
<<qname
<<": NS (with ip, or non-glue) in cache for '"<<subdomain
<<"' -> '"<<nrr
->getNS()<<"'"<<endl
);
779 LOG(prefix
<<qname
<<": within bailiwick: "<< nrr
->getNS().isPartOf(subdomain
));
781 LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset
.begin()->d_ttl
- d_now
.tv_sec
))<<endl
);
784 LOG(", not in cache / did not look at cache"<<endl
);
789 LOG(prefix
<<qname
<<": NS in cache for '"<<subdomain
<<"', but needs glue ("<<nrr
->getNS()<<") which we miss or is expired"<<endl
);
794 if(!bestns
.empty()) {
795 GetBestNSAnswer answer
;
797 answer
.qtype
=qtype
.getCode();
798 for(const auto& dr
: bestns
) {
799 if (auto nsContent
= getRR
<NSRecordContent
>(dr
)) {
800 answer
.bestns
.insert(make_pair(dr
.d_name
, nsContent
->getNS()));
804 if(beenthere
.count(answer
)) {
806 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' but part of LOOP (already seen "<<answer
.qname
<<")! Trying less specific NS"<<endl
);
809 for( set
<GetBestNSAnswer
>::const_iterator j
=beenthere
.begin();j
!=beenthere
.end();++j
) {
810 bool neo
= !(*j
< answer
|| answer
<*j
);
811 LOG(prefix
<<qname
<<": beenthere"<<(neo
?"*":"")<<": "<<j
->qname
<<"|"<<DNSRecordContent::NumberToType(j
->qtype
)<<" ("<<(unsigned int)j
->bestns
.size()<<")"<<endl
);
816 beenthere
.insert(answer
);
817 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' (flawedNSSet="<<*flawedNSSet
<<")"<<endl
);
822 LOG(prefix
<<qname
<<": no valid/useful NS in cache for '"<<subdomain
<<"'"<<endl
);
824 if(subdomain
.isRoot() && !brokeloop
) {
825 // We lost the root NS records
827 LOG(prefix
<<qname
<<": reprimed the root"<<endl
);
828 /* let's prevent an infinite loop */
829 if (!d_updatingRootNS
) {
830 getRootNS(d_now
, d_asyncResolve
);
833 } while(subdomain
.chopOff());
836 SyncRes::domainmap_t::const_iterator
SyncRes::getBestAuthZone(DNSName
* qname
) const
838 SyncRes::domainmap_t::const_iterator ret
;
840 ret
=t_sstorage
.domainmap
->find(*qname
);
841 if(ret
!=t_sstorage
.domainmap
->end())
843 }while(qname
->chopOff());
847 /** doesn't actually do the work, leaves that to getBestNSFromCache */
848 DNSName
SyncRes::getBestNSNamesFromCache(const DNSName
&qname
, const QType
& qtype
, NsSet
& nsset
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
)
850 DNSName
subdomain(qname
);
851 DNSName
authdomain(qname
);
853 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
854 if(iter
!=t_sstorage
.domainmap
->end()) {
855 if( iter
->second
.isAuth() )
856 // this gets picked up in doResolveAt, the empty DNSName, combined with the
857 // empty vector means 'we are auth for this zone'
858 nsset
.insert({DNSName(), {{}, false}});
860 // Again, picked up in doResolveAt. An empty DNSName, combined with a
861 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
862 // This is actually picked up in retrieveAddressesForNS called from doResolveAt.
863 nsset
.insert({DNSName(), {iter
->second
.d_servers
, iter
->second
.shouldRecurse() }});
868 vector
<DNSRecord
> bestns
;
869 getBestNSFromCache(subdomain
, qtype
, bestns
, flawedNSSet
, depth
, beenthere
);
871 for(auto k
=bestns
.cbegin() ; k
!= bestns
.cend(); ++k
) {
872 // The actual resolver code will not even look at the ComboAddress or bool
873 const auto nsContent
= getRR
<NSRecordContent
>(*k
);
875 nsset
.insert({nsContent
->getNS(), {{}, false}});
876 if(k
==bestns
.cbegin())
883 bool SyncRes::doCNAMECacheCheck(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>& ret
, unsigned int depth
, int &res
, vState
& state
, bool wasAuthZone
)
888 prefix
.append(depth
, ' ');
891 if((depth
>9 && d_outqueries
>10 && d_throttledqueries
>5) || depth
> 15) {
892 LOG(prefix
<<qname
<<": recursing (CNAME or other indirection) too deep, depth="<<depth
<<endl
);
897 LOG(prefix
<<qname
<<": Looking for CNAME cache hit of '"<<qname
<<"|CNAME"<<"'"<<endl
);
898 vector
<DNSRecord
> cset
;
899 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
900 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
902 if(t_RC
->get(d_now
.tv_sec
, qname
, QType(QType::CNAME
), d_requireAuthData
, &cset
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, d_doDNSSEC
? &signatures
: nullptr, d_doDNSSEC
? &authorityRecs
: nullptr, &d_wasVariable
, &state
, &wasAuth
) > 0) {
904 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
905 if (j
->d_class
!= QClass::IN
) {
909 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
911 if (!wasAuthZone
&& shouldValidate() && wasAuth
&& state
== Indeterminate
&& d_requireAuthData
) {
912 /* This means we couldn't figure out the state when this entry was cached,
913 most likely because we hadn't computed the zone cuts yet. */
914 /* make sure they are computed before validating */
915 DNSName
subdomain(qname
);
916 /* if we are retrieving a DS, we only care about the state of the parent zone */
917 if(qtype
== QType::DS
)
920 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
922 vState recordState
= getValidationStatus(qname
, false);
923 if (recordState
== Secure
) {
924 LOG(prefix
<<qname
<<": got Indeterminate state from the CNAME cache, validating.."<<endl
);
925 state
= SyncRes::validateRecordsWithSigs(depth
, qname
, QType(QType::CNAME
), qname
, cset
, signatures
);
926 if (state
!= Indeterminate
) {
927 LOG(prefix
<<qname
<<": got Indeterminate state from the CNAME cache, new validation result is "<<vStates
[state
]<<endl
);
928 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, QType(QType::CNAME
), d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, d_requireAuthData
, state
);
933 LOG(prefix
<<qname
<<": Found cache CNAME hit for '"<< qname
<< "|CNAME" <<"' to '"<<j
->d_content
->getZoneRepresentation()<<"', validation state is "<<vStates
[state
]<<endl
);
936 dr
.d_ttl
-=d_now
.tv_sec
;
939 for(const auto& signature
: signatures
) {
941 sigdr
.d_type
=QType::RRSIG
;
943 sigdr
.d_ttl
=j
->d_ttl
- d_now
.tv_sec
;
944 sigdr
.d_content
=signature
;
945 sigdr
.d_place
=DNSResourceRecord::ANSWER
;
946 sigdr
.d_class
=QClass::IN
;
947 ret
.push_back(sigdr
);
950 for(const auto& rec
: authorityRecs
) {
951 DNSRecord
authDR(*rec
);
952 authDR
.d_ttl
=j
->d_ttl
- d_now
.tv_sec
;
953 ret
.push_back(authDR
);
956 if(qtype
!= QType::CNAME
) { // perhaps they really wanted a CNAME!
957 set
<GetBestNSAnswer
>beenthere
;
959 vState cnameState
= Indeterminate
;
960 const auto cnameContent
= getRR
<CNAMERecordContent
>(*j
);
962 res
=doResolve(cnameContent
->getTarget(), qtype
, ret
, depth
+1, beenthere
, cnameState
);
963 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
964 updateValidationState(state
, cnameState
);
974 LOG(prefix
<<qname
<<": No CNAME cache hit of '"<< qname
<< "|CNAME" <<"' found"<<endl
);
981 vector
<DNSRecord
> records
;
982 vector
<shared_ptr
<RRSIGRecordContent
>> signatures
;
983 uint32_t signaturesTTL
{std::numeric_limits
<uint32_t>::max()};
989 DNSResourceRecord::Place place
;
990 bool operator<(const CacheKey
& rhs
) const {
991 return tie(name
, type
) < tie(rhs
.name
, rhs
.type
);
994 typedef map
<CacheKey
, CacheEntry
> tcache_t
;
997 static void reapRecordsFromNegCacheEntryForValidation(tcache_t
& tcache
, const vector
<DNSRecord
>& records
)
999 for (const auto& rec
: records
) {
1000 if (rec
.d_type
== QType::RRSIG
) {
1001 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1003 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
1006 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(rec
);
1012 * Convience function to push the records from records into ret with a new TTL
1014 * \param records DNSRecords that need to go into ret
1015 * \param ttl The new TTL for these records
1016 * \param ret The vector of DNSRecords that should contian the records with the modified TTL
1018 static void addTTLModifiedRecords(const vector
<DNSRecord
>& records
, const uint32_t ttl
, vector
<DNSRecord
>& ret
) {
1019 for (const auto& rec
: records
) {
1026 void SyncRes::computeNegCacheValidationStatus(NegCache::NegCacheEntry
& ne
, const DNSName
& qname
, const QType
& qtype
, const int res
, vState
& state
, unsigned int depth
)
1028 DNSName
subdomain(qname
);
1029 /* if we are retrieving a DS, we only care about the state of the parent zone */
1030 if(qtype
== QType::DS
)
1031 subdomain
.chopOff();
1033 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1036 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.authoritySOA
.records
);
1037 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.authoritySOA
.signatures
);
1038 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.DNSSECRecords
.records
);
1039 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.DNSSECRecords
.signatures
);
1041 for (const auto& entry
: tcache
) {
1042 // this happens when we did store signatures, but passed on the records themselves
1043 if (entry
.second
.records
.empty()) {
1047 const DNSName
& owner
= entry
.first
.name
;
1049 vState recordState
= getValidationStatus(owner
, false);
1050 if (state
== Indeterminate
) {
1051 state
= recordState
;
1054 if (recordState
== Secure
) {
1055 recordState
= SyncRes::validateRecordsWithSigs(depth
, qname
, qtype
, owner
, entry
.second
.records
, entry
.second
.signatures
);
1058 if (recordState
!= Indeterminate
&& recordState
!= state
) {
1059 updateValidationState(state
, recordState
);
1060 if (state
!= Secure
) {
1066 if (state
== Secure
) {
1067 dState expectedState
= res
== RCode::NXDomain
? NXDOMAIN
: NXQTYPE
;
1068 dState denialState
= getDenialValidationState(ne
, state
, expectedState
, false);
1069 updateDenialValidationState(ne
, state
, denialState
, expectedState
, qtype
== QType::DS
);
1071 if (state
!= Indeterminate
) {
1072 /* validation succeeded, let's update the cache entry so we don't have to validate again */
1073 t_sstorage
.negcache
.updateValidationStatus(ne
.d_name
, ne
.d_qtype
, state
);
1077 bool SyncRes::doCacheCheck(const DNSName
&qname
, const DNSName
& authname
, bool wasForwardedOrAuthZone
, bool wasAuthZone
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int &res
, vState
& state
)
1079 bool giveNegative
=false;
1084 prefix
.append(depth
, ' ');
1087 // sqname and sqtype are used contain 'higher' names if we have them (e.g. powerdns.com|SOA when we find a negative entry for doesnotexists.powerdns.com|A)
1088 DNSName
sqname(qname
);
1091 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
1093 NegCache::NegCacheEntry ne
;
1096 t_sstorage
.negcache
.getRootNXTrust(qname
, d_now
, ne
) &&
1097 ne
.d_auth
.isRoot() &&
1098 !(wasForwardedOrAuthZone
&& !authname
.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
1099 sttl
= ne
.d_ttd
- d_now
.tv_sec
;
1100 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
.d_auth
<<"' & '"<<ne
.d_name
<<"' for another "<<sttl
<<" seconds"<<endl
);
1101 res
= RCode::NXDomain
;
1102 giveNegative
= true;
1103 cachedState
= ne
.d_validationState
;
1105 else if (t_sstorage
.negcache
.get(qname
, qtype
, d_now
, ne
) &&
1106 !(wasForwardedOrAuthZone
&& ne
.d_auth
!= authname
)) { // Only the authname nameserver can neg cache entries
1108 /* If we are looking for a DS, discard NXD if auth == qname
1109 and ask for a specific denial instead */
1110 if (qtype
!= QType::DS
|| ne
.d_qtype
.getCode() || ne
.d_auth
!= qname
||
1111 t_sstorage
.negcache
.get(qname
, qtype
, d_now
, ne
, true))
1114 sttl
= ne
.d_ttd
- d_now
.tv_sec
;
1115 giveNegative
= true;
1116 cachedState
= ne
.d_validationState
;
1117 if(ne
.d_qtype
.getCode()) {
1118 LOG(prefix
<<qname
<<": "<<qtype
.getName()<<" is negatively cached via '"<<ne
.d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1119 res
= RCode::NoError
;
1122 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
.d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1123 res
= RCode::NXDomain
;
1130 state
= cachedState
;
1132 if (!wasAuthZone
&& shouldValidate() && state
== Indeterminate
) {
1133 LOG(prefix
<<qname
<<": got Indeterminate state for records retrieved from the negative cache, validating.."<<endl
);
1134 computeNegCacheValidationStatus(ne
, qname
, qtype
, res
, state
, depth
);
1137 // Transplant SOA to the returned packet
1138 addTTLModifiedRecords(ne
.authoritySOA
.records
, sttl
, ret
);
1140 addTTLModifiedRecords(ne
.authoritySOA
.signatures
, sttl
, ret
);
1141 addTTLModifiedRecords(ne
.DNSSECRecords
.records
, sttl
, ret
);
1142 addTTLModifiedRecords(ne
.DNSSECRecords
.signatures
, sttl
, ret
);
1145 LOG(prefix
<<qname
<<": updating validation state with negative cache content for "<<qname
<<" to "<<vStates
[state
]<<endl
);
1149 vector
<DNSRecord
> cset
;
1150 bool found
=false, expired
=false;
1151 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
1152 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1155 if(t_RC
->get(d_now
.tv_sec
, sqname
, sqt
, d_requireAuthData
, &cset
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, d_doDNSSEC
? &signatures
: nullptr, d_doDNSSEC
? &authorityRecs
: nullptr, &d_wasVariable
, &cachedState
, &wasCachedAuth
) > 0) {
1157 LOG(prefix
<<sqname
<<": Found cache hit for "<<sqt
.getName()<<": ");
1159 if (!wasAuthZone
&& shouldValidate() && wasCachedAuth
&& cachedState
== Indeterminate
&& d_requireAuthData
) {
1161 /* This means we couldn't figure out the state when this entry was cached,
1162 most likely because we hadn't computed the zone cuts yet. */
1163 /* make sure they are computed before validating */
1164 DNSName
subdomain(sqname
);
1165 /* if we are retrieving a DS, we only care about the state of the parent zone */
1166 if(qtype
== QType::DS
)
1167 subdomain
.chopOff();
1169 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1171 vState recordState
= getValidationStatus(qname
, false);
1172 if (recordState
== Secure
) {
1173 LOG(prefix
<<sqname
<<": got Indeterminate state from the cache, validating.."<<endl
);
1174 cachedState
= SyncRes::validateRecordsWithSigs(depth
, sqname
, sqt
, sqname
, cset
, signatures
);
1177 cachedState
= recordState
;
1180 if (cachedState
!= Indeterminate
) {
1181 LOG(prefix
<<qname
<<": got Indeterminate state from the cache, validation result is "<<vStates
[cachedState
]<<endl
);
1182 t_RC
->updateValidationStatus(d_now
.tv_sec
, sqname
, sqt
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, d_requireAuthData
, cachedState
);
1186 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
1188 LOG(j
->d_content
->getZoneRepresentation());
1190 if (j
->d_class
!= QClass::IN
) {
1194 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
1196 ttl
= (dr
.d_ttl
-=d_now
.tv_sec
);
1198 LOG("[ttl="<<dr
.d_ttl
<<"] ");
1207 for(const auto& signature
: signatures
) {
1209 dr
.d_type
=QType::RRSIG
;
1212 dr
.d_content
=signature
;
1213 dr
.d_place
= DNSResourceRecord::ANSWER
;
1214 dr
.d_class
=QClass::IN
;
1218 for(const auto& rec
: authorityRecs
) {
1225 if(found
&& !expired
) {
1228 LOG(prefix
<<qname
<<": updating validation state with cache content for "<<qname
<<" to "<<vStates
[cachedState
]<<endl
);
1229 state
= cachedState
;
1233 LOG(prefix
<<qname
<<": cache had only stale entries"<<endl
);
1239 bool SyncRes::moreSpecificThan(const DNSName
& a
, const DNSName
&b
) const
1241 return (a
.isPartOf(b
) && a
.countLabels() > b
.countLabels());
1246 speedOrder(map
<DNSName
,double> &speeds
) : d_speeds(speeds
) {}
1247 bool operator()(const DNSName
&a
, const DNSName
&b
) const
1249 return d_speeds
[a
] < d_speeds
[b
];
1251 map
<DNSName
, double>& d_speeds
;
1254 inline vector
<DNSName
> SyncRes::shuffleInSpeedOrder(NsSet
&tnameservers
, const string
&prefix
)
1256 vector
<DNSName
> rnameservers
;
1257 rnameservers
.reserve(tnameservers
.size());
1258 for(const auto& tns
: tnameservers
) {
1259 rnameservers
.push_back(tns
.first
);
1260 if(tns
.first
.empty()) // this was an authoritative OOB zone, don't pollute the nsSpeeds with that
1261 return rnameservers
;
1263 map
<DNSName
, double> speeds
;
1265 for(const auto& val
: rnameservers
) {
1267 speed
=t_sstorage
.nsSpeeds
[val
].get(&d_now
);
1270 random_shuffle(rnameservers
.begin(),rnameservers
.end(), dns_random
);
1271 speedOrder
so(speeds
);
1272 stable_sort(rnameservers
.begin(),rnameservers
.end(), so
);
1275 LOG(prefix
<<"Nameservers: ");
1276 for(vector
<DNSName
>::const_iterator i
=rnameservers
.begin();i
!=rnameservers
.end();++i
) {
1277 if(i
!=rnameservers
.begin()) {
1279 if(!((i
-rnameservers
.begin())%3)) {
1280 LOG(endl
<<prefix
<<" ");
1283 LOG((i
->empty() ? string("<empty>") : i
->toString())<<"(" << (boost::format("%0.2f") % (speeds
[*i
]/1000.0)).str() <<"ms)");
1287 return rnameservers
;
1290 static uint32_t getRRSIGTTL(const time_t now
, const std::shared_ptr
<RRSIGRecordContent
>& rrsig
)
1293 if (now
< rrsig
->d_sigexpire
) {
1294 res
= static_cast<uint32_t>(rrsig
->d_sigexpire
) - now
;
1299 static const set
<uint16_t> nsecTypes
= {QType::NSEC
, QType::NSEC3
};
1301 /* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
1303 * \param records The records to parse for the authority SOA and NSEC(3) records
1304 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
1306 static void harvestNXRecords(const vector
<DNSRecord
>& records
, NegCache::NegCacheEntry
& ne
, const time_t now
, uint32_t* lowestTTL
) {
1307 for(const auto& rec
: records
) {
1308 if(rec
.d_place
!= DNSResourceRecord::AUTHORITY
)
1309 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
1310 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
1311 // records MUST be in the same section as the records they cover.
1312 // Hence, we ignore all records outside of the AUTHORITY section.
1315 if(rec
.d_type
== QType::RRSIG
) {
1316 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1318 if(rrsig
->d_type
== QType::SOA
) {
1319 ne
.authoritySOA
.signatures
.push_back(rec
);
1320 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1321 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1322 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1325 if(nsecTypes
.count(rrsig
->d_type
)) {
1326 ne
.DNSSECRecords
.signatures
.push_back(rec
);
1327 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1328 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1329 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1335 if(rec
.d_type
== QType::SOA
) {
1336 ne
.authoritySOA
.records
.push_back(rec
);
1338 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1342 if(nsecTypes
.count(rec
.d_type
)) {
1343 ne
.DNSSECRecords
.records
.push_back(rec
);
1345 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1352 static cspmap_t
harvestCSPFromNE(const NegCache::NegCacheEntry
& ne
)
1355 for(const auto& rec
: ne
.DNSSECRecords
.signatures
) {
1356 if(rec
.d_type
== QType::RRSIG
) {
1357 auto rrc
= getRR
<RRSIGRecordContent
>(rec
);
1359 cspmap
[{rec
.d_name
,rrc
->d_type
}].signatures
.push_back(rrc
);
1363 for(const auto& rec
: ne
.DNSSECRecords
.records
) {
1364 cspmap
[{rec
.d_name
, rec
.d_type
}].records
.push_back(rec
.d_content
);
1369 // TODO remove after processRecords is fixed!
1370 // Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
1371 static void addNXNSECS(vector
<DNSRecord
>&ret
, const vector
<DNSRecord
>& records
)
1373 NegCache::NegCacheEntry ne
;
1374 harvestNXRecords(records
, ne
, 0, nullptr);
1375 ret
.insert(ret
.end(), ne
.authoritySOA
.signatures
.begin(), ne
.authoritySOA
.signatures
.end());
1376 ret
.insert(ret
.end(), ne
.DNSSECRecords
.records
.begin(), ne
.DNSSECRecords
.records
.end());
1377 ret
.insert(ret
.end(), ne
.DNSSECRecords
.signatures
.begin(), ne
.DNSSECRecords
.signatures
.end());
1380 bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine
& dfe
, const NsSet
& nameservers
)
1383 for (auto const &ns
: nameservers
) {
1384 d_appliedPolicy
= dfe
.getProcessingPolicy(ns
.first
, d_discardedPolicies
);
1385 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1386 LOG(", however nameserver "<<ns
.first
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1390 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1391 for (auto const &address
: ns
.second
.first
) {
1392 d_appliedPolicy
= dfe
.getProcessingPolicy(address
, d_discardedPolicies
);
1393 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1394 LOG(", however nameserver "<<ns
.first
<<" IP address "<<address
.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1403 bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine
& dfe
, const ComboAddress
& remoteIP
)
1406 d_appliedPolicy
= dfe
.getProcessingPolicy(remoteIP
, d_discardedPolicies
);
1407 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) {
1408 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")+"')");
1415 vector
<ComboAddress
> SyncRes::retrieveAddressesForNS(const std::string
& prefix
, const DNSName
& qname
, vector
<DNSName
>::const_iterator
& tns
, const unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, const vector
<DNSName
>& rnameservers
, NsSet
& nameservers
, bool& sendRDQuery
, bool& pierceDontQuery
, bool& flawedNSSet
, bool cacheOnly
)
1417 vector
<ComboAddress
> result
;
1420 LOG(prefix
<<qname
<<": Trying to resolve NS '"<<*tns
<< "' ("<<1+tns
-rnameservers
.begin()<<"/"<<(unsigned int)rnameservers
.size()<<")"<<endl
);
1421 result
= getAddrs(*tns
, depth
+2, beenthere
, cacheOnly
);
1422 pierceDontQuery
=false;
1425 LOG(prefix
<<qname
<<": Domain has hardcoded nameserver");
1427 result
= nameservers
[*tns
].first
;
1428 if(result
.size() > 1) {
1433 sendRDQuery
= nameservers
[*tns
].second
;
1434 pierceDontQuery
=true;
1439 bool SyncRes::throttledOrBlocked(const std::string
& prefix
, const ComboAddress
& remoteIP
, const DNSName
& qname
, const QType
& qtype
, bool pierceDontQuery
)
1441 if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0))) {
1442 LOG(prefix
<<qname
<<": server throttled "<<endl
);
1443 s_throttledqueries
++; d_throttledqueries
++;
1446 else if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()))) {
1447 LOG(prefix
<<qname
<<": query throttled "<<remoteIP
.toString()<<", "<<qname
<<"; "<<qtype
.getName()<<endl
);
1448 s_throttledqueries
++; d_throttledqueries
++;
1451 else if(!pierceDontQuery
&& s_dontQuery
&& s_dontQuery
->match(&remoteIP
)) {
1452 LOG(prefix
<<qname
<<": not sending query to " << remoteIP
.toString() << ", blocked by 'dont-query' setting" << endl
);
1459 bool SyncRes::validationEnabled() const
1461 return g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
;
1464 uint32_t SyncRes::computeLowestTTD(const std::vector
<DNSRecord
>& records
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, uint32_t signaturesTTL
) const
1466 uint32_t lowestTTD
= std::numeric_limits
<uint32_t>::max();
1467 for(const auto& record
: records
)
1468 lowestTTD
= min(lowestTTD
, record
.d_ttl
);
1470 /* even if it was not requested for that request (Process, and neither AD nor DO set),
1471 it might be requested at a later time so we need to be careful with the TTL. */
1472 if (validationEnabled() && !signatures
.empty()) {
1473 /* if we are validating, we don't want to cache records after their signatures expire. */
1474 /* records TTL are now TTD, let's add 'now' to the signatures lowest TTL */
1475 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(signaturesTTL
+ d_now
.tv_sec
));
1477 for(const auto& sig
: signatures
) {
1478 if (isRRSIGNotExpired(d_now
.tv_sec
, sig
)) {
1479 // we don't decerement d_sigexpire by 'now' because we actually want a TTD, not a TTL */
1480 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(sig
->d_sigexpire
));
1488 void SyncRes::updateValidationState(vState
& state
, const vState stateUpdate
)
1490 LOG(d_prefix
<<"validation state was "<<std::string(vStates
[state
])<<", state update is "<<std::string(vStates
[stateUpdate
]));
1492 if (stateUpdate
== TA
) {
1495 else if (stateUpdate
== NTA
) {
1498 else if (stateUpdate
== Bogus
) {
1501 else if (state
== Indeterminate
) {
1502 state
= stateUpdate
;
1504 else if (stateUpdate
== Insecure
) {
1505 if (state
!= Bogus
) {
1509 LOG(", validation state is now "<<std::string(vStates
[state
])<<endl
);
1512 vState
SyncRes::getTA(const DNSName
& zone
, dsmap_t
& ds
)
1514 auto luaLocal
= g_luaconfs
.getLocal();
1516 if (luaLocal
->dsAnchors
.empty()) {
1517 LOG(d_prefix
<<": No trust anchors configured, everything is Insecure"<<endl
);
1518 /* We have no TA, everything is insecure */
1523 if (haveNegativeTrustAnchor(luaLocal
->negAnchors
, zone
, reason
)) {
1524 LOG(d_prefix
<<": got NTA for '"<<zone
<<"'"<<endl
);
1528 if (getTrustAnchor(luaLocal
->dsAnchors
, zone
, ds
)) {
1529 LOG(d_prefix
<<": got TA for '"<<zone
<<"'"<<endl
);
1533 LOG(d_prefix
<<": no TA found for '"<<zone
<<"' among "<< luaLocal
->dsAnchors
.size()<<endl
);
1536 if (zone
.isRoot()) {
1537 /* No TA for the root */
1541 return Indeterminate
;
1544 static size_t countSupportedDS(const dsmap_t
& dsmap
)
1548 for (const auto& ds
: dsmap
) {
1549 if (isSupportedDS(ds
)) {
1557 vState
SyncRes::getDSRecords(const DNSName
& zone
, dsmap_t
& ds
, bool taOnly
, unsigned int depth
, bool bogusOnNXD
, bool* foundCut
)
1559 vState result
= getTA(zone
, ds
);
1561 if (result
!= Indeterminate
|| taOnly
) {
1563 *foundCut
= (result
!= Indeterminate
);
1567 if (countSupportedDS(ds
) == 0) {
1575 else if (result
== NTA
) {
1582 bool oldSkipCNAME
= d_skipCNAMECheck
;
1583 d_skipCNAMECheck
= true;
1585 std::set
<GetBestNSAnswer
> beenthere
;
1586 std::vector
<DNSRecord
> dsrecords
;
1588 vState state
= Indeterminate
;
1589 int rcode
= doResolve(zone
, QType(QType::DS
), dsrecords
, depth
+ 1, beenthere
, state
);
1590 d_skipCNAMECheck
= oldSkipCNAME
;
1592 if (rcode
== RCode::NoError
|| (rcode
== RCode::NXDomain
&& !bogusOnNXD
)) {
1594 uint8_t bestDigestType
= 0;
1596 if (state
== Secure
) {
1597 bool gotCNAME
= false;
1598 for (const auto& record
: dsrecords
) {
1599 if (record
.d_type
== QType::DS
) {
1600 const auto dscontent
= getRR
<DSRecordContent
>(record
);
1601 if (dscontent
&& isSupportedDS(*dscontent
)) {
1602 // Make GOST a lower prio than SHA256
1603 if (dscontent
->d_digesttype
== DNSSECKeeper::GOST
&& bestDigestType
== DNSSECKeeper::SHA256
) {
1606 if (dscontent
->d_digesttype
> bestDigestType
|| (bestDigestType
== DNSSECKeeper::GOST
&& dscontent
->d_digesttype
== DNSSECKeeper::SHA256
)) {
1607 bestDigestType
= dscontent
->d_digesttype
;
1609 ds
.insert(*dscontent
);
1612 else if (record
.d_type
== QType::CNAME
&& record
.d_name
== zone
) {
1617 /* RFC 4509 section 3: "Validator implementations SHOULD ignore DS RRs containing SHA-1
1618 * digests if DS RRs with SHA-256 digests are present in the DS RRset."
1619 * As SHA348 is specified as well, the spirit of the this line is "use the best algorithm".
1621 for (auto dsrec
= ds
.begin(); dsrec
!= ds
.end(); ) {
1622 if (dsrec
->d_digesttype
!= bestDigestType
) {
1623 dsrec
= ds
.erase(dsrec
);
1630 if (rcode
== RCode::NoError
&& ds
.empty()) {
1632 if (gotCNAME
|| denialProvesNoDelegation(zone
, dsrecords
)) {
1633 /* we are still inside the same Secure zone */
1643 } else if (foundCut
&& rcode
== RCode::NoError
&& !ds
.empty()) {
1651 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
1655 bool SyncRes::haveExactValidationStatus(const DNSName
& domain
)
1657 if (!shouldValidate()) {
1660 const auto& it
= d_cutStates
.find(domain
);
1661 if (it
!= d_cutStates
.cend()) {
1667 vState
SyncRes::getValidationStatus(const DNSName
& subdomain
, bool allowIndeterminate
)
1669 vState result
= Indeterminate
;
1671 if (!shouldValidate()) {
1674 DNSName
name(subdomain
);
1676 const auto& it
= d_cutStates
.find(name
);
1677 if (it
!= d_cutStates
.cend()) {
1678 if (allowIndeterminate
|| it
->second
!= Indeterminate
) {
1679 LOG(d_prefix
<<": got status "<<vStates
[it
->second
]<<" for name "<<subdomain
<<" (from "<<name
<<")"<<endl
);
1684 while (name
.chopOff());
1689 bool SyncRes::lookForCut(const DNSName
& qname
, unsigned int depth
, const vState existingState
, vState
& newState
)
1691 bool foundCut
= false;
1693 vState dsState
= getDSRecords(qname
, ds
, newState
== Bogus
|| existingState
== Insecure
|| existingState
== Bogus
, depth
, false, &foundCut
);
1695 if (dsState
!= Indeterminate
) {
1702 void SyncRes::computeZoneCuts(const DNSName
& begin
, const DNSName
& end
, unsigned int depth
)
1704 if(!begin
.isPartOf(end
)) {
1705 LOG(d_prefix
<<" "<<begin
.toLogString()<<" is not part of "<<end
.toString()<<endl
);
1706 throw PDNSException(begin
.toLogString() + " is not part of " + end
.toString());
1709 if (d_cutStates
.count(begin
) != 0) {
1714 vState cutState
= getDSRecords(end
, ds
, false, depth
);
1715 LOG(d_prefix
<<": setting cut state for "<<end
<<" to "<<vStates
[cutState
]<<endl
);
1716 d_cutStates
[end
] = cutState
;
1718 if (!shouldValidate()) {
1723 std::vector
<string
> labelsToAdd
= begin
.makeRelative(end
).getRawLabels();
1725 bool oldSkipCNAME
= d_skipCNAMECheck
;
1726 d_skipCNAMECheck
= true;
1728 while(qname
!= begin
) {
1729 if (labelsToAdd
.empty())
1732 qname
.prependRawLabel(labelsToAdd
.back());
1733 labelsToAdd
.pop_back();
1734 LOG(d_prefix
<<": - Looking for a cut at "<<qname
<<endl
);
1736 const auto cutIt
= d_cutStates
.find(qname
);
1737 if (cutIt
!= d_cutStates
.cend()) {
1738 if (cutIt
->second
!= Indeterminate
) {
1739 LOG(d_prefix
<<": - Cut already known at "<<qname
<<endl
);
1740 cutState
= cutIt
->second
;
1745 /* no need to look for NS and DS if we are already insecure or bogus,
1748 if (cutState
== Insecure
|| cutState
== Bogus
) {
1750 vState newState
= getDSRecords(qname
, cutDS
, true, depth
);
1751 if (newState
== Indeterminate
) {
1755 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[newState
]<<endl
);
1756 cutState
= newState
;
1758 d_cutStates
[qname
] = cutState
;
1763 vState newState
= Indeterminate
;
1764 /* temporarily mark as Indeterminate, so that we won't enter an endless loop
1765 trying to determine that zone cut again. */
1766 d_cutStates
[qname
] = newState
;
1767 bool foundCut
= lookForCut(qname
, depth
+ 1, cutState
, newState
);
1769 LOG(d_prefix
<<": - Found cut at "<<qname
<<endl
);
1770 if (newState
!= Indeterminate
) {
1771 cutState
= newState
;
1773 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[cutState
]<<endl
);
1774 d_cutStates
[qname
] = cutState
;
1777 /* remove the temporary cut */
1778 LOG(d_prefix
<<qname
<<": removing cut state for "<<qname
<<endl
);
1779 d_cutStates
.erase(qname
);
1783 d_skipCNAMECheck
= oldSkipCNAME
;
1785 LOG(d_prefix
<<": list of cuts from "<<begin
<<" to "<<end
<<endl
);
1786 for (const auto& cut
: d_cutStates
) {
1787 if (cut
.first
.isRoot() || (begin
.isPartOf(cut
.first
) && cut
.first
.isPartOf(end
))) {
1788 LOG(" - "<<cut
.first
<<": "<<vStates
[cut
.second
]<<endl
);
1793 vState
SyncRes::validateDNSKeys(const DNSName
& zone
, const std::vector
<DNSRecord
>& dnskeys
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, unsigned int depth
)
1796 if (!signatures
.empty()) {
1797 DNSName signer
= getSigner(signatures
);
1799 if (!signer
.empty() && zone
.isPartOf(signer
)) {
1800 vState state
= getDSRecords(signer
, ds
, false, depth
);
1802 if (state
!= Secure
) {
1808 skeyset_t tentativeKeys
;
1809 std::vector
<shared_ptr
<DNSRecordContent
> > toSign
;
1811 for (const auto& dnskey
: dnskeys
) {
1812 if (dnskey
.d_type
== QType::DNSKEY
) {
1813 auto content
= getRR
<DNSKEYRecordContent
>(dnskey
);
1815 tentativeKeys
.insert(content
);
1816 toSign
.push_back(content
);
1821 LOG(d_prefix
<<": trying to validate "<<std::to_string(tentativeKeys
.size())<<" DNSKEYs with "<<std::to_string(ds
.size())<<" DS"<<endl
);
1822 skeyset_t validatedKeys
;
1823 validateDNSKeysAgainstDS(d_now
.tv_sec
, zone
, ds
, tentativeKeys
, toSign
, signatures
, validatedKeys
);
1825 LOG(d_prefix
<<": we now have "<<std::to_string(validatedKeys
.size())<<" DNSKEYs"<<endl
);
1827 /* if we found at least one valid RRSIG covering the set,
1828 all tentative keys are validated keys. Otherwise it means
1829 we haven't found at least one DNSKEY and a matching RRSIG
1830 covering this set, this looks Bogus. */
1831 if (validatedKeys
.size() != tentativeKeys
.size()) {
1832 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
1839 vState
SyncRes::getDNSKeys(const DNSName
& signer
, skeyset_t
& keys
, unsigned int depth
)
1841 std::vector
<DNSRecord
> records
;
1842 std::set
<GetBestNSAnswer
> beenthere
;
1843 LOG(d_prefix
<<"Retrieving DNSKeys for "<<signer
<<endl
);
1845 vState state
= Indeterminate
;
1846 /* following CNAME might lead to us to the wrong DNSKEY */
1847 bool oldSkipCNAME
= d_skipCNAMECheck
;
1848 d_skipCNAMECheck
= true;
1849 int rcode
= doResolve(signer
, QType(QType::DNSKEY
), records
, depth
+ 1, beenthere
, state
);
1850 d_skipCNAMECheck
= oldSkipCNAME
;
1852 if (rcode
== RCode::NoError
) {
1853 if (state
== Secure
) {
1854 for (const auto& key
: records
) {
1855 if (key
.d_type
== QType::DNSKEY
) {
1856 auto content
= getRR
<DNSKEYRecordContent
>(key
);
1858 keys
.insert(content
);
1863 LOG(d_prefix
<<"Retrieved "<<keys
.size()<<" DNSKeys for "<<signer
<<", state is "<<vStates
[state
]<<endl
);
1867 LOG(d_prefix
<<"Returning Bogus state from "<<__func__
<<"("<<signer
<<")"<<endl
);
1871 vState
SyncRes::validateRecordsWithSigs(unsigned int depth
, const DNSName
& qname
, const QType
& qtype
, const DNSName
& name
, const std::vector
<DNSRecord
>& records
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
)
1874 if (!signatures
.empty()) {
1875 const DNSName signer
= getSigner(signatures
);
1876 if (!signer
.empty() && name
.isPartOf(signer
)) {
1877 if ((qtype
== QType::DNSKEY
|| qtype
== QType::DS
) && signer
== qname
) {
1878 /* we are already retrieving those keys, sorry */
1879 return Indeterminate
;
1881 vState state
= getDNSKeys(signer
, keys
, depth
);
1882 if (state
!= Secure
) {
1887 LOG(d_prefix
<<"Bogus!"<<endl
);
1891 std::vector
<std::shared_ptr
<DNSRecordContent
> > recordcontents
;
1892 for (const auto& record
: records
) {
1893 recordcontents
.push_back(record
.d_content
);
1896 LOG(d_prefix
<<"Going to validate "<<recordcontents
.size()<< " record contents with "<<signatures
.size()<<" sigs and "<<keys
.size()<<" keys for "<<name
<<endl
);
1897 if (validateWithKeySet(d_now
.tv_sec
, name
, recordcontents
, signatures
, keys
, false)) {
1898 LOG(d_prefix
<<"Secure!"<<endl
);
1902 LOG(d_prefix
<<"Bogus!"<<endl
);
1906 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
, unsigned int& wildcardLabelsCount
)
1913 prefix
.append(depth
, ' ');
1916 std::vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1917 const unsigned int labelCount
= qname
.countLabels();
1918 bool isCNAMEAnswer
= false;
1919 for(const auto& rec
: lwr
.d_records
) {
1920 if (rec
.d_class
!= QClass::IN
) {
1924 if(!isCNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
) {
1925 isCNAMEAnswer
= true;
1928 /* if we have a positive answer synthetized from a wildcard,
1929 we need to store the corresponding NSEC/NSEC3 records proving
1930 that the exact name did not exist in the negative cache */
1931 if(needWildcardProof
) {
1932 if (nsecTypes
.count(rec
.d_type
)) {
1933 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
1935 else if (rec
.d_type
== QType::RRSIG
) {
1936 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1937 if (rrsig
&& nsecTypes
.count(rrsig
->d_type
)) {
1938 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
1942 if(rec
.d_type
== QType::RRSIG
) {
1943 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1945 /* As illustrated in rfc4035's Appendix B.6, the RRSIG label
1946 count can be lower than the name's label count if it was
1947 synthetized from the wildcard. Note that the difference might
1949 if (rec
.d_name
== qname
&& rrsig
->d_labels
< labelCount
) {
1950 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthetized from a wildcard, we need a wildcard proof"<<endl
);
1951 needWildcardProof
= true;
1952 wildcardLabelsCount
= rrsig
->d_labels
;
1955 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
1956 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
1957 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
);
1962 // reap all answers from this packet that are acceptable
1963 for(auto& rec
: lwr
.d_records
) {
1964 if(rec
.d_type
== QType::OPT
) {
1965 LOG(prefix
<<qname
<<": OPT answer '"<<rec
.d_name
<<"' from '"<<auth
<<"' nameservers" <<endl
);
1968 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
<<" ");
1969 if(rec
.d_type
== QType::ANY
) {
1970 LOG("NO! - we don't accept 'ANY'-typed data"<<endl
);
1974 if(rec
.d_class
!= QClass::IN
) {
1975 LOG("NO! - we don't accept records for any other class than 'IN'"<<endl
);
1979 if(rec
.d_name
.isPartOf(auth
)) {
1980 if(rec
.d_type
== QType::RRSIG
) {
1981 LOG("RRSIG - separate"<<endl
);
1983 else if(lwr
.d_aabit
&& lwr
.d_rcode
==RCode::NoError
&& rec
.d_place
==DNSResourceRecord::ANSWER
&& ((rec
.d_type
!= QType::DNSKEY
&& rec
.d_type
!= QType::DS
) || rec
.d_name
!= auth
) && s_delegationOnly
.count(auth
)) {
1984 LOG("NO! Is from delegation-only zone"<<endl
);
1986 return RCode::NXDomain
;
1989 bool haveLogged
= false;
1990 if (!t_sstorage
.domainmap
->empty()) {
1991 // Check if we are authoritative for a zone in this answer
1992 DNSName
tmp_qname(rec
.d_name
);
1993 auto auth_domain_iter
=getBestAuthZone(&tmp_qname
);
1994 if(auth_domain_iter
!=t_sstorage
.domainmap
->end() &&
1995 auth
.countLabels() <= auth_domain_iter
->first
.countLabels()) {
1996 if (auth_domain_iter
->first
!= auth
) {
1997 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter
->first
<<endl
);
2000 LOG("YES! - This answer was ");
2001 if (!wasForwarded
) {
2002 LOG("retrieved from the local auth store.");
2004 LOG("received from a server we forward to.");
2015 rec
.d_ttl
=min(s_maxcachettl
, rec
.d_ttl
);
2018 dr
.d_ttl
+= d_now
.tv_sec
;
2019 dr
.d_place
=DNSResourceRecord::ANSWER
;
2020 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(dr
);
2028 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2029 if((i
->second
.records
.size() + i
->second
.signatures
.size()) > 1) { // need to group the ttl to be the minimum of the RRSET (RFC 2181, 5.2)
2030 uint32_t lowestTTD
=computeLowestTTD(i
->second
.records
, i
->second
.signatures
, i
->second
.signaturesTTL
);
2032 for(auto& record
: i
->second
.records
)
2033 record
.d_ttl
= lowestTTD
; // boom
2036 // cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
2037 // cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
2040 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2042 if(i
->second
.records
.empty()) // this happens when we did store signatures, but passed on the records themselves
2045 /* Even if the AA bit is set, additional data cannot be considered
2046 as authoritative. This is especially important during validation
2047 because keeping records in the additional section is allowed even
2048 if the corresponding RRSIGs are not included, without setting the TC
2049 bit, as stated in rfc4035's section 3.1.1. Including RRSIG RRs in a Response:
2050 "When placing a signed RRset in the Additional section, the name
2051 server MUST also place its RRSIG RRs in the Additional section.
2052 If space does not permit inclusion of both the RRset and its
2053 associated RRSIG RRs, the name server MAY retain the RRset while
2054 dropping the RRSIG RRs. If this happens, the name server MUST NOT
2055 set the TC bit solely because these RRSIG RRs didn't fit."
2057 bool isAA
= lwr
.d_aabit
&& i
->first
.place
!= DNSResourceRecord::ADDITIONAL
;
2058 if (isAA
&& isCNAMEAnswer
&& (i
->first
.place
!= DNSResourceRecord::ANSWER
|| i
->first
.type
!= QType::CNAME
|| i
->first
.name
!= qname
)) {
2061 Note that the answer section of an authoritative answer normally
2062 contains only authoritative data. However when the name sought is an
2063 alias (see section 10.1.1) only the record describing that alias is
2064 necessarily authoritative. Clients should assume that other records
2065 may have come from the server's cache. Where authoritative answers
2066 are required, the client should query again, using the canonical name
2067 associated with the alias.
2072 vState recordState
= getValidationStatus(i
->first
.name
, false);
2073 LOG(d_prefix
<<": got initial zone status "<<vStates
[recordState
]<<" for record "<<i
->first
.name
<<endl
);
2075 if (shouldValidate() && recordState
== Secure
) {
2076 vState initialState
= recordState
;
2079 if (i
->first
.place
!= DNSResourceRecord::ADDITIONAL
) {
2080 /* the additional entries can be insecure,
2082 "Glue address RRsets associated with delegations MUST NOT be signed"
2084 if (i
->first
.type
== QType::DNSKEY
&& i
->first
.place
== DNSResourceRecord::ANSWER
) {
2085 LOG(d_prefix
<<"Validating DNSKEY for "<<i
->first
.name
<<endl
);
2086 recordState
= validateDNSKeys(i
->first
.name
, i
->second
.records
, i
->second
.signatures
, depth
);
2089 LOG(d_prefix
<<"Validating non-additional record for "<<i
->first
.name
<<endl
);
2090 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2091 /* we might have missed a cut (zone cut within the same auth servers), causing the NS query for an Insecure zone to seem Bogus during zone cut determination */
2092 if (qtype
== QType::NS
&& i
->second
.signatures
.empty() && recordState
== Bogus
&& haveExactValidationStatus(i
->first
.name
) && getValidationStatus(i
->first
.name
) == Indeterminate
) {
2093 recordState
= Indeterminate
;
2099 recordState
= Indeterminate
;
2101 /* in a non authoritative answer, we only care about the DS record (or lack of) */
2102 if ((i
->first
.type
== QType::DS
|| i
->first
.type
== QType::NSEC
|| i
->first
.type
== QType::NSEC3
) && i
->first
.place
== DNSResourceRecord::AUTHORITY
) {
2103 LOG(d_prefix
<<"Validating DS record for "<<i
->first
.name
<<endl
);
2104 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2108 if (initialState
== Secure
&& state
!= recordState
&& isAA
) {
2109 updateValidationState(state
, recordState
);
2113 if (shouldValidate()) {
2114 LOG(d_prefix
<<"Skipping validation because the current state is "<<vStates
[recordState
]<<endl
);
2118 /* We don't need to store NSEC3 records in the positive cache because:
2119 - we don't allow direct NSEC3 queries
2120 - denial of existence proofs in wildcard expanded positive responses are stored in authorityRecs
2121 - denial of existence proofs for negative responses are stored in the negative cache
2123 if (i
->first
.type
!= QType::NSEC3
) {
2124 t_RC
->replace(d_now
.tv_sec
, i
->first
.name
, QType(i
->first
.type
), i
->second
.records
, i
->second
.signatures
, authorityRecs
, i
->first
.type
== QType::DS
? true : isAA
, i
->first
.place
== DNSResourceRecord::ANSWER
? ednsmask
: boost::none
, recordState
);
2127 if(i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
)
2131 return RCode::NoError
;
2134 void SyncRes::updateDenialValidationState(NegCache::NegCacheEntry
& ne
, vState
& state
, const dState denialState
, const dState expectedState
, bool allowOptOut
)
2136 if (denialState
== expectedState
) {
2137 ne
.d_validationState
= Secure
;
2140 if (denialState
== OPTOUT
&& allowOptOut
) {
2141 LOG(d_prefix
<<"OPT-out denial found for "<<ne
.d_name
<<endl
);
2142 ne
.d_validationState
= Secure
;
2145 else if (denialState
== INSECURE
) {
2146 LOG(d_prefix
<<"Insecure denial found for "<<ne
.d_name
<<", returning Insecure"<<endl
);
2147 ne
.d_validationState
= Insecure
;
2150 LOG(d_prefix
<<"Invalid denial found for "<<ne
.d_name
<<", returning Bogus, res="<<denialState
<<", expectedState="<<expectedState
<<endl
);
2151 ne
.d_validationState
= Bogus
;
2153 updateValidationState(state
, ne
.d_validationState
);
2157 dState
SyncRes::getDenialValidationState(NegCache::NegCacheEntry
& ne
, const vState state
, const dState expectedState
, bool referralToUnsigned
)
2159 cspmap_t csp
= harvestCSPFromNE(ne
);
2160 return getDenial(csp
, ne
.d_name
, ne
.d_qtype
.getCode(), referralToUnsigned
, expectedState
== NXQTYPE
);
2163 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 unsigned int wildcardLabelsCount
)
2167 for(auto& rec
: lwr
.d_records
) {
2168 if (rec
.d_type
!=QType::OPT
&& rec
.d_class
!=QClass::IN
)
2171 if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2172 lwr
.d_rcode
==RCode::NXDomain
&& qname
.isPartOf(rec
.d_name
) && rec
.d_name
.isPartOf(auth
)) {
2173 LOG(prefix
<<qname
<<": got negative caching indication for name '"<<qname
<<"' (accept="<<rec
.d_name
.isPartOf(auth
)<<"), newtarget='"<<newtarget
<<"'"<<endl
);
2175 rec
.d_ttl
= min(rec
.d_ttl
, s_maxnegttl
);
2176 if(newtarget
.empty()) // only add a SOA if we're not going anywhere after this
2179 NegCache::NegCacheEntry ne
;
2181 uint32_t lowestTTL
= rec
.d_ttl
;
2182 /* if we get an NXDomain answer with a CNAME, the name
2183 does exist but the target does not */
2184 ne
.d_name
= newtarget
.empty() ? qname
: newtarget
;
2185 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2186 ne
.d_auth
= rec
.d_name
;
2187 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2188 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2190 if (state
== Secure
) {
2191 dState denialState
= getDenialValidationState(ne
, state
, NXDOMAIN
, false);
2192 updateDenialValidationState(ne
, state
, denialState
, NXDOMAIN
, false);
2195 ne
.d_validationState
= state
;
2198 /* if we get an NXDomain answer with a CNAME, let's not cache the
2199 target, even the server was authoritative for it,
2200 and do an additional query for the CNAME target.
2201 We have a regression test making sure we do exactly that.
2203 if(!wasVariable() && newtarget
.empty()) {
2204 t_sstorage
.negcache
.add(ne
);
2205 if(s_rootNXTrust
&& ne
.d_auth
.isRoot() && auth
.isRoot()) {
2206 ne
.d_name
= ne
.d_name
.getLastLabel();
2207 t_sstorage
.negcache
.add(ne
);
2213 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_type
==QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
) {
2215 if (auto content
= getRR
<CNAMERecordContent
>(rec
)) {
2216 newtarget
=content
->getTarget();
2219 /* if we have a positive answer synthetized from a wildcard, we need to
2220 return the corresponding NSEC/NSEC3 records from the AUTHORITY section
2221 proving that the exact name did not exist */
2222 else if(needWildcardProof
&& (rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::AUTHORITY
) {
2223 ret
.push_back(rec
); // enjoy your DNSSEC
2225 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
2226 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&&
2228 rec
.d_type
==qtype
.getCode() || ((lwr
.d_aabit
|| sendRDQuery
) && qtype
== QType(QType::ANY
))
2232 LOG(prefix
<<qname
<<": answer is in: resolved to '"<< rec
.d_content
->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"'"<<endl
);
2237 if (state
== Secure
&& needWildcardProof
) {
2238 /* We have a positive answer synthetized from a wildcard, we need to check that we have
2239 proof that the exact name doesn't exist so the wildcard can be used,
2240 as described in section 5.3.4 of RFC 4035 and 5.3 of FRC 7129.
2242 NegCache::NegCacheEntry ne
;
2244 uint32_t lowestTTL
= rec
.d_ttl
;
2246 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2247 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2249 cspmap_t csp
= harvestCSPFromNE(ne
);
2250 dState res
= getDenial(csp
, qname
, ne
.d_qtype
.getCode(), false, false, false, wildcardLabelsCount
);
2251 if (res
!= NXDOMAIN
) {
2253 if (res
== INSECURE
) {
2254 /* Some part could not be validated, for example a NSEC3 record with a too large number of iterations,
2255 this is not enough to warrant a Bogus, but go Insecure. */
2257 LOG(d_prefix
<<"Unable to validate denial in wildcard expanded positive response found for "<<qname
<<", returning Insecure, res="<<res
<<endl
);
2260 LOG(d_prefix
<<"Invalid denial in wildcard expanded positive response found for "<<qname
<<", returning Bogus, res="<<res
<<endl
);
2263 updateValidationState(state
, st
);
2264 /* we already stored the record with a different validation status, let's fix it */
2265 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qtype
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, lwr
.d_aabit
, st
);
2269 else if((rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::ANSWER
) {
2270 if(rec
.d_type
!= QType::RRSIG
|| rec
.d_name
== qname
)
2271 ret
.push_back(rec
); // enjoy your DNSSEC
2273 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::NS
&& qname
.isPartOf(rec
.d_name
)) {
2274 if(moreSpecificThan(rec
.d_name
,auth
)) {
2276 LOG(prefix
<<qname
<<": got NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2280 LOG(prefix
<<qname
<<": got upwards/level NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"', had '"<<auth
<<"'"<<endl
);
2282 if (auto content
= getRR
<NSRecordContent
>(rec
)) {
2283 nsset
.insert(content
->getNS());
2286 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::DS
&& qname
.isPartOf(rec
.d_name
)) {
2287 LOG(prefix
<<qname
<<": got DS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2289 else if(realreferral
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& (rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && newauth
.isPartOf(auth
)) {
2290 /* we might have received a denial of the DS, let's check */
2291 if (state
== Secure
) {
2292 NegCache::NegCacheEntry ne
;
2294 ne
.d_name
= newauth
;
2295 ne
.d_qtype
= QType::DS
;
2296 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2297 uint32_t lowestTTL
= rec
.d_ttl
;
2298 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2300 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, true);
2302 if (denialState
== NXQTYPE
|| denialState
== OPTOUT
|| denialState
== INSECURE
) {
2303 ne
.d_ttd
= lowestTTL
+ d_now
.tv_sec
;
2304 ne
.d_validationState
= Secure
;
2305 LOG(prefix
<<qname
<<": got negative indication of DS record for '"<<newauth
<<"'"<<endl
);
2307 if(!wasVariable()) {
2308 t_sstorage
.negcache
.add(ne
);
2311 if (qname
== newauth
&& qtype
== QType::DS
) {
2312 /* we are actually done! */
2319 else if(!done
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2320 lwr
.d_rcode
==RCode::NoError
&& qname
.isPartOf(rec
.d_name
)) {
2321 LOG(prefix
<<qname
<<": got negative caching indication for '"<< qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
2323 if(!newtarget
.empty()) {
2324 LOG(prefix
<<qname
<<": Hang on! Got a redirect to '"<<newtarget
<<"' already"<<endl
);
2327 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2330 NegCache::NegCacheEntry ne
;
2331 ne
.d_auth
= rec
.d_name
;
2332 uint32_t lowestTTL
= rec
.d_ttl
;
2335 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2336 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2338 if (state
== Secure
) {
2339 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, false);
2340 updateDenialValidationState(ne
, state
, denialState
, NXQTYPE
, qtype
== QType::DS
);
2342 ne
.d_validationState
= state
;
2345 if(!wasVariable()) {
2346 if(qtype
.getCode()) { // prevents us from blacking out a whole domain
2347 t_sstorage
.negcache
.add(ne
);
2358 bool SyncRes::doResolveAtThisIP(const std::string
& prefix
, const DNSName
& qname
, const QType
& qtype
, LWResult
& lwr
, boost::optional
<Netmask
>& ednsmask
, const DNSName
& auth
, bool const sendRDQuery
, const DNSName
& nsName
, const ComboAddress
& remoteIP
, bool doTCP
, bool* truncated
)
2360 bool chained
= false;
2361 int resolveret
= RCode::NoError
;
2365 if(d_outqueries
+ d_throttledqueries
> s_maxqperq
) {
2366 throw ImmediateServFailException("more than "+std::to_string(s_maxqperq
)+" (max-qperq) queries sent while resolving "+qname
.toLogString());
2369 if(s_maxtotusec
&& d_totUsec
> s_maxtotusec
) {
2370 throw ImmediateServFailException("Too much time waiting for "+qname
.toLogString()+"|"+qtype
.getName()+", timeouts: "+std::to_string(d_timeouts
) +", throttles: "+std::to_string(d_throttledqueries
) + ", queries: "+std::to_string(d_outqueries
)+", "+std::to_string(d_totUsec
/1000)+"msec");
2374 LOG(prefix
<<qname
<<": using TCP with "<< remoteIP
.toStringWithPort() <<endl
);
2379 if(d_pdl
&& d_pdl
->preoutquery(remoteIP
, d_requestor
, qname
, qtype
, doTCP
, lwr
.d_records
, resolveret
)) {
2380 LOG(prefix
<<qname
<<": query handled by Lua"<<endl
);
2383 ednsmask
=getEDNSSubnetMask(d_requestor
, qname
, remoteIP
);
2385 LOG(prefix
<<qname
<<": Adding EDNS Client Subnet Mask "<<ednsmask
->toString()<<" to query"<<endl
);
2388 resolveret
= asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(),
2389 doTCP
, sendRDQuery
, &d_now
, ednsmask
, &lwr
, &chained
); // <- we go out on the wire!
2392 LOG(prefix
<<qname
<<": Received EDNS Client Subnet Mask "<<ednsmask
->toString()<<" on response"<<endl
);
2396 /* preoutquery killed the query by setting dq.rcode to -3 */
2397 if(resolveret
==-3) {
2398 throw ImmediateServFailException("Query killed by policy");
2401 d_totUsec
+= lwr
.d_usec
;
2402 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
2404 if(resolveret
!= 1) {
2405 /* Error while resolving */
2406 if(resolveret
== 0) {
2409 LOG(prefix
<<qname
<<": timeout resolving after "<<lwr
.d_usec
/1000.0<<"msec "<< (doTCP
? "over TCP" : "")<<endl
);
2411 s_outgoingtimeouts
++;
2413 if(remoteIP
.sin4
.sin_family
== AF_INET
)
2414 s_outgoing4timeouts
++;
2416 s_outgoing6timeouts
++;
2418 else if(resolveret
== -2) {
2419 /* OS resource limit reached */
2420 LOG(prefix
<<qname
<<": hit a local resource limit resolving"<< (doTCP
? " over TCP" : "")<<", probable error: "<<stringerror()<<endl
);
2421 g_stats
.resourceLimits
++;
2424 /* -1 means server unreachable */
2427 LOG(prefix
<<qname
<<": error resolving from "<<remoteIP
.toString()<< (doTCP
? " over TCP" : "") <<", possible error: "<<strerror(errno
)<< endl
);
2430 if(resolveret
!= -2 && !chained
) { // don't account for resource limits, they are our own fault
2431 t_sstorage
.nsSpeeds
[nsName
].submit(remoteIP
, 1000000, &d_now
); // 1 sec
2433 // code below makes sure we don't filter COM or the root
2434 if (s_serverdownmaxfails
> 0 && (auth
!= g_rootdnsname
) && t_sstorage
.fails
.incr(remoteIP
) >= s_serverdownmaxfails
) {
2435 LOG(prefix
<<qname
<<": Max fails reached resolving on "<< remoteIP
.toString() <<". Going full throttle for "<< s_serverdownthrottletime
<<" seconds" <<endl
);
2436 // mark server as down
2437 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0), s_serverdownthrottletime
, 10000);
2439 else if (resolveret
== -1) {
2440 // unreachable, 1 minute or 100 queries
2441 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 100);
2445 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 10, 5);
2452 /* we got an answer */
2453 if(lwr
.d_rcode
==RCode::ServFail
|| lwr
.d_rcode
==RCode::Refused
) {
2454 LOG(prefix
<<qname
<<": "<<nsName
<<" ("<<remoteIP
.toString()<<") returned a "<< (lwr
.d_rcode
==RCode::ServFail
? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl
);
2456 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
2461 /* this server sent a valid answer, mark it backup up if it was down */
2462 if(s_serverdownmaxfails
> 0) {
2463 t_sstorage
.fails
.clear(remoteIP
);
2470 LOG(prefix
<<qname
<<": truncated bit set, over TCP?"<<endl
);
2471 /* let's treat that as a ServFail answer from this server */
2472 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
2482 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
)
2487 prefix
.append(depth
, ' ');
2491 for(auto& rec
: lwr
.d_records
) {
2492 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumTTL
);
2496 bool needWildcardProof
= false;
2497 unsigned int wildcardLabelsCount
;
2498 *rcode
= updateCacheFromRecords(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, state
, needWildcardProof
, wildcardLabelsCount
);
2499 if (*rcode
!= RCode::NoError
) {
2503 LOG(prefix
<<qname
<<": determining status after receiving this packet"<<endl
);
2506 bool realreferral
=false, negindic
=false;
2510 bool done
= processRecords(prefix
, qname
, qtype
, auth
, lwr
, sendRDQuery
, ret
, nsset
, newtarget
, newauth
, realreferral
, negindic
, state
, needWildcardProof
, wildcardLabelsCount
);
2513 LOG(prefix
<<qname
<<": status=got results, this level of recursion done"<<endl
);
2514 LOG(prefix
<<qname
<<": validation status is "<<vStates
[state
]<<endl
);
2515 *rcode
= RCode::NoError
;
2519 if(!newtarget
.empty()) {
2520 if(newtarget
== qname
) {
2521 LOG(prefix
<<qname
<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl
);
2522 *rcode
= RCode::ServFail
;
2527 LOG(prefix
<<qname
<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl
);
2528 *rcode
= RCode::ServFail
;
2532 if (qtype
== QType::DS
) {
2533 LOG(prefix
<<qname
<<": status=got a CNAME referral, but we are looking for a DS"<<endl
);
2536 addNXNSECS(ret
, lwr
.d_records
);
2538 *rcode
= RCode::NoError
;
2542 LOG(prefix
<<qname
<<": status=got a CNAME referral, starting over with "<<newtarget
<<endl
);
2544 set
<GetBestNSAnswer
> beenthere2
;
2545 vState cnameState
= Indeterminate
;
2546 *rcode
= doResolve(newtarget
, qtype
, ret
, depth
+ 1, beenthere2
, cnameState
);
2547 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
2548 updateValidationState(state
, cnameState
);
2553 if(lwr
.d_rcode
== RCode::NXDomain
) {
2554 LOG(prefix
<<qname
<<": status=NXDOMAIN, we are done "<<(negindic
? "(have negative SOA)" : "")<<endl
);
2557 addNXNSECS(ret
, lwr
.d_records
);
2559 *rcode
= RCode::NXDomain
;
2563 if(nsset
.empty() && !lwr
.d_rcode
&& (negindic
|| lwr
.d_aabit
|| sendRDQuery
)) {
2564 LOG(prefix
<<qname
<<": status=noerror, other types may exist, but we are done "<<(negindic
? "(have negative SOA) " : "")<<(lwr
.d_aabit
? "(have aa bit) " : "")<<endl
);
2566 if(state
== Secure
&& lwr
.d_aabit
&& !negindic
) {
2567 updateValidationState(state
, Bogus
);
2571 addNXNSECS(ret
, lwr
.d_records
);
2573 *rcode
= RCode::NoError
;
2578 LOG(prefix
<<qname
<<": status=did not resolve, got "<<(unsigned int)nsset
.size()<<" NS, ");
2580 nameservers
.clear();
2581 for (auto const &nameserver
: nsset
) {
2583 d_appliedPolicy
= dfe
.getProcessingPolicy(nameserver
, d_discardedPolicies
);
2584 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
2585 LOG("however "<<nameserver
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
2590 nameservers
.insert({nameserver
, {{}, false}});
2592 LOG("looping to them"<<endl
);
2593 *gotNewServers
= true;
2603 * -1 in case of no results
2604 * -2 when a FilterEngine Policy was hit
2607 int SyncRes::doResolveAt(NsSet
&nameservers
, DNSName auth
, bool flawedNSSet
, const DNSName
&qname
, const QType
&qtype
,
2608 vector
<DNSRecord
>&ret
,
2609 unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
, vState
& state
)
2611 auto luaconfsLocal
= g_luaconfs
.getLocal();
2615 prefix
.append(depth
, ' ');
2618 LOG(prefix
<<qname
<<": Cache consultations done, have "<<(unsigned int)nameservers
.size()<<" NS to contact");
2620 if (nameserversBlockedByRPZ(luaconfsLocal
->dfe
, nameservers
)) {
2626 for(;;) { // we may get more specific nameservers
2627 vector
<DNSName
> rnameservers
= shuffleInSpeedOrder(nameservers
, doLog() ? (prefix
+qname
.toString()+": ") : string() );
2629 for(auto tns
=rnameservers
.cbegin();;++tns
) {
2630 if(tns
==rnameservers
.cend()) {
2631 LOG(prefix
<<qname
<<": Failed to resolve via any of the "<<(unsigned int)rnameservers
.size()<<" offered NS at level '"<<auth
<<"'"<<endl
);
2632 if(!auth
.isRoot() && flawedNSSet
) {
2633 LOG(prefix
<<qname
<<": Ageing nameservers for level '"<<auth
<<"', next query might succeed"<<endl
);
2635 if(t_RC
->doAgeCache(d_now
.tv_sec
, auth
, QType::NS
, 10))
2636 g_stats
.nsSetInvalidations
++;
2641 bool cacheOnly
= false;
2642 // this line needs to identify the 'self-resolving' behaviour
2643 if(qname
== *tns
&& (qtype
.getCode() == QType::A
|| qtype
.getCode() == QType::AAAA
)) {
2644 /* we might have a glue entry in cache so let's try this NS
2645 but only if we have enough in the cache to know how to reach it */
2646 LOG(prefix
<<qname
<<": Using NS to resolve itself, but only using what we have in cache ("<<(1+tns
-rnameservers
.cbegin())<<"/"<<rnameservers
.size()<<")"<<endl
);
2650 typedef vector
<ComboAddress
> remoteIPs_t
;
2651 remoteIPs_t remoteIPs
;
2652 remoteIPs_t::const_iterator remoteIP
;
2653 bool pierceDontQuery
=false;
2654 bool sendRDQuery
=false;
2655 boost::optional
<Netmask
> ednsmask
;
2657 const bool wasForwarded
= tns
->empty() && (!nameservers
[*tns
].first
.empty());
2658 int rcode
= RCode::NoError
;
2659 bool gotNewServers
= false;
2661 if(tns
->empty() && !wasForwarded
) {
2662 LOG(prefix
<<qname
<<": Domain is out-of-band"<<endl
);
2663 /* setting state to indeterminate since validation is disabled for local auth zone,
2664 and Insecure would be misleading. */
2665 state
= Indeterminate
;
2666 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, lwr
.d_records
, depth
, lwr
.d_rcode
);
2670 /* we have received an answer, are we done ? */
2671 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, false, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
2675 if (gotNewServers
) {
2680 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
2681 remoteIPs
= retrieveAddressesForNS(prefix
, qname
, tns
, depth
, beenthere
, rnameservers
, nameservers
, sendRDQuery
, pierceDontQuery
, flawedNSSet
, cacheOnly
);
2683 if(remoteIPs
.empty()) {
2684 LOG(prefix
<<qname
<<": Failed to get IP for NS "<<*tns
<<", trying next if available"<<endl
);
2689 bool hitPolicy
{false};
2690 LOG(prefix
<<qname
<<": Resolved '"<<auth
<<"' NS "<<*tns
<<" to: ");
2691 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
2692 if(remoteIP
!= remoteIPs
.cbegin()) {
2695 LOG(remoteIP
->toString());
2696 if(nameserverIPBlockedByRPZ(luaconfsLocal
->dfe
, *remoteIP
)) {
2701 if (hitPolicy
) //implies d_wantsRPZ
2705 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
2706 LOG(prefix
<<qname
<<": Trying IP "<< remoteIP
->toStringWithPort() <<", asking '"<<qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
2708 if (throttledOrBlocked(prefix
, *remoteIP
, qname
, qtype
, pierceDontQuery
)) {
2712 bool truncated
= false;
2713 bool gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
2714 *tns
, *remoteIP
, false, &truncated
);
2715 if (gotAnswer
&& truncated
) {
2716 /* retry, over TCP this time */
2717 gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
2718 *tns
, *remoteIP
, true, &truncated
);
2725 LOG(prefix
<<qname
<<": Got "<<(unsigned int)lwr
.d_records
.size()<<" answers from "<<*tns
<<" ("<< remoteIP
->toString() <<"), rcode="<<lwr
.d_rcode
<<" ("<<RCode::to_s(lwr
.d_rcode
)<<"), aa="<<lwr
.d_aabit
<<", in "<<lwr
.d_usec
/1000<<"ms"<<endl
);
2727 /* // for you IPv6 fanatics :-)
2728 if(remoteIP->sin4.sin_family==AF_INET6)
2731 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
2733 t_sstorage
.nsSpeeds
[*tns
].submit(*remoteIP
, lwr
.d_usec
, &d_now
);
2735 /* we have received an answer, are we done ? */
2736 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
2740 if (gotNewServers
) {
2744 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100);
2747 if (gotNewServers
) {
2751 if(remoteIP
== remoteIPs
.cend()) // we tried all IP addresses, none worked
2760 void SyncRes::setIncomingECS(boost::optional
<const EDNSSubnetOpts
&> incomingECS
)
2762 d_incomingECS
= incomingECS
;
2764 if (d_incomingECS
->source
.getBits() == 0) {
2765 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0.
2766 But using an empty ECS in that case would mean inserting
2767 a non ECS-specific entry into the cache, preventing any further
2768 ECS-specific query to be sent.
2769 So instead we use the trick described in section 7.1.2:
2770 "The subsequent Recursive Resolver query to the Authoritative Nameserver
2771 will then either not include an ECS option or MAY optionally include
2772 its own address information, which is what the Authoritative
2773 Nameserver will almost certainly use to generate any Tailored
2774 Response in lieu of an option. This allows the answer to be handled
2775 by the same caching mechanism as other queries, with an explicit
2776 indicator of the applicable scope. Subsequent Stub Resolver queries
2777 for /0 can then be answered from this cached response.
2779 d_incomingECS
= s_ecsScopeZero
;
2780 d_incomingECSNetwork
= s_ecsScopeZero
.source
.getMaskedNetwork();
2783 uint8_t bits
= std::min(incomingECS
->source
.getBits(), (incomingECS
->source
.isIpv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
2784 d_incomingECS
->source
= Netmask(incomingECS
->source
.getNetwork(), bits
);
2785 d_incomingECSNetwork
= d_incomingECS
->source
.getMaskedNetwork();
2789 d_incomingECSNetwork
= ComboAddress();
2793 boost::optional
<Netmask
> SyncRes::getEDNSSubnetMask(const ComboAddress
& local
, const DNSName
&dn
, const ComboAddress
& rem
)
2795 boost::optional
<Netmask
> result
;
2798 if(d_incomingECSFound
) {
2799 trunc
= d_incomingECSNetwork
;
2800 bits
= d_incomingECS
->source
.getBits();
2802 else if(!local
.isIPv4() || local
.sin4
.sin_addr
.s_addr
) { // detect unset 'requestor'
2804 bits
= local
.isIPv4() ? 32 : 128;
2805 bits
= std::min(bits
, (trunc
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
2808 /* nothing usable */
2812 if(s_ednsdomains
.check(dn
) || s_ednssubnets
.match(rem
)) {
2813 trunc
.truncate(bits
);
2814 return boost::optional
<Netmask
>(Netmask(trunc
, bits
));
2820 void SyncRes::parseEDNSSubnetWhitelist(const std::string
& wlist
)
2822 vector
<string
> parts
;
2823 stringtok(parts
, wlist
, ",; ");
2824 for(const auto& a
: parts
) {
2826 s_ednssubnets
.addMask(Netmask(a
));
2829 s_ednsdomains
.add(DNSName(a
));
2834 // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
2835 int directResolve(const DNSName
& qname
, const QType
& qtype
, int qclass
, vector
<DNSRecord
>& ret
)
2838 gettimeofday(&now
, 0);
2841 int res
= sr
.beginResolve(qname
, QType(qtype
), qclass
, ret
);
2846 int SyncRes::getRootNS(struct timeval now
, asyncresolve_t asyncCallback
) {
2848 sr
.setDoEDNS0(true);
2849 sr
.setUpdatingRootNS();
2850 sr
.setDoDNSSEC(g_dnssecmode
!= DNSSECMode::Off
);
2851 sr
.setDNSSECValidationRequested(g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
);
2852 sr
.setAsyncCallback(asyncCallback
);
2854 vector
<DNSRecord
> ret
;
2857 res
=sr
.beginResolve(g_rootdnsname
, QType(QType::NS
), 1, ret
);
2858 if (g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
) {
2859 auto state
= sr
.getValidationState();
2861 throw PDNSException("Got Bogus validation result for .|NS");
2865 catch(const PDNSException
& e
) {
2866 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
2868 catch(const ImmediateServFailException
& e
) {
2869 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
2871 catch(const std::exception
& e
) {
2872 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.what()<<endl
;
2875 L
<<Logger::Error
<<"Failed to update . records, got an exception"<<endl
;
2879 L
<<Logger::Notice
<<"Refreshed . records"<<endl
;
2882 L
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;