2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "arguments.hh"
27 #include "cachecleaner.hh"
28 #include "dns_random.hh"
29 #include "dnsparser.hh"
30 #include "dnsrecords.hh"
31 #include "ednssubnet.hh"
33 #include "lua-recursor4.hh"
34 #include "rec-lua-conf.hh"
36 #include "dnsseckeeper.hh"
37 #include "validate-recursor.hh"
39 thread_local
SyncRes::ThreadLocalStorage
SyncRes::t_sstorage
;
41 std::unordered_set
<DNSName
> SyncRes::s_delegationOnly
;
42 std::unique_ptr
<NetmaskGroup
> SyncRes::s_dontQuery
{nullptr};
43 NetmaskGroup
SyncRes::s_ednslocalsubnets
;
44 NetmaskGroup
SyncRes::s_ednsremotesubnets
;
45 SuffixMatchNode
SyncRes::s_ednsdomains
;
46 EDNSSubnetOpts
SyncRes::s_ecsScopeZero
;
47 string
SyncRes::s_serverID
;
48 SyncRes::LogMode
SyncRes::s_lm
;
50 unsigned int SyncRes::s_maxnegttl
;
51 unsigned int SyncRes::s_maxcachettl
;
52 unsigned int SyncRes::s_maxqperq
;
53 unsigned int SyncRes::s_maxtotusec
;
54 unsigned int SyncRes::s_maxdepth
;
55 unsigned int SyncRes::s_minimumTTL
;
56 unsigned int SyncRes::s_packetcachettl
;
57 unsigned int SyncRes::s_packetcacheservfailttl
;
58 unsigned int SyncRes::s_serverdownmaxfails
;
59 unsigned int SyncRes::s_serverdownthrottletime
;
60 std::atomic
<uint64_t> SyncRes::s_authzonequeries
;
61 std::atomic
<uint64_t> SyncRes::s_queries
;
62 std::atomic
<uint64_t> SyncRes::s_outgoingtimeouts
;
63 std::atomic
<uint64_t> SyncRes::s_outgoing4timeouts
;
64 std::atomic
<uint64_t> SyncRes::s_outgoing6timeouts
;
65 std::atomic
<uint64_t> SyncRes::s_outqueries
;
66 std::atomic
<uint64_t> SyncRes::s_tcpoutqueries
;
67 std::atomic
<uint64_t> SyncRes::s_throttledqueries
;
68 std::atomic
<uint64_t> SyncRes::s_dontqueries
;
69 std::atomic
<uint64_t> SyncRes::s_nodelegated
;
70 std::atomic
<uint64_t> SyncRes::s_unreachables
;
71 std::atomic
<uint64_t> SyncRes::s_ecsqueries
;
72 std::atomic
<uint64_t> SyncRes::s_ecsresponses
;
73 uint8_t SyncRes::s_ecsipv4limit
;
74 uint8_t SyncRes::s_ecsipv6limit
;
75 bool SyncRes::s_doIPv6
;
76 bool SyncRes::s_nopacketcache
;
77 bool SyncRes::s_rootNXTrust
;
78 bool SyncRes::s_noEDNS
;
80 #define LOG(x) if(d_lm == Log) { L <<Logger::Warning << x; } else if(d_lm == Store) { d_trace << x; }
82 static void accountAuthLatency(int usec
, int family
)
84 if(family
== AF_INET
) {
86 g_stats
.auth4Answers0_1
++;
88 g_stats
.auth4Answers1_10
++;
89 else if(usec
< 100000)
90 g_stats
.auth4Answers10_100
++;
91 else if(usec
< 1000000)
92 g_stats
.auth4Answers100_1000
++;
94 g_stats
.auth4AnswersSlow
++;
97 g_stats
.auth6Answers0_1
++;
99 g_stats
.auth6Answers1_10
++;
100 else if(usec
< 100000)
101 g_stats
.auth6Answers10_100
++;
102 else if(usec
< 1000000)
103 g_stats
.auth6Answers100_1000
++;
105 g_stats
.auth6AnswersSlow
++;
111 SyncRes::SyncRes(const struct timeval
& now
) : d_authzonequeries(0), d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
112 d_totUsec(0), d_now(now
),
113 d_cacheonly(false), d_doDNSSEC(false), d_doEDNS0(false), d_lm(s_lm
)
118 /** everything begins here - this is the entry point just after receiving a packet */
119 int SyncRes::beginResolve(const DNSName
&qname
, const QType
&qtype
, uint16_t qclass
, vector
<DNSRecord
>&ret
)
121 vState state
= Indeterminate
;
124 d_wasOutOfBand
=false;
126 if (doSpecialNamesResolve(qname
, qtype
, qclass
, ret
)) {
127 d_queryValidationState
= Insecure
;
131 if( (qtype
.getCode() == QType::AXFR
) || (qtype
.getCode() == QType::IXFR
) || (qtype
.getCode() == QType::RRSIG
) || (qtype
.getCode() == QType::NSEC3
))
134 if(qclass
==QClass::ANY
)
136 else if(qclass
!=QClass::IN
)
139 set
<GetBestNSAnswer
> beenthere
;
140 int res
=doResolve(qname
, qtype
, ret
, 0, beenthere
, state
);
141 d_queryValidationState
= state
;
143 if (d_queryValidationState
!= Indeterminate
) {
144 g_stats
.dnssecValidations
++;
146 if (shouldValidate()) {
147 increaseDNSSECStateCounter(d_queryValidationState
);
153 /*! Handles all special, built-in names
154 * Fills ret with an answer and returns true if it handled the query.
156 * Handles the following queries (and their ANY variants):
159 * - localhost. IN AAAA
160 * - 1.0.0.127.in-addr.arpa. IN PTR
161 * - 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
162 * - version.bind. CH TXT
163 * - version.pdns. CH TXT
164 * - id.server. CH TXT
166 bool SyncRes::doSpecialNamesResolve(const DNSName
&qname
, const QType
&qtype
, const uint16_t qclass
, vector
<DNSRecord
> &ret
)
168 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."),
169 localhost("localhost."), versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns.");
171 bool handled
= false;
172 vector
<pair
<QType::typeenum
, string
> > answers
;
174 if ((qname
== arpa
|| qname
== ip6_arpa
) &&
175 qclass
== QClass::IN
) {
177 if (qtype
== QType::PTR
|| qtype
== QType::ANY
)
178 answers
.push_back({QType::PTR
, "localhost."});
181 if (qname
== localhost
&&
182 qclass
== QClass::IN
) {
184 if (qtype
== QType::A
|| qtype
== QType::ANY
)
185 answers
.push_back({QType::A
, "127.0.0.1"});
186 if (qtype
== QType::AAAA
|| qtype
== QType::ANY
)
187 answers
.push_back({QType::AAAA
, "::1"});
190 if ((qname
== versionbind
|| qname
== idserver
|| qname
== versionpdns
) &&
191 qclass
== QClass::CHAOS
) {
193 if (qtype
== QType::TXT
|| qtype
== QType::ANY
) {
194 if(qname
== versionbind
|| qname
== versionpdns
)
195 answers
.push_back({QType::TXT
, "\""+::arg()["version-string"]+"\""});
197 answers
.push_back({QType::TXT
, "\""+s_serverID
+"\""});
201 if (handled
&& !answers
.empty()) {
207 dr
.d_place
= DNSResourceRecord::ANSWER
;
210 for (const auto& ans
: answers
) {
211 dr
.d_type
= ans
.first
;
212 dr
.d_content
= DNSRecordContent::mastermake(ans
.first
, qclass
, ans
.second
);
221 //! This is the 'out of band resolver', in other words, the authoritative server
222 void SyncRes::AuthDomain::addSOA(std::vector
<DNSRecord
>& records
) const
224 SyncRes::AuthDomain::records_t::const_iterator ziter
= d_records
.find(boost::make_tuple(getName(), QType::SOA
));
225 if (ziter
!= d_records
.end()) {
226 DNSRecord dr
= *ziter
;
227 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
228 records
.push_back(dr
);
231 // cerr<<qname<<": can't find SOA record '"<<getName()<<"' in our zone!"<<endl;
235 int SyncRes::AuthDomain::getRecords(const DNSName
& qname
, uint16_t qtype
, std::vector
<DNSRecord
>& records
) const
237 int result
= RCode::NoError
;
241 std::pair
<records_t::const_iterator
,records_t::const_iterator
> range
= d_records
.equal_range(tie(qname
));
243 SyncRes::AuthDomain::records_t::const_iterator ziter
;
244 bool somedata
= false;
246 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
249 if(qtype
== QType::ANY
|| ziter
->d_type
== qtype
|| ziter
->d_type
== QType::CNAME
) {
250 // let rest of nameserver do the legwork on this one
251 records
.push_back(*ziter
);
253 else if (ziter
->d_type
== QType::NS
&& ziter
->d_name
.countLabels() > getName().countLabels()) {
254 // we hit a delegation point!
255 DNSRecord dr
= *ziter
;
256 dr
.d_place
=DNSResourceRecord::AUTHORITY
;
257 records
.push_back(dr
);
261 if (!records
.empty()) {
262 /* We have found an exact match, we're done */
263 // cerr<<qname<<": exact match in zone '"<<getName()<<"'"<<endl;
268 /* We have records for that name, but not of the wanted qtype */
269 // cerr<<qname<<": found record in '"<<getName()<<"', but nothing of the right type, sending SOA"<<endl;
275 // cerr<<qname<<": nothing found so far in '"<<getName()<<"', trying wildcards"<<endl;
276 DNSName
wcarddomain(qname
);
277 while(wcarddomain
!= getName() && wcarddomain
.chopOff()) {
278 // cerr<<qname<<": trying '*."<<wcarddomain<<"' in "<<getName()<<endl;
279 range
= d_records
.equal_range(boost::make_tuple(g_wildcarddnsname
+ wcarddomain
));
280 if (range
.first
==range
.second
)
283 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
284 DNSRecord dr
= *ziter
;
285 // if we hit a CNAME, just answer that - rest of recursor will do the needful & follow
286 if(dr
.d_type
== qtype
|| qtype
== QType::ANY
|| dr
.d_type
== QType::CNAME
) {
288 dr
.d_place
= DNSResourceRecord::ANSWER
;
289 records
.push_back(dr
);
293 if (records
.empty()) {
297 // cerr<<qname<<": in '"<<getName()<<"', had wildcard match on '*."<<wcarddomain<<"'"<<endl;
301 /* Nothing for this name, no wildcard, let's see if there is some NS */
302 DNSName
nsdomain(qname
);
303 while (nsdomain
.chopOff() && nsdomain
!= getName()) {
304 range
= d_records
.equal_range(boost::make_tuple(nsdomain
,QType::NS
));
305 if(range
.first
== range
.second
)
308 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
309 DNSRecord dr
= *ziter
;
310 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
311 records
.push_back(dr
);
315 if(records
.empty()) {
316 // cerr<<qname<<": no NS match in zone '"<<getName()<<"' either, handing out SOA"<<endl;
318 result
= RCode::NXDomain
;
324 bool SyncRes::doOOBResolve(const AuthDomain
& domain
, const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, int& res
)
329 res
= domain
.getRecords(qname
, qtype
.getCode(), ret
);
333 bool SyncRes::doOOBResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int& res
)
338 prefix
.append(depth
, ' ');
341 DNSName
authdomain(qname
);
342 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
343 if(iter
==t_sstorage
.domainmap
->end() || !iter
->second
.isAuth()) {
344 LOG(prefix
<<qname
<<": auth storage has no zone for this query!"<<endl
);
348 LOG(prefix
<<qname
<<": auth storage has data, zone='"<<authdomain
<<"'"<<endl
);
349 return doOOBResolve(iter
->second
, qname
, qtype
, ret
, res
);
352 void SyncRes::doEDNSDumpAndClose(int fd
)
354 FILE* fp
=fdopen(fd
, "w");
358 fprintf(fp
,"IP Address\tMode\tMode last updated at\n");
359 for(const auto& eds
: t_sstorage
.ednsstatus
) {
360 fprintf(fp
, "%s\t%d\t%s", eds
.first
.toString().c_str(), (int)eds
.second
.mode
, ctime(&eds
.second
.modeSetAt
));
366 uint64_t SyncRes::doDumpNSSpeeds(int fd
)
368 FILE* fp
=fdopen(dup(fd
), "w");
371 fprintf(fp
, "; nsspeed dump from thread follows\n;\n");
374 for(const auto& i
: t_sstorage
.nsSpeeds
)
378 // an <empty> can appear hear in case of authoritative (hosted) zones
379 fprintf(fp
, "%s -> ", i
.first
.toLogString().c_str());
380 for(const auto& j
: i
.second
.d_collection
)
382 // typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
383 fprintf(fp
, "%s/%f ", j
.first
.toString().c_str(), j
.second
.peek());
391 /* so here is the story. First we complete the full resolution process for a domain name. And only THEN do we decide
392 to also do DNSSEC validation, which leads to new queries. To make this simple, we *always* ask for DNSSEC records
393 so that if there are RRSIGs for a name, we'll have them.
395 However, some hosts simply can't answer questions which ask for DNSSEC. This can manifest itself as:
400 The cause of "No answer" may be fragmentation, and it is tempting to probe if smaller answers would get through.
401 Another cause of "No answer" may simply be a network condition.
402 Nonsense answers are a clearer indication this host won't be able to do DNSSEC evah.
404 Previous implementations have suffered from turning off DNSSEC questions for an authoritative server based on timeouts.
405 A clever idea is to only turn off DNSSEC if we know a domain isn't signed anyhow. The problem with that really
406 clever idea however is that at this point in PowerDNS, we may simply not know that yet. All the DNSSEC thinking happens
407 elsewhere. It may not have happened yet.
409 For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish.
412 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
) const
414 /* what is your QUEST?
415 the goal is to get as many remotes as possible on the highest level of EDNS support
418 0) UNKNOWN Unknown state
419 1) EDNS: Honors EDNS0
420 2) EDNSIGNORANT: Ignores EDNS0, gives replies without EDNS0
421 3) NOEDNS: Generates FORMERR/NOTIMP on EDNS queries
423 Everybody starts out assumed to be '0'.
424 If '0', send out EDNS0
425 If you FORMERR us, go to '3',
426 If no EDNS in response, go to '2'
427 If '1', send out EDNS0
428 If FORMERR, downgrade to 3
429 If '2', keep on including EDNS0, see what happens
431 If '3', send bare queries
434 SyncRes::EDNSStatus
* ednsstatus
;
435 ednsstatus
= &t_sstorage
.ednsstatus
[ip
]; // does this include port? YES
437 if(ednsstatus
->modeSetAt
&& ednsstatus
->modeSetAt
+ 3600 < d_now
.tv_sec
) {
438 *ednsstatus
=SyncRes::EDNSStatus();
439 // cerr<<"Resetting EDNS Status for "<<ip.toString()<<endl);
442 SyncRes::EDNSStatus::EDNSMode
& mode
=ednsstatus
->mode
;
443 SyncRes::EDNSStatus::EDNSMode oldmode
= mode
;
445 auto luaconfsLocal
= g_luaconfs
.getLocal();
448 ctx
.d_initialRequestId
= d_initialRequestId
;
452 for(int tries
= 0; tries
< 3; ++tries
) {
453 // cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl;
455 if(mode
==EDNSStatus::NOEDNS
) {
456 g_stats
.noEdnsOutQueries
++;
457 EDNSLevel
= 0; // level != mode
459 else if(ednsMANDATORY
|| mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
==EDNSStatus::EDNSIGNORANT
)
462 DNSName
sendQname(domain
);
463 if (g_lowercaseOutgoing
)
464 sendQname
.makeUsLowerCase();
466 if (d_asyncResolve
) {
467 ret
= d_asyncResolve(ip
, sendQname
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, luaconfsLocal
->outgoingProtobufServer
, res
);
470 ret
=asyncresolve(ip
, sendQname
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, luaconfsLocal
->outgoingProtobufServer
, res
);
473 return ret
; // transport error, nothing to learn here
476 if(ret
== 0) { // timeout, not doing anything with it now
479 else if(mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
== EDNSStatus::EDNSIGNORANT
) {
480 if(res
->d_rcode
== RCode::FormErr
|| res
->d_rcode
== RCode::NotImp
) {
481 // cerr<<"Downgrading to NOEDNS because of "<<RCode::to_s(res->d_rcode)<<" for query to "<<ip.toString()<<" for '"<<domain<<"'"<<endl;
482 mode
= EDNSStatus::NOEDNS
;
485 else if(!res
->d_haveEDNS
) {
486 if(mode
!= EDNSStatus::EDNSIGNORANT
) {
487 mode
= EDNSStatus::EDNSIGNORANT
;
488 // cerr<<"We find that "<<ip.toString()<<" is an EDNS-ignorer for '"<<domain<<"', moving to mode 3"<<endl;
492 mode
= EDNSStatus::EDNSOK
;
493 // cerr<<"We find that "<<ip.toString()<<" is EDNS OK!"<<endl;
497 if(oldmode
!= mode
|| !ednsstatus
->modeSetAt
)
498 ednsstatus
->modeSetAt
=d_now
.tv_sec
;
499 // cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", new mode: "<<mode<<endl;
505 /*! This function will check the cache and go out to the internet if the answer is not in cache
507 * \param qname The name we need an answer for
509 * \param ret The vector of DNSRecords we need to fill with the answers
510 * \param depth The recursion depth we are in
512 * \return DNS RCODE or -1 (Error) or -2 (RPZ hit)
514 int SyncRes::doResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, vState
& state
)
519 prefix
.append(depth
, ' ');
522 LOG(prefix
<<qname
<<": Wants "<< (d_doDNSSEC
? "" : "NO ") << "DNSSEC processing, "<<(d_requireAuthData
? "" : "NO ")<<"auth data in query for "<<qtype
.getName()<<endl
);
524 state
= Indeterminate
;
526 if(s_maxdepth
&& depth
> s_maxdepth
)
527 throw ImmediateServFailException("More than "+std::to_string(s_maxdepth
)+" (max-recursion-depth) levels of recursion needed while resolving "+qname
.toLogString());
531 // This is a difficult way of expressing "this is a normal query", i.e. not getRootNS.
532 if(!(d_updatingRootNS
&& qtype
.getCode()==QType::NS
&& qname
.isRoot())) {
533 if(d_cacheonly
) { // very limited OOB support
535 LOG(prefix
<<qname
<<": Recursion not requested for '"<<qname
<<"|"<<qtype
.getName()<<"', peeking at auth/forward zones"<<endl
);
536 DNSName
authname(qname
);
537 domainmap_t::const_iterator iter
=getBestAuthZone(&authname
);
538 if(iter
!= t_sstorage
.domainmap
->end()) {
539 if(iter
->second
.isAuth()) {
541 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, ret
, depth
, res
);
545 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
546 const ComboAddress remoteIP
= servers
.front();
547 LOG(prefix
<<qname
<<": forwarding query to hardcoded nameserver '"<< remoteIP
.toStringWithPort()<<"' for zone '"<<authname
<<"'"<<endl
);
549 boost::optional
<Netmask
> nm
;
550 res
=asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(), false, false, &d_now
, nm
, &lwr
);
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_cacheRemote
) > 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_cacheRemote
) > 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_cacheRemote
) > 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_cacheRemote
, 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_cacheRemote
, 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
, place
) < tie(rhs
.name
, rhs
.type
, rhs
.place
);
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_cacheRemote
, 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_cacheRemote
, 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
->toLogString()<<"(" << (boost::format("%0.2f") % (speeds
[*i
]/1000.0)).str() <<"ms)");
1287 return rnameservers
;
1290 inline vector
<ComboAddress
> SyncRes::shuffleForwardSpeed(const vector
<ComboAddress
> &rnameservers
, const string
&prefix
, const bool wasRd
)
1292 vector
<ComboAddress
> nameservers
= rnameservers
;
1293 map
<ComboAddress
, double> speeds
;
1295 for(const auto& val
: nameservers
) {
1297 DNSName nsName
= DNSName(val
.toStringWithPort());
1298 speed
=t_sstorage
.nsSpeeds
[nsName
].get(&d_now
);
1301 random_shuffle(nameservers
.begin(),nameservers
.end(), dns_random
);
1302 speedOrderCA
so(speeds
);
1303 stable_sort(nameservers
.begin(),nameservers
.end(), so
);
1306 LOG(prefix
<<"Nameservers: ");
1307 for(vector
<ComboAddress
>::const_iterator i
=nameservers
.cbegin();i
!=nameservers
.cend();++i
) {
1308 if(i
!=nameservers
.cbegin()) {
1310 if(!((i
-nameservers
.cbegin())%3)) {
1311 LOG(endl
<<prefix
<<" ");
1314 LOG((wasRd
? string("+") : string("-")) << i
->toStringWithPort() <<"(" << (boost::format("%0.2f") % (speeds
[*i
]/1000.0)).str() <<"ms)");
1321 static uint32_t getRRSIGTTL(const time_t now
, const std::shared_ptr
<RRSIGRecordContent
>& rrsig
)
1324 if (now
< rrsig
->d_sigexpire
) {
1325 res
= static_cast<uint32_t>(rrsig
->d_sigexpire
) - now
;
1330 static const set
<uint16_t> nsecTypes
= {QType::NSEC
, QType::NSEC3
};
1332 /* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
1334 * \param records The records to parse for the authority SOA and NSEC(3) records
1335 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
1337 static void harvestNXRecords(const vector
<DNSRecord
>& records
, NegCache::NegCacheEntry
& ne
, const time_t now
, uint32_t* lowestTTL
) {
1338 for(const auto& rec
: records
) {
1339 if(rec
.d_place
!= DNSResourceRecord::AUTHORITY
)
1340 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
1341 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
1342 // records MUST be in the same section as the records they cover.
1343 // Hence, we ignore all records outside of the AUTHORITY section.
1346 if(rec
.d_type
== QType::RRSIG
) {
1347 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1349 if(rrsig
->d_type
== QType::SOA
) {
1350 ne
.authoritySOA
.signatures
.push_back(rec
);
1351 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1352 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1353 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1356 if(nsecTypes
.count(rrsig
->d_type
)) {
1357 ne
.DNSSECRecords
.signatures
.push_back(rec
);
1358 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1359 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1360 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1366 if(rec
.d_type
== QType::SOA
) {
1367 ne
.authoritySOA
.records
.push_back(rec
);
1369 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1373 if(nsecTypes
.count(rec
.d_type
)) {
1374 ne
.DNSSECRecords
.records
.push_back(rec
);
1376 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1383 static cspmap_t
harvestCSPFromNE(const NegCache::NegCacheEntry
& ne
)
1386 for(const auto& rec
: ne
.DNSSECRecords
.signatures
) {
1387 if(rec
.d_type
== QType::RRSIG
) {
1388 auto rrc
= getRR
<RRSIGRecordContent
>(rec
);
1390 cspmap
[{rec
.d_name
,rrc
->d_type
}].signatures
.push_back(rrc
);
1394 for(const auto& rec
: ne
.DNSSECRecords
.records
) {
1395 cspmap
[{rec
.d_name
, rec
.d_type
}].records
.push_back(rec
.d_content
);
1400 // TODO remove after processRecords is fixed!
1401 // Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
1402 static void addNXNSECS(vector
<DNSRecord
>&ret
, const vector
<DNSRecord
>& records
)
1404 NegCache::NegCacheEntry ne
;
1405 harvestNXRecords(records
, ne
, 0, nullptr);
1406 ret
.insert(ret
.end(), ne
.authoritySOA
.signatures
.begin(), ne
.authoritySOA
.signatures
.end());
1407 ret
.insert(ret
.end(), ne
.DNSSECRecords
.records
.begin(), ne
.DNSSECRecords
.records
.end());
1408 ret
.insert(ret
.end(), ne
.DNSSECRecords
.signatures
.begin(), ne
.DNSSECRecords
.signatures
.end());
1411 bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine
& dfe
, const NsSet
& nameservers
)
1414 for (auto const &ns
: nameservers
) {
1415 d_appliedPolicy
= dfe
.getProcessingPolicy(ns
.first
, d_discardedPolicies
);
1416 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1417 LOG(", however nameserver "<<ns
.first
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1421 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1422 for (auto const &address
: ns
.second
.first
) {
1423 d_appliedPolicy
= dfe
.getProcessingPolicy(address
, d_discardedPolicies
);
1424 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1425 LOG(", however nameserver "<<ns
.first
<<" IP address "<<address
.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1434 bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine
& dfe
, const ComboAddress
& remoteIP
)
1437 d_appliedPolicy
= dfe
.getProcessingPolicy(remoteIP
, d_discardedPolicies
);
1438 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) {
1439 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")+"')");
1446 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
)
1448 vector
<ComboAddress
> result
;
1451 LOG(prefix
<<qname
<<": Trying to resolve NS '"<<*tns
<< "' ("<<1+tns
-rnameservers
.begin()<<"/"<<(unsigned int)rnameservers
.size()<<")"<<endl
);
1452 result
= getAddrs(*tns
, depth
+2, beenthere
, cacheOnly
);
1453 pierceDontQuery
=false;
1456 LOG(prefix
<<qname
<<": Domain has hardcoded nameserver");
1458 if(nameservers
[*tns
].first
.size() > 1) {
1463 sendRDQuery
= nameservers
[*tns
].second
;
1464 result
= shuffleForwardSpeed(nameservers
[*tns
].first
, doLog() ? (prefix
+qname
.toString()+": ") : string(), sendRDQuery
);
1465 pierceDontQuery
=true;
1470 bool SyncRes::throttledOrBlocked(const std::string
& prefix
, const ComboAddress
& remoteIP
, const DNSName
& qname
, const QType
& qtype
, bool pierceDontQuery
)
1472 if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0))) {
1473 LOG(prefix
<<qname
<<": server throttled "<<endl
);
1474 s_throttledqueries
++; d_throttledqueries
++;
1477 else if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()))) {
1478 LOG(prefix
<<qname
<<": query throttled "<<remoteIP
.toString()<<", "<<qname
<<"; "<<qtype
.getName()<<endl
);
1479 s_throttledqueries
++; d_throttledqueries
++;
1482 else if(!pierceDontQuery
&& s_dontQuery
&& s_dontQuery
->match(&remoteIP
)) {
1483 LOG(prefix
<<qname
<<": not sending query to " << remoteIP
.toString() << ", blocked by 'dont-query' setting" << endl
);
1490 bool SyncRes::validationEnabled() const
1492 return g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
;
1495 uint32_t SyncRes::computeLowestTTD(const std::vector
<DNSRecord
>& records
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, uint32_t signaturesTTL
) const
1497 uint32_t lowestTTD
= std::numeric_limits
<uint32_t>::max();
1498 for(const auto& record
: records
)
1499 lowestTTD
= min(lowestTTD
, record
.d_ttl
);
1501 /* even if it was not requested for that request (Process, and neither AD nor DO set),
1502 it might be requested at a later time so we need to be careful with the TTL. */
1503 if (validationEnabled() && !signatures
.empty()) {
1504 /* if we are validating, we don't want to cache records after their signatures expire. */
1505 /* records TTL are now TTD, let's add 'now' to the signatures lowest TTL */
1506 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(signaturesTTL
+ d_now
.tv_sec
));
1508 for(const auto& sig
: signatures
) {
1509 if (isRRSIGNotExpired(d_now
.tv_sec
, sig
)) {
1510 // we don't decerement d_sigexpire by 'now' because we actually want a TTD, not a TTL */
1511 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(sig
->d_sigexpire
));
1519 void SyncRes::updateValidationState(vState
& state
, const vState stateUpdate
)
1521 LOG(d_prefix
<<"validation state was "<<std::string(vStates
[state
])<<", state update is "<<std::string(vStates
[stateUpdate
]));
1523 if (stateUpdate
== TA
) {
1526 else if (stateUpdate
== NTA
) {
1529 else if (stateUpdate
== Bogus
) {
1532 else if (state
== Indeterminate
) {
1533 state
= stateUpdate
;
1535 else if (stateUpdate
== Insecure
) {
1536 if (state
!= Bogus
) {
1540 LOG(", validation state is now "<<std::string(vStates
[state
])<<endl
);
1543 vState
SyncRes::getTA(const DNSName
& zone
, dsmap_t
& ds
)
1545 auto luaLocal
= g_luaconfs
.getLocal();
1547 if (luaLocal
->dsAnchors
.empty()) {
1548 LOG(d_prefix
<<": No trust anchors configured, everything is Insecure"<<endl
);
1549 /* We have no TA, everything is insecure */
1554 if (haveNegativeTrustAnchor(luaLocal
->negAnchors
, zone
, reason
)) {
1555 LOG(d_prefix
<<": got NTA for '"<<zone
<<"'"<<endl
);
1559 if (getTrustAnchor(luaLocal
->dsAnchors
, zone
, ds
)) {
1560 LOG(d_prefix
<<": got TA for '"<<zone
<<"'"<<endl
);
1564 LOG(d_prefix
<<": no TA found for '"<<zone
<<"' among "<< luaLocal
->dsAnchors
.size()<<endl
);
1567 if (zone
.isRoot()) {
1568 /* No TA for the root */
1572 return Indeterminate
;
1575 static size_t countSupportedDS(const dsmap_t
& dsmap
)
1579 for (const auto& ds
: dsmap
) {
1580 if (isSupportedDS(ds
)) {
1588 vState
SyncRes::getDSRecords(const DNSName
& zone
, dsmap_t
& ds
, bool taOnly
, unsigned int depth
, bool bogusOnNXD
, bool* foundCut
)
1590 vState result
= getTA(zone
, ds
);
1592 if (result
!= Indeterminate
|| taOnly
) {
1594 *foundCut
= (result
!= Indeterminate
);
1598 if (countSupportedDS(ds
) == 0) {
1606 else if (result
== NTA
) {
1613 bool oldSkipCNAME
= d_skipCNAMECheck
;
1614 d_skipCNAMECheck
= true;
1616 std::set
<GetBestNSAnswer
> beenthere
;
1617 std::vector
<DNSRecord
> dsrecords
;
1619 vState state
= Indeterminate
;
1620 int rcode
= doResolve(zone
, QType(QType::DS
), dsrecords
, depth
+ 1, beenthere
, state
);
1621 d_skipCNAMECheck
= oldSkipCNAME
;
1623 if (rcode
== RCode::NoError
|| (rcode
== RCode::NXDomain
&& !bogusOnNXD
)) {
1625 uint8_t bestDigestType
= 0;
1627 if (state
== Secure
) {
1628 bool gotCNAME
= false;
1629 for (const auto& record
: dsrecords
) {
1630 if (record
.d_type
== QType::DS
) {
1631 const auto dscontent
= getRR
<DSRecordContent
>(record
);
1632 if (dscontent
&& isSupportedDS(*dscontent
)) {
1633 // Make GOST a lower prio than SHA256
1634 if (dscontent
->d_digesttype
== DNSSECKeeper::GOST
&& bestDigestType
== DNSSECKeeper::SHA256
) {
1637 if (dscontent
->d_digesttype
> bestDigestType
|| (bestDigestType
== DNSSECKeeper::GOST
&& dscontent
->d_digesttype
== DNSSECKeeper::SHA256
)) {
1638 bestDigestType
= dscontent
->d_digesttype
;
1640 ds
.insert(*dscontent
);
1643 else if (record
.d_type
== QType::CNAME
&& record
.d_name
== zone
) {
1648 /* RFC 4509 section 3: "Validator implementations SHOULD ignore DS RRs containing SHA-1
1649 * digests if DS RRs with SHA-256 digests are present in the DS RRset."
1650 * As SHA348 is specified as well, the spirit of the this line is "use the best algorithm".
1652 for (auto dsrec
= ds
.begin(); dsrec
!= ds
.end(); ) {
1653 if (dsrec
->d_digesttype
!= bestDigestType
) {
1654 dsrec
= ds
.erase(dsrec
);
1661 if (rcode
== RCode::NoError
&& ds
.empty()) {
1663 if (gotCNAME
|| denialProvesNoDelegation(zone
, dsrecords
)) {
1664 /* we are still inside the same Secure zone */
1674 } else if (foundCut
&& rcode
== RCode::NoError
&& !ds
.empty()) {
1682 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
1686 bool SyncRes::haveExactValidationStatus(const DNSName
& domain
)
1688 if (!shouldValidate()) {
1691 const auto& it
= d_cutStates
.find(domain
);
1692 if (it
!= d_cutStates
.cend()) {
1698 vState
SyncRes::getValidationStatus(const DNSName
& subdomain
, bool allowIndeterminate
)
1700 vState result
= Indeterminate
;
1702 if (!shouldValidate()) {
1705 DNSName
name(subdomain
);
1707 const auto& it
= d_cutStates
.find(name
);
1708 if (it
!= d_cutStates
.cend()) {
1709 if (allowIndeterminate
|| it
->second
!= Indeterminate
) {
1710 LOG(d_prefix
<<": got status "<<vStates
[it
->second
]<<" for name "<<subdomain
<<" (from "<<name
<<")"<<endl
);
1715 while (name
.chopOff());
1720 bool SyncRes::lookForCut(const DNSName
& qname
, unsigned int depth
, const vState existingState
, vState
& newState
)
1722 bool foundCut
= false;
1724 vState dsState
= getDSRecords(qname
, ds
, newState
== Bogus
|| existingState
== Insecure
|| existingState
== Bogus
, depth
, false, &foundCut
);
1726 if (dsState
!= Indeterminate
) {
1733 void SyncRes::computeZoneCuts(const DNSName
& begin
, const DNSName
& end
, unsigned int depth
)
1735 if(!begin
.isPartOf(end
)) {
1736 LOG(d_prefix
<<" "<<begin
.toLogString()<<" is not part of "<<end
.toLogString()<<endl
);
1737 throw PDNSException(begin
.toLogString() + " is not part of " + end
.toLogString());
1740 if (d_cutStates
.count(begin
) != 0) {
1745 vState cutState
= getDSRecords(end
, ds
, false, depth
);
1746 LOG(d_prefix
<<": setting cut state for "<<end
<<" to "<<vStates
[cutState
]<<endl
);
1747 d_cutStates
[end
] = cutState
;
1749 if (!shouldValidate()) {
1754 std::vector
<string
> labelsToAdd
= begin
.makeRelative(end
).getRawLabels();
1756 bool oldSkipCNAME
= d_skipCNAMECheck
;
1757 d_skipCNAMECheck
= true;
1759 while(qname
!= begin
) {
1760 if (labelsToAdd
.empty())
1763 qname
.prependRawLabel(labelsToAdd
.back());
1764 labelsToAdd
.pop_back();
1765 LOG(d_prefix
<<": - Looking for a cut at "<<qname
<<endl
);
1767 const auto cutIt
= d_cutStates
.find(qname
);
1768 if (cutIt
!= d_cutStates
.cend()) {
1769 if (cutIt
->second
!= Indeterminate
) {
1770 LOG(d_prefix
<<": - Cut already known at "<<qname
<<endl
);
1771 cutState
= cutIt
->second
;
1776 /* no need to look for NS and DS if we are already insecure or bogus,
1779 if (cutState
== Insecure
|| cutState
== Bogus
) {
1781 vState newState
= getDSRecords(qname
, cutDS
, true, depth
);
1782 if (newState
== Indeterminate
) {
1786 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[newState
]<<endl
);
1787 cutState
= newState
;
1789 d_cutStates
[qname
] = cutState
;
1794 vState newState
= Indeterminate
;
1795 /* temporarily mark as Indeterminate, so that we won't enter an endless loop
1796 trying to determine that zone cut again. */
1797 d_cutStates
[qname
] = newState
;
1798 bool foundCut
= lookForCut(qname
, depth
+ 1, cutState
, newState
);
1800 LOG(d_prefix
<<": - Found cut at "<<qname
<<endl
);
1801 if (newState
!= Indeterminate
) {
1802 cutState
= newState
;
1804 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[cutState
]<<endl
);
1805 d_cutStates
[qname
] = cutState
;
1808 /* remove the temporary cut */
1809 LOG(d_prefix
<<qname
<<": removing cut state for "<<qname
<<endl
);
1810 d_cutStates
.erase(qname
);
1814 d_skipCNAMECheck
= oldSkipCNAME
;
1816 LOG(d_prefix
<<": list of cuts from "<<begin
<<" to "<<end
<<endl
);
1817 for (const auto& cut
: d_cutStates
) {
1818 if (cut
.first
.isRoot() || (begin
.isPartOf(cut
.first
) && cut
.first
.isPartOf(end
))) {
1819 LOG(" - "<<cut
.first
<<": "<<vStates
[cut
.second
]<<endl
);
1824 vState
SyncRes::validateDNSKeys(const DNSName
& zone
, const std::vector
<DNSRecord
>& dnskeys
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, unsigned int depth
)
1827 if (!signatures
.empty()) {
1828 DNSName signer
= getSigner(signatures
);
1830 if (!signer
.empty() && zone
.isPartOf(signer
)) {
1831 vState state
= getDSRecords(signer
, ds
, false, depth
);
1833 if (state
!= Secure
) {
1839 skeyset_t tentativeKeys
;
1840 std::vector
<shared_ptr
<DNSRecordContent
> > toSign
;
1842 for (const auto& dnskey
: dnskeys
) {
1843 if (dnskey
.d_type
== QType::DNSKEY
) {
1844 auto content
= getRR
<DNSKEYRecordContent
>(dnskey
);
1846 tentativeKeys
.insert(content
);
1847 toSign
.push_back(content
);
1852 LOG(d_prefix
<<": trying to validate "<<std::to_string(tentativeKeys
.size())<<" DNSKEYs with "<<std::to_string(ds
.size())<<" DS"<<endl
);
1853 skeyset_t validatedKeys
;
1854 validateDNSKeysAgainstDS(d_now
.tv_sec
, zone
, ds
, tentativeKeys
, toSign
, signatures
, validatedKeys
);
1856 LOG(d_prefix
<<": we now have "<<std::to_string(validatedKeys
.size())<<" DNSKEYs"<<endl
);
1858 /* if we found at least one valid RRSIG covering the set,
1859 all tentative keys are validated keys. Otherwise it means
1860 we haven't found at least one DNSKEY and a matching RRSIG
1861 covering this set, this looks Bogus. */
1862 if (validatedKeys
.size() != tentativeKeys
.size()) {
1863 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
1870 vState
SyncRes::getDNSKeys(const DNSName
& signer
, skeyset_t
& keys
, unsigned int depth
)
1872 std::vector
<DNSRecord
> records
;
1873 std::set
<GetBestNSAnswer
> beenthere
;
1874 LOG(d_prefix
<<"Retrieving DNSKeys for "<<signer
<<endl
);
1876 vState state
= Indeterminate
;
1877 /* following CNAME might lead to us to the wrong DNSKEY */
1878 bool oldSkipCNAME
= d_skipCNAMECheck
;
1879 d_skipCNAMECheck
= true;
1880 int rcode
= doResolve(signer
, QType(QType::DNSKEY
), records
, depth
+ 1, beenthere
, state
);
1881 d_skipCNAMECheck
= oldSkipCNAME
;
1883 if (rcode
== RCode::NoError
) {
1884 if (state
== Secure
) {
1885 for (const auto& key
: records
) {
1886 if (key
.d_type
== QType::DNSKEY
) {
1887 auto content
= getRR
<DNSKEYRecordContent
>(key
);
1889 keys
.insert(content
);
1894 LOG(d_prefix
<<"Retrieved "<<keys
.size()<<" DNSKeys for "<<signer
<<", state is "<<vStates
[state
]<<endl
);
1898 LOG(d_prefix
<<"Returning Bogus state from "<<__func__
<<"("<<signer
<<")"<<endl
);
1902 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
)
1905 if (!signatures
.empty()) {
1906 const DNSName signer
= getSigner(signatures
);
1907 if (!signer
.empty() && name
.isPartOf(signer
)) {
1908 if ((qtype
== QType::DNSKEY
|| qtype
== QType::DS
) && signer
== qname
) {
1909 /* we are already retrieving those keys, sorry */
1910 return Indeterminate
;
1912 vState state
= getDNSKeys(signer
, keys
, depth
);
1913 if (state
!= Secure
) {
1918 LOG(d_prefix
<<"Bogus!"<<endl
);
1922 std::vector
<std::shared_ptr
<DNSRecordContent
> > recordcontents
;
1923 for (const auto& record
: records
) {
1924 recordcontents
.push_back(record
.d_content
);
1927 LOG(d_prefix
<<"Going to validate "<<recordcontents
.size()<< " record contents with "<<signatures
.size()<<" sigs and "<<keys
.size()<<" keys for "<<name
<<endl
);
1928 if (validateWithKeySet(d_now
.tv_sec
, name
, recordcontents
, signatures
, keys
, false)) {
1929 LOG(d_prefix
<<"Secure!"<<endl
);
1933 LOG(d_prefix
<<"Bogus!"<<endl
);
1937 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
)
1944 prefix
.append(depth
, ' ');
1947 std::vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1948 const unsigned int labelCount
= qname
.countLabels();
1949 bool isCNAMEAnswer
= false;
1950 for(const auto& rec
: lwr
.d_records
) {
1951 if (rec
.d_class
!= QClass::IN
) {
1955 if(!isCNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
) {
1956 isCNAMEAnswer
= true;
1959 /* if we have a positive answer synthetized from a wildcard,
1960 we need to store the corresponding NSEC/NSEC3 records proving
1961 that the exact name did not exist in the negative cache */
1962 if(needWildcardProof
) {
1963 if (nsecTypes
.count(rec
.d_type
)) {
1964 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
1966 else if (rec
.d_type
== QType::RRSIG
) {
1967 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1968 if (rrsig
&& nsecTypes
.count(rrsig
->d_type
)) {
1969 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
1973 if(rec
.d_type
== QType::RRSIG
) {
1974 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1976 /* As illustrated in rfc4035's Appendix B.6, the RRSIG label
1977 count can be lower than the name's label count if it was
1978 synthetized from the wildcard. Note that the difference might
1980 if (rec
.d_name
== qname
&& rrsig
->d_labels
< labelCount
) {
1981 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthetized from a wildcard, we need a wildcard proof"<<endl
);
1982 needWildcardProof
= true;
1983 wildcardLabelsCount
= rrsig
->d_labels
;
1986 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
1987 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
1988 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
);
1993 // reap all answers from this packet that are acceptable
1994 for(auto& rec
: lwr
.d_records
) {
1995 if(rec
.d_type
== QType::OPT
) {
1996 LOG(prefix
<<qname
<<": OPT answer '"<<rec
.d_name
<<"' from '"<<auth
<<"' nameservers" <<endl
);
1999 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
<<" ");
2000 if(rec
.d_type
== QType::ANY
) {
2001 LOG("NO! - we don't accept 'ANY'-typed data"<<endl
);
2005 if(rec
.d_class
!= QClass::IN
) {
2006 LOG("NO! - we don't accept records for any other class than 'IN'"<<endl
);
2010 if(rec
.d_name
.isPartOf(auth
)) {
2011 if(rec
.d_type
== QType::RRSIG
) {
2012 LOG("RRSIG - separate"<<endl
);
2014 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
)) {
2015 LOG("NO! Is from delegation-only zone"<<endl
);
2017 return RCode::NXDomain
;
2020 bool haveLogged
= false;
2021 if (!t_sstorage
.domainmap
->empty()) {
2022 // Check if we are authoritative for a zone in this answer
2023 DNSName
tmp_qname(rec
.d_name
);
2024 auto auth_domain_iter
=getBestAuthZone(&tmp_qname
);
2025 if(auth_domain_iter
!=t_sstorage
.domainmap
->end() &&
2026 auth
.countLabels() <= auth_domain_iter
->first
.countLabels()) {
2027 if (auth_domain_iter
->first
!= auth
) {
2028 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter
->first
<<endl
);
2031 LOG("YES! - This answer was ");
2032 if (!wasForwarded
) {
2033 LOG("retrieved from the local auth store.");
2035 LOG("received from a server we forward to.");
2046 rec
.d_ttl
=min(s_maxcachettl
, rec
.d_ttl
);
2049 dr
.d_ttl
+= d_now
.tv_sec
;
2050 dr
.d_place
=DNSResourceRecord::ANSWER
;
2051 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(dr
);
2059 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2060 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)
2061 uint32_t lowestTTD
=computeLowestTTD(i
->second
.records
, i
->second
.signatures
, i
->second
.signaturesTTL
);
2063 for(auto& record
: i
->second
.records
)
2064 record
.d_ttl
= lowestTTD
; // boom
2067 // cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
2068 // cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
2071 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2073 if(i
->second
.records
.empty()) // this happens when we did store signatures, but passed on the records themselves
2076 /* Even if the AA bit is set, additional data cannot be considered
2077 as authoritative. This is especially important during validation
2078 because keeping records in the additional section is allowed even
2079 if the corresponding RRSIGs are not included, without setting the TC
2080 bit, as stated in rfc4035's section 3.1.1. Including RRSIG RRs in a Response:
2081 "When placing a signed RRset in the Additional section, the name
2082 server MUST also place its RRSIG RRs in the Additional section.
2083 If space does not permit inclusion of both the RRset and its
2084 associated RRSIG RRs, the name server MAY retain the RRset while
2085 dropping the RRSIG RRs. If this happens, the name server MUST NOT
2086 set the TC bit solely because these RRSIG RRs didn't fit."
2088 bool isAA
= lwr
.d_aabit
&& i
->first
.place
!= DNSResourceRecord::ADDITIONAL
;
2089 if (isAA
&& isCNAMEAnswer
&& (i
->first
.place
!= DNSResourceRecord::ANSWER
|| i
->first
.type
!= QType::CNAME
|| i
->first
.name
!= qname
)) {
2092 Note that the answer section of an authoritative answer normally
2093 contains only authoritative data. However when the name sought is an
2094 alias (see section 10.1.1) only the record describing that alias is
2095 necessarily authoritative. Clients should assume that other records
2096 may have come from the server's cache. Where authoritative answers
2097 are required, the client should query again, using the canonical name
2098 associated with the alias.
2103 vState recordState
= getValidationStatus(i
->first
.name
, false);
2104 LOG(d_prefix
<<": got initial zone status "<<vStates
[recordState
]<<" for record "<<i
->first
.name
<<endl
);
2106 if (shouldValidate() && recordState
== Secure
) {
2107 vState initialState
= recordState
;
2110 if (i
->first
.place
!= DNSResourceRecord::ADDITIONAL
) {
2111 /* the additional entries can be insecure,
2113 "Glue address RRsets associated with delegations MUST NOT be signed"
2115 if (i
->first
.type
== QType::DNSKEY
&& i
->first
.place
== DNSResourceRecord::ANSWER
) {
2116 LOG(d_prefix
<<"Validating DNSKEY for "<<i
->first
.name
<<endl
);
2117 recordState
= validateDNSKeys(i
->first
.name
, i
->second
.records
, i
->second
.signatures
, depth
);
2120 LOG(d_prefix
<<"Validating non-additional record for "<<i
->first
.name
<<endl
);
2121 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2122 /* 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 */
2123 if (qtype
== QType::NS
&& i
->second
.signatures
.empty() && recordState
== Bogus
&& haveExactValidationStatus(i
->first
.name
) && getValidationStatus(i
->first
.name
) == Indeterminate
) {
2124 recordState
= Indeterminate
;
2130 recordState
= Indeterminate
;
2132 /* in a non authoritative answer, we only care about the DS record (or lack of) */
2133 if ((i
->first
.type
== QType::DS
|| i
->first
.type
== QType::NSEC
|| i
->first
.type
== QType::NSEC3
) && i
->first
.place
== DNSResourceRecord::AUTHORITY
) {
2134 LOG(d_prefix
<<"Validating DS record for "<<i
->first
.name
<<endl
);
2135 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2139 if (initialState
== Secure
&& state
!= recordState
&& isAA
) {
2140 updateValidationState(state
, recordState
);
2144 if (shouldValidate()) {
2145 LOG(d_prefix
<<"Skipping validation because the current state is "<<vStates
[recordState
]<<endl
);
2149 /* We don't need to store NSEC3 records in the positive cache because:
2150 - we don't allow direct NSEC3 queries
2151 - denial of existence proofs in wildcard expanded positive responses are stored in authorityRecs
2152 - denial of existence proofs for negative responses are stored in the negative cache
2154 if (i
->first
.type
!= QType::NSEC3
) {
2155 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
);
2158 if(i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
)
2162 return RCode::NoError
;
2165 void SyncRes::updateDenialValidationState(NegCache::NegCacheEntry
& ne
, vState
& state
, const dState denialState
, const dState expectedState
, bool allowOptOut
)
2167 if (denialState
== expectedState
) {
2168 ne
.d_validationState
= Secure
;
2171 if (denialState
== OPTOUT
&& allowOptOut
) {
2172 LOG(d_prefix
<<"OPT-out denial found for "<<ne
.d_name
<<endl
);
2173 ne
.d_validationState
= Secure
;
2176 else if (denialState
== INSECURE
) {
2177 LOG(d_prefix
<<"Insecure denial found for "<<ne
.d_name
<<", returning Insecure"<<endl
);
2178 ne
.d_validationState
= Insecure
;
2181 LOG(d_prefix
<<"Invalid denial found for "<<ne
.d_name
<<", returning Bogus, res="<<denialState
<<", expectedState="<<expectedState
<<endl
);
2182 ne
.d_validationState
= Bogus
;
2184 updateValidationState(state
, ne
.d_validationState
);
2188 dState
SyncRes::getDenialValidationState(NegCache::NegCacheEntry
& ne
, const vState state
, const dState expectedState
, bool referralToUnsigned
)
2190 cspmap_t csp
= harvestCSPFromNE(ne
);
2191 return getDenial(csp
, ne
.d_name
, ne
.d_qtype
.getCode(), referralToUnsigned
, expectedState
== NXQTYPE
);
2194 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
)
2198 for(auto& rec
: lwr
.d_records
) {
2199 if (rec
.d_type
!=QType::OPT
&& rec
.d_class
!=QClass::IN
)
2202 if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2203 lwr
.d_rcode
==RCode::NXDomain
&& qname
.isPartOf(rec
.d_name
) && rec
.d_name
.isPartOf(auth
)) {
2204 LOG(prefix
<<qname
<<": got negative caching indication for name '"<<qname
<<"' (accept="<<rec
.d_name
.isPartOf(auth
)<<"), newtarget='"<<newtarget
<<"'"<<endl
);
2206 rec
.d_ttl
= min(rec
.d_ttl
, s_maxnegttl
);
2207 if(newtarget
.empty()) // only add a SOA if we're not going anywhere after this
2210 NegCache::NegCacheEntry ne
;
2212 uint32_t lowestTTL
= rec
.d_ttl
;
2213 /* if we get an NXDomain answer with a CNAME, the name
2214 does exist but the target does not */
2215 ne
.d_name
= newtarget
.empty() ? qname
: newtarget
;
2216 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2217 ne
.d_auth
= rec
.d_name
;
2218 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2219 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2221 if (state
== Secure
) {
2222 dState denialState
= getDenialValidationState(ne
, state
, NXDOMAIN
, false);
2223 updateDenialValidationState(ne
, state
, denialState
, NXDOMAIN
, false);
2226 ne
.d_validationState
= state
;
2229 /* if we get an NXDomain answer with a CNAME, let's not cache the
2230 target, even the server was authoritative for it,
2231 and do an additional query for the CNAME target.
2232 We have a regression test making sure we do exactly that.
2234 if(!wasVariable() && newtarget
.empty()) {
2235 t_sstorage
.negcache
.add(ne
);
2236 if(s_rootNXTrust
&& ne
.d_auth
.isRoot() && auth
.isRoot()) {
2237 ne
.d_name
= ne
.d_name
.getLastLabel();
2238 t_sstorage
.negcache
.add(ne
);
2244 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_type
==QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
) {
2246 if (auto content
= getRR
<CNAMERecordContent
>(rec
)) {
2247 newtarget
=content
->getTarget();
2250 /* if we have a positive answer synthetized from a wildcard, we need to
2251 return the corresponding NSEC/NSEC3 records from the AUTHORITY section
2252 proving that the exact name did not exist */
2253 else if(needWildcardProof
&& (rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::AUTHORITY
) {
2254 ret
.push_back(rec
); // enjoy your DNSSEC
2256 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
2257 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&&
2259 rec
.d_type
==qtype
.getCode() || ((lwr
.d_aabit
|| sendRDQuery
) && qtype
== QType(QType::ANY
))
2263 LOG(prefix
<<qname
<<": answer is in: resolved to '"<< rec
.d_content
->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"'"<<endl
);
2268 if (state
== Secure
&& needWildcardProof
) {
2269 /* We have a positive answer synthetized from a wildcard, we need to check that we have
2270 proof that the exact name doesn't exist so the wildcard can be used,
2271 as described in section 5.3.4 of RFC 4035 and 5.3 of FRC 7129.
2273 NegCache::NegCacheEntry ne
;
2275 uint32_t lowestTTL
= rec
.d_ttl
;
2277 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2278 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2280 cspmap_t csp
= harvestCSPFromNE(ne
);
2281 dState res
= getDenial(csp
, qname
, ne
.d_qtype
.getCode(), false, false, false, wildcardLabelsCount
);
2282 if (res
!= NXDOMAIN
) {
2284 if (res
== INSECURE
) {
2285 /* Some part could not be validated, for example a NSEC3 record with a too large number of iterations,
2286 this is not enough to warrant a Bogus, but go Insecure. */
2288 LOG(d_prefix
<<"Unable to validate denial in wildcard expanded positive response found for "<<qname
<<", returning Insecure, res="<<res
<<endl
);
2291 LOG(d_prefix
<<"Invalid denial in wildcard expanded positive response found for "<<qname
<<", returning Bogus, res="<<res
<<endl
);
2294 updateValidationState(state
, st
);
2295 /* we already stored the record with a different validation status, let's fix it */
2296 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qtype
, d_cacheRemote
, lwr
.d_aabit
, st
);
2300 else if((rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::ANSWER
) {
2301 if(rec
.d_type
!= QType::RRSIG
|| rec
.d_name
== qname
)
2302 ret
.push_back(rec
); // enjoy your DNSSEC
2304 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::NS
&& qname
.isPartOf(rec
.d_name
)) {
2305 if(moreSpecificThan(rec
.d_name
,auth
)) {
2307 LOG(prefix
<<qname
<<": got NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2311 LOG(prefix
<<qname
<<": got upwards/level NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"', had '"<<auth
<<"'"<<endl
);
2313 if (auto content
= getRR
<NSRecordContent
>(rec
)) {
2314 nsset
.insert(content
->getNS());
2317 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::DS
&& qname
.isPartOf(rec
.d_name
)) {
2318 LOG(prefix
<<qname
<<": got DS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2320 else if(realreferral
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& (rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && newauth
.isPartOf(auth
)) {
2321 /* we might have received a denial of the DS, let's check */
2322 if (state
== Secure
) {
2323 NegCache::NegCacheEntry ne
;
2325 ne
.d_name
= newauth
;
2326 ne
.d_qtype
= QType::DS
;
2327 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2328 uint32_t lowestTTL
= rec
.d_ttl
;
2329 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2331 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, true);
2333 if (denialState
== NXQTYPE
|| denialState
== OPTOUT
|| denialState
== INSECURE
) {
2334 ne
.d_ttd
= lowestTTL
+ d_now
.tv_sec
;
2335 ne
.d_validationState
= Secure
;
2336 LOG(prefix
<<qname
<<": got negative indication of DS record for '"<<newauth
<<"'"<<endl
);
2338 if(!wasVariable()) {
2339 t_sstorage
.negcache
.add(ne
);
2342 if (qname
== newauth
&& qtype
== QType::DS
) {
2343 /* we are actually done! */
2350 else if(!done
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2351 lwr
.d_rcode
==RCode::NoError
&& qname
.isPartOf(rec
.d_name
)) {
2352 LOG(prefix
<<qname
<<": got negative caching indication for '"<< qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
2354 if(!newtarget
.empty()) {
2355 LOG(prefix
<<qname
<<": Hang on! Got a redirect to '"<<newtarget
<<"' already"<<endl
);
2358 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2361 NegCache::NegCacheEntry ne
;
2362 ne
.d_auth
= rec
.d_name
;
2363 uint32_t lowestTTL
= rec
.d_ttl
;
2366 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2367 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2369 if (state
== Secure
) {
2370 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, false);
2371 updateDenialValidationState(ne
, state
, denialState
, NXQTYPE
, qtype
== QType::DS
);
2373 ne
.d_validationState
= state
;
2376 if(!wasVariable()) {
2377 if(qtype
.getCode()) { // prevents us from blacking out a whole domain
2378 t_sstorage
.negcache
.add(ne
);
2389 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
)
2391 int resolveret
= RCode::NoError
;
2395 if(d_outqueries
+ d_throttledqueries
> s_maxqperq
) {
2396 throw ImmediateServFailException("more than "+std::to_string(s_maxqperq
)+" (max-qperq) queries sent while resolving "+qname
.toLogString());
2399 if(s_maxtotusec
&& d_totUsec
> s_maxtotusec
) {
2400 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");
2404 LOG(prefix
<<qname
<<": using TCP with "<< remoteIP
.toStringWithPort() <<endl
);
2409 if(d_pdl
&& d_pdl
->preoutquery(remoteIP
, d_requestor
, qname
, qtype
, doTCP
, lwr
.d_records
, resolveret
)) {
2410 LOG(prefix
<<qname
<<": query handled by Lua"<<endl
);
2413 ednsmask
=getEDNSSubnetMask(qname
, remoteIP
);
2415 LOG(prefix
<<qname
<<": Adding EDNS Client Subnet Mask "<<ednsmask
->toString()<<" to query"<<endl
);
2418 resolveret
= asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(),
2419 doTCP
, sendRDQuery
, &d_now
, ednsmask
, &lwr
); // <- we go out on the wire!
2422 LOG(prefix
<<qname
<<": Received EDNS Client Subnet Mask "<<ednsmask
->toString()<<" on response"<<endl
);
2426 /* preoutquery killed the query by setting dq.rcode to -3 */
2427 if(resolveret
==-3) {
2428 throw ImmediateServFailException("Query killed by policy");
2431 d_totUsec
+= lwr
.d_usec
;
2432 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
2434 if(resolveret
!= 1) {
2435 /* Error while resolving */
2436 if(resolveret
== 0) {
2439 LOG(prefix
<<qname
<<": timeout resolving after "<<lwr
.d_usec
/1000.0<<"msec "<< (doTCP
? "over TCP" : "")<<endl
);
2441 s_outgoingtimeouts
++;
2443 if(remoteIP
.sin4
.sin_family
== AF_INET
)
2444 s_outgoing4timeouts
++;
2446 s_outgoing6timeouts
++;
2448 else if(resolveret
== -2) {
2449 /* OS resource limit reached */
2450 LOG(prefix
<<qname
<<": hit a local resource limit resolving"<< (doTCP
? " over TCP" : "")<<", probable error: "<<stringerror()<<endl
);
2451 g_stats
.resourceLimits
++;
2454 /* -1 means server unreachable */
2457 LOG(prefix
<<qname
<<": error resolving from "<<remoteIP
.toString()<< (doTCP
? " over TCP" : "") <<", possible error: "<<strerror(errno
)<< endl
);
2460 if(resolveret
!= -2) { // don't account for resource limits, they are our own fault
2461 t_sstorage
.nsSpeeds
[nsName
.empty()? DNSName(remoteIP
.toStringWithPort()) : nsName
].submit(remoteIP
, 1000000, &d_now
); // 1 sec
2463 // code below makes sure we don't filter COM or the root
2464 if (s_serverdownmaxfails
> 0 && (auth
!= g_rootdnsname
) && t_sstorage
.fails
.incr(remoteIP
) >= s_serverdownmaxfails
) {
2465 LOG(prefix
<<qname
<<": Max fails reached resolving on "<< remoteIP
.toString() <<". Going full throttle for "<< s_serverdownthrottletime
<<" seconds" <<endl
);
2466 // mark server as down
2467 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0), s_serverdownthrottletime
, 10000);
2469 else if (resolveret
== -1) {
2470 // unreachable, 1 minute or 100 queries
2471 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 100);
2475 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 10, 5);
2482 /* we got an answer */
2483 if(lwr
.d_rcode
==RCode::ServFail
|| lwr
.d_rcode
==RCode::Refused
) {
2484 LOG(prefix
<<qname
<<": "<<nsName
<<" ("<<remoteIP
.toString()<<") returned a "<< (lwr
.d_rcode
==RCode::ServFail
? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl
);
2485 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
2489 /* this server sent a valid answer, mark it backup up if it was down */
2490 if(s_serverdownmaxfails
> 0) {
2491 t_sstorage
.fails
.clear(remoteIP
);
2498 LOG(prefix
<<qname
<<": truncated bit set, over TCP?"<<endl
);
2499 /* let's treat that as a ServFail answer from this server */
2500 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
2510 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
)
2515 prefix
.append(depth
, ' ');
2519 for(auto& rec
: lwr
.d_records
) {
2520 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumTTL
);
2524 bool needWildcardProof
= false;
2525 unsigned int wildcardLabelsCount
;
2526 *rcode
= updateCacheFromRecords(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, state
, needWildcardProof
, wildcardLabelsCount
);
2527 if (*rcode
!= RCode::NoError
) {
2531 LOG(prefix
<<qname
<<": determining status after receiving this packet"<<endl
);
2534 bool realreferral
=false, negindic
=false;
2538 bool done
= processRecords(prefix
, qname
, qtype
, auth
, lwr
, sendRDQuery
, ret
, nsset
, newtarget
, newauth
, realreferral
, negindic
, state
, needWildcardProof
, wildcardLabelsCount
);
2541 LOG(prefix
<<qname
<<": status=got results, this level of recursion done"<<endl
);
2542 LOG(prefix
<<qname
<<": validation status is "<<vStates
[state
]<<endl
);
2543 *rcode
= RCode::NoError
;
2547 if(!newtarget
.empty()) {
2548 if(newtarget
== qname
) {
2549 LOG(prefix
<<qname
<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl
);
2550 *rcode
= RCode::ServFail
;
2555 LOG(prefix
<<qname
<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl
);
2556 *rcode
= RCode::ServFail
;
2560 if (qtype
== QType::DS
) {
2561 LOG(prefix
<<qname
<<": status=got a CNAME referral, but we are looking for a DS"<<endl
);
2564 addNXNSECS(ret
, lwr
.d_records
);
2566 *rcode
= RCode::NoError
;
2570 LOG(prefix
<<qname
<<": status=got a CNAME referral, starting over with "<<newtarget
<<endl
);
2572 set
<GetBestNSAnswer
> beenthere2
;
2573 vState cnameState
= Indeterminate
;
2574 *rcode
= doResolve(newtarget
, qtype
, ret
, depth
+ 1, beenthere2
, cnameState
);
2575 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
2576 updateValidationState(state
, cnameState
);
2581 if(lwr
.d_rcode
== RCode::NXDomain
) {
2582 LOG(prefix
<<qname
<<": status=NXDOMAIN, we are done "<<(negindic
? "(have negative SOA)" : "")<<endl
);
2585 addNXNSECS(ret
, lwr
.d_records
);
2587 *rcode
= RCode::NXDomain
;
2591 if(nsset
.empty() && !lwr
.d_rcode
&& (negindic
|| lwr
.d_aabit
|| sendRDQuery
)) {
2592 LOG(prefix
<<qname
<<": status=noerror, other types may exist, but we are done "<<(negindic
? "(have negative SOA) " : "")<<(lwr
.d_aabit
? "(have aa bit) " : "")<<endl
);
2594 if(state
== Secure
&& lwr
.d_aabit
&& !negindic
) {
2595 updateValidationState(state
, Bogus
);
2599 addNXNSECS(ret
, lwr
.d_records
);
2601 *rcode
= RCode::NoError
;
2606 LOG(prefix
<<qname
<<": status=did not resolve, got "<<(unsigned int)nsset
.size()<<" NS, ");
2608 nameservers
.clear();
2609 for (auto const &nameserver
: nsset
) {
2611 d_appliedPolicy
= dfe
.getProcessingPolicy(nameserver
, d_discardedPolicies
);
2612 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
2613 LOG("however "<<nameserver
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
2618 nameservers
.insert({nameserver
, {{}, false}});
2620 LOG("looping to them"<<endl
);
2621 *gotNewServers
= true;
2631 * -1 in case of no results
2632 * -2 when a FilterEngine Policy was hit
2635 int SyncRes::doResolveAt(NsSet
&nameservers
, DNSName auth
, bool flawedNSSet
, const DNSName
&qname
, const QType
&qtype
,
2636 vector
<DNSRecord
>&ret
,
2637 unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
, vState
& state
)
2639 auto luaconfsLocal
= g_luaconfs
.getLocal();
2643 prefix
.append(depth
, ' ');
2646 LOG(prefix
<<qname
<<": Cache consultations done, have "<<(unsigned int)nameservers
.size()<<" NS to contact");
2648 if (nameserversBlockedByRPZ(luaconfsLocal
->dfe
, nameservers
)) {
2654 for(;;) { // we may get more specific nameservers
2655 vector
<DNSName
> rnameservers
= shuffleInSpeedOrder(nameservers
, doLog() ? (prefix
+qname
.toString()+": ") : string() );
2657 for(auto tns
=rnameservers
.cbegin();;++tns
) {
2658 if(tns
==rnameservers
.cend()) {
2659 LOG(prefix
<<qname
<<": Failed to resolve via any of the "<<(unsigned int)rnameservers
.size()<<" offered NS at level '"<<auth
<<"'"<<endl
);
2660 if(!auth
.isRoot() && flawedNSSet
) {
2661 LOG(prefix
<<qname
<<": Ageing nameservers for level '"<<auth
<<"', next query might succeed"<<endl
);
2663 if(t_RC
->doAgeCache(d_now
.tv_sec
, auth
, QType::NS
, 10))
2664 g_stats
.nsSetInvalidations
++;
2669 bool cacheOnly
= false;
2670 // this line needs to identify the 'self-resolving' behaviour
2671 if(qname
== *tns
&& (qtype
.getCode() == QType::A
|| qtype
.getCode() == QType::AAAA
)) {
2672 /* we might have a glue entry in cache so let's try this NS
2673 but only if we have enough in the cache to know how to reach it */
2674 LOG(prefix
<<qname
<<": Using NS to resolve itself, but only using what we have in cache ("<<(1+tns
-rnameservers
.cbegin())<<"/"<<rnameservers
.size()<<")"<<endl
);
2678 typedef vector
<ComboAddress
> remoteIPs_t
;
2679 remoteIPs_t remoteIPs
;
2680 remoteIPs_t::const_iterator remoteIP
;
2681 bool pierceDontQuery
=false;
2682 bool sendRDQuery
=false;
2683 boost::optional
<Netmask
> ednsmask
;
2685 const bool wasForwarded
= tns
->empty() && (!nameservers
[*tns
].first
.empty());
2686 int rcode
= RCode::NoError
;
2687 bool gotNewServers
= false;
2689 if(tns
->empty() && !wasForwarded
) {
2690 LOG(prefix
<<qname
<<": Domain is out-of-band"<<endl
);
2691 /* setting state to indeterminate since validation is disabled for local auth zone,
2692 and Insecure would be misleading. */
2693 state
= Indeterminate
;
2694 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, lwr
.d_records
, depth
, lwr
.d_rcode
);
2698 /* we have received an answer, are we done ? */
2699 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, false, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
2703 if (gotNewServers
) {
2708 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
2709 remoteIPs
= retrieveAddressesForNS(prefix
, qname
, tns
, depth
, beenthere
, rnameservers
, nameservers
, sendRDQuery
, pierceDontQuery
, flawedNSSet
, cacheOnly
);
2711 if(remoteIPs
.empty()) {
2712 LOG(prefix
<<qname
<<": Failed to get IP for NS "<<*tns
<<", trying next if available"<<endl
);
2717 bool hitPolicy
{false};
2718 LOG(prefix
<<qname
<<": Resolved '"<<auth
<<"' NS "<<*tns
<<" to: ");
2719 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
2720 if(remoteIP
!= remoteIPs
.cbegin()) {
2723 LOG(remoteIP
->toString());
2724 if(nameserverIPBlockedByRPZ(luaconfsLocal
->dfe
, *remoteIP
)) {
2729 if (hitPolicy
) //implies d_wantsRPZ
2733 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
2734 LOG(prefix
<<qname
<<": Trying IP "<< remoteIP
->toStringWithPort() <<", asking '"<<qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
2736 if (throttledOrBlocked(prefix
, *remoteIP
, qname
, qtype
, pierceDontQuery
)) {
2740 bool truncated
= false;
2741 bool gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
2742 *tns
, *remoteIP
, false, &truncated
);
2743 if (gotAnswer
&& truncated
) {
2744 /* retry, over TCP this time */
2745 gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
2746 *tns
, *remoteIP
, true, &truncated
);
2753 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
);
2755 /* // for you IPv6 fanatics :-)
2756 if(remoteIP->sin4.sin_family==AF_INET6)
2759 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
2761 t_sstorage
.nsSpeeds
[tns
->empty()? DNSName(remoteIP
->toStringWithPort()) : *tns
].submit(*remoteIP
, lwr
.d_usec
, &d_now
);
2763 /* we have received an answer, are we done ? */
2764 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
2768 if (gotNewServers
) {
2772 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100);
2775 if (gotNewServers
) {
2779 if(remoteIP
== remoteIPs
.cend()) // we tried all IP addresses, none worked
2788 void SyncRes::setQuerySource(const ComboAddress
& requestor
, boost::optional
<const EDNSSubnetOpts
&> incomingECS
)
2790 d_requestor
= requestor
;
2792 if (incomingECS
&& incomingECS
->source
.getBits() > 0) {
2793 d_cacheRemote
= incomingECS
->source
.getMaskedNetwork();
2794 uint8_t bits
= std::min(incomingECS
->source
.getBits(), (incomingECS
->source
.isIpv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
2795 ComboAddress trunc
= incomingECS
->source
.getNetwork();
2796 trunc
.truncate(bits
);
2797 d_outgoingECSNetwork
= boost::optional
<Netmask
>(Netmask(trunc
, bits
));
2799 d_cacheRemote
= d_requestor
;
2800 if(!incomingECS
&& s_ednslocalsubnets
.match(d_requestor
)) {
2801 ComboAddress trunc
= d_requestor
;
2802 uint8_t bits
= d_requestor
.isIPv4() ? 32 : 128;
2803 bits
= std::min(bits
, (trunc
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
2804 trunc
.truncate(bits
);
2805 d_outgoingECSNetwork
= boost::optional
<Netmask
>(Netmask(trunc
, bits
));
2806 } else if (s_ecsScopeZero
.source
.getBits() > 0) {
2807 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0.
2808 But using an empty ECS in that case would mean inserting
2809 a non ECS-specific entry into the cache, preventing any further
2810 ECS-specific query to be sent.
2811 So instead we use the trick described in section 7.1.2:
2812 "The subsequent Recursive Resolver query to the Authoritative Nameserver
2813 will then either not include an ECS option or MAY optionally include
2814 its own address information, which is what the Authoritative
2815 Nameserver will almost certainly use to generate any Tailored
2816 Response in lieu of an option. This allows the answer to be handled
2817 by the same caching mechanism as other queries, with an explicit
2818 indicator of the applicable scope. Subsequent Stub Resolver queries
2819 for /0 can then be answered from this cached response.
2821 d_outgoingECSNetwork
= boost::optional
<Netmask
>(s_ecsScopeZero
.source
.getMaskedNetwork());
2822 d_cacheRemote
= s_ecsScopeZero
.source
.getNetwork();
2824 // ECS disabled because no scope-zero address could be derived.
2825 d_outgoingECSNetwork
= boost::none
;
2830 boost::optional
<Netmask
> SyncRes::getEDNSSubnetMask(const DNSName
& dn
, const ComboAddress
& rem
)
2832 if(d_outgoingECSNetwork
&& (s_ednsdomains
.check(dn
) || s_ednsremotesubnets
.match(rem
))) {
2833 return d_outgoingECSNetwork
;
2838 void SyncRes::parseEDNSSubnetWhitelist(const std::string
& wlist
)
2840 vector
<string
> parts
;
2841 stringtok(parts
, wlist
, ",; ");
2842 for(const auto& a
: parts
) {
2844 s_ednsremotesubnets
.addMask(Netmask(a
));
2847 s_ednsdomains
.add(DNSName(a
));
2852 void SyncRes::parseEDNSSubnetAddFor(const std::string
& subnetlist
)
2854 vector
<string
> parts
;
2855 stringtok(parts
, subnetlist
, ",; ");
2856 for(const auto& a
: parts
) {
2857 s_ednslocalsubnets
.addMask(a
);
2861 // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
2862 int directResolve(const DNSName
& qname
, const QType
& qtype
, int qclass
, vector
<DNSRecord
>& ret
)
2865 gettimeofday(&now
, 0);
2868 int res
= sr
.beginResolve(qname
, QType(qtype
), qclass
, ret
);
2873 int SyncRes::getRootNS(struct timeval now
, asyncresolve_t asyncCallback
) {
2875 sr
.setDoEDNS0(true);
2876 sr
.setUpdatingRootNS();
2877 sr
.setDoDNSSEC(g_dnssecmode
!= DNSSECMode::Off
);
2878 sr
.setDNSSECValidationRequested(g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
);
2879 sr
.setAsyncCallback(asyncCallback
);
2881 vector
<DNSRecord
> ret
;
2884 res
=sr
.beginResolve(g_rootdnsname
, QType(QType::NS
), 1, ret
);
2885 if (g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
) {
2886 auto state
= sr
.getValidationState();
2888 throw PDNSException("Got Bogus validation result for .|NS");
2892 catch(const PDNSException
& e
) {
2893 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
2895 catch(const ImmediateServFailException
& e
) {
2896 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
2898 catch(const std::exception
& e
) {
2899 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.what()<<endl
;
2902 L
<<Logger::Error
<<"Failed to update . records, got an exception"<<endl
;
2906 L
<<Logger::Notice
<<"Refreshed . records"<<endl
;
2909 L
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;