2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "arguments.hh"
27 #include "cachecleaner.hh"
28 #include "dns_random.hh"
29 #include "dnsparser.hh"
30 #include "dnsrecords.hh"
31 #include "ednssubnet.hh"
33 #include "lua-recursor4.hh"
34 #include "rec-lua-conf.hh"
36 #include "dnsseckeeper.hh"
37 #include "validate-recursor.hh"
39 thread_local
SyncRes::ThreadLocalStorage
SyncRes::t_sstorage
;
40 thread_local
std::unique_ptr
<addrringbuf_t
> t_timeouts
;
42 std::unordered_set
<DNSName
> SyncRes::s_delegationOnly
;
43 std::unique_ptr
<NetmaskGroup
> SyncRes::s_dontQuery
{nullptr};
44 NetmaskGroup
SyncRes::s_ednslocalsubnets
;
45 NetmaskGroup
SyncRes::s_ednsremotesubnets
;
46 SuffixMatchNode
SyncRes::s_ednsdomains
;
47 EDNSSubnetOpts
SyncRes::s_ecsScopeZero
;
48 string
SyncRes::s_serverID
;
49 SyncRes::LogMode
SyncRes::s_lm
;
50 const std::unordered_set
<uint16_t> SyncRes::s_redirectionQTypes
= {QType::CNAME
, QType::DNAME
};
52 unsigned int SyncRes::s_maxnegttl
;
53 unsigned int SyncRes::s_maxbogusttl
;
54 unsigned int SyncRes::s_maxcachettl
;
55 unsigned int SyncRes::s_maxqperq
;
56 unsigned int SyncRes::s_maxtotusec
;
57 unsigned int SyncRes::s_maxdepth
;
58 unsigned int SyncRes::s_minimumTTL
;
59 unsigned int SyncRes::s_minimumECSTTL
;
60 unsigned int SyncRes::s_packetcachettl
;
61 unsigned int SyncRes::s_packetcacheservfailttl
;
62 unsigned int SyncRes::s_serverdownmaxfails
;
63 unsigned int SyncRes::s_serverdownthrottletime
;
64 unsigned int SyncRes::s_ecscachelimitttl
;
65 std::atomic
<uint64_t> SyncRes::s_authzonequeries
;
66 std::atomic
<uint64_t> SyncRes::s_queries
;
67 std::atomic
<uint64_t> SyncRes::s_outgoingtimeouts
;
68 std::atomic
<uint64_t> SyncRes::s_outgoing4timeouts
;
69 std::atomic
<uint64_t> SyncRes::s_outgoing6timeouts
;
70 std::atomic
<uint64_t> SyncRes::s_outqueries
;
71 std::atomic
<uint64_t> SyncRes::s_tcpoutqueries
;
72 std::atomic
<uint64_t> SyncRes::s_throttledqueries
;
73 std::atomic
<uint64_t> SyncRes::s_dontqueries
;
74 std::atomic
<uint64_t> SyncRes::s_nodelegated
;
75 std::atomic
<uint64_t> SyncRes::s_unreachables
;
76 std::atomic
<uint64_t> SyncRes::s_ecsqueries
;
77 std::atomic
<uint64_t> SyncRes::s_ecsresponses
;
78 std::map
<uint8_t, std::atomic
<uint64_t>> SyncRes::s_ecsResponsesBySubnetSize4
;
79 std::map
<uint8_t, std::atomic
<uint64_t>> SyncRes::s_ecsResponsesBySubnetSize6
;
81 uint8_t SyncRes::s_ecsipv4limit
;
82 uint8_t SyncRes::s_ecsipv6limit
;
83 uint8_t SyncRes::s_ecsipv4cachelimit
;
84 uint8_t SyncRes::s_ecsipv6cachelimit
;
86 bool SyncRes::s_doIPv6
;
87 bool SyncRes::s_nopacketcache
;
88 bool SyncRes::s_rootNXTrust
;
89 bool SyncRes::s_noEDNS
;
91 #define LOG(x) if(d_lm == Log) { g_log <<Logger::Warning << x; } else if(d_lm == Store) { d_trace << x; }
93 static void accountAuthLatency(int usec
, int family
)
95 if(family
== AF_INET
) {
97 g_stats
.auth4Answers0_1
++;
99 g_stats
.auth4Answers1_10
++;
100 else if(usec
< 100000)
101 g_stats
.auth4Answers10_100
++;
102 else if(usec
< 1000000)
103 g_stats
.auth4Answers100_1000
++;
105 g_stats
.auth4AnswersSlow
++;
108 g_stats
.auth6Answers0_1
++;
109 else if(usec
< 10000)
110 g_stats
.auth6Answers1_10
++;
111 else if(usec
< 100000)
112 g_stats
.auth6Answers10_100
++;
113 else if(usec
< 1000000)
114 g_stats
.auth6Answers100_1000
++;
116 g_stats
.auth6AnswersSlow
++;
122 SyncRes::SyncRes(const struct timeval
& now
) : d_authzonequeries(0), d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
123 d_totUsec(0), d_now(now
),
124 d_cacheonly(false), d_doDNSSEC(false), d_doEDNS0(false), d_lm(s_lm
)
129 /** everything begins here - this is the entry point just after receiving a packet */
130 int SyncRes::beginResolve(const DNSName
&qname
, const QType
&qtype
, uint16_t qclass
, vector
<DNSRecord
>&ret
)
132 vState state
= Indeterminate
;
135 d_wasOutOfBand
=false;
137 if (doSpecialNamesResolve(qname
, qtype
, qclass
, ret
)) {
138 d_queryValidationState
= Insecure
; // this could fool our stats into thinking a validation took place
139 return 0; // so do check before updating counters (we do now)
142 auto qtypeCode
= qtype
.getCode();
143 /* rfc6895 section 3.1 */
144 if ((qtypeCode
>= 128 && qtypeCode
<= 254) || qtypeCode
== QType::RRSIG
|| qtypeCode
== QType::NSEC3
|| qtypeCode
== QType::OPT
|| qtypeCode
== 65535) {
148 if(qclass
==QClass::ANY
)
150 else if(qclass
!=QClass::IN
)
153 set
<GetBestNSAnswer
> beenthere
;
154 int res
=doResolve(qname
, qtype
, ret
, 0, beenthere
, state
);
155 d_queryValidationState
= state
;
157 if (shouldValidate()) {
158 if (d_queryValidationState
!= Indeterminate
) {
159 g_stats
.dnssecValidations
++;
161 increaseDNSSECStateCounter(d_queryValidationState
);
167 /*! Handles all special, built-in names
168 * Fills ret with an answer and returns true if it handled the query.
170 * Handles the following queries (and their ANY variants):
173 * - localhost. IN AAAA
174 * - 1.0.0.127.in-addr.arpa. IN PTR
175 * - 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
176 * - version.bind. CH TXT
177 * - version.pdns. CH TXT
178 * - id.server. CH TXT
180 bool SyncRes::doSpecialNamesResolve(const DNSName
&qname
, const QType
&qtype
, const uint16_t qclass
, vector
<DNSRecord
> &ret
)
182 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."),
183 localhost("localhost."), versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns.");
185 bool handled
= false;
186 vector
<pair
<QType::typeenum
, string
> > answers
;
188 if ((qname
== arpa
|| qname
== ip6_arpa
) &&
189 qclass
== QClass::IN
) {
191 if (qtype
== QType::PTR
|| qtype
== QType::ANY
)
192 answers
.push_back({QType::PTR
, "localhost."});
195 if (qname
== localhost
&&
196 qclass
== QClass::IN
) {
198 if (qtype
== QType::A
|| qtype
== QType::ANY
)
199 answers
.push_back({QType::A
, "127.0.0.1"});
200 if (qtype
== QType::AAAA
|| qtype
== QType::ANY
)
201 answers
.push_back({QType::AAAA
, "::1"});
204 if ((qname
== versionbind
|| qname
== idserver
|| qname
== versionpdns
) &&
205 qclass
== QClass::CHAOS
) {
207 if (qtype
== QType::TXT
|| qtype
== QType::ANY
) {
208 if(qname
== versionbind
|| qname
== versionpdns
)
209 answers
.push_back({QType::TXT
, "\""+::arg()["version-string"]+"\""});
210 else if (s_serverID
!= "disabled")
211 answers
.push_back({QType::TXT
, "\""+s_serverID
+"\""});
215 if (handled
&& !answers
.empty()) {
221 dr
.d_place
= DNSResourceRecord::ANSWER
;
224 for (const auto& ans
: answers
) {
225 dr
.d_type
= ans
.first
;
226 dr
.d_content
= DNSRecordContent::mastermake(ans
.first
, qclass
, ans
.second
);
235 //! This is the 'out of band resolver', in other words, the authoritative server
236 void SyncRes::AuthDomain::addSOA(std::vector
<DNSRecord
>& records
) const
238 SyncRes::AuthDomain::records_t::const_iterator ziter
= d_records
.find(boost::make_tuple(getName(), QType::SOA
));
239 if (ziter
!= d_records
.end()) {
240 DNSRecord dr
= *ziter
;
241 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
242 records
.push_back(dr
);
245 // cerr<<qname<<": can't find SOA record '"<<getName()<<"' in our zone!"<<endl;
249 int SyncRes::AuthDomain::getRecords(const DNSName
& qname
, uint16_t qtype
, std::vector
<DNSRecord
>& records
) const
251 int result
= RCode::NoError
;
255 std::pair
<records_t::const_iterator
,records_t::const_iterator
> range
= d_records
.equal_range(tie(qname
));
257 SyncRes::AuthDomain::records_t::const_iterator ziter
;
258 bool somedata
= false;
260 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
263 if(qtype
== QType::ANY
|| ziter
->d_type
== qtype
|| ziter
->d_type
== QType::CNAME
) {
264 // let rest of nameserver do the legwork on this one
265 records
.push_back(*ziter
);
267 else if (ziter
->d_type
== QType::NS
&& ziter
->d_name
.countLabels() > getName().countLabels()) {
268 // we hit a delegation point!
269 DNSRecord dr
= *ziter
;
270 dr
.d_place
=DNSResourceRecord::AUTHORITY
;
271 records
.push_back(dr
);
275 if (!records
.empty()) {
276 /* We have found an exact match, we're done */
277 // cerr<<qname<<": exact match in zone '"<<getName()<<"'"<<endl;
282 /* We have records for that name, but not of the wanted qtype */
283 // cerr<<qname<<": found record in '"<<getName()<<"', but nothing of the right type, sending SOA"<<endl;
289 // cerr<<qname<<": nothing found so far in '"<<getName()<<"', trying wildcards"<<endl;
290 DNSName
wcarddomain(qname
);
291 while(wcarddomain
!= getName() && wcarddomain
.chopOff()) {
292 // cerr<<qname<<": trying '*."<<wcarddomain<<"' in "<<getName()<<endl;
293 range
= d_records
.equal_range(boost::make_tuple(g_wildcarddnsname
+ wcarddomain
));
294 if (range
.first
==range
.second
)
297 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
298 DNSRecord dr
= *ziter
;
299 // if we hit a CNAME, just answer that - rest of recursor will do the needful & follow
300 if(dr
.d_type
== qtype
|| qtype
== QType::ANY
|| dr
.d_type
== QType::CNAME
) {
302 dr
.d_place
= DNSResourceRecord::ANSWER
;
303 records
.push_back(dr
);
307 if (records
.empty()) {
311 // cerr<<qname<<": in '"<<getName()<<"', had wildcard match on '*."<<wcarddomain<<"'"<<endl;
315 /* Nothing for this name, no wildcard, let's see if there is some NS */
316 DNSName
nsdomain(qname
);
317 while (nsdomain
.chopOff() && nsdomain
!= getName()) {
318 range
= d_records
.equal_range(boost::make_tuple(nsdomain
,QType::NS
));
319 if(range
.first
== range
.second
)
322 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
323 DNSRecord dr
= *ziter
;
324 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
325 records
.push_back(dr
);
329 if(records
.empty()) {
330 // cerr<<qname<<": no NS match in zone '"<<getName()<<"' either, handing out SOA"<<endl;
332 result
= RCode::NXDomain
;
338 bool SyncRes::doOOBResolve(const AuthDomain
& domain
, const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, int& res
)
343 res
= domain
.getRecords(qname
, qtype
.getCode(), ret
);
347 bool SyncRes::doOOBResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int& res
)
352 prefix
.append(depth
, ' ');
355 DNSName
authdomain(qname
);
356 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
357 if(iter
==t_sstorage
.domainmap
->end() || !iter
->second
.isAuth()) {
358 LOG(prefix
<<qname
<<": auth storage has no zone for this query!"<<endl
);
362 LOG(prefix
<<qname
<<": auth storage has data, zone='"<<authdomain
<<"'"<<endl
);
363 return doOOBResolve(iter
->second
, qname
, qtype
, ret
, res
);
366 uint64_t SyncRes::doEDNSDump(int fd
)
368 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(dup(fd
), "w"), fclose
);
374 fprintf(fp
.get(),"; edns from thread follows\n;\n");
375 for(const auto& eds
: t_sstorage
.ednsstatus
) {
377 fprintf(fp
.get(), "%s\t%d\t%s", eds
.first
.toString().c_str(), (int)eds
.second
.mode
, ctime(&eds
.second
.modeSetAt
));
382 uint64_t SyncRes::doDumpNSSpeeds(int fd
)
384 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(dup(fd
), "w"), fclose
);
387 fprintf(fp
.get(), "; nsspeed dump from thread follows\n;\n");
390 for(const auto& i
: t_sstorage
.nsSpeeds
)
394 // an <empty> can appear hear in case of authoritative (hosted) zones
395 fprintf(fp
.get(), "%s -> ", i
.first
.toLogString().c_str());
396 for(const auto& j
: i
.second
.d_collection
)
398 // typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
399 fprintf(fp
.get(), "%s/%f ", j
.first
.toString().c_str(), j
.second
.peek());
401 fprintf(fp
.get(), "\n");
406 uint64_t SyncRes::doDumpThrottleMap(int fd
)
408 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(dup(fd
), "w"), fclose
);
411 fprintf(fp
.get(), "; throttle map dump follows\n");
412 fprintf(fp
.get(), "; remote IP\tqname\tqtype\tcount\tttd\n");
415 const auto& throttleMap
= t_sstorage
.throttle
.getThrottleMap();
416 for(const auto& i
: throttleMap
)
419 // remote IP, dns name, qtype, count, ttd
420 fprintf(fp
.get(), "%s\t%s\t%d\t%u\t%s", i
.first
.get
<0>().toString().c_str(), i
.first
.get
<1>().toLogString().c_str(), i
.first
.get
<2>(), i
.second
.count
, ctime(&i
.second
.ttd
));
426 /* so here is the story. First we complete the full resolution process for a domain name. And only THEN do we decide
427 to also do DNSSEC validation, which leads to new queries. To make this simple, we *always* ask for DNSSEC records
428 so that if there are RRSIGs for a name, we'll have them.
430 However, some hosts simply can't answer questions which ask for DNSSEC. This can manifest itself as:
435 The cause of "No answer" may be fragmentation, and it is tempting to probe if smaller answers would get through.
436 Another cause of "No answer" may simply be a network condition.
437 Nonsense answers are a clearer indication this host won't be able to do DNSSEC evah.
439 Previous implementations have suffered from turning off DNSSEC questions for an authoritative server based on timeouts.
440 A clever idea is to only turn off DNSSEC if we know a domain isn't signed anyhow. The problem with that really
441 clever idea however is that at this point in PowerDNS, we may simply not know that yet. All the DNSSEC thinking happens
442 elsewhere. It may not have happened yet.
444 For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish.
447 int SyncRes::asyncresolveWrapper(const ComboAddress
& ip
, bool ednsMANDATORY
, const DNSName
& domain
, int type
, bool doTCP
, bool sendRDQuery
, struct timeval
* now
, boost::optional
<Netmask
>& srcmask
, LWResult
* res
, bool* chained
) const
449 /* what is your QUEST?
450 the goal is to get as many remotes as possible on the highest level of EDNS support
453 0) UNKNOWN Unknown state
454 1) EDNS: Honors EDNS0
455 2) EDNSIGNORANT: Ignores EDNS0, gives replies without EDNS0
456 3) NOEDNS: Generates FORMERR on EDNS queries
458 Everybody starts out assumed to be '0'.
459 If '0', send out EDNS0
460 If you FORMERR us, go to '3',
461 If no EDNS in response, go to '2'
462 If '1', send out EDNS0
463 If FORMERR, downgrade to 3
464 If '2', keep on including EDNS0, see what happens
466 If '3', send bare queries
469 SyncRes::EDNSStatus
* ednsstatus
;
470 ednsstatus
= &t_sstorage
.ednsstatus
[ip
]; // does this include port? YES
472 if(ednsstatus
->modeSetAt
&& ednsstatus
->modeSetAt
+ 3600 < d_now
.tv_sec
) {
473 *ednsstatus
=SyncRes::EDNSStatus();
474 // cerr<<"Resetting EDNS Status for "<<ip.toString()<<endl);
477 SyncRes::EDNSStatus::EDNSMode
& mode
=ednsstatus
->mode
;
478 SyncRes::EDNSStatus::EDNSMode oldmode
= mode
;
480 auto luaconfsLocal
= g_luaconfs
.getLocal();
483 ctx
.d_initialRequestId
= d_initialRequestId
;
487 for(int tries
= 0; tries
< 3; ++tries
) {
488 // cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl;
490 if(mode
==EDNSStatus::NOEDNS
) {
491 g_stats
.noEdnsOutQueries
++;
492 EDNSLevel
= 0; // level != mode
494 else if(ednsMANDATORY
|| mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
==EDNSStatus::EDNSIGNORANT
)
497 DNSName
sendQname(domain
);
498 if (g_lowercaseOutgoing
)
499 sendQname
.makeUsLowerCase();
501 if (d_asyncResolve
) {
502 ret
= d_asyncResolve(ip
, sendQname
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, res
, chained
);
505 ret
=asyncresolve(ip
, sendQname
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, d_outgoingProtobufServers
, luaconfsLocal
->outgoingProtobufExportConfig
.exportTypes
, res
, chained
);
508 return ret
; // transport error, nothing to learn here
511 if(ret
== 0) { // timeout, not doing anything with it now
514 else if(mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
== EDNSStatus::EDNSIGNORANT
) {
515 if(res
->d_validpacket
&& !res
->d_haveEDNS
&& res
->d_rcode
== RCode::FormErr
) {
516 // cerr<<"Downgrading to NOEDNS because of "<<RCode::to_s(res->d_rcode)<<" for query to "<<ip.toString()<<" for '"<<domain<<"'"<<endl;
517 mode
= EDNSStatus::NOEDNS
;
520 else if(!res
->d_haveEDNS
) {
521 if(mode
!= EDNSStatus::EDNSIGNORANT
) {
522 mode
= EDNSStatus::EDNSIGNORANT
;
523 // cerr<<"We find that "<<ip.toString()<<" is an EDNS-ignorer for '"<<domain<<"', moving to mode 2"<<endl;
527 mode
= EDNSStatus::EDNSOK
;
528 // cerr<<"We find that "<<ip.toString()<<" is EDNS OK!"<<endl;
532 if(oldmode
!= mode
|| !ednsstatus
->modeSetAt
)
533 ednsstatus
->modeSetAt
=d_now
.tv_sec
;
534 // cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", new mode: "<<mode<<endl;
540 /*! This function will check the cache and go out to the internet if the answer is not in cache
542 * \param qname The name we need an answer for
544 * \param ret The vector of DNSRecords we need to fill with the answers
545 * \param depth The recursion depth we are in
547 * \return DNS RCODE or -1 (Error) or -2 (RPZ hit)
549 int SyncRes::doResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, vState
& state
)
554 prefix
.append(depth
, ' ');
557 LOG(prefix
<<qname
<<": Wants "<< (d_doDNSSEC
? "" : "NO ") << "DNSSEC processing, "<<(d_requireAuthData
? "" : "NO ")<<"auth data in query for "<<qtype
.getName()<<endl
);
559 state
= Indeterminate
;
561 if(s_maxdepth
&& depth
> s_maxdepth
)
562 throw ImmediateServFailException("More than "+std::to_string(s_maxdepth
)+" (max-recursion-depth) levels of recursion needed while resolving "+qname
.toLogString());
566 // This is a difficult way of expressing "this is a normal query", i.e. not getRootNS.
567 if(!(d_updatingRootNS
&& qtype
.getCode()==QType::NS
&& qname
.isRoot())) {
568 if(d_cacheonly
) { // very limited OOB support
570 LOG(prefix
<<qname
<<": Recursion not requested for '"<<qname
<<"|"<<qtype
.getName()<<"', peeking at auth/forward zones"<<endl
);
571 DNSName
authname(qname
);
572 domainmap_t::const_iterator iter
=getBestAuthZone(&authname
);
573 if(iter
!= t_sstorage
.domainmap
->end()) {
574 if(iter
->second
.isAuth()) {
576 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, ret
, depth
, res
);
580 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
581 const ComboAddress remoteIP
= servers
.front();
582 LOG(prefix
<<qname
<<": forwarding query to hardcoded nameserver '"<< remoteIP
.toStringWithPort()<<"' for zone '"<<authname
<<"'"<<endl
);
584 boost::optional
<Netmask
> nm
;
585 bool chained
= false;
586 res
=asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(), false, false, &d_now
, nm
, &lwr
, &chained
);
588 d_totUsec
+= lwr
.d_usec
;
589 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
591 // filter out the good stuff from lwr.result()
593 for(const auto& rec
: lwr
.d_records
) {
594 if(rec
.d_place
== DNSResourceRecord::ANSWER
)
600 return RCode::ServFail
;
606 DNSName
authname(qname
);
607 bool wasForwardedOrAuthZone
= false;
608 bool wasAuthZone
= false;
609 bool wasForwardRecurse
= false;
610 domainmap_t::const_iterator iter
= getBestAuthZone(&authname
);
611 if(iter
!= t_sstorage
.domainmap
->end()) {
612 const auto& domain
= iter
->second
;
613 wasForwardedOrAuthZone
= true;
615 if (domain
.isAuth()) {
617 } else if (domain
.shouldRecurse()) {
618 wasForwardRecurse
= true;
622 if(!d_skipCNAMECheck
&& doCNAMECacheCheck(qname
, qtype
, ret
, depth
, res
, state
, wasAuthZone
, wasForwardRecurse
)) { // will reroute us if needed
623 d_wasOutOfBand
= wasAuthZone
;
627 if(doCacheCheck(qname
, authname
, wasForwardedOrAuthZone
, wasAuthZone
, wasForwardRecurse
, qtype
, ret
, depth
, res
, state
)) {
629 d_wasOutOfBand
= wasAuthZone
;
637 LOG(prefix
<<qname
<<": No cache hit for '"<<qname
<<"|"<<qtype
.getName()<<"', trying to find an appropriate NS record"<<endl
);
639 DNSName
subdomain(qname
);
640 if(qtype
== QType::DS
) subdomain
.chopOff();
643 bool flawedNSSet
=false;
645 /* we use subdomain here instead of qname because for DS queries we only care about the state of the parent zone */
646 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
648 // the two retries allow getBestNSNamesFromCache&co to reprime the root
649 // hints, in case they ever go missing
650 for(int tries
=0;tries
<2 && nsset
.empty();++tries
) {
651 subdomain
=getBestNSNamesFromCache(subdomain
, qtype
, nsset
, &flawedNSSet
, depth
, beenthere
); // pass beenthere to both occasions
654 state
= getValidationStatus(qname
, false);
656 LOG(prefix
<<qname
<<": initial validation status for "<<qname
<<" is "<<vStates
[state
]<<endl
);
658 if(!(res
=doResolveAt(nsset
, subdomain
, flawedNSSet
, qname
, qtype
, ret
, depth
, beenthere
, state
)))
661 LOG(prefix
<<qname
<<": failed (res="<<res
<<")"<<endl
);
666 return res
<0 ? RCode::ServFail
: res
;
670 // for testing purposes
671 static bool ipv6First(const ComboAddress
& a
, const ComboAddress
& b
)
673 return !(a
.sin4
.sin_family
< a
.sin4
.sin_family
);
679 speedOrderCA(std::map
<ComboAddress
,double>& speeds
): d_speeds(speeds
) {}
680 bool operator()(const ComboAddress
& a
, const ComboAddress
& b
) const
682 return d_speeds
[a
] < d_speeds
[b
];
684 std::map
<ComboAddress
, double>& d_speeds
;
687 /** This function explicitly goes out for A or AAAA addresses
689 vector
<ComboAddress
> SyncRes::getAddrs(const DNSName
&qname
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, bool cacheOnly
)
691 typedef vector
<DNSRecord
> res_t
;
694 typedef vector
<ComboAddress
> ret_t
;
698 bool oldCacheOnly
= d_cacheonly
;
699 bool oldRequireAuthData
= d_requireAuthData
;
700 bool oldValidationRequested
= d_DNSSECValidationRequested
;
701 d_requireAuthData
= false;
702 d_DNSSECValidationRequested
= false;
703 d_cacheonly
= cacheOnly
;
705 for(int j
=1; j
<2+s_doIPv6
; j
++)
720 vState newState
= Indeterminate
;
721 if(!doResolve(qname
, type
, res
,depth
+1, beenthere
, newState
) && !res
.empty()) { // this consults cache, OR goes out
722 for(res_t::const_iterator i
=res
.begin(); i
!= res
.end(); ++i
) {
723 if(i
->d_type
== QType::A
|| i
->d_type
== QType::AAAA
) {
724 if(auto rec
= getRR
<ARecordContent
>(*i
))
725 ret
.push_back(rec
->getCA(53));
726 else if(auto aaaarec
= getRR
<AAAARecordContent
>(*i
))
727 ret
.push_back(aaaarec
->getCA(53));
733 if(j
==1 && s_doIPv6
) { // we got an A record, see if we have some AAAA lying around
734 vector
<DNSRecord
> cset
;
735 if(t_RC
->get(d_now
.tv_sec
, qname
, QType(QType::AAAA
), false, &cset
, d_cacheRemote
) > 0) {
736 for(auto k
=cset
.cbegin();k
!=cset
.cend();++k
) {
737 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
738 if (auto drc
= getRR
<AAAARecordContent
>(*k
)) {
739 ComboAddress ca
=drc
->getCA(53);
750 d_requireAuthData
= oldRequireAuthData
;
751 d_DNSSECValidationRequested
= oldValidationRequested
;
752 d_cacheonly
= oldCacheOnly
;
754 /* we need to remove from the nsSpeeds collection the existing IPs
755 for this nameserver that are no longer in the set, even if there
756 is only one or none at all in the current set.
758 map
<ComboAddress
, double> speeds
;
759 auto& collection
= t_sstorage
.nsSpeeds
[qname
].d_collection
;
760 for(const auto& val
: ret
) {
761 speeds
[val
] = collection
[val
].get(&d_now
);
764 t_sstorage
.nsSpeeds
[qname
].purge(speeds
);
767 random_shuffle(ret
.begin(), ret
.end(), dns_random
);
768 speedOrderCA
so(speeds
);
769 stable_sort(ret
.begin(), ret
.end(), so
);
772 string prefix
=d_prefix
;
773 prefix
.append(depth
, ' ');
774 LOG(prefix
<<"Nameserver "<<qname
<<" IPs: ");
776 for(const auto& addr
: ret
) {
783 LOG((addr
.toString())<<"(" << (boost::format("%0.2f") % (speeds
[addr
]/1000.0)).str() <<"ms)");
792 void SyncRes::getBestNSFromCache(const DNSName
&qname
, const QType
& qtype
, vector
<DNSRecord
>& bestns
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
)
795 DNSName
subdomain(qname
);
798 prefix
.append(depth
, ' ');
804 LOG(prefix
<<qname
<<": Checking if we have NS in cache for '"<<subdomain
<<"'"<<endl
);
805 vector
<DNSRecord
> ns
;
806 *flawedNSSet
= false;
808 if(t_RC
->get(d_now
.tv_sec
, subdomain
, QType(QType::NS
), false, &ns
, d_cacheRemote
) > 0) {
809 for(auto k
=ns
.cbegin();k
!=ns
.cend(); ++k
) {
810 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
811 vector
<DNSRecord
> aset
;
813 const DNSRecord
& dr
=*k
;
814 auto nrr
= getRR
<NSRecordContent
>(dr
);
815 if(nrr
&& (!nrr
->getNS().isPartOf(subdomain
) || t_RC
->get(d_now
.tv_sec
, nrr
->getNS(), s_doIPv6
? QType(QType::ADDR
) : QType(QType::A
),
816 false, doLog() ? &aset
: 0, d_cacheRemote
) > 5)) {
817 bestns
.push_back(dr
);
818 LOG(prefix
<<qname
<<": NS (with ip, or non-glue) in cache for '"<<subdomain
<<"' -> '"<<nrr
->getNS()<<"'"<<endl
);
819 LOG(prefix
<<qname
<<": within bailiwick: "<< nrr
->getNS().isPartOf(subdomain
));
821 LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset
.begin()->d_ttl
- d_now
.tv_sec
))<<endl
);
824 LOG(", not in cache / did not look at cache"<<endl
);
829 LOG(prefix
<<qname
<<": NS in cache for '"<<subdomain
<<"', but needs glue ("<<nrr
->getNS()<<") which we miss or is expired"<<endl
);
834 if(!bestns
.empty()) {
835 GetBestNSAnswer answer
;
837 answer
.qtype
=qtype
.getCode();
838 for(const auto& dr
: bestns
) {
839 if (auto nsContent
= getRR
<NSRecordContent
>(dr
)) {
840 answer
.bestns
.insert(make_pair(dr
.d_name
, nsContent
->getNS()));
844 if(beenthere
.count(answer
)) {
846 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' but part of LOOP (already seen "<<answer
.qname
<<")! Trying less specific NS"<<endl
);
849 for( set
<GetBestNSAnswer
>::const_iterator j
=beenthere
.begin();j
!=beenthere
.end();++j
) {
850 bool neo
= !(*j
< answer
|| answer
<*j
);
851 LOG(prefix
<<qname
<<": beenthere"<<(neo
?"*":"")<<": "<<j
->qname
<<"|"<<DNSRecordContent::NumberToType(j
->qtype
)<<" ("<<(unsigned int)j
->bestns
.size()<<")"<<endl
);
856 beenthere
.insert(answer
);
857 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' (flawedNSSet="<<*flawedNSSet
<<")"<<endl
);
862 LOG(prefix
<<qname
<<": no valid/useful NS in cache for '"<<subdomain
<<"'"<<endl
);
864 if(subdomain
.isRoot() && !brokeloop
) {
865 // We lost the root NS records
867 LOG(prefix
<<qname
<<": reprimed the root"<<endl
);
868 /* let's prevent an infinite loop */
869 if (!d_updatingRootNS
) {
870 getRootNS(d_now
, d_asyncResolve
);
873 } while(subdomain
.chopOff());
876 SyncRes::domainmap_t::const_iterator
SyncRes::getBestAuthZone(DNSName
* qname
) const
878 SyncRes::domainmap_t::const_iterator ret
;
880 ret
=t_sstorage
.domainmap
->find(*qname
);
881 if(ret
!=t_sstorage
.domainmap
->end())
883 }while(qname
->chopOff());
887 /** doesn't actually do the work, leaves that to getBestNSFromCache */
888 DNSName
SyncRes::getBestNSNamesFromCache(const DNSName
&qname
, const QType
& qtype
, NsSet
& nsset
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
)
890 DNSName
subdomain(qname
);
891 DNSName
authdomain(qname
);
893 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
894 if(iter
!=t_sstorage
.domainmap
->end()) {
895 if( iter
->second
.isAuth() )
896 // this gets picked up in doResolveAt, the empty DNSName, combined with the
897 // empty vector means 'we are auth for this zone'
898 nsset
.insert({DNSName(), {{}, false}});
900 // Again, picked up in doResolveAt. An empty DNSName, combined with a
901 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
902 // This is actually picked up in retrieveAddressesForNS called from doResolveAt.
903 nsset
.insert({DNSName(), {iter
->second
.d_servers
, iter
->second
.shouldRecurse() }});
908 vector
<DNSRecord
> bestns
;
909 getBestNSFromCache(subdomain
, qtype
, bestns
, flawedNSSet
, depth
, beenthere
);
911 for(auto k
=bestns
.cbegin() ; k
!= bestns
.cend(); ++k
) {
912 // The actual resolver code will not even look at the ComboAddress or bool
913 const auto nsContent
= getRR
<NSRecordContent
>(*k
);
915 nsset
.insert({nsContent
->getNS(), {{}, false}});
916 if(k
==bestns
.cbegin())
923 void SyncRes::updateValidationStatusInCache(const DNSName
&qname
, const QType
& qt
, bool aa
, vState newState
) const
925 if (newState
== Bogus
) {
926 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qt
, d_cacheRemote
, aa
, newState
, s_maxbogusttl
+ d_now
.tv_sec
);
929 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qt
, d_cacheRemote
, aa
, newState
, boost::none
);
933 bool SyncRes::doCNAMECacheCheck(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>& ret
, unsigned int depth
, int &res
, vState
& state
, bool wasAuthZone
, bool wasForwardRecurse
)
938 prefix
.append(depth
, ' ');
941 if((depth
>9 && d_outqueries
>10 && d_throttledqueries
>5) || depth
> 15) {
942 LOG(prefix
<<qname
<<": recursing (CNAME or other indirection) too deep, depth="<<depth
<<endl
);
947 vector
<DNSRecord
> cset
;
948 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
949 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
951 uint32_t capTTL
= std::numeric_limits
<uint32_t>::max();
953 QType foundQT
= QType(0); // 0 == QTYPE::ENT
955 LOG(prefix
<<qname
<<": Looking for CNAME cache hit of '"<<qname
<<"|CNAME"<<"'"<<endl
);
956 /* we don't require auth data for forward-recurse lookups */
957 if (t_RC
->get(d_now
.tv_sec
, qname
, QType(QType::CNAME
), !wasForwardRecurse
&& d_requireAuthData
, &cset
, d_cacheRemote
, d_doDNSSEC
? &signatures
: nullptr, d_doDNSSEC
? &authorityRecs
: nullptr, &d_wasVariable
, &state
, &wasAuth
) > 0) {
959 foundQT
= QType(QType::CNAME
);
962 if (foundName
.empty() && qname
!= g_rootdnsname
) {
963 // look for a DNAME cache hit
964 auto labels
= qname
.getRawLabels();
965 DNSName
dnameName(g_rootdnsname
);
968 dnameName
.prependRawLabel(labels
.back());
970 if (dnameName
== qname
&& qtype
!= QType::DNAME
) { // The client does not want a DNAME, but we've reached the QNAME already. So there is no match
973 LOG(prefix
<<qname
<<": Looking for DNAME cache hit of '"<<dnameName
<<"|DNAME"<<"'"<<endl
);
974 if (t_RC
->get(d_now
.tv_sec
, dnameName
, QType(QType::DNAME
), !wasForwardRecurse
&& d_requireAuthData
, &cset
, d_cacheRemote
, d_doDNSSEC
? &signatures
: nullptr, d_doDNSSEC
? &authorityRecs
: nullptr, &d_wasVariable
, &state
, &wasAuth
) > 0) {
975 foundName
= dnameName
;
976 foundQT
= QType(QType::DNAME
);
979 } while(!labels
.empty());
982 if(!foundName
.empty()) {
983 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
984 if (j
->d_class
!= QClass::IN
) {
988 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
990 if (!wasAuthZone
&& shouldValidate() && (wasAuth
|| wasForwardRecurse
) && state
== Indeterminate
&& d_requireAuthData
) {
991 /* This means we couldn't figure out the state when this entry was cached,
992 most likely because we hadn't computed the zone cuts yet. */
993 /* make sure they are computed before validating */
994 DNSName
subdomain(foundName
);
995 /* if we are retrieving a DS, we only care about the state of the parent zone */
996 if(qtype
== QType::DS
)
999 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1001 vState recordState
= getValidationStatus(foundName
, false);
1002 if (recordState
== Secure
) {
1003 LOG(prefix
<<qname
<<": got Indeterminate state from the "<<foundQT
.getName()<<" cache, validating.."<<endl
);
1004 state
= SyncRes::validateRecordsWithSigs(depth
, foundName
, foundQT
, foundName
, cset
, signatures
);
1005 if (state
!= Indeterminate
) {
1006 LOG(prefix
<<qname
<<": got Indeterminate state from the CNAME cache, new validation result is "<<vStates
[state
]<<endl
);
1007 if (state
== Bogus
) {
1008 capTTL
= s_maxbogusttl
;
1010 updateValidationStatusInCache(foundName
, foundQT
, wasAuth
, state
);
1015 LOG(prefix
<<qname
<<": Found cache "<<foundQT
.getName()<<" hit for '"<< foundName
<< "|"<<foundQT
.getName()<<"' to '"<<j
->d_content
->getZoneRepresentation()<<"', validation state is "<<vStates
[state
]<<endl
);
1018 dr
.d_ttl
-= d_now
.tv_sec
;
1019 dr
.d_ttl
= std::min(dr
.d_ttl
, capTTL
);
1020 const uint32_t ttl
= dr
.d_ttl
;
1021 ret
.reserve(ret
.size() + 2 + signatures
.size() + authorityRecs
.size());
1024 for(const auto& signature
: signatures
) {
1026 sigdr
.d_type
=QType::RRSIG
;
1027 sigdr
.d_name
=foundName
;
1029 sigdr
.d_content
=signature
;
1030 sigdr
.d_place
=DNSResourceRecord::ANSWER
;
1031 sigdr
.d_class
=QClass::IN
;
1032 ret
.push_back(sigdr
);
1035 for(const auto& rec
: authorityRecs
) {
1036 DNSRecord
authDR(*rec
);
1038 ret
.push_back(authDR
);
1042 if (foundQT
== QType::DNAME
) {
1043 if (qtype
== QType::DNAME
&& qname
== foundName
) { // client wanted the DNAME, no need to synthesize a CNAME
1047 // Synthesize a CNAME
1048 auto dnameRR
= getRR
<DNAMERecordContent
>(*j
);
1049 if (dnameRR
== nullptr) {
1050 throw ImmediateServFailException("Unable to get record content for "+foundName
.toLogString()+"|DNAME cache entry");
1052 const auto& dnameSuffix
= dnameRR
->getTarget();
1053 DNSName targetPrefix
= qname
.makeRelative(foundName
);
1055 dr
.d_type
= QType::CNAME
;
1056 dr
.d_name
= targetPrefix
+ foundName
;
1057 newTarget
= targetPrefix
+ dnameSuffix
;
1058 dr
.d_content
= std::make_shared
<CNAMERecordContent
>(CNAMERecordContent(newTarget
));
1060 } catch (const std::exception
&e
) {
1061 // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
1062 // But this is consistent with processRecords
1063 throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + foundName
.toLogString() +
1064 "', DNAME target: '" + dnameSuffix
.toLogString() + "', substituted name: '" +
1065 targetPrefix
.toLogString() + "." + dnameSuffix
.toLogString() +
1069 LOG(prefix
<<qname
<<": Synthesized "<<dr
.d_name
<<"|CNAME "<<newTarget
<<endl
);
1072 if(qtype
== QType::CNAME
) { // perhaps they really wanted a CNAME!
1077 // We have a DNAME _or_ CNAME cache hit and the client wants something else than those two.
1078 // Let's find the answer!
1079 if (foundQT
== QType::CNAME
) {
1080 const auto cnameContent
= getRR
<CNAMERecordContent
>(*j
);
1081 if (cnameContent
== nullptr) {
1082 throw ImmediateServFailException("Unable to get record content for "+foundName
.toLogString()+"|CNAME cache entry");
1084 newTarget
= cnameContent
->getTarget();
1087 set
<GetBestNSAnswer
>beenthere
;
1088 vState cnameState
= Indeterminate
;
1089 res
= doResolve(newTarget
, qtype
, ret
, depth
+1, beenthere
, cnameState
);
1090 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the DNAME/CNAME quest: "<<vStates
[cnameState
]<<endl
);
1091 updateValidationState(state
, cnameState
);
1097 LOG(prefix
<<qname
<<": No CNAME or DNAME cache hit of '"<< qname
<<"' found"<<endl
);
1104 vector
<DNSRecord
> records
;
1105 vector
<shared_ptr
<RRSIGRecordContent
>> signatures
;
1106 uint32_t signaturesTTL
{std::numeric_limits
<uint32_t>::max()};
1112 DNSResourceRecord::Place place
;
1113 bool operator<(const CacheKey
& rhs
) const {
1114 return tie(name
, type
, place
) < tie(rhs
.name
, rhs
.type
, rhs
.place
);
1117 typedef map
<CacheKey
, CacheEntry
> tcache_t
;
1120 static void reapRecordsFromNegCacheEntryForValidation(tcache_t
& tcache
, const vector
<DNSRecord
>& records
)
1122 for (const auto& rec
: records
) {
1123 if (rec
.d_type
== QType::RRSIG
) {
1124 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1126 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
1129 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(rec
);
1135 * Convience function to push the records from records into ret with a new TTL
1137 * \param records DNSRecords that need to go into ret
1138 * \param ttl The new TTL for these records
1139 * \param ret The vector of DNSRecords that should contian the records with the modified TTL
1141 static void addTTLModifiedRecords(const vector
<DNSRecord
>& records
, const uint32_t ttl
, vector
<DNSRecord
>& ret
) {
1142 for (const auto& rec
: records
) {
1149 void SyncRes::computeNegCacheValidationStatus(const NegCache::NegCacheEntry
* ne
, const DNSName
& qname
, const QType
& qtype
, const int res
, vState
& state
, unsigned int depth
)
1151 DNSName
subdomain(qname
);
1152 /* if we are retrieving a DS, we only care about the state of the parent zone */
1153 if(qtype
== QType::DS
)
1154 subdomain
.chopOff();
1156 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1159 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->authoritySOA
.records
);
1160 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->authoritySOA
.signatures
);
1161 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->DNSSECRecords
.records
);
1162 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->DNSSECRecords
.signatures
);
1164 for (const auto& entry
: tcache
) {
1165 // this happens when we did store signatures, but passed on the records themselves
1166 if (entry
.second
.records
.empty()) {
1170 const DNSName
& owner
= entry
.first
.name
;
1172 vState recordState
= getValidationStatus(owner
, false);
1173 if (state
== Indeterminate
) {
1174 state
= recordState
;
1177 if (recordState
== Secure
) {
1178 recordState
= SyncRes::validateRecordsWithSigs(depth
, qname
, qtype
, owner
, entry
.second
.records
, entry
.second
.signatures
);
1181 if (recordState
!= Indeterminate
&& recordState
!= state
) {
1182 updateValidationState(state
, recordState
);
1183 if (state
!= Secure
) {
1189 if (state
== Secure
) {
1190 vState neValidationState
= ne
->d_validationState
;
1191 dState expectedState
= res
== RCode::NXDomain
? NXDOMAIN
: NXQTYPE
;
1192 dState denialState
= getDenialValidationState(*ne
, state
, expectedState
, false);
1193 updateDenialValidationState(neValidationState
, ne
->d_name
, state
, denialState
, expectedState
, qtype
== QType::DS
);
1195 if (state
!= Indeterminate
) {
1196 /* validation succeeded, let's update the cache entry so we don't have to validate again */
1197 boost::optional
<uint32_t> capTTD
= boost::none
;
1198 if (state
== Bogus
) {
1199 capTTD
= d_now
.tv_sec
+ s_maxbogusttl
;
1201 t_sstorage
.negcache
.updateValidationStatus(ne
->d_name
, ne
->d_qtype
, state
, capTTD
);
1205 bool SyncRes::doCacheCheck(const DNSName
&qname
, const DNSName
& authname
, bool wasForwardedOrAuthZone
, bool wasAuthZone
, bool wasForwardRecurse
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int &res
, vState
& state
)
1207 bool giveNegative
=false;
1212 prefix
.append(depth
, ' ');
1215 // 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)
1216 DNSName
sqname(qname
);
1219 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
1221 const NegCache::NegCacheEntry
* ne
= nullptr;
1224 t_sstorage
.negcache
.getRootNXTrust(qname
, d_now
, &ne
) &&
1225 ne
->d_auth
.isRoot() &&
1226 !(wasForwardedOrAuthZone
&& !authname
.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
1227 sttl
= ne
->d_ttd
- d_now
.tv_sec
;
1228 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
->d_auth
<<"' & '"<<ne
->d_name
<<"' for another "<<sttl
<<" seconds"<<endl
);
1229 res
= RCode::NXDomain
;
1230 giveNegative
= true;
1231 cachedState
= ne
->d_validationState
;
1233 else if (t_sstorage
.negcache
.get(qname
, qtype
, d_now
, &ne
)) {
1234 /* If we are looking for a DS, discard NXD if auth == qname
1235 and ask for a specific denial instead */
1236 if (qtype
!= QType::DS
|| ne
->d_qtype
.getCode() || ne
->d_auth
!= qname
||
1237 t_sstorage
.negcache
.get(qname
, qtype
, d_now
, &ne
, true))
1240 sttl
= ne
->d_ttd
- d_now
.tv_sec
;
1241 giveNegative
= true;
1242 cachedState
= ne
->d_validationState
;
1243 if(ne
->d_qtype
.getCode()) {
1244 LOG(prefix
<<qname
<<": "<<qtype
.getName()<<" is negatively cached via '"<<ne
->d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1245 res
= RCode::NoError
;
1248 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
->d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1249 res
= RCode::NXDomain
;
1256 state
= cachedState
;
1258 if (!wasAuthZone
&& shouldValidate() && state
== Indeterminate
) {
1259 LOG(prefix
<<qname
<<": got Indeterminate state for records retrieved from the negative cache, validating.."<<endl
);
1260 computeNegCacheValidationStatus(ne
, qname
, qtype
, res
, state
, depth
);
1262 if (state
!= cachedState
&& state
== Bogus
) {
1263 sttl
= std::min(sttl
, s_maxbogusttl
);
1267 // Transplant SOA to the returned packet
1268 addTTLModifiedRecords(ne
->authoritySOA
.records
, sttl
, ret
);
1270 addTTLModifiedRecords(ne
->authoritySOA
.signatures
, sttl
, ret
);
1271 addTTLModifiedRecords(ne
->DNSSECRecords
.records
, sttl
, ret
);
1272 addTTLModifiedRecords(ne
->DNSSECRecords
.signatures
, sttl
, ret
);
1275 LOG(prefix
<<qname
<<": updating validation state with negative cache content for "<<qname
<<" to "<<vStates
[state
]<<endl
);
1279 vector
<DNSRecord
> cset
;
1280 bool found
=false, expired
=false;
1281 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
1282 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1284 uint32_t capTTL
= std::numeric_limits
<uint32_t>::max();
1286 if(t_RC
->get(d_now
.tv_sec
, sqname
, sqt
, !wasForwardRecurse
&& d_requireAuthData
, &cset
, d_cacheRemote
, d_doDNSSEC
? &signatures
: nullptr, d_doDNSSEC
? &authorityRecs
: nullptr, &d_wasVariable
, &cachedState
, &wasCachedAuth
) > 0) {
1288 LOG(prefix
<<sqname
<<": Found cache hit for "<<sqt
.getName()<<": ");
1290 if (!wasAuthZone
&& shouldValidate() && (wasCachedAuth
|| wasForwardRecurse
) && cachedState
== Indeterminate
&& d_requireAuthData
) {
1292 /* This means we couldn't figure out the state when this entry was cached,
1293 most likely because we hadn't computed the zone cuts yet. */
1294 /* make sure they are computed before validating */
1295 DNSName
subdomain(sqname
);
1296 /* if we are retrieving a DS, we only care about the state of the parent zone */
1297 if(qtype
== QType::DS
)
1298 subdomain
.chopOff();
1300 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1302 vState recordState
= getValidationStatus(qname
, false);
1303 if (recordState
== Secure
) {
1304 LOG(prefix
<<sqname
<<": got Indeterminate state from the cache, validating.."<<endl
);
1305 cachedState
= SyncRes::validateRecordsWithSigs(depth
, sqname
, sqt
, sqname
, cset
, signatures
);
1308 cachedState
= recordState
;
1311 if (cachedState
!= Indeterminate
) {
1312 LOG(prefix
<<qname
<<": got Indeterminate state from the cache, validation result is "<<vStates
[cachedState
]<<endl
);
1313 if (cachedState
== Bogus
) {
1314 capTTL
= s_maxbogusttl
;
1316 updateValidationStatusInCache(sqname
, sqt
, wasCachedAuth
, cachedState
);
1320 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
1322 LOG(j
->d_content
->getZoneRepresentation());
1324 if (j
->d_class
!= QClass::IN
) {
1328 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
1330 dr
.d_ttl
-= d_now
.tv_sec
;
1331 dr
.d_ttl
= std::min(dr
.d_ttl
, capTTL
);
1334 LOG("[ttl="<<dr
.d_ttl
<<"] ");
1343 ret
.reserve(ret
.size() + signatures
.size() + authorityRecs
.size());
1345 for(const auto& signature
: signatures
) {
1347 dr
.d_type
=QType::RRSIG
;
1350 dr
.d_content
=signature
;
1351 dr
.d_place
= DNSResourceRecord::ANSWER
;
1352 dr
.d_class
=QClass::IN
;
1356 for(const auto& rec
: authorityRecs
) {
1363 if(found
&& !expired
) {
1366 LOG(prefix
<<qname
<<": updating validation state with cache content for "<<qname
<<" to "<<vStates
[cachedState
]<<endl
);
1367 state
= cachedState
;
1371 LOG(prefix
<<qname
<<": cache had only stale entries"<<endl
);
1377 bool SyncRes::moreSpecificThan(const DNSName
& a
, const DNSName
&b
) const
1379 return (a
.isPartOf(b
) && a
.countLabels() > b
.countLabels());
1384 speedOrder(map
<DNSName
,double> &speeds
) : d_speeds(speeds
) {}
1385 bool operator()(const DNSName
&a
, const DNSName
&b
) const
1387 return d_speeds
[a
] < d_speeds
[b
];
1389 map
<DNSName
, double>& d_speeds
;
1392 inline vector
<DNSName
> SyncRes::shuffleInSpeedOrder(NsSet
&tnameservers
, const string
&prefix
)
1394 vector
<DNSName
> rnameservers
;
1395 rnameservers
.reserve(tnameservers
.size());
1396 for(const auto& tns
: tnameservers
) {
1397 rnameservers
.push_back(tns
.first
);
1398 if(tns
.first
.empty()) // this was an authoritative OOB zone, don't pollute the nsSpeeds with that
1399 return rnameservers
;
1401 map
<DNSName
, double> speeds
;
1403 for(const auto& val
: rnameservers
) {
1405 speed
=t_sstorage
.nsSpeeds
[val
].get(&d_now
);
1408 random_shuffle(rnameservers
.begin(),rnameservers
.end(), dns_random
);
1409 speedOrder
so(speeds
);
1410 stable_sort(rnameservers
.begin(),rnameservers
.end(), so
);
1413 LOG(prefix
<<"Nameservers: ");
1414 for(vector
<DNSName
>::const_iterator i
=rnameservers
.begin();i
!=rnameservers
.end();++i
) {
1415 if(i
!=rnameservers
.begin()) {
1417 if(!((i
-rnameservers
.begin())%3)) {
1418 LOG(endl
<<prefix
<<" ");
1421 LOG(i
->toLogString()<<"(" << (boost::format("%0.2f") % (speeds
[*i
]/1000.0)).str() <<"ms)");
1425 return rnameservers
;
1428 inline vector
<ComboAddress
> SyncRes::shuffleForwardSpeed(const vector
<ComboAddress
> &rnameservers
, const string
&prefix
, const bool wasRd
)
1430 vector
<ComboAddress
> nameservers
= rnameservers
;
1431 map
<ComboAddress
, double> speeds
;
1433 for(const auto& val
: nameservers
) {
1435 DNSName nsName
= DNSName(val
.toStringWithPort());
1436 speed
=t_sstorage
.nsSpeeds
[nsName
].get(&d_now
);
1439 random_shuffle(nameservers
.begin(),nameservers
.end(), dns_random
);
1440 speedOrderCA
so(speeds
);
1441 stable_sort(nameservers
.begin(),nameservers
.end(), so
);
1444 LOG(prefix
<<"Nameservers: ");
1445 for(vector
<ComboAddress
>::const_iterator i
=nameservers
.cbegin();i
!=nameservers
.cend();++i
) {
1446 if(i
!=nameservers
.cbegin()) {
1448 if(!((i
-nameservers
.cbegin())%3)) {
1449 LOG(endl
<<prefix
<<" ");
1452 LOG((wasRd
? string("+") : string("-")) << i
->toStringWithPort() <<"(" << (boost::format("%0.2f") % (speeds
[*i
]/1000.0)).str() <<"ms)");
1459 static uint32_t getRRSIGTTL(const time_t now
, const std::shared_ptr
<RRSIGRecordContent
>& rrsig
)
1462 if (now
< rrsig
->d_sigexpire
) {
1463 res
= static_cast<uint32_t>(rrsig
->d_sigexpire
) - now
;
1468 static const set
<uint16_t> nsecTypes
= {QType::NSEC
, QType::NSEC3
};
1470 /* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
1472 * \param records The records to parse for the authority SOA and NSEC(3) records
1473 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
1475 static void harvestNXRecords(const vector
<DNSRecord
>& records
, NegCache::NegCacheEntry
& ne
, const time_t now
, uint32_t* lowestTTL
) {
1476 for(const auto& rec
: records
) {
1477 if(rec
.d_place
!= DNSResourceRecord::AUTHORITY
)
1478 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
1479 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
1480 // records MUST be in the same section as the records they cover.
1481 // Hence, we ignore all records outside of the AUTHORITY section.
1484 if(rec
.d_type
== QType::RRSIG
) {
1485 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1487 if(rrsig
->d_type
== QType::SOA
) {
1488 ne
.authoritySOA
.signatures
.push_back(rec
);
1489 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1490 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1491 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1494 if(nsecTypes
.count(rrsig
->d_type
)) {
1495 ne
.DNSSECRecords
.signatures
.push_back(rec
);
1496 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1497 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1498 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1504 if(rec
.d_type
== QType::SOA
) {
1505 ne
.authoritySOA
.records
.push_back(rec
);
1507 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1511 if(nsecTypes
.count(rec
.d_type
)) {
1512 ne
.DNSSECRecords
.records
.push_back(rec
);
1514 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1521 static cspmap_t
harvestCSPFromNE(const NegCache::NegCacheEntry
& ne
)
1524 for(const auto& rec
: ne
.DNSSECRecords
.signatures
) {
1525 if(rec
.d_type
== QType::RRSIG
) {
1526 auto rrc
= getRR
<RRSIGRecordContent
>(rec
);
1528 cspmap
[{rec
.d_name
,rrc
->d_type
}].signatures
.push_back(rrc
);
1532 for(const auto& rec
: ne
.DNSSECRecords
.records
) {
1533 cspmap
[{rec
.d_name
, rec
.d_type
}].records
.push_back(rec
.d_content
);
1538 // TODO remove after processRecords is fixed!
1539 // Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
1540 static void addNXNSECS(vector
<DNSRecord
>&ret
, const vector
<DNSRecord
>& records
)
1542 NegCache::NegCacheEntry ne
;
1543 harvestNXRecords(records
, ne
, 0, nullptr);
1544 ret
.insert(ret
.end(), ne
.authoritySOA
.signatures
.begin(), ne
.authoritySOA
.signatures
.end());
1545 ret
.insert(ret
.end(), ne
.DNSSECRecords
.records
.begin(), ne
.DNSSECRecords
.records
.end());
1546 ret
.insert(ret
.end(), ne
.DNSSECRecords
.signatures
.begin(), ne
.DNSSECRecords
.signatures
.end());
1549 bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine
& dfe
, const NsSet
& nameservers
)
1552 for (auto const &ns
: nameservers
) {
1553 d_appliedPolicy
= dfe
.getProcessingPolicy(ns
.first
, d_discardedPolicies
);
1554 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1555 LOG(", however nameserver "<<ns
.first
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1559 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1560 for (auto const &address
: ns
.second
.first
) {
1561 d_appliedPolicy
= dfe
.getProcessingPolicy(address
, d_discardedPolicies
);
1562 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1563 LOG(", however nameserver "<<ns
.first
<<" IP address "<<address
.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1572 bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine
& dfe
, const ComboAddress
& remoteIP
)
1575 d_appliedPolicy
= dfe
.getProcessingPolicy(remoteIP
, d_discardedPolicies
);
1576 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) {
1577 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")+"')");
1584 vector
<ComboAddress
> SyncRes::retrieveAddressesForNS(const std::string
& prefix
, const DNSName
& qname
, vector
<DNSName
>::const_iterator
& tns
, const unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, const vector
<DNSName
>& rnameservers
, NsSet
& nameservers
, bool& sendRDQuery
, bool& pierceDontQuery
, bool& flawedNSSet
, bool cacheOnly
)
1586 vector
<ComboAddress
> result
;
1589 LOG(prefix
<<qname
<<": Trying to resolve NS '"<<*tns
<< "' ("<<1+tns
-rnameservers
.begin()<<"/"<<(unsigned int)rnameservers
.size()<<")"<<endl
);
1590 result
= getAddrs(*tns
, depth
+2, beenthere
, cacheOnly
);
1591 pierceDontQuery
=false;
1594 LOG(prefix
<<qname
<<": Domain has hardcoded nameserver");
1596 if(nameservers
[*tns
].first
.size() > 1) {
1601 sendRDQuery
= nameservers
[*tns
].second
;
1602 result
= shuffleForwardSpeed(nameservers
[*tns
].first
, doLog() ? (prefix
+qname
.toString()+": ") : string(), sendRDQuery
);
1603 pierceDontQuery
=true;
1608 bool SyncRes::throttledOrBlocked(const std::string
& prefix
, const ComboAddress
& remoteIP
, const DNSName
& qname
, const QType
& qtype
, bool pierceDontQuery
)
1610 if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0))) {
1611 LOG(prefix
<<qname
<<": server throttled "<<endl
);
1612 s_throttledqueries
++; d_throttledqueries
++;
1615 else if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()))) {
1616 LOG(prefix
<<qname
<<": query throttled "<<remoteIP
.toString()<<", "<<qname
<<"; "<<qtype
.getName()<<endl
);
1617 s_throttledqueries
++; d_throttledqueries
++;
1620 else if(!pierceDontQuery
&& s_dontQuery
&& s_dontQuery
->match(&remoteIP
)) {
1621 LOG(prefix
<<qname
<<": not sending query to " << remoteIP
.toString() << ", blocked by 'dont-query' setting" << endl
);
1628 bool SyncRes::validationEnabled() const
1630 return g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
;
1633 uint32_t SyncRes::computeLowestTTD(const std::vector
<DNSRecord
>& records
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, uint32_t signaturesTTL
) const
1635 uint32_t lowestTTD
= std::numeric_limits
<uint32_t>::max();
1636 for(const auto& record
: records
)
1637 lowestTTD
= min(lowestTTD
, record
.d_ttl
);
1639 /* even if it was not requested for that request (Process, and neither AD nor DO set),
1640 it might be requested at a later time so we need to be careful with the TTL. */
1641 if (validationEnabled() && !signatures
.empty()) {
1642 /* if we are validating, we don't want to cache records after their signatures expire. */
1643 /* records TTL are now TTD, let's add 'now' to the signatures lowest TTL */
1644 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(signaturesTTL
+ d_now
.tv_sec
));
1646 for(const auto& sig
: signatures
) {
1647 if (isRRSIGNotExpired(d_now
.tv_sec
, sig
)) {
1648 // we don't decerement d_sigexpire by 'now' because we actually want a TTD, not a TTL */
1649 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(sig
->d_sigexpire
));
1657 void SyncRes::updateValidationState(vState
& state
, const vState stateUpdate
)
1659 LOG(d_prefix
<<"validation state was "<<std::string(vStates
[state
])<<", state update is "<<std::string(vStates
[stateUpdate
]));
1661 if (stateUpdate
== TA
) {
1664 else if (stateUpdate
== NTA
) {
1667 else if (stateUpdate
== Bogus
) {
1670 else if (state
== Indeterminate
) {
1671 state
= stateUpdate
;
1673 else if (stateUpdate
== Insecure
) {
1674 if (state
!= Bogus
) {
1678 LOG(", validation state is now "<<std::string(vStates
[state
])<<endl
);
1681 vState
SyncRes::getTA(const DNSName
& zone
, dsmap_t
& ds
)
1683 auto luaLocal
= g_luaconfs
.getLocal();
1685 if (luaLocal
->dsAnchors
.empty()) {
1686 LOG(d_prefix
<<": No trust anchors configured, everything is Insecure"<<endl
);
1687 /* We have no TA, everything is insecure */
1692 if (haveNegativeTrustAnchor(luaLocal
->negAnchors
, zone
, reason
)) {
1693 LOG(d_prefix
<<": got NTA for '"<<zone
<<"'"<<endl
);
1697 if (getTrustAnchor(luaLocal
->dsAnchors
, zone
, ds
)) {
1698 LOG(d_prefix
<<": got TA for '"<<zone
<<"'"<<endl
);
1702 LOG(d_prefix
<<": no TA found for '"<<zone
<<"' among "<< luaLocal
->dsAnchors
.size()<<endl
);
1705 if (zone
.isRoot()) {
1706 /* No TA for the root */
1710 return Indeterminate
;
1713 static size_t countSupportedDS(const dsmap_t
& dsmap
)
1717 for (const auto& ds
: dsmap
) {
1718 if (isSupportedDS(ds
)) {
1726 vState
SyncRes::getDSRecords(const DNSName
& zone
, dsmap_t
& ds
, bool taOnly
, unsigned int depth
, bool bogusOnNXD
, bool* foundCut
)
1728 vState result
= getTA(zone
, ds
);
1730 if (result
!= Indeterminate
|| taOnly
) {
1732 *foundCut
= (result
!= Indeterminate
);
1736 if (countSupportedDS(ds
) == 0) {
1744 else if (result
== NTA
) {
1751 bool oldSkipCNAME
= d_skipCNAMECheck
;
1752 d_skipCNAMECheck
= true;
1754 std::set
<GetBestNSAnswer
> beenthere
;
1755 std::vector
<DNSRecord
> dsrecords
;
1757 vState state
= Indeterminate
;
1758 int rcode
= doResolve(zone
, QType(QType::DS
), dsrecords
, depth
+ 1, beenthere
, state
);
1759 d_skipCNAMECheck
= oldSkipCNAME
;
1761 if (rcode
== RCode::NoError
|| (rcode
== RCode::NXDomain
&& !bogusOnNXD
)) {
1763 uint8_t bestDigestType
= 0;
1765 if (state
== Secure
) {
1766 bool gotCNAME
= false;
1767 for (const auto& record
: dsrecords
) {
1768 if (record
.d_type
== QType::DS
) {
1769 const auto dscontent
= getRR
<DSRecordContent
>(record
);
1770 if (dscontent
&& isSupportedDS(*dscontent
)) {
1771 // Make GOST a lower prio than SHA256
1772 if (dscontent
->d_digesttype
== DNSSECKeeper::GOST
&& bestDigestType
== DNSSECKeeper::SHA256
) {
1775 if (dscontent
->d_digesttype
> bestDigestType
|| (bestDigestType
== DNSSECKeeper::GOST
&& dscontent
->d_digesttype
== DNSSECKeeper::SHA256
)) {
1776 bestDigestType
= dscontent
->d_digesttype
;
1778 ds
.insert(*dscontent
);
1781 else if (record
.d_type
== QType::CNAME
&& record
.d_name
== zone
) {
1786 /* RFC 4509 section 3: "Validator implementations SHOULD ignore DS RRs containing SHA-1
1787 * digests if DS RRs with SHA-256 digests are present in the DS RRset."
1788 * As SHA348 is specified as well, the spirit of the this line is "use the best algorithm".
1790 for (auto dsrec
= ds
.begin(); dsrec
!= ds
.end(); ) {
1791 if (dsrec
->d_digesttype
!= bestDigestType
) {
1792 dsrec
= ds
.erase(dsrec
);
1799 if (rcode
== RCode::NoError
&& ds
.empty()) {
1801 if (gotCNAME
|| denialProvesNoDelegation(zone
, dsrecords
)) {
1802 /* we are still inside the same Secure zone */
1812 } else if (foundCut
&& rcode
== RCode::NoError
&& !ds
.empty()) {
1820 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
1824 bool SyncRes::haveExactValidationStatus(const DNSName
& domain
)
1826 if (!shouldValidate()) {
1829 const auto& it
= d_cutStates
.find(domain
);
1830 if (it
!= d_cutStates
.cend()) {
1836 vState
SyncRes::getValidationStatus(const DNSName
& subdomain
, bool allowIndeterminate
)
1838 vState result
= Indeterminate
;
1840 if (!shouldValidate()) {
1843 DNSName
name(subdomain
);
1845 const auto& it
= d_cutStates
.find(name
);
1846 if (it
!= d_cutStates
.cend()) {
1847 if (allowIndeterminate
|| it
->second
!= Indeterminate
) {
1848 LOG(d_prefix
<<": got status "<<vStates
[it
->second
]<<" for name "<<subdomain
<<" (from "<<name
<<")"<<endl
);
1853 while (name
.chopOff());
1858 bool SyncRes::lookForCut(const DNSName
& qname
, unsigned int depth
, const vState existingState
, vState
& newState
)
1860 bool foundCut
= false;
1862 vState dsState
= getDSRecords(qname
, ds
, newState
== Bogus
|| existingState
== Insecure
|| existingState
== Bogus
, depth
, false, &foundCut
);
1864 if (dsState
!= Indeterminate
) {
1871 void SyncRes::computeZoneCuts(const DNSName
& begin
, const DNSName
& end
, unsigned int depth
)
1873 if(!begin
.isPartOf(end
)) {
1874 LOG(d_prefix
<<" "<<begin
.toLogString()<<" is not part of "<<end
.toLogString()<<endl
);
1875 throw PDNSException(begin
.toLogString() + " is not part of " + end
.toLogString());
1878 if (d_cutStates
.count(begin
) != 0) {
1883 vState cutState
= getDSRecords(end
, ds
, false, depth
);
1884 LOG(d_prefix
<<": setting cut state for "<<end
<<" to "<<vStates
[cutState
]<<endl
);
1885 d_cutStates
[end
] = cutState
;
1887 if (!shouldValidate()) {
1892 std::vector
<string
> labelsToAdd
= begin
.makeRelative(end
).getRawLabels();
1894 bool oldSkipCNAME
= d_skipCNAMECheck
;
1895 d_skipCNAMECheck
= true;
1897 while(qname
!= begin
) {
1898 if (labelsToAdd
.empty())
1901 qname
.prependRawLabel(labelsToAdd
.back());
1902 labelsToAdd
.pop_back();
1903 LOG(d_prefix
<<": - Looking for a cut at "<<qname
<<endl
);
1905 const auto cutIt
= d_cutStates
.find(qname
);
1906 if (cutIt
!= d_cutStates
.cend()) {
1907 if (cutIt
->second
!= Indeterminate
) {
1908 LOG(d_prefix
<<": - Cut already known at "<<qname
<<endl
);
1909 cutState
= cutIt
->second
;
1914 /* no need to look for NS and DS if we are already insecure or bogus,
1917 if (cutState
== Insecure
|| cutState
== Bogus
) {
1919 vState newState
= getDSRecords(qname
, cutDS
, true, depth
);
1920 if (newState
== Indeterminate
) {
1924 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[newState
]<<endl
);
1925 cutState
= newState
;
1927 d_cutStates
[qname
] = cutState
;
1932 vState newState
= Indeterminate
;
1933 /* temporarily mark as Indeterminate, so that we won't enter an endless loop
1934 trying to determine that zone cut again. */
1935 d_cutStates
[qname
] = newState
;
1936 bool foundCut
= lookForCut(qname
, depth
+ 1, cutState
, newState
);
1938 LOG(d_prefix
<<": - Found cut at "<<qname
<<endl
);
1939 if (newState
!= Indeterminate
) {
1940 cutState
= newState
;
1942 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[cutState
]<<endl
);
1943 d_cutStates
[qname
] = cutState
;
1946 /* remove the temporary cut */
1947 LOG(d_prefix
<<qname
<<": removing cut state for "<<qname
<<endl
);
1948 d_cutStates
.erase(qname
);
1952 d_skipCNAMECheck
= oldSkipCNAME
;
1954 LOG(d_prefix
<<": list of cuts from "<<begin
<<" to "<<end
<<endl
);
1955 for (const auto& cut
: d_cutStates
) {
1956 if (cut
.first
.isRoot() || (begin
.isPartOf(cut
.first
) && cut
.first
.isPartOf(end
))) {
1957 LOG(" - "<<cut
.first
<<": "<<vStates
[cut
.second
]<<endl
);
1962 vState
SyncRes::validateDNSKeys(const DNSName
& zone
, const std::vector
<DNSRecord
>& dnskeys
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, unsigned int depth
)
1965 if (!signatures
.empty()) {
1966 DNSName signer
= getSigner(signatures
);
1968 if (!signer
.empty() && zone
.isPartOf(signer
)) {
1969 vState state
= getDSRecords(signer
, ds
, false, depth
);
1971 if (state
!= Secure
) {
1977 skeyset_t tentativeKeys
;
1978 std::vector
<shared_ptr
<DNSRecordContent
> > toSign
;
1980 for (const auto& dnskey
: dnskeys
) {
1981 if (dnskey
.d_type
== QType::DNSKEY
) {
1982 auto content
= getRR
<DNSKEYRecordContent
>(dnskey
);
1984 tentativeKeys
.insert(content
);
1985 toSign
.push_back(content
);
1990 LOG(d_prefix
<<": trying to validate "<<std::to_string(tentativeKeys
.size())<<" DNSKEYs with "<<std::to_string(ds
.size())<<" DS"<<endl
);
1991 skeyset_t validatedKeys
;
1992 validateDNSKeysAgainstDS(d_now
.tv_sec
, zone
, ds
, tentativeKeys
, toSign
, signatures
, validatedKeys
);
1994 LOG(d_prefix
<<": we now have "<<std::to_string(validatedKeys
.size())<<" DNSKEYs"<<endl
);
1996 /* if we found at least one valid RRSIG covering the set,
1997 all tentative keys are validated keys. Otherwise it means
1998 we haven't found at least one DNSKEY and a matching RRSIG
1999 covering this set, this looks Bogus. */
2000 if (validatedKeys
.size() != tentativeKeys
.size()) {
2001 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
2008 vState
SyncRes::getDNSKeys(const DNSName
& signer
, skeyset_t
& keys
, unsigned int depth
)
2010 std::vector
<DNSRecord
> records
;
2011 std::set
<GetBestNSAnswer
> beenthere
;
2012 LOG(d_prefix
<<"Retrieving DNSKeys for "<<signer
<<endl
);
2014 vState state
= Indeterminate
;
2015 /* following CNAME might lead to us to the wrong DNSKEY */
2016 bool oldSkipCNAME
= d_skipCNAMECheck
;
2017 d_skipCNAMECheck
= true;
2018 int rcode
= doResolve(signer
, QType(QType::DNSKEY
), records
, depth
+ 1, beenthere
, state
);
2019 d_skipCNAMECheck
= oldSkipCNAME
;
2021 if (rcode
== RCode::NoError
) {
2022 if (state
== Secure
) {
2023 for (const auto& key
: records
) {
2024 if (key
.d_type
== QType::DNSKEY
) {
2025 auto content
= getRR
<DNSKEYRecordContent
>(key
);
2027 keys
.insert(content
);
2032 LOG(d_prefix
<<"Retrieved "<<keys
.size()<<" DNSKeys for "<<signer
<<", state is "<<vStates
[state
]<<endl
);
2036 LOG(d_prefix
<<"Returning Bogus state from "<<__func__
<<"("<<signer
<<")"<<endl
);
2040 vState
SyncRes::validateRecordsWithSigs(unsigned int depth
, const DNSName
& qname
, const QType
& qtype
, const DNSName
& name
, const std::vector
<DNSRecord
>& records
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
)
2043 if (!signatures
.empty()) {
2044 const DNSName signer
= getSigner(signatures
);
2045 if (!signer
.empty() && name
.isPartOf(signer
)) {
2046 if ((qtype
== QType::DNSKEY
|| qtype
== QType::DS
) && signer
== qname
) {
2047 /* we are already retrieving those keys, sorry */
2048 return Indeterminate
;
2050 vState state
= getDNSKeys(signer
, keys
, depth
);
2051 if (state
!= Secure
) {
2056 LOG(d_prefix
<<"Bogus!"<<endl
);
2060 std::vector
<std::shared_ptr
<DNSRecordContent
> > recordcontents
;
2061 for (const auto& record
: records
) {
2062 recordcontents
.push_back(record
.d_content
);
2065 LOG(d_prefix
<<"Going to validate "<<recordcontents
.size()<< " record contents with "<<signatures
.size()<<" sigs and "<<keys
.size()<<" keys for "<<name
<<endl
);
2066 if (validateWithKeySet(d_now
.tv_sec
, name
, recordcontents
, signatures
, keys
, false)) {
2067 LOG(d_prefix
<<"Secure!"<<endl
);
2071 LOG(d_prefix
<<"Bogus!"<<endl
);
2075 static bool allowAdditionalEntry(std::unordered_set
<DNSName
>& allowedAdditionals
, const DNSRecord
& rec
)
2077 switch(rec
.d_type
) {
2080 if (auto mxContent
= getRR
<MXRecordContent
>(rec
)) {
2081 allowedAdditionals
.insert(mxContent
->d_mxname
);
2087 if (auto nsContent
= getRR
<NSRecordContent
>(rec
)) {
2088 allowedAdditionals
.insert(nsContent
->getNS());
2094 if (auto srvContent
= getRR
<SRVRecordContent
>(rec
)) {
2095 allowedAdditionals
.insert(srvContent
->d_target
);
2104 void SyncRes::sanitizeRecords(const std::string
& prefix
, LWResult
& lwr
, const DNSName
& qname
, const QType
& qtype
, const DNSName
& auth
, bool wasForwarded
, bool rdQuery
)
2106 const bool wasForwardRecurse
= wasForwarded
&& rdQuery
;
2107 /* list of names for which we will allow A and AAAA records in the additional section
2109 std::unordered_set
<DNSName
> allowedAdditionals
= { qname
};
2110 bool haveAnswers
= false;
2111 bool isNXDomain
= false;
2112 bool isNXQType
= false;
2114 for(auto rec
= lwr
.d_records
.begin(); rec
!= lwr
.d_records
.end(); ) {
2116 if (rec
->d_type
== QType::OPT
) {
2121 if (rec
->d_class
!= QClass::IN
) {
2122 LOG(prefix
<<"Removing non internet-classed data received from "<<auth
<<endl
);
2123 rec
= lwr
.d_records
.erase(rec
);
2127 if (rec
->d_type
== QType::ANY
) {
2128 LOG(prefix
<<"Removing 'ANY'-typed data received from "<<auth
<<endl
);
2129 rec
= lwr
.d_records
.erase(rec
);
2133 if (!rec
->d_name
.isPartOf(auth
)) {
2134 LOG(prefix
<<"Removing record '"<<rec
->d_name
<<"|"<<DNSRecordContent::NumberToType(rec
->d_type
)<<"|"<<rec
->d_content
->getZoneRepresentation()<<"' in the "<<(int)rec
->d_place
<<" section received from "<<auth
<<endl
);
2135 rec
= lwr
.d_records
.erase(rec
);
2139 /* dealing with the records in answer */
2140 if (!(lwr
.d_aabit
|| wasForwardRecurse
) && rec
->d_place
== DNSResourceRecord::ANSWER
) {
2141 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2142 are sending such responses */
2143 if (!(rec
->d_type
== QType::CNAME
&& qname
== rec
->d_name
)) {
2144 LOG(prefix
<<"Removing record '"<<rec
->d_name
<<"|"<<DNSRecordContent::NumberToType(rec
->d_type
)<<"|"<<rec
->d_content
->getZoneRepresentation()<<"' in the answer section without the AA bit set received from "<<auth
<<endl
);
2145 rec
= lwr
.d_records
.erase(rec
);
2150 if (rec
->d_type
== QType::DNAME
&& (rec
->d_place
!= DNSResourceRecord::ANSWER
|| !qname
.isPartOf(rec
->d_name
))) {
2151 LOG(prefix
<<"Removing invalid DNAME record '"<<rec
->d_name
<<"|"<<DNSRecordContent::NumberToType(rec
->d_type
)<<"|"<<rec
->d_content
->getZoneRepresentation()<<"' in the "<<(int)rec
->d_place
<<" section received from "<<auth
<<endl
);
2152 rec
= lwr
.d_records
.erase(rec
);
2156 if (rec
->d_place
== DNSResourceRecord::ANSWER
&& (qtype
!= QType::ANY
&& rec
->d_type
!= qtype
.getCode() && s_redirectionQTypes
.count(rec
->d_type
) == 0 && rec
->d_type
!= QType::SOA
&& rec
->d_type
!= QType::RRSIG
)) {
2157 LOG(prefix
<<"Removing irrelevant record '"<<rec
->d_name
<<"|"<<DNSRecordContent::NumberToType(rec
->d_type
)<<"|"<<rec
->d_content
->getZoneRepresentation()<<"' in the "<<(int)rec
->d_place
<<" section received from "<<auth
<<endl
);
2158 rec
= lwr
.d_records
.erase(rec
);
2162 if (rec
->d_place
== DNSResourceRecord::ANSWER
&& !haveAnswers
) {
2166 if (rec
->d_place
== DNSResourceRecord::ANSWER
) {
2167 allowAdditionalEntry(allowedAdditionals
, *rec
);
2170 /* dealing with the records in authority */
2171 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
!= QType::NS
&& rec
->d_type
!= QType::DS
&& rec
->d_type
!= QType::SOA
&& rec
->d_type
!= QType::RRSIG
&& rec
->d_type
!= QType::NSEC
&& rec
->d_type
!= QType::NSEC3
) {
2172 LOG(prefix
<<"Removing irrelevant record '"<<rec
->d_name
<<"|"<<DNSRecordContent::NumberToType(rec
->d_type
)<<"|"<<rec
->d_content
->getZoneRepresentation()<<"' in the "<<(int)rec
->d_place
<<" section received from "<<auth
<<endl
);
2173 rec
= lwr
.d_records
.erase(rec
);
2177 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::SOA
) {
2178 if (!qname
.isPartOf(rec
->d_name
)) {
2179 LOG(prefix
<<"Removing irrelevant record '"<<rec
->d_name
<<"|"<<DNSRecordContent::NumberToType(rec
->d_type
)<<"|"<<rec
->d_content
->getZoneRepresentation()<<"' in the "<<(int)rec
->d_place
<<" section received from "<<auth
<<endl
);
2180 rec
= lwr
.d_records
.erase(rec
);
2184 if (!(lwr
.d_aabit
|| wasForwardRecurse
)) {
2185 LOG(prefix
<<"Removing irrelevant record '"<<rec
->d_name
<<"|"<<DNSRecordContent::NumberToType(rec
->d_type
)<<"|"<<rec
->d_content
->getZoneRepresentation()<<"' in the "<<(int)rec
->d_place
<<" section received from "<<auth
<<endl
);
2186 rec
= lwr
.d_records
.erase(rec
);
2191 if (lwr
.d_rcode
== RCode::NXDomain
) {
2194 else if (lwr
.d_rcode
== RCode::NoError
) {
2200 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::NS
&& (isNXDomain
|| isNXQType
)) {
2201 /* we don't want to pick up NS records in AUTHORITY or ADDITIONAL sections of NXDomain answers
2202 because they are somewhat easy to insert into a large, fragmented UDP response
2203 for an off-path attacker by injecting spoofed UDP fragments.
2205 LOG(prefix
<<"Removing NS record '"<<rec
->d_name
<<"|"<<DNSRecordContent::NumberToType(rec
->d_type
)<<"|"<<rec
->d_content
->getZoneRepresentation()<<"' in the "<<(int)rec
->d_place
<<" section of a "<<(isNXDomain
? "NXD" : "NXQTYPE")<<" response received from "<<auth
<<endl
);
2206 rec
= lwr
.d_records
.erase(rec
);
2210 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::NS
) {
2211 allowAdditionalEntry(allowedAdditionals
, *rec
);
2214 /* dealing with the records in additional */
2215 if (rec
->d_place
== DNSResourceRecord::ADDITIONAL
&& rec
->d_type
!= QType::A
&& rec
->d_type
!= QType::AAAA
&& rec
->d_type
!= QType::RRSIG
) {
2216 LOG(prefix
<<"Removing irrelevant record '"<<rec
->d_name
<<"|"<<DNSRecordContent::NumberToType(rec
->d_type
)<<"|"<<rec
->d_content
->getZoneRepresentation()<<"' in the "<<(int)rec
->d_place
<<" section received from "<<auth
<<endl
);
2217 rec
= lwr
.d_records
.erase(rec
);
2221 if (rec
->d_place
== DNSResourceRecord::ADDITIONAL
&& allowedAdditionals
.count(rec
->d_name
) == 0) {
2222 LOG(prefix
<<"Removing irrelevant additional record '"<<rec
->d_name
<<"|"<<DNSRecordContent::NumberToType(rec
->d_type
)<<"|"<<rec
->d_content
->getZoneRepresentation()<<"' in the "<<(int)rec
->d_place
<<" section received from "<<auth
<<endl
);
2223 rec
= lwr
.d_records
.erase(rec
);
2231 RCode::rcodes_
SyncRes::updateCacheFromRecords(unsigned int depth
, LWResult
& lwr
, const DNSName
& qname
, const QType
& qtype
, const DNSName
& auth
, bool wasForwarded
, const boost::optional
<Netmask
> ednsmask
, vState
& state
, bool& needWildcardProof
, bool& gatherWildcardProof
, unsigned int& wildcardLabelsCount
, bool rdQuery
)
2233 bool wasForwardRecurse
= wasForwarded
&& rdQuery
;
2239 prefix
.append(depth
, ' ');
2242 sanitizeRecords(prefix
, lwr
, qname
, qtype
, auth
, wasForwarded
, rdQuery
);
2244 std::vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
2245 const unsigned int labelCount
= qname
.countLabels();
2246 bool isCNAMEAnswer
= false;
2247 bool isDNAMEAnswer
= false;
2248 for(const auto& rec
: lwr
.d_records
) {
2249 if (rec
.d_class
!= QClass::IN
) {
2253 if(!isCNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
&& !isDNAMEAnswer
) {
2254 isCNAMEAnswer
= true;
2256 if(!isDNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::DNAME
&& qtype
!= QType(QType::DNAME
) && qname
.isPartOf(rec
.d_name
)) {
2257 isDNAMEAnswer
= true;
2258 isCNAMEAnswer
= false;
2261 /* if we have a positive answer synthetized from a wildcard,
2262 we need to store the corresponding NSEC/NSEC3 records proving
2263 that the exact name did not exist in the negative cache */
2264 if(gatherWildcardProof
) {
2265 if (nsecTypes
.count(rec
.d_type
)) {
2266 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
2268 else if (rec
.d_type
== QType::RRSIG
) {
2269 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
2270 if (rrsig
&& nsecTypes
.count(rrsig
->d_type
)) {
2271 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
2275 if(rec
.d_type
== QType::RRSIG
) {
2276 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
2278 /* As illustrated in rfc4035's Appendix B.6, the RRSIG label
2279 count can be lower than the name's label count if it was
2280 synthetized from the wildcard. Note that the difference might
2282 if (rec
.d_name
== qname
&& isWildcardExpanded(labelCount
, rrsig
)) {
2283 gatherWildcardProof
= true;
2284 if (!isWildcardExpandedOntoItself(rec
.d_name
, labelCount
, rrsig
)) {
2285 /* if we have a wildcard expanded onto itself, we don't need to prove
2286 that the exact name doesn't exist because it actually does.
2287 We still want to gather the corresponding NSEC/NSEC3 records
2288 to pass them to our client in case it wants to validate by itself.
2290 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthetized from a wildcard, we need a wildcard proof"<<endl
);
2291 needWildcardProof
= true;
2294 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthetized from a wildcard expanded onto itself, we need to gather wildcard proof"<<endl
);
2296 wildcardLabelsCount
= rrsig
->d_labels
;
2299 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
2300 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
2301 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signaturesTTL
= std::min(tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signaturesTTL
, rec
.d_ttl
);
2306 // reap all answers from this packet that are acceptable
2307 for(auto& rec
: lwr
.d_records
) {
2308 if(rec
.d_type
== QType::OPT
) {
2309 LOG(prefix
<<qname
<<": OPT answer '"<<rec
.d_name
<<"' from '"<<auth
<<"' nameservers" <<endl
);
2312 LOG(prefix
<<qname
<<": accept answer '"<<rec
.d_name
<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"|"<<rec
.d_content
->getZoneRepresentation()<<"' from '"<<auth
<<"' nameservers? ttl="<<rec
.d_ttl
<<", place="<<(int)rec
.d_place
<<" ");
2313 if(rec
.d_type
== QType::ANY
) {
2314 LOG("NO! - we don't accept 'ANY'-typed data"<<endl
);
2318 if(rec
.d_class
!= QClass::IN
) {
2319 LOG("NO! - we don't accept records for any other class than 'IN'"<<endl
);
2323 if (!(lwr
.d_aabit
|| wasForwardRecurse
) && rec
.d_place
== DNSResourceRecord::ANSWER
) {
2324 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2325 are sending such responses */
2326 if (!(rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
)) {
2327 LOG("NO! - we don't accept records in the answers section without the AA bit set"<<endl
);
2332 if(rec
.d_name
.isPartOf(auth
)) {
2333 if(rec
.d_type
== QType::RRSIG
) {
2334 LOG("RRSIG - separate"<<endl
);
2336 else if(lwr
.d_aabit
&& lwr
.d_rcode
==RCode::NoError
&& rec
.d_place
==DNSResourceRecord::ANSWER
&& ((rec
.d_type
!= QType::DNSKEY
&& rec
.d_type
!= QType::DS
) || rec
.d_name
!= auth
) && s_delegationOnly
.count(auth
)) {
2337 LOG("NO! Is from delegation-only zone"<<endl
);
2339 return RCode::NXDomain
;
2342 bool haveLogged
= false;
2343 if (isDNAMEAnswer
&& rec
.d_type
== QType::CNAME
) {
2344 LOG("NO - we already have a DNAME answer for this domain");
2347 if (!t_sstorage
.domainmap
->empty()) {
2348 // Check if we are authoritative for a zone in this answer
2349 DNSName
tmp_qname(rec
.d_name
);
2350 auto auth_domain_iter
=getBestAuthZone(&tmp_qname
);
2351 if(auth_domain_iter
!=t_sstorage
.domainmap
->end() &&
2352 auth
.countLabels() <= auth_domain_iter
->first
.countLabels()) {
2353 if (auth_domain_iter
->first
!= auth
) {
2354 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter
->first
<<endl
);
2357 LOG("YES! - This answer was ");
2358 if (!wasForwarded
) {
2359 LOG("retrieved from the local auth store.");
2361 LOG("received from a server we forward to.");
2372 rec
.d_ttl
=min(s_maxcachettl
, rec
.d_ttl
);
2375 dr
.d_ttl
+= d_now
.tv_sec
;
2376 dr
.d_place
=DNSResourceRecord::ANSWER
;
2377 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(dr
);
2385 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2386 if((i
->second
.records
.size() + i
->second
.signatures
.size()) > 1) { // need to group the ttl to be the minimum of the RRSET (RFC 2181, 5.2)
2387 uint32_t lowestTTD
=computeLowestTTD(i
->second
.records
, i
->second
.signatures
, i
->second
.signaturesTTL
);
2389 for(auto& record
: i
->second
.records
)
2390 record
.d_ttl
= lowestTTD
; // boom
2393 // cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
2394 // cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
2397 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2399 if(i
->second
.records
.empty()) // this happens when we did store signatures, but passed on the records themselves
2402 /* Even if the AA bit is set, additional data cannot be considered
2403 as authoritative. This is especially important during validation
2404 because keeping records in the additional section is allowed even
2405 if the corresponding RRSIGs are not included, without setting the TC
2406 bit, as stated in rfc4035's section 3.1.1. Including RRSIG RRs in a Response:
2407 "When placing a signed RRset in the Additional section, the name
2408 server MUST also place its RRSIG RRs in the Additional section.
2409 If space does not permit inclusion of both the RRset and its
2410 associated RRSIG RRs, the name server MAY retain the RRset while
2411 dropping the RRSIG RRs. If this happens, the name server MUST NOT
2412 set the TC bit solely because these RRSIG RRs didn't fit."
2414 bool isAA
= lwr
.d_aabit
&& i
->first
.place
!= DNSResourceRecord::ADDITIONAL
;
2415 /* if we forwarded the query to a recursor, we can expect the answer to be signed,
2416 even if the answer is not AA. Of course that's not only true inside a Secure
2417 zone, but we check that below. */
2418 bool expectSignature
= i
->first
.place
== DNSResourceRecord::ANSWER
|| ((lwr
.d_aabit
|| wasForwardRecurse
) && i
->first
.place
!= DNSResourceRecord::ADDITIONAL
);
2419 if (isCNAMEAnswer
&& (i
->first
.place
!= DNSResourceRecord::ANSWER
|| i
->first
.type
!= QType::CNAME
|| i
->first
.name
!= qname
)) {
2422 Note that the answer section of an authoritative answer normally
2423 contains only authoritative data. However when the name sought is an
2424 alias (see section 10.1.1) only the record describing that alias is
2425 necessarily authoritative. Clients should assume that other records
2426 may have come from the server's cache. Where authoritative answers
2427 are required, the client should query again, using the canonical name
2428 associated with the alias.
2431 expectSignature
= false;
2434 if (isCNAMEAnswer
&& i
->first
.place
== DNSResourceRecord::AUTHORITY
&& i
->first
.type
== QType::NS
&& auth
== i
->first
.name
) {
2435 /* These NS can't be authoritative since we have a CNAME answer for which (see above) only the
2436 record describing that alias is necessarily authoritative.
2437 But if we allow the current auth, which might be serving the child zone, to raise the TTL
2438 of non-authoritative NS in the cache, they might be able to keep a "ghost" zone alive forever,
2439 even after the delegation is gone from the parent.
2440 So let's just do nothing with them, we can fetch them directly if we need them.
2442 LOG(d_prefix
<<": skipping authority NS from '"<<auth
<<"' nameservers in CNAME answer "<<i
->first
.name
<<"|"<<DNSRecordContent::NumberToType(i
->first
.type
)<<endl
);
2446 vState recordState
= getValidationStatus(i
->first
.name
, false);
2447 LOG(d_prefix
<<": got initial zone status "<<vStates
[recordState
]<<" for record "<<i
->first
.name
<<"|"<<DNSRecordContent::NumberToType(i
->first
.type
)<<endl
);
2449 if (shouldValidate() && recordState
== Secure
) {
2450 vState initialState
= recordState
;
2452 if (expectSignature
) {
2453 if (i
->first
.place
!= DNSResourceRecord::ADDITIONAL
) {
2454 /* the additional entries can be insecure,
2456 "Glue address RRsets associated with delegations MUST NOT be signed"
2458 if (i
->first
.type
== QType::DNSKEY
&& i
->first
.place
== DNSResourceRecord::ANSWER
) {
2459 LOG(d_prefix
<<"Validating DNSKEY for "<<i
->first
.name
<<endl
);
2460 recordState
= validateDNSKeys(i
->first
.name
, i
->second
.records
, i
->second
.signatures
, depth
);
2464 * RFC 6672 section 5.3.1
2465 * In any response, a signed DNAME RR indicates a non-terminal
2466 * redirection of the query. There might or might not be a server-
2467 * synthesized CNAME in the answer section; if there is, the CNAME will
2468 * never be signed. For a DNSSEC validator, verification of the DNAME
2469 * RR and then that the CNAME was properly synthesized is sufficient
2472 * We do the synthesis check in processRecords, here we make sure we
2473 * don't validate the CNAME.
2475 if (!(isDNAMEAnswer
&& i
->first
.type
== QType::CNAME
)) {
2476 LOG(d_prefix
<<"Validating non-additional record for "<<i
->first
.name
<<endl
);
2477 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2478 /* we might have missed a cut (zone cut within the same auth servers), causing the NS query for an Insecure zone to seem Bogus during zone cut determination */
2479 if (qtype
== QType::NS
&& i
->second
.signatures
.empty() && recordState
== Bogus
&& haveExactValidationStatus(i
->first
.name
) && getValidationStatus(i
->first
.name
) == Indeterminate
) {
2480 recordState
= Indeterminate
;
2487 recordState
= Indeterminate
;
2489 /* in a non authoritative answer, we only care about the DS record (or lack of) */
2490 if ((i
->first
.type
== QType::DS
|| i
->first
.type
== QType::NSEC
|| i
->first
.type
== QType::NSEC3
) && i
->first
.place
== DNSResourceRecord::AUTHORITY
) {
2491 LOG(d_prefix
<<"Validating DS record for "<<i
->first
.name
<<endl
);
2492 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2496 if (initialState
== Secure
&& state
!= recordState
&& expectSignature
) {
2497 updateValidationState(state
, recordState
);
2501 if (shouldValidate()) {
2502 LOG(d_prefix
<<"Skipping validation because the current state is "<<vStates
[recordState
]<<endl
);
2506 if (recordState
== Bogus
) {
2507 /* this is a TTD by now, be careful */
2508 for(auto& record
: i
->second
.records
) {
2509 record
.d_ttl
= std::min(record
.d_ttl
, static_cast<uint32_t>(s_maxbogusttl
+ d_now
.tv_sec
));
2513 /* We don't need to store NSEC3 records in the positive cache because:
2514 - we don't allow direct NSEC3 queries
2515 - denial of existence proofs in wildcard expanded positive responses are stored in authorityRecs
2516 - denial of existence proofs for negative responses are stored in the negative cache
2517 We also don't want to cache non-authoritative data except for:
2518 - records coming from non forward-recurse servers (those will never be AA)
2520 - NS, A and AAAA (used for infra queries)
2522 if (i
->first
.type
!= QType::NSEC3
&& (i
->first
.type
== QType::DS
|| i
->first
.type
== QType::NS
|| i
->first
.type
== QType::A
|| i
->first
.type
== QType::AAAA
|| isAA
|| wasForwardRecurse
)) {
2524 bool doCache
= true;
2525 if (i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
) {
2526 // If ednsmask is relevant, we do not want to cache if the scope prefix length is large and TTL is small
2527 if (SyncRes::s_ecscachelimitttl
> 0) {
2528 bool manyMaskBits
= (ednsmask
->isIpv4() && ednsmask
->getBits() > SyncRes::s_ecsipv4cachelimit
) ||
2529 (ednsmask
->isIpv6() && ednsmask
->getBits() > SyncRes::s_ecsipv6cachelimit
);
2532 uint32_t minttl
= UINT32_MAX
;
2533 for (const auto &it
: i
->second
.records
) {
2534 if (it
.d_ttl
< minttl
)
2537 bool ttlIsSmall
= minttl
< SyncRes::s_ecscachelimitttl
+ d_now
.tv_sec
;
2539 // Case: many bits and ttlIsSmall
2546 t_RC
->replace(d_now
.tv_sec
, i
->first
.name
, QType(i
->first
.type
), i
->second
.records
, i
->second
.signatures
, authorityRecs
, i
->first
.type
== QType::DS
? true : isAA
, i
->first
.place
== DNSResourceRecord::ANSWER
? ednsmask
: boost::none
, recordState
);
2550 if(i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
)
2554 return RCode::NoError
;
2557 void SyncRes::updateDenialValidationState(vState
& neValidationState
, const DNSName
& neName
, vState
& state
, const dState denialState
, const dState expectedState
, bool allowOptOut
)
2559 if (denialState
== expectedState
) {
2560 neValidationState
= Secure
;
2563 if (denialState
== OPTOUT
&& allowOptOut
) {
2564 LOG(d_prefix
<<"OPT-out denial found for "<<neName
<<endl
);
2565 neValidationState
= Secure
;
2568 else if (denialState
== INSECURE
) {
2569 LOG(d_prefix
<<"Insecure denial found for "<<neName
<<", returning Insecure"<<endl
);
2570 neValidationState
= Insecure
;
2573 LOG(d_prefix
<<"Invalid denial found for "<<neName
<<", returning Bogus, res="<<denialState
<<", expectedState="<<expectedState
<<endl
);
2574 neValidationState
= Bogus
;
2576 updateValidationState(state
, neValidationState
);
2580 dState
SyncRes::getDenialValidationState(const NegCache::NegCacheEntry
& ne
, const vState state
, const dState expectedState
, bool referralToUnsigned
)
2582 cspmap_t csp
= harvestCSPFromNE(ne
);
2583 return getDenial(csp
, ne
.d_name
, ne
.d_qtype
.getCode(), referralToUnsigned
, expectedState
== NXQTYPE
);
2586 bool SyncRes::processRecords(const std::string
& prefix
, const DNSName
& qname
, const QType
& qtype
, const DNSName
& auth
, LWResult
& lwr
, const bool sendRDQuery
, vector
<DNSRecord
>& ret
, set
<DNSName
>& nsset
, DNSName
& newtarget
, DNSName
& newauth
, bool& realreferral
, bool& negindic
, vState
& state
, const bool needWildcardProof
, const bool gatherWildcardProof
, const unsigned int wildcardLabelsCount
)
2589 DNSName dnameTarget
, dnameOwner
;
2590 uint32_t dnameTTL
= 0;
2592 for(auto& rec
: lwr
.d_records
) {
2593 if (rec
.d_type
!=QType::OPT
&& rec
.d_class
!=QClass::IN
)
2596 if (rec
.d_place
==DNSResourceRecord::ANSWER
&& !(lwr
.d_aabit
|| sendRDQuery
)) {
2597 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2598 are sending such responses */
2599 if (!(rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
)) {
2604 if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2605 lwr
.d_rcode
==RCode::NXDomain
&& qname
.isPartOf(rec
.d_name
) && rec
.d_name
.isPartOf(auth
)) {
2606 LOG(prefix
<<qname
<<": got negative caching indication for name '"<<qname
<<"' (accept="<<rec
.d_name
.isPartOf(auth
)<<"), newtarget='"<<newtarget
<<"'"<<endl
);
2608 rec
.d_ttl
= min(rec
.d_ttl
, s_maxnegttl
);
2609 if(newtarget
.empty()) // only add a SOA if we're not going anywhere after this
2612 NegCache::NegCacheEntry ne
;
2614 uint32_t lowestTTL
= rec
.d_ttl
;
2615 /* if we get an NXDomain answer with a CNAME, the name
2616 does exist but the target does not */
2617 ne
.d_name
= newtarget
.empty() ? qname
: newtarget
;
2618 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2619 ne
.d_auth
= rec
.d_name
;
2620 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2622 if (state
== Secure
) {
2623 dState denialState
= getDenialValidationState(ne
, state
, NXDOMAIN
, false);
2624 updateDenialValidationState(ne
.d_validationState
, ne
.d_name
, state
, denialState
, NXDOMAIN
, false);
2627 ne
.d_validationState
= state
;
2630 if (ne
.d_validationState
== Bogus
) {
2631 lowestTTL
= min(lowestTTL
, s_maxbogusttl
);
2634 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2635 /* if we get an NXDomain answer with a CNAME, let's not cache the
2636 target, even the server was authoritative for it,
2637 and do an additional query for the CNAME target.
2638 We have a regression test making sure we do exactly that.
2640 if(!wasVariable() && newtarget
.empty()) {
2641 t_sstorage
.negcache
.add(ne
);
2642 if(s_rootNXTrust
&& ne
.d_auth
.isRoot() && auth
.isRoot() && lwr
.d_aabit
) {
2643 ne
.d_name
= ne
.d_name
.getLastLabel();
2644 t_sstorage
.negcache
.add(ne
);
2650 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& s_redirectionQTypes
.count(rec
.d_type
) > 0 && // CNAME or DNAME answer
2651 s_redirectionQTypes
.count(qtype
.getCode()) == 0) { // But not in response to a CNAME or DNAME query
2652 if (rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
) {
2653 if (!dnameOwner
.empty()) { // We synthesize ourselves
2657 if (auto content
= getRR
<CNAMERecordContent
>(rec
)) {
2658 newtarget
=content
->getTarget();
2660 } else if (rec
.d_type
== QType::DNAME
&& qname
.isPartOf(rec
.d_name
)) { // DNAME
2662 if (auto content
= getRR
<DNAMERecordContent
>(rec
)) {
2663 dnameOwner
= rec
.d_name
;
2664 dnameTarget
= content
->getTarget();
2665 dnameTTL
= rec
.d_ttl
;
2666 if (!newtarget
.empty()) { // We had a CNAME before, remove it from ret so we don't cache it
2667 ret
.erase(std::remove_if(
2670 [&qname
](DNSRecord
& rr
) {
2671 return (rr
.d_place
== DNSResourceRecord::ANSWER
&& rr
.d_type
== QType::CNAME
&& rr
.d_name
== qname
);
2676 newtarget
= qname
.makeRelative(dnameOwner
) + dnameTarget
;
2677 } catch (const std::exception
&e
) {
2678 // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
2679 // But there is no way to set the RCODE from this function
2680 throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + dnameOwner
.toLogString() +
2681 "', DNAME target: '" + dnameTarget
.toLogString() + "', substituted name: '" +
2682 qname
.makeRelative(dnameOwner
).toLogString() + "." + dnameTarget
.toLogString() +
2688 /* if we have a positive answer synthetized from a wildcard, we need to
2689 return the corresponding NSEC/NSEC3 records from the AUTHORITY section
2690 proving that the exact name did not exist */
2691 else if(gatherWildcardProof
&& (rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::AUTHORITY
) {
2692 ret
.push_back(rec
); // enjoy your DNSSEC
2694 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
2695 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&&
2697 rec
.d_type
==qtype
.getCode() || ((lwr
.d_aabit
|| sendRDQuery
) && qtype
== QType(QType::ANY
))
2701 LOG(prefix
<<qname
<<": answer is in: resolved to '"<< rec
.d_content
->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"'"<<endl
);
2705 if (state
== Secure
&& needWildcardProof
) {
2706 /* We have a positive answer synthetized from a wildcard, we need to check that we have
2707 proof that the exact name doesn't exist so the wildcard can be used,
2708 as described in section 5.3.4 of RFC 4035 and 5.3 of FRC 7129.
2710 NegCache::NegCacheEntry ne
;
2712 uint32_t lowestTTL
= rec
.d_ttl
;
2714 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2715 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2717 cspmap_t csp
= harvestCSPFromNE(ne
);
2718 dState res
= getDenial(csp
, qname
, ne
.d_qtype
.getCode(), false, false, false, wildcardLabelsCount
);
2719 if (res
!= NXDOMAIN
) {
2721 if (res
== INSECURE
) {
2722 /* Some part could not be validated, for example a NSEC3 record with a too large number of iterations,
2723 this is not enough to warrant a Bogus, but go Insecure. */
2725 LOG(d_prefix
<<"Unable to validate denial in wildcard expanded positive response found for "<<qname
<<", returning Insecure, res="<<res
<<endl
);
2728 LOG(d_prefix
<<"Invalid denial in wildcard expanded positive response found for "<<qname
<<", returning Bogus, res="<<res
<<endl
);
2729 rec
.d_ttl
= std::min(rec
.d_ttl
, s_maxbogusttl
);
2732 updateValidationState(state
, st
);
2733 /* we already stored the record with a different validation status, let's fix it */
2734 updateValidationStatusInCache(qname
, qtype
, lwr
.d_aabit
, st
);
2739 else if((rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::ANSWER
) {
2740 if(rec
.d_type
!= QType::RRSIG
|| rec
.d_name
== qname
) {
2741 ret
.push_back(rec
); // enjoy your DNSSEC
2742 } else if(rec
.d_type
== QType::RRSIG
&& qname
.isPartOf(rec
.d_name
)) {
2743 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
2744 if (rrsig
!= nullptr && rrsig
->d_type
== QType::DNAME
) {
2749 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::NS
&& qname
.isPartOf(rec
.d_name
)) {
2750 if(moreSpecificThan(rec
.d_name
,auth
)) {
2752 LOG(prefix
<<qname
<<": got NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2756 LOG(prefix
<<qname
<<": got upwards/level NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"', had '"<<auth
<<"'"<<endl
);
2758 if (auto content
= getRR
<NSRecordContent
>(rec
)) {
2759 nsset
.insert(content
->getNS());
2762 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::DS
&& qname
.isPartOf(rec
.d_name
)) {
2763 LOG(prefix
<<qname
<<": got DS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2765 else if(realreferral
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& (rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && newauth
.isPartOf(auth
)) {
2766 /* we might have received a denial of the DS, let's check */
2767 if (state
== Secure
) {
2768 NegCache::NegCacheEntry ne
;
2770 ne
.d_name
= newauth
;
2771 ne
.d_qtype
= QType::DS
;
2772 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2773 uint32_t lowestTTL
= rec
.d_ttl
;
2774 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2776 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, true);
2778 if (denialState
== NXQTYPE
|| denialState
== OPTOUT
|| denialState
== INSECURE
) {
2779 ne
.d_ttd
= lowestTTL
+ d_now
.tv_sec
;
2780 ne
.d_validationState
= Secure
;
2781 LOG(prefix
<<qname
<<": got negative indication of DS record for '"<<newauth
<<"'"<<endl
);
2783 if(!wasVariable()) {
2784 t_sstorage
.negcache
.add(ne
);
2787 if (qname
== newauth
&& qtype
== QType::DS
) {
2788 /* we are actually done! */
2795 else if(!done
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2796 lwr
.d_rcode
==RCode::NoError
&& qname
.isPartOf(rec
.d_name
)) {
2797 LOG(prefix
<<qname
<<": got negative caching indication for '"<< qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
2799 if(!newtarget
.empty()) {
2800 LOG(prefix
<<qname
<<": Hang on! Got a redirect to '"<<newtarget
<<"' already"<<endl
);
2803 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2805 NegCache::NegCacheEntry ne
;
2806 ne
.d_auth
= rec
.d_name
;
2807 uint32_t lowestTTL
= rec
.d_ttl
;
2810 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2812 if (state
== Secure
) {
2813 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, false);
2814 updateDenialValidationState(ne
.d_validationState
, ne
.d_name
, state
, denialState
, NXQTYPE
, qtype
== QType::DS
);
2816 ne
.d_validationState
= state
;
2819 if (ne
.d_validationState
== Bogus
) {
2820 lowestTTL
= min(lowestTTL
, s_maxbogusttl
);
2821 rec
.d_ttl
= min(rec
.d_ttl
, s_maxbogusttl
);
2823 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2825 if(!wasVariable()) {
2826 if(qtype
.getCode()) { // prevents us from blacking out a whole domain
2827 t_sstorage
.negcache
.add(ne
);
2837 if (!dnameTarget
.empty()) {
2838 // Synthesize a CNAME
2839 auto cnamerec
= DNSRecord();
2840 cnamerec
.d_name
= qname
;
2841 cnamerec
.d_type
= QType::CNAME
;
2842 cnamerec
.d_ttl
= dnameTTL
;
2843 cnamerec
.d_content
= std::make_shared
<CNAMERecordContent
>(CNAMERecordContent(newtarget
));
2844 ret
.push_back(cnamerec
);
2849 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
)
2851 bool chained
= false;
2852 int resolveret
= RCode::NoError
;
2856 if(d_outqueries
+ d_throttledqueries
> s_maxqperq
) {
2857 throw ImmediateServFailException("more than "+std::to_string(s_maxqperq
)+" (max-qperq) queries sent while resolving "+qname
.toLogString());
2860 if(s_maxtotusec
&& d_totUsec
> s_maxtotusec
) {
2861 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");
2865 LOG(prefix
<<qname
<<": using TCP with "<< remoteIP
.toStringWithPort() <<endl
);
2870 if(d_pdl
&& d_pdl
->preoutquery(remoteIP
, d_requestor
, qname
, qtype
, doTCP
, lwr
.d_records
, resolveret
)) {
2871 LOG(prefix
<<qname
<<": query handled by Lua"<<endl
);
2874 ednsmask
=getEDNSSubnetMask(qname
, remoteIP
);
2876 LOG(prefix
<<qname
<<": Adding EDNS Client Subnet Mask "<<ednsmask
->toString()<<" to query"<<endl
);
2879 resolveret
= asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(),
2880 doTCP
, sendRDQuery
, &d_now
, ednsmask
, &lwr
, &chained
); // <- we go out on the wire!
2883 LOG(prefix
<<qname
<<": Received EDNS Client Subnet Mask "<<ednsmask
->toString()<<" on response"<<endl
);
2884 if (ednsmask
->getBits() > 0) {
2885 if (ednsmask
->isIpv4()) {
2886 ++SyncRes::s_ecsResponsesBySubnetSize4
.at(ednsmask
->getBits()-1);
2889 ++SyncRes::s_ecsResponsesBySubnetSize6
.at(ednsmask
->getBits()-1);
2895 /* preoutquery killed the query by setting dq.rcode to -3 */
2896 if(resolveret
==-3) {
2897 throw ImmediateServFailException("Query killed by policy");
2900 d_totUsec
+= lwr
.d_usec
;
2901 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
2903 bool dontThrottle
= false;
2905 auto dontThrottleNames
= g_dontThrottleNames
.getLocal();
2906 auto dontThrottleNetmasks
= g_dontThrottleNetmasks
.getLocal();
2907 dontThrottle
= dontThrottleNames
->check(nsName
) || dontThrottleNetmasks
->match(remoteIP
);
2910 if(resolveret
!= 1) {
2911 /* Error while resolving */
2912 if(resolveret
== 0) {
2915 LOG(prefix
<<qname
<<": timeout resolving after "<<lwr
.d_usec
/1000.0<<"msec "<< (doTCP
? "over TCP" : "")<<endl
);
2917 s_outgoingtimeouts
++;
2919 if(remoteIP
.sin4
.sin_family
== AF_INET
)
2920 s_outgoing4timeouts
++;
2922 s_outgoing6timeouts
++;
2925 t_timeouts
->push_back(remoteIP
);
2927 else if(resolveret
== -2) {
2928 /* OS resource limit reached */
2929 LOG(prefix
<<qname
<<": hit a local resource limit resolving"<< (doTCP
? " over TCP" : "")<<", probable error: "<<stringerror()<<endl
);
2930 g_stats
.resourceLimits
++;
2933 /* -1 means server unreachable */
2936 LOG(prefix
<<qname
<<": error resolving from "<<remoteIP
.toString()<< (doTCP
? " over TCP" : "") <<", possible error: "<<strerror(errno
)<< endl
);
2939 if(resolveret
!= -2 && !chained
&& !dontThrottle
) {
2940 // don't account for resource limits, they are our own fault
2941 // And don't throttle when the IP address is on the dontThrottleNetmasks list or the name is part of dontThrottleNames
2942 t_sstorage
.nsSpeeds
[nsName
.empty()? DNSName(remoteIP
.toStringWithPort()) : nsName
].submit(remoteIP
, 1000000, &d_now
); // 1 sec
2944 // code below makes sure we don't filter COM or the root
2945 if (s_serverdownmaxfails
> 0 && (auth
!= g_rootdnsname
) && t_sstorage
.fails
.incr(remoteIP
) >= s_serverdownmaxfails
) {
2946 LOG(prefix
<<qname
<<": Max fails reached resolving on "<< remoteIP
.toString() <<". Going full throttle for "<< s_serverdownthrottletime
<<" seconds" <<endl
);
2947 // mark server as down
2948 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0), s_serverdownthrottletime
, 10000);
2950 else if (resolveret
== -1) {
2951 // unreachable, 1 minute or 100 queries
2952 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 100);
2955 // timeout, 10 seconds or 5 queries
2956 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 10, 5);
2963 /* we got an answer */
2964 if(lwr
.d_rcode
==RCode::ServFail
|| lwr
.d_rcode
==RCode::Refused
) {
2965 LOG(prefix
<<qname
<<": "<<nsName
<<" ("<<remoteIP
.toString()<<") returned a "<< (lwr
.d_rcode
==RCode::ServFail
? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl
);
2966 if (!chained
&& !dontThrottle
) {
2967 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
2972 /* this server sent a valid answer, mark it backup up if it was down */
2973 if(s_serverdownmaxfails
> 0) {
2974 t_sstorage
.fails
.clear(remoteIP
);
2980 if (doTCP
&& !dontThrottle
) {
2981 LOG(prefix
<<qname
<<": truncated bit set, over TCP?"<<endl
);
2982 /* let's treat that as a ServFail answer from this server */
2983 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
2993 bool SyncRes::processAnswer(unsigned int depth
, LWResult
& lwr
, const DNSName
& qname
, const QType
& qtype
, DNSName
& auth
, bool wasForwarded
, const boost::optional
<Netmask
> ednsmask
, bool sendRDQuery
, NsSet
&nameservers
, std::vector
<DNSRecord
>& ret
, const DNSFilterEngine
& dfe
, bool* gotNewServers
, int* rcode
, vState
& state
)
2998 prefix
.append(depth
, ' ');
3002 for(auto& rec
: lwr
.d_records
) {
3003 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumTTL
);
3007 /* if the answer is ECS-specific, a minimum TTL is set for this kind of answers
3008 and it's higher than the global minimum TTL */
3009 if (ednsmask
&& s_minimumECSTTL
> 0 && (s_minimumTTL
== 0 || s_minimumECSTTL
> s_minimumTTL
)) {
3010 for(auto& rec
: lwr
.d_records
) {
3011 if (rec
.d_place
== DNSResourceRecord::ANSWER
) {
3012 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumECSTTL
);
3017 bool needWildcardProof
= false;
3018 bool gatherWildcardProof
= false;
3019 unsigned int wildcardLabelsCount
;
3020 *rcode
= updateCacheFromRecords(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, state
, needWildcardProof
, gatherWildcardProof
, wildcardLabelsCount
, sendRDQuery
);
3021 if (*rcode
!= RCode::NoError
) {
3025 LOG(prefix
<<qname
<<": determining status after receiving this packet"<<endl
);
3028 bool realreferral
=false, negindic
=false;
3032 bool done
= processRecords(prefix
, qname
, qtype
, auth
, lwr
, sendRDQuery
, ret
, nsset
, newtarget
, newauth
, realreferral
, negindic
, state
, needWildcardProof
, gatherWildcardProof
, wildcardLabelsCount
);
3035 LOG(prefix
<<qname
<<": status=got results, this level of recursion done"<<endl
);
3036 LOG(prefix
<<qname
<<": validation status is "<<vStates
[state
]<<endl
);
3037 *rcode
= RCode::NoError
;
3041 if(!newtarget
.empty()) {
3042 if(newtarget
== qname
) {
3043 LOG(prefix
<<qname
<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl
);
3044 *rcode
= RCode::ServFail
;
3049 LOG(prefix
<<qname
<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl
);
3050 *rcode
= RCode::ServFail
;
3054 if (qtype
== QType::DS
) {
3055 LOG(prefix
<<qname
<<": status=got a CNAME referral, but we are looking for a DS"<<endl
);
3058 addNXNSECS(ret
, lwr
.d_records
);
3060 *rcode
= RCode::NoError
;
3064 LOG(prefix
<<qname
<<": status=got a CNAME referral, starting over with "<<newtarget
<<endl
);
3066 set
<GetBestNSAnswer
> beenthere2
;
3067 vState cnameState
= Indeterminate
;
3068 *rcode
= doResolve(newtarget
, qtype
, ret
, depth
+ 1, beenthere2
, cnameState
);
3069 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
3070 updateValidationState(state
, cnameState
);
3075 if(lwr
.d_rcode
== RCode::NXDomain
) {
3076 LOG(prefix
<<qname
<<": status=NXDOMAIN, we are done "<<(negindic
? "(have negative SOA)" : "")<<endl
);
3079 addNXNSECS(ret
, lwr
.d_records
);
3081 *rcode
= RCode::NXDomain
;
3085 if(nsset
.empty() && !lwr
.d_rcode
&& (negindic
|| lwr
.d_aabit
|| sendRDQuery
)) {
3086 LOG(prefix
<<qname
<<": status=noerror, other types may exist, but we are done "<<(negindic
? "(have negative SOA) " : "")<<(lwr
.d_aabit
? "(have aa bit) " : "")<<endl
);
3088 if(state
== Secure
&& (lwr
.d_aabit
|| sendRDQuery
) && !negindic
) {
3089 updateValidationState(state
, Bogus
);
3093 addNXNSECS(ret
, lwr
.d_records
);
3095 *rcode
= RCode::NoError
;
3100 LOG(prefix
<<qname
<<": status=did not resolve, got "<<(unsigned int)nsset
.size()<<" NS, ");
3102 nameservers
.clear();
3103 for (auto const &nameserver
: nsset
) {
3105 d_appliedPolicy
= dfe
.getProcessingPolicy(nameserver
, d_discardedPolicies
);
3106 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
3107 LOG("however "<<nameserver
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
3112 nameservers
.insert({nameserver
, {{}, false}});
3114 LOG("looping to them"<<endl
);
3115 *gotNewServers
= true;
3125 * -1 in case of no results
3126 * -2 when a FilterEngine Policy was hit
3129 int SyncRes::doResolveAt(NsSet
&nameservers
, DNSName auth
, bool flawedNSSet
, const DNSName
&qname
, const QType
&qtype
,
3130 vector
<DNSRecord
>&ret
,
3131 unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
, vState
& state
)
3133 auto luaconfsLocal
= g_luaconfs
.getLocal();
3137 prefix
.append(depth
, ' ');
3140 LOG(prefix
<<qname
<<": Cache consultations done, have "<<(unsigned int)nameservers
.size()<<" NS to contact");
3142 if (nameserversBlockedByRPZ(luaconfsLocal
->dfe
, nameservers
)) {
3148 for(;;) { // we may get more specific nameservers
3149 vector
<DNSName
> rnameservers
= shuffleInSpeedOrder(nameservers
, doLog() ? (prefix
+qname
.toString()+": ") : string() );
3151 for(auto tns
=rnameservers
.cbegin();;++tns
) {
3152 if(tns
==rnameservers
.cend()) {
3153 LOG(prefix
<<qname
<<": Failed to resolve via any of the "<<(unsigned int)rnameservers
.size()<<" offered NS at level '"<<auth
<<"'"<<endl
);
3154 if(!auth
.isRoot() && flawedNSSet
) {
3155 LOG(prefix
<<qname
<<": Ageing nameservers for level '"<<auth
<<"', next query might succeed"<<endl
);
3157 if(t_RC
->doAgeCache(d_now
.tv_sec
, auth
, QType::NS
, 10))
3158 g_stats
.nsSetInvalidations
++;
3163 bool cacheOnly
= false;
3164 // this line needs to identify the 'self-resolving' behaviour
3165 if(qname
== *tns
&& (qtype
.getCode() == QType::A
|| qtype
.getCode() == QType::AAAA
)) {
3166 /* we might have a glue entry in cache so let's try this NS
3167 but only if we have enough in the cache to know how to reach it */
3168 LOG(prefix
<<qname
<<": Using NS to resolve itself, but only using what we have in cache ("<<(1+tns
-rnameservers
.cbegin())<<"/"<<rnameservers
.size()<<")"<<endl
);
3172 typedef vector
<ComboAddress
> remoteIPs_t
;
3173 remoteIPs_t remoteIPs
;
3174 remoteIPs_t::const_iterator remoteIP
;
3175 bool pierceDontQuery
=false;
3176 bool sendRDQuery
=false;
3177 boost::optional
<Netmask
> ednsmask
;
3179 const bool wasForwarded
= tns
->empty() && (!nameservers
[*tns
].first
.empty());
3180 int rcode
= RCode::NoError
;
3181 bool gotNewServers
= false;
3183 if(tns
->empty() && !wasForwarded
) {
3184 LOG(prefix
<<qname
<<": Domain is out-of-band"<<endl
);
3185 /* setting state to indeterminate since validation is disabled for local auth zone,
3186 and Insecure would be misleading. */
3187 state
= Indeterminate
;
3188 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, lwr
.d_records
, depth
, lwr
.d_rcode
);
3192 /* we have received an answer, are we done ? */
3193 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, false, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
3197 if (gotNewServers
) {
3202 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
3203 remoteIPs
= retrieveAddressesForNS(prefix
, qname
, tns
, depth
, beenthere
, rnameservers
, nameservers
, sendRDQuery
, pierceDontQuery
, flawedNSSet
, cacheOnly
);
3205 if(remoteIPs
.empty()) {
3206 LOG(prefix
<<qname
<<": Failed to get IP for NS "<<*tns
<<", trying next if available"<<endl
);
3211 bool hitPolicy
{false};
3212 LOG(prefix
<<qname
<<": Resolved '"<<auth
<<"' NS "<<*tns
<<" to: ");
3213 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
3214 if(remoteIP
!= remoteIPs
.cbegin()) {
3217 LOG(remoteIP
->toString());
3218 if(nameserverIPBlockedByRPZ(luaconfsLocal
->dfe
, *remoteIP
)) {
3223 if (hitPolicy
) //implies d_wantsRPZ
3227 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
3228 LOG(prefix
<<qname
<<": Trying IP "<< remoteIP
->toStringWithPort() <<", asking '"<<qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
3230 if (throttledOrBlocked(prefix
, *remoteIP
, qname
, qtype
, pierceDontQuery
)) {
3234 bool truncated
= false;
3235 bool gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
3236 *tns
, *remoteIP
, false, &truncated
);
3237 if (gotAnswer
&& truncated
) {
3238 /* retry, over TCP this time */
3239 gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
3240 *tns
, *remoteIP
, true, &truncated
);
3247 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
);
3249 /* // for you IPv6 fanatics :-)
3250 if(remoteIP->sin4.sin_family==AF_INET6)
3253 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
3255 t_sstorage
.nsSpeeds
[tns
->empty()? DNSName(remoteIP
->toStringWithPort()) : *tns
].submit(*remoteIP
, lwr
.d_usec
, &d_now
);
3257 /* we have received an answer, are we done ? */
3258 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
3262 if (gotNewServers
) {
3266 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100);
3269 if (gotNewServers
) {
3273 if(remoteIP
== remoteIPs
.cend()) // we tried all IP addresses, none worked
3282 void SyncRes::setQuerySource(const ComboAddress
& requestor
, boost::optional
<const EDNSSubnetOpts
&> incomingECS
)
3284 d_requestor
= requestor
;
3286 if (incomingECS
&& incomingECS
->source
.getBits() > 0) {
3287 d_cacheRemote
= incomingECS
->source
.getMaskedNetwork();
3288 uint8_t bits
= std::min(incomingECS
->source
.getBits(), (incomingECS
->source
.isIpv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
3289 ComboAddress trunc
= incomingECS
->source
.getNetwork();
3290 trunc
.truncate(bits
);
3291 d_outgoingECSNetwork
= boost::optional
<Netmask
>(Netmask(trunc
, bits
));
3293 d_cacheRemote
= d_requestor
;
3294 if(!incomingECS
&& s_ednslocalsubnets
.match(d_requestor
)) {
3295 ComboAddress trunc
= d_requestor
;
3296 uint8_t bits
= d_requestor
.isIPv4() ? 32 : 128;
3297 bits
= std::min(bits
, (trunc
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
3298 trunc
.truncate(bits
);
3299 d_outgoingECSNetwork
= boost::optional
<Netmask
>(Netmask(trunc
, bits
));
3300 } else if (s_ecsScopeZero
.source
.getBits() > 0) {
3301 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0.
3302 But using an empty ECS in that case would mean inserting
3303 a non ECS-specific entry into the cache, preventing any further
3304 ECS-specific query to be sent.
3305 So instead we use the trick described in section 7.1.2:
3306 "The subsequent Recursive Resolver query to the Authoritative Nameserver
3307 will then either not include an ECS option or MAY optionally include
3308 its own address information, which is what the Authoritative
3309 Nameserver will almost certainly use to generate any Tailored
3310 Response in lieu of an option. This allows the answer to be handled
3311 by the same caching mechanism as other queries, with an explicit
3312 indicator of the applicable scope. Subsequent Stub Resolver queries
3313 for /0 can then be answered from this cached response.
3315 d_outgoingECSNetwork
= boost::optional
<Netmask
>(s_ecsScopeZero
.source
.getMaskedNetwork());
3316 d_cacheRemote
= s_ecsScopeZero
.source
.getNetwork();
3318 // ECS disabled because no scope-zero address could be derived.
3319 d_outgoingECSNetwork
= boost::none
;
3324 boost::optional
<Netmask
> SyncRes::getEDNSSubnetMask(const DNSName
& dn
, const ComboAddress
& rem
)
3326 if(d_outgoingECSNetwork
&& (s_ednsdomains
.check(dn
) || s_ednsremotesubnets
.match(rem
))) {
3327 return d_outgoingECSNetwork
;
3332 void SyncRes::parseEDNSSubnetWhitelist(const std::string
& wlist
)
3334 vector
<string
> parts
;
3335 stringtok(parts
, wlist
, ",; ");
3336 for(const auto& a
: parts
) {
3338 s_ednsremotesubnets
.addMask(Netmask(a
));
3341 s_ednsdomains
.add(DNSName(a
));
3346 void SyncRes::parseEDNSSubnetAddFor(const std::string
& subnetlist
)
3348 vector
<string
> parts
;
3349 stringtok(parts
, subnetlist
, ",; ");
3350 for(const auto& a
: parts
) {
3351 s_ednslocalsubnets
.addMask(a
);
3355 // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
3356 int directResolve(const DNSName
& qname
, const QType
& qtype
, int qclass
, vector
<DNSRecord
>& ret
)
3359 gettimeofday(&now
, 0);
3364 res
= sr
.beginResolve(qname
, QType(qtype
), qclass
, ret
);
3366 catch(const PDNSException
& e
) {
3367 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got pdns exception: "<<e
.reason
<<endl
;
3370 catch(const ImmediateServFailException
& e
) {
3371 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got ImmediateServFailException: "<<e
.reason
<<endl
;
3374 catch(const std::exception
& e
) {
3375 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got STL error: "<<e
.what()<<endl
;
3379 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got an exception"<<endl
;
3386 int SyncRes::getRootNS(struct timeval now
, asyncresolve_t asyncCallback
) {
3388 sr
.setDoEDNS0(true);
3389 sr
.setUpdatingRootNS();
3390 sr
.setDoDNSSEC(g_dnssecmode
!= DNSSECMode::Off
);
3391 sr
.setDNSSECValidationRequested(g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
);
3392 sr
.setAsyncCallback(asyncCallback
);
3394 vector
<DNSRecord
> ret
;
3397 res
=sr
.beginResolve(g_rootdnsname
, QType(QType::NS
), 1, ret
);
3398 if (g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
) {
3399 auto state
= sr
.getValidationState();
3401 throw PDNSException("Got Bogus validation result for .|NS");
3405 catch(const PDNSException
& e
) {
3406 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
3408 catch(const ImmediateServFailException
& e
) {
3409 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
3411 catch(const std::exception
& e
) {
3412 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.what()<<endl
;
3415 g_log
<<Logger::Error
<<"Failed to update . records, got an exception"<<endl
;
3419 g_log
<<Logger::Notice
<<"Refreshed . records"<<endl
;
3422 g_log
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;