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
);
2981 LOG(prefix
<<qname
<<": truncated bit set, over TCP?"<<endl
);
2982 if (!dontThrottle
) {
2983 /* let's treat that as a ServFail answer from this server */
2984 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
2988 LOG(prefix
<<qname
<<": truncated bit set, over UDP"<<endl
);
2996 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
)
3001 prefix
.append(depth
, ' ');
3005 for(auto& rec
: lwr
.d_records
) {
3006 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumTTL
);
3010 /* if the answer is ECS-specific, a minimum TTL is set for this kind of answers
3011 and it's higher than the global minimum TTL */
3012 if (ednsmask
&& s_minimumECSTTL
> 0 && (s_minimumTTL
== 0 || s_minimumECSTTL
> s_minimumTTL
)) {
3013 for(auto& rec
: lwr
.d_records
) {
3014 if (rec
.d_place
== DNSResourceRecord::ANSWER
) {
3015 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumECSTTL
);
3020 bool needWildcardProof
= false;
3021 bool gatherWildcardProof
= false;
3022 unsigned int wildcardLabelsCount
;
3023 *rcode
= updateCacheFromRecords(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, state
, needWildcardProof
, gatherWildcardProof
, wildcardLabelsCount
, sendRDQuery
);
3024 if (*rcode
!= RCode::NoError
) {
3028 LOG(prefix
<<qname
<<": determining status after receiving this packet"<<endl
);
3031 bool realreferral
=false, negindic
=false;
3035 bool done
= processRecords(prefix
, qname
, qtype
, auth
, lwr
, sendRDQuery
, ret
, nsset
, newtarget
, newauth
, realreferral
, negindic
, state
, needWildcardProof
, gatherWildcardProof
, wildcardLabelsCount
);
3038 LOG(prefix
<<qname
<<": status=got results, this level of recursion done"<<endl
);
3039 LOG(prefix
<<qname
<<": validation status is "<<vStates
[state
]<<endl
);
3040 *rcode
= RCode::NoError
;
3044 if(!newtarget
.empty()) {
3045 if(newtarget
== qname
) {
3046 LOG(prefix
<<qname
<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl
);
3047 *rcode
= RCode::ServFail
;
3052 LOG(prefix
<<qname
<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl
);
3053 *rcode
= RCode::ServFail
;
3057 if (qtype
== QType::DS
) {
3058 LOG(prefix
<<qname
<<": status=got a CNAME referral, but we are looking for a DS"<<endl
);
3061 addNXNSECS(ret
, lwr
.d_records
);
3063 *rcode
= RCode::NoError
;
3067 LOG(prefix
<<qname
<<": status=got a CNAME referral, starting over with "<<newtarget
<<endl
);
3069 set
<GetBestNSAnswer
> beenthere2
;
3070 vState cnameState
= Indeterminate
;
3071 *rcode
= doResolve(newtarget
, qtype
, ret
, depth
+ 1, beenthere2
, cnameState
);
3072 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
3073 updateValidationState(state
, cnameState
);
3078 if(lwr
.d_rcode
== RCode::NXDomain
) {
3079 LOG(prefix
<<qname
<<": status=NXDOMAIN, we are done "<<(negindic
? "(have negative SOA)" : "")<<endl
);
3082 addNXNSECS(ret
, lwr
.d_records
);
3084 *rcode
= RCode::NXDomain
;
3088 if(nsset
.empty() && !lwr
.d_rcode
&& (negindic
|| lwr
.d_aabit
|| sendRDQuery
)) {
3089 LOG(prefix
<<qname
<<": status=noerror, other types may exist, but we are done "<<(negindic
? "(have negative SOA) " : "")<<(lwr
.d_aabit
? "(have aa bit) " : "")<<endl
);
3091 if(state
== Secure
&& (lwr
.d_aabit
|| sendRDQuery
) && !negindic
) {
3092 updateValidationState(state
, Bogus
);
3096 addNXNSECS(ret
, lwr
.d_records
);
3098 *rcode
= RCode::NoError
;
3103 LOG(prefix
<<qname
<<": status=did not resolve, got "<<(unsigned int)nsset
.size()<<" NS, ");
3105 nameservers
.clear();
3106 for (auto const &nameserver
: nsset
) {
3108 d_appliedPolicy
= dfe
.getProcessingPolicy(nameserver
, d_discardedPolicies
);
3109 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
3110 LOG("however "<<nameserver
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
3115 nameservers
.insert({nameserver
, {{}, false}});
3117 LOG("looping to them"<<endl
);
3118 *gotNewServers
= true;
3128 * -1 in case of no results
3129 * -2 when a FilterEngine Policy was hit
3132 int SyncRes::doResolveAt(NsSet
&nameservers
, DNSName auth
, bool flawedNSSet
, const DNSName
&qname
, const QType
&qtype
,
3133 vector
<DNSRecord
>&ret
,
3134 unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
, vState
& state
)
3136 auto luaconfsLocal
= g_luaconfs
.getLocal();
3140 prefix
.append(depth
, ' ');
3143 LOG(prefix
<<qname
<<": Cache consultations done, have "<<(unsigned int)nameservers
.size()<<" NS to contact");
3145 if (nameserversBlockedByRPZ(luaconfsLocal
->dfe
, nameservers
)) {
3151 for(;;) { // we may get more specific nameservers
3152 vector
<DNSName
> rnameservers
= shuffleInSpeedOrder(nameservers
, doLog() ? (prefix
+qname
.toString()+": ") : string() );
3154 for(auto tns
=rnameservers
.cbegin();;++tns
) {
3155 if(tns
==rnameservers
.cend()) {
3156 LOG(prefix
<<qname
<<": Failed to resolve via any of the "<<(unsigned int)rnameservers
.size()<<" offered NS at level '"<<auth
<<"'"<<endl
);
3157 if(!auth
.isRoot() && flawedNSSet
) {
3158 LOG(prefix
<<qname
<<": Ageing nameservers for level '"<<auth
<<"', next query might succeed"<<endl
);
3160 if(t_RC
->doAgeCache(d_now
.tv_sec
, auth
, QType::NS
, 10))
3161 g_stats
.nsSetInvalidations
++;
3166 bool cacheOnly
= false;
3167 // this line needs to identify the 'self-resolving' behaviour
3168 if(qname
== *tns
&& (qtype
.getCode() == QType::A
|| qtype
.getCode() == QType::AAAA
)) {
3169 /* we might have a glue entry in cache so let's try this NS
3170 but only if we have enough in the cache to know how to reach it */
3171 LOG(prefix
<<qname
<<": Using NS to resolve itself, but only using what we have in cache ("<<(1+tns
-rnameservers
.cbegin())<<"/"<<rnameservers
.size()<<")"<<endl
);
3175 typedef vector
<ComboAddress
> remoteIPs_t
;
3176 remoteIPs_t remoteIPs
;
3177 remoteIPs_t::const_iterator remoteIP
;
3178 bool pierceDontQuery
=false;
3179 bool sendRDQuery
=false;
3180 boost::optional
<Netmask
> ednsmask
;
3182 const bool wasForwarded
= tns
->empty() && (!nameservers
[*tns
].first
.empty());
3183 int rcode
= RCode::NoError
;
3184 bool gotNewServers
= false;
3186 if(tns
->empty() && !wasForwarded
) {
3187 LOG(prefix
<<qname
<<": Domain is out-of-band"<<endl
);
3188 /* setting state to indeterminate since validation is disabled for local auth zone,
3189 and Insecure would be misleading. */
3190 state
= Indeterminate
;
3191 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, lwr
.d_records
, depth
, lwr
.d_rcode
);
3195 /* we have received an answer, are we done ? */
3196 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, false, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
3200 if (gotNewServers
) {
3205 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
3206 remoteIPs
= retrieveAddressesForNS(prefix
, qname
, tns
, depth
, beenthere
, rnameservers
, nameservers
, sendRDQuery
, pierceDontQuery
, flawedNSSet
, cacheOnly
);
3208 if(remoteIPs
.empty()) {
3209 LOG(prefix
<<qname
<<": Failed to get IP for NS "<<*tns
<<", trying next if available"<<endl
);
3214 bool hitPolicy
{false};
3215 LOG(prefix
<<qname
<<": Resolved '"<<auth
<<"' NS "<<*tns
<<" to: ");
3216 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
3217 if(remoteIP
!= remoteIPs
.cbegin()) {
3220 LOG(remoteIP
->toString());
3221 if(nameserverIPBlockedByRPZ(luaconfsLocal
->dfe
, *remoteIP
)) {
3226 if (hitPolicy
) //implies d_wantsRPZ
3230 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
3231 LOG(prefix
<<qname
<<": Trying IP "<< remoteIP
->toStringWithPort() <<", asking '"<<qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
3233 if (throttledOrBlocked(prefix
, *remoteIP
, qname
, qtype
, pierceDontQuery
)) {
3237 bool truncated
= false;
3238 bool gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
3239 *tns
, *remoteIP
, false, &truncated
);
3240 if (gotAnswer
&& truncated
) {
3241 /* retry, over TCP this time */
3242 gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
3243 *tns
, *remoteIP
, true, &truncated
);
3250 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
);
3252 /* // for you IPv6 fanatics :-)
3253 if(remoteIP->sin4.sin_family==AF_INET6)
3256 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
3258 t_sstorage
.nsSpeeds
[tns
->empty()? DNSName(remoteIP
->toStringWithPort()) : *tns
].submit(*remoteIP
, lwr
.d_usec
, &d_now
);
3260 /* we have received an answer, are we done ? */
3261 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
3265 if (gotNewServers
) {
3269 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100);
3272 if (gotNewServers
) {
3276 if(remoteIP
== remoteIPs
.cend()) // we tried all IP addresses, none worked
3285 void SyncRes::setQuerySource(const ComboAddress
& requestor
, boost::optional
<const EDNSSubnetOpts
&> incomingECS
)
3287 d_requestor
= requestor
;
3289 if (incomingECS
&& incomingECS
->source
.getBits() > 0) {
3290 d_cacheRemote
= incomingECS
->source
.getMaskedNetwork();
3291 uint8_t bits
= std::min(incomingECS
->source
.getBits(), (incomingECS
->source
.isIpv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
3292 ComboAddress trunc
= incomingECS
->source
.getNetwork();
3293 trunc
.truncate(bits
);
3294 d_outgoingECSNetwork
= boost::optional
<Netmask
>(Netmask(trunc
, bits
));
3296 d_cacheRemote
= d_requestor
;
3297 if(!incomingECS
&& s_ednslocalsubnets
.match(d_requestor
)) {
3298 ComboAddress trunc
= d_requestor
;
3299 uint8_t bits
= d_requestor
.isIPv4() ? 32 : 128;
3300 bits
= std::min(bits
, (trunc
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
3301 trunc
.truncate(bits
);
3302 d_outgoingECSNetwork
= boost::optional
<Netmask
>(Netmask(trunc
, bits
));
3303 } else if (s_ecsScopeZero
.source
.getBits() > 0) {
3304 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0.
3305 But using an empty ECS in that case would mean inserting
3306 a non ECS-specific entry into the cache, preventing any further
3307 ECS-specific query to be sent.
3308 So instead we use the trick described in section 7.1.2:
3309 "The subsequent Recursive Resolver query to the Authoritative Nameserver
3310 will then either not include an ECS option or MAY optionally include
3311 its own address information, which is what the Authoritative
3312 Nameserver will almost certainly use to generate any Tailored
3313 Response in lieu of an option. This allows the answer to be handled
3314 by the same caching mechanism as other queries, with an explicit
3315 indicator of the applicable scope. Subsequent Stub Resolver queries
3316 for /0 can then be answered from this cached response.
3318 d_outgoingECSNetwork
= boost::optional
<Netmask
>(s_ecsScopeZero
.source
.getMaskedNetwork());
3319 d_cacheRemote
= s_ecsScopeZero
.source
.getNetwork();
3321 // ECS disabled because no scope-zero address could be derived.
3322 d_outgoingECSNetwork
= boost::none
;
3327 boost::optional
<Netmask
> SyncRes::getEDNSSubnetMask(const DNSName
& dn
, const ComboAddress
& rem
)
3329 if(d_outgoingECSNetwork
&& (s_ednsdomains
.check(dn
) || s_ednsremotesubnets
.match(rem
))) {
3330 return d_outgoingECSNetwork
;
3335 void SyncRes::parseEDNSSubnetWhitelist(const std::string
& wlist
)
3337 vector
<string
> parts
;
3338 stringtok(parts
, wlist
, ",; ");
3339 for(const auto& a
: parts
) {
3341 s_ednsremotesubnets
.addMask(Netmask(a
));
3344 s_ednsdomains
.add(DNSName(a
));
3349 void SyncRes::parseEDNSSubnetAddFor(const std::string
& subnetlist
)
3351 vector
<string
> parts
;
3352 stringtok(parts
, subnetlist
, ",; ");
3353 for(const auto& a
: parts
) {
3354 s_ednslocalsubnets
.addMask(a
);
3358 // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
3359 int directResolve(const DNSName
& qname
, const QType
& qtype
, int qclass
, vector
<DNSRecord
>& ret
)
3362 gettimeofday(&now
, 0);
3367 res
= sr
.beginResolve(qname
, QType(qtype
), qclass
, ret
);
3369 catch(const PDNSException
& e
) {
3370 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got pdns exception: "<<e
.reason
<<endl
;
3373 catch(const ImmediateServFailException
& e
) {
3374 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got ImmediateServFailException: "<<e
.reason
<<endl
;
3377 catch(const std::exception
& e
) {
3378 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got STL error: "<<e
.what()<<endl
;
3382 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got an exception"<<endl
;
3389 int SyncRes::getRootNS(struct timeval now
, asyncresolve_t asyncCallback
) {
3391 sr
.setDoEDNS0(true);
3392 sr
.setUpdatingRootNS();
3393 sr
.setDoDNSSEC(g_dnssecmode
!= DNSSECMode::Off
);
3394 sr
.setDNSSECValidationRequested(g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
);
3395 sr
.setAsyncCallback(asyncCallback
);
3397 vector
<DNSRecord
> ret
;
3400 res
=sr
.beginResolve(g_rootdnsname
, QType(QType::NS
), 1, ret
);
3401 if (g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
) {
3402 auto state
= sr
.getValidationState();
3404 throw PDNSException("Got Bogus validation result for .|NS");
3408 catch(const PDNSException
& e
) {
3409 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
3411 catch(const ImmediateServFailException
& e
) {
3412 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
3414 catch(const std::exception
& e
) {
3415 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.what()<<endl
;
3418 g_log
<<Logger::Error
<<"Failed to update . records, got an exception"<<endl
;
3422 g_log
<<Logger::Notice
<<"Refreshed . records"<<endl
;
3425 g_log
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;