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
;
51 unsigned int SyncRes::s_maxnegttl
;
52 unsigned int SyncRes::s_maxbogusttl
;
53 unsigned int SyncRes::s_maxcachettl
;
54 unsigned int SyncRes::s_maxqperq
;
55 unsigned int SyncRes::s_maxtotusec
;
56 unsigned int SyncRes::s_maxdepth
;
57 unsigned int SyncRes::s_minimumTTL
;
58 unsigned int SyncRes::s_minimumECSTTL
;
59 unsigned int SyncRes::s_packetcachettl
;
60 unsigned int SyncRes::s_packetcacheservfailttl
;
61 unsigned int SyncRes::s_serverdownmaxfails
;
62 unsigned int SyncRes::s_serverdownthrottletime
;
63 std::atomic
<uint64_t> SyncRes::s_authzonequeries
;
64 std::atomic
<uint64_t> SyncRes::s_queries
;
65 std::atomic
<uint64_t> SyncRes::s_outgoingtimeouts
;
66 std::atomic
<uint64_t> SyncRes::s_outgoing4timeouts
;
67 std::atomic
<uint64_t> SyncRes::s_outgoing6timeouts
;
68 std::atomic
<uint64_t> SyncRes::s_outqueries
;
69 std::atomic
<uint64_t> SyncRes::s_tcpoutqueries
;
70 std::atomic
<uint64_t> SyncRes::s_throttledqueries
;
71 std::atomic
<uint64_t> SyncRes::s_dontqueries
;
72 std::atomic
<uint64_t> SyncRes::s_nodelegated
;
73 std::atomic
<uint64_t> SyncRes::s_unreachables
;
74 std::atomic
<uint64_t> SyncRes::s_ecsqueries
;
75 std::atomic
<uint64_t> SyncRes::s_ecsresponses
;
76 std::map
<uint8_t, std::atomic
<uint64_t>> SyncRes::s_ecsResponsesBySubnetSize4
;
77 std::map
<uint8_t, std::atomic
<uint64_t>> SyncRes::s_ecsResponsesBySubnetSize6
;
79 uint8_t SyncRes::s_ecsipv4limit
;
80 uint8_t SyncRes::s_ecsipv6limit
;
81 uint8_t SyncRes::s_ecsipv4cachelimit
;
82 uint8_t SyncRes::s_ecsipv6cachelimit
;
83 unsigned int SyncRes::s_ecscachelimitttl
;
85 bool SyncRes::s_doIPv6
;
86 bool SyncRes::s_nopacketcache
;
87 bool SyncRes::s_rootNXTrust
;
88 bool SyncRes::s_noEDNS
;
90 #define LOG(x) if(d_lm == Log) { g_log <<Logger::Warning << x; } else if(d_lm == Store) { d_trace << x; }
92 static void accountAuthLatency(int usec
, int family
)
94 if(family
== AF_INET
) {
96 g_stats
.auth4Answers0_1
++;
98 g_stats
.auth4Answers1_10
++;
99 else if(usec
< 100000)
100 g_stats
.auth4Answers10_100
++;
101 else if(usec
< 1000000)
102 g_stats
.auth4Answers100_1000
++;
104 g_stats
.auth4AnswersSlow
++;
107 g_stats
.auth6Answers0_1
++;
108 else if(usec
< 10000)
109 g_stats
.auth6Answers1_10
++;
110 else if(usec
< 100000)
111 g_stats
.auth6Answers10_100
++;
112 else if(usec
< 1000000)
113 g_stats
.auth6Answers100_1000
++;
115 g_stats
.auth6AnswersSlow
++;
121 SyncRes::SyncRes(const struct timeval
& now
) : d_authzonequeries(0), d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
122 d_totUsec(0), d_now(now
),
123 d_cacheonly(false), d_doDNSSEC(false), d_doEDNS0(false), d_lm(s_lm
)
128 /** everything begins here - this is the entry point just after receiving a packet */
129 int SyncRes::beginResolve(const DNSName
&qname
, const QType
&qtype
, uint16_t qclass
, vector
<DNSRecord
>&ret
)
131 vState state
= Indeterminate
;
134 d_wasOutOfBand
=false;
136 if (doSpecialNamesResolve(qname
, qtype
, qclass
, ret
)) {
137 d_queryValidationState
= Insecure
; // this could fool our stats into thinking a validation took place
138 return 0; // so do check before updating counters (we do now)
141 auto qtypeCode
= qtype
.getCode();
142 /* rfc6895 section 3.1 */
143 if ((qtypeCode
>= 128 && qtypeCode
<= 254) || qtypeCode
== QType::RRSIG
|| qtypeCode
== QType::NSEC3
|| qtypeCode
== QType::OPT
|| qtypeCode
== 65535) {
147 if(qclass
==QClass::ANY
)
149 else if(qclass
!=QClass::IN
)
152 set
<GetBestNSAnswer
> beenthere
;
153 int res
=doResolve(qname
, qtype
, ret
, 0, beenthere
, state
);
154 d_queryValidationState
= state
;
156 if (shouldValidate()) {
157 if (d_queryValidationState
!= Indeterminate
) {
158 g_stats
.dnssecValidations
++;
160 increaseDNSSECStateCounter(d_queryValidationState
);
166 /*! Handles all special, built-in names
167 * Fills ret with an answer and returns true if it handled the query.
169 * Handles the following queries (and their ANY variants):
172 * - localhost. IN AAAA
173 * - 1.0.0.127.in-addr.arpa. IN PTR
174 * - 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
175 * - version.bind. CH TXT
176 * - version.pdns. CH TXT
177 * - id.server. CH TXT
179 bool SyncRes::doSpecialNamesResolve(const DNSName
&qname
, const QType
&qtype
, const uint16_t qclass
, vector
<DNSRecord
> &ret
)
181 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."),
182 localhost("localhost."), versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns.");
184 bool handled
= false;
185 vector
<pair
<QType::typeenum
, string
> > answers
;
187 if ((qname
== arpa
|| qname
== ip6_arpa
) &&
188 qclass
== QClass::IN
) {
190 if (qtype
== QType::PTR
|| qtype
== QType::ANY
)
191 answers
.push_back({QType::PTR
, "localhost."});
194 if (qname
== localhost
&&
195 qclass
== QClass::IN
) {
197 if (qtype
== QType::A
|| qtype
== QType::ANY
)
198 answers
.push_back({QType::A
, "127.0.0.1"});
199 if (qtype
== QType::AAAA
|| qtype
== QType::ANY
)
200 answers
.push_back({QType::AAAA
, "::1"});
203 if ((qname
== versionbind
|| qname
== idserver
|| qname
== versionpdns
) &&
204 qclass
== QClass::CHAOS
) {
206 if (qtype
== QType::TXT
|| qtype
== QType::ANY
) {
207 if(qname
== versionbind
|| qname
== versionpdns
)
208 answers
.push_back({QType::TXT
, "\""+::arg()["version-string"]+"\""});
209 else if (s_serverID
!= "disabled")
210 answers
.push_back({QType::TXT
, "\""+s_serverID
+"\""});
214 if (handled
&& !answers
.empty()) {
220 dr
.d_place
= DNSResourceRecord::ANSWER
;
223 for (const auto& ans
: answers
) {
224 dr
.d_type
= ans
.first
;
225 dr
.d_content
= DNSRecordContent::mastermake(ans
.first
, qclass
, ans
.second
);
234 //! This is the 'out of band resolver', in other words, the authoritative server
235 void SyncRes::AuthDomain::addSOA(std::vector
<DNSRecord
>& records
) const
237 SyncRes::AuthDomain::records_t::const_iterator ziter
= d_records
.find(boost::make_tuple(getName(), QType::SOA
));
238 if (ziter
!= d_records
.end()) {
239 DNSRecord dr
= *ziter
;
240 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
241 records
.push_back(dr
);
244 // cerr<<qname<<": can't find SOA record '"<<getName()<<"' in our zone!"<<endl;
248 int SyncRes::AuthDomain::getRecords(const DNSName
& qname
, uint16_t qtype
, std::vector
<DNSRecord
>& records
) const
250 int result
= RCode::NoError
;
254 std::pair
<records_t::const_iterator
,records_t::const_iterator
> range
= d_records
.equal_range(tie(qname
));
256 SyncRes::AuthDomain::records_t::const_iterator ziter
;
257 bool somedata
= false;
259 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
262 if(qtype
== QType::ANY
|| ziter
->d_type
== qtype
|| ziter
->d_type
== QType::CNAME
) {
263 // let rest of nameserver do the legwork on this one
264 records
.push_back(*ziter
);
266 else if (ziter
->d_type
== QType::NS
&& ziter
->d_name
.countLabels() > getName().countLabels()) {
267 // we hit a delegation point!
268 DNSRecord dr
= *ziter
;
269 dr
.d_place
=DNSResourceRecord::AUTHORITY
;
270 records
.push_back(dr
);
274 if (!records
.empty()) {
275 /* We have found an exact match, we're done */
276 // cerr<<qname<<": exact match in zone '"<<getName()<<"'"<<endl;
281 /* We have records for that name, but not of the wanted qtype */
282 // cerr<<qname<<": found record in '"<<getName()<<"', but nothing of the right type, sending SOA"<<endl;
288 // cerr<<qname<<": nothing found so far in '"<<getName()<<"', trying wildcards"<<endl;
289 DNSName
wcarddomain(qname
);
290 while(wcarddomain
!= getName() && wcarddomain
.chopOff()) {
291 // cerr<<qname<<": trying '*."<<wcarddomain<<"' in "<<getName()<<endl;
292 range
= d_records
.equal_range(boost::make_tuple(g_wildcarddnsname
+ wcarddomain
));
293 if (range
.first
==range
.second
)
296 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
297 DNSRecord dr
= *ziter
;
298 // if we hit a CNAME, just answer that - rest of recursor will do the needful & follow
299 if(dr
.d_type
== qtype
|| qtype
== QType::ANY
|| dr
.d_type
== QType::CNAME
) {
301 dr
.d_place
= DNSResourceRecord::ANSWER
;
302 records
.push_back(dr
);
306 if (records
.empty()) {
310 // cerr<<qname<<": in '"<<getName()<<"', had wildcard match on '*."<<wcarddomain<<"'"<<endl;
314 /* Nothing for this name, no wildcard, let's see if there is some NS */
315 DNSName
nsdomain(qname
);
316 while (nsdomain
.chopOff() && nsdomain
!= getName()) {
317 range
= d_records
.equal_range(boost::make_tuple(nsdomain
,QType::NS
));
318 if(range
.first
== range
.second
)
321 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
322 DNSRecord dr
= *ziter
;
323 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
324 records
.push_back(dr
);
328 if(records
.empty()) {
329 // cerr<<qname<<": no NS match in zone '"<<getName()<<"' either, handing out SOA"<<endl;
331 result
= RCode::NXDomain
;
337 bool SyncRes::doOOBResolve(const AuthDomain
& domain
, const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, int& res
)
342 res
= domain
.getRecords(qname
, qtype
.getCode(), ret
);
346 bool SyncRes::doOOBResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int& res
)
351 prefix
.append(depth
, ' ');
354 DNSName
authdomain(qname
);
355 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
356 if(iter
==t_sstorage
.domainmap
->end() || !iter
->second
.isAuth()) {
357 LOG(prefix
<<qname
<<": auth storage has no zone for this query!"<<endl
);
361 LOG(prefix
<<qname
<<": auth storage has data, zone='"<<authdomain
<<"'"<<endl
);
362 return doOOBResolve(iter
->second
, qname
, qtype
, ret
, res
);
365 uint64_t SyncRes::doEDNSDump(int fd
)
367 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(dup(fd
), "w"), fclose
);
373 fprintf(fp
.get(),"; edns from thread follows\n;\n");
374 for(const auto& eds
: t_sstorage
.ednsstatus
) {
376 fprintf(fp
.get(), "%s\t%d\t%s", eds
.first
.toString().c_str(), (int)eds
.second
.mode
, ctime(&eds
.second
.modeSetAt
));
381 uint64_t SyncRes::doDumpNSSpeeds(int fd
)
383 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(dup(fd
), "w"), fclose
);
386 fprintf(fp
.get(), "; nsspeed dump from thread follows\n;\n");
389 for(const auto& i
: t_sstorage
.nsSpeeds
)
393 // an <empty> can appear hear in case of authoritative (hosted) zones
394 fprintf(fp
.get(), "%s -> ", i
.first
.toLogString().c_str());
395 for(const auto& j
: i
.second
.d_collection
)
397 // typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
398 fprintf(fp
.get(), "%s/%f ", j
.first
.toString().c_str(), j
.second
.peek());
400 fprintf(fp
.get(), "\n");
405 uint64_t SyncRes::doDumpThrottleMap(int fd
)
407 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(dup(fd
), "w"), fclose
);
410 fprintf(fp
.get(), "; throttle map dump follows\n");
411 fprintf(fp
.get(), "; remote IP\tqname\tqtype\tcount\tttd\n");
414 const auto& throttleMap
= t_sstorage
.throttle
.getThrottleMap();
415 for(const auto& i
: throttleMap
)
418 // remote IP, dns name, qtype, count, ttd
419 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
));
425 /* so here is the story. First we complete the full resolution process for a domain name. And only THEN do we decide
426 to also do DNSSEC validation, which leads to new queries. To make this simple, we *always* ask for DNSSEC records
427 so that if there are RRSIGs for a name, we'll have them.
429 However, some hosts simply can't answer questions which ask for DNSSEC. This can manifest itself as:
434 The cause of "No answer" may be fragmentation, and it is tempting to probe if smaller answers would get through.
435 Another cause of "No answer" may simply be a network condition.
436 Nonsense answers are a clearer indication this host won't be able to do DNSSEC evah.
438 Previous implementations have suffered from turning off DNSSEC questions for an authoritative server based on timeouts.
439 A clever idea is to only turn off DNSSEC if we know a domain isn't signed anyhow. The problem with that really
440 clever idea however is that at this point in PowerDNS, we may simply not know that yet. All the DNSSEC thinking happens
441 elsewhere. It may not have happened yet.
443 For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish.
446 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
448 /* what is your QUEST?
449 the goal is to get as many remotes as possible on the highest level of EDNS support
452 0) UNKNOWN Unknown state
453 1) EDNS: Honors EDNS0
454 2) EDNSIGNORANT: Ignores EDNS0, gives replies without EDNS0
455 3) NOEDNS: Generates FORMERR on EDNS queries
457 Everybody starts out assumed to be '0'.
458 If '0', send out EDNS0
459 If you FORMERR us, go to '3',
460 If no EDNS in response, go to '2'
461 If '1', send out EDNS0
462 If FORMERR, downgrade to 3
463 If '2', keep on including EDNS0, see what happens
465 If '3', send bare queries
468 SyncRes::EDNSStatus
* ednsstatus
;
469 ednsstatus
= &t_sstorage
.ednsstatus
[ip
]; // does this include port? YES
471 if(ednsstatus
->modeSetAt
&& ednsstatus
->modeSetAt
+ 3600 < d_now
.tv_sec
) {
472 *ednsstatus
=SyncRes::EDNSStatus();
473 // cerr<<"Resetting EDNS Status for "<<ip.toString()<<endl);
476 SyncRes::EDNSStatus::EDNSMode
& mode
=ednsstatus
->mode
;
477 SyncRes::EDNSStatus::EDNSMode oldmode
= mode
;
479 auto luaconfsLocal
= g_luaconfs
.getLocal();
482 ctx
.d_initialRequestId
= d_initialRequestId
;
486 for(int tries
= 0; tries
< 3; ++tries
) {
487 // cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl;
489 if(mode
==EDNSStatus::NOEDNS
) {
490 g_stats
.noEdnsOutQueries
++;
491 EDNSLevel
= 0; // level != mode
493 else if(ednsMANDATORY
|| mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
==EDNSStatus::EDNSIGNORANT
)
496 DNSName
sendQname(domain
);
497 if (g_lowercaseOutgoing
)
498 sendQname
.makeUsLowerCase();
500 if (d_asyncResolve
) {
501 ret
= d_asyncResolve(ip
, sendQname
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, res
, chained
);
504 ret
=asyncresolve(ip
, sendQname
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, d_outgoingProtobufServers
, luaconfsLocal
->outgoingProtobufExportConfig
.exportTypes
, res
, chained
);
507 return ret
; // transport error, nothing to learn here
510 if(ret
== 0) { // timeout, not doing anything with it now
513 else if(mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
== EDNSStatus::EDNSIGNORANT
) {
514 if(res
->d_validpacket
&& !res
->d_haveEDNS
&& res
->d_rcode
== RCode::FormErr
) {
515 // cerr<<"Downgrading to NOEDNS because of "<<RCode::to_s(res->d_rcode)<<" for query to "<<ip.toString()<<" for '"<<domain<<"'"<<endl;
516 mode
= EDNSStatus::NOEDNS
;
519 else if(!res
->d_haveEDNS
) {
520 if(mode
!= EDNSStatus::EDNSIGNORANT
) {
521 mode
= EDNSStatus::EDNSIGNORANT
;
522 // cerr<<"We find that "<<ip.toString()<<" is an EDNS-ignorer for '"<<domain<<"', moving to mode 2"<<endl;
526 mode
= EDNSStatus::EDNSOK
;
527 // cerr<<"We find that "<<ip.toString()<<" is EDNS OK!"<<endl;
531 if(oldmode
!= mode
|| !ednsstatus
->modeSetAt
)
532 ednsstatus
->modeSetAt
=d_now
.tv_sec
;
533 // cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", new mode: "<<mode<<endl;
539 /*! This function will check the cache and go out to the internet if the answer is not in cache
541 * \param qname The name we need an answer for
543 * \param ret The vector of DNSRecords we need to fill with the answers
544 * \param depth The recursion depth we are in
546 * \return DNS RCODE or -1 (Error) or -2 (RPZ hit)
548 int SyncRes::doResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, vState
& state
)
553 prefix
.append(depth
, ' ');
556 LOG(prefix
<<qname
<<": Wants "<< (d_doDNSSEC
? "" : "NO ") << "DNSSEC processing, "<<(d_requireAuthData
? "" : "NO ")<<"auth data in query for "<<qtype
.getName()<<endl
);
558 state
= Indeterminate
;
560 if(s_maxdepth
&& depth
> s_maxdepth
)
561 throw ImmediateServFailException("More than "+std::to_string(s_maxdepth
)+" (max-recursion-depth) levels of recursion needed while resolving "+qname
.toLogString());
565 // This is a difficult way of expressing "this is a normal query", i.e. not getRootNS.
566 if(!(d_updatingRootNS
&& qtype
.getCode()==QType::NS
&& qname
.isRoot())) {
567 if(d_cacheonly
) { // very limited OOB support
569 LOG(prefix
<<qname
<<": Recursion not requested for '"<<qname
<<"|"<<qtype
.getName()<<"', peeking at auth/forward zones"<<endl
);
570 DNSName
authname(qname
);
571 domainmap_t::const_iterator iter
=getBestAuthZone(&authname
);
572 if(iter
!= t_sstorage
.domainmap
->end()) {
573 if(iter
->second
.isAuth()) {
575 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, ret
, depth
, res
);
579 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
580 const ComboAddress remoteIP
= servers
.front();
581 LOG(prefix
<<qname
<<": forwarding query to hardcoded nameserver '"<< remoteIP
.toStringWithPort()<<"' for zone '"<<authname
<<"'"<<endl
);
583 boost::optional
<Netmask
> nm
;
584 bool chained
= false;
585 res
=asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(), false, false, &d_now
, nm
, &lwr
, &chained
);
587 d_totUsec
+= lwr
.d_usec
;
588 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
590 // filter out the good stuff from lwr.result()
592 for(const auto& rec
: lwr
.d_records
) {
593 if(rec
.d_place
== DNSResourceRecord::ANSWER
)
599 return RCode::ServFail
;
605 DNSName
authname(qname
);
606 bool wasForwardedOrAuthZone
= false;
607 bool wasAuthZone
= false;
608 bool wasForwardRecurse
= false;
609 domainmap_t::const_iterator iter
= getBestAuthZone(&authname
);
610 if(iter
!= t_sstorage
.domainmap
->end()) {
611 const auto& domain
= iter
->second
;
612 wasForwardedOrAuthZone
= true;
614 if (domain
.isAuth()) {
616 } else if (domain
.shouldRecurse()) {
617 wasForwardRecurse
= true;
621 if(!d_skipCNAMECheck
&& doCNAMECacheCheck(qname
, qtype
, ret
, depth
, res
, state
, wasAuthZone
, wasForwardRecurse
)) { // will reroute us if needed
622 d_wasOutOfBand
= wasAuthZone
;
626 if(doCacheCheck(qname
, authname
, wasForwardedOrAuthZone
, wasAuthZone
, wasForwardRecurse
, qtype
, ret
, depth
, res
, state
)) {
628 d_wasOutOfBand
= wasAuthZone
;
636 LOG(prefix
<<qname
<<": No cache hit for '"<<qname
<<"|"<<qtype
.getName()<<"', trying to find an appropriate NS record"<<endl
);
638 DNSName
subdomain(qname
);
639 if(qtype
== QType::DS
) subdomain
.chopOff();
642 bool flawedNSSet
=false;
644 /* we use subdomain here instead of qname because for DS queries we only care about the state of the parent zone */
645 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
647 // the two retries allow getBestNSNamesFromCache&co to reprime the root
648 // hints, in case they ever go missing
649 for(int tries
=0;tries
<2 && nsset
.empty();++tries
) {
650 subdomain
=getBestNSNamesFromCache(subdomain
, qtype
, nsset
, &flawedNSSet
, depth
, beenthere
); // pass beenthere to both occasions
653 state
= getValidationStatus(qname
, false);
655 LOG(prefix
<<qname
<<": initial validation status for "<<qname
<<" is "<<vStates
[state
]<<endl
);
657 if(!(res
=doResolveAt(nsset
, subdomain
, flawedNSSet
, qname
, qtype
, ret
, depth
, beenthere
, state
)))
660 LOG(prefix
<<qname
<<": failed (res="<<res
<<")"<<endl
);
665 return res
<0 ? RCode::ServFail
: res
;
669 // for testing purposes
670 static bool ipv6First(const ComboAddress
& a
, const ComboAddress
& b
)
672 return !(a
.sin4
.sin_family
< a
.sin4
.sin_family
);
678 speedOrderCA(std::map
<ComboAddress
,double>& speeds
): d_speeds(speeds
) {}
679 bool operator()(const ComboAddress
& a
, const ComboAddress
& b
) const
681 return d_speeds
[a
] < d_speeds
[b
];
683 std::map
<ComboAddress
, double>& d_speeds
;
686 /** This function explicitly goes out for A or AAAA addresses
688 vector
<ComboAddress
> SyncRes::getAddrs(const DNSName
&qname
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, bool cacheOnly
)
690 typedef vector
<DNSRecord
> res_t
;
693 typedef vector
<ComboAddress
> ret_t
;
697 bool oldCacheOnly
= d_cacheonly
;
698 bool oldRequireAuthData
= d_requireAuthData
;
699 bool oldValidationRequested
= d_DNSSECValidationRequested
;
700 d_requireAuthData
= false;
701 d_DNSSECValidationRequested
= false;
702 d_cacheonly
= cacheOnly
;
704 for(int j
=1; j
<2+s_doIPv6
; j
++)
719 vState newState
= Indeterminate
;
720 if(!doResolve(qname
, type
, res
,depth
+1, beenthere
, newState
) && !res
.empty()) { // this consults cache, OR goes out
721 for(res_t::const_iterator i
=res
.begin(); i
!= res
.end(); ++i
) {
722 if(i
->d_type
== QType::A
|| i
->d_type
== QType::AAAA
) {
723 if(auto rec
= getRR
<ARecordContent
>(*i
))
724 ret
.push_back(rec
->getCA(53));
725 else if(auto aaaarec
= getRR
<AAAARecordContent
>(*i
))
726 ret
.push_back(aaaarec
->getCA(53));
732 if(j
==1 && s_doIPv6
) { // we got an A record, see if we have some AAAA lying around
733 vector
<DNSRecord
> cset
;
734 if(t_RC
->get(d_now
.tv_sec
, qname
, QType(QType::AAAA
), false, &cset
, d_cacheRemote
) > 0) {
735 for(auto k
=cset
.cbegin();k
!=cset
.cend();++k
) {
736 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
737 if (auto drc
= getRR
<AAAARecordContent
>(*k
)) {
738 ComboAddress ca
=drc
->getCA(53);
749 d_requireAuthData
= oldRequireAuthData
;
750 d_DNSSECValidationRequested
= oldValidationRequested
;
751 d_cacheonly
= oldCacheOnly
;
753 /* we need to remove from the nsSpeeds collection the existing IPs
754 for this nameserver that are no longer in the set, even if there
755 is only one or none at all in the current set.
757 map
<ComboAddress
, double> speeds
;
758 auto& collection
= t_sstorage
.nsSpeeds
[qname
].d_collection
;
759 for(const auto& val
: ret
) {
760 speeds
[val
] = collection
[val
].get(&d_now
);
763 t_sstorage
.nsSpeeds
[qname
].purge(speeds
);
766 random_shuffle(ret
.begin(), ret
.end(), dns_random
);
767 speedOrderCA
so(speeds
);
768 stable_sort(ret
.begin(), ret
.end(), so
);
771 string prefix
=d_prefix
;
772 prefix
.append(depth
, ' ');
773 LOG(prefix
<<"Nameserver "<<qname
<<" IPs: ");
775 for(const auto& addr
: ret
) {
782 LOG((addr
.toString())<<"(" << (boost::format("%0.2f") % (speeds
[addr
]/1000.0)).str() <<"ms)");
791 void SyncRes::getBestNSFromCache(const DNSName
&qname
, const QType
& qtype
, vector
<DNSRecord
>& bestns
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
)
794 DNSName
subdomain(qname
);
797 prefix
.append(depth
, ' ');
803 LOG(prefix
<<qname
<<": Checking if we have NS in cache for '"<<subdomain
<<"'"<<endl
);
804 vector
<DNSRecord
> ns
;
805 *flawedNSSet
= false;
807 if(t_RC
->get(d_now
.tv_sec
, subdomain
, QType(QType::NS
), false, &ns
, d_cacheRemote
) > 0) {
808 for(auto k
=ns
.cbegin();k
!=ns
.cend(); ++k
) {
809 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
810 vector
<DNSRecord
> aset
;
812 const DNSRecord
& dr
=*k
;
813 auto nrr
= getRR
<NSRecordContent
>(dr
);
814 if(nrr
&& (!nrr
->getNS().isPartOf(subdomain
) || t_RC
->get(d_now
.tv_sec
, nrr
->getNS(), s_doIPv6
? QType(QType::ADDR
) : QType(QType::A
),
815 false, doLog() ? &aset
: 0, d_cacheRemote
) > 5)) {
816 bestns
.push_back(dr
);
817 LOG(prefix
<<qname
<<": NS (with ip, or non-glue) in cache for '"<<subdomain
<<"' -> '"<<nrr
->getNS()<<"'"<<endl
);
818 LOG(prefix
<<qname
<<": within bailiwick: "<< nrr
->getNS().isPartOf(subdomain
));
820 LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset
.begin()->d_ttl
- d_now
.tv_sec
))<<endl
);
823 LOG(", not in cache / did not look at cache"<<endl
);
828 LOG(prefix
<<qname
<<": NS in cache for '"<<subdomain
<<"', but needs glue ("<<nrr
->getNS()<<") which we miss or is expired"<<endl
);
833 if(!bestns
.empty()) {
834 GetBestNSAnswer answer
;
836 answer
.qtype
=qtype
.getCode();
837 for(const auto& dr
: bestns
) {
838 if (auto nsContent
= getRR
<NSRecordContent
>(dr
)) {
839 answer
.bestns
.insert(make_pair(dr
.d_name
, nsContent
->getNS()));
843 if(beenthere
.count(answer
)) {
845 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' but part of LOOP (already seen "<<answer
.qname
<<")! Trying less specific NS"<<endl
);
848 for( set
<GetBestNSAnswer
>::const_iterator j
=beenthere
.begin();j
!=beenthere
.end();++j
) {
849 bool neo
= !(*j
< answer
|| answer
<*j
);
850 LOG(prefix
<<qname
<<": beenthere"<<(neo
?"*":"")<<": "<<j
->qname
<<"|"<<DNSRecordContent::NumberToType(j
->qtype
)<<" ("<<(unsigned int)j
->bestns
.size()<<")"<<endl
);
855 beenthere
.insert(answer
);
856 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' (flawedNSSet="<<*flawedNSSet
<<")"<<endl
);
861 LOG(prefix
<<qname
<<": no valid/useful NS in cache for '"<<subdomain
<<"'"<<endl
);
863 if(subdomain
.isRoot() && !brokeloop
) {
864 // We lost the root NS records
866 LOG(prefix
<<qname
<<": reprimed the root"<<endl
);
867 /* let's prevent an infinite loop */
868 if (!d_updatingRootNS
) {
869 getRootNS(d_now
, d_asyncResolve
);
872 } while(subdomain
.chopOff());
875 SyncRes::domainmap_t::const_iterator
SyncRes::getBestAuthZone(DNSName
* qname
) const
877 SyncRes::domainmap_t::const_iterator ret
;
879 ret
=t_sstorage
.domainmap
->find(*qname
);
880 if(ret
!=t_sstorage
.domainmap
->end())
882 }while(qname
->chopOff());
886 /** doesn't actually do the work, leaves that to getBestNSFromCache */
887 DNSName
SyncRes::getBestNSNamesFromCache(const DNSName
&qname
, const QType
& qtype
, NsSet
& nsset
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
)
889 DNSName
subdomain(qname
);
890 DNSName
authdomain(qname
);
892 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
893 if(iter
!=t_sstorage
.domainmap
->end()) {
894 if( iter
->second
.isAuth() )
895 // this gets picked up in doResolveAt, the empty DNSName, combined with the
896 // empty vector means 'we are auth for this zone'
897 nsset
.insert({DNSName(), {{}, false}});
899 // Again, picked up in doResolveAt. An empty DNSName, combined with a
900 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
901 // This is actually picked up in retrieveAddressesForNS called from doResolveAt.
902 nsset
.insert({DNSName(), {iter
->second
.d_servers
, iter
->second
.shouldRecurse() }});
907 vector
<DNSRecord
> bestns
;
908 getBestNSFromCache(subdomain
, qtype
, bestns
, flawedNSSet
, depth
, beenthere
);
910 for(auto k
=bestns
.cbegin() ; k
!= bestns
.cend(); ++k
) {
911 // The actual resolver code will not even look at the ComboAddress or bool
912 const auto nsContent
= getRR
<NSRecordContent
>(*k
);
914 nsset
.insert({nsContent
->getNS(), {{}, false}});
915 if(k
==bestns
.cbegin())
922 void SyncRes::updateValidationStatusInCache(const DNSName
&qname
, const QType
& qt
, bool aa
, vState newState
) const
924 if (newState
== Bogus
) {
925 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qt
, d_cacheRemote
, aa
, newState
, s_maxbogusttl
+ d_now
.tv_sec
);
928 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qt
, d_cacheRemote
, aa
, newState
, boost::none
);
932 bool SyncRes::doCNAMECacheCheck(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>& ret
, unsigned int depth
, int &res
, vState
& state
, bool wasAuthZone
, bool wasForwardRecurse
)
937 prefix
.append(depth
, ' ');
940 if((depth
>9 && d_outqueries
>10 && d_throttledqueries
>5) || depth
> 15) {
941 LOG(prefix
<<qname
<<": recursing (CNAME or other indirection) too deep, depth="<<depth
<<endl
);
946 LOG(prefix
<<qname
<<": Looking for CNAME cache hit of '"<<qname
<<"|CNAME"<<"'"<<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();
952 /* we don't require auth data for forward-recurse lookups */
953 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) {
955 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
956 if (j
->d_class
!= QClass::IN
) {
960 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
962 if (!wasAuthZone
&& shouldValidate() && (wasAuth
|| wasForwardRecurse
) && state
== Indeterminate
&& d_requireAuthData
) {
963 /* This means we couldn't figure out the state when this entry was cached,
964 most likely because we hadn't computed the zone cuts yet. */
965 /* make sure they are computed before validating */
966 DNSName
subdomain(qname
);
967 /* if we are retrieving a DS, we only care about the state of the parent zone */
968 if(qtype
== QType::DS
)
971 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
973 vState recordState
= getValidationStatus(qname
, false);
974 if (recordState
== Secure
) {
975 LOG(prefix
<<qname
<<": got Indeterminate state from the CNAME cache, validating.."<<endl
);
976 state
= SyncRes::validateRecordsWithSigs(depth
, qname
, QType(QType::CNAME
), qname
, cset
, signatures
);
977 if (state
!= Indeterminate
) {
978 LOG(prefix
<<qname
<<": got Indeterminate state from the CNAME cache, new validation result is "<<vStates
[state
]<<endl
);
979 if (state
== Bogus
) {
980 capTTL
= s_maxbogusttl
;
982 updateValidationStatusInCache(qname
, QType(QType::CNAME
), wasAuth
, state
);
987 LOG(prefix
<<qname
<<": Found cache CNAME hit for '"<< qname
<< "|CNAME" <<"' to '"<<j
->d_content
->getZoneRepresentation()<<"', validation state is "<<vStates
[state
]<<endl
);
990 dr
.d_ttl
-= d_now
.tv_sec
;
991 dr
.d_ttl
= std::min(dr
.d_ttl
, capTTL
);
992 const uint32_t ttl
= dr
.d_ttl
;
993 ret
.reserve(ret
.size() + 1 + signatures
.size() + authorityRecs
.size());
996 for(const auto& signature
: signatures
) {
998 sigdr
.d_type
=QType::RRSIG
;
1001 sigdr
.d_content
=signature
;
1002 sigdr
.d_place
=DNSResourceRecord::ANSWER
;
1003 sigdr
.d_class
=QClass::IN
;
1004 ret
.push_back(sigdr
);
1007 for(const auto& rec
: authorityRecs
) {
1008 DNSRecord
authDR(*rec
);
1010 ret
.push_back(authDR
);
1013 if(qtype
!= QType::CNAME
) { // perhaps they really wanted a CNAME!
1014 set
<GetBestNSAnswer
>beenthere
;
1016 vState cnameState
= Indeterminate
;
1017 const auto cnameContent
= getRR
<CNAMERecordContent
>(*j
);
1019 res
=doResolve(cnameContent
->getTarget(), qtype
, ret
, depth
+1, beenthere
, cnameState
);
1020 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
1021 updateValidationState(state
, cnameState
);
1031 LOG(prefix
<<qname
<<": No CNAME cache hit of '"<< qname
<< "|CNAME" <<"' found"<<endl
);
1038 vector
<DNSRecord
> records
;
1039 vector
<shared_ptr
<RRSIGRecordContent
>> signatures
;
1040 uint32_t signaturesTTL
{std::numeric_limits
<uint32_t>::max()};
1046 DNSResourceRecord::Place place
;
1047 bool operator<(const CacheKey
& rhs
) const {
1048 return tie(name
, type
, place
) < tie(rhs
.name
, rhs
.type
, rhs
.place
);
1051 typedef map
<CacheKey
, CacheEntry
> tcache_t
;
1054 static void reapRecordsFromNegCacheEntryForValidation(tcache_t
& tcache
, const vector
<DNSRecord
>& records
)
1056 for (const auto& rec
: records
) {
1057 if (rec
.d_type
== QType::RRSIG
) {
1058 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1060 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
1063 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(rec
);
1069 * Convience function to push the records from records into ret with a new TTL
1071 * \param records DNSRecords that need to go into ret
1072 * \param ttl The new TTL for these records
1073 * \param ret The vector of DNSRecords that should contian the records with the modified TTL
1075 static void addTTLModifiedRecords(const vector
<DNSRecord
>& records
, const uint32_t ttl
, vector
<DNSRecord
>& ret
) {
1076 for (const auto& rec
: records
) {
1083 void SyncRes::computeNegCacheValidationStatus(const NegCache::NegCacheEntry
* ne
, const DNSName
& qname
, const QType
& qtype
, const int res
, vState
& state
, unsigned int depth
)
1085 DNSName
subdomain(qname
);
1086 /* if we are retrieving a DS, we only care about the state of the parent zone */
1087 if(qtype
== QType::DS
)
1088 subdomain
.chopOff();
1090 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1093 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->authoritySOA
.records
);
1094 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->authoritySOA
.signatures
);
1095 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->DNSSECRecords
.records
);
1096 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->DNSSECRecords
.signatures
);
1098 for (const auto& entry
: tcache
) {
1099 // this happens when we did store signatures, but passed on the records themselves
1100 if (entry
.second
.records
.empty()) {
1104 const DNSName
& owner
= entry
.first
.name
;
1106 vState recordState
= getValidationStatus(owner
, false);
1107 if (state
== Indeterminate
) {
1108 state
= recordState
;
1111 if (recordState
== Secure
) {
1112 recordState
= SyncRes::validateRecordsWithSigs(depth
, qname
, qtype
, owner
, entry
.second
.records
, entry
.second
.signatures
);
1115 if (recordState
!= Indeterminate
&& recordState
!= state
) {
1116 updateValidationState(state
, recordState
);
1117 if (state
!= Secure
) {
1123 if (state
== Secure
) {
1124 vState neValidationState
= ne
->d_validationState
;
1125 dState expectedState
= res
== RCode::NXDomain
? NXDOMAIN
: NXQTYPE
;
1126 dState denialState
= getDenialValidationState(*ne
, state
, expectedState
, false);
1127 updateDenialValidationState(neValidationState
, ne
->d_name
, state
, denialState
, expectedState
, qtype
== QType::DS
);
1129 if (state
!= Indeterminate
) {
1130 /* validation succeeded, let's update the cache entry so we don't have to validate again */
1131 boost::optional
<uint32_t> capTTD
= boost::none
;
1132 if (state
== Bogus
) {
1133 capTTD
= d_now
.tv_sec
+ s_maxbogusttl
;
1135 t_sstorage
.negcache
.updateValidationStatus(ne
->d_name
, ne
->d_qtype
, state
, capTTD
);
1139 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
)
1141 bool giveNegative
=false;
1146 prefix
.append(depth
, ' ');
1149 // 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)
1150 DNSName
sqname(qname
);
1153 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
1155 const NegCache::NegCacheEntry
* ne
= nullptr;
1158 t_sstorage
.negcache
.getRootNXTrust(qname
, d_now
, &ne
) &&
1159 ne
->d_auth
.isRoot() &&
1160 !(wasForwardedOrAuthZone
&& !authname
.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
1161 sttl
= ne
->d_ttd
- d_now
.tv_sec
;
1162 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
->d_auth
<<"' & '"<<ne
->d_name
<<"' for another "<<sttl
<<" seconds"<<endl
);
1163 res
= RCode::NXDomain
;
1164 giveNegative
= true;
1165 cachedState
= ne
->d_validationState
;
1167 else if (t_sstorage
.negcache
.get(qname
, qtype
, d_now
, &ne
)) {
1168 /* If we are looking for a DS, discard NXD if auth == qname
1169 and ask for a specific denial instead */
1170 if (qtype
!= QType::DS
|| ne
->d_qtype
.getCode() || ne
->d_auth
!= qname
||
1171 t_sstorage
.negcache
.get(qname
, qtype
, d_now
, &ne
, true))
1174 sttl
= ne
->d_ttd
- d_now
.tv_sec
;
1175 giveNegative
= true;
1176 cachedState
= ne
->d_validationState
;
1177 if(ne
->d_qtype
.getCode()) {
1178 LOG(prefix
<<qname
<<": "<<qtype
.getName()<<" is negatively cached via '"<<ne
->d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1179 res
= RCode::NoError
;
1182 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
->d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1183 res
= RCode::NXDomain
;
1190 state
= cachedState
;
1192 if (!wasAuthZone
&& shouldValidate() && state
== Indeterminate
) {
1193 LOG(prefix
<<qname
<<": got Indeterminate state for records retrieved from the negative cache, validating.."<<endl
);
1194 computeNegCacheValidationStatus(ne
, qname
, qtype
, res
, state
, depth
);
1196 if (state
!= cachedState
&& state
== Bogus
) {
1197 sttl
= std::min(sttl
, s_maxbogusttl
);
1201 // Transplant SOA to the returned packet
1202 addTTLModifiedRecords(ne
->authoritySOA
.records
, sttl
, ret
);
1204 addTTLModifiedRecords(ne
->authoritySOA
.signatures
, sttl
, ret
);
1205 addTTLModifiedRecords(ne
->DNSSECRecords
.records
, sttl
, ret
);
1206 addTTLModifiedRecords(ne
->DNSSECRecords
.signatures
, sttl
, ret
);
1209 LOG(prefix
<<qname
<<": updating validation state with negative cache content for "<<qname
<<" to "<<vStates
[state
]<<endl
);
1213 vector
<DNSRecord
> cset
;
1214 bool found
=false, expired
=false;
1215 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
1216 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1218 uint32_t capTTL
= std::numeric_limits
<uint32_t>::max();
1220 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) {
1222 LOG(prefix
<<sqname
<<": Found cache hit for "<<sqt
.getName()<<": ");
1224 if (!wasAuthZone
&& shouldValidate() && (wasCachedAuth
|| wasForwardRecurse
) && cachedState
== Indeterminate
&& d_requireAuthData
) {
1226 /* This means we couldn't figure out the state when this entry was cached,
1227 most likely because we hadn't computed the zone cuts yet. */
1228 /* make sure they are computed before validating */
1229 DNSName
subdomain(sqname
);
1230 /* if we are retrieving a DS, we only care about the state of the parent zone */
1231 if(qtype
== QType::DS
)
1232 subdomain
.chopOff();
1234 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1236 vState recordState
= getValidationStatus(qname
, false);
1237 if (recordState
== Secure
) {
1238 LOG(prefix
<<sqname
<<": got Indeterminate state from the cache, validating.."<<endl
);
1239 cachedState
= SyncRes::validateRecordsWithSigs(depth
, sqname
, sqt
, sqname
, cset
, signatures
);
1242 cachedState
= recordState
;
1245 if (cachedState
!= Indeterminate
) {
1246 LOG(prefix
<<qname
<<": got Indeterminate state from the cache, validation result is "<<vStates
[cachedState
]<<endl
);
1247 if (cachedState
== Bogus
) {
1248 capTTL
= s_maxbogusttl
;
1250 updateValidationStatusInCache(sqname
, sqt
, wasCachedAuth
, cachedState
);
1254 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
1256 LOG(j
->d_content
->getZoneRepresentation());
1258 if (j
->d_class
!= QClass::IN
) {
1262 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
1264 dr
.d_ttl
-= d_now
.tv_sec
;
1265 dr
.d_ttl
= std::min(dr
.d_ttl
, capTTL
);
1268 LOG("[ttl="<<dr
.d_ttl
<<"] ");
1277 ret
.reserve(ret
.size() + signatures
.size() + authorityRecs
.size());
1279 for(const auto& signature
: signatures
) {
1281 dr
.d_type
=QType::RRSIG
;
1284 dr
.d_content
=signature
;
1285 dr
.d_place
= DNSResourceRecord::ANSWER
;
1286 dr
.d_class
=QClass::IN
;
1290 for(const auto& rec
: authorityRecs
) {
1297 if(found
&& !expired
) {
1300 LOG(prefix
<<qname
<<": updating validation state with cache content for "<<qname
<<" to "<<vStates
[cachedState
]<<endl
);
1301 state
= cachedState
;
1305 LOG(prefix
<<qname
<<": cache had only stale entries"<<endl
);
1311 bool SyncRes::moreSpecificThan(const DNSName
& a
, const DNSName
&b
) const
1313 return (a
.isPartOf(b
) && a
.countLabels() > b
.countLabels());
1318 speedOrder(map
<DNSName
,double> &speeds
) : d_speeds(speeds
) {}
1319 bool operator()(const DNSName
&a
, const DNSName
&b
) const
1321 return d_speeds
[a
] < d_speeds
[b
];
1323 map
<DNSName
, double>& d_speeds
;
1326 inline vector
<DNSName
> SyncRes::shuffleInSpeedOrder(NsSet
&tnameservers
, const string
&prefix
)
1328 vector
<DNSName
> rnameservers
;
1329 rnameservers
.reserve(tnameservers
.size());
1330 for(const auto& tns
: tnameservers
) {
1331 rnameservers
.push_back(tns
.first
);
1332 if(tns
.first
.empty()) // this was an authoritative OOB zone, don't pollute the nsSpeeds with that
1333 return rnameservers
;
1335 map
<DNSName
, double> speeds
;
1337 for(const auto& val
: rnameservers
) {
1339 speed
=t_sstorage
.nsSpeeds
[val
].get(&d_now
);
1342 random_shuffle(rnameservers
.begin(),rnameservers
.end(), dns_random
);
1343 speedOrder
so(speeds
);
1344 stable_sort(rnameservers
.begin(),rnameservers
.end(), so
);
1347 LOG(prefix
<<"Nameservers: ");
1348 for(vector
<DNSName
>::const_iterator i
=rnameservers
.begin();i
!=rnameservers
.end();++i
) {
1349 if(i
!=rnameservers
.begin()) {
1351 if(!((i
-rnameservers
.begin())%3)) {
1352 LOG(endl
<<prefix
<<" ");
1355 LOG(i
->toLogString()<<"(" << (boost::format("%0.2f") % (speeds
[*i
]/1000.0)).str() <<"ms)");
1359 return rnameservers
;
1362 inline vector
<ComboAddress
> SyncRes::shuffleForwardSpeed(const vector
<ComboAddress
> &rnameservers
, const string
&prefix
, const bool wasRd
)
1364 vector
<ComboAddress
> nameservers
= rnameservers
;
1365 map
<ComboAddress
, double> speeds
;
1367 for(const auto& val
: nameservers
) {
1369 DNSName nsName
= DNSName(val
.toStringWithPort());
1370 speed
=t_sstorage
.nsSpeeds
[nsName
].get(&d_now
);
1373 random_shuffle(nameservers
.begin(),nameservers
.end(), dns_random
);
1374 speedOrderCA
so(speeds
);
1375 stable_sort(nameservers
.begin(),nameservers
.end(), so
);
1378 LOG(prefix
<<"Nameservers: ");
1379 for(vector
<ComboAddress
>::const_iterator i
=nameservers
.cbegin();i
!=nameservers
.cend();++i
) {
1380 if(i
!=nameservers
.cbegin()) {
1382 if(!((i
-nameservers
.cbegin())%3)) {
1383 LOG(endl
<<prefix
<<" ");
1386 LOG((wasRd
? string("+") : string("-")) << i
->toStringWithPort() <<"(" << (boost::format("%0.2f") % (speeds
[*i
]/1000.0)).str() <<"ms)");
1393 static uint32_t getRRSIGTTL(const time_t now
, const std::shared_ptr
<RRSIGRecordContent
>& rrsig
)
1396 if (now
< rrsig
->d_sigexpire
) {
1397 res
= static_cast<uint32_t>(rrsig
->d_sigexpire
) - now
;
1402 static const set
<uint16_t> nsecTypes
= {QType::NSEC
, QType::NSEC3
};
1404 /* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
1406 * \param records The records to parse for the authority SOA and NSEC(3) records
1407 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
1409 static void harvestNXRecords(const vector
<DNSRecord
>& records
, NegCache::NegCacheEntry
& ne
, const time_t now
, uint32_t* lowestTTL
) {
1410 for(const auto& rec
: records
) {
1411 if(rec
.d_place
!= DNSResourceRecord::AUTHORITY
)
1412 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
1413 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
1414 // records MUST be in the same section as the records they cover.
1415 // Hence, we ignore all records outside of the AUTHORITY section.
1418 if(rec
.d_type
== QType::RRSIG
) {
1419 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1421 if(rrsig
->d_type
== QType::SOA
) {
1422 ne
.authoritySOA
.signatures
.push_back(rec
);
1423 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1424 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1425 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1428 if(nsecTypes
.count(rrsig
->d_type
)) {
1429 ne
.DNSSECRecords
.signatures
.push_back(rec
);
1430 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1431 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1432 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1438 if(rec
.d_type
== QType::SOA
) {
1439 ne
.authoritySOA
.records
.push_back(rec
);
1441 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1445 if(nsecTypes
.count(rec
.d_type
)) {
1446 ne
.DNSSECRecords
.records
.push_back(rec
);
1448 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1455 static cspmap_t
harvestCSPFromNE(const NegCache::NegCacheEntry
& ne
)
1458 for(const auto& rec
: ne
.DNSSECRecords
.signatures
) {
1459 if(rec
.d_type
== QType::RRSIG
) {
1460 auto rrc
= getRR
<RRSIGRecordContent
>(rec
);
1462 cspmap
[{rec
.d_name
,rrc
->d_type
}].signatures
.push_back(rrc
);
1466 for(const auto& rec
: ne
.DNSSECRecords
.records
) {
1467 cspmap
[{rec
.d_name
, rec
.d_type
}].records
.push_back(rec
.d_content
);
1472 // TODO remove after processRecords is fixed!
1473 // Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
1474 static void addNXNSECS(vector
<DNSRecord
>&ret
, const vector
<DNSRecord
>& records
)
1476 NegCache::NegCacheEntry ne
;
1477 harvestNXRecords(records
, ne
, 0, nullptr);
1478 ret
.insert(ret
.end(), ne
.authoritySOA
.signatures
.begin(), ne
.authoritySOA
.signatures
.end());
1479 ret
.insert(ret
.end(), ne
.DNSSECRecords
.records
.begin(), ne
.DNSSECRecords
.records
.end());
1480 ret
.insert(ret
.end(), ne
.DNSSECRecords
.signatures
.begin(), ne
.DNSSECRecords
.signatures
.end());
1483 bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine
& dfe
, const NsSet
& nameservers
)
1486 for (auto const &ns
: nameservers
) {
1487 d_appliedPolicy
= dfe
.getProcessingPolicy(ns
.first
, d_discardedPolicies
);
1488 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1489 LOG(", however nameserver "<<ns
.first
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1493 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1494 for (auto const &address
: ns
.second
.first
) {
1495 d_appliedPolicy
= dfe
.getProcessingPolicy(address
, d_discardedPolicies
);
1496 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1497 LOG(", however nameserver "<<ns
.first
<<" IP address "<<address
.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1506 bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine
& dfe
, const ComboAddress
& remoteIP
)
1509 d_appliedPolicy
= dfe
.getProcessingPolicy(remoteIP
, d_discardedPolicies
);
1510 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) {
1511 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")+"')");
1518 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
)
1520 vector
<ComboAddress
> result
;
1523 LOG(prefix
<<qname
<<": Trying to resolve NS '"<<*tns
<< "' ("<<1+tns
-rnameservers
.begin()<<"/"<<(unsigned int)rnameservers
.size()<<")"<<endl
);
1524 result
= getAddrs(*tns
, depth
+2, beenthere
, cacheOnly
);
1525 pierceDontQuery
=false;
1528 LOG(prefix
<<qname
<<": Domain has hardcoded nameserver");
1530 if(nameservers
[*tns
].first
.size() > 1) {
1535 sendRDQuery
= nameservers
[*tns
].second
;
1536 result
= shuffleForwardSpeed(nameservers
[*tns
].first
, doLog() ? (prefix
+qname
.toString()+": ") : string(), sendRDQuery
);
1537 pierceDontQuery
=true;
1542 bool SyncRes::throttledOrBlocked(const std::string
& prefix
, const ComboAddress
& remoteIP
, const DNSName
& qname
, const QType
& qtype
, bool pierceDontQuery
)
1544 if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0))) {
1545 LOG(prefix
<<qname
<<": server throttled "<<endl
);
1546 s_throttledqueries
++; d_throttledqueries
++;
1549 else if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()))) {
1550 LOG(prefix
<<qname
<<": query throttled "<<remoteIP
.toString()<<", "<<qname
<<"; "<<qtype
.getName()<<endl
);
1551 s_throttledqueries
++; d_throttledqueries
++;
1554 else if(!pierceDontQuery
&& s_dontQuery
&& s_dontQuery
->match(&remoteIP
)) {
1555 LOG(prefix
<<qname
<<": not sending query to " << remoteIP
.toString() << ", blocked by 'dont-query' setting" << endl
);
1562 bool SyncRes::validationEnabled() const
1564 return g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
;
1567 uint32_t SyncRes::computeLowestTTD(const std::vector
<DNSRecord
>& records
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, uint32_t signaturesTTL
) const
1569 uint32_t lowestTTD
= std::numeric_limits
<uint32_t>::max();
1570 for(const auto& record
: records
)
1571 lowestTTD
= min(lowestTTD
, record
.d_ttl
);
1573 /* even if it was not requested for that request (Process, and neither AD nor DO set),
1574 it might be requested at a later time so we need to be careful with the TTL. */
1575 if (validationEnabled() && !signatures
.empty()) {
1576 /* if we are validating, we don't want to cache records after their signatures expire. */
1577 /* records TTL are now TTD, let's add 'now' to the signatures lowest TTL */
1578 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(signaturesTTL
+ d_now
.tv_sec
));
1580 for(const auto& sig
: signatures
) {
1581 if (isRRSIGNotExpired(d_now
.tv_sec
, sig
)) {
1582 // we don't decerement d_sigexpire by 'now' because we actually want a TTD, not a TTL */
1583 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(sig
->d_sigexpire
));
1591 void SyncRes::updateValidationState(vState
& state
, const vState stateUpdate
)
1593 LOG(d_prefix
<<"validation state was "<<std::string(vStates
[state
])<<", state update is "<<std::string(vStates
[stateUpdate
]));
1595 if (stateUpdate
== TA
) {
1598 else if (stateUpdate
== NTA
) {
1601 else if (stateUpdate
== Bogus
) {
1604 else if (state
== Indeterminate
) {
1605 state
= stateUpdate
;
1607 else if (stateUpdate
== Insecure
) {
1608 if (state
!= Bogus
) {
1612 LOG(", validation state is now "<<std::string(vStates
[state
])<<endl
);
1615 vState
SyncRes::getTA(const DNSName
& zone
, dsmap_t
& ds
)
1617 auto luaLocal
= g_luaconfs
.getLocal();
1619 if (luaLocal
->dsAnchors
.empty()) {
1620 LOG(d_prefix
<<": No trust anchors configured, everything is Insecure"<<endl
);
1621 /* We have no TA, everything is insecure */
1626 if (haveNegativeTrustAnchor(luaLocal
->negAnchors
, zone
, reason
)) {
1627 LOG(d_prefix
<<": got NTA for '"<<zone
<<"'"<<endl
);
1631 if (getTrustAnchor(luaLocal
->dsAnchors
, zone
, ds
)) {
1632 LOG(d_prefix
<<": got TA for '"<<zone
<<"'"<<endl
);
1636 LOG(d_prefix
<<": no TA found for '"<<zone
<<"' among "<< luaLocal
->dsAnchors
.size()<<endl
);
1639 if (zone
.isRoot()) {
1640 /* No TA for the root */
1644 return Indeterminate
;
1647 static size_t countSupportedDS(const dsmap_t
& dsmap
)
1651 for (const auto& ds
: dsmap
) {
1652 if (isSupportedDS(ds
)) {
1660 vState
SyncRes::getDSRecords(const DNSName
& zone
, dsmap_t
& ds
, bool taOnly
, unsigned int depth
, bool bogusOnNXD
, bool* foundCut
)
1662 vState result
= getTA(zone
, ds
);
1664 if (result
!= Indeterminate
|| taOnly
) {
1666 *foundCut
= (result
!= Indeterminate
);
1670 if (countSupportedDS(ds
) == 0) {
1678 else if (result
== NTA
) {
1685 bool oldSkipCNAME
= d_skipCNAMECheck
;
1686 d_skipCNAMECheck
= true;
1688 std::set
<GetBestNSAnswer
> beenthere
;
1689 std::vector
<DNSRecord
> dsrecords
;
1691 vState state
= Indeterminate
;
1692 int rcode
= doResolve(zone
, QType(QType::DS
), dsrecords
, depth
+ 1, beenthere
, state
);
1693 d_skipCNAMECheck
= oldSkipCNAME
;
1695 if (rcode
== RCode::NoError
|| (rcode
== RCode::NXDomain
&& !bogusOnNXD
)) {
1697 uint8_t bestDigestType
= 0;
1699 if (state
== Secure
) {
1700 bool gotCNAME
= false;
1701 for (const auto& record
: dsrecords
) {
1702 if (record
.d_type
== QType::DS
) {
1703 const auto dscontent
= getRR
<DSRecordContent
>(record
);
1704 if (dscontent
&& isSupportedDS(*dscontent
)) {
1705 // Make GOST a lower prio than SHA256
1706 if (dscontent
->d_digesttype
== DNSSECKeeper::GOST
&& bestDigestType
== DNSSECKeeper::SHA256
) {
1709 if (dscontent
->d_digesttype
> bestDigestType
|| (bestDigestType
== DNSSECKeeper::GOST
&& dscontent
->d_digesttype
== DNSSECKeeper::SHA256
)) {
1710 bestDigestType
= dscontent
->d_digesttype
;
1712 ds
.insert(*dscontent
);
1715 else if (record
.d_type
== QType::CNAME
&& record
.d_name
== zone
) {
1720 /* RFC 4509 section 3: "Validator implementations SHOULD ignore DS RRs containing SHA-1
1721 * digests if DS RRs with SHA-256 digests are present in the DS RRset."
1722 * As SHA348 is specified as well, the spirit of the this line is "use the best algorithm".
1724 for (auto dsrec
= ds
.begin(); dsrec
!= ds
.end(); ) {
1725 if (dsrec
->d_digesttype
!= bestDigestType
) {
1726 dsrec
= ds
.erase(dsrec
);
1733 if (rcode
== RCode::NoError
&& ds
.empty()) {
1735 if (gotCNAME
|| denialProvesNoDelegation(zone
, dsrecords
)) {
1736 /* we are still inside the same Secure zone */
1746 } else if (foundCut
&& rcode
== RCode::NoError
&& !ds
.empty()) {
1754 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
1758 bool SyncRes::haveExactValidationStatus(const DNSName
& domain
)
1760 if (!shouldValidate()) {
1763 const auto& it
= d_cutStates
.find(domain
);
1764 if (it
!= d_cutStates
.cend()) {
1770 vState
SyncRes::getValidationStatus(const DNSName
& subdomain
, bool allowIndeterminate
)
1772 vState result
= Indeterminate
;
1774 if (!shouldValidate()) {
1777 DNSName
name(subdomain
);
1779 const auto& it
= d_cutStates
.find(name
);
1780 if (it
!= d_cutStates
.cend()) {
1781 if (allowIndeterminate
|| it
->second
!= Indeterminate
) {
1782 LOG(d_prefix
<<": got status "<<vStates
[it
->second
]<<" for name "<<subdomain
<<" (from "<<name
<<")"<<endl
);
1787 while (name
.chopOff());
1792 bool SyncRes::lookForCut(const DNSName
& qname
, unsigned int depth
, const vState existingState
, vState
& newState
)
1794 bool foundCut
= false;
1796 vState dsState
= getDSRecords(qname
, ds
, newState
== Bogus
|| existingState
== Insecure
|| existingState
== Bogus
, depth
, false, &foundCut
);
1798 if (dsState
!= Indeterminate
) {
1805 void SyncRes::computeZoneCuts(const DNSName
& begin
, const DNSName
& end
, unsigned int depth
)
1807 if(!begin
.isPartOf(end
)) {
1808 LOG(d_prefix
<<" "<<begin
.toLogString()<<" is not part of "<<end
.toLogString()<<endl
);
1809 throw PDNSException(begin
.toLogString() + " is not part of " + end
.toLogString());
1812 if (d_cutStates
.count(begin
) != 0) {
1817 vState cutState
= getDSRecords(end
, ds
, false, depth
);
1818 LOG(d_prefix
<<": setting cut state for "<<end
<<" to "<<vStates
[cutState
]<<endl
);
1819 d_cutStates
[end
] = cutState
;
1821 if (!shouldValidate()) {
1826 std::vector
<string
> labelsToAdd
= begin
.makeRelative(end
).getRawLabels();
1828 bool oldSkipCNAME
= d_skipCNAMECheck
;
1829 d_skipCNAMECheck
= true;
1831 while(qname
!= begin
) {
1832 if (labelsToAdd
.empty())
1835 qname
.prependRawLabel(labelsToAdd
.back());
1836 labelsToAdd
.pop_back();
1837 LOG(d_prefix
<<": - Looking for a cut at "<<qname
<<endl
);
1839 const auto cutIt
= d_cutStates
.find(qname
);
1840 if (cutIt
!= d_cutStates
.cend()) {
1841 if (cutIt
->second
!= Indeterminate
) {
1842 LOG(d_prefix
<<": - Cut already known at "<<qname
<<endl
);
1843 cutState
= cutIt
->second
;
1848 /* no need to look for NS and DS if we are already insecure or bogus,
1851 if (cutState
== Insecure
|| cutState
== Bogus
) {
1853 vState newState
= getDSRecords(qname
, cutDS
, true, depth
);
1854 if (newState
== Indeterminate
) {
1858 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[newState
]<<endl
);
1859 cutState
= newState
;
1861 d_cutStates
[qname
] = cutState
;
1866 vState newState
= Indeterminate
;
1867 /* temporarily mark as Indeterminate, so that we won't enter an endless loop
1868 trying to determine that zone cut again. */
1869 d_cutStates
[qname
] = newState
;
1870 bool foundCut
= lookForCut(qname
, depth
+ 1, cutState
, newState
);
1872 LOG(d_prefix
<<": - Found cut at "<<qname
<<endl
);
1873 if (newState
!= Indeterminate
) {
1874 cutState
= newState
;
1876 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[cutState
]<<endl
);
1877 d_cutStates
[qname
] = cutState
;
1880 /* remove the temporary cut */
1881 LOG(d_prefix
<<qname
<<": removing cut state for "<<qname
<<endl
);
1882 d_cutStates
.erase(qname
);
1886 d_skipCNAMECheck
= oldSkipCNAME
;
1888 LOG(d_prefix
<<": list of cuts from "<<begin
<<" to "<<end
<<endl
);
1889 for (const auto& cut
: d_cutStates
) {
1890 if (cut
.first
.isRoot() || (begin
.isPartOf(cut
.first
) && cut
.first
.isPartOf(end
))) {
1891 LOG(" - "<<cut
.first
<<": "<<vStates
[cut
.second
]<<endl
);
1896 vState
SyncRes::validateDNSKeys(const DNSName
& zone
, const std::vector
<DNSRecord
>& dnskeys
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, unsigned int depth
)
1899 if (!signatures
.empty()) {
1900 DNSName signer
= getSigner(signatures
);
1902 if (!signer
.empty() && zone
.isPartOf(signer
)) {
1903 vState state
= getDSRecords(signer
, ds
, false, depth
);
1905 if (state
!= Secure
) {
1911 skeyset_t tentativeKeys
;
1912 std::vector
<shared_ptr
<DNSRecordContent
> > toSign
;
1914 for (const auto& dnskey
: dnskeys
) {
1915 if (dnskey
.d_type
== QType::DNSKEY
) {
1916 auto content
= getRR
<DNSKEYRecordContent
>(dnskey
);
1918 tentativeKeys
.insert(content
);
1919 toSign
.push_back(content
);
1924 LOG(d_prefix
<<": trying to validate "<<std::to_string(tentativeKeys
.size())<<" DNSKEYs with "<<std::to_string(ds
.size())<<" DS"<<endl
);
1925 skeyset_t validatedKeys
;
1926 validateDNSKeysAgainstDS(d_now
.tv_sec
, zone
, ds
, tentativeKeys
, toSign
, signatures
, validatedKeys
);
1928 LOG(d_prefix
<<": we now have "<<std::to_string(validatedKeys
.size())<<" DNSKEYs"<<endl
);
1930 /* if we found at least one valid RRSIG covering the set,
1931 all tentative keys are validated keys. Otherwise it means
1932 we haven't found at least one DNSKEY and a matching RRSIG
1933 covering this set, this looks Bogus. */
1934 if (validatedKeys
.size() != tentativeKeys
.size()) {
1935 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
1942 vState
SyncRes::getDNSKeys(const DNSName
& signer
, skeyset_t
& keys
, unsigned int depth
)
1944 std::vector
<DNSRecord
> records
;
1945 std::set
<GetBestNSAnswer
> beenthere
;
1946 LOG(d_prefix
<<"Retrieving DNSKeys for "<<signer
<<endl
);
1948 vState state
= Indeterminate
;
1949 /* following CNAME might lead to us to the wrong DNSKEY */
1950 bool oldSkipCNAME
= d_skipCNAMECheck
;
1951 d_skipCNAMECheck
= true;
1952 int rcode
= doResolve(signer
, QType(QType::DNSKEY
), records
, depth
+ 1, beenthere
, state
);
1953 d_skipCNAMECheck
= oldSkipCNAME
;
1955 if (rcode
== RCode::NoError
) {
1956 if (state
== Secure
) {
1957 for (const auto& key
: records
) {
1958 if (key
.d_type
== QType::DNSKEY
) {
1959 auto content
= getRR
<DNSKEYRecordContent
>(key
);
1961 keys
.insert(content
);
1966 LOG(d_prefix
<<"Retrieved "<<keys
.size()<<" DNSKeys for "<<signer
<<", state is "<<vStates
[state
]<<endl
);
1970 LOG(d_prefix
<<"Returning Bogus state from "<<__func__
<<"("<<signer
<<")"<<endl
);
1974 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
)
1977 if (!signatures
.empty()) {
1978 const DNSName signer
= getSigner(signatures
);
1979 if (!signer
.empty() && name
.isPartOf(signer
)) {
1980 if ((qtype
== QType::DNSKEY
|| qtype
== QType::DS
) && signer
== qname
) {
1981 /* we are already retrieving those keys, sorry */
1982 return Indeterminate
;
1984 vState state
= getDNSKeys(signer
, keys
, depth
);
1985 if (state
!= Secure
) {
1990 LOG(d_prefix
<<"Bogus!"<<endl
);
1994 std::vector
<std::shared_ptr
<DNSRecordContent
> > recordcontents
;
1995 for (const auto& record
: records
) {
1996 recordcontents
.push_back(record
.d_content
);
1999 LOG(d_prefix
<<"Going to validate "<<recordcontents
.size()<< " record contents with "<<signatures
.size()<<" sigs and "<<keys
.size()<<" keys for "<<name
<<endl
);
2000 if (validateWithKeySet(d_now
.tv_sec
, name
, recordcontents
, signatures
, keys
, false)) {
2001 LOG(d_prefix
<<"Secure!"<<endl
);
2005 LOG(d_prefix
<<"Bogus!"<<endl
);
2009 static bool allowAdditionalEntry(std::unordered_set
<DNSName
>& allowedAdditionals
, const DNSRecord
& rec
)
2011 switch(rec
.d_type
) {
2014 if (auto mxContent
= getRR
<MXRecordContent
>(rec
)) {
2015 allowedAdditionals
.insert(mxContent
->d_mxname
);
2021 if (auto nsContent
= getRR
<NSRecordContent
>(rec
)) {
2022 allowedAdditionals
.insert(nsContent
->getNS());
2028 if (auto srvContent
= getRR
<SRVRecordContent
>(rec
)) {
2029 allowedAdditionals
.insert(srvContent
->d_target
);
2038 void SyncRes::sanitizeRecords(const std::string
& prefix
, LWResult
& lwr
, const DNSName
& qname
, const QType
& qtype
, const DNSName
& auth
, bool wasForwarded
, bool rdQuery
)
2040 const bool wasForwardRecurse
= wasForwarded
&& rdQuery
;
2041 /* list of names for which we will allow A and AAAA records in the additional section
2043 std::unordered_set
<DNSName
> allowedAdditionals
= { qname
};
2044 bool haveAnswers
= false;
2045 bool isNXDomain
= false;
2046 bool isNXQType
= false;
2048 for(auto rec
= lwr
.d_records
.begin(); rec
!= lwr
.d_records
.end(); ) {
2050 if (rec
->d_type
== QType::OPT
) {
2055 if (rec
->d_class
!= QClass::IN
) {
2056 LOG(prefix
<<"Removing non internet-classed data received from "<<auth
<<endl
);
2057 rec
= lwr
.d_records
.erase(rec
);
2061 if (rec
->d_type
== QType::ANY
) {
2062 LOG(prefix
<<"Removing 'ANY'-typed data received from "<<auth
<<endl
);
2063 rec
= lwr
.d_records
.erase(rec
);
2067 if (!rec
->d_name
.isPartOf(auth
)) {
2068 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
);
2069 rec
= lwr
.d_records
.erase(rec
);
2073 /* dealing with the records in answer */
2074 if (!(lwr
.d_aabit
|| wasForwardRecurse
) && rec
->d_place
== DNSResourceRecord::ANSWER
) {
2075 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2076 are sending such responses */
2077 if (!(rec
->d_type
== QType::CNAME
&& qname
== rec
->d_name
)) {
2078 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
);
2079 rec
= lwr
.d_records
.erase(rec
);
2084 if (rec
->d_type
== QType::DNAME
&& (rec
->d_place
!= DNSResourceRecord::ANSWER
|| !qname
.isPartOf(rec
->d_name
))) {
2085 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
);
2086 rec
= lwr
.d_records
.erase(rec
);
2090 if (rec
->d_place
== DNSResourceRecord::ANSWER
&& (qtype
!= QType::ANY
&& rec
->d_type
!= qtype
.getCode() && rec
->d_type
!= QType::CNAME
&& rec
->d_type
!= QType::SOA
&& rec
->d_type
!= QType::RRSIG
)) {
2091 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
);
2092 rec
= lwr
.d_records
.erase(rec
);
2096 if (rec
->d_place
== DNSResourceRecord::ANSWER
&& !haveAnswers
) {
2100 if (rec
->d_place
== DNSResourceRecord::ANSWER
) {
2101 allowAdditionalEntry(allowedAdditionals
, *rec
);
2104 /* dealing with the records in authority */
2105 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
) {
2106 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
);
2107 rec
= lwr
.d_records
.erase(rec
);
2111 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::SOA
) {
2112 if (!qname
.isPartOf(rec
->d_name
)) {
2113 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
);
2114 rec
= lwr
.d_records
.erase(rec
);
2118 if (!(lwr
.d_aabit
|| wasForwardRecurse
)) {
2119 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
);
2120 rec
= lwr
.d_records
.erase(rec
);
2125 if (lwr
.d_rcode
== RCode::NXDomain
) {
2128 else if (lwr
.d_rcode
== RCode::NoError
) {
2134 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::NS
&& (isNXDomain
|| isNXQType
)) {
2135 /* we don't want to pick up NS records in AUTHORITY or ADDITIONAL sections of NXDomain answers
2136 because they are somewhat easy to insert into a large, fragmented UDP response
2137 for an off-path attacker by injecting spoofed UDP fragments.
2139 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
);
2140 rec
= lwr
.d_records
.erase(rec
);
2144 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::NS
) {
2145 allowAdditionalEntry(allowedAdditionals
, *rec
);
2148 /* dealing with the records in additional */
2149 if (rec
->d_place
== DNSResourceRecord::ADDITIONAL
&& rec
->d_type
!= QType::A
&& rec
->d_type
!= QType::AAAA
&& rec
->d_type
!= QType::RRSIG
) {
2150 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
);
2151 rec
= lwr
.d_records
.erase(rec
);
2155 if (rec
->d_place
== DNSResourceRecord::ADDITIONAL
&& allowedAdditionals
.count(rec
->d_name
) == 0) {
2156 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
);
2157 rec
= lwr
.d_records
.erase(rec
);
2165 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
, unsigned int& wildcardLabelsCount
, bool rdQuery
)
2167 bool wasForwardRecurse
= wasForwarded
&& rdQuery
;
2173 prefix
.append(depth
, ' ');
2176 sanitizeRecords(prefix
, lwr
, qname
, qtype
, auth
, wasForwarded
, rdQuery
);
2178 std::vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
2179 const unsigned int labelCount
= qname
.countLabels();
2180 bool isCNAMEAnswer
= false;
2181 for(const auto& rec
: lwr
.d_records
) {
2182 if (rec
.d_class
!= QClass::IN
) {
2186 if(!isCNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
) {
2187 isCNAMEAnswer
= true;
2190 /* if we have a positive answer synthetized from a wildcard,
2191 we need to store the corresponding NSEC/NSEC3 records proving
2192 that the exact name did not exist in the negative cache */
2193 if(needWildcardProof
) {
2194 if (nsecTypes
.count(rec
.d_type
)) {
2195 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
2197 else if (rec
.d_type
== QType::RRSIG
) {
2198 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
2199 if (rrsig
&& nsecTypes
.count(rrsig
->d_type
)) {
2200 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
2204 if(rec
.d_type
== QType::RRSIG
) {
2205 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
2207 /* As illustrated in rfc4035's Appendix B.6, the RRSIG label
2208 count can be lower than the name's label count if it was
2209 synthetized from the wildcard. Note that the difference might
2211 if (rec
.d_name
== qname
&& rrsig
->d_labels
< labelCount
) {
2212 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthetized from a wildcard, we need a wildcard proof"<<endl
);
2213 needWildcardProof
= true;
2214 wildcardLabelsCount
= rrsig
->d_labels
;
2217 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
2218 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
2219 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
);
2224 // reap all answers from this packet that are acceptable
2225 for(auto& rec
: lwr
.d_records
) {
2226 if(rec
.d_type
== QType::OPT
) {
2227 LOG(prefix
<<qname
<<": OPT answer '"<<rec
.d_name
<<"' from '"<<auth
<<"' nameservers" <<endl
);
2230 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
<<" ");
2231 if(rec
.d_type
== QType::ANY
) {
2232 LOG("NO! - we don't accept 'ANY'-typed data"<<endl
);
2236 if(rec
.d_class
!= QClass::IN
) {
2237 LOG("NO! - we don't accept records for any other class than 'IN'"<<endl
);
2241 if (!(lwr
.d_aabit
|| wasForwardRecurse
) && rec
.d_place
== DNSResourceRecord::ANSWER
) {
2242 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2243 are sending such responses */
2244 if (!(rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
)) {
2245 LOG("NO! - we don't accept records in the answers section without the AA bit set"<<endl
);
2250 if(rec
.d_name
.isPartOf(auth
)) {
2251 if(rec
.d_type
== QType::RRSIG
) {
2252 LOG("RRSIG - separate"<<endl
);
2254 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
)) {
2255 LOG("NO! Is from delegation-only zone"<<endl
);
2257 return RCode::NXDomain
;
2260 bool haveLogged
= false;
2261 if (!t_sstorage
.domainmap
->empty()) {
2262 // Check if we are authoritative for a zone in this answer
2263 DNSName
tmp_qname(rec
.d_name
);
2264 auto auth_domain_iter
=getBestAuthZone(&tmp_qname
);
2265 if(auth_domain_iter
!=t_sstorage
.domainmap
->end() &&
2266 auth
.countLabels() <= auth_domain_iter
->first
.countLabels()) {
2267 if (auth_domain_iter
->first
!= auth
) {
2268 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter
->first
<<endl
);
2271 LOG("YES! - This answer was ");
2272 if (!wasForwarded
) {
2273 LOG("retrieved from the local auth store.");
2275 LOG("received from a server we forward to.");
2286 rec
.d_ttl
=min(s_maxcachettl
, rec
.d_ttl
);
2289 dr
.d_ttl
+= d_now
.tv_sec
;
2290 dr
.d_place
=DNSResourceRecord::ANSWER
;
2291 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(dr
);
2299 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2300 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)
2301 uint32_t lowestTTD
=computeLowestTTD(i
->second
.records
, i
->second
.signatures
, i
->second
.signaturesTTL
);
2303 for(auto& record
: i
->second
.records
)
2304 record
.d_ttl
= lowestTTD
; // boom
2307 // cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
2308 // cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
2311 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2313 if(i
->second
.records
.empty()) // this happens when we did store signatures, but passed on the records themselves
2316 /* Even if the AA bit is set, additional data cannot be considered
2317 as authoritative. This is especially important during validation
2318 because keeping records in the additional section is allowed even
2319 if the corresponding RRSIGs are not included, without setting the TC
2320 bit, as stated in rfc4035's section 3.1.1. Including RRSIG RRs in a Response:
2321 "When placing a signed RRset in the Additional section, the name
2322 server MUST also place its RRSIG RRs in the Additional section.
2323 If space does not permit inclusion of both the RRset and its
2324 associated RRSIG RRs, the name server MAY retain the RRset while
2325 dropping the RRSIG RRs. If this happens, the name server MUST NOT
2326 set the TC bit solely because these RRSIG RRs didn't fit."
2328 bool isAA
= lwr
.d_aabit
&& i
->first
.place
!= DNSResourceRecord::ADDITIONAL
;
2329 /* if we forwarded the query to a recursor, we can expect the answer to be signed,
2330 even if the answer is not AA. Of course that's not only true inside a Secure
2331 zone, but we check that below. */
2332 bool expectSignature
= i
->first
.place
== DNSResourceRecord::ANSWER
|| ((lwr
.d_aabit
|| wasForwardRecurse
) && i
->first
.place
!= DNSResourceRecord::ADDITIONAL
);
2333 if (isCNAMEAnswer
&& (i
->first
.place
!= DNSResourceRecord::ANSWER
|| i
->first
.type
!= QType::CNAME
|| i
->first
.name
!= qname
)) {
2336 Note that the answer section of an authoritative answer normally
2337 contains only authoritative data. However when the name sought is an
2338 alias (see section 10.1.1) only the record describing that alias is
2339 necessarily authoritative. Clients should assume that other records
2340 may have come from the server's cache. Where authoritative answers
2341 are required, the client should query again, using the canonical name
2342 associated with the alias.
2345 expectSignature
= false;
2348 if (isCNAMEAnswer
&& i
->first
.place
== DNSResourceRecord::AUTHORITY
&& i
->first
.type
== QType::NS
&& auth
== i
->first
.name
) {
2349 /* These NS can't be authoritative since we have a CNAME answer for which (see above) only the
2350 record describing that alias is necessarily authoritative.
2351 But if we allow the current auth, which might be serving the child zone, to raise the TTL
2352 of non-authoritative NS in the cache, they might be able to keep a "ghost" zone alive forever,
2353 even after the delegation is gone from the parent.
2354 So let's just do nothing with them, we can fetch them directly if we need them.
2356 LOG(d_prefix
<<": skipping authority NS from '"<<auth
<<"' nameservers in CNAME answer "<<i
->first
.name
<<"|"<<DNSRecordContent::NumberToType(i
->first
.type
)<<endl
);
2360 vState recordState
= getValidationStatus(i
->first
.name
, false);
2361 LOG(d_prefix
<<": got initial zone status "<<vStates
[recordState
]<<" for record "<<i
->first
.name
<<"|"<<DNSRecordContent::NumberToType(i
->first
.type
)<<endl
);
2363 if (shouldValidate() && recordState
== Secure
) {
2364 vState initialState
= recordState
;
2366 if (expectSignature
) {
2367 if (i
->first
.place
!= DNSResourceRecord::ADDITIONAL
) {
2368 /* the additional entries can be insecure,
2370 "Glue address RRsets associated with delegations MUST NOT be signed"
2372 if (i
->first
.type
== QType::DNSKEY
&& i
->first
.place
== DNSResourceRecord::ANSWER
) {
2373 LOG(d_prefix
<<"Validating DNSKEY for "<<i
->first
.name
<<endl
);
2374 recordState
= validateDNSKeys(i
->first
.name
, i
->second
.records
, i
->second
.signatures
, depth
);
2377 LOG(d_prefix
<<"Validating non-additional record for "<<i
->first
.name
<<endl
);
2378 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2379 /* 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 */
2380 if (qtype
== QType::NS
&& i
->second
.signatures
.empty() && recordState
== Bogus
&& haveExactValidationStatus(i
->first
.name
) && getValidationStatus(i
->first
.name
) == Indeterminate
) {
2381 recordState
= Indeterminate
;
2387 recordState
= Indeterminate
;
2389 /* in a non authoritative answer, we only care about the DS record (or lack of) */
2390 if ((i
->first
.type
== QType::DS
|| i
->first
.type
== QType::NSEC
|| i
->first
.type
== QType::NSEC3
) && i
->first
.place
== DNSResourceRecord::AUTHORITY
) {
2391 LOG(d_prefix
<<"Validating DS record for "<<i
->first
.name
<<endl
);
2392 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2396 if (initialState
== Secure
&& state
!= recordState
&& expectSignature
) {
2397 updateValidationState(state
, recordState
);
2401 if (shouldValidate()) {
2402 LOG(d_prefix
<<"Skipping validation because the current state is "<<vStates
[recordState
]<<endl
);
2406 if (recordState
== Bogus
) {
2407 /* this is a TTD by now, be careful */
2408 for(auto& record
: i
->second
.records
) {
2409 record
.d_ttl
= std::min(record
.d_ttl
, static_cast<uint32_t>(s_maxbogusttl
+ d_now
.tv_sec
));
2413 /* We don't need to store NSEC3 records in the positive cache because:
2414 - we don't allow direct NSEC3 queries
2415 - denial of existence proofs in wildcard expanded positive responses are stored in authorityRecs
2416 - denial of existence proofs for negative responses are stored in the negative cache
2417 We also don't want to cache non-authoritative data except for:
2418 - records coming from non forward-recurse servers (those will never be AA)
2420 - NS, A and AAAA (used for infra queries)
2422 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
)) {
2423 if (i
->first
.place
!= DNSResourceRecord::ANSWER
||
2425 (ednsmask
->isIpv4() && ednsmask
->getBits() <= SyncRes::s_ecsipv4cachelimit
) ||
2426 (ednsmask
->isIpv6() && ednsmask
->getBits() <= SyncRes::s_ecsipv6cachelimit
)) {
2428 if (ednsmask
&& SyncRes::s_ecscachelimitttl
> 0) {
2429 minTTD
= SyncRes::s_ecscachelimitttl
+ d_now
.tv_sec
;
2431 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
, minTTD
, recordState
);
2435 if(i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
)
2439 return RCode::NoError
;
2442 void SyncRes::updateDenialValidationState(vState
& neValidationState
, const DNSName
& neName
, vState
& state
, const dState denialState
, const dState expectedState
, bool allowOptOut
)
2444 if (denialState
== expectedState
) {
2445 neValidationState
= Secure
;
2448 if (denialState
== OPTOUT
&& allowOptOut
) {
2449 LOG(d_prefix
<<"OPT-out denial found for "<<neName
<<endl
);
2450 neValidationState
= Secure
;
2453 else if (denialState
== INSECURE
) {
2454 LOG(d_prefix
<<"Insecure denial found for "<<neName
<<", returning Insecure"<<endl
);
2455 neValidationState
= Insecure
;
2458 LOG(d_prefix
<<"Invalid denial found for "<<neName
<<", returning Bogus, res="<<denialState
<<", expectedState="<<expectedState
<<endl
);
2459 neValidationState
= Bogus
;
2461 updateValidationState(state
, neValidationState
);
2465 dState
SyncRes::getDenialValidationState(const NegCache::NegCacheEntry
& ne
, const vState state
, const dState expectedState
, bool referralToUnsigned
)
2467 cspmap_t csp
= harvestCSPFromNE(ne
);
2468 return getDenial(csp
, ne
.d_name
, ne
.d_qtype
.getCode(), referralToUnsigned
, expectedState
== NXQTYPE
);
2471 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 unsigned int wildcardLabelsCount
)
2475 for(auto& rec
: lwr
.d_records
) {
2476 if (rec
.d_type
!=QType::OPT
&& rec
.d_class
!=QClass::IN
)
2479 if (rec
.d_place
==DNSResourceRecord::ANSWER
&& !(lwr
.d_aabit
|| sendRDQuery
)) {
2480 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2481 are sending such responses */
2482 if (!(rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
)) {
2487 if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2488 lwr
.d_rcode
==RCode::NXDomain
&& qname
.isPartOf(rec
.d_name
) && rec
.d_name
.isPartOf(auth
)) {
2489 LOG(prefix
<<qname
<<": got negative caching indication for name '"<<qname
<<"' (accept="<<rec
.d_name
.isPartOf(auth
)<<"), newtarget='"<<newtarget
<<"'"<<endl
);
2491 rec
.d_ttl
= min(rec
.d_ttl
, s_maxnegttl
);
2492 if(newtarget
.empty()) // only add a SOA if we're not going anywhere after this
2495 NegCache::NegCacheEntry ne
;
2497 uint32_t lowestTTL
= rec
.d_ttl
;
2498 /* if we get an NXDomain answer with a CNAME, the name
2499 does exist but the target does not */
2500 ne
.d_name
= newtarget
.empty() ? qname
: newtarget
;
2501 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2502 ne
.d_auth
= rec
.d_name
;
2503 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2505 if (state
== Secure
) {
2506 dState denialState
= getDenialValidationState(ne
, state
, NXDOMAIN
, false);
2507 updateDenialValidationState(ne
.d_validationState
, ne
.d_name
, state
, denialState
, NXDOMAIN
, false);
2510 ne
.d_validationState
= state
;
2513 if (ne
.d_validationState
== Bogus
) {
2514 lowestTTL
= min(lowestTTL
, s_maxbogusttl
);
2517 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2518 /* if we get an NXDomain answer with a CNAME, let's not cache the
2519 target, even the server was authoritative for it,
2520 and do an additional query for the CNAME target.
2521 We have a regression test making sure we do exactly that.
2523 if(!wasVariable() && newtarget
.empty()) {
2524 t_sstorage
.negcache
.add(ne
);
2525 if(s_rootNXTrust
&& ne
.d_auth
.isRoot() && auth
.isRoot() && lwr
.d_aabit
) {
2526 ne
.d_name
= ne
.d_name
.getLastLabel();
2527 t_sstorage
.negcache
.add(ne
);
2533 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_type
==QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
) {
2535 if (auto content
= getRR
<CNAMERecordContent
>(rec
)) {
2536 newtarget
=content
->getTarget();
2539 /* if we have a positive answer synthetized from a wildcard, we need to
2540 return the corresponding NSEC/NSEC3 records from the AUTHORITY section
2541 proving that the exact name did not exist */
2542 else if(needWildcardProof
&& (rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::AUTHORITY
) {
2543 ret
.push_back(rec
); // enjoy your DNSSEC
2545 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
2546 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&&
2548 rec
.d_type
==qtype
.getCode() || ((lwr
.d_aabit
|| sendRDQuery
) && qtype
== QType(QType::ANY
))
2552 LOG(prefix
<<qname
<<": answer is in: resolved to '"<< rec
.d_content
->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"'"<<endl
);
2556 if (state
== Secure
&& needWildcardProof
) {
2557 /* We have a positive answer synthetized from a wildcard, we need to check that we have
2558 proof that the exact name doesn't exist so the wildcard can be used,
2559 as described in section 5.3.4 of RFC 4035 and 5.3 of FRC 7129.
2561 NegCache::NegCacheEntry ne
;
2563 uint32_t lowestTTL
= rec
.d_ttl
;
2565 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2566 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2568 cspmap_t csp
= harvestCSPFromNE(ne
);
2569 dState res
= getDenial(csp
, qname
, ne
.d_qtype
.getCode(), false, false, false, wildcardLabelsCount
);
2570 if (res
!= NXDOMAIN
) {
2572 if (res
== INSECURE
) {
2573 /* Some part could not be validated, for example a NSEC3 record with a too large number of iterations,
2574 this is not enough to warrant a Bogus, but go Insecure. */
2576 LOG(d_prefix
<<"Unable to validate denial in wildcard expanded positive response found for "<<qname
<<", returning Insecure, res="<<res
<<endl
);
2579 LOG(d_prefix
<<"Invalid denial in wildcard expanded positive response found for "<<qname
<<", returning Bogus, res="<<res
<<endl
);
2580 rec
.d_ttl
= std::min(rec
.d_ttl
, s_maxbogusttl
);
2583 updateValidationState(state
, st
);
2584 /* we already stored the record with a different validation status, let's fix it */
2585 updateValidationStatusInCache(qname
, qtype
, lwr
.d_aabit
, st
);
2590 else if((rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::ANSWER
) {
2591 if(rec
.d_type
!= QType::RRSIG
|| rec
.d_name
== qname
)
2592 ret
.push_back(rec
); // enjoy your DNSSEC
2594 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::NS
&& qname
.isPartOf(rec
.d_name
)) {
2595 if(moreSpecificThan(rec
.d_name
,auth
)) {
2597 LOG(prefix
<<qname
<<": got NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2601 LOG(prefix
<<qname
<<": got upwards/level NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"', had '"<<auth
<<"'"<<endl
);
2603 if (auto content
= getRR
<NSRecordContent
>(rec
)) {
2604 nsset
.insert(content
->getNS());
2607 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::DS
&& qname
.isPartOf(rec
.d_name
)) {
2608 LOG(prefix
<<qname
<<": got DS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2610 else if(realreferral
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& (rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && newauth
.isPartOf(auth
)) {
2611 /* we might have received a denial of the DS, let's check */
2612 if (state
== Secure
) {
2613 NegCache::NegCacheEntry ne
;
2615 ne
.d_name
= newauth
;
2616 ne
.d_qtype
= QType::DS
;
2617 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2618 uint32_t lowestTTL
= rec
.d_ttl
;
2619 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2621 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, true);
2623 if (denialState
== NXQTYPE
|| denialState
== OPTOUT
|| denialState
== INSECURE
) {
2624 ne
.d_ttd
= lowestTTL
+ d_now
.tv_sec
;
2625 ne
.d_validationState
= Secure
;
2626 LOG(prefix
<<qname
<<": got negative indication of DS record for '"<<newauth
<<"'"<<endl
);
2628 if(!wasVariable()) {
2629 t_sstorage
.negcache
.add(ne
);
2632 if (qname
== newauth
&& qtype
== QType::DS
) {
2633 /* we are actually done! */
2640 else if(!done
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2641 lwr
.d_rcode
==RCode::NoError
&& qname
.isPartOf(rec
.d_name
)) {
2642 LOG(prefix
<<qname
<<": got negative caching indication for '"<< qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
2644 if(!newtarget
.empty()) {
2645 LOG(prefix
<<qname
<<": Hang on! Got a redirect to '"<<newtarget
<<"' already"<<endl
);
2648 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2650 NegCache::NegCacheEntry ne
;
2651 ne
.d_auth
= rec
.d_name
;
2652 uint32_t lowestTTL
= rec
.d_ttl
;
2655 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2657 if (state
== Secure
) {
2658 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, false);
2659 updateDenialValidationState(ne
.d_validationState
, ne
.d_name
, state
, denialState
, NXQTYPE
, qtype
== QType::DS
);
2661 ne
.d_validationState
= state
;
2664 if (ne
.d_validationState
== Bogus
) {
2665 lowestTTL
= min(lowestTTL
, s_maxbogusttl
);
2666 rec
.d_ttl
= min(rec
.d_ttl
, s_maxbogusttl
);
2668 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2670 if(!wasVariable()) {
2671 if(qtype
.getCode()) { // prevents us from blacking out a whole domain
2672 t_sstorage
.negcache
.add(ne
);
2685 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
)
2687 bool chained
= false;
2688 int resolveret
= RCode::NoError
;
2692 if(d_outqueries
+ d_throttledqueries
> s_maxqperq
) {
2693 throw ImmediateServFailException("more than "+std::to_string(s_maxqperq
)+" (max-qperq) queries sent while resolving "+qname
.toLogString());
2696 if(s_maxtotusec
&& d_totUsec
> s_maxtotusec
) {
2697 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");
2701 LOG(prefix
<<qname
<<": using TCP with "<< remoteIP
.toStringWithPort() <<endl
);
2706 if(d_pdl
&& d_pdl
->preoutquery(remoteIP
, d_requestor
, qname
, qtype
, doTCP
, lwr
.d_records
, resolveret
)) {
2707 LOG(prefix
<<qname
<<": query handled by Lua"<<endl
);
2710 ednsmask
=getEDNSSubnetMask(qname
, remoteIP
);
2712 LOG(prefix
<<qname
<<": Adding EDNS Client Subnet Mask "<<ednsmask
->toString()<<" to query"<<endl
);
2715 resolveret
= asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(),
2716 doTCP
, sendRDQuery
, &d_now
, ednsmask
, &lwr
, &chained
); // <- we go out on the wire!
2719 LOG(prefix
<<qname
<<": Received EDNS Client Subnet Mask "<<ednsmask
->toString()<<" on response"<<endl
);
2720 if (ednsmask
->getBits() > 0) {
2721 if (ednsmask
->isIpv4()) {
2722 ++SyncRes::s_ecsResponsesBySubnetSize4
.at(ednsmask
->getBits()-1);
2725 ++SyncRes::s_ecsResponsesBySubnetSize6
.at(ednsmask
->getBits()-1);
2731 /* preoutquery killed the query by setting dq.rcode to -3 */
2732 if(resolveret
==-3) {
2733 throw ImmediateServFailException("Query killed by policy");
2736 d_totUsec
+= lwr
.d_usec
;
2737 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
2739 if(resolveret
!= 1) {
2740 /* Error while resolving */
2741 if(resolveret
== 0) {
2744 LOG(prefix
<<qname
<<": timeout resolving after "<<lwr
.d_usec
/1000.0<<"msec "<< (doTCP
? "over TCP" : "")<<endl
);
2746 s_outgoingtimeouts
++;
2748 if(remoteIP
.sin4
.sin_family
== AF_INET
)
2749 s_outgoing4timeouts
++;
2751 s_outgoing6timeouts
++;
2754 t_timeouts
->push_back(remoteIP
);
2756 else if(resolveret
== -2) {
2757 /* OS resource limit reached */
2758 LOG(prefix
<<qname
<<": hit a local resource limit resolving"<< (doTCP
? " over TCP" : "")<<", probable error: "<<stringerror()<<endl
);
2759 g_stats
.resourceLimits
++;
2762 /* -1 means server unreachable */
2765 LOG(prefix
<<qname
<<": error resolving from "<<remoteIP
.toString()<< (doTCP
? " over TCP" : "") <<", possible error: "<<strerror(errno
)<< endl
);
2768 if(resolveret
!= -2 && !chained
) { // don't account for resource limits, they are our own fault
2769 t_sstorage
.nsSpeeds
[nsName
.empty()? DNSName(remoteIP
.toStringWithPort()) : nsName
].submit(remoteIP
, 1000000, &d_now
); // 1 sec
2771 // code below makes sure we don't filter COM or the root
2772 if (s_serverdownmaxfails
> 0 && (auth
!= g_rootdnsname
) && t_sstorage
.fails
.incr(remoteIP
) >= s_serverdownmaxfails
) {
2773 LOG(prefix
<<qname
<<": Max fails reached resolving on "<< remoteIP
.toString() <<". Going full throttle for "<< s_serverdownthrottletime
<<" seconds" <<endl
);
2774 // mark server as down
2775 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0), s_serverdownthrottletime
, 10000);
2777 else if (resolveret
== -1) {
2778 // unreachable, 1 minute or 100 queries
2779 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 100);
2783 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 10, 5);
2790 /* we got an answer */
2791 if(lwr
.d_rcode
==RCode::ServFail
|| lwr
.d_rcode
==RCode::Refused
) {
2792 LOG(prefix
<<qname
<<": "<<nsName
<<" ("<<remoteIP
.toString()<<") returned a "<< (lwr
.d_rcode
==RCode::ServFail
? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl
);
2794 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
2799 /* this server sent a valid answer, mark it backup up if it was down */
2800 if(s_serverdownmaxfails
> 0) {
2801 t_sstorage
.fails
.clear(remoteIP
);
2808 LOG(prefix
<<qname
<<": truncated bit set, over TCP?"<<endl
);
2809 /* let's treat that as a ServFail answer from this server */
2810 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
2820 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
)
2825 prefix
.append(depth
, ' ');
2829 for(auto& rec
: lwr
.d_records
) {
2830 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumTTL
);
2834 /* if the answer is ECS-specific, a minimum TTL is set for this kind of answers
2835 and it's higher than the global minimum TTL */
2836 if (ednsmask
&& s_minimumECSTTL
> 0 && (s_minimumTTL
== 0 || s_minimumECSTTL
> s_minimumTTL
)) {
2837 for(auto& rec
: lwr
.d_records
) {
2838 if (rec
.d_place
== DNSResourceRecord::ANSWER
) {
2839 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumECSTTL
);
2844 bool needWildcardProof
= false;
2845 unsigned int wildcardLabelsCount
;
2846 *rcode
= updateCacheFromRecords(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, state
, needWildcardProof
, wildcardLabelsCount
, sendRDQuery
);
2847 if (*rcode
!= RCode::NoError
) {
2851 LOG(prefix
<<qname
<<": determining status after receiving this packet"<<endl
);
2854 bool realreferral
=false, negindic
=false;
2858 bool done
= processRecords(prefix
, qname
, qtype
, auth
, lwr
, sendRDQuery
, ret
, nsset
, newtarget
, newauth
, realreferral
, negindic
, state
, needWildcardProof
, wildcardLabelsCount
);
2861 LOG(prefix
<<qname
<<": status=got results, this level of recursion done"<<endl
);
2862 LOG(prefix
<<qname
<<": validation status is "<<vStates
[state
]<<endl
);
2863 *rcode
= RCode::NoError
;
2867 if(!newtarget
.empty()) {
2868 if(newtarget
== qname
) {
2869 LOG(prefix
<<qname
<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl
);
2870 *rcode
= RCode::ServFail
;
2875 LOG(prefix
<<qname
<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl
);
2876 *rcode
= RCode::ServFail
;
2880 if (qtype
== QType::DS
) {
2881 LOG(prefix
<<qname
<<": status=got a CNAME referral, but we are looking for a DS"<<endl
);
2884 addNXNSECS(ret
, lwr
.d_records
);
2886 *rcode
= RCode::NoError
;
2890 LOG(prefix
<<qname
<<": status=got a CNAME referral, starting over with "<<newtarget
<<endl
);
2892 set
<GetBestNSAnswer
> beenthere2
;
2893 vState cnameState
= Indeterminate
;
2894 *rcode
= doResolve(newtarget
, qtype
, ret
, depth
+ 1, beenthere2
, cnameState
);
2895 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
2896 updateValidationState(state
, cnameState
);
2901 if(lwr
.d_rcode
== RCode::NXDomain
) {
2902 LOG(prefix
<<qname
<<": status=NXDOMAIN, we are done "<<(negindic
? "(have negative SOA)" : "")<<endl
);
2905 addNXNSECS(ret
, lwr
.d_records
);
2907 *rcode
= RCode::NXDomain
;
2911 if(nsset
.empty() && !lwr
.d_rcode
&& (negindic
|| lwr
.d_aabit
|| sendRDQuery
)) {
2912 LOG(prefix
<<qname
<<": status=noerror, other types may exist, but we are done "<<(negindic
? "(have negative SOA) " : "")<<(lwr
.d_aabit
? "(have aa bit) " : "")<<endl
);
2914 if(state
== Secure
&& (lwr
.d_aabit
|| sendRDQuery
) && !negindic
) {
2915 updateValidationState(state
, Bogus
);
2919 addNXNSECS(ret
, lwr
.d_records
);
2921 *rcode
= RCode::NoError
;
2926 LOG(prefix
<<qname
<<": status=did not resolve, got "<<(unsigned int)nsset
.size()<<" NS, ");
2928 nameservers
.clear();
2929 for (auto const &nameserver
: nsset
) {
2931 d_appliedPolicy
= dfe
.getProcessingPolicy(nameserver
, d_discardedPolicies
);
2932 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
2933 LOG("however "<<nameserver
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
2938 nameservers
.insert({nameserver
, {{}, false}});
2940 LOG("looping to them"<<endl
);
2941 *gotNewServers
= true;
2951 * -1 in case of no results
2952 * -2 when a FilterEngine Policy was hit
2955 int SyncRes::doResolveAt(NsSet
&nameservers
, DNSName auth
, bool flawedNSSet
, const DNSName
&qname
, const QType
&qtype
,
2956 vector
<DNSRecord
>&ret
,
2957 unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
, vState
& state
)
2959 auto luaconfsLocal
= g_luaconfs
.getLocal();
2963 prefix
.append(depth
, ' ');
2966 LOG(prefix
<<qname
<<": Cache consultations done, have "<<(unsigned int)nameservers
.size()<<" NS to contact");
2968 if (nameserversBlockedByRPZ(luaconfsLocal
->dfe
, nameservers
)) {
2974 for(;;) { // we may get more specific nameservers
2975 vector
<DNSName
> rnameservers
= shuffleInSpeedOrder(nameservers
, doLog() ? (prefix
+qname
.toString()+": ") : string() );
2977 for(auto tns
=rnameservers
.cbegin();;++tns
) {
2978 if(tns
==rnameservers
.cend()) {
2979 LOG(prefix
<<qname
<<": Failed to resolve via any of the "<<(unsigned int)rnameservers
.size()<<" offered NS at level '"<<auth
<<"'"<<endl
);
2980 if(!auth
.isRoot() && flawedNSSet
) {
2981 LOG(prefix
<<qname
<<": Ageing nameservers for level '"<<auth
<<"', next query might succeed"<<endl
);
2983 if(t_RC
->doAgeCache(d_now
.tv_sec
, auth
, QType::NS
, 10))
2984 g_stats
.nsSetInvalidations
++;
2989 bool cacheOnly
= false;
2990 // this line needs to identify the 'self-resolving' behaviour
2991 if(qname
== *tns
&& (qtype
.getCode() == QType::A
|| qtype
.getCode() == QType::AAAA
)) {
2992 /* we might have a glue entry in cache so let's try this NS
2993 but only if we have enough in the cache to know how to reach it */
2994 LOG(prefix
<<qname
<<": Using NS to resolve itself, but only using what we have in cache ("<<(1+tns
-rnameservers
.cbegin())<<"/"<<rnameservers
.size()<<")"<<endl
);
2998 typedef vector
<ComboAddress
> remoteIPs_t
;
2999 remoteIPs_t remoteIPs
;
3000 remoteIPs_t::const_iterator remoteIP
;
3001 bool pierceDontQuery
=false;
3002 bool sendRDQuery
=false;
3003 boost::optional
<Netmask
> ednsmask
;
3005 const bool wasForwarded
= tns
->empty() && (!nameservers
[*tns
].first
.empty());
3006 int rcode
= RCode::NoError
;
3007 bool gotNewServers
= false;
3009 if(tns
->empty() && !wasForwarded
) {
3010 LOG(prefix
<<qname
<<": Domain is out-of-band"<<endl
);
3011 /* setting state to indeterminate since validation is disabled for local auth zone,
3012 and Insecure would be misleading. */
3013 state
= Indeterminate
;
3014 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, lwr
.d_records
, depth
, lwr
.d_rcode
);
3018 /* we have received an answer, are we done ? */
3019 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, false, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
3023 if (gotNewServers
) {
3028 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
3029 remoteIPs
= retrieveAddressesForNS(prefix
, qname
, tns
, depth
, beenthere
, rnameservers
, nameservers
, sendRDQuery
, pierceDontQuery
, flawedNSSet
, cacheOnly
);
3031 if(remoteIPs
.empty()) {
3032 LOG(prefix
<<qname
<<": Failed to get IP for NS "<<*tns
<<", trying next if available"<<endl
);
3037 bool hitPolicy
{false};
3038 LOG(prefix
<<qname
<<": Resolved '"<<auth
<<"' NS "<<*tns
<<" to: ");
3039 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
3040 if(remoteIP
!= remoteIPs
.cbegin()) {
3043 LOG(remoteIP
->toString());
3044 if(nameserverIPBlockedByRPZ(luaconfsLocal
->dfe
, *remoteIP
)) {
3049 if (hitPolicy
) //implies d_wantsRPZ
3053 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
3054 LOG(prefix
<<qname
<<": Trying IP "<< remoteIP
->toStringWithPort() <<", asking '"<<qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
3056 if (throttledOrBlocked(prefix
, *remoteIP
, qname
, qtype
, pierceDontQuery
)) {
3060 bool truncated
= false;
3061 bool gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
3062 *tns
, *remoteIP
, false, &truncated
);
3063 if (gotAnswer
&& truncated
) {
3064 /* retry, over TCP this time */
3065 gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
3066 *tns
, *remoteIP
, true, &truncated
);
3073 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
);
3075 /* // for you IPv6 fanatics :-)
3076 if(remoteIP->sin4.sin_family==AF_INET6)
3079 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
3081 t_sstorage
.nsSpeeds
[tns
->empty()? DNSName(remoteIP
->toStringWithPort()) : *tns
].submit(*remoteIP
, lwr
.d_usec
, &d_now
);
3083 /* we have received an answer, are we done ? */
3084 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
3088 if (gotNewServers
) {
3092 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100);
3095 if (gotNewServers
) {
3099 if(remoteIP
== remoteIPs
.cend()) // we tried all IP addresses, none worked
3108 void SyncRes::setQuerySource(const ComboAddress
& requestor
, boost::optional
<const EDNSSubnetOpts
&> incomingECS
)
3110 d_requestor
= requestor
;
3112 if (incomingECS
&& incomingECS
->source
.getBits() > 0) {
3113 d_cacheRemote
= incomingECS
->source
.getMaskedNetwork();
3114 uint8_t bits
= std::min(incomingECS
->source
.getBits(), (incomingECS
->source
.isIpv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
3115 ComboAddress trunc
= incomingECS
->source
.getNetwork();
3116 trunc
.truncate(bits
);
3117 d_outgoingECSNetwork
= boost::optional
<Netmask
>(Netmask(trunc
, bits
));
3119 d_cacheRemote
= d_requestor
;
3120 if(!incomingECS
&& s_ednslocalsubnets
.match(d_requestor
)) {
3121 ComboAddress trunc
= d_requestor
;
3122 uint8_t bits
= d_requestor
.isIPv4() ? 32 : 128;
3123 bits
= std::min(bits
, (trunc
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
3124 trunc
.truncate(bits
);
3125 d_outgoingECSNetwork
= boost::optional
<Netmask
>(Netmask(trunc
, bits
));
3126 } else if (s_ecsScopeZero
.source
.getBits() > 0) {
3127 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0.
3128 But using an empty ECS in that case would mean inserting
3129 a non ECS-specific entry into the cache, preventing any further
3130 ECS-specific query to be sent.
3131 So instead we use the trick described in section 7.1.2:
3132 "The subsequent Recursive Resolver query to the Authoritative Nameserver
3133 will then either not include an ECS option or MAY optionally include
3134 its own address information, which is what the Authoritative
3135 Nameserver will almost certainly use to generate any Tailored
3136 Response in lieu of an option. This allows the answer to be handled
3137 by the same caching mechanism as other queries, with an explicit
3138 indicator of the applicable scope. Subsequent Stub Resolver queries
3139 for /0 can then be answered from this cached response.
3141 d_outgoingECSNetwork
= boost::optional
<Netmask
>(s_ecsScopeZero
.source
.getMaskedNetwork());
3142 d_cacheRemote
= s_ecsScopeZero
.source
.getNetwork();
3144 // ECS disabled because no scope-zero address could be derived.
3145 d_outgoingECSNetwork
= boost::none
;
3150 boost::optional
<Netmask
> SyncRes::getEDNSSubnetMask(const DNSName
& dn
, const ComboAddress
& rem
)
3152 if(d_outgoingECSNetwork
&& (s_ednsdomains
.check(dn
) || s_ednsremotesubnets
.match(rem
))) {
3153 return d_outgoingECSNetwork
;
3158 void SyncRes::parseEDNSSubnetWhitelist(const std::string
& wlist
)
3160 vector
<string
> parts
;
3161 stringtok(parts
, wlist
, ",; ");
3162 for(const auto& a
: parts
) {
3164 s_ednsremotesubnets
.addMask(Netmask(a
));
3167 s_ednsdomains
.add(DNSName(a
));
3172 void SyncRes::parseEDNSSubnetAddFor(const std::string
& subnetlist
)
3174 vector
<string
> parts
;
3175 stringtok(parts
, subnetlist
, ",; ");
3176 for(const auto& a
: parts
) {
3177 s_ednslocalsubnets
.addMask(a
);
3181 // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
3182 int directResolve(const DNSName
& qname
, const QType
& qtype
, int qclass
, vector
<DNSRecord
>& ret
)
3185 gettimeofday(&now
, 0);
3190 res
= sr
.beginResolve(qname
, QType(qtype
), qclass
, ret
);
3192 catch(const PDNSException
& e
) {
3193 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got pdns exception: "<<e
.reason
<<endl
;
3196 catch(const ImmediateServFailException
& e
) {
3197 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got ImmediateServFailException: "<<e
.reason
<<endl
;
3200 catch(const std::exception
& e
) {
3201 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got STL error: "<<e
.what()<<endl
;
3205 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got an exception"<<endl
;
3212 int SyncRes::getRootNS(struct timeval now
, asyncresolve_t asyncCallback
) {
3214 sr
.setDoEDNS0(true);
3215 sr
.setUpdatingRootNS();
3216 sr
.setDoDNSSEC(g_dnssecmode
!= DNSSECMode::Off
);
3217 sr
.setDNSSECValidationRequested(g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
);
3218 sr
.setAsyncCallback(asyncCallback
);
3220 vector
<DNSRecord
> ret
;
3223 res
=sr
.beginResolve(g_rootdnsname
, QType(QType::NS
), 1, ret
);
3224 if (g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
) {
3225 auto state
= sr
.getValidationState();
3227 throw PDNSException("Got Bogus validation result for .|NS");
3231 catch(const PDNSException
& e
) {
3232 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
3234 catch(const ImmediateServFailException
& e
) {
3235 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
3237 catch(const std::exception
& e
) {
3238 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.what()<<endl
;
3241 g_log
<<Logger::Error
<<"Failed to update . records, got an exception"<<endl
;
3245 g_log
<<Logger::Notice
<<"Refreshed . records"<<endl
;
3248 g_log
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;