2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "arguments.hh"
27 #include "cachecleaner.hh"
28 #include "dns_random.hh"
29 #include "dnsparser.hh"
30 #include "dnsrecords.hh"
31 #include "ednssubnet.hh"
33 #include "lua-recursor4.hh"
34 #include "rec-lua-conf.hh"
37 thread_local
SyncRes::ThreadLocalStorage
SyncRes::t_sstorage
;
39 std::unordered_set
<DNSName
> SyncRes::s_delegationOnly
;
40 std::unique_ptr
<NetmaskGroup
> SyncRes::s_dontQuery
{nullptr};
41 NetmaskGroup
SyncRes::s_ednssubnets
;
42 SuffixMatchNode
SyncRes::s_ednsdomains
;
43 string
SyncRes::s_serverID
;
44 SyncRes::LogMode
SyncRes::s_lm
;
46 unsigned int SyncRes::s_maxnegttl
;
47 unsigned int SyncRes::s_maxcachettl
;
48 unsigned int SyncRes::s_maxqperq
;
49 unsigned int SyncRes::s_maxtotusec
;
50 unsigned int SyncRes::s_maxdepth
;
51 unsigned int SyncRes::s_minimumTTL
;
52 unsigned int SyncRes::s_packetcachettl
;
53 unsigned int SyncRes::s_packetcacheservfailttl
;
54 unsigned int SyncRes::s_serverdownmaxfails
;
55 unsigned int SyncRes::s_serverdownthrottletime
;
56 std::atomic
<uint64_t> SyncRes::s_queries
;
57 std::atomic
<uint64_t> SyncRes::s_outgoingtimeouts
;
58 std::atomic
<uint64_t> SyncRes::s_outgoing4timeouts
;
59 std::atomic
<uint64_t> SyncRes::s_outgoing6timeouts
;
60 std::atomic
<uint64_t> SyncRes::s_outqueries
;
61 std::atomic
<uint64_t> SyncRes::s_tcpoutqueries
;
62 std::atomic
<uint64_t> SyncRes::s_throttledqueries
;
63 std::atomic
<uint64_t> SyncRes::s_dontqueries
;
64 std::atomic
<uint64_t> SyncRes::s_nodelegated
;
65 std::atomic
<uint64_t> SyncRes::s_unreachables
;
66 uint8_t SyncRes::s_ecsipv4limit
;
67 uint8_t SyncRes::s_ecsipv6limit
;
68 bool SyncRes::s_doIPv6
;
69 bool SyncRes::s_nopacketcache
;
70 bool SyncRes::s_rootNXTrust
;
71 bool SyncRes::s_noEDNS
;
73 #define LOG(x) if(d_lm == Log) { L <<Logger::Warning << x; } else if(d_lm == Store) { d_trace << x; }
75 static void accountAuthLatency(int usec
, int family
)
77 if(family
== AF_INET
) {
79 g_stats
.auth4Answers0_1
++;
81 g_stats
.auth4Answers1_10
++;
82 else if(usec
< 100000)
83 g_stats
.auth4Answers10_100
++;
84 else if(usec
< 1000000)
85 g_stats
.auth4Answers100_1000
++;
87 g_stats
.auth4AnswersSlow
++;
90 g_stats
.auth6Answers0_1
++;
92 g_stats
.auth6Answers1_10
++;
93 else if(usec
< 100000)
94 g_stats
.auth6Answers10_100
++;
95 else if(usec
< 1000000)
96 g_stats
.auth6Answers100_1000
++;
98 g_stats
.auth6AnswersSlow
++;
104 SyncRes::SyncRes(const struct timeval
& now
) : d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
105 d_totUsec(0), d_now(now
),
106 d_cacheonly(false), d_doDNSSEC(false), d_doEDNS0(false), d_lm(s_lm
)
111 /** everything begins here - this is the entry point just after receiving a packet */
112 int SyncRes::beginResolve(const DNSName
&qname
, const QType
&qtype
, uint16_t qclass
, vector
<DNSRecord
>&ret
)
116 d_wasOutOfBand
=false;
118 if (doSpecialNamesResolve(qname
, qtype
, qclass
, ret
))
121 if( (qtype
.getCode() == QType::AXFR
) || (qtype
.getCode() == QType::IXFR
))
124 if(qclass
==QClass::ANY
)
126 else if(qclass
!=QClass::IN
)
129 set
<GetBestNSAnswer
> beenthere
;
130 int res
=doResolve(qname
, qtype
, ret
, 0, beenthere
);
134 /*! Handles all special, built-in names
135 * Fills ret with an answer and returns true if it handled the query.
137 * Handles the following queries (and their ANY variants):
140 * - localhost. IN AAAA
141 * - 1.0.0.127.in-addr.arpa. IN PTR
142 * - 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
143 * - version.bind. CH TXT
144 * - version.pdns. CH TXT
145 * - id.server. CH TXT
147 bool SyncRes::doSpecialNamesResolve(const DNSName
&qname
, const QType
&qtype
, const uint16_t qclass
, vector
<DNSRecord
> &ret
)
149 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."),
150 localhost("localhost."), versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns.");
152 bool handled
= false;
153 vector
<pair
<QType::typeenum
, string
> > answers
;
155 if ((qname
== arpa
|| qname
== ip6_arpa
) &&
156 qclass
== QClass::IN
) {
158 if (qtype
== QType::PTR
|| qtype
== QType::ANY
)
159 answers
.push_back({QType::PTR
, "localhost."});
162 if (qname
== localhost
&&
163 qclass
== QClass::IN
) {
165 if (qtype
== QType::A
|| qtype
== QType::ANY
)
166 answers
.push_back({QType::A
, "127.0.0.1"});
167 if (qtype
== QType::AAAA
|| qtype
== QType::ANY
)
168 answers
.push_back({QType::AAAA
, "::1"});
171 if ((qname
== versionbind
|| qname
== idserver
|| qname
== versionpdns
) &&
172 qclass
== QClass::CHAOS
) {
174 if (qtype
== QType::TXT
|| qtype
== QType::ANY
) {
175 if(qname
== versionbind
|| qname
== versionpdns
)
176 answers
.push_back({QType::TXT
, "\""+::arg()["version-string"]+"\""});
178 answers
.push_back({QType::TXT
, "\""+s_serverID
+"\""});
182 if (handled
&& !answers
.empty()) {
188 dr
.d_place
= DNSResourceRecord::ANSWER
;
191 for (const auto& ans
: answers
) {
192 dr
.d_type
= ans
.first
;
193 dr
.d_content
= DNSRecordContent::mastermake(ans
.first
, qclass
, ans
.second
);
202 //! This is the 'out of band resolver', in other words, the authoritative server
203 void SyncRes::AuthDomain::addSOA(std::vector
<DNSRecord
>& records
) const
205 SyncRes::AuthDomain::records_t::const_iterator ziter
= d_records
.find(boost::make_tuple(getName(), QType::SOA
));
206 if (ziter
!= d_records
.end()) {
207 DNSRecord dr
= *ziter
;
208 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
209 records
.push_back(dr
);
212 // cerr<<qname<<": can't find SOA record '"<<getName()<<"' in our zone!"<<endl;
216 int SyncRes::AuthDomain::getRecords(const DNSName
& qname
, uint16_t qtype
, std::vector
<DNSRecord
>& records
) const
218 int result
= RCode::NoError
;
222 std::pair
<records_t::const_iterator
,records_t::const_iterator
> range
= d_records
.equal_range(tie(qname
));
224 SyncRes::AuthDomain::records_t::const_iterator ziter
;
225 bool somedata
= false;
227 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
230 if(qtype
== QType::ANY
|| ziter
->d_type
== qtype
|| ziter
->d_type
== QType::CNAME
) {
231 // let rest of nameserver do the legwork on this one
232 records
.push_back(*ziter
);
234 else if (ziter
->d_type
== QType::NS
&& ziter
->d_name
.countLabels() > getName().countLabels()) {
235 // we hit a delegation point!
236 DNSRecord dr
= *ziter
;
237 dr
.d_place
=DNSResourceRecord::AUTHORITY
;
238 records
.push_back(dr
);
242 if (!records
.empty()) {
243 /* We have found an exact match, we're done */
244 // cerr<<qname<<": exact match in zone '"<<getName()<<"'"<<endl;
249 /* We have records for that name, but not of the wanted qtype */
250 // cerr<<qname<<": found record in '"<<getName()<<"', but nothing of the right type, sending SOA"<<endl;
256 // cerr<<qname<<": nothing found so far in '"<<getName()<<"', trying wildcards"<<endl;
257 DNSName
wcarddomain(qname
);
258 while(wcarddomain
!= getName() && wcarddomain
.chopOff()) {
259 // cerr<<qname<<": trying '*."<<wcarddomain<<"' in "<<getName()<<endl;
260 range
= d_records
.equal_range(boost::make_tuple(g_wildcarddnsname
+ wcarddomain
));
261 if (range
.first
==range
.second
)
264 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
265 DNSRecord dr
= *ziter
;
266 // if we hit a CNAME, just answer that - rest of recursor will do the needful & follow
267 if(dr
.d_type
== qtype
|| qtype
== QType::ANY
|| dr
.d_type
== QType::CNAME
) {
269 dr
.d_place
= DNSResourceRecord::ANSWER
;
270 records
.push_back(dr
);
274 if (records
.empty()) {
278 // cerr<<qname<<": in '"<<getName()<<"', had wildcard match on '*."<<wcarddomain<<"'"<<endl;
282 /* Nothing for this name, no wildcard, let's see if there is some NS */
283 DNSName
nsdomain(qname
);
284 while (nsdomain
.chopOff() && nsdomain
!= getName()) {
285 range
= d_records
.equal_range(boost::make_tuple(nsdomain
,QType::NS
));
286 if(range
.first
== range
.second
)
289 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
290 DNSRecord dr
= *ziter
;
291 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
292 records
.push_back(dr
);
296 if(records
.empty()) {
297 // cerr<<qname<<": no NS match in zone '"<<getName()<<"' either, handing out SOA"<<endl;
299 result
= RCode::NXDomain
;
305 bool SyncRes::doOOBResolve(const AuthDomain
& domain
, const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, int& res
) const
307 res
= domain
.getRecords(qname
, qtype
.getCode(), ret
);
311 bool SyncRes::doOOBResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int& res
)
316 prefix
.append(depth
, ' ');
319 DNSName
authdomain(qname
);
320 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
321 if(iter
==t_sstorage
.domainmap
->end() || !iter
->second
.isAuth()) {
322 LOG(prefix
<<qname
<<": auth storage has no zone for this query!"<<endl
);
326 LOG(prefix
<<qname
<<": auth storage has data, zone='"<<authdomain
<<"'"<<endl
);
327 return doOOBResolve(iter
->second
, qname
, qtype
, ret
, res
);
330 void SyncRes::doEDNSDumpAndClose(int fd
)
332 FILE* fp
=fdopen(fd
, "w");
336 fprintf(fp
,"IP Address\tMode\tMode last updated at\n");
337 for(const auto& eds
: t_sstorage
.ednsstatus
) {
338 fprintf(fp
, "%s\t%d\t%s", eds
.first
.toString().c_str(), (int)eds
.second
.mode
, ctime(&eds
.second
.modeSetAt
));
344 uint64_t SyncRes::doDumpNSSpeeds(int fd
)
346 FILE* fp
=fdopen(dup(fd
), "w");
349 fprintf(fp
, "; nsspeed dump from thread follows\n;\n");
352 for(const auto& i
: t_sstorage
.nsSpeeds
)
355 fprintf(fp
, "%s -> ", i
.first
.toString().c_str());
356 for(const auto& j
: i
.second
.d_collection
)
358 // typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
359 fprintf(fp
, "%s/%f ", j
.first
.toString().c_str(), j
.second
.peek());
367 /* so here is the story. First we complete the full resolution process for a domain name. And only THEN do we decide
368 to also do DNSSEC validation, which leads to new queries. To make this simple, we *always* ask for DNSSEC records
369 so that if there are RRSIGs for a name, we'll have them.
371 However, some hosts simply can't answer questions which ask for DNSSEC. This can manifest itself as:
376 The cause of "No answer" may be fragmentation, and it is tempting to probe if smaller answers would get through.
377 Another cause of "No answer" may simply be a network condition.
378 Nonsense answers are a clearer indication this host won't be able to do DNSSEC evah.
380 Previous implementations have suffered from turning off DNSSEC questions for an authoritative server based on timeouts.
381 A clever idea is to only turn off DNSSEC if we know a domain isn't signed anyhow. The problem with that really
382 clever idea however is that at this point in PowerDNS, we may simply not know that yet. All the DNSSEC thinking happens
383 elsewhere. It may not have happened yet.
385 For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish.
388 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
390 /* what is your QUEST?
391 the goal is to get as many remotes as possible on the highest level of EDNS support
394 0) UNKNOWN Unknown state
395 1) EDNS: Honors EDNS0
396 2) EDNSIGNORANT: Ignores EDNS0, gives replies without EDNS0
397 3) NOEDNS: Generates FORMERR/NOTIMP on EDNS queries
399 Everybody starts out assumed to be '0'.
400 If '0', send out EDNS0
401 If you FORMERR us, go to '3',
402 If no EDNS in response, go to '2'
403 If '1', send out EDNS0
404 If FORMERR, downgrade to 3
405 If '2', keep on including EDNS0, see what happens
407 If '3', send bare queries
410 SyncRes::EDNSStatus
* ednsstatus
;
411 ednsstatus
= &t_sstorage
.ednsstatus
[ip
]; // does this include port? YES
413 if(ednsstatus
->modeSetAt
&& ednsstatus
->modeSetAt
+ 3600 < d_now
.tv_sec
) {
414 *ednsstatus
=SyncRes::EDNSStatus();
415 // cerr<<"Resetting EDNS Status for "<<ip.toString()<<endl);
418 SyncRes::EDNSStatus::EDNSMode
& mode
=ednsstatus
->mode
;
419 SyncRes::EDNSStatus::EDNSMode oldmode
= mode
;
421 auto luaconfsLocal
= g_luaconfs
.getLocal();
424 ctx
.d_initialRequestId
= d_initialRequestId
;
428 for(int tries
= 0; tries
< 3; ++tries
) {
429 // cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl;
431 if(mode
==EDNSStatus::NOEDNS
) {
432 g_stats
.noEdnsOutQueries
++;
433 EDNSLevel
= 0; // level != mode
435 else if(ednsMANDATORY
|| mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
==EDNSStatus::EDNSIGNORANT
)
438 if (d_asyncResolve
) {
439 ret
= d_asyncResolve(ip
, domain
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, luaconfsLocal
->outgoingProtobufServer
, res
);
442 ret
=asyncresolve(ip
, domain
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, luaconfsLocal
->outgoingProtobufServer
, res
);
445 return ret
; // transport error, nothing to learn here
448 if(ret
== 0) { // timeout, not doing anything with it now
451 else if(mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
== EDNSStatus::EDNSIGNORANT
) {
452 if(res
->d_rcode
== RCode::FormErr
|| res
->d_rcode
== RCode::NotImp
) {
453 // cerr<<"Downgrading to NOEDNS because of "<<RCode::to_s(res->d_rcode)<<" for query to "<<ip.toString()<<" for '"<<domain<<"'"<<endl;
454 mode
= EDNSStatus::NOEDNS
;
457 else if(!res
->d_haveEDNS
) {
458 if(mode
!= EDNSStatus::EDNSIGNORANT
) {
459 mode
= EDNSStatus::EDNSIGNORANT
;
460 // cerr<<"We find that "<<ip.toString()<<" is an EDNS-ignorer for '"<<domain<<"', moving to mode 3"<<endl;
464 mode
= EDNSStatus::EDNSOK
;
465 // cerr<<"We find that "<<ip.toString()<<" is EDNS OK!"<<endl;
469 if(oldmode
!= mode
|| !ednsstatus
->modeSetAt
)
470 ednsstatus
->modeSetAt
=d_now
.tv_sec
;
471 // cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", new mode: "<<mode<<endl;
477 /*! This function will check the cache and go out to the internet if the answer is not in cache
479 * \param qname The name we need an answer for
481 * \param ret The vector of DNSRecords we need to fill with the answers
482 * \param depth The recursion depth we are in
484 * \return DNS RCODE or -1 (Error) or -2 (RPZ hit)
486 int SyncRes::doResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
)
491 prefix
.append(depth
, ' ');
494 LOG(prefix
<<qname
<<": Wants "<< (d_doDNSSEC
? "" : "NO ") << "DNSSEC processing in query for "<<qtype
.getName()<<endl
);
496 if(s_maxdepth
&& depth
> s_maxdepth
)
497 throw ImmediateServFailException("More than "+std::to_string(s_maxdepth
)+" (max-recursion-depth) levels of recursion needed while resolving "+qname
.toLogString());
501 // This is a difficult way of expressing "this is a normal query", i.e. not getRootNS.
502 if(!(d_updatingRootNS
&& qtype
.getCode()==QType::NS
&& qname
.isRoot())) {
503 if(d_cacheonly
) { // very limited OOB support
505 LOG(prefix
<<qname
<<": Recursion not requested for '"<<qname
<<"|"<<qtype
.getName()<<"', peeking at auth/forward zones"<<endl
);
506 DNSName
authname(qname
);
507 domainmap_t::const_iterator iter
=getBestAuthZone(&authname
);
508 if(iter
!= t_sstorage
.domainmap
->end()) {
509 if(iter
->second
.isAuth()) {
511 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, ret
, depth
, res
);
515 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
516 const ComboAddress remoteIP
= servers
.front();
517 LOG(prefix
<<qname
<<": forwarding query to hardcoded nameserver '"<< remoteIP
.toStringWithPort()<<"' for zone '"<<authname
<<"'"<<endl
);
519 boost::optional
<Netmask
> nm
;
520 res
=asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(), false, false, &d_now
, nm
, &lwr
);
521 // filter out the good stuff from lwr.result()
523 for(const auto& rec
: lwr
.d_records
) {
524 if(rec
.d_place
== DNSResourceRecord::ANSWER
)
530 return RCode::ServFail
;
536 if(!d_skipCNAMECheck
&& doCNAMECacheCheck(qname
,qtype
,ret
,depth
,res
)) // will reroute us if needed
539 if(doCacheCheck(qname
,qtype
,ret
,depth
,res
)) // we done
546 LOG(prefix
<<qname
<<": No cache hit for '"<<qname
<<"|"<<qtype
.getName()<<"', trying to find an appropriate NS record"<<endl
);
548 DNSName
subdomain(qname
);
549 if(qtype
== QType::DS
) subdomain
.chopOff();
552 bool flawedNSSet
=false;
554 // the two retries allow getBestNSNamesFromCache&co to reprime the root
555 // hints, in case they ever go missing
556 for(int tries
=0;tries
<2 && nsset
.empty();++tries
) {
557 subdomain
=getBestNSNamesFromCache(subdomain
, qtype
, nsset
, &flawedNSSet
, depth
, beenthere
); // pass beenthere to both occasions
560 if(!(res
=doResolveAt(nsset
, subdomain
, flawedNSSet
, qname
, qtype
, ret
, depth
, beenthere
)))
563 LOG(prefix
<<qname
<<": failed (res="<<res
<<")"<<endl
);
569 return res
<0 ? RCode::ServFail
: res
;
573 // for testing purposes
574 static bool ipv6First(const ComboAddress
& a
, const ComboAddress
& b
)
576 return !(a
.sin4
.sin_family
< a
.sin4
.sin_family
);
580 /** This function explicitly goes out for A or AAAA addresses
582 vector
<ComboAddress
> SyncRes::getAddrs(const DNSName
&qname
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
)
584 typedef vector
<DNSRecord
> res_t
;
587 typedef vector
<ComboAddress
> ret_t
;
592 for(int j
=1; j
<2+s_doIPv6
; j
++)
607 if(!doResolve(qname
, type
, res
,depth
+1, beenthere
) && !res
.empty()) { // this consults cache, OR goes out
608 for(res_t::const_iterator i
=res
.begin(); i
!= res
.end(); ++i
) {
609 if(i
->d_type
== QType::A
|| i
->d_type
== QType::AAAA
) {
610 if(auto rec
= std::dynamic_pointer_cast
<ARecordContent
>(i
->d_content
))
611 ret
.push_back(rec
->getCA(53));
612 else if(auto aaaarec
= std::dynamic_pointer_cast
<AAAARecordContent
>(i
->d_content
))
613 ret
.push_back(aaaarec
->getCA(53));
619 if(j
==1 && s_doIPv6
) { // we got an A record, see if we have some AAAA lying around
620 vector
<DNSRecord
> cset
;
621 if(t_RC
->get(d_now
.tv_sec
, qname
, QType(QType::AAAA
), &cset
, d_requestor
) > 0) {
622 for(auto k
=cset
.cbegin();k
!=cset
.cend();++k
) {
623 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
624 if (auto drc
= std::dynamic_pointer_cast
<AAAARecordContent
>(k
->d_content
)) {
625 ComboAddress ca
=drc
->getCA(53);
637 random_shuffle(ret
.begin(), ret
.end(), dns_random
);
639 // move 'best' address for this nameserver name up front
640 nsspeeds_t::iterator best
= t_sstorage
.nsSpeeds
.find(qname
);
642 if(best
!= t_sstorage
.nsSpeeds
.end())
643 for(ret_t::iterator i
=ret
.begin(); i
!= ret
.end(); ++i
) {
644 if(*i
==best
->second
.d_best
) { // got the fastest one
647 *ret
.begin()=best
->second
.d_best
;
657 void SyncRes::getBestNSFromCache(const DNSName
&qname
, const QType
& qtype
, vector
<DNSRecord
>& bestns
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
)
660 DNSName
subdomain(qname
);
663 prefix
.append(depth
, ' ');
669 LOG(prefix
<<qname
<<": Checking if we have NS in cache for '"<<subdomain
<<"'"<<endl
);
670 vector
<DNSRecord
> ns
;
671 *flawedNSSet
= false;
672 if(t_RC
->get(d_now
.tv_sec
, subdomain
, QType(QType::NS
), &ns
, d_requestor
) > 0) {
673 for(auto k
=ns
.cbegin();k
!=ns
.cend(); ++k
) {
674 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
675 vector
<DNSRecord
> aset
;
677 const DNSRecord
& dr
=*k
;
678 auto nrr
= getRR
<NSRecordContent
>(dr
);
679 if(nrr
&& (!nrr
->getNS().isPartOf(subdomain
) || t_RC
->get(d_now
.tv_sec
, nrr
->getNS(), s_doIPv6
? QType(QType::ADDR
) : QType(QType::A
),
680 doLog() ? &aset
: 0, d_requestor
) > 5)) {
681 bestns
.push_back(dr
);
682 LOG(prefix
<<qname
<<": NS (with ip, or non-glue) in cache for '"<<subdomain
<<"' -> '"<<nrr
->getNS()<<"'"<<endl
);
683 LOG(prefix
<<qname
<<": within bailiwick: "<< nrr
->getNS().isPartOf(subdomain
));
685 LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset
.begin()->d_ttl
- d_now
.tv_sec
))<<endl
);
688 LOG(", not in cache / did not look at cache"<<endl
);
693 LOG(prefix
<<qname
<<": NS in cache for '"<<subdomain
<<"', but needs glue ("<<nrr
->getNS()<<") which we miss or is expired"<<endl
);
697 if(!bestns
.empty()) {
698 GetBestNSAnswer answer
;
700 answer
.qtype
=qtype
.getCode();
701 for(const auto& dr
: bestns
)
702 answer
.bestns
.insert(make_pair(dr
.d_name
, getRR
<NSRecordContent
>(dr
)->getNS()));
704 if(beenthere
.count(answer
)) {
706 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' but part of LOOP (already seen "<<answer
.qname
<<")! Trying less specific NS"<<endl
);
709 for( set
<GetBestNSAnswer
>::const_iterator j
=beenthere
.begin();j
!=beenthere
.end();++j
) {
710 bool neo
= !(*j
< answer
|| answer
<*j
);
711 LOG(prefix
<<qname
<<": beenthere"<<(neo
?"*":"")<<": "<<j
->qname
<<"|"<<DNSRecordContent::NumberToType(j
->qtype
)<<" ("<<(unsigned int)j
->bestns
.size()<<")"<<endl
);
716 beenthere
.insert(answer
);
717 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' (flawedNSSet="<<*flawedNSSet
<<")"<<endl
);
722 LOG(prefix
<<qname
<<": no valid/useful NS in cache for '"<<subdomain
<<"'"<<endl
);
724 if(subdomain
.isRoot() && !brokeloop
) {
725 // We lost the root NS records
727 LOG(prefix
<<qname
<<": reprimed the root"<<endl
);
728 /* let's prevent an infinite loop */
729 if (!d_updatingRootNS
) {
730 getRootNS(d_now
, d_asyncResolve
);
733 }while(subdomain
.chopOff());
736 SyncRes::domainmap_t::const_iterator
SyncRes::getBestAuthZone(DNSName
* qname
) const
738 SyncRes::domainmap_t::const_iterator ret
;
740 ret
=t_sstorage
.domainmap
->find(*qname
);
741 if(ret
!=t_sstorage
.domainmap
->end())
743 }while(qname
->chopOff());
747 /** doesn't actually do the work, leaves that to getBestNSFromCache */
748 DNSName
SyncRes::getBestNSNamesFromCache(const DNSName
&qname
, const QType
& qtype
, NsSet
& nsset
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
)
750 DNSName
subdomain(qname
);
751 DNSName
authdomain(qname
);
753 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
754 if(iter
!=t_sstorage
.domainmap
->end()) {
755 if( iter
->second
.isAuth() )
756 // this gets picked up in doResolveAt, the empty DNSName, combined with the
757 // empty vector means 'we are auth for this zone'
758 nsset
.insert({DNSName(), {{}, false}});
760 // Again, picked up in doResolveAt. An empty DNSName, combined with a
761 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
762 // This is actually picked up in retrieveAddressesForNS called from doResolveAt.
763 nsset
.insert({DNSName(), {iter
->second
.d_servers
, iter
->second
.shouldRecurse() }});
768 vector
<DNSRecord
> bestns
;
769 getBestNSFromCache(subdomain
, qtype
, bestns
, flawedNSSet
, depth
, beenthere
);
771 for(auto k
=bestns
.cbegin() ; k
!= bestns
.cend(); ++k
) {
772 // The actual resolver code will not even look at the ComboAddress or bool
773 nsset
.insert({std::dynamic_pointer_cast
<NSRecordContent
>(k
->d_content
)->getNS(), {{}, false}});
774 if(k
==bestns
.cbegin())
780 bool SyncRes::doCNAMECacheCheck(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>& ret
, unsigned int depth
, int &res
)
785 prefix
.append(depth
, ' ');
788 if((depth
>9 && d_outqueries
>10 && d_throttledqueries
>5) || depth
> 15) {
789 LOG(prefix
<<qname
<<": recursing (CNAME or other indirection) too deep, depth="<<depth
<<endl
);
794 LOG(prefix
<<qname
<<": Looking for CNAME cache hit of '"<<qname
<<"|CNAME"<<"'"<<endl
);
795 vector
<DNSRecord
> cset
;
796 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
797 if(t_RC
->get(d_now
.tv_sec
, qname
,QType(QType::CNAME
), &cset
, d_requestor
, &signatures
, &d_wasVariable
) > 0) {
799 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
800 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
801 LOG(prefix
<<qname
<<": Found cache CNAME hit for '"<< qname
<< "|CNAME" <<"' to '"<<j
->d_content
->getZoneRepresentation()<<"'"<<endl
);
803 dr
.d_ttl
-=d_now
.tv_sec
;
806 for(const auto& signature
: signatures
) {
808 sigdr
.d_type
=QType::RRSIG
;
810 sigdr
.d_ttl
=j
->d_ttl
- d_now
.tv_sec
;
811 sigdr
.d_content
=signature
;
812 sigdr
.d_place
=DNSResourceRecord::ANSWER
;
814 ret
.push_back(sigdr
);
817 if(qtype
!= QType::CNAME
) { // perhaps they really wanted a CNAME!
818 set
<GetBestNSAnswer
>beenthere
;
819 res
=doResolve(std::dynamic_pointer_cast
<CNAMERecordContent
>(j
->d_content
)->getTarget(), qtype
, ret
, depth
+1, beenthere
);
827 LOG(prefix
<<qname
<<": No CNAME cache hit of '"<< qname
<< "|CNAME" <<"' found"<<endl
);
832 * Convience function to push the records from records into ret with a new TTL
834 * \param records DNSRecords that need to go into ret
835 * \param ttl The new TTL for these records
836 * \param ret The vector of DNSRecords that should contian the records with the modified TTL
838 static void addTTLModifiedRecords(const vector
<DNSRecord
>& records
, const uint32_t ttl
, vector
<DNSRecord
>& ret
) {
839 for (const auto& rec
: records
) {
847 bool SyncRes::doCacheCheck(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int &res
)
849 bool giveNegative
=false;
854 prefix
.append(depth
, ' ');
857 // 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)
858 DNSName
sqname(qname
);
861 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
863 DNSName
authname(qname
);
864 bool wasForwardedOrAuth
= false;
865 bool wasAuth
= false;
866 domainmap_t::const_iterator iter
=getBestAuthZone(&authname
);
867 if(iter
!= t_sstorage
.domainmap
->end()) {
868 wasForwardedOrAuth
= true;
869 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
870 if(servers
.empty()) {
874 NegCache::NegCacheEntry ne
;
877 t_sstorage
.negcache
.getRootNXTrust(qname
, d_now
, ne
) &&
878 ne
.d_auth
.isRoot() &&
879 !(wasForwardedOrAuth
&& !authname
.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
880 sttl
= ne
.d_ttd
- d_now
.tv_sec
;
881 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
.d_auth
<<"' & '"<<ne
.d_name
<<"' for another "<<sttl
<<" seconds"<<endl
);
882 res
= RCode::NXDomain
;
885 else if (t_sstorage
.negcache
.get(qname
, qtype
, d_now
, ne
) &&
886 !(wasForwardedOrAuth
&& ne
.d_auth
!= authname
)) { // Only the authname nameserver can neg cache entries
888 sttl
= ne
.d_ttd
- d_now
.tv_sec
;
890 if(ne
.d_qtype
.getCode()) {
891 LOG(prefix
<<qname
<<": "<<qtype
.getName()<<" is negatively cached via '"<<ne
.d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
892 res
= RCode::NoError
;
895 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
.d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
896 res
= RCode::NXDomain
;
899 addTTLModifiedRecords(ne
.DNSSECRecords
.records
, sttl
, ret
);
900 addTTLModifiedRecords(ne
.DNSSECRecords
.signatures
, sttl
, ret
);
905 // Transplant SOA to the returned packet
906 addTTLModifiedRecords(ne
.authoritySOA
.records
, sttl
, ret
);
908 addTTLModifiedRecords(ne
.authoritySOA
.signatures
, sttl
, ret
);
912 vector
<DNSRecord
> cset
;
913 bool found
=false, expired
=false;
914 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
916 if(t_RC
->get(d_now
.tv_sec
, sqname
, sqt
, &cset
, d_requestor
, d_doDNSSEC
? &signatures
: 0, &d_wasVariable
) > 0) {
917 LOG(prefix
<<sqname
<<": Found cache hit for "<<sqt
.getName()<<": ");
918 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
919 LOG(j
->d_content
->getZoneRepresentation());
920 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
922 ttl
= (dr
.d_ttl
-=d_now
.tv_sec
);
924 LOG("[ttl="<<dr
.d_ttl
<<"] ");
933 for(const auto& signature
: signatures
) {
935 dr
.d_type
=QType::RRSIG
;
938 dr
.d_content
=signature
;
939 dr
.d_place
= DNSResourceRecord::ANSWER
;
945 if(found
&& !expired
) {
948 d_wasOutOfBand
= wasAuth
;
952 LOG(prefix
<<qname
<<": cache had only stale entries"<<endl
);
958 bool SyncRes::moreSpecificThan(const DNSName
& a
, const DNSName
&b
) const
960 return (a
.isPartOf(b
) && a
.countLabels() > b
.countLabels());
965 speedOrder(map
<DNSName
,double> &speeds
) : d_speeds(speeds
) {}
966 bool operator()(const DNSName
&a
, const DNSName
&b
) const
968 return d_speeds
[a
] < d_speeds
[b
];
970 map
<DNSName
, double>& d_speeds
;
973 inline vector
<DNSName
> SyncRes::shuffleInSpeedOrder(NsSet
&tnameservers
, const string
&prefix
)
975 vector
<DNSName
> rnameservers
;
976 rnameservers
.reserve(tnameservers
.size());
977 for(const auto& tns
:tnameservers
) {
978 rnameservers
.push_back(tns
.first
);
980 map
<DNSName
, double> speeds
;
982 for(const auto& val
: rnameservers
) {
984 speed
=t_sstorage
.nsSpeeds
[val
].get(&d_now
);
987 random_shuffle(rnameservers
.begin(),rnameservers
.end(), dns_random
);
988 speedOrder
so(speeds
);
989 stable_sort(rnameservers
.begin(),rnameservers
.end(), so
);
992 LOG(prefix
<<"Nameservers: ");
993 for(vector
<DNSName
>::const_iterator i
=rnameservers
.begin();i
!=rnameservers
.end();++i
) {
994 if(i
!=rnameservers
.begin()) {
996 if(!((i
-rnameservers
.begin())%3)) {
997 LOG(endl
<<prefix
<<" ");
1000 LOG((i
->empty() ? string("<empty>") : i
->toString())<<"(" << (boost::format("%0.2f") % (speeds
[*i
]/1000.0)).str() <<"ms)");
1004 return rnameservers
;
1007 static bool magicAddrMatch(const QType
& query
, const QType
& answer
)
1009 if(query
.getCode() != QType::ADDR
)
1011 return answer
.getCode() == QType::A
|| answer
.getCode() == QType::AAAA
;
1014 /* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
1016 * \param records The records to parse for the authority SOA and NSEC(3) records
1017 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
1019 static void harvestNXRecords(const vector
<DNSRecord
>& records
, NegCache::NegCacheEntry
& ne
) {
1020 static const set
<uint16_t> nsecTypes
= {QType::NSEC
, QType::NSEC3
};
1021 for(const auto& rec
: records
) {
1022 if(rec
.d_place
!= DNSResourceRecord::AUTHORITY
)
1023 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
1024 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
1025 // records MUST be in the same section as the records they cover.
1026 // Hence, we ignore all records outside of the AUTHORITY section.
1029 if(rec
.d_type
== QType::RRSIG
) {
1030 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1032 if(rrsig
->d_type
== QType::SOA
) {
1033 ne
.authoritySOA
.signatures
.push_back(rec
);
1035 if(nsecTypes
.count(rrsig
->d_type
)) {
1036 ne
.DNSSECRecords
.signatures
.push_back(rec
);
1041 if(rec
.d_type
== QType::SOA
) {
1042 ne
.authoritySOA
.records
.push_back(rec
);
1045 if(nsecTypes
.count(rec
.d_type
)) {
1046 ne
.DNSSECRecords
.records
.push_back(rec
);
1052 // TODO remove after processRecords is fixed!
1053 // Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
1054 static void addNXNSECS(vector
<DNSRecord
>&ret
, const vector
<DNSRecord
>& records
)
1056 NegCache::NegCacheEntry ne
;
1057 harvestNXRecords(records
, ne
);
1058 ret
.insert(ret
.end(), ne
.authoritySOA
.signatures
.begin(), ne
.authoritySOA
.signatures
.end());
1059 ret
.insert(ret
.end(), ne
.DNSSECRecords
.records
.begin(), ne
.DNSSECRecords
.records
.end());
1060 ret
.insert(ret
.end(), ne
.DNSSECRecords
.signatures
.begin(), ne
.DNSSECRecords
.signatures
.end());
1063 bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine
& dfe
, const NsSet
& nameservers
)
1066 for (auto const &ns
: nameservers
) {
1067 d_appliedPolicy
= dfe
.getProcessingPolicy(ns
.first
, d_discardedPolicies
);
1068 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1069 LOG(", however nameserver "<<ns
.first
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1073 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1074 for (auto const &address
: ns
.second
.first
) {
1075 d_appliedPolicy
= dfe
.getProcessingPolicy(address
, d_discardedPolicies
);
1076 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1077 LOG(", however nameserver "<<ns
.first
<<" IP address "<<address
.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1086 bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine
& dfe
, const ComboAddress
& remoteIP
)
1089 d_appliedPolicy
= dfe
.getProcessingPolicy(remoteIP
, d_discardedPolicies
);
1090 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) {
1091 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")+"')");
1098 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
)
1100 vector
<ComboAddress
> result
;
1103 LOG(prefix
<<qname
<<": Trying to resolve NS '"<<*tns
<< "' ("<<1+tns
-rnameservers
.begin()<<"/"<<(unsigned int)rnameservers
.size()<<")"<<endl
);
1104 result
= getAddrs(*tns
, depth
+2, beenthere
);
1105 pierceDontQuery
=false;
1108 LOG(prefix
<<qname
<<": Domain has hardcoded nameserver");
1110 result
= nameservers
[*tns
].first
;
1111 if(result
.size() > 1) {
1116 sendRDQuery
= nameservers
[*tns
].second
;
1117 pierceDontQuery
=true;
1122 bool SyncRes::throttledOrBlocked(const std::string
& prefix
, const ComboAddress
& remoteIP
, const DNSName
& qname
, const QType
& qtype
, bool pierceDontQuery
)
1124 if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0))) {
1125 LOG(prefix
<<qname
<<": server throttled "<<endl
);
1126 s_throttledqueries
++; d_throttledqueries
++;
1129 else if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()))) {
1130 LOG(prefix
<<qname
<<": query throttled "<<remoteIP
.toString()<<", "<<qname
<<"; "<<qtype
.getName()<<endl
);
1131 s_throttledqueries
++; d_throttledqueries
++;
1134 else if(!pierceDontQuery
&& s_dontQuery
&& s_dontQuery
->match(&remoteIP
)) {
1135 LOG(prefix
<<qname
<<": not sending query to " << remoteIP
.toString() << ", blocked by 'dont-query' setting" << endl
);
1142 RCode::rcodes_
SyncRes::updateCacheFromRecords(const std::string
& prefix
, LWResult
& lwr
, const DNSName
& qname
, const DNSName
& auth
, bool wasForwarded
, const boost::optional
<Netmask
> ednsmask
)
1146 vector
<DNSRecord
> records
;
1147 vector
<shared_ptr
<RRSIGRecordContent
>> signatures
;
1153 DNSResourceRecord::Place place
;
1154 bool operator<(const CacheKey
& rhs
) const {
1155 return tie(name
, type
) < tie(rhs
.name
, rhs
.type
);
1158 typedef map
<CacheKey
, CachePair
> tcache_t
;
1161 for(const auto& rec
: lwr
.d_records
) {
1162 if(rec
.d_type
== QType::RRSIG
) {
1163 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1165 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
1166 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
1171 // reap all answers from this packet that are acceptable
1172 for(auto& rec
: lwr
.d_records
) {
1173 if(rec
.d_type
== QType::OPT
) {
1174 LOG(prefix
<<qname
<<": OPT answer '"<<rec
.d_name
<<"' from '"<<auth
<<"' nameservers" <<endl
);
1177 LOG(prefix
<<qname
<<": accept answer '"<<rec
.d_name
<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"|"<<rec
.d_content
->getZoneRepresentation()<<"' from '"<<auth
<<"' nameservers? "<<(int)rec
.d_place
<<" ");
1178 if(rec
.d_type
== QType::ANY
) {
1179 LOG("NO! - we don't accept 'ANY' data"<<endl
);
1183 if(rec
.d_name
.isPartOf(auth
)) {
1184 if(rec
.d_type
== QType::RRSIG
) {
1185 LOG("RRSIG - separate"<<endl
);
1187 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
)) {
1188 LOG("NO! Is from delegation-only zone"<<endl
);
1190 return RCode::NXDomain
;
1193 bool haveLogged
= false;
1194 if (!t_sstorage
.domainmap
->empty()) {
1195 // Check if we are authoritative for a zone in this answer
1196 DNSName
tmp_qname(rec
.d_name
);
1197 auto auth_domain_iter
=getBestAuthZone(&tmp_qname
);
1198 if(auth_domain_iter
!=t_sstorage
.domainmap
->end() &&
1199 auth
.countLabels() <= auth_domain_iter
->first
.countLabels()) {
1200 if (auth_domain_iter
->first
!= auth
) {
1201 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter
->first
<<endl
);
1204 LOG("YES! - This answer was ");
1205 if (!wasForwarded
) {
1206 LOG("retrieved from the local auth store.");
1208 LOG("received from a server we forward to.");
1219 rec
.d_ttl
=min(s_maxcachettl
, rec
.d_ttl
);
1222 dr
.d_place
=DNSResourceRecord::ANSWER
;
1224 dr
.d_ttl
+= d_now
.tv_sec
;
1225 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(dr
);
1233 for(tcache_t::iterator i
=tcache
.begin();i
!=tcache
.end();++i
) {
1234 if(i
->second
.records
.size() > 1) { // need to group the ttl to be the minimum of the RRSET (RFC 2181, 5.2)
1235 uint32_t lowestTTL
=std::numeric_limits
<uint32_t>::max();
1236 for(const auto& record
: i
->second
.records
)
1237 lowestTTL
=min(lowestTTL
, record
.d_ttl
);
1239 for(auto& record
: i
->second
.records
)
1240 *const_cast<uint32_t*>(&record
.d_ttl
)=lowestTTL
; // boom
1243 // cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
1244 // cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
1245 if(i
->second
.records
.empty()) // this happens when we did store signatures, but passed on the records themselves
1248 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::none
);
1250 if(i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
)
1254 return RCode::NoError
;
1257 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
)
1261 for(auto& rec
: lwr
.d_records
) {
1262 if (rec
.d_type
!=QType::OPT
&& rec
.d_class
!=QClass::IN
)
1265 if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
1266 lwr
.d_rcode
==RCode::NXDomain
&& qname
.isPartOf(rec
.d_name
) && rec
.d_name
.isPartOf(auth
)) {
1267 LOG(prefix
<<qname
<<": got negative caching indication for name '"<<qname
<<"' (accept="<<rec
.d_name
.isPartOf(auth
)<<"), newtarget='"<<newtarget
<<"'"<<endl
);
1269 rec
.d_ttl
= min(rec
.d_ttl
, s_maxnegttl
);
1270 if(newtarget
.empty()) // only add a SOA if we're not going anywhere after this
1272 if(!wasVariable()) {
1273 NegCache::NegCacheEntry ne
;
1275 ne
.d_ttd
= d_now
.tv_sec
+ rec
.d_ttl
;
1277 ne
.d_qtype
= QType(0); // this encodes 'whole record'
1278 ne
.d_auth
= rec
.d_name
;
1279 harvestNXRecords(lwr
.d_records
, ne
);
1280 t_sstorage
.negcache
.add(ne
);
1281 if(s_rootNXTrust
&& ne
.d_auth
.isRoot() && auth
.isRoot()) {
1282 ne
.d_name
= ne
.d_name
.getLastLabel();
1283 t_sstorage
.negcache
.add(ne
);
1289 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&& rec
.d_type
==QType::CNAME
&& (!(qtype
==QType(QType::CNAME
)))) {
1291 if (auto content
= getRR
<CNAMERecordContent
>(rec
)) {
1292 newtarget
=content
->getTarget();
1295 else if((rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::ANSWER
){
1296 if(rec
.d_type
!= QType::RRSIG
|| rec
.d_name
== qname
)
1297 ret
.push_back(rec
); // enjoy your DNSSEC
1299 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
1300 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&&
1302 rec
.d_type
==qtype
.getCode() || (lwr
.d_aabit
&& (qtype
==QType(QType::ANY
) || magicAddrMatch(qtype
, QType(rec
.d_type
)) ) ) || sendRDQuery
1306 LOG(prefix
<<qname
<<": answer is in: resolved to '"<< rec
.d_content
->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"'"<<endl
);
1311 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& qname
.isPartOf(rec
.d_name
) && rec
.d_type
==QType::NS
) {
1312 if(moreSpecificThan(rec
.d_name
,auth
)) {
1314 LOG(prefix
<<qname
<<": got NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
1318 LOG(prefix
<<qname
<<": got upwards/level NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"', had '"<<auth
<<"'"<<endl
);
1320 if (auto content
= getRR
<NSRecordContent
>(rec
)) {
1321 nsset
.insert(content
->getNS());
1324 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& qname
.isPartOf(rec
.d_name
) && rec
.d_type
==QType::DS
) {
1325 LOG(prefix
<<qname
<<": got DS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
1327 else if(!done
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& qname
.isPartOf(rec
.d_name
) && rec
.d_type
==QType::SOA
&&
1328 lwr
.d_rcode
==RCode::NoError
) {
1329 LOG(prefix
<<qname
<<": got negative caching indication for '"<< qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
1331 if(!newtarget
.empty()) {
1332 LOG(prefix
<<qname
<<": Hang on! Got a redirect to '"<<newtarget
<<"' already"<<endl
);
1335 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
1337 if(!wasVariable()) {
1338 NegCache::NegCacheEntry ne
;
1339 ne
.d_auth
= rec
.d_name
;
1340 ne
.d_ttd
= d_now
.tv_sec
+ rec
.d_ttl
;
1343 harvestNXRecords(lwr
.d_records
, ne
);
1344 if(qtype
.getCode()) { // prevents us from blacking out a whole domain
1345 t_sstorage
.negcache
.add(ne
);
1356 bool SyncRes::doResolveAtThisIP(const std::string
& prefix
, const DNSName
& qname
, const QType
& qtype
, LWResult
& lwr
, boost::optional
<Netmask
>& ednsmask
, const DNSName
& auth
, bool const sendRDQuery
, const DNSName
& nsName
, const ComboAddress
& remoteIP
, bool doTCP
, bool* truncated
)
1362 if(d_outqueries
+ d_throttledqueries
> s_maxqperq
) {
1363 throw ImmediateServFailException("more than "+std::to_string(s_maxqperq
)+" (max-qperq) queries sent while resolving "+qname
.toLogString());
1366 if(s_maxtotusec
&& d_totUsec
> s_maxtotusec
) {
1367 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");
1371 LOG(prefix
<<qname
<<": using TCP with "<< remoteIP
.toStringWithPort() <<endl
);
1376 if(d_pdl
&& d_pdl
->preoutquery(remoteIP
, d_requestor
, qname
, qtype
, doTCP
, lwr
.d_records
, resolveret
)) {
1377 LOG(prefix
<<qname
<<": query handled by Lua"<<endl
);
1380 ednsmask
=getEDNSSubnetMask(d_requestor
, qname
, remoteIP
);
1382 LOG(prefix
<<qname
<<": Adding EDNS Client Subnet Mask "<<ednsmask
->toString()<<" to query"<<endl
);
1384 resolveret
= asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(),
1385 doTCP
, sendRDQuery
, &d_now
, ednsmask
, &lwr
); // <- we go out on the wire!
1387 LOG(prefix
<<qname
<<": Received EDNS Client Subnet Mask "<<ednsmask
->toString()<<" on response"<<endl
);
1391 /* preoutquery killed the query by setting dq.rcode to -3 */
1392 if(resolveret
==-3) {
1393 throw ImmediateServFailException("Query killed by policy");
1396 d_totUsec
+= lwr
.d_usec
;
1397 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
1399 if(resolveret
!= 1) {
1400 /* Error while resolving */
1401 if(resolveret
== 0) {
1404 LOG(prefix
<<qname
<<": timeout resolving after "<<lwr
.d_usec
/1000.0<<"msec "<< (doTCP
? "over TCP" : "")<<endl
);
1406 s_outgoingtimeouts
++;
1408 if(remoteIP
.sin4
.sin_family
== AF_INET
)
1409 s_outgoing4timeouts
++;
1411 s_outgoing6timeouts
++;
1413 else if(resolveret
== -2) {
1414 /* OS resource limit reached */
1415 LOG(prefix
<<qname
<<": hit a local resource limit resolving"<< (doTCP
? " over TCP" : "")<<", probable error: "<<stringerror()<<endl
);
1416 g_stats
.resourceLimits
++;
1419 /* -1 means server unreachable */
1422 LOG(prefix
<<qname
<<": error resolving from "<<remoteIP
.toString()<< (doTCP
? " over TCP" : "") <<", possible error: "<<strerror(errno
)<< endl
);
1425 if(resolveret
!= -2) { // don't account for resource limits, they are our own fault
1426 t_sstorage
.nsSpeeds
[nsName
].submit(remoteIP
, 1000000, &d_now
); // 1 sec
1428 // code below makes sure we don't filter COM or the root
1429 if (s_serverdownmaxfails
> 0 && (auth
!= g_rootdnsname
) && t_sstorage
.fails
.incr(remoteIP
) >= s_serverdownmaxfails
) {
1430 LOG(prefix
<<qname
<<": Max fails reached resolving on "<< remoteIP
.toString() <<". Going full throttle for "<< s_serverdownthrottletime
<<" seconds" <<endl
);
1431 // mark server as down
1432 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0), s_serverdownthrottletime
, 10000);
1434 else if (resolveret
== -1) {
1435 // unreachable, 1 minute or 100 queries
1436 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 100);
1440 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 10, 5);
1447 /* we got an answer */
1448 if(lwr
.d_rcode
==RCode::ServFail
|| lwr
.d_rcode
==RCode::Refused
) {
1449 LOG(prefix
<<qname
<<": "<<nsName
<<" ("<<remoteIP
.toString()<<") returned a "<< (lwr
.d_rcode
==RCode::ServFail
? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl
);
1450 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
1454 /* this server sent a valid answer, mark it backup up if it was down */
1455 if(s_serverdownmaxfails
> 0) {
1456 t_sstorage
.fails
.clear(remoteIP
);
1463 LOG(prefix
<<qname
<<": truncated bit set, over TCP?"<<endl
);
1464 /* let's treat that as a ServFail answer from this server */
1465 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
1475 bool SyncRes::processAnswer(unsigned int depth
, LWResult
& lwr
, const DNSName
& qname
, const QType
& qtype
, DNSName
& auth
, bool wasForwarded
, const boost::optional
<Netmask
> ednsmask
, bool sendRDQuery
, NsSet
&nameservers
, std::vector
<DNSRecord
>& ret
, const DNSFilterEngine
& dfe
, bool* gotNewServers
, int* rcode
)
1480 prefix
.append(depth
, ' ');
1484 for(auto& rec
: lwr
.d_records
) {
1485 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumTTL
);
1489 *rcode
= updateCacheFromRecords(prefix
, lwr
, qname
, auth
, wasForwarded
, ednsmask
);
1490 if (*rcode
!= RCode::NoError
) {
1494 LOG(prefix
<<qname
<<": determining status after receiving this packet"<<endl
);
1497 bool realreferral
=false, negindic
=false;
1501 bool done
= processRecords(prefix
, qname
, qtype
, auth
, lwr
, sendRDQuery
, ret
, nsset
, newtarget
, newauth
, realreferral
, negindic
);
1504 LOG(prefix
<<qname
<<": status=got results, this level of recursion done"<<endl
);
1505 *rcode
= RCode::NoError
;
1509 if(!newtarget
.empty()) {
1510 if(newtarget
== qname
) {
1511 LOG(prefix
<<qname
<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl
);
1512 *rcode
= RCode::ServFail
;
1517 LOG(prefix
<<qname
<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl
);
1518 *rcode
= RCode::ServFail
;
1522 LOG(prefix
<<qname
<<": status=got a CNAME referral, starting over with "<<newtarget
<<endl
);
1524 set
<GetBestNSAnswer
> beenthere2
;
1525 *rcode
= doResolve(newtarget
, qtype
, ret
, depth
+ 1, beenthere2
);
1529 if(lwr
.d_rcode
== RCode::NXDomain
) {
1530 LOG(prefix
<<qname
<<": status=NXDOMAIN, we are done "<<(negindic
? "(have negative SOA)" : "")<<endl
);
1533 addNXNSECS(ret
, lwr
.d_records
);
1535 *rcode
= RCode::NXDomain
;
1539 if(nsset
.empty() && !lwr
.d_rcode
&& (negindic
|| lwr
.d_aabit
|| sendRDQuery
)) {
1540 LOG(prefix
<<qname
<<": status=noerror, other types may exist, but we are done "<<(negindic
? "(have negative SOA) " : "")<<(lwr
.d_aabit
? "(have aa bit) " : "")<<endl
);
1543 addNXNSECS(ret
, lwr
.d_records
);
1545 *rcode
= RCode::NoError
;
1550 LOG(prefix
<<qname
<<": status=did not resolve, got "<<(unsigned int)nsset
.size()<<" NS, ");
1553 nameservers
.clear();
1554 for (auto const &nameserver
: nsset
) {
1556 d_appliedPolicy
= dfe
.getProcessingPolicy(nameserver
, d_discardedPolicies
);
1557 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1558 LOG("however "<<nameserver
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1563 nameservers
.insert({nameserver
, {{}, false}});
1565 LOG("looping to them"<<endl
);
1566 *gotNewServers
= true;
1574 * -1 in case of no results
1575 * -2 when a FilterEngine Policy was hit
1578 int SyncRes::doResolveAt(NsSet
&nameservers
, DNSName auth
, bool flawedNSSet
, const DNSName
&qname
, const QType
&qtype
,
1579 vector
<DNSRecord
>&ret
,
1580 unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
)
1582 auto luaconfsLocal
= g_luaconfs
.getLocal();
1586 prefix
.append(depth
, ' ');
1589 LOG(prefix
<<qname
<<": Cache consultations done, have "<<(unsigned int)nameservers
.size()<<" NS to contact");
1591 if (nameserversBlockedByRPZ(luaconfsLocal
->dfe
, nameservers
)) {
1597 for(;;) { // we may get more specific nameservers
1598 vector
<DNSName
> rnameservers
= shuffleInSpeedOrder(nameservers
, doLog() ? (prefix
+qname
.toString()+": ") : string() );
1600 for(auto tns
=rnameservers
.cbegin();;++tns
) {
1601 if(tns
==rnameservers
.cend()) {
1602 LOG(prefix
<<qname
<<": Failed to resolve via any of the "<<(unsigned int)rnameservers
.size()<<" offered NS at level '"<<auth
<<"'"<<endl
);
1603 if(!auth
.isRoot() && flawedNSSet
) {
1604 LOG(prefix
<<qname
<<": Ageing nameservers for level '"<<auth
<<"', next query might succeed"<<endl
);
1606 if(t_RC
->doAgeCache(d_now
.tv_sec
, auth
, QType::NS
, 10))
1607 g_stats
.nsSetInvalidations
++;
1612 // this line needs to identify the 'self-resolving' behaviour, but we get it wrong now
1613 if(qname
== *tns
&& qtype
.getCode()==QType::A
&& rnameservers
.size() > (size_t)(1+1*s_doIPv6
)) {
1614 LOG(prefix
<<qname
<<": Not using NS to resolve itself! ("<<(1+tns
-rnameservers
.cbegin())<<"/"<<rnameservers
.size()<<")"<<endl
);
1618 typedef vector
<ComboAddress
> remoteIPs_t
;
1619 remoteIPs_t remoteIPs
;
1620 remoteIPs_t::const_iterator remoteIP
;
1621 bool pierceDontQuery
=false;
1622 bool sendRDQuery
=false;
1623 boost::optional
<Netmask
> ednsmask
;
1625 const bool wasForwarded
= tns
->empty() && (!nameservers
[*tns
].first
.empty());
1626 int rcode
= RCode::NoError
;
1627 bool gotNewServers
= false;
1629 if(tns
->empty() && !wasForwarded
) {
1630 LOG(prefix
<<qname
<<": Domain is out-of-band"<<endl
);
1631 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, lwr
.d_records
, depth
, lwr
.d_rcode
);
1635 /* we have received an answer, are we done ? */
1636 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, false, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
);
1640 if (gotNewServers
) {
1645 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
1646 remoteIPs
= retrieveAddressesForNS(prefix
, qname
, tns
, depth
, beenthere
, rnameservers
, nameservers
, sendRDQuery
, pierceDontQuery
, flawedNSSet
);
1648 if(remoteIPs
.empty()) {
1649 LOG(prefix
<<qname
<<": Failed to get IP for NS "<<*tns
<<", trying next if available"<<endl
);
1654 bool hitPolicy
{false};
1655 LOG(prefix
<<qname
<<": Resolved '"<<auth
<<"' NS "<<*tns
<<" to: ");
1656 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
1657 if(remoteIP
!= remoteIPs
.cbegin()) {
1660 LOG(remoteIP
->toString());
1661 if(nameserverIPBlockedByRPZ(luaconfsLocal
->dfe
, *remoteIP
)) {
1666 if (hitPolicy
) //implies d_wantsRPZ
1670 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
1671 LOG(prefix
<<qname
<<": Trying IP "<< remoteIP
->toStringWithPort() <<", asking '"<<qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
1673 if (throttledOrBlocked(prefix
, *remoteIP
, qname
, qtype
, pierceDontQuery
)) {
1677 bool truncated
= false;
1678 bool gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
1679 *tns
, *remoteIP
, false, &truncated
);
1680 if (gotAnswer
&& truncated
) {
1681 /* retry, over TCP this time */
1682 gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
1683 *tns
, *remoteIP
, true, &truncated
);
1690 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
);
1692 /* // for you IPv6 fanatics :-)
1693 if(remoteIP->sin4.sin_family==AF_INET6)
1696 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
1698 t_sstorage
.nsSpeeds
[*tns
].submit(*remoteIP
, lwr
.d_usec
, &d_now
);
1700 /* we have received an answer, are we done ? */
1701 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
);
1705 if (gotNewServers
) {
1709 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100);
1712 if (gotNewServers
) {
1716 if(remoteIP
== remoteIPs
.cend()) // we tried all IP addresses, none worked
1725 boost::optional
<Netmask
> SyncRes::getEDNSSubnetMask(const ComboAddress
& local
, const DNSName
&dn
, const ComboAddress
& rem
)
1727 boost::optional
<Netmask
> result
;
1730 if(d_incomingECSFound
) {
1731 if (d_incomingECS
->source
.getBits() == 0) {
1732 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0 */
1735 trunc
= d_incomingECS
->source
.getMaskedNetwork();
1736 bits
= d_incomingECS
->source
.getBits();
1738 else if(!local
.isIPv4() || local
.sin4
.sin_addr
.s_addr
) { // detect unset 'requestor'
1740 bits
= local
.isIPv4() ? 32 : 128;
1743 /* nothing usable */
1747 if(s_ednsdomains
.check(dn
) || s_ednssubnets
.match(rem
)) {
1748 bits
= std::min(bits
, (trunc
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
1749 trunc
.truncate(bits
);
1750 return boost::optional
<Netmask
>(Netmask(trunc
, bits
));
1756 void SyncRes::parseEDNSSubnetWhitelist(const std::string
& wlist
)
1758 vector
<string
> parts
;
1759 stringtok(parts
, wlist
, ",; ");
1760 for(const auto& a
: parts
) {
1762 s_ednssubnets
.addMask(Netmask(a
));
1765 s_ednsdomains
.add(DNSName(a
));
1770 // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
1771 int directResolve(const DNSName
& qname
, const QType
& qtype
, int qclass
, vector
<DNSRecord
>& ret
)
1774 gettimeofday(&now
, 0);
1777 int res
= sr
.beginResolve(qname
, QType(qtype
), qclass
, ret
);
1782 #include "validate-recursor.hh"
1784 int SyncRes::getRootNS(struct timeval now
, asyncresolve_t asyncCallback
) {
1786 sr
.setDoEDNS0(true);
1787 sr
.setUpdatingRootNS();
1788 sr
.setDoDNSSEC(g_dnssecmode
!= DNSSECMode::Off
);
1789 sr
.setAsyncCallback(asyncCallback
);
1791 vector
<DNSRecord
> ret
;
1794 res
=sr
.beginResolve(g_rootdnsname
, QType(QType::NS
), 1, ret
);
1795 if (g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
) {
1797 auto state
= validateRecords(ctx
, ret
);
1799 throw PDNSException("Got Bogus validation result for .|NS");
1803 catch(const PDNSException
& e
) {
1804 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
1806 catch(const ImmediateServFailException
& e
) {
1807 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
1809 catch(const std::exception
& e
) {
1810 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.what()<<endl
;
1813 L
<<Logger::Error
<<"Failed to update . records, got an exception"<<endl
;
1817 L
<<Logger::Notice
<<"Refreshed . records"<<endl
;
1820 L
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;