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
;
82 #define LOG(x) if(d_lm == Log) { L <<Logger::Warning << x; } else if(d_lm == Store) { d_trace << x; }
84 bool SyncRes::s_noEDNS
;
86 static void accountAuthLatency(int usec
, int family
)
88 if(family
== AF_INET
) {
90 g_stats
.auth4Answers0_1
++;
92 g_stats
.auth4Answers1_10
++;
93 else if(usec
< 100000)
94 g_stats
.auth4Answers10_100
++;
95 else if(usec
< 1000000)
96 g_stats
.auth4Answers100_1000
++;
98 g_stats
.auth4AnswersSlow
++;
101 g_stats
.auth6Answers0_1
++;
102 else if(usec
< 10000)
103 g_stats
.auth6Answers1_10
++;
104 else if(usec
< 100000)
105 g_stats
.auth6Answers10_100
++;
106 else if(usec
< 1000000)
107 g_stats
.auth6Answers100_1000
++;
109 g_stats
.auth6AnswersSlow
++;
115 SyncRes::SyncRes(const struct timeval
& now
) : d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
116 d_totUsec(0), d_now(now
),
117 d_cacheonly(false), d_nocache(false), d_doDNSSEC(false), d_doEDNS0(false), d_lm(s_lm
)
121 t_sstorage
= new StaticStorage();
125 /** everything begins here - this is the entry point just after receiving a packet */
126 int SyncRes::beginResolve(const DNSName
&qname
, const QType
&qtype
, uint16_t qclass
, vector
<DNSRecord
>&ret
)
130 d_wasOutOfBand
=false;
132 if (doSpecialNamesResolve(qname
, qtype
, qclass
, ret
))
135 if( (qtype
.getCode() == QType::AXFR
) || (qtype
.getCode() == QType::IXFR
))
138 if(qclass
==QClass::ANY
)
140 else if(qclass
!=QClass::IN
)
143 set
<GetBestNSAnswer
> beenthere
;
144 int res
=doResolve(qname
, qtype
, ret
, 0, beenthere
);
148 /*! Handles all special, built-in names
149 * Fills ret with an answer and returns true if it handled the query.
151 * Handles the following queries (and their ANY variants):
154 * - localhost. IN AAAA
155 * - 1.0.0.127.in-addr.arpa. IN PTR
156 * - 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
157 * - version.bind. CH TXT
158 * - version.pdns. CH TXT
159 * - id.server. CH TXT
161 bool SyncRes::doSpecialNamesResolve(const DNSName
&qname
, const QType
&qtype
, const uint16_t &qclass
, vector
<DNSRecord
> &ret
)
163 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."),
164 localhost("localhost."), versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns.");
166 bool handled
= false;
167 vector
<pair
<QType::typeenum
, string
> > answers
;
169 if ((qname
== arpa
|| qname
== ip6_arpa
) &&
170 qclass
== QClass::IN
) {
172 if (qtype
== QType::PTR
|| qtype
== QType::ANY
)
173 answers
.push_back({QType::PTR
, "localhost."});
176 if (qname
== localhost
&&
177 qclass
== QClass::IN
) {
179 if (qtype
== QType::A
|| qtype
== QType::ANY
)
180 answers
.push_back({QType::A
, "127.0.0.1"});
181 if (qtype
== QType::AAAA
|| qtype
== QType::ANY
)
182 answers
.push_back({QType::AAAA
, "::1"});
185 if ((qname
== versionbind
|| qname
== idserver
|| qname
== versionpdns
) &&
186 qclass
== QClass::CHAOS
) {
188 if (qtype
== QType::TXT
|| qtype
== QType::ANY
) {
189 if(qname
== versionbind
|| qname
== versionpdns
)
190 answers
.push_back({QType::TXT
, "\""+::arg()["version-string"]+"\""});
192 answers
.push_back({QType::TXT
, "\""+s_serverID
+"\""});
196 if (handled
&& !answers
.empty()) {
202 dr
.d_place
= DNSResourceRecord::ANSWER
;
205 for (const auto& ans
: answers
) {
206 dr
.d_type
= ans
.first
;
207 dr
.d_content
= shared_ptr
<DNSRecordContent
>(DNSRecordContent::mastermake(ans
.first
, qclass
, ans
.second
));
216 //! This is the 'out of band resolver', in other words, the authoritative server
217 bool SyncRes::doOOBResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int& res
)
222 prefix
.append(depth
, ' ');
225 LOG(prefix
<<qname
<<": checking auth storage for '"<<qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
226 DNSName
authdomain(qname
);
228 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
229 if(iter
==t_sstorage
->domainmap
->end()) {
230 LOG(prefix
<<qname
<<": auth storage has no zone for this query!"<<endl
);
233 LOG(prefix
<<qname
<<": auth storage has data, zone='"<<authdomain
<<"'"<<endl
);
234 pair
<AuthDomain::records_t::const_iterator
, AuthDomain::records_t::const_iterator
> range
;
236 range
=iter
->second
.d_records
.equal_range(tie(qname
)); // partial lookup
239 AuthDomain::records_t::const_iterator ziter
;
241 for(ziter
=range
.first
; ziter
!=range
.second
; ++ziter
) {
243 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
244 ret
.push_back(*ziter
);
245 else if(ziter
->d_type
== QType::NS
&& ziter
->d_name
.countLabels() > authdomain
.countLabels()) { // we hit a delegation point!
247 dr
.d_place
=DNSResourceRecord::AUTHORITY
;
252 LOG(prefix
<<qname
<<": exact match in zone '"<<authdomain
<<"'"<<endl
);
257 LOG(prefix
<<qname
<<": found record in '"<<authdomain
<<"', but nothing of the right type, sending SOA"<<endl
);
258 ziter
=iter
->second
.d_records
.find(boost::make_tuple(authdomain
, QType::SOA
));
259 if(ziter
!=iter
->second
.d_records
.end()) {
261 dr
.d_place
=DNSResourceRecord::AUTHORITY
;
265 LOG(prefix
<<qname
<<": can't find SOA record '"<<authdomain
<<"' in our zone!"<<endl
);
270 LOG(prefix
<<qname
<<": nothing found so far in '"<<authdomain
<<"', trying wildcards"<<endl
);
271 DNSName
wcarddomain(qname
);
272 while(wcarddomain
!= iter
->first
&& wcarddomain
.chopOff()) {
273 LOG(prefix
<<qname
<<": trying '*."<<wcarddomain
<<"' in "<<authdomain
<<endl
);
274 range
=iter
->second
.d_records
.equal_range(boost::make_tuple(g_wildcarddnsname
+wcarddomain
));
275 if(range
.first
==range
.second
)
278 for(ziter
=range
.first
; ziter
!=range
.second
; ++ziter
) {
280 // if we hit a CNAME, just answer that - rest of recursor will do the needful & follow
281 if(dr
.d_type
== qtype
.getCode() || qtype
.getCode() == QType::ANY
|| dr
.d_type
== QType::CNAME
) {
283 dr
.d_place
=DNSResourceRecord::ANSWER
;
287 LOG(prefix
<<qname
<<": in '"<<authdomain
<<"', had wildcard match on '*."<<wcarddomain
<<"'"<<endl
);
292 DNSName
nsdomain(qname
);
294 while(nsdomain
.chopOff() && nsdomain
!= iter
->first
) {
295 range
=iter
->second
.d_records
.equal_range(boost::make_tuple(nsdomain
,QType::NS
));
296 if(range
.first
==range
.second
)
299 for(ziter
=range
.first
; ziter
!=range
.second
; ++ziter
) {
301 dr
.d_place
=DNSResourceRecord::AUTHORITY
;
306 LOG(prefix
<<qname
<<": no NS match in zone '"<<authdomain
<<"' either, handing out SOA"<<endl
);
307 ziter
=iter
->second
.d_records
.find(boost::make_tuple(authdomain
, QType::SOA
));
308 if(ziter
!=iter
->second
.d_records
.end()) {
310 dr
.d_place
=DNSResourceRecord::AUTHORITY
;
314 LOG(prefix
<<qname
<<": can't find SOA record '"<<authdomain
<<"' in our zone!"<<endl
);
324 void SyncRes::doEDNSDumpAndClose(int fd
)
326 FILE* fp
=fdopen(fd
, "w");
330 fprintf(fp
,"IP Address\tMode\tMode last updated at\n");
331 for(const auto& eds
: t_sstorage
->ednsstatus
) {
332 fprintf(fp
, "%s\t%d\t%s", eds
.first
.toString().c_str(), (int)eds
.second
.mode
, ctime(&eds
.second
.modeSetAt
));
338 /* so here is the story. First we complete the full resolution process for a domain name. And only THEN do we decide
339 to also do DNSSEC validation, which leads to new queries. To make this simple, we *always* ask for DNSSEC records
340 so that if there are RRSIGs for a name, we'll have them.
342 However, some hosts simply can't answer questions which ask for DNSSEC. This can manifest itself as:
347 The cause of "No answer" may be fragmentation, and it is tempting to probe if smaller answers would get through.
348 Another cause of "No answer" may simply be a network condition.
349 Nonsense answers are a clearer indication this host won't be able to do DNSSEC evah.
351 Previous implementations have suffered from turning off DNSSEC questions for an authoritative server based on timeouts.
352 A clever idea is to only turn off DNSSEC if we know a domain isn't signed anyhow. The problem with that really
353 clever idea however is that at this point in PowerDNS, we may simply not know that yet. All the DNSSEC thinking happens
354 elsewhere. It may not have happened yet.
356 For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish.
359 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
361 /* what is your QUEST?
362 the goal is to get as many remotes as possible on the highest level of EDNS support
365 0) UNKNOWN Unknown state
366 1) EDNS: Honors EDNS0
367 2) EDNSIGNORANT: Ignores EDNS0, gives replies without EDNS0
368 3) NOEDNS: Generates FORMERR/NOTIMP on EDNS queries
370 Everybody starts out assumed to be '0'.
371 If '0', send out EDNS0
372 If you FORMERR us, go to '3',
373 If no EDNS in response, go to '2'
374 If '1', send out EDNS0
375 If FORMERR, downgrade to 3
376 If '2', keep on including EDNS0, see what happens
378 If '3', send bare queries
381 SyncRes::EDNSStatus
* ednsstatus
;
382 ednsstatus
= &t_sstorage
->ednsstatus
[ip
]; // does this include port? YES
384 if(ednsstatus
->modeSetAt
&& ednsstatus
->modeSetAt
+ 3600 < d_now
.tv_sec
) {
385 *ednsstatus
=SyncRes::EDNSStatus();
386 // cerr<<"Resetting EDNS Status for "<<ip.toString()<<endl);
389 SyncRes::EDNSStatus::EDNSMode
& mode
=ednsstatus
->mode
;
390 SyncRes::EDNSStatus::EDNSMode oldmode
= mode
;
392 auto luaconfsLocal
= g_luaconfs
.getLocal();
395 ctx
.d_initialRequestId
= d_initialRequestId
;
399 for(int tries
= 0; tries
< 3; ++tries
) {
400 // cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl;
402 if(mode
==EDNSStatus::NOEDNS
) {
403 g_stats
.noEdnsOutQueries
++;
404 EDNSLevel
= 0; // level != mode
406 else if(ednsMANDATORY
|| mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
==EDNSStatus::EDNSIGNORANT
)
409 if (d_asyncResolve
) {
410 ret
= d_asyncResolve(ip
, domain
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, luaconfsLocal
->outgoingProtobufServer
, res
);
413 ret
=asyncresolve(ip
, domain
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, luaconfsLocal
->outgoingProtobufServer
, res
);
416 return ret
; // transport error, nothing to learn here
419 if(ret
== 0) { // timeout, not doing anything with it now
422 else if(mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
== EDNSStatus::EDNSIGNORANT
) {
423 if(res
->d_rcode
== RCode::FormErr
|| res
->d_rcode
== RCode::NotImp
) {
424 // cerr<<"Downgrading to NOEDNS because of "<<RCode::to_s(res->d_rcode)<<" for query to "<<ip.toString()<<" for '"<<domain<<"'"<<endl;
425 mode
= EDNSStatus::NOEDNS
;
428 else if(!res
->d_haveEDNS
) {
429 if(mode
!= EDNSStatus::EDNSIGNORANT
) {
430 mode
= EDNSStatus::EDNSIGNORANT
;
431 // cerr<<"We find that "<<ip.toString()<<" is an EDNS-ignorer for '"<<domain<<"', moving to mode 3"<<endl;
435 mode
= EDNSStatus::EDNSOK
;
436 // cerr<<"We find that "<<ip.toString()<<" is EDNS OK!"<<endl;
440 if(oldmode
!= mode
|| !ednsstatus
->modeSetAt
)
441 ednsstatus
->modeSetAt
=d_now
.tv_sec
;
442 // cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", new mode: "<<mode<<endl;
448 /*! This function will check the cache and go out to the internet if the answer is not in cache
450 * \param qname The name we need an answer for
452 * \param ret The vector of DNSRecords we need to fill with the answers
453 * \param depth The recursion depth we are in
455 * \return DNS RCODE or -1 (Error) or -2 (RPZ hit)
457 int SyncRes::doResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
)
462 prefix
.append(depth
, ' ');
465 LOG(prefix
<<qname
<<": Wants "<< (d_doDNSSEC
? "" : "NO ") << "DNSSEC processing in query for "<<qtype
.getName()<<endl
);
467 if(s_maxdepth
&& depth
> s_maxdepth
)
468 throw ImmediateServFailException("More than "+std::to_string(s_maxdepth
)+" (max-recursion-depth) levels of recursion needed while resolving "+qname
.toLogString());
472 // This is a difficult way of expressing "this is a normal query", i.e. not getRootNS.
473 if(!(d_nocache
&& qtype
.getCode()==QType::NS
&& qname
.isRoot())) {
474 if(d_cacheonly
) { // very limited OOB support
476 LOG(prefix
<<qname
<<": Recursion not requested for '"<<qname
<<"|"<<qtype
.getName()<<"', peeking at auth/forward zones"<<endl
);
477 DNSName
authname(qname
);
478 domainmap_t::const_iterator iter
=getBestAuthZone(&authname
);
479 if(iter
!= t_sstorage
->domainmap
->end()) {
480 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
481 if(servers
.empty()) {
483 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, ret
, depth
, res
);
487 const ComboAddress remoteIP
= servers
.front();
488 LOG(prefix
<<qname
<<": forwarding query to hardcoded nameserver '"<< remoteIP
.toStringWithPort()<<"' for zone '"<<authname
<<"'"<<endl
);
490 boost::optional
<Netmask
> nm
;
491 res
=asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(), false, false, &d_now
, nm
, &lwr
);
492 // filter out the good stuff from lwr.result()
494 for(const auto& rec
: lwr
.d_records
) {
495 if(rec
.d_place
== DNSResourceRecord::ANSWER
)
501 return RCode::ServFail
;
507 if(!d_skipCNAMECheck
&& doCNAMECacheCheck(qname
,qtype
,ret
,depth
,res
)) // will reroute us if needed
510 if(doCacheCheck(qname
,qtype
,ret
,depth
,res
)) // we done
517 LOG(prefix
<<qname
<<": No cache hit for '"<<qname
<<"|"<<qtype
.getName()<<"', trying to find an appropriate NS record"<<endl
);
519 DNSName
subdomain(qname
);
520 if(qtype
== QType::DS
) subdomain
.chopOff();
523 bool flawedNSSet
=false;
525 // the two retries allow getBestNSNamesFromCache&co to reprime the root
526 // hints, in case they ever go missing
527 for(int tries
=0;tries
<2 && nsset
.empty();++tries
) {
528 subdomain
=getBestNSNamesFromCache(subdomain
, qtype
, nsset
, &flawedNSSet
, depth
, beenthere
); // pass beenthere to both occasions
531 if(!(res
=doResolveAt(nsset
, subdomain
, flawedNSSet
, qname
, qtype
, ret
, depth
, beenthere
)))
534 LOG(prefix
<<qname
<<": failed (res="<<res
<<")"<<endl
);
540 return res
<0 ? RCode::ServFail
: res
;
544 // for testing purposes
545 static bool ipv6First(const ComboAddress
& a
, const ComboAddress
& b
)
547 return !(a
.sin4
.sin_family
< a
.sin4
.sin_family
);
551 /** This function explicitly goes out for A or AAAA addresses
553 vector
<ComboAddress
> SyncRes::getAddrs(const DNSName
&qname
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
)
555 typedef vector
<DNSRecord
> res_t
;
558 typedef vector
<ComboAddress
> ret_t
;
563 for(int j
=1; j
<2+s_doIPv6
; j
++)
578 if(!doResolve(qname
, type
, res
,depth
+1, beenthere
) && !res
.empty()) { // this consults cache, OR goes out
579 for(res_t::const_iterator i
=res
.begin(); i
!= res
.end(); ++i
) {
580 if(i
->d_type
== QType::A
|| i
->d_type
== QType::AAAA
) {
581 if(auto rec
= std::dynamic_pointer_cast
<ARecordContent
>(i
->d_content
))
582 ret
.push_back(rec
->getCA(53));
583 else if(auto aaaarec
= std::dynamic_pointer_cast
<AAAARecordContent
>(i
->d_content
))
584 ret
.push_back(aaaarec
->getCA(53));
590 if(j
==1 && s_doIPv6
) { // we got an A record, see if we have some AAAA lying around
591 vector
<DNSRecord
> cset
;
592 if(t_RC
->get(d_now
.tv_sec
, qname
, QType(QType::AAAA
), &cset
, d_requestor
) > 0) {
593 for(auto k
=cset
.cbegin();k
!=cset
.cend();++k
) {
594 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
595 if (auto drc
= std::dynamic_pointer_cast
<AAAARecordContent
>(k
->d_content
)) {
596 ComboAddress ca
=drc
->getCA(53);
608 random_shuffle(ret
.begin(), ret
.end(), dns_random
);
610 // move 'best' address for this nameserver name up front
611 nsspeeds_t::iterator best
= t_sstorage
->nsSpeeds
.find(qname
);
613 if(best
!= t_sstorage
->nsSpeeds
.end())
614 for(ret_t::iterator i
=ret
.begin(); i
!= ret
.end(); ++i
) {
615 if(*i
==best
->second
.d_best
) { // got the fastest one
618 *ret
.begin()=best
->second
.d_best
;
628 void SyncRes::getBestNSFromCache(const DNSName
&qname
, const QType
& qtype
, vector
<DNSRecord
>& bestns
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
)
631 DNSName
subdomain(qname
);
634 prefix
.append(depth
, ' ');
640 LOG(prefix
<<qname
<<": Checking if we have NS in cache for '"<<subdomain
<<"'"<<endl
);
641 vector
<DNSRecord
> ns
;
642 *flawedNSSet
= false;
643 if(t_RC
->get(d_now
.tv_sec
, subdomain
, QType(QType::NS
), &ns
, d_requestor
) > 0) {
644 for(auto k
=ns
.cbegin();k
!=ns
.cend(); ++k
) {
645 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
646 vector
<DNSRecord
> aset
;
648 const DNSRecord
& dr
=*k
;
649 auto nrr
= getRR
<NSRecordContent
>(dr
);
650 if(nrr
&& (!nrr
->getNS().isPartOf(subdomain
) || t_RC
->get(d_now
.tv_sec
, nrr
->getNS(), s_doIPv6
? QType(QType::ADDR
) : QType(QType::A
),
651 doLog() ? &aset
: 0, d_requestor
) > 5)) {
652 bestns
.push_back(dr
);
653 LOG(prefix
<<qname
<<": NS (with ip, or non-glue) in cache for '"<<subdomain
<<"' -> '"<<nrr
->getNS()<<"'"<<endl
);
654 LOG(prefix
<<qname
<<": within bailiwick: "<< nrr
->getNS().isPartOf(subdomain
));
656 LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset
.begin()->d_ttl
- d_now
.tv_sec
))<<endl
);
659 LOG(", not in cache / did not look at cache"<<endl
);
664 LOG(prefix
<<qname
<<": NS in cache for '"<<subdomain
<<"', but needs glue ("<<nrr
->getNS()<<") which we miss or is expired"<<endl
);
668 if(!bestns
.empty()) {
669 GetBestNSAnswer answer
;
671 answer
.qtype
=qtype
.getCode();
672 for(const auto& dr
: bestns
)
673 answer
.bestns
.insert(make_pair(dr
.d_name
, getRR
<NSRecordContent
>(dr
)->getNS()));
675 if(beenthere
.count(answer
)) {
677 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' but part of LOOP (already seen "<<answer
.qname
<<")! Trying less specific NS"<<endl
);
680 for( set
<GetBestNSAnswer
>::const_iterator j
=beenthere
.begin();j
!=beenthere
.end();++j
) {
681 bool neo
= !(*j
< answer
|| answer
<*j
);
682 LOG(prefix
<<qname
<<": beenthere"<<(neo
?"*":"")<<": "<<j
->qname
<<"|"<<DNSRecordContent::NumberToType(j
->qtype
)<<" ("<<(unsigned int)j
->bestns
.size()<<")"<<endl
);
687 beenthere
.insert(answer
);
688 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' (flawedNSSet="<<*flawedNSSet
<<")"<<endl
);
693 LOG(prefix
<<qname
<<": no valid/useful NS in cache for '"<<subdomain
<<"'"<<endl
);
695 if(subdomain
.isRoot() && !brokeloop
) {
696 // We lost the root NS records
698 LOG(prefix
<<qname
<<": reprimed the root"<<endl
);
699 getRootNS(d_now
, d_asyncResolve
);
701 }while(subdomain
.chopOff());
704 SyncRes::domainmap_t::const_iterator
SyncRes::getBestAuthZone(DNSName
* qname
) const
706 SyncRes::domainmap_t::const_iterator ret
;
708 ret
=t_sstorage
->domainmap
->find(*qname
);
709 if(ret
!=t_sstorage
->domainmap
->end())
711 }while(qname
->chopOff());
715 /** doesn't actually do the work, leaves that to getBestNSFromCache */
716 DNSName
SyncRes::getBestNSNamesFromCache(const DNSName
&qname
, const QType
& qtype
, NsSet
& nsset
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
)
718 DNSName
subdomain(qname
);
719 DNSName
authdomain(qname
);
721 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
722 if(iter
!=t_sstorage
->domainmap
->end()) {
723 if( iter
->second
.d_servers
.empty() )
724 // this gets picked up in doResolveAt, the empty DNSName, combined with the
725 // empty vector means 'we are auth for this zone'
726 nsset
.insert({DNSName(), {{}, false}});
728 // Again, picked up in doResolveAt. An empty DNSName, combined with a
729 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
730 nsset
.insert({DNSName(), {iter
->second
.d_servers
, iter
->second
.d_rdForward
}});
735 vector
<DNSRecord
> bestns
;
736 getBestNSFromCache(subdomain
, qtype
, bestns
, flawedNSSet
, depth
, beenthere
);
738 for(auto k
=bestns
.cbegin() ; k
!= bestns
.cend(); ++k
) {
739 // The actual resolver code will not even look at the ComboAddress or bool
740 nsset
.insert({std::dynamic_pointer_cast
<NSRecordContent
>(k
->d_content
)->getNS(), {{}, false}});
741 if(k
==bestns
.cbegin())
747 bool SyncRes::doCNAMECacheCheck(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>& ret
, unsigned int depth
, int &res
)
752 prefix
.append(depth
, ' ');
755 if((depth
>9 && d_outqueries
>10 && d_throttledqueries
>5) || depth
> 15) {
756 LOG(prefix
<<qname
<<": recursing (CNAME or other indirection) too deep, depth="<<depth
<<endl
);
761 LOG(prefix
<<qname
<<": Looking for CNAME cache hit of '"<<qname
<<"|CNAME"<<"'"<<endl
);
762 vector
<DNSRecord
> cset
;
763 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
764 if(t_RC
->get(d_now
.tv_sec
, qname
,QType(QType::CNAME
), &cset
, d_requestor
, &signatures
) > 0) {
766 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
767 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
768 LOG(prefix
<<qname
<<": Found cache CNAME hit for '"<< qname
<< "|CNAME" <<"' to '"<<j
->d_content
->getZoneRepresentation()<<"'"<<endl
);
770 dr
.d_ttl
-=d_now
.tv_sec
;
773 for(const auto& signature
: signatures
) {
775 sigdr
.d_type
=QType::RRSIG
;
777 sigdr
.d_ttl
=j
->d_ttl
- d_now
.tv_sec
;
778 sigdr
.d_content
=signature
;
779 sigdr
.d_place
=DNSResourceRecord::ANSWER
;
781 ret
.push_back(sigdr
);
784 if(qtype
!= QType::CNAME
) { // perhaps they really wanted a CNAME!
785 set
<GetBestNSAnswer
>beenthere
;
786 res
=doResolve(std::dynamic_pointer_cast
<CNAMERecordContent
>(j
->d_content
)->getTarget(), qtype
, ret
, depth
+1, beenthere
);
794 LOG(prefix
<<qname
<<": No CNAME cache hit of '"<< qname
<< "|CNAME" <<"' found"<<endl
);
799 * Convience function to push the records from records into ret with a new TTL
801 * \param records DNSRecords that need to go into ret
802 * \param ttl The new TTL for these records
803 * \param ret The vector of DNSRecords that should contian the records with the modified TTL
805 static void addTTLModifiedRecords(const vector
<DNSRecord
>& records
, const uint32_t ttl
, vector
<DNSRecord
>& ret
) {
806 for (const auto& rec
: records
) {
814 bool SyncRes::doCacheCheck(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int &res
)
816 bool giveNegative
=false;
821 prefix
.append(depth
, ' ');
824 // 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)
825 DNSName
sqname(qname
);
828 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
830 DNSName
authname(qname
);
831 bool wasForwardedOrAuth
= false;
832 bool wasAuth
= false;
833 domainmap_t::const_iterator iter
=getBestAuthZone(&authname
);
834 if(iter
!= t_sstorage
->domainmap
->end()) {
835 wasForwardedOrAuth
= true;
836 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
837 if(servers
.empty()) {
841 NegCache::NegCacheEntry ne
;
844 t_sstorage
->negcache
.getRootNXTrust(qname
, d_now
, ne
) &&
845 ne
.d_auth
.isRoot() &&
846 !(wasForwardedOrAuth
&& !authname
.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
847 sttl
= ne
.d_ttd
- d_now
.tv_sec
;
848 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
.d_auth
<<"' & '"<<ne
.d_name
<<"' for another "<<sttl
<<" seconds"<<endl
);
849 res
= RCode::NXDomain
;
852 else if (t_sstorage
->negcache
.get(qname
, qtype
, d_now
, ne
) &&
853 !(wasForwardedOrAuth
&& ne
.d_auth
!= authname
)) { // Only the authname nameserver can neg cache entries
855 sttl
= ne
.d_ttd
- d_now
.tv_sec
;
857 if(ne
.d_qtype
.getCode()) {
858 LOG(prefix
<<qname
<<": "<<qtype
.getName()<<" is negatively cached via '"<<ne
.d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
859 res
= RCode::NoError
;
862 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
.d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
863 res
= RCode::NXDomain
;
866 addTTLModifiedRecords(ne
.DNSSECRecords
.records
, sttl
, ret
);
867 addTTLModifiedRecords(ne
.DNSSECRecords
.signatures
, sttl
, ret
);
872 // Transplant SOA to the returned packet
873 addTTLModifiedRecords(ne
.authoritySOA
.records
, sttl
, ret
);
875 addTTLModifiedRecords(ne
.authoritySOA
.signatures
, sttl
, ret
);
879 vector
<DNSRecord
> cset
;
880 bool found
=false, expired
=false;
881 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
883 if(t_RC
->get(d_now
.tv_sec
, sqname
, sqt
, &cset
, d_requestor
, d_doDNSSEC
? &signatures
: 0) > 0) {
884 LOG(prefix
<<sqname
<<": Found cache hit for "<<sqt
.getName()<<": ");
885 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
886 LOG(j
->d_content
->getZoneRepresentation());
887 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
889 ttl
= (dr
.d_ttl
-=d_now
.tv_sec
);
891 LOG("[ttl="<<dr
.d_ttl
<<"] ");
900 for(const auto& signature
: signatures
) {
902 dr
.d_type
=QType::RRSIG
;
905 dr
.d_content
=signature
;
906 dr
.d_place
= DNSResourceRecord::ANSWER
;
912 if(found
&& !expired
) {
915 d_wasOutOfBand
= wasAuth
;
919 LOG(prefix
<<qname
<<": cache had only stale entries"<<endl
);
925 bool SyncRes::moreSpecificThan(const DNSName
& a
, const DNSName
&b
) const
927 return (a
.isPartOf(b
) && a
.countLabels() > b
.countLabels());
932 speedOrder(map
<DNSName
,double> &speeds
) : d_speeds(speeds
) {}
933 bool operator()(const DNSName
&a
, const DNSName
&b
) const
935 return d_speeds
[a
] < d_speeds
[b
];
937 map
<DNSName
, double>& d_speeds
;
940 inline vector
<DNSName
> SyncRes::shuffleInSpeedOrder(NsSet
&tnameservers
, const string
&prefix
)
942 vector
<DNSName
> rnameservers
;
943 rnameservers
.reserve(tnameservers
.size());
944 for(const auto& tns
:tnameservers
) {
945 rnameservers
.push_back(tns
.first
);
947 map
<DNSName
, double> speeds
;
949 for(const auto& val
: rnameservers
) {
951 speed
=t_sstorage
->nsSpeeds
[val
].get(&d_now
);
954 random_shuffle(rnameservers
.begin(),rnameservers
.end(), dns_random
);
955 speedOrder
so(speeds
);
956 stable_sort(rnameservers
.begin(),rnameservers
.end(), so
);
959 LOG(prefix
<<"Nameservers: ");
960 for(vector
<DNSName
>::const_iterator i
=rnameservers
.begin();i
!=rnameservers
.end();++i
) {
961 if(i
!=rnameservers
.begin()) {
963 if(!((i
-rnameservers
.begin())%3)) {
964 LOG(endl
<<prefix
<<" ");
967 LOG((i
->empty() ? string("<empty>") : i
->toString())<<"(" << (boost::format("%0.2f") % (speeds
[*i
]/1000.0)).str() <<"ms)");
974 static bool magicAddrMatch(const QType
& query
, const QType
& answer
)
976 if(query
.getCode() != QType::ADDR
)
978 return answer
.getCode() == QType::A
|| answer
.getCode() == QType::AAAA
;
981 /* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
983 * \param records The records to parse for the authority SOA and NSEC(3) records
984 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
986 static void harvestNXRecords(const vector
<DNSRecord
>& records
, NegCache::NegCacheEntry
& ne
) {
987 static const set
<uint16_t> nsecTypes
= {QType::NSEC
, QType::NSEC3
};
988 for(const auto& rec
: records
) {
989 if(rec
.d_place
!= DNSResourceRecord::AUTHORITY
)
990 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
991 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
992 // records MUST be in the same section as the records they cover.
993 // Hence, we ignore all records outside of the AUTHORITY section.
996 if(rec
.d_type
== QType::RRSIG
) {
997 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
999 if(rrsig
->d_type
== QType::SOA
) {
1000 ne
.authoritySOA
.signatures
.push_back(rec
);
1002 if(nsecTypes
.count(rrsig
->d_type
)) {
1003 ne
.DNSSECRecords
.signatures
.push_back(rec
);
1008 if(rec
.d_type
== QType::SOA
) {
1009 ne
.authoritySOA
.records
.push_back(rec
);
1012 if(nsecTypes
.count(rec
.d_type
)) {
1013 ne
.DNSSECRecords
.records
.push_back(rec
);
1019 // TODO remove after processRecords is fixed!
1020 // Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
1021 static void addNXNSECS(vector
<DNSRecord
>&ret
, const vector
<DNSRecord
>& records
)
1023 NegCache::NegCacheEntry ne
;
1024 harvestNXRecords(records
, ne
);
1025 ret
.insert(ret
.end(), ne
.authoritySOA
.signatures
.begin(), ne
.authoritySOA
.signatures
.end());
1026 ret
.insert(ret
.end(), ne
.DNSSECRecords
.records
.begin(), ne
.DNSSECRecords
.records
.end());
1027 ret
.insert(ret
.end(), ne
.DNSSECRecords
.signatures
.begin(), ne
.DNSSECRecords
.signatures
.end());
1030 bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine
& dfe
, const NsSet
& nameservers
)
1033 for (auto const &ns
: nameservers
) {
1034 d_appliedPolicy
= dfe
.getProcessingPolicy(ns
.first
, d_discardedPolicies
);
1035 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1036 LOG(", however nameserver "<<ns
.first
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1040 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1041 for (auto const &address
: ns
.second
.first
) {
1042 d_appliedPolicy
= dfe
.getProcessingPolicy(address
, d_discardedPolicies
);
1043 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1044 LOG(", however nameserver "<<ns
.first
<<" IP address "<<address
.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1053 bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine
& dfe
, const ComboAddress
& remoteIP
)
1056 d_appliedPolicy
= dfe
.getProcessingPolicy(remoteIP
, d_discardedPolicies
);
1057 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) {
1058 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")+"')");
1065 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
)
1067 vector
<ComboAddress
> result
;
1070 LOG(prefix
<<qname
<<": Trying to resolve NS '"<<*tns
<< "' ("<<1+tns
-rnameservers
.begin()<<"/"<<(unsigned int)rnameservers
.size()<<")"<<endl
);
1071 result
= getAddrs(*tns
, depth
+2, beenthere
);
1072 pierceDontQuery
=false;
1075 LOG(prefix
<<qname
<<": Domain has hardcoded nameserver");
1077 result
= nameservers
[*tns
].first
;
1078 if(result
.size() > 1) {
1083 sendRDQuery
= nameservers
[*tns
].second
;
1084 pierceDontQuery
=true;
1089 bool SyncRes::throttledOrBlocked(const std::string
& prefix
, const ComboAddress
& remoteIP
, const DNSName
& qname
, const QType
& qtype
, bool pierceDontQuery
)
1091 extern NetmaskGroup
* g_dontQuery
;
1093 if(t_sstorage
->throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0))) {
1094 LOG(prefix
<<qname
<<": server throttled "<<endl
);
1095 s_throttledqueries
++; d_throttledqueries
++;
1098 else if(t_sstorage
->throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()))) {
1099 LOG(prefix
<<qname
<<": query throttled "<<endl
);
1100 s_throttledqueries
++; d_throttledqueries
++;
1103 else if(!pierceDontQuery
&& g_dontQuery
&& g_dontQuery
->match(&remoteIP
)) {
1104 LOG(prefix
<<qname
<<": not sending query to " << remoteIP
.toString() << ", blocked by 'dont-query' setting" << endl
);
1111 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
)
1115 vector
<DNSRecord
> records
;
1116 vector
<shared_ptr
<RRSIGRecordContent
>> signatures
;
1122 DNSResourceRecord::Place place
;
1123 bool operator<(const CacheKey
& rhs
) const {
1124 return tie(name
, type
) < tie(rhs
.name
, rhs
.type
);
1127 typedef map
<CacheKey
, CachePair
> tcache_t
;
1130 for(const auto& rec
: lwr
.d_records
) {
1131 if(rec
.d_type
== QType::RRSIG
) {
1132 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1134 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
1135 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
1140 // reap all answers from this packet that are acceptable
1141 for(auto& rec
: lwr
.d_records
) {
1142 if(rec
.d_type
== QType::OPT
) {
1143 LOG(prefix
<<qname
<<": OPT answer '"<<rec
.d_name
<<"' from '"<<auth
<<"' nameservers" <<endl
);
1146 LOG(prefix
<<qname
<<": accept answer '"<<rec
.d_name
<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"|"<<rec
.d_content
->getZoneRepresentation()<<"' from '"<<auth
<<"' nameservers? "<<(int)rec
.d_place
<<" ");
1147 if(rec
.d_type
== QType::ANY
) {
1148 LOG("NO! - we don't accept 'ANY' data"<<endl
);
1152 if(rec
.d_name
.isPartOf(auth
)) {
1153 if(rec
.d_type
== QType::RRSIG
) {
1154 LOG("RRSIG - separate"<<endl
);
1156 else if(lwr
.d_aabit
&& lwr
.d_rcode
==RCode::NoError
&& rec
.d_place
==DNSResourceRecord::ANSWER
&& (rec
.d_type
!= QType::DNSKEY
|| rec
.d_name
!= auth
) && g_delegationOnly
.count(auth
)) {
1157 LOG("NO! Is from delegation-only zone"<<endl
);
1159 return RCode::NXDomain
;
1162 bool haveLogged
= false;
1163 if (!t_sstorage
->domainmap
->empty()) {
1164 // Check if we are authoritative for a zone in this answer
1165 DNSName
tmp_qname(rec
.d_name
);
1166 auto auth_domain_iter
=getBestAuthZone(&tmp_qname
);
1167 if(auth_domain_iter
!=t_sstorage
->domainmap
->end() &&
1168 auth
.countLabels() <= auth_domain_iter
->first
.countLabels()) {
1169 if (auth_domain_iter
->first
!= auth
) {
1170 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter
->first
<<endl
);
1173 LOG("YES! - This answer was ");
1174 if (nameservers
[tns
].first
.empty()) {
1175 LOG("retrieved from the local auth store.");
1177 LOG("received from a server we forward to.");
1188 rec
.d_ttl
=min(s_maxcachettl
, rec
.d_ttl
);
1191 dr
.d_place
=DNSResourceRecord::ANSWER
;
1193 dr
.d_ttl
+= d_now
.tv_sec
;
1194 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(dr
);
1202 for(tcache_t::iterator i
=tcache
.begin();i
!=tcache
.end();++i
) {
1203 if(i
->second
.records
.size() > 1) { // need to group the ttl to be the minimum of the RRSET (RFC 2181, 5.2)
1204 uint32_t lowestTTL
=std::numeric_limits
<uint32_t>::max();
1205 for(const auto& record
: i
->second
.records
)
1206 lowestTTL
=min(lowestTTL
, record
.d_ttl
);
1208 for(auto& record
: i
->second
.records
)
1209 *const_cast<uint32_t*>(&record
.d_ttl
)=lowestTTL
; // boom
1212 // cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
1213 // cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
1214 if(i
->second
.records
.empty()) // this happens when we did store signatures, but passed on the records themselves
1216 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
>());
1217 if(i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
)
1221 return RCode::NoError
;
1224 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
)
1228 for(auto& rec
: lwr
.d_records
) {
1229 if (rec
.d_type
!=QType::OPT
&& rec
.d_class
!=QClass::IN
)
1232 if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
1233 lwr
.d_rcode
==RCode::NXDomain
&& qname
.isPartOf(rec
.d_name
) && rec
.d_name
.isPartOf(auth
)) {
1234 LOG(prefix
<<qname
<<": got negative caching indication for name '"<<qname
<<"' (accept="<<rec
.d_name
.isPartOf(auth
)<<"), newtarget='"<<newtarget
<<"'"<<endl
);
1236 rec
.d_ttl
= min(rec
.d_ttl
, s_maxnegttl
);
1237 if(newtarget
.empty()) // only add a SOA if we're not going anywhere after this
1239 if(!wasVariable()) {
1240 NegCache::NegCacheEntry ne
;
1242 ne
.d_ttd
= d_now
.tv_sec
+ rec
.d_ttl
;
1244 ne
.d_qtype
= QType(0); // this encodes 'whole record'
1245 ne
.d_auth
= rec
.d_name
;
1246 harvestNXRecords(lwr
.d_records
, ne
);
1247 t_sstorage
->negcache
.add(ne
);
1248 if(s_rootNXTrust
&& ne
.d_auth
.isRoot() && auth
.isRoot()) {
1249 ne
.d_name
= ne
.d_name
.getLastLabel();
1250 t_sstorage
->negcache
.add(ne
);
1256 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&& rec
.d_type
==QType::CNAME
&& (!(qtype
==QType(QType::CNAME
)))) {
1258 if (auto content
= getRR
<CNAMERecordContent
>(rec
)) {
1259 newtarget
=content
->getTarget();
1262 else if((rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::ANSWER
){
1263 if(rec
.d_type
!= QType::RRSIG
|| rec
.d_name
== qname
)
1264 ret
.push_back(rec
); // enjoy your DNSSEC
1266 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
1267 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&&
1269 rec
.d_type
==qtype
.getCode() || (lwr
.d_aabit
&& (qtype
==QType(QType::ANY
) || magicAddrMatch(qtype
, QType(rec
.d_type
)) ) ) || sendRDQuery
1273 LOG(prefix
<<qname
<<": answer is in: resolved to '"<< rec
.d_content
->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"'"<<endl
);
1278 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& qname
.isPartOf(rec
.d_name
) && rec
.d_type
==QType::NS
) {
1279 if(moreSpecificThan(rec
.d_name
,auth
)) {
1281 LOG(prefix
<<qname
<<": got NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
1285 LOG(prefix
<<qname
<<": got upwards/level NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"', had '"<<auth
<<"'"<<endl
);
1287 if (auto content
= getRR
<NSRecordContent
>(rec
)) {
1288 nsset
.insert(content
->getNS());
1291 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& qname
.isPartOf(rec
.d_name
) && rec
.d_type
==QType::DS
) {
1292 LOG(prefix
<<qname
<<": got DS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
1295 else if(!done
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& qname
.isPartOf(rec
.d_name
) && rec
.d_type
==QType::SOA
&&
1296 lwr
.d_rcode
==RCode::NoError
) {
1297 LOG(prefix
<<qname
<<": got negative caching indication for '"<< qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
1299 if(!newtarget
.empty()) {
1300 LOG(prefix
<<qname
<<": Hang on! Got a redirect to '"<<newtarget
<<"' already"<<endl
);
1303 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
1305 if(!wasVariable()) {
1306 NegCache::NegCacheEntry ne
;
1307 ne
.d_auth
= rec
.d_name
;
1308 ne
.d_ttd
= d_now
.tv_sec
+ rec
.d_ttl
;
1311 harvestNXRecords(lwr
.d_records
, ne
);
1312 if(qtype
.getCode()) { // prevents us from blacking out a whole domain
1313 t_sstorage
->negcache
.add(ne
);
1325 * -1 in case of no results
1326 * -2 when a FilterEngine Policy was hit
1329 int SyncRes::doResolveAt(NsSet
&nameservers
, DNSName auth
, bool flawedNSSet
, const DNSName
&qname
, const QType
&qtype
,
1330 vector
<DNSRecord
>&ret
,
1331 unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
)
1333 auto luaconfsLocal
= g_luaconfs
.getLocal();
1337 prefix
.append(depth
, ' ');
1340 LOG(prefix
<<qname
<<": Cache consultations done, have "<<(unsigned int)nameservers
.size()<<" NS to contact");
1342 if (nameserversBlockedByRPZ(luaconfsLocal
->dfe
, nameservers
)) {
1348 for(;;) { // we may get more specific nameservers
1349 vector
<DNSName
> rnameservers
= shuffleInSpeedOrder(nameservers
, doLog() ? (prefix
+qname
.toString()+": ") : string() );
1351 for(auto tns
=rnameservers
.cbegin();;++tns
) {
1352 if(tns
==rnameservers
.cend()) {
1353 LOG(prefix
<<qname
<<": Failed to resolve via any of the "<<(unsigned int)rnameservers
.size()<<" offered NS at level '"<<auth
<<"'"<<endl
);
1354 if(!auth
.isRoot() && flawedNSSet
) {
1355 LOG(prefix
<<qname
<<": Ageing nameservers for level '"<<auth
<<"', next query might succeed"<<endl
);
1357 if(t_RC
->doAgeCache(d_now
.tv_sec
, auth
, QType::NS
, 10))
1358 g_stats
.nsSetInvalidations
++;
1362 // this line needs to identify the 'self-resolving' behaviour, but we get it wrong now
1363 if(qname
== *tns
&& qtype
.getCode()==QType::A
&& rnameservers
.size() > (size_t)(1+1*s_doIPv6
)) {
1364 LOG(prefix
<<qname
<<": Not using NS to resolve itself! ("<<(1+tns
-rnameservers
.cbegin())<<"/"<<rnameservers
.size()<<")"<<endl
);
1368 typedef vector
<ComboAddress
> remoteIPs_t
;
1369 remoteIPs_t remoteIPs
;
1370 remoteIPs_t::const_iterator remoteIP
;
1372 bool pierceDontQuery
=false;
1373 bool sendRDQuery
=false;
1374 boost::optional
<Netmask
> ednsmask
;
1376 if(tns
->empty() && nameservers
[*tns
].first
.empty() ) {
1377 LOG(prefix
<<qname
<<": Domain is out-of-band"<<endl
);
1378 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, lwr
.d_records
, depth
, lwr
.d_rcode
);
1383 remoteIPs
= retrieveAddressesForNS(prefix
, qname
, tns
, depth
, beenthere
, rnameservers
, nameservers
, sendRDQuery
, pierceDontQuery
, flawedNSSet
);
1385 if(remoteIPs
.empty()) {
1386 LOG(prefix
<<qname
<<": Failed to get IP for NS "<<*tns
<<", trying next if available"<<endl
);
1391 bool hitPolicy
{false};
1392 LOG(prefix
<<qname
<<": Resolved '"<<auth
<<"' NS "<<*tns
<<" to: ");
1393 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
1394 if(remoteIP
!= remoteIPs
.cbegin()) {
1397 LOG(remoteIP
->toString());
1398 if(nameserverIPBlockedByRPZ(luaconfsLocal
->dfe
, *remoteIP
)) {
1403 if (hitPolicy
) //implies d_wantsRPZ
1407 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
1408 LOG(prefix
<<qname
<<": Trying IP "<< remoteIP
->toStringWithPort() <<", asking '"<<qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
1409 if (throttledOrBlocked(prefix
, *remoteIP
, qname
, qtype
, pierceDontQuery
)) {
1414 s_outqueries
++; d_outqueries
++;
1415 if(d_outqueries
+ d_throttledqueries
> s_maxqperq
) throw ImmediateServFailException("more than "+std::to_string(s_maxqperq
)+" (max-qperq) queries sent while resolving "+qname
.toLogString());
1418 LOG(prefix
<<qname
<<": using TCP with "<< remoteIP
->toStringWithPort() <<endl
);
1419 s_tcpoutqueries
++; d_tcpoutqueries
++;
1422 if(s_maxtotusec
&& d_totUsec
> s_maxtotusec
)
1423 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");
1425 if(d_pdl
&& d_pdl
->preoutquery(*remoteIP
, d_requestor
, qname
, qtype
, doTCP
, lwr
.d_records
, resolveret
)) {
1426 LOG(prefix
<<qname
<<": query handled by Lua"<<endl
);
1429 ednsmask
=getEDNSSubnetMask(d_requestor
, qname
, *remoteIP
);
1431 LOG(prefix
<<qname
<<": Adding EDNS Client Subnet Mask "<<ednsmask
->toString()<<" to query"<<endl
);
1433 resolveret
=asyncresolveWrapper(*remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(),
1434 doTCP
, sendRDQuery
, &d_now
, ednsmask
, &lwr
); // <- we go out on the wire!
1436 LOG(prefix
<<qname
<<": Received EDNS Client Subnet Mask "<<ednsmask
->toString()<<" on response"<<endl
);
1442 throw ImmediateServFailException("Query killed by policy");
1444 d_totUsec
+= lwr
.d_usec
;
1445 accountAuthLatency(lwr
.d_usec
, remoteIP
->sin4
.sin_family
);
1446 if(resolveret
!= 1) {
1448 LOG(prefix
<<qname
<<": timeout resolving after "<<lwr
.d_usec
/1000.0<<"msec "<< (doTCP
? "over TCP" : "")<<endl
);
1450 s_outgoingtimeouts
++;
1451 if(remoteIP
->sin4
.sin_family
== AF_INET
)
1452 s_outgoing4timeouts
++;
1454 s_outgoing6timeouts
++;
1456 else if(resolveret
==-2) {
1457 LOG(prefix
<<qname
<<": hit a local resource limit resolving"<< (doTCP
? " over TCP" : "")<<", probable error: "<<stringerror()<<endl
);
1458 g_stats
.resourceLimits
++;
1461 s_unreachables
++; d_unreachables
++;
1462 LOG(prefix
<<qname
<<": error resolving from "<<remoteIP
->toString()<< (doTCP
? " over TCP" : "") <<", possible error: "<<strerror(errno
)<< endl
);
1465 if(resolveret
!=-2) { // don't account for resource limits, they are our own fault
1466 t_sstorage
->nsSpeeds
[*tns
].submit(*remoteIP
, 1000000, &d_now
); // 1 sec
1468 // code below makes sure we don't filter COM or the root
1469 if (s_serverdownmaxfails
> 0 && (auth
!= g_rootdnsname
) && t_sstorage
->fails
.incr(*remoteIP
) >= s_serverdownmaxfails
) {
1470 LOG(prefix
<<qname
<<": Max fails reached resolving on "<< remoteIP
->toString() <<". Going full throttle for "<< s_serverdownthrottletime
<<" seconds" <<endl
);
1471 t_sstorage
->throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, "", 0), s_serverdownthrottletime
, 10000); // mark server as down
1472 } else if(resolveret
==-1)
1473 t_sstorage
->throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100); // unreachable, 1 minute or 100 queries
1475 t_sstorage
->throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 10, 5); // timeout
1480 // 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));
1482 if(lwr
.d_rcode
==RCode::ServFail
|| lwr
.d_rcode
==RCode::Refused
) {
1483 LOG(prefix
<<qname
<<": "<<*tns
<<" ("<<remoteIP
->toString()<<") returned a "<< (lwr
.d_rcode
==RCode::ServFail
? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl
);
1484 t_sstorage
->throttle
.throttle(d_now
.tv_sec
,boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()),60,3); // servfail or refused
1488 if(s_serverdownmaxfails
> 0)
1489 t_sstorage
->fails
.clear(*remoteIP
);
1491 break; // this IP address worked!
1492 wasLame
:; // well, it didn't
1493 LOG(prefix
<<qname
<<": status=NS "<<*tns
<<" ("<< remoteIP
->toString() <<") is lame for '"<<auth
<<"', trying sibling IP or NS"<<endl
);
1494 t_sstorage
->throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100); // lame
1498 if(remoteIP
== remoteIPs
.cend()) // we tried all IP addresses, none worked
1504 LOG(prefix
<<qname
<<": truncated bit set, retrying via TCP"<<endl
);
1507 LOG(prefix
<<qname
<<": truncated bit set, over TCP?"<<endl
);
1508 return RCode::ServFail
;
1510 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
);
1512 /* // for you IPv6 fanatics :-)
1513 if(remoteIP->sin4.sin_family==AF_INET6)
1516 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
1518 t_sstorage
->nsSpeeds
[*tns
].submit(*remoteIP
, lwr
.d_usec
, &d_now
);
1522 for(auto& rec
: lwr
.d_records
) {
1523 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumTTL
);
1527 RCode::rcodes_ rcode
= updateCacheFromRecords(prefix
, lwr
, qname
, auth
, nameservers
, *tns
, ednsmask
);
1528 if (rcode
!= RCode::NoError
) {
1532 LOG(prefix
<<qname
<<": determining status after receiving this packet"<<endl
);
1535 bool realreferral
=false, negindic
=false, sawDS
=false;
1539 bool done
= processRecords(prefix
, qname
, qtype
, auth
, lwr
, sendRDQuery
, ret
, nsset
, newtarget
, newauth
, realreferral
, negindic
, sawDS
);
1542 LOG(prefix
<<qname
<<": status=got results, this level of recursion done"<<endl
);
1545 if(!newtarget
.empty()) {
1546 if(newtarget
== qname
) {
1547 LOG(prefix
<<qname
<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl
);
1548 return RCode::ServFail
;
1551 LOG(prefix
<<qname
<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl
);
1552 return RCode::ServFail
;
1554 LOG(prefix
<<qname
<<": status=got a CNAME referral, starting over with "<<newtarget
<<endl
);
1556 set
<GetBestNSAnswer
> beenthere2
;
1557 return doResolve(newtarget
, qtype
, ret
, depth
+ 1, beenthere2
);
1559 if(lwr
.d_rcode
==RCode::NXDomain
) {
1560 LOG(prefix
<<qname
<<": status=NXDOMAIN, we are done "<<(negindic
? "(have negative SOA)" : "")<<endl
);
1563 addNXNSECS(ret
, lwr
.d_records
);
1565 return RCode::NXDomain
;
1567 if(nsset
.empty() && !lwr
.d_rcode
&& (negindic
|| lwr
.d_aabit
|| sendRDQuery
)) {
1568 LOG(prefix
<<qname
<<": status=noerror, other types may exist, but we are done "<<(negindic
? "(have negative SOA) " : "")<<(lwr
.d_aabit
? "(have aa bit) " : "")<<endl
);
1571 addNXNSECS(ret
, lwr
.d_records
);
1574 else if(realreferral
) {
1575 LOG(prefix
<<qname
<<": status=did not resolve, got "<<(unsigned int)nsset
.size()<<" NS, ");
1577 t_sstorage
->dnssecmap
[newauth
]=true;
1578 /* for(const auto& e : t_sstorage->dnssecmap)
1584 nameservers
.clear();
1585 for (auto const &nameserver
: nsset
) {
1587 d_appliedPolicy
= luaconfsLocal
->dfe
.getProcessingPolicy(nameserver
, d_discardedPolicies
);
1588 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1589 LOG("however "<<nameserver
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1593 nameservers
.insert({nameserver
, {{}, false}});
1595 LOG("looping to them"<<endl
);
1598 else if(!tns
->empty()) { // means: not OOB, OOB == empty
1606 boost::optional
<Netmask
> SyncRes::getEDNSSubnetMask(const ComboAddress
& local
, const DNSName
&dn
, const ComboAddress
& rem
)
1608 boost::optional
<Netmask
> result
;
1611 if(d_incomingECSFound
) {
1612 if (d_incomingECS
->source
.getBits() == 0) {
1613 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0 */
1616 trunc
= d_incomingECS
->source
.getMaskedNetwork();
1617 bits
= d_incomingECS
->source
.getBits();
1619 else if(!local
.isIPv4() || local
.sin4
.sin_addr
.s_addr
) { // detect unset 'requestor'
1621 bits
= local
.isIPv4() ? 32 : 128;
1624 /* nothing usable */
1628 if(g_ednsdomains
.check(dn
) || g_ednssubnets
.match(rem
)) {
1629 bits
= std::min(bits
, (trunc
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
1630 trunc
.truncate(bits
);
1631 return boost::optional
<Netmask
>(Netmask(trunc
, bits
));
1637 // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
1638 int directResolve(const DNSName
& qname
, const QType
& qtype
, int qclass
, vector
<DNSRecord
>& ret
)
1641 gettimeofday(&now
, 0);
1644 int res
= sr
.beginResolve(qname
, QType(qtype
), qclass
, ret
);
1649 #include "validate-recursor.hh"
1651 int SyncRes::getRootNS(struct timeval now
, asyncresolve_t asyncCallback
) {
1653 sr
.setDoEDNS0(true);
1655 sr
.setDoDNSSEC(g_dnssecmode
!= DNSSECMode::Off
);
1656 sr
.setAsyncCallback(asyncCallback
);
1658 vector
<DNSRecord
> ret
;
1661 res
=sr
.beginResolve(g_rootdnsname
, QType(QType::NS
), 1, ret
);
1662 if (g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
) {
1664 auto state
= validateRecords(ctx
, ret
);
1666 throw PDNSException("Got Bogus validation result for .|NS");
1670 catch(PDNSException
& e
)
1672 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
1675 catch(std::exception
& e
)
1677 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.what()<<endl
;
1682 L
<<Logger::Error
<<"Failed to update . records, got an exception"<<endl
;
1685 L
<<Logger::Notice
<<"Refreshed . records"<<endl
;
1688 L
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;