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.
25 #include <boost/algorithm/string.hpp>
27 #include "lua-recursor4.hh"
32 #include "dnsrecords.hh"
41 #include "validate.hh"
43 #include "arguments.hh"
45 #include "recursor_cache.hh"
46 #include "dnsparser.hh"
47 #include "dns_random.hh"
49 #include "ednssubnet.hh"
50 #include "cachecleaner.hh"
51 #include "rec-lua-conf.hh"
52 __thread
SyncRes::StaticStorage
* t_sstorage
;
54 unsigned int SyncRes::s_maxnegttl
;
55 unsigned int SyncRes::s_maxcachettl
;
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_queries
;
61 std::atomic
<uint64_t> SyncRes::s_outgoingtimeouts
;
62 std::atomic
<uint64_t> SyncRes::s_outgoing4timeouts
;
63 std::atomic
<uint64_t> SyncRes::s_outgoing6timeouts
;
64 std::atomic
<uint64_t> SyncRes::s_outqueries
;
65 std::atomic
<uint64_t> SyncRes::s_tcpoutqueries
;
66 std::atomic
<uint64_t> SyncRes::s_throttledqueries
;
67 std::atomic
<uint64_t> SyncRes::s_dontqueries
;
68 std::atomic
<uint64_t> SyncRes::s_nodelegated
;
69 std::atomic
<uint64_t> SyncRes::s_unreachables
;
70 uint8_t SyncRes::s_ecsipv4limit
;
71 uint8_t SyncRes::s_ecsipv6limit
;
72 unsigned int SyncRes::s_minimumTTL
;
73 bool SyncRes::s_doIPv6
;
74 bool SyncRes::s_nopacketcache
;
75 bool SyncRes::s_rootNXTrust
;
76 unsigned int SyncRes::s_maxqperq
;
77 unsigned int SyncRes::s_maxtotusec
;
78 unsigned int SyncRes::s_maxdepth
;
79 string
SyncRes::s_serverID
;
80 SyncRes::LogMode
SyncRes::s_lm
;
81 std::unordered_set
<DNSName
> SyncRes::s_delegationOnly
;
82 std::unique_ptr
<NetmaskGroup
> SyncRes::s_dontQuery
{nullptr};
83 NetmaskGroup
SyncRes::s_ednssubnets
;
84 SuffixMatchNode
SyncRes::s_ednsdomains
;
86 #define LOG(x) if(d_lm == Log) { L <<Logger::Warning << x; } else if(d_lm == Store) { d_trace << x; }
88 bool SyncRes::s_noEDNS
;
90 static void accountAuthLatency(int usec
, int family
)
92 if(family
== AF_INET
) {
94 g_stats
.auth4Answers0_1
++;
96 g_stats
.auth4Answers1_10
++;
97 else if(usec
< 100000)
98 g_stats
.auth4Answers10_100
++;
99 else if(usec
< 1000000)
100 g_stats
.auth4Answers100_1000
++;
102 g_stats
.auth4AnswersSlow
++;
105 g_stats
.auth6Answers0_1
++;
106 else if(usec
< 10000)
107 g_stats
.auth6Answers1_10
++;
108 else if(usec
< 100000)
109 g_stats
.auth6Answers10_100
++;
110 else if(usec
< 1000000)
111 g_stats
.auth6Answers100_1000
++;
113 g_stats
.auth6AnswersSlow
++;
119 SyncRes::SyncRes(const struct timeval
& now
) : d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
120 d_totUsec(0), d_now(now
),
121 d_cacheonly(false), d_nocache(false), d_doDNSSEC(false), d_doEDNS0(false), d_lm(s_lm
)
125 t_sstorage
= new StaticStorage();
129 /** everything begins here - this is the entry point just after receiving a packet */
130 int SyncRes::beginResolve(const DNSName
&qname
, const QType
&qtype
, uint16_t qclass
, vector
<DNSRecord
>&ret
)
134 d_wasOutOfBand
=false;
136 if (doSpecialNamesResolve(qname
, qtype
, qclass
, ret
))
139 if( (qtype
.getCode() == QType::AXFR
) || (qtype
.getCode() == QType::IXFR
))
142 if(qclass
==QClass::ANY
)
144 else if(qclass
!=QClass::IN
)
147 set
<GetBestNSAnswer
> beenthere
;
148 int res
=doResolve(qname
, qtype
, ret
, 0, beenthere
);
152 /*! Handles all special, built-in names
153 * Fills ret with an answer and returns true if it handled the query.
155 * Handles the following queries (and their ANY variants):
158 * - localhost. IN AAAA
159 * - 1.0.0.127.in-addr.arpa. IN PTR
160 * - 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. IN PTR
161 * - version.bind. CH TXT
162 * - version.pdns. CH TXT
163 * - id.server. CH TXT
165 bool SyncRes::doSpecialNamesResolve(const DNSName
&qname
, const QType
&qtype
, const uint16_t &qclass
, vector
<DNSRecord
> &ret
)
167 static const DNSName
arpa("1.0.0.127.in-addr.arpa."), ip6_arpa("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa."),
168 localhost("localhost."), versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns.");
170 bool handled
= false;
171 vector
<pair
<QType::typeenum
, string
> > answers
;
173 if ((qname
== arpa
|| qname
== ip6_arpa
) &&
174 qclass
== QClass::IN
) {
176 if (qtype
== QType::PTR
|| qtype
== QType::ANY
)
177 answers
.push_back({QType::PTR
, "localhost."});
180 if (qname
== localhost
&&
181 qclass
== QClass::IN
) {
183 if (qtype
== QType::A
|| qtype
== QType::ANY
)
184 answers
.push_back({QType::A
, "127.0.0.1"});
185 if (qtype
== QType::AAAA
|| qtype
== QType::ANY
)
186 answers
.push_back({QType::AAAA
, "::1"});
189 if ((qname
== versionbind
|| qname
== idserver
|| qname
== versionpdns
) &&
190 qclass
== QClass::CHAOS
) {
192 if (qtype
== QType::TXT
|| qtype
== QType::ANY
) {
193 if(qname
== versionbind
|| qname
== versionpdns
)
194 answers
.push_back({QType::TXT
, "\""+::arg()["version-string"]+"\""});
196 answers
.push_back({QType::TXT
, "\""+s_serverID
+"\""});
200 if (handled
&& !answers
.empty()) {
206 dr
.d_place
= DNSResourceRecord::ANSWER
;
209 for (const auto& ans
: answers
) {
210 dr
.d_type
= ans
.first
;
211 dr
.d_content
= shared_ptr
<DNSRecordContent
>(DNSRecordContent::mastermake(ans
.first
, qclass
, ans
.second
));
220 //! This is the 'out of band resolver', in other words, the authoritative server
221 bool SyncRes::doOOBResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int& res
)
226 prefix
.append(depth
, ' ');
229 LOG(prefix
<<qname
<<": checking auth storage for '"<<qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
230 DNSName
authdomain(qname
);
232 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
233 if(iter
==t_sstorage
->domainmap
->end()) {
234 LOG(prefix
<<qname
<<": auth storage has no zone for this query!"<<endl
);
237 LOG(prefix
<<qname
<<": auth storage has data, zone='"<<authdomain
<<"'"<<endl
);
238 pair
<AuthDomain::records_t::const_iterator
, AuthDomain::records_t::const_iterator
> range
;
240 range
=iter
->second
.d_records
.equal_range(tie(qname
)); // partial lookup
243 AuthDomain::records_t::const_iterator ziter
;
245 for(ziter
=range
.first
; ziter
!=range
.second
; ++ziter
) {
247 if(qtype
.getCode()==QType::ANY
|| ziter
->d_type
==qtype
.getCode() || ziter
->d_type
==QType::CNAME
) // let rest of nameserver do the legwork on this one
248 ret
.push_back(*ziter
);
249 else if(ziter
->d_type
== QType::NS
&& ziter
->d_name
.countLabels() > authdomain
.countLabels()) { // we hit a delegation point!
251 dr
.d_place
=DNSResourceRecord::AUTHORITY
;
256 LOG(prefix
<<qname
<<": exact match in zone '"<<authdomain
<<"'"<<endl
);
261 LOG(prefix
<<qname
<<": found record in '"<<authdomain
<<"', but nothing of the right type, sending SOA"<<endl
);
262 ziter
=iter
->second
.d_records
.find(boost::make_tuple(authdomain
, QType::SOA
));
263 if(ziter
!=iter
->second
.d_records
.end()) {
265 dr
.d_place
=DNSResourceRecord::AUTHORITY
;
269 LOG(prefix
<<qname
<<": can't find SOA record '"<<authdomain
<<"' in our zone!"<<endl
);
274 LOG(prefix
<<qname
<<": nothing found so far in '"<<authdomain
<<"', trying wildcards"<<endl
);
275 DNSName
wcarddomain(qname
);
276 while(wcarddomain
!= iter
->first
&& wcarddomain
.chopOff()) {
277 LOG(prefix
<<qname
<<": trying '*."<<wcarddomain
<<"' in "<<authdomain
<<endl
);
278 range
=iter
->second
.d_records
.equal_range(boost::make_tuple(g_wildcarddnsname
+wcarddomain
));
279 if(range
.first
==range
.second
)
282 for(ziter
=range
.first
; ziter
!=range
.second
; ++ziter
) {
284 // if we hit a CNAME, just answer that - rest of recursor will do the needful & follow
285 if(dr
.d_type
== qtype
.getCode() || qtype
.getCode() == QType::ANY
|| dr
.d_type
== QType::CNAME
) {
287 dr
.d_place
=DNSResourceRecord::ANSWER
;
291 LOG(prefix
<<qname
<<": in '"<<authdomain
<<"', had wildcard match on '*."<<wcarddomain
<<"'"<<endl
);
296 DNSName
nsdomain(qname
);
298 while(nsdomain
.chopOff() && nsdomain
!= iter
->first
) {
299 range
=iter
->second
.d_records
.equal_range(boost::make_tuple(nsdomain
,QType::NS
));
300 if(range
.first
==range
.second
)
303 for(ziter
=range
.first
; ziter
!=range
.second
; ++ziter
) {
305 dr
.d_place
=DNSResourceRecord::AUTHORITY
;
310 LOG(prefix
<<qname
<<": no NS match in zone '"<<authdomain
<<"' either, handing out SOA"<<endl
);
311 ziter
=iter
->second
.d_records
.find(boost::make_tuple(authdomain
, QType::SOA
));
312 if(ziter
!=iter
->second
.d_records
.end()) {
314 dr
.d_place
=DNSResourceRecord::AUTHORITY
;
318 LOG(prefix
<<qname
<<": can't find SOA record '"<<authdomain
<<"' in our zone!"<<endl
);
328 void SyncRes::doEDNSDumpAndClose(int fd
)
330 FILE* fp
=fdopen(fd
, "w");
334 fprintf(fp
,"IP Address\tMode\tMode last updated at\n");
335 for(const auto& eds
: t_sstorage
->ednsstatus
) {
336 fprintf(fp
, "%s\t%d\t%s", eds
.first
.toString().c_str(), (int)eds
.second
.mode
, ctime(&eds
.second
.modeSetAt
));
342 uint64_t SyncRes::doDumpNSSpeeds(int fd
)
344 FILE* fp
=fdopen(dup(fd
), "w");
347 fprintf(fp
, "; nsspeed dump from thread follows\n;\n");
350 for(const auto& i
: t_sstorage
->nsSpeeds
)
353 fprintf(fp
, "%s -> ", i
.first
.toString().c_str());
354 for(const auto& j
: i
.second
.d_collection
)
356 // typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
357 fprintf(fp
, "%s/%f ", j
.first
.toString().c_str(), j
.second
.peek());
365 /* so here is the story. First we complete the full resolution process for a domain name. And only THEN do we decide
366 to also do DNSSEC validation, which leads to new queries. To make this simple, we *always* ask for DNSSEC records
367 so that if there are RRSIGs for a name, we'll have them.
369 However, some hosts simply can't answer questions which ask for DNSSEC. This can manifest itself as:
374 The cause of "No answer" may be fragmentation, and it is tempting to probe if smaller answers would get through.
375 Another cause of "No answer" may simply be a network condition.
376 Nonsense answers are a clearer indication this host won't be able to do DNSSEC evah.
378 Previous implementations have suffered from turning off DNSSEC questions for an authoritative server based on timeouts.
379 A clever idea is to only turn off DNSSEC if we know a domain isn't signed anyhow. The problem with that really
380 clever idea however is that at this point in PowerDNS, we may simply not know that yet. All the DNSSEC thinking happens
381 elsewhere. It may not have happened yet.
383 For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish.
386 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
388 /* what is your QUEST?
389 the goal is to get as many remotes as possible on the highest level of EDNS support
392 0) UNKNOWN Unknown state
393 1) EDNS: Honors EDNS0
394 2) EDNSIGNORANT: Ignores EDNS0, gives replies without EDNS0
395 3) NOEDNS: Generates FORMERR/NOTIMP on EDNS queries
397 Everybody starts out assumed to be '0'.
398 If '0', send out EDNS0
399 If you FORMERR us, go to '3',
400 If no EDNS in response, go to '2'
401 If '1', send out EDNS0
402 If FORMERR, downgrade to 3
403 If '2', keep on including EDNS0, see what happens
405 If '3', send bare queries
408 SyncRes::EDNSStatus
* ednsstatus
;
409 ednsstatus
= &t_sstorage
->ednsstatus
[ip
]; // does this include port? YES
411 if(ednsstatus
->modeSetAt
&& ednsstatus
->modeSetAt
+ 3600 < d_now
.tv_sec
) {
412 *ednsstatus
=SyncRes::EDNSStatus();
413 // cerr<<"Resetting EDNS Status for "<<ip.toString()<<endl);
416 SyncRes::EDNSStatus::EDNSMode
& mode
=ednsstatus
->mode
;
417 SyncRes::EDNSStatus::EDNSMode oldmode
= mode
;
419 auto luaconfsLocal
= g_luaconfs
.getLocal();
422 ctx
.d_initialRequestId
= d_initialRequestId
;
426 for(int tries
= 0; tries
< 3; ++tries
) {
427 // cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl;
429 if(mode
==EDNSStatus::NOEDNS
) {
430 g_stats
.noEdnsOutQueries
++;
431 EDNSLevel
= 0; // level != mode
433 else if(ednsMANDATORY
|| mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
==EDNSStatus::EDNSIGNORANT
)
436 if (d_asyncResolve
) {
437 ret
= d_asyncResolve(ip
, domain
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, luaconfsLocal
->outgoingProtobufServer
, res
);
440 ret
=asyncresolve(ip
, domain
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, luaconfsLocal
->outgoingProtobufServer
, res
);
443 return ret
; // transport error, nothing to learn here
446 if(ret
== 0) { // timeout, not doing anything with it now
449 else if(mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
== EDNSStatus::EDNSIGNORANT
) {
450 if(res
->d_rcode
== RCode::FormErr
|| res
->d_rcode
== RCode::NotImp
) {
451 // cerr<<"Downgrading to NOEDNS because of "<<RCode::to_s(res->d_rcode)<<" for query to "<<ip.toString()<<" for '"<<domain<<"'"<<endl;
452 mode
= EDNSStatus::NOEDNS
;
455 else if(!res
->d_haveEDNS
) {
456 if(mode
!= EDNSStatus::EDNSIGNORANT
) {
457 mode
= EDNSStatus::EDNSIGNORANT
;
458 // cerr<<"We find that "<<ip.toString()<<" is an EDNS-ignorer for '"<<domain<<"', moving to mode 3"<<endl;
462 mode
= EDNSStatus::EDNSOK
;
463 // cerr<<"We find that "<<ip.toString()<<" is EDNS OK!"<<endl;
467 if(oldmode
!= mode
|| !ednsstatus
->modeSetAt
)
468 ednsstatus
->modeSetAt
=d_now
.tv_sec
;
469 // cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", new mode: "<<mode<<endl;
475 /*! This function will check the cache and go out to the internet if the answer is not in cache
477 * \param qname The name we need an answer for
479 * \param ret The vector of DNSRecords we need to fill with the answers
480 * \param depth The recursion depth we are in
482 * \return DNS RCODE or -1 (Error) or -2 (RPZ hit)
484 int SyncRes::doResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
)
489 prefix
.append(depth
, ' ');
492 LOG(prefix
<<qname
<<": Wants "<< (d_doDNSSEC
? "" : "NO ") << "DNSSEC processing in query for "<<qtype
.getName()<<endl
);
494 if(s_maxdepth
&& depth
> s_maxdepth
)
495 throw ImmediateServFailException("More than "+std::to_string(s_maxdepth
)+" (max-recursion-depth) levels of recursion needed while resolving "+qname
.toLogString());
499 // This is a difficult way of expressing "this is a normal query", i.e. not getRootNS.
500 if(!(d_nocache
&& qtype
.getCode()==QType::NS
&& qname
.isRoot())) {
501 if(d_cacheonly
) { // very limited OOB support
503 LOG(prefix
<<qname
<<": Recursion not requested for '"<<qname
<<"|"<<qtype
.getName()<<"', peeking at auth/forward zones"<<endl
);
504 DNSName
authname(qname
);
505 domainmap_t::const_iterator iter
=getBestAuthZone(&authname
);
506 if(iter
!= t_sstorage
->domainmap
->end()) {
507 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
508 if(servers
.empty()) {
510 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, ret
, depth
, res
);
514 const ComboAddress remoteIP
= servers
.front();
515 LOG(prefix
<<qname
<<": forwarding query to hardcoded nameserver '"<< remoteIP
.toStringWithPort()<<"' for zone '"<<authname
<<"'"<<endl
);
517 boost::optional
<Netmask
> nm
;
518 res
=asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(), false, false, &d_now
, nm
, &lwr
);
519 // filter out the good stuff from lwr.result()
521 for(const auto& rec
: lwr
.d_records
) {
522 if(rec
.d_place
== DNSResourceRecord::ANSWER
)
528 return RCode::ServFail
;
534 if(!d_skipCNAMECheck
&& doCNAMECacheCheck(qname
,qtype
,ret
,depth
,res
)) // will reroute us if needed
537 if(doCacheCheck(qname
,qtype
,ret
,depth
,res
)) // we done
544 LOG(prefix
<<qname
<<": No cache hit for '"<<qname
<<"|"<<qtype
.getName()<<"', trying to find an appropriate NS record"<<endl
);
546 DNSName
subdomain(qname
);
547 if(qtype
== QType::DS
) subdomain
.chopOff();
550 bool flawedNSSet
=false;
552 // the two retries allow getBestNSNamesFromCache&co to reprime the root
553 // hints, in case they ever go missing
554 for(int tries
=0;tries
<2 && nsset
.empty();++tries
) {
555 subdomain
=getBestNSNamesFromCache(subdomain
, qtype
, nsset
, &flawedNSSet
, depth
, beenthere
); // pass beenthere to both occasions
558 if(!(res
=doResolveAt(nsset
, subdomain
, flawedNSSet
, qname
, qtype
, ret
, depth
, beenthere
)))
561 LOG(prefix
<<qname
<<": failed (res="<<res
<<")"<<endl
);
567 return res
<0 ? RCode::ServFail
: res
;
571 // for testing purposes
572 static bool ipv6First(const ComboAddress
& a
, const ComboAddress
& b
)
574 return !(a
.sin4
.sin_family
< a
.sin4
.sin_family
);
578 /** This function explicitly goes out for A or AAAA addresses
580 vector
<ComboAddress
> SyncRes::getAddrs(const DNSName
&qname
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
)
582 typedef vector
<DNSRecord
> res_t
;
585 typedef vector
<ComboAddress
> ret_t
;
590 for(int j
=1; j
<2+s_doIPv6
; j
++)
605 if(!doResolve(qname
, type
, res
,depth
+1, beenthere
) && !res
.empty()) { // this consults cache, OR goes out
606 for(res_t::const_iterator i
=res
.begin(); i
!= res
.end(); ++i
) {
607 if(i
->d_type
== QType::A
|| i
->d_type
== QType::AAAA
) {
608 if(auto rec
= std::dynamic_pointer_cast
<ARecordContent
>(i
->d_content
))
609 ret
.push_back(rec
->getCA(53));
610 else if(auto aaaarec
= std::dynamic_pointer_cast
<AAAARecordContent
>(i
->d_content
))
611 ret
.push_back(aaaarec
->getCA(53));
617 if(j
==1 && s_doIPv6
) { // we got an A record, see if we have some AAAA lying around
618 vector
<DNSRecord
> cset
;
619 if(t_RC
->get(d_now
.tv_sec
, qname
, QType(QType::AAAA
), &cset
, d_requestor
) > 0) {
620 for(auto k
=cset
.cbegin();k
!=cset
.cend();++k
) {
621 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
622 if (auto drc
= std::dynamic_pointer_cast
<AAAARecordContent
>(k
->d_content
)) {
623 ComboAddress ca
=drc
->getCA(53);
635 random_shuffle(ret
.begin(), ret
.end(), dns_random
);
637 // move 'best' address for this nameserver name up front
638 nsspeeds_t::iterator best
= t_sstorage
->nsSpeeds
.find(qname
);
640 if(best
!= t_sstorage
->nsSpeeds
.end())
641 for(ret_t::iterator i
=ret
.begin(); i
!= ret
.end(); ++i
) {
642 if(*i
==best
->second
.d_best
) { // got the fastest one
645 *ret
.begin()=best
->second
.d_best
;
655 void SyncRes::getBestNSFromCache(const DNSName
&qname
, const QType
& qtype
, vector
<DNSRecord
>& bestns
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
)
658 DNSName
subdomain(qname
);
661 prefix
.append(depth
, ' ');
667 LOG(prefix
<<qname
<<": Checking if we have NS in cache for '"<<subdomain
<<"'"<<endl
);
668 vector
<DNSRecord
> ns
;
669 *flawedNSSet
= false;
670 if(t_RC
->get(d_now
.tv_sec
, subdomain
, QType(QType::NS
), &ns
, d_requestor
) > 0) {
671 for(auto k
=ns
.cbegin();k
!=ns
.cend(); ++k
) {
672 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
673 vector
<DNSRecord
> aset
;
675 const DNSRecord
& dr
=*k
;
676 auto nrr
= getRR
<NSRecordContent
>(dr
);
677 if(nrr
&& (!nrr
->getNS().isPartOf(subdomain
) || t_RC
->get(d_now
.tv_sec
, nrr
->getNS(), s_doIPv6
? QType(QType::ADDR
) : QType(QType::A
),
678 doLog() ? &aset
: 0, d_requestor
) > 5)) {
679 bestns
.push_back(dr
);
680 LOG(prefix
<<qname
<<": NS (with ip, or non-glue) in cache for '"<<subdomain
<<"' -> '"<<nrr
->getNS()<<"'"<<endl
);
681 LOG(prefix
<<qname
<<": within bailiwick: "<< nrr
->getNS().isPartOf(subdomain
));
683 LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset
.begin()->d_ttl
- d_now
.tv_sec
))<<endl
);
686 LOG(", not in cache / did not look at cache"<<endl
);
691 LOG(prefix
<<qname
<<": NS in cache for '"<<subdomain
<<"', but needs glue ("<<nrr
->getNS()<<") which we miss or is expired"<<endl
);
695 if(!bestns
.empty()) {
696 GetBestNSAnswer answer
;
698 answer
.qtype
=qtype
.getCode();
699 for(const auto& dr
: bestns
)
700 answer
.bestns
.insert(make_pair(dr
.d_name
, getRR
<NSRecordContent
>(dr
)->getNS()));
702 if(beenthere
.count(answer
)) {
704 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' but part of LOOP (already seen "<<answer
.qname
<<")! Trying less specific NS"<<endl
);
707 for( set
<GetBestNSAnswer
>::const_iterator j
=beenthere
.begin();j
!=beenthere
.end();++j
) {
708 bool neo
= !(*j
< answer
|| answer
<*j
);
709 LOG(prefix
<<qname
<<": beenthere"<<(neo
?"*":"")<<": "<<j
->qname
<<"|"<<DNSRecordContent::NumberToType(j
->qtype
)<<" ("<<(unsigned int)j
->bestns
.size()<<")"<<endl
);
714 beenthere
.insert(answer
);
715 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' (flawedNSSet="<<*flawedNSSet
<<")"<<endl
);
720 LOG(prefix
<<qname
<<": no valid/useful NS in cache for '"<<subdomain
<<"'"<<endl
);
722 if(subdomain
.isRoot() && !brokeloop
) {
723 // We lost the root NS records
725 LOG(prefix
<<qname
<<": reprimed the root"<<endl
);
726 getRootNS(d_now
, d_asyncResolve
);
728 }while(subdomain
.chopOff());
731 SyncRes::domainmap_t::const_iterator
SyncRes::getBestAuthZone(DNSName
* qname
) const
733 SyncRes::domainmap_t::const_iterator ret
;
735 ret
=t_sstorage
->domainmap
->find(*qname
);
736 if(ret
!=t_sstorage
->domainmap
->end())
738 }while(qname
->chopOff());
742 /** doesn't actually do the work, leaves that to getBestNSFromCache */
743 DNSName
SyncRes::getBestNSNamesFromCache(const DNSName
&qname
, const QType
& qtype
, NsSet
& nsset
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
)
745 DNSName
subdomain(qname
);
746 DNSName
authdomain(qname
);
748 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
749 if(iter
!=t_sstorage
->domainmap
->end()) {
750 if( iter
->second
.d_servers
.empty() )
751 // this gets picked up in doResolveAt, the empty DNSName, combined with the
752 // empty vector means 'we are auth for this zone'
753 nsset
.insert({DNSName(), {{}, false}});
755 // Again, picked up in doResolveAt. An empty DNSName, combined with a
756 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
757 nsset
.insert({DNSName(), {iter
->second
.d_servers
, iter
->second
.d_rdForward
}});
762 vector
<DNSRecord
> bestns
;
763 getBestNSFromCache(subdomain
, qtype
, bestns
, flawedNSSet
, depth
, beenthere
);
765 for(auto k
=bestns
.cbegin() ; k
!= bestns
.cend(); ++k
) {
766 // The actual resolver code will not even look at the ComboAddress or bool
767 nsset
.insert({std::dynamic_pointer_cast
<NSRecordContent
>(k
->d_content
)->getNS(), {{}, false}});
768 if(k
==bestns
.cbegin())
774 bool SyncRes::doCNAMECacheCheck(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>& ret
, unsigned int depth
, int &res
)
779 prefix
.append(depth
, ' ');
782 if((depth
>9 && d_outqueries
>10 && d_throttledqueries
>5) || depth
> 15) {
783 LOG(prefix
<<qname
<<": recursing (CNAME or other indirection) too deep, depth="<<depth
<<endl
);
788 LOG(prefix
<<qname
<<": Looking for CNAME cache hit of '"<<qname
<<"|CNAME"<<"'"<<endl
);
789 vector
<DNSRecord
> cset
;
790 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
791 if(t_RC
->get(d_now
.tv_sec
, qname
,QType(QType::CNAME
), &cset
, d_requestor
, &signatures
) > 0) {
793 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
794 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
795 LOG(prefix
<<qname
<<": Found cache CNAME hit for '"<< qname
<< "|CNAME" <<"' to '"<<j
->d_content
->getZoneRepresentation()<<"'"<<endl
);
797 dr
.d_ttl
-=d_now
.tv_sec
;
800 for(const auto& signature
: signatures
) {
802 sigdr
.d_type
=QType::RRSIG
;
804 sigdr
.d_ttl
=j
->d_ttl
- d_now
.tv_sec
;
805 sigdr
.d_content
=signature
;
806 sigdr
.d_place
=DNSResourceRecord::ANSWER
;
808 ret
.push_back(sigdr
);
811 if(qtype
!= QType::CNAME
) { // perhaps they really wanted a CNAME!
812 set
<GetBestNSAnswer
>beenthere
;
813 res
=doResolve(std::dynamic_pointer_cast
<CNAMERecordContent
>(j
->d_content
)->getTarget(), qtype
, ret
, depth
+1, beenthere
);
821 LOG(prefix
<<qname
<<": No CNAME cache hit of '"<< qname
<< "|CNAME" <<"' found"<<endl
);
826 * Convience function to push the records from records into ret with a new TTL
828 * \param records DNSRecords that need to go into ret
829 * \param ttl The new TTL for these records
830 * \param ret The vector of DNSRecords that should contian the records with the modified TTL
832 static void addTTLModifiedRecords(const vector
<DNSRecord
>& records
, const uint32_t ttl
, vector
<DNSRecord
>& ret
) {
833 for (const auto& rec
: records
) {
841 bool SyncRes::doCacheCheck(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int &res
)
843 bool giveNegative
=false;
848 prefix
.append(depth
, ' ');
851 // 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)
852 DNSName
sqname(qname
);
855 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
857 DNSName
authname(qname
);
858 bool wasForwardedOrAuth
= false;
859 bool wasAuth
= false;
860 domainmap_t::const_iterator iter
=getBestAuthZone(&authname
);
861 if(iter
!= t_sstorage
->domainmap
->end()) {
862 wasForwardedOrAuth
= true;
863 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
864 if(servers
.empty()) {
868 NegCache::NegCacheEntry ne
;
871 t_sstorage
->negcache
.getRootNXTrust(qname
, d_now
, ne
) &&
872 ne
.d_auth
.isRoot() &&
873 !(wasForwardedOrAuth
&& !authname
.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
874 sttl
= ne
.d_ttd
- d_now
.tv_sec
;
875 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
.d_auth
<<"' & '"<<ne
.d_name
<<"' for another "<<sttl
<<" seconds"<<endl
);
876 res
= RCode::NXDomain
;
879 else if (t_sstorage
->negcache
.get(qname
, qtype
, d_now
, ne
) &&
880 !(wasForwardedOrAuth
&& ne
.d_auth
!= authname
)) { // Only the authname nameserver can neg cache entries
882 sttl
= ne
.d_ttd
- d_now
.tv_sec
;
884 if(ne
.d_qtype
.getCode()) {
885 LOG(prefix
<<qname
<<": "<<qtype
.getName()<<" is negatively cached via '"<<ne
.d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
886 res
= RCode::NoError
;
889 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
.d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
890 res
= RCode::NXDomain
;
893 addTTLModifiedRecords(ne
.DNSSECRecords
.records
, sttl
, ret
);
894 addTTLModifiedRecords(ne
.DNSSECRecords
.signatures
, sttl
, ret
);
899 // Transplant SOA to the returned packet
900 addTTLModifiedRecords(ne
.authoritySOA
.records
, sttl
, ret
);
902 addTTLModifiedRecords(ne
.authoritySOA
.signatures
, sttl
, ret
);
906 vector
<DNSRecord
> cset
;
907 bool found
=false, expired
=false;
908 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
910 if(t_RC
->get(d_now
.tv_sec
, sqname
, sqt
, &cset
, d_requestor
, d_doDNSSEC
? &signatures
: 0) > 0) {
911 LOG(prefix
<<sqname
<<": Found cache hit for "<<sqt
.getName()<<": ");
912 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
913 LOG(j
->d_content
->getZoneRepresentation());
914 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
916 ttl
= (dr
.d_ttl
-=d_now
.tv_sec
);
918 LOG("[ttl="<<dr
.d_ttl
<<"] ");
927 for(const auto& signature
: signatures
) {
929 dr
.d_type
=QType::RRSIG
;
932 dr
.d_content
=signature
;
933 dr
.d_place
= DNSResourceRecord::ANSWER
;
939 if(found
&& !expired
) {
942 d_wasOutOfBand
= wasAuth
;
946 LOG(prefix
<<qname
<<": cache had only stale entries"<<endl
);
952 bool SyncRes::moreSpecificThan(const DNSName
& a
, const DNSName
&b
) const
954 return (a
.isPartOf(b
) && a
.countLabels() > b
.countLabels());
959 speedOrder(map
<DNSName
,double> &speeds
) : d_speeds(speeds
) {}
960 bool operator()(const DNSName
&a
, const DNSName
&b
) const
962 return d_speeds
[a
] < d_speeds
[b
];
964 map
<DNSName
, double>& d_speeds
;
967 inline vector
<DNSName
> SyncRes::shuffleInSpeedOrder(NsSet
&tnameservers
, const string
&prefix
)
969 vector
<DNSName
> rnameservers
;
970 rnameservers
.reserve(tnameservers
.size());
971 for(const auto& tns
:tnameservers
) {
972 rnameservers
.push_back(tns
.first
);
974 map
<DNSName
, double> speeds
;
976 for(const auto& val
: rnameservers
) {
978 speed
=t_sstorage
->nsSpeeds
[val
].get(&d_now
);
981 random_shuffle(rnameservers
.begin(),rnameservers
.end(), dns_random
);
982 speedOrder
so(speeds
);
983 stable_sort(rnameservers
.begin(),rnameservers
.end(), so
);
986 LOG(prefix
<<"Nameservers: ");
987 for(vector
<DNSName
>::const_iterator i
=rnameservers
.begin();i
!=rnameservers
.end();++i
) {
988 if(i
!=rnameservers
.begin()) {
990 if(!((i
-rnameservers
.begin())%3)) {
991 LOG(endl
<<prefix
<<" ");
994 LOG((i
->empty() ? string("<empty>") : i
->toString())<<"(" << (boost::format("%0.2f") % (speeds
[*i
]/1000.0)).str() <<"ms)");
1001 static bool magicAddrMatch(const QType
& query
, const QType
& answer
)
1003 if(query
.getCode() != QType::ADDR
)
1005 return answer
.getCode() == QType::A
|| answer
.getCode() == QType::AAAA
;
1008 /* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
1010 * \param records The records to parse for the authority SOA and NSEC(3) records
1011 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
1013 static void harvestNXRecords(const vector
<DNSRecord
>& records
, NegCache::NegCacheEntry
& ne
) {
1014 static const set
<uint16_t> nsecTypes
= {QType::NSEC
, QType::NSEC3
};
1015 for(const auto& rec
: records
) {
1016 if(rec
.d_place
!= DNSResourceRecord::AUTHORITY
)
1017 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
1018 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
1019 // records MUST be in the same section as the records they cover.
1020 // Hence, we ignore all records outside of the AUTHORITY section.
1023 if(rec
.d_type
== QType::RRSIG
) {
1024 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1026 if(rrsig
->d_type
== QType::SOA
) {
1027 ne
.authoritySOA
.signatures
.push_back(rec
);
1029 if(nsecTypes
.count(rrsig
->d_type
)) {
1030 ne
.DNSSECRecords
.signatures
.push_back(rec
);
1035 if(rec
.d_type
== QType::SOA
) {
1036 ne
.authoritySOA
.records
.push_back(rec
);
1039 if(nsecTypes
.count(rec
.d_type
)) {
1040 ne
.DNSSECRecords
.records
.push_back(rec
);
1046 // TODO remove after processRecords is fixed!
1047 // Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
1048 static void addNXNSECS(vector
<DNSRecord
>&ret
, const vector
<DNSRecord
>& records
)
1050 NegCache::NegCacheEntry ne
;
1051 harvestNXRecords(records
, ne
);
1052 ret
.insert(ret
.end(), ne
.authoritySOA
.signatures
.begin(), ne
.authoritySOA
.signatures
.end());
1053 ret
.insert(ret
.end(), ne
.DNSSECRecords
.records
.begin(), ne
.DNSSECRecords
.records
.end());
1054 ret
.insert(ret
.end(), ne
.DNSSECRecords
.signatures
.begin(), ne
.DNSSECRecords
.signatures
.end());
1057 bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine
& dfe
, const NsSet
& nameservers
)
1060 for (auto const &ns
: nameservers
) {
1061 d_appliedPolicy
= dfe
.getProcessingPolicy(ns
.first
, d_discardedPolicies
);
1062 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1063 LOG(", however nameserver "<<ns
.first
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1067 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1068 for (auto const &address
: ns
.second
.first
) {
1069 d_appliedPolicy
= dfe
.getProcessingPolicy(address
, d_discardedPolicies
);
1070 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1071 LOG(", however nameserver "<<ns
.first
<<" IP address "<<address
.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1080 bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine
& dfe
, const ComboAddress
& remoteIP
)
1083 d_appliedPolicy
= dfe
.getProcessingPolicy(remoteIP
, d_discardedPolicies
);
1084 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) {
1085 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")+"')");
1092 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
)
1094 vector
<ComboAddress
> result
;
1097 LOG(prefix
<<qname
<<": Trying to resolve NS '"<<*tns
<< "' ("<<1+tns
-rnameservers
.begin()<<"/"<<(unsigned int)rnameservers
.size()<<")"<<endl
);
1098 result
= getAddrs(*tns
, depth
+2, beenthere
);
1099 pierceDontQuery
=false;
1102 LOG(prefix
<<qname
<<": Domain has hardcoded nameserver");
1104 result
= nameservers
[*tns
].first
;
1105 if(result
.size() > 1) {
1110 sendRDQuery
= nameservers
[*tns
].second
;
1111 pierceDontQuery
=true;
1116 bool SyncRes::throttledOrBlocked(const std::string
& prefix
, const ComboAddress
& remoteIP
, const DNSName
& qname
, const QType
& qtype
, bool pierceDontQuery
)
1118 if(t_sstorage
->throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0))) {
1119 LOG(prefix
<<qname
<<": server throttled "<<endl
);
1120 s_throttledqueries
++; d_throttledqueries
++;
1123 else if(t_sstorage
->throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()))) {
1124 LOG(prefix
<<qname
<<": query throttled "<<endl
);
1125 s_throttledqueries
++; d_throttledqueries
++;
1128 else if(!pierceDontQuery
&& s_dontQuery
&& s_dontQuery
->match(&remoteIP
)) {
1129 LOG(prefix
<<qname
<<": not sending query to " << remoteIP
.toString() << ", blocked by 'dont-query' setting" << endl
);
1136 RCode::rcodes_
SyncRes::updateCacheFromRecords(const std::string
& prefix
, LWResult
& lwr
, const DNSName
& qname
, const DNSName
& auth
, NsSet
& nameservers
, const DNSName
& tns
, const boost::optional
<Netmask
> ednsmask
)
1140 vector
<DNSRecord
> records
;
1141 vector
<shared_ptr
<RRSIGRecordContent
>> signatures
;
1147 DNSResourceRecord::Place place
;
1148 bool operator<(const CacheKey
& rhs
) const {
1149 return tie(name
, type
) < tie(rhs
.name
, rhs
.type
);
1152 typedef map
<CacheKey
, CachePair
> tcache_t
;
1155 for(const auto& rec
: lwr
.d_records
) {
1156 if(rec
.d_type
== QType::RRSIG
) {
1157 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1159 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
1160 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
1165 // reap all answers from this packet that are acceptable
1166 for(auto& rec
: lwr
.d_records
) {
1167 if(rec
.d_type
== QType::OPT
) {
1168 LOG(prefix
<<qname
<<": OPT answer '"<<rec
.d_name
<<"' from '"<<auth
<<"' nameservers" <<endl
);
1171 LOG(prefix
<<qname
<<": accept answer '"<<rec
.d_name
<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"|"<<rec
.d_content
->getZoneRepresentation()<<"' from '"<<auth
<<"' nameservers? "<<(int)rec
.d_place
<<" ");
1172 if(rec
.d_type
== QType::ANY
) {
1173 LOG("NO! - we don't accept 'ANY' data"<<endl
);
1177 if(rec
.d_name
.isPartOf(auth
)) {
1178 if(rec
.d_type
== QType::RRSIG
) {
1179 LOG("RRSIG - separate"<<endl
);
1181 else if(lwr
.d_aabit
&& lwr
.d_rcode
==RCode::NoError
&& rec
.d_place
==DNSResourceRecord::ANSWER
&& (rec
.d_type
!= QType::DNSKEY
|| rec
.d_name
!= auth
) && s_delegationOnly
.count(auth
)) {
1182 LOG("NO! Is from delegation-only zone"<<endl
);
1184 return RCode::NXDomain
;
1187 bool haveLogged
= false;
1188 if (!t_sstorage
->domainmap
->empty()) {
1189 // Check if we are authoritative for a zone in this answer
1190 DNSName
tmp_qname(rec
.d_name
);
1191 auto auth_domain_iter
=getBestAuthZone(&tmp_qname
);
1192 if(auth_domain_iter
!=t_sstorage
->domainmap
->end() &&
1193 auth
.countLabels() <= auth_domain_iter
->first
.countLabels()) {
1194 if (auth_domain_iter
->first
!= auth
) {
1195 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter
->first
<<endl
);
1198 LOG("YES! - This answer was ");
1199 if (nameservers
[tns
].first
.empty()) {
1200 LOG("retrieved from the local auth store.");
1202 LOG("received from a server we forward to.");
1213 rec
.d_ttl
=min(s_maxcachettl
, rec
.d_ttl
);
1216 dr
.d_place
=DNSResourceRecord::ANSWER
;
1218 dr
.d_ttl
+= d_now
.tv_sec
;
1219 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(dr
);
1227 for(tcache_t::iterator i
=tcache
.begin();i
!=tcache
.end();++i
) {
1228 if(i
->second
.records
.size() > 1) { // need to group the ttl to be the minimum of the RRSET (RFC 2181, 5.2)
1229 uint32_t lowestTTL
=std::numeric_limits
<uint32_t>::max();
1230 for(const auto& record
: i
->second
.records
)
1231 lowestTTL
=min(lowestTTL
, record
.d_ttl
);
1233 for(auto& record
: i
->second
.records
)
1234 *const_cast<uint32_t*>(&record
.d_ttl
)=lowestTTL
; // boom
1237 // cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
1238 // cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
1239 if(i
->second
.records
.empty()) // this happens when we did store signatures, but passed on the records themselves
1241 t_RC
->replace(d_now
.tv_sec
, i
->first
.name
, QType(i
->first
.type
), i
->second
.records
, i
->second
.signatures
, lwr
.d_aabit
, i
->first
.place
== DNSResourceRecord::ANSWER
? ednsmask
: boost::optional
<Netmask
>());
1242 if(i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
)
1246 return RCode::NoError
;
1249 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
, bool& sawDS
)
1253 for(auto& rec
: lwr
.d_records
) {
1254 if (rec
.d_type
!=QType::OPT
&& rec
.d_class
!=QClass::IN
)
1257 if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
1258 lwr
.d_rcode
==RCode::NXDomain
&& qname
.isPartOf(rec
.d_name
) && rec
.d_name
.isPartOf(auth
)) {
1259 LOG(prefix
<<qname
<<": got negative caching indication for name '"<<qname
<<"' (accept="<<rec
.d_name
.isPartOf(auth
)<<"), newtarget='"<<newtarget
<<"'"<<endl
);
1261 rec
.d_ttl
= min(rec
.d_ttl
, s_maxnegttl
);
1262 if(newtarget
.empty()) // only add a SOA if we're not going anywhere after this
1264 if(!wasVariable()) {
1265 NegCache::NegCacheEntry ne
;
1267 ne
.d_ttd
= d_now
.tv_sec
+ rec
.d_ttl
;
1269 ne
.d_qtype
= QType(0); // this encodes 'whole record'
1270 ne
.d_auth
= rec
.d_name
;
1271 harvestNXRecords(lwr
.d_records
, ne
);
1272 t_sstorage
->negcache
.add(ne
);
1273 if(s_rootNXTrust
&& ne
.d_auth
.isRoot() && auth
.isRoot()) {
1274 ne
.d_name
= ne
.d_name
.getLastLabel();
1275 t_sstorage
->negcache
.add(ne
);
1281 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&& rec
.d_type
==QType::CNAME
&& (!(qtype
==QType(QType::CNAME
)))) {
1283 if (auto content
= getRR
<CNAMERecordContent
>(rec
)) {
1284 newtarget
=content
->getTarget();
1287 else if((rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::ANSWER
){
1288 if(rec
.d_type
!= QType::RRSIG
|| rec
.d_name
== qname
)
1289 ret
.push_back(rec
); // enjoy your DNSSEC
1291 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
1292 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&&
1294 rec
.d_type
==qtype
.getCode() || (lwr
.d_aabit
&& (qtype
==QType(QType::ANY
) || magicAddrMatch(qtype
, QType(rec
.d_type
)) ) ) || sendRDQuery
1298 LOG(prefix
<<qname
<<": answer is in: resolved to '"<< rec
.d_content
->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"'"<<endl
);
1303 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& qname
.isPartOf(rec
.d_name
) && rec
.d_type
==QType::NS
) {
1304 if(moreSpecificThan(rec
.d_name
,auth
)) {
1306 LOG(prefix
<<qname
<<": got NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
1310 LOG(prefix
<<qname
<<": got upwards/level NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"', had '"<<auth
<<"'"<<endl
);
1312 if (auto content
= getRR
<NSRecordContent
>(rec
)) {
1313 nsset
.insert(content
->getNS());
1316 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& qname
.isPartOf(rec
.d_name
) && rec
.d_type
==QType::DS
) {
1317 LOG(prefix
<<qname
<<": got DS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
1320 else if(!done
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& qname
.isPartOf(rec
.d_name
) && rec
.d_type
==QType::SOA
&&
1321 lwr
.d_rcode
==RCode::NoError
) {
1322 LOG(prefix
<<qname
<<": got negative caching indication for '"<< qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
1324 if(!newtarget
.empty()) {
1325 LOG(prefix
<<qname
<<": Hang on! Got a redirect to '"<<newtarget
<<"' already"<<endl
);
1328 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
1330 if(!wasVariable()) {
1331 NegCache::NegCacheEntry ne
;
1332 ne
.d_auth
= rec
.d_name
;
1333 ne
.d_ttd
= d_now
.tv_sec
+ rec
.d_ttl
;
1336 harvestNXRecords(lwr
.d_records
, ne
);
1337 if(qtype
.getCode()) { // prevents us from blacking out a whole domain
1338 t_sstorage
->negcache
.add(ne
);
1350 * -1 in case of no results
1351 * -2 when a FilterEngine Policy was hit
1354 int SyncRes::doResolveAt(NsSet
&nameservers
, DNSName auth
, bool flawedNSSet
, const DNSName
&qname
, const QType
&qtype
,
1355 vector
<DNSRecord
>&ret
,
1356 unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
)
1358 auto luaconfsLocal
= g_luaconfs
.getLocal();
1362 prefix
.append(depth
, ' ');
1365 LOG(prefix
<<qname
<<": Cache consultations done, have "<<(unsigned int)nameservers
.size()<<" NS to contact");
1367 if (nameserversBlockedByRPZ(luaconfsLocal
->dfe
, nameservers
)) {
1373 for(;;) { // we may get more specific nameservers
1374 vector
<DNSName
> rnameservers
= shuffleInSpeedOrder(nameservers
, doLog() ? (prefix
+qname
.toString()+": ") : string() );
1376 for(auto tns
=rnameservers
.cbegin();;++tns
) {
1377 if(tns
==rnameservers
.cend()) {
1378 LOG(prefix
<<qname
<<": Failed to resolve via any of the "<<(unsigned int)rnameservers
.size()<<" offered NS at level '"<<auth
<<"'"<<endl
);
1379 if(!auth
.isRoot() && flawedNSSet
) {
1380 LOG(prefix
<<qname
<<": Ageing nameservers for level '"<<auth
<<"', next query might succeed"<<endl
);
1382 if(t_RC
->doAgeCache(d_now
.tv_sec
, auth
, QType::NS
, 10))
1383 g_stats
.nsSetInvalidations
++;
1387 // this line needs to identify the 'self-resolving' behaviour, but we get it wrong now
1388 if(qname
== *tns
&& qtype
.getCode()==QType::A
&& rnameservers
.size() > (size_t)(1+1*s_doIPv6
)) {
1389 LOG(prefix
<<qname
<<": Not using NS to resolve itself! ("<<(1+tns
-rnameservers
.cbegin())<<"/"<<rnameservers
.size()<<")"<<endl
);
1393 typedef vector
<ComboAddress
> remoteIPs_t
;
1394 remoteIPs_t remoteIPs
;
1395 remoteIPs_t::const_iterator remoteIP
;
1397 bool pierceDontQuery
=false;
1398 bool sendRDQuery
=false;
1399 boost::optional
<Netmask
> ednsmask
;
1401 if(tns
->empty() && nameservers
[*tns
].first
.empty() ) {
1402 LOG(prefix
<<qname
<<": Domain is out-of-band"<<endl
);
1403 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, lwr
.d_records
, depth
, lwr
.d_rcode
);
1408 remoteIPs
= retrieveAddressesForNS(prefix
, qname
, tns
, depth
, beenthere
, rnameservers
, nameservers
, sendRDQuery
, pierceDontQuery
, flawedNSSet
);
1410 if(remoteIPs
.empty()) {
1411 LOG(prefix
<<qname
<<": Failed to get IP for NS "<<*tns
<<", trying next if available"<<endl
);
1416 bool hitPolicy
{false};
1417 LOG(prefix
<<qname
<<": Resolved '"<<auth
<<"' NS "<<*tns
<<" to: ");
1418 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
1419 if(remoteIP
!= remoteIPs
.cbegin()) {
1422 LOG(remoteIP
->toString());
1423 if(nameserverIPBlockedByRPZ(luaconfsLocal
->dfe
, *remoteIP
)) {
1428 if (hitPolicy
) //implies d_wantsRPZ
1432 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
1433 LOG(prefix
<<qname
<<": Trying IP "<< remoteIP
->toStringWithPort() <<", asking '"<<qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
1434 if (throttledOrBlocked(prefix
, *remoteIP
, qname
, qtype
, pierceDontQuery
)) {
1439 s_outqueries
++; d_outqueries
++;
1440 if(d_outqueries
+ d_throttledqueries
> s_maxqperq
) throw ImmediateServFailException("more than "+std::to_string(s_maxqperq
)+" (max-qperq) queries sent while resolving "+qname
.toLogString());
1443 LOG(prefix
<<qname
<<": using TCP with "<< remoteIP
->toStringWithPort() <<endl
);
1444 s_tcpoutqueries
++; d_tcpoutqueries
++;
1447 if(s_maxtotusec
&& d_totUsec
> s_maxtotusec
)
1448 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");
1450 if(d_pdl
&& d_pdl
->preoutquery(*remoteIP
, d_requestor
, qname
, qtype
, doTCP
, lwr
.d_records
, resolveret
)) {
1451 LOG(prefix
<<qname
<<": query handled by Lua"<<endl
);
1454 ednsmask
=getEDNSSubnetMask(d_requestor
, qname
, *remoteIP
);
1456 LOG(prefix
<<qname
<<": Adding EDNS Client Subnet Mask "<<ednsmask
->toString()<<" to query"<<endl
);
1458 resolveret
=asyncresolveWrapper(*remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(),
1459 doTCP
, sendRDQuery
, &d_now
, ednsmask
, &lwr
); // <- we go out on the wire!
1461 LOG(prefix
<<qname
<<": Received EDNS Client Subnet Mask "<<ednsmask
->toString()<<" on response"<<endl
);
1467 throw ImmediateServFailException("Query killed by policy");
1469 d_totUsec
+= lwr
.d_usec
;
1470 accountAuthLatency(lwr
.d_usec
, remoteIP
->sin4
.sin_family
);
1471 if(resolveret
!= 1) {
1473 LOG(prefix
<<qname
<<": timeout resolving after "<<lwr
.d_usec
/1000.0<<"msec "<< (doTCP
? "over TCP" : "")<<endl
);
1475 s_outgoingtimeouts
++;
1476 if(remoteIP
->sin4
.sin_family
== AF_INET
)
1477 s_outgoing4timeouts
++;
1479 s_outgoing6timeouts
++;
1481 else if(resolveret
==-2) {
1482 LOG(prefix
<<qname
<<": hit a local resource limit resolving"<< (doTCP
? " over TCP" : "")<<", probable error: "<<stringerror()<<endl
);
1483 g_stats
.resourceLimits
++;
1486 s_unreachables
++; d_unreachables
++;
1487 LOG(prefix
<<qname
<<": error resolving from "<<remoteIP
->toString()<< (doTCP
? " over TCP" : "") <<", possible error: "<<strerror(errno
)<< endl
);
1490 if(resolveret
!=-2) { // don't account for resource limits, they are our own fault
1491 t_sstorage
->nsSpeeds
[*tns
].submit(*remoteIP
, 1000000, &d_now
); // 1 sec
1493 // code below makes sure we don't filter COM or the root
1494 if (s_serverdownmaxfails
> 0 && (auth
!= g_rootdnsname
) && t_sstorage
->fails
.incr(*remoteIP
) >= s_serverdownmaxfails
) {
1495 LOG(prefix
<<qname
<<": Max fails reached resolving on "<< remoteIP
->toString() <<". Going full throttle for "<< s_serverdownthrottletime
<<" seconds" <<endl
);
1496 t_sstorage
->throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, "", 0), s_serverdownthrottletime
, 10000); // mark server as down
1497 } else if(resolveret
==-1)
1498 t_sstorage
->throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100); // unreachable, 1 minute or 100 queries
1500 t_sstorage
->throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 10, 5); // timeout
1505 // if(d_timeouts + 0.5*d_throttledqueries > 6.0 && d_timeouts > 2) throw ImmediateServFailException("Too much work resolving "+qname+"|"+qtype.getName()+", timeouts: "+std::to_string(d_timeouts) +", throttles: "+std::to_string(d_throttledqueries));
1507 if(lwr
.d_rcode
==RCode::ServFail
|| lwr
.d_rcode
==RCode::Refused
) {
1508 LOG(prefix
<<qname
<<": "<<*tns
<<" ("<<remoteIP
->toString()<<") returned a "<< (lwr
.d_rcode
==RCode::ServFail
? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl
);
1509 t_sstorage
->throttle
.throttle(d_now
.tv_sec
,boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()),60,3); // servfail or refused
1513 if(s_serverdownmaxfails
> 0)
1514 t_sstorage
->fails
.clear(*remoteIP
);
1516 break; // this IP address worked!
1517 wasLame
:; // well, it didn't
1518 LOG(prefix
<<qname
<<": status=NS "<<*tns
<<" ("<< remoteIP
->toString() <<") is lame for '"<<auth
<<"', trying sibling IP or NS"<<endl
);
1519 t_sstorage
->throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100); // lame
1523 if(remoteIP
== remoteIPs
.cend()) // we tried all IP addresses, none worked
1529 LOG(prefix
<<qname
<<": truncated bit set, retrying via TCP"<<endl
);
1532 LOG(prefix
<<qname
<<": truncated bit set, over TCP?"<<endl
);
1533 return RCode::ServFail
;
1535 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
);
1537 /* // for you IPv6 fanatics :-)
1538 if(remoteIP->sin4.sin_family==AF_INET6)
1541 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
1543 t_sstorage
->nsSpeeds
[*tns
].submit(*remoteIP
, lwr
.d_usec
, &d_now
);
1547 for(auto& rec
: lwr
.d_records
) {
1548 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumTTL
);
1552 RCode::rcodes_ rcode
= updateCacheFromRecords(prefix
, lwr
, qname
, auth
, nameservers
, *tns
, ednsmask
);
1553 if (rcode
!= RCode::NoError
) {
1557 LOG(prefix
<<qname
<<": determining status after receiving this packet"<<endl
);
1560 bool realreferral
=false, negindic
=false, sawDS
=false;
1564 bool done
= processRecords(prefix
, qname
, qtype
, auth
, lwr
, sendRDQuery
, ret
, nsset
, newtarget
, newauth
, realreferral
, negindic
, sawDS
);
1567 LOG(prefix
<<qname
<<": status=got results, this level of recursion done"<<endl
);
1570 if(!newtarget
.empty()) {
1571 if(newtarget
== qname
) {
1572 LOG(prefix
<<qname
<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl
);
1573 return RCode::ServFail
;
1576 LOG(prefix
<<qname
<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl
);
1577 return RCode::ServFail
;
1579 LOG(prefix
<<qname
<<": status=got a CNAME referral, starting over with "<<newtarget
<<endl
);
1581 set
<GetBestNSAnswer
> beenthere2
;
1582 return doResolve(newtarget
, qtype
, ret
, depth
+ 1, beenthere2
);
1584 if(lwr
.d_rcode
==RCode::NXDomain
) {
1585 LOG(prefix
<<qname
<<": status=NXDOMAIN, we are done "<<(negindic
? "(have negative SOA)" : "")<<endl
);
1588 addNXNSECS(ret
, lwr
.d_records
);
1590 return RCode::NXDomain
;
1592 if(nsset
.empty() && !lwr
.d_rcode
&& (negindic
|| lwr
.d_aabit
|| sendRDQuery
)) {
1593 LOG(prefix
<<qname
<<": status=noerror, other types may exist, but we are done "<<(negindic
? "(have negative SOA) " : "")<<(lwr
.d_aabit
? "(have aa bit) " : "")<<endl
);
1596 addNXNSECS(ret
, lwr
.d_records
);
1599 else if(realreferral
) {
1600 LOG(prefix
<<qname
<<": status=did not resolve, got "<<(unsigned int)nsset
.size()<<" NS, ");
1602 t_sstorage
->dnssecmap
[newauth
]=true;
1603 /* for(const auto& e : t_sstorage->dnssecmap)
1609 nameservers
.clear();
1610 for (auto const &nameserver
: nsset
) {
1612 d_appliedPolicy
= luaconfsLocal
->dfe
.getProcessingPolicy(nameserver
, d_discardedPolicies
);
1613 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1614 LOG("however "<<nameserver
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1618 nameservers
.insert({nameserver
, {{}, false}});
1620 LOG("looping to them"<<endl
);
1623 else if(!tns
->empty()) { // means: not OOB, OOB == empty
1631 boost::optional
<Netmask
> SyncRes::getEDNSSubnetMask(const ComboAddress
& local
, const DNSName
&dn
, const ComboAddress
& rem
)
1633 boost::optional
<Netmask
> result
;
1636 if(d_incomingECSFound
) {
1637 if (d_incomingECS
->source
.getBits() == 0) {
1638 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0 */
1641 trunc
= d_incomingECS
->source
.getMaskedNetwork();
1642 bits
= d_incomingECS
->source
.getBits();
1644 else if(!local
.isIPv4() || local
.sin4
.sin_addr
.s_addr
) { // detect unset 'requestor'
1646 bits
= local
.isIPv4() ? 32 : 128;
1649 /* nothing usable */
1653 if(s_ednsdomains
.check(dn
) || s_ednssubnets
.match(rem
)) {
1654 bits
= std::min(bits
, (trunc
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
1655 trunc
.truncate(bits
);
1656 return boost::optional
<Netmask
>(Netmask(trunc
, bits
));
1662 void SyncRes::parseEDNSSubnetWhitelist(const std::string
& wlist
)
1664 vector
<string
> parts
;
1665 stringtok(parts
, wlist
, ",; ");
1666 for(const auto& a
: parts
) {
1668 s_ednssubnets
.addMask(Netmask(a
));
1671 s_ednsdomains
.add(DNSName(a
));
1676 // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
1677 int directResolve(const DNSName
& qname
, const QType
& qtype
, int qclass
, vector
<DNSRecord
>& ret
)
1680 gettimeofday(&now
, 0);
1683 int res
= sr
.beginResolve(qname
, QType(qtype
), qclass
, ret
);
1688 #include "validate-recursor.hh"
1690 int SyncRes::getRootNS(struct timeval now
, asyncresolve_t asyncCallback
) {
1692 sr
.setDoEDNS0(true);
1694 sr
.setDoDNSSEC(g_dnssecmode
!= DNSSECMode::Off
);
1695 sr
.setAsyncCallback(asyncCallback
);
1697 vector
<DNSRecord
> ret
;
1700 res
=sr
.beginResolve(g_rootdnsname
, QType(QType::NS
), 1, ret
);
1701 if (g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
) {
1703 auto state
= validateRecords(ctx
, ret
);
1705 throw PDNSException("Got Bogus validation result for .|NS");
1709 catch(PDNSException
& e
)
1711 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
1714 catch(std::exception
& e
)
1716 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.what()<<endl
;
1721 L
<<Logger::Error
<<"Failed to update . records, got an exception"<<endl
;
1724 L
<<Logger::Notice
<<"Refreshed . records"<<endl
;
1727 L
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;