2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "arguments.hh"
27 #include "cachecleaner.hh"
28 #include "dns_random.hh"
29 #include "dnsparser.hh"
30 #include "dnsrecords.hh"
31 #include "ednssubnet.hh"
33 #include "lua-recursor4.hh"
34 #include "rec-lua-conf.hh"
36 #include "dnsseckeeper.hh"
37 #include "validate-recursor.hh"
39 thread_local
SyncRes::ThreadLocalStorage
SyncRes::t_sstorage
;
40 thread_local
std::unique_ptr
<addrringbuf_t
> t_timeouts
;
42 std::unordered_set
<DNSName
> SyncRes::s_delegationOnly
;
43 std::unique_ptr
<NetmaskGroup
> SyncRes::s_dontQuery
{nullptr};
44 NetmaskGroup
SyncRes::s_ednslocalsubnets
;
45 NetmaskGroup
SyncRes::s_ednsremotesubnets
;
46 SuffixMatchNode
SyncRes::s_ednsdomains
;
47 EDNSSubnetOpts
SyncRes::s_ecsScopeZero
;
48 string
SyncRes::s_serverID
;
49 SyncRes::LogMode
SyncRes::s_lm
;
50 const std::unordered_set
<uint16_t> SyncRes::s_redirectionQTypes
= {QType::CNAME
, QType::DNAME
};
52 unsigned int SyncRes::s_maxnegttl
;
53 unsigned int SyncRes::s_maxbogusttl
;
54 unsigned int SyncRes::s_maxcachettl
;
55 unsigned int SyncRes::s_maxqperq
;
56 unsigned int SyncRes::s_maxtotusec
;
57 unsigned int SyncRes::s_maxdepth
;
58 unsigned int SyncRes::s_minimumTTL
;
59 unsigned int SyncRes::s_minimumECSTTL
;
60 unsigned int SyncRes::s_packetcachettl
;
61 unsigned int SyncRes::s_packetcacheservfailttl
;
62 unsigned int SyncRes::s_serverdownmaxfails
;
63 unsigned int SyncRes::s_serverdownthrottletime
;
64 unsigned int SyncRes::s_ecscachelimitttl
;
65 std::atomic
<uint64_t> SyncRes::s_authzonequeries
;
66 std::atomic
<uint64_t> SyncRes::s_queries
;
67 std::atomic
<uint64_t> SyncRes::s_outgoingtimeouts
;
68 std::atomic
<uint64_t> SyncRes::s_outgoing4timeouts
;
69 std::atomic
<uint64_t> SyncRes::s_outgoing6timeouts
;
70 std::atomic
<uint64_t> SyncRes::s_outqueries
;
71 std::atomic
<uint64_t> SyncRes::s_tcpoutqueries
;
72 std::atomic
<uint64_t> SyncRes::s_throttledqueries
;
73 std::atomic
<uint64_t> SyncRes::s_dontqueries
;
74 std::atomic
<uint64_t> SyncRes::s_nodelegated
;
75 std::atomic
<uint64_t> SyncRes::s_unreachables
;
76 std::atomic
<uint64_t> SyncRes::s_ecsqueries
;
77 std::atomic
<uint64_t> SyncRes::s_ecsresponses
;
78 std::map
<uint8_t, std::atomic
<uint64_t>> SyncRes::s_ecsResponsesBySubnetSize4
;
79 std::map
<uint8_t, std::atomic
<uint64_t>> SyncRes::s_ecsResponsesBySubnetSize6
;
81 uint8_t SyncRes::s_ecsipv4limit
;
82 uint8_t SyncRes::s_ecsipv6limit
;
83 uint8_t SyncRes::s_ecsipv4cachelimit
;
84 uint8_t SyncRes::s_ecsipv6cachelimit
;
86 bool SyncRes::s_doIPv6
;
87 bool SyncRes::s_nopacketcache
;
88 bool SyncRes::s_rootNXTrust
;
89 bool SyncRes::s_noEDNS
;
90 bool SyncRes::s_qnameminimization
;
92 #define LOG(x) if(d_lm == Log) { g_log <<Logger::Warning << x; } else if(d_lm == Store) { d_trace << x; }
94 static void accountAuthLatency(int usec
, int family
)
96 if(family
== AF_INET
) {
98 g_stats
.auth4Answers0_1
++;
100 g_stats
.auth4Answers1_10
++;
101 else if(usec
< 100000)
102 g_stats
.auth4Answers10_100
++;
103 else if(usec
< 1000000)
104 g_stats
.auth4Answers100_1000
++;
106 g_stats
.auth4AnswersSlow
++;
109 g_stats
.auth6Answers0_1
++;
110 else if(usec
< 10000)
111 g_stats
.auth6Answers1_10
++;
112 else if(usec
< 100000)
113 g_stats
.auth6Answers10_100
++;
114 else if(usec
< 1000000)
115 g_stats
.auth6Answers100_1000
++;
117 g_stats
.auth6AnswersSlow
++;
123 SyncRes::SyncRes(const struct timeval
& now
) : d_authzonequeries(0), d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
124 d_totUsec(0), d_now(now
),
125 d_cacheonly(false), d_doDNSSEC(false), d_doEDNS0(false), d_qNameMinimization(s_qnameminimization
), d_lm(s_lm
)
130 /** everything begins here - this is the entry point just after receiving a packet */
131 int SyncRes::beginResolve(const DNSName
&qname
, const QType
&qtype
, uint16_t qclass
, vector
<DNSRecord
>&ret
)
133 vState state
= Indeterminate
;
136 d_wasOutOfBand
=false;
138 if (doSpecialNamesResolve(qname
, qtype
, qclass
, ret
)) {
139 d_queryValidationState
= Insecure
; // this could fool our stats into thinking a validation took place
140 return 0; // so do check before updating counters (we do now)
143 auto qtypeCode
= qtype
.getCode();
144 /* rfc6895 section 3.1 */
145 if ((qtypeCode
>= 128 && qtypeCode
<= 254) || qtypeCode
== QType::RRSIG
|| qtypeCode
== QType::NSEC3
|| qtypeCode
== QType::OPT
|| qtypeCode
== 65535) {
149 if(qclass
==QClass::ANY
)
151 else if(qclass
!=QClass::IN
)
154 set
<GetBestNSAnswer
> beenthere
;
155 int res
=doResolve(qname
, qtype
, ret
, 0, beenthere
, state
);
156 d_queryValidationState
= state
;
158 if (shouldValidate()) {
159 if (d_queryValidationState
!= Indeterminate
) {
160 g_stats
.dnssecValidations
++;
162 increaseDNSSECStateCounter(d_queryValidationState
);
168 /*! Handles all special, built-in names
169 * Fills ret with an answer and returns true if it handled the query.
171 * Handles the following queries (and their ANY variants):
174 * - localhost. IN AAAA
175 * - 1.0.0.127.in-addr.arpa. IN PTR
176 * - 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
177 * - version.bind. CH TXT
178 * - version.pdns. CH TXT
179 * - id.server. CH TXT
180 * - trustanchor.server CH TXT
181 * - negativetrustanchor.server CH TXT
183 bool SyncRes::doSpecialNamesResolve(const DNSName
&qname
, const QType
&qtype
, const uint16_t qclass
, vector
<DNSRecord
> &ret
)
185 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."),
186 localhost("localhost."), versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns."), trustanchorserver("trustanchor.server."),
187 negativetrustanchorserver("negativetrustanchor.server.");
189 bool handled
= false;
190 vector
<pair
<QType::typeenum
, string
> > answers
;
192 if ((qname
== arpa
|| qname
== ip6_arpa
) &&
193 qclass
== QClass::IN
) {
195 if (qtype
== QType::PTR
|| qtype
== QType::ANY
)
196 answers
.push_back({QType::PTR
, "localhost."});
199 if (qname
== localhost
&&
200 qclass
== QClass::IN
) {
202 if (qtype
== QType::A
|| qtype
== QType::ANY
)
203 answers
.push_back({QType::A
, "127.0.0.1"});
204 if (qtype
== QType::AAAA
|| qtype
== QType::ANY
)
205 answers
.push_back({QType::AAAA
, "::1"});
208 if ((qname
== versionbind
|| qname
== idserver
|| qname
== versionpdns
) &&
209 qclass
== QClass::CHAOS
) {
211 if (qtype
== QType::TXT
|| qtype
== QType::ANY
) {
212 if(qname
== versionbind
|| qname
== versionpdns
)
213 answers
.push_back({QType::TXT
, "\""+::arg()["version-string"]+"\""});
214 else if (s_serverID
!= "disabled")
215 answers
.push_back({QType::TXT
, "\""+s_serverID
+"\""});
219 if (qname
== trustanchorserver
&& qclass
== QClass::CHAOS
&&
220 ::arg().mustDo("allow-trust-anchor-query")) {
222 if (qtype
== QType::TXT
|| qtype
== QType::ANY
) {
223 auto luaLocal
= g_luaconfs
.getLocal();
224 for (auto const &dsAnchor
: luaLocal
->dsAnchors
) {
227 ans
<<dsAnchor
.first
.toString(); // Explicit toString to have a trailing dot
228 for (auto const &dsRecord
: dsAnchor
.second
) {
233 answers
.push_back({QType::TXT
, ans
.str()});
238 if (qname
== negativetrustanchorserver
&& qclass
== QClass::CHAOS
&&
239 ::arg().mustDo("allow-trust-anchor-query")) {
241 if (qtype
== QType::TXT
|| qtype
== QType::ANY
) {
242 auto luaLocal
= g_luaconfs
.getLocal();
243 for (auto const &negAnchor
: luaLocal
->negAnchors
) {
246 ans
<<negAnchor
.first
.toString(); // Explicit toString to have a trailing dot
247 if (negAnchor
.second
.length())
248 ans
<<" "<<negAnchor
.second
;
250 answers
.push_back({QType::TXT
, ans
.str()});
255 if (handled
&& !answers
.empty()) {
261 dr
.d_place
= DNSResourceRecord::ANSWER
;
264 for (const auto& ans
: answers
) {
265 dr
.d_type
= ans
.first
;
266 dr
.d_content
= DNSRecordContent::mastermake(ans
.first
, qclass
, ans
.second
);
275 //! This is the 'out of band resolver', in other words, the authoritative server
276 void SyncRes::AuthDomain::addSOA(std::vector
<DNSRecord
>& records
) const
278 SyncRes::AuthDomain::records_t::const_iterator ziter
= d_records
.find(boost::make_tuple(getName(), QType::SOA
));
279 if (ziter
!= d_records
.end()) {
280 DNSRecord dr
= *ziter
;
281 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
282 records
.push_back(dr
);
285 // cerr<<qname<<": can't find SOA record '"<<getName()<<"' in our zone!"<<endl;
289 int SyncRes::AuthDomain::getRecords(const DNSName
& qname
, uint16_t qtype
, std::vector
<DNSRecord
>& records
) const
291 int result
= RCode::NoError
;
295 std::pair
<records_t::const_iterator
,records_t::const_iterator
> range
= d_records
.equal_range(tie(qname
));
297 SyncRes::AuthDomain::records_t::const_iterator ziter
;
298 bool somedata
= false;
300 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
303 if(qtype
== QType::ANY
|| ziter
->d_type
== qtype
|| ziter
->d_type
== QType::CNAME
) {
304 // let rest of nameserver do the legwork on this one
305 records
.push_back(*ziter
);
307 else if (ziter
->d_type
== QType::NS
&& ziter
->d_name
.countLabels() > getName().countLabels()) {
308 // we hit a delegation point!
309 DNSRecord dr
= *ziter
;
310 dr
.d_place
=DNSResourceRecord::AUTHORITY
;
311 records
.push_back(dr
);
315 if (!records
.empty()) {
316 /* We have found an exact match, we're done */
317 // cerr<<qname<<": exact match in zone '"<<getName()<<"'"<<endl;
322 /* We have records for that name, but not of the wanted qtype */
323 // cerr<<qname<<": found record in '"<<getName()<<"', but nothing of the right type, sending SOA"<<endl;
329 // cerr<<qname<<": nothing found so far in '"<<getName()<<"', trying wildcards"<<endl;
330 DNSName
wcarddomain(qname
);
331 while(wcarddomain
!= getName() && wcarddomain
.chopOff()) {
332 // cerr<<qname<<": trying '*."<<wcarddomain<<"' in "<<getName()<<endl;
333 range
= d_records
.equal_range(boost::make_tuple(g_wildcarddnsname
+ wcarddomain
));
334 if (range
.first
==range
.second
)
337 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
338 DNSRecord dr
= *ziter
;
339 // if we hit a CNAME, just answer that - rest of recursor will do the needful & follow
340 if(dr
.d_type
== qtype
|| qtype
== QType::ANY
|| dr
.d_type
== QType::CNAME
) {
342 dr
.d_place
= DNSResourceRecord::ANSWER
;
343 records
.push_back(dr
);
347 if (records
.empty()) {
351 // cerr<<qname<<": in '"<<getName()<<"', had wildcard match on '*."<<wcarddomain<<"'"<<endl;
355 /* Nothing for this name, no wildcard, let's see if there is some NS */
356 DNSName
nsdomain(qname
);
357 while (nsdomain
.chopOff() && nsdomain
!= getName()) {
358 range
= d_records
.equal_range(boost::make_tuple(nsdomain
,QType::NS
));
359 if(range
.first
== range
.second
)
362 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
363 DNSRecord dr
= *ziter
;
364 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
365 records
.push_back(dr
);
369 if(records
.empty()) {
370 // cerr<<qname<<": no NS match in zone '"<<getName()<<"' either, handing out SOA"<<endl;
372 result
= RCode::NXDomain
;
378 bool SyncRes::doOOBResolve(const AuthDomain
& domain
, const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, int& res
)
383 res
= domain
.getRecords(qname
, qtype
.getCode(), ret
);
387 bool SyncRes::doOOBResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int& res
)
392 prefix
.append(depth
, ' ');
395 DNSName
authdomain(qname
);
396 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
397 if(iter
==t_sstorage
.domainmap
->end() || !iter
->second
.isAuth()) {
398 LOG(prefix
<<qname
<<": auth storage has no zone for this query!"<<endl
);
402 LOG(prefix
<<qname
<<": auth storage has data, zone='"<<authdomain
<<"'"<<endl
);
403 return doOOBResolve(iter
->second
, qname
, qtype
, ret
, res
);
406 uint64_t SyncRes::doEDNSDump(int fd
)
408 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(dup(fd
), "w"), fclose
);
414 fprintf(fp
.get(),"; edns from thread follows\n;\n");
415 for(const auto& eds
: t_sstorage
.ednsstatus
) {
417 fprintf(fp
.get(), "%s\t%d\t%s", eds
.first
.toString().c_str(), (int)eds
.second
.mode
, ctime(&eds
.second
.modeSetAt
));
422 uint64_t SyncRes::doDumpNSSpeeds(int fd
)
424 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(dup(fd
), "w"), fclose
);
427 fprintf(fp
.get(), "; nsspeed dump from thread follows\n;\n");
430 for(const auto& i
: t_sstorage
.nsSpeeds
)
434 // an <empty> can appear hear in case of authoritative (hosted) zones
435 fprintf(fp
.get(), "%s -> ", i
.first
.toLogString().c_str());
436 for(const auto& j
: i
.second
.d_collection
)
438 // typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
439 fprintf(fp
.get(), "%s/%f ", j
.first
.toString().c_str(), j
.second
.peek());
441 fprintf(fp
.get(), "\n");
446 uint64_t SyncRes::doDumpThrottleMap(int fd
)
448 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fdopen(dup(fd
), "w"), fclose
);
451 fprintf(fp
.get(), "; throttle map dump follows\n");
452 fprintf(fp
.get(), "; remote IP\tqname\tqtype\tcount\tttd\n");
455 const auto& throttleMap
= t_sstorage
.throttle
.getThrottleMap();
456 for(const auto& i
: throttleMap
)
459 // remote IP, dns name, qtype, count, ttd
460 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
));
466 /* so here is the story. First we complete the full resolution process for a domain name. And only THEN do we decide
467 to also do DNSSEC validation, which leads to new queries. To make this simple, we *always* ask for DNSSEC records
468 so that if there are RRSIGs for a name, we'll have them.
470 However, some hosts simply can't answer questions which ask for DNSSEC. This can manifest itself as:
475 The cause of "No answer" may be fragmentation, and it is tempting to probe if smaller answers would get through.
476 Another cause of "No answer" may simply be a network condition.
477 Nonsense answers are a clearer indication this host won't be able to do DNSSEC evah.
479 Previous implementations have suffered from turning off DNSSEC questions for an authoritative server based on timeouts.
480 A clever idea is to only turn off DNSSEC if we know a domain isn't signed anyhow. The problem with that really
481 clever idea however is that at this point in PowerDNS, we may simply not know that yet. All the DNSSEC thinking happens
482 elsewhere. It may not have happened yet.
484 For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish.
487 int SyncRes::asyncresolveWrapper(const ComboAddress
& ip
, bool ednsMANDATORY
, const DNSName
& domain
, const DNSName
& auth
, int type
, bool doTCP
, bool sendRDQuery
, struct timeval
* now
, boost::optional
<Netmask
>& srcmask
, LWResult
* res
, bool* chained
) const
489 /* what is your QUEST?
490 the goal is to get as many remotes as possible on the highest level of EDNS support
493 0) UNKNOWN Unknown state
494 1) EDNS: Honors EDNS0
495 2) EDNSIGNORANT: Ignores EDNS0, gives replies without EDNS0
496 3) NOEDNS: Generates FORMERR on EDNS queries
498 Everybody starts out assumed to be '0'.
499 If '0', send out EDNS0
500 If you FORMERR us, go to '3',
501 If no EDNS in response, go to '2'
502 If '1', send out EDNS0
503 If FORMERR, downgrade to 3
504 If '2', keep on including EDNS0, see what happens
506 If '3', send bare queries
509 SyncRes::EDNSStatus
* ednsstatus
;
510 ednsstatus
= &t_sstorage
.ednsstatus
[ip
]; // does this include port? YES
512 if(ednsstatus
->modeSetAt
&& ednsstatus
->modeSetAt
+ 3600 < d_now
.tv_sec
) {
513 *ednsstatus
=SyncRes::EDNSStatus();
514 // cerr<<"Resetting EDNS Status for "<<ip.toString()<<endl);
517 SyncRes::EDNSStatus::EDNSMode
& mode
=ednsstatus
->mode
;
518 SyncRes::EDNSStatus::EDNSMode oldmode
= mode
;
520 auto luaconfsLocal
= g_luaconfs
.getLocal();
523 ctx
.d_initialRequestId
= d_initialRequestId
;
530 for(int tries
= 0; tries
< 3; ++tries
) {
531 // cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl;
533 if(mode
==EDNSStatus::NOEDNS
) {
534 g_stats
.noEdnsOutQueries
++;
535 EDNSLevel
= 0; // level != mode
537 else if(ednsMANDATORY
|| mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
==EDNSStatus::EDNSIGNORANT
)
540 DNSName
sendQname(domain
);
541 if (g_lowercaseOutgoing
)
542 sendQname
.makeUsLowerCase();
544 if (d_asyncResolve
) {
545 ret
= d_asyncResolve(ip
, sendQname
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, res
, chained
);
548 ret
=asyncresolve(ip
, sendQname
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, d_outgoingProtobufServers
, d_frameStreamServers
, luaconfsLocal
->outgoingProtobufExportConfig
.exportTypes
, res
, chained
);
551 return ret
; // transport error, nothing to learn here
554 if(ret
== 0) { // timeout, not doing anything with it now
557 else if(mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
== EDNSStatus::EDNSIGNORANT
) {
558 if(res
->d_validpacket
&& !res
->d_haveEDNS
&& res
->d_rcode
== RCode::FormErr
) {
559 // cerr<<"Downgrading to NOEDNS because of "<<RCode::to_s(res->d_rcode)<<" for query to "<<ip.toString()<<" for '"<<domain<<"'"<<endl;
560 mode
= EDNSStatus::NOEDNS
;
563 else if(!res
->d_haveEDNS
) {
564 if(mode
!= EDNSStatus::EDNSIGNORANT
) {
565 mode
= EDNSStatus::EDNSIGNORANT
;
566 // cerr<<"We find that "<<ip.toString()<<" is an EDNS-ignorer for '"<<domain<<"', moving to mode 2"<<endl;
570 mode
= EDNSStatus::EDNSOK
;
571 // cerr<<"We find that "<<ip.toString()<<" is EDNS OK!"<<endl;
575 if(oldmode
!= mode
|| !ednsstatus
->modeSetAt
)
576 ednsstatus
->modeSetAt
=d_now
.tv_sec
;
577 // cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", new mode: "<<mode<<endl;
583 #define QLOG(x) LOG(prefix << " child=" << child << ": " << x << endl)
585 int SyncRes::doResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, vState
& state
) {
587 if (!getQNameMinimization()) {
588 return doResolveNoQNameMinimization(qname
, qtype
, ret
, depth
, beenthere
, state
);
591 // The qname minimization algorithm is a simplified version of the one in RFC 7816 (bis).
592 // It could be simplified because the cache maintenance (both positive and negative)
593 // is already done by doResolveNoQNameMinimization().
595 // Sketch of algorithm:
597 // If result found: done
598 // Otherwise determine closes ancestor from cache data
599 // Repeat querying A, adding more labels of the original qname
600 // If we get a delegation continue at ancestor determination
601 // Until we have the full name.
603 // The algorithm starts with adding a single label per iteration, and
604 // moves to three labels per iteration after three iterations.
607 string prefix
= d_prefix
;
608 prefix
.append(depth
, ' ');
609 prefix
.append(string("QM ") + qname
.toString() + "|" + qtype
.getName());
613 // Look in cache only
614 vector
<DNSRecord
> retq
;
615 bool old
= setCacheOnly(true);
616 bool fromCache
= false;
617 int res
= doResolveNoQNameMinimization(qname
, qtype
, retq
, depth
+ 1, beenthere
, state
, &fromCache
);
620 QLOG("Step0 Found in cache");
621 ret
.insert(ret
.end(), retq
.begin(), retq
.end());
624 QLOG("Step0 Not cached");
626 const unsigned int qnamelen
= qname
.countLabels();
628 for (unsigned int i
= 0; i
<= qnamelen
; ) {
631 vector
<DNSRecord
> bestns
;
632 // the two retries allow getBestNSFromCache&co to reprime the root
633 // hints, in case they ever go missing
634 for (int tries
= 0; tries
< 2 && bestns
.empty(); ++tries
) {
635 bool flawedNSSet
= false;
636 set
<GetBestNSAnswer
> beenthereIgnored
;
637 getBestNSFromCache(qname
, qtype
, bestns
, &flawedNSSet
, depth
+ 1, beenthereIgnored
);
640 if (bestns
.size() == 0) {
641 // Something terrible is wrong
642 QLOG("Step1 No ancestor found return ServFail");
643 return RCode::ServFail
;
646 const DNSName
& ancestor(bestns
[0].d_name
);
647 QLOG("Step1 Ancestor from cache is " << ancestor
.toString());
650 unsigned int targetlen
= std::min(child
.countLabels() + (i
> 3 ? 3 : 1), qnamelen
);
652 for (; i
<= qnamelen
; i
++) {
654 while (child
.countLabels() < targetlen
) {
655 child
.prependRawLabel(qname
.getRawLabel(qnamelen
- child
.countLabels() - 1));
657 targetlen
+= i
> 3 ? 3 : 1;
658 targetlen
= std::min(targetlen
, qnamelen
);
660 QLOG("Step2 New child");
663 if (child
== qname
) {
664 QLOG("Step3 Going to do final resolve");
665 res
= doResolveNoQNameMinimization(qname
, qtype
, ret
, depth
+ 1, beenthere
, state
);
666 QLOG("Step3 Final resolve: " << RCode::to_s(res
) << "/" << ret
.size());
671 QLOG("Step4 Resolve A for child");
673 StopAtDelegation stopAtDelegation
= Stop
;
674 res
= doResolveNoQNameMinimization(child
, QType::A
, retq
, depth
+ 1, beenthere
, state
, NULL
, &stopAtDelegation
);
675 QLOG("Step4 Resolve A result is " << RCode::to_s(res
) << "/" << retq
.size() << "/" << stopAtDelegation
);
676 if (stopAtDelegation
== Stopped
) {
677 QLOG("Delegation seen, continue at step 1");
680 if (res
!= RCode::NoError
) {
681 // Case 5: unexpected answer
682 QLOG("Step5: other rcode, last effort final resolve");
683 setQNameMinimization(false);
684 res
= doResolveNoQNameMinimization(qname
, qtype
, ret
, depth
+ 1, beenthere
, state
);
685 QLOG("Step5 End resolve: " << RCode::to_s(res
) << "/" << ret
.size());
691 // Should not be reached
692 QLOG("Max iterations reached, return ServFail");
693 return RCode::ServFail
;
696 /*! This function will check the cache and go out to the internet if the answer is not in cache
698 * \param qname The name we need an answer for
700 * \param ret The vector of DNSRecords we need to fill with the answers
701 * \param depth The recursion depth we are in
703 * \param fromCache tells the caller the result came from the cache, may be nullptr
704 * \param stopAtDelegation if non-nullptr and pointed-to value is Stop requests the callee to stop at a delegation, if so pointed-to value is set to Stopped
705 * \return DNS RCODE or -1 (Error) or -2 (RPZ hit)
707 int SyncRes::doResolveNoQNameMinimization(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, vState
& state
, bool *fromCache
, StopAtDelegation
*stopAtDelegation
)
712 prefix
.append(depth
, ' ');
715 LOG(prefix
<<qname
<<": Wants "<< (d_doDNSSEC
? "" : "NO ") << "DNSSEC processing, "<<(d_requireAuthData
? "" : "NO ")<<"auth data in query for "<<qtype
.getName()<<endl
);
717 state
= Indeterminate
;
719 if(s_maxdepth
&& depth
> s_maxdepth
)
720 throw ImmediateServFailException("More than "+std::to_string(s_maxdepth
)+" (max-recursion-depth) levels of recursion needed while resolving "+qname
.toLogString());
724 // This is a difficult way of expressing "this is a normal query", i.e. not getRootNS.
725 if(!(d_updatingRootNS
&& qtype
.getCode()==QType::NS
&& qname
.isRoot())) {
726 if(d_cacheonly
) { // very limited OOB support
728 LOG(prefix
<<qname
<<": Recursion not requested for '"<<qname
<<"|"<<qtype
.getName()<<"', peeking at auth/forward zones"<<endl
);
729 DNSName
authname(qname
);
730 domainmap_t::const_iterator iter
=getBestAuthZone(&authname
);
731 if(iter
!= t_sstorage
.domainmap
->end()) {
732 if(iter
->second
.isAuth()) {
734 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, ret
, depth
, res
);
736 *fromCache
= d_wasOutOfBand
;
740 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
741 const ComboAddress remoteIP
= servers
.front();
742 LOG(prefix
<<qname
<<": forwarding query to hardcoded nameserver '"<< remoteIP
.toStringWithPort()<<"' for zone '"<<authname
<<"'"<<endl
);
744 boost::optional
<Netmask
> nm
;
745 bool chained
= false;
746 res
=asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, authname
, qtype
.getCode(), false, false, &d_now
, nm
, &lwr
, &chained
);
748 d_totUsec
+= lwr
.d_usec
;
749 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
753 // filter out the good stuff from lwr.result()
755 for(const auto& rec
: lwr
.d_records
) {
756 if(rec
.d_place
== DNSResourceRecord::ANSWER
)
762 return RCode::ServFail
;
768 DNSName
authname(qname
);
769 bool wasForwardedOrAuthZone
= false;
770 bool wasAuthZone
= false;
771 bool wasForwardRecurse
= false;
772 domainmap_t::const_iterator iter
= getBestAuthZone(&authname
);
773 if(iter
!= t_sstorage
.domainmap
->end()) {
774 const auto& domain
= iter
->second
;
775 wasForwardedOrAuthZone
= true;
777 if (domain
.isAuth()) {
779 } else if (domain
.shouldRecurse()) {
780 wasForwardRecurse
= true;
784 if(!d_skipCNAMECheck
&& doCNAMECacheCheck(qname
, qtype
, ret
, depth
, res
, state
, wasAuthZone
, wasForwardRecurse
)) { // will reroute us if needed
785 d_wasOutOfBand
= wasAuthZone
;
789 if(doCacheCheck(qname
, authname
, wasForwardedOrAuthZone
, wasAuthZone
, wasForwardRecurse
, qtype
, ret
, depth
, res
, state
)) {
791 d_wasOutOfBand
= wasAuthZone
;
801 LOG(prefix
<<qname
<<": No cache hit for '"<<qname
<<"|"<<qtype
.getName()<<"', trying to find an appropriate NS record"<<endl
);
803 DNSName
subdomain(qname
);
804 if(qtype
== QType::DS
) subdomain
.chopOff();
807 bool flawedNSSet
=false;
809 /* we use subdomain here instead of qname because for DS queries we only care about the state of the parent zone */
810 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
812 // the two retries allow getBestNSNamesFromCache&co to reprime the root
813 // hints, in case they ever go missing
814 for(int tries
=0;tries
<2 && nsset
.empty();++tries
) {
815 subdomain
=getBestNSNamesFromCache(subdomain
, qtype
, nsset
, &flawedNSSet
, depth
, beenthere
); // pass beenthere to both occasions
818 state
= getValidationStatus(qname
, false);
820 LOG(prefix
<<qname
<<": initial validation status for "<<qname
<<" is "<<vStates
[state
]<<endl
);
822 if(!(res
=doResolveAt(nsset
, subdomain
, flawedNSSet
, qname
, qtype
, ret
, depth
, beenthere
, state
, stopAtDelegation
)))
825 LOG(prefix
<<qname
<<": failed (res="<<res
<<")"<<endl
);
830 return res
<0 ? RCode::ServFail
: res
;
834 // for testing purposes
835 static bool ipv6First(const ComboAddress
& a
, const ComboAddress
& b
)
837 return !(a
.sin4
.sin_family
< a
.sin4
.sin_family
);
843 speedOrderCA(std::map
<ComboAddress
,double>& speeds
): d_speeds(speeds
) {}
844 bool operator()(const ComboAddress
& a
, const ComboAddress
& b
) const
846 return d_speeds
[a
] < d_speeds
[b
];
848 std::map
<ComboAddress
, double>& d_speeds
;
851 /** This function explicitly goes out for A or AAAA addresses
853 vector
<ComboAddress
> SyncRes::getAddrs(const DNSName
&qname
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, bool cacheOnly
)
855 typedef vector
<DNSRecord
> res_t
;
856 typedef vector
<ComboAddress
> ret_t
;
859 bool oldCacheOnly
= setCacheOnly(cacheOnly
);
860 bool oldRequireAuthData
= d_requireAuthData
;
861 bool oldValidationRequested
= d_DNSSECValidationRequested
;
862 d_requireAuthData
= false;
863 d_DNSSECValidationRequested
= false;
865 vState newState
= Indeterminate
;
867 // If IPv4 ever becomes second class, we should revisit this
868 if (doResolve(qname
, QType::A
, resv4
, depth
+1, beenthere
, newState
) == 0) { // this consults cache, OR goes out
869 for (auto const &i
: resv4
) {
870 if (i
.d_type
== QType::A
) {
871 if (auto rec
= getRR
<ARecordContent
>(i
)) {
872 ret
.push_back(rec
->getCA(53));
879 // We did not find IPv4 addresses, try to get IPv6 ones
880 newState
= Indeterminate
;
882 if (doResolve(qname
, QType::AAAA
, resv6
, depth
+1, beenthere
, newState
) == 0) { // this consults cache, OR goes out
883 for (const auto &i
: resv6
) {
884 if (i
.d_type
== QType::AAAA
) {
885 if (auto rec
= getRR
<AAAARecordContent
>(i
))
886 ret
.push_back(rec
->getCA(53));
891 // We have some IPv4 records, don't bother with going out to get IPv6, but do consult the cache
892 // Once IPv6 adoption matters, this needs to be revisited
894 if (t_RC
->get(d_now
.tv_sec
, qname
, QType(QType::AAAA
), false, &cset
, d_cacheRemote
) > 0) {
895 for (const auto &i
: cset
) {
896 if (i
.d_ttl
> (unsigned int)d_now
.tv_sec
) {
897 if (auto rec
= getRR
<AAAARecordContent
>(i
)) {
898 ret
.push_back(rec
->getCA(53));
906 d_requireAuthData
= oldRequireAuthData
;
907 d_DNSSECValidationRequested
= oldValidationRequested
;
908 setCacheOnly(oldCacheOnly
);
910 /* we need to remove from the nsSpeeds collection the existing IPs
911 for this nameserver that are no longer in the set, even if there
912 is only one or none at all in the current set.
914 map
<ComboAddress
, double> speeds
;
915 auto& collection
= t_sstorage
.nsSpeeds
[qname
].d_collection
;
916 for(const auto& val
: ret
) {
917 speeds
[val
] = collection
[val
].get(&d_now
);
920 t_sstorage
.nsSpeeds
[qname
].purge(speeds
);
923 random_shuffle(ret
.begin(), ret
.end());
924 speedOrderCA
so(speeds
);
925 stable_sort(ret
.begin(), ret
.end(), so
);
928 string prefix
=d_prefix
;
929 prefix
.append(depth
, ' ');
930 LOG(prefix
<<"Nameserver "<<qname
<<" IPs: ");
932 for(const auto& addr
: ret
) {
939 LOG((addr
.toString())<<"(" << (boost::format("%0.2f") % (speeds
[addr
]/1000.0)).str() <<"ms)");
948 void SyncRes::getBestNSFromCache(const DNSName
&qname
, const QType
& qtype
, vector
<DNSRecord
>& bestns
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
)
951 DNSName
subdomain(qname
);
954 prefix
.append(depth
, ' ');
960 LOG(prefix
<<qname
<<": Checking if we have NS in cache for '"<<subdomain
<<"'"<<endl
);
961 vector
<DNSRecord
> ns
;
962 *flawedNSSet
= false;
964 if(t_RC
->get(d_now
.tv_sec
, subdomain
, QType(QType::NS
), false, &ns
, d_cacheRemote
) > 0) {
965 bestns
.reserve(ns
.size());
967 for(auto k
=ns
.cbegin();k
!=ns
.cend(); ++k
) {
968 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
969 vector
<DNSRecord
> aset
;
971 const DNSRecord
& dr
=*k
;
972 auto nrr
= getRR
<NSRecordContent
>(dr
);
973 if(nrr
&& (!nrr
->getNS().isPartOf(subdomain
) || t_RC
->get(d_now
.tv_sec
, nrr
->getNS(), s_doIPv6
? QType(QType::ADDR
) : QType(QType::A
),
974 false, doLog() ? &aset
: 0, d_cacheRemote
) > 5)) {
975 bestns
.push_back(dr
);
976 LOG(prefix
<<qname
<<": NS (with ip, or non-glue) in cache for '"<<subdomain
<<"' -> '"<<nrr
->getNS()<<"'"<<endl
);
977 LOG(prefix
<<qname
<<": within bailiwick: "<< nrr
->getNS().isPartOf(subdomain
));
979 LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset
.begin()->d_ttl
- d_now
.tv_sec
))<<endl
);
982 LOG(", not in cache / did not look at cache"<<endl
);
987 LOG(prefix
<<qname
<<": NS in cache for '"<<subdomain
<<"', but needs glue ("<<nrr
->getNS()<<") which we miss or is expired"<<endl
);
992 if(!bestns
.empty()) {
993 GetBestNSAnswer answer
;
995 answer
.qtype
=qtype
.getCode();
996 for(const auto& dr
: bestns
) {
997 if (auto nsContent
= getRR
<NSRecordContent
>(dr
)) {
998 answer
.bestns
.insert(make_pair(dr
.d_name
, nsContent
->getNS()));
1002 if(beenthere
.count(answer
)) {
1004 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' but part of LOOP (already seen "<<answer
.qname
<<")! Trying less specific NS"<<endl
);
1007 for( set
<GetBestNSAnswer
>::const_iterator j
=beenthere
.begin();j
!=beenthere
.end();++j
) {
1008 bool neo
= !(*j
< answer
|| answer
<*j
);
1009 LOG(prefix
<<qname
<<": beenthere"<<(neo
?"*":"")<<": "<<j
->qname
<<"|"<<DNSRecordContent::NumberToType(j
->qtype
)<<" ("<<(unsigned int)j
->bestns
.size()<<")"<<endl
);
1014 beenthere
.insert(answer
);
1015 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' (flawedNSSet="<<*flawedNSSet
<<")"<<endl
);
1020 LOG(prefix
<<qname
<<": no valid/useful NS in cache for '"<<subdomain
<<"'"<<endl
);
1022 if(subdomain
.isRoot() && !brokeloop
) {
1023 // We lost the root NS records
1025 LOG(prefix
<<qname
<<": reprimed the root"<<endl
);
1026 /* let's prevent an infinite loop */
1027 if (!d_updatingRootNS
) {
1028 getRootNS(d_now
, d_asyncResolve
);
1031 } while(subdomain
.chopOff());
1034 SyncRes::domainmap_t::const_iterator
SyncRes::getBestAuthZone(DNSName
* qname
) const
1036 SyncRes::domainmap_t::const_iterator ret
;
1038 ret
=t_sstorage
.domainmap
->find(*qname
);
1039 if(ret
!=t_sstorage
.domainmap
->end())
1041 }while(qname
->chopOff());
1045 /** doesn't actually do the work, leaves that to getBestNSFromCache */
1046 DNSName
SyncRes::getBestNSNamesFromCache(const DNSName
&qname
, const QType
& qtype
, NsSet
& nsset
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
)
1048 DNSName
subdomain(qname
);
1049 DNSName
authdomain(qname
);
1051 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
1052 if(iter
!=t_sstorage
.domainmap
->end()) {
1053 if( iter
->second
.isAuth() )
1054 // this gets picked up in doResolveAt, the empty DNSName, combined with the
1055 // empty vector means 'we are auth for this zone'
1056 nsset
.insert({DNSName(), {{}, false}});
1058 // Again, picked up in doResolveAt. An empty DNSName, combined with a
1059 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
1060 // This is actually picked up in retrieveAddressesForNS called from doResolveAt.
1061 nsset
.insert({DNSName(), {iter
->second
.d_servers
, iter
->second
.shouldRecurse() }});
1066 vector
<DNSRecord
> bestns
;
1067 getBestNSFromCache(subdomain
, qtype
, bestns
, flawedNSSet
, depth
, beenthere
);
1069 for(auto k
=bestns
.cbegin() ; k
!= bestns
.cend(); ++k
) {
1070 // The actual resolver code will not even look at the ComboAddress or bool
1071 const auto nsContent
= getRR
<NSRecordContent
>(*k
);
1073 nsset
.insert({nsContent
->getNS(), {{}, false}});
1074 if(k
==bestns
.cbegin())
1075 subdomain
=k
->d_name
;
1081 void SyncRes::updateValidationStatusInCache(const DNSName
&qname
, const QType
& qt
, bool aa
, vState newState
) const
1083 if (newState
== Bogus
) {
1084 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qt
, d_cacheRemote
, aa
, newState
, s_maxbogusttl
+ d_now
.tv_sec
);
1087 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qt
, d_cacheRemote
, aa
, newState
, boost::none
);
1091 bool SyncRes::doCNAMECacheCheck(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>& ret
, unsigned int depth
, int &res
, vState
& state
, bool wasAuthZone
, bool wasForwardRecurse
)
1096 prefix
.append(depth
, ' ');
1099 if((depth
>9 && d_outqueries
>10 && d_throttledqueries
>5) || depth
> 15) {
1100 LOG(prefix
<<qname
<<": recursing (CNAME or other indirection) too deep, depth="<<depth
<<endl
);
1101 res
=RCode::ServFail
;
1105 vector
<DNSRecord
> cset
;
1106 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
1107 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1109 uint32_t capTTL
= std::numeric_limits
<uint32_t>::max();
1111 QType foundQT
= QType(0); // 0 == QTYPE::ENT
1113 LOG(prefix
<<qname
<<": Looking for CNAME cache hit of '"<<qname
<<"|CNAME"<<"'"<<endl
);
1114 /* we don't require auth data for forward-recurse lookups */
1115 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) {
1117 foundQT
= QType(QType::CNAME
);
1120 if (foundName
.empty() && qname
!= g_rootdnsname
) {
1121 // look for a DNAME cache hit
1122 auto labels
= qname
.getRawLabels();
1123 DNSName
dnameName(g_rootdnsname
);
1125 LOG(prefix
<<qname
<<": Looking for DNAME cache hit of '"<<qname
<<"|DNAME' or its ancestors"<<endl
);
1127 dnameName
.prependRawLabel(labels
.back());
1129 if (dnameName
== qname
&& qtype
!= QType::DNAME
) { // The client does not want a DNAME, but we've reached the QNAME already. So there is no match
1132 if (t_RC
->get(d_now
.tv_sec
, dnameName
, QType(QType::DNAME
), !wasForwardRecurse
&& d_requireAuthData
, &cset
, d_cacheRemote
, d_doDNSSEC
? &signatures
: nullptr, d_doDNSSEC
? &authorityRecs
: nullptr, &d_wasVariable
, &state
, &wasAuth
) > 0) {
1133 foundName
= dnameName
;
1134 foundQT
= QType(QType::DNAME
);
1137 } while(!labels
.empty());
1140 if (foundName
.empty()) {
1141 LOG(prefix
<<qname
<<": No CNAME or DNAME cache hit of '"<< qname
<<"' found"<<endl
);
1145 for(auto const &record
: cset
) {
1146 if (record
.d_class
!= QClass::IN
) {
1150 if(record
.d_ttl
> (unsigned int) d_now
.tv_sec
) {
1152 if (!wasAuthZone
&& shouldValidate() && (wasAuth
|| wasForwardRecurse
) && state
== Indeterminate
&& d_requireAuthData
) {
1153 /* This means we couldn't figure out the state when this entry was cached,
1154 most likely because we hadn't computed the zone cuts yet. */
1155 /* make sure they are computed before validating */
1156 DNSName
subdomain(foundName
);
1157 /* if we are retrieving a DS, we only care about the state of the parent zone */
1158 if(qtype
== QType::DS
)
1159 subdomain
.chopOff();
1161 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1163 vState recordState
= getValidationStatus(foundName
, false);
1164 if (recordState
== Secure
) {
1165 LOG(prefix
<<qname
<<": got Indeterminate state from the "<<foundQT
.getName()<<" cache, validating.."<<endl
);
1166 state
= SyncRes::validateRecordsWithSigs(depth
, foundName
, foundQT
, foundName
, cset
, signatures
);
1167 if (state
!= Indeterminate
) {
1168 LOG(prefix
<<qname
<<": got Indeterminate state from the CNAME cache, new validation result is "<<vStates
[state
]<<endl
);
1169 if (state
== Bogus
) {
1170 capTTL
= s_maxbogusttl
;
1172 updateValidationStatusInCache(foundName
, foundQT
, wasAuth
, state
);
1177 LOG(prefix
<<qname
<<": Found cache "<<foundQT
.getName()<<" hit for '"<< foundName
<< "|"<<foundQT
.getName()<<"' to '"<<record
.d_content
->getZoneRepresentation()<<"', validation state is "<<vStates
[state
]<<endl
);
1179 DNSRecord dr
= record
;
1180 dr
.d_ttl
-= d_now
.tv_sec
;
1181 dr
.d_ttl
= std::min(dr
.d_ttl
, capTTL
);
1182 const uint32_t ttl
= dr
.d_ttl
;
1183 ret
.reserve(ret
.size() + 2 + signatures
.size() + authorityRecs
.size());
1186 for(const auto& signature
: signatures
) {
1188 sigdr
.d_type
=QType::RRSIG
;
1189 sigdr
.d_name
=foundName
;
1191 sigdr
.d_content
=signature
;
1192 sigdr
.d_place
=DNSResourceRecord::ANSWER
;
1193 sigdr
.d_class
=QClass::IN
;
1194 ret
.push_back(sigdr
);
1197 for(const auto& rec
: authorityRecs
) {
1198 DNSRecord
authDR(*rec
);
1200 ret
.push_back(authDR
);
1204 if (foundQT
== QType::DNAME
) {
1205 if (qtype
== QType::DNAME
&& qname
== foundName
) { // client wanted the DNAME, no need to synthesize a CNAME
1209 // Synthesize a CNAME
1210 auto dnameRR
= getRR
<DNAMERecordContent
>(record
);
1211 if (dnameRR
== nullptr) {
1212 throw ImmediateServFailException("Unable to get record content for "+foundName
.toLogString()+"|DNAME cache entry");
1214 const auto& dnameSuffix
= dnameRR
->getTarget();
1215 DNSName targetPrefix
= qname
.makeRelative(foundName
);
1217 dr
.d_type
= QType::CNAME
;
1218 dr
.d_name
= targetPrefix
+ foundName
;
1219 newTarget
= targetPrefix
+ dnameSuffix
;
1220 dr
.d_content
= std::make_shared
<CNAMERecordContent
>(CNAMERecordContent(newTarget
));
1222 } catch (const std::exception
&e
) {
1223 // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
1224 // But this is consistent with processRecords
1225 throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + foundName
.toLogString() +
1226 "', DNAME target: '" + dnameSuffix
.toLogString() + "', substituted name: '" +
1227 targetPrefix
.toLogString() + "." + dnameSuffix
.toLogString() +
1231 LOG(prefix
<<qname
<<": Synthesized "<<dr
.d_name
<<"|CNAME "<<newTarget
<<endl
);
1234 if(qtype
== QType::CNAME
) { // perhaps they really wanted a CNAME!
1239 // We have a DNAME _or_ CNAME cache hit and the client wants something else than those two.
1240 // Let's find the answer!
1241 if (foundQT
== QType::CNAME
) {
1242 const auto cnameContent
= getRR
<CNAMERecordContent
>(record
);
1243 if (cnameContent
== nullptr) {
1244 throw ImmediateServFailException("Unable to get record content for "+foundName
.toLogString()+"|CNAME cache entry");
1246 newTarget
= cnameContent
->getTarget();
1249 set
<GetBestNSAnswer
>beenthere
;
1250 vState cnameState
= Indeterminate
;
1251 res
= doResolve(newTarget
, qtype
, ret
, depth
+1, beenthere
, cnameState
);
1252 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the DNAME/CNAME quest: "<<vStates
[cnameState
]<<endl
);
1253 updateValidationState(state
, cnameState
);
1258 throw ImmediateServFailException("Could not determine whether or not there was a CNAME or DNAME in cache for '" + qname
.toLogString() + "'");
1264 vector
<DNSRecord
> records
;
1265 vector
<shared_ptr
<RRSIGRecordContent
>> signatures
;
1266 uint32_t signaturesTTL
{std::numeric_limits
<uint32_t>::max()};
1272 DNSResourceRecord::Place place
;
1273 bool operator<(const CacheKey
& rhs
) const {
1274 return tie(type
, place
, name
) < tie(rhs
.type
, rhs
.place
, rhs
.name
);
1277 typedef map
<CacheKey
, CacheEntry
> tcache_t
;
1280 static void reapRecordsFromNegCacheEntryForValidation(tcache_t
& tcache
, const vector
<DNSRecord
>& records
)
1282 for (const auto& rec
: records
) {
1283 if (rec
.d_type
== QType::RRSIG
) {
1284 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1286 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
1289 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(rec
);
1295 * Convience function to push the records from records into ret with a new TTL
1297 * \param records DNSRecords that need to go into ret
1298 * \param ttl The new TTL for these records
1299 * \param ret The vector of DNSRecords that should contian the records with the modified TTL
1301 static void addTTLModifiedRecords(const vector
<DNSRecord
>& records
, const uint32_t ttl
, vector
<DNSRecord
>& ret
) {
1302 for (const auto& rec
: records
) {
1309 void SyncRes::computeNegCacheValidationStatus(const NegCache::NegCacheEntry
* ne
, const DNSName
& qname
, const QType
& qtype
, const int res
, vState
& state
, unsigned int depth
)
1311 DNSName
subdomain(qname
);
1312 /* if we are retrieving a DS, we only care about the state of the parent zone */
1313 if(qtype
== QType::DS
)
1314 subdomain
.chopOff();
1316 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1319 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->authoritySOA
.records
);
1320 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->authoritySOA
.signatures
);
1321 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->DNSSECRecords
.records
);
1322 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
->DNSSECRecords
.signatures
);
1324 for (const auto& entry
: tcache
) {
1325 // this happens when we did store signatures, but passed on the records themselves
1326 if (entry
.second
.records
.empty()) {
1330 const DNSName
& owner
= entry
.first
.name
;
1332 vState recordState
= getValidationStatus(owner
, false);
1333 if (state
== Indeterminate
) {
1334 state
= recordState
;
1337 if (recordState
== Secure
) {
1338 recordState
= SyncRes::validateRecordsWithSigs(depth
, qname
, qtype
, owner
, entry
.second
.records
, entry
.second
.signatures
);
1341 if (recordState
!= Indeterminate
&& recordState
!= state
) {
1342 updateValidationState(state
, recordState
);
1343 if (state
!= Secure
) {
1349 if (state
== Secure
) {
1350 vState neValidationState
= ne
->d_validationState
;
1351 dState expectedState
= res
== RCode::NXDomain
? NXDOMAIN
: NXQTYPE
;
1352 dState denialState
= getDenialValidationState(*ne
, state
, expectedState
, false);
1353 updateDenialValidationState(neValidationState
, ne
->d_name
, state
, denialState
, expectedState
, qtype
== QType::DS
);
1355 if (state
!= Indeterminate
) {
1356 /* validation succeeded, let's update the cache entry so we don't have to validate again */
1357 boost::optional
<uint32_t> capTTD
= boost::none
;
1358 if (state
== Bogus
) {
1359 capTTD
= d_now
.tv_sec
+ s_maxbogusttl
;
1361 t_sstorage
.negcache
.updateValidationStatus(ne
->d_name
, ne
->d_qtype
, state
, capTTD
);
1365 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
)
1367 bool giveNegative
=false;
1372 prefix
.append(depth
, ' ');
1375 // 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)
1376 DNSName
sqname(qname
);
1379 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
1381 const NegCache::NegCacheEntry
* ne
= nullptr;
1384 t_sstorage
.negcache
.getRootNXTrust(qname
, d_now
, &ne
) &&
1385 ne
->d_auth
.isRoot() &&
1386 !(wasForwardedOrAuthZone
&& !authname
.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
1387 sttl
= ne
->d_ttd
- d_now
.tv_sec
;
1388 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
->d_auth
<<"' & '"<<ne
->d_name
<<"' for another "<<sttl
<<" seconds"<<endl
);
1389 res
= RCode::NXDomain
;
1390 giveNegative
= true;
1391 cachedState
= ne
->d_validationState
;
1393 else if (t_sstorage
.negcache
.get(qname
, qtype
, d_now
, &ne
)) {
1394 /* If we are looking for a DS, discard NXD if auth == qname
1395 and ask for a specific denial instead */
1396 if (qtype
!= QType::DS
|| ne
->d_qtype
.getCode() || ne
->d_auth
!= qname
||
1397 t_sstorage
.negcache
.get(qname
, qtype
, d_now
, &ne
, true))
1400 sttl
= ne
->d_ttd
- d_now
.tv_sec
;
1401 giveNegative
= true;
1402 cachedState
= ne
->d_validationState
;
1403 if(ne
->d_qtype
.getCode()) {
1404 LOG(prefix
<<qname
<<": "<<qtype
.getName()<<" is negatively cached via '"<<ne
->d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1405 res
= RCode::NoError
;
1408 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
->d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1409 res
= RCode::NXDomain
;
1416 state
= cachedState
;
1418 if (!wasAuthZone
&& shouldValidate() && state
== Indeterminate
) {
1419 LOG(prefix
<<qname
<<": got Indeterminate state for records retrieved from the negative cache, validating.."<<endl
);
1420 computeNegCacheValidationStatus(ne
, qname
, qtype
, res
, state
, depth
);
1422 if (state
!= cachedState
&& state
== Bogus
) {
1423 sttl
= std::min(sttl
, s_maxbogusttl
);
1427 // Transplant SOA to the returned packet
1428 addTTLModifiedRecords(ne
->authoritySOA
.records
, sttl
, ret
);
1430 addTTLModifiedRecords(ne
->authoritySOA
.signatures
, sttl
, ret
);
1431 addTTLModifiedRecords(ne
->DNSSECRecords
.records
, sttl
, ret
);
1432 addTTLModifiedRecords(ne
->DNSSECRecords
.signatures
, sttl
, ret
);
1435 LOG(prefix
<<qname
<<": updating validation state with negative cache content for "<<qname
<<" to "<<vStates
[state
]<<endl
);
1439 vector
<DNSRecord
> cset
;
1440 bool found
=false, expired
=false;
1441 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
1442 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1444 uint32_t capTTL
= std::numeric_limits
<uint32_t>::max();
1446 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) {
1448 LOG(prefix
<<sqname
<<": Found cache hit for "<<sqt
.getName()<<": ");
1450 if (!wasAuthZone
&& shouldValidate() && (wasCachedAuth
|| wasForwardRecurse
) && cachedState
== Indeterminate
&& d_requireAuthData
) {
1452 /* This means we couldn't figure out the state when this entry was cached,
1453 most likely because we hadn't computed the zone cuts yet. */
1454 /* make sure they are computed before validating */
1455 DNSName
subdomain(sqname
);
1456 /* if we are retrieving a DS, we only care about the state of the parent zone */
1457 if(qtype
== QType::DS
)
1458 subdomain
.chopOff();
1460 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1462 vState recordState
= getValidationStatus(qname
, false);
1463 if (recordState
== Secure
) {
1464 LOG(prefix
<<sqname
<<": got Indeterminate state from the cache, validating.."<<endl
);
1465 cachedState
= SyncRes::validateRecordsWithSigs(depth
, sqname
, sqt
, sqname
, cset
, signatures
);
1468 cachedState
= recordState
;
1471 if (cachedState
!= Indeterminate
) {
1472 LOG(prefix
<<qname
<<": got Indeterminate state from the cache, validation result is "<<vStates
[cachedState
]<<endl
);
1473 if (cachedState
== Bogus
) {
1474 capTTL
= s_maxbogusttl
;
1476 updateValidationStatusInCache(sqname
, sqt
, wasCachedAuth
, cachedState
);
1480 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
1482 LOG(j
->d_content
->getZoneRepresentation());
1484 if (j
->d_class
!= QClass::IN
) {
1488 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
1490 dr
.d_ttl
-= d_now
.tv_sec
;
1491 dr
.d_ttl
= std::min(dr
.d_ttl
, capTTL
);
1494 LOG("[ttl="<<dr
.d_ttl
<<"] ");
1503 ret
.reserve(ret
.size() + signatures
.size() + authorityRecs
.size());
1505 for(const auto& signature
: signatures
) {
1507 dr
.d_type
=QType::RRSIG
;
1510 dr
.d_content
=signature
;
1511 dr
.d_place
= DNSResourceRecord::ANSWER
;
1512 dr
.d_class
=QClass::IN
;
1516 for(const auto& rec
: authorityRecs
) {
1523 if(found
&& !expired
) {
1526 LOG(prefix
<<qname
<<": updating validation state with cache content for "<<qname
<<" to "<<vStates
[cachedState
]<<endl
);
1527 state
= cachedState
;
1531 LOG(prefix
<<qname
<<": cache had only stale entries"<<endl
);
1537 bool SyncRes::moreSpecificThan(const DNSName
& a
, const DNSName
&b
) const
1539 return (a
.isPartOf(b
) && a
.countLabels() > b
.countLabels());
1544 bool operator()(const std::pair
<DNSName
, double> &a
, const std::pair
<DNSName
, double> &b
) const
1546 return a
.second
< b
.second
;
1550 inline std::vector
<std::pair
<DNSName
, double>> SyncRes::shuffleInSpeedOrder(NsSet
&tnameservers
, const string
&prefix
)
1552 std::vector
<std::pair
<DNSName
, double>> rnameservers
;
1553 rnameservers
.reserve(tnameservers
.size());
1554 for(const auto& tns
: tnameservers
) {
1555 double speed
= t_sstorage
.nsSpeeds
[tns
.first
].get(&d_now
);
1556 rnameservers
.push_back({tns
.first
, speed
});
1557 if(tns
.first
.empty()) // this was an authoritative OOB zone, don't pollute the nsSpeeds with that
1558 return rnameservers
;
1561 random_shuffle(rnameservers
.begin(),rnameservers
.end());
1563 stable_sort(rnameservers
.begin(),rnameservers
.end(), so
);
1566 LOG(prefix
<<"Nameservers: ");
1567 for(auto i
=rnameservers
.begin();i
!=rnameservers
.end();++i
) {
1568 if(i
!=rnameservers
.begin()) {
1570 if(!((i
-rnameservers
.begin())%3)) {
1571 LOG(endl
<<prefix
<<" ");
1574 LOG(i
->first
.toLogString()<<"(" << (boost::format("%0.2f") % (i
->second
/1000.0)).str() <<"ms)");
1578 return rnameservers
;
1581 inline vector
<ComboAddress
> SyncRes::shuffleForwardSpeed(const vector
<ComboAddress
> &rnameservers
, const string
&prefix
, const bool wasRd
)
1583 vector
<ComboAddress
> nameservers
= rnameservers
;
1584 map
<ComboAddress
, double> speeds
;
1586 for(const auto& val
: nameservers
) {
1588 DNSName nsName
= DNSName(val
.toStringWithPort());
1589 speed
=t_sstorage
.nsSpeeds
[nsName
].get(&d_now
);
1592 random_shuffle(nameservers
.begin(),nameservers
.end());
1593 speedOrderCA
so(speeds
);
1594 stable_sort(nameservers
.begin(),nameservers
.end(), so
);
1597 LOG(prefix
<<"Nameservers: ");
1598 for(vector
<ComboAddress
>::const_iterator i
=nameservers
.cbegin();i
!=nameservers
.cend();++i
) {
1599 if(i
!=nameservers
.cbegin()) {
1601 if(!((i
-nameservers
.cbegin())%3)) {
1602 LOG(endl
<<prefix
<<" ");
1605 LOG((wasRd
? string("+") : string("-")) << i
->toStringWithPort() <<"(" << (boost::format("%0.2f") % (speeds
[*i
]/1000.0)).str() <<"ms)");
1612 static uint32_t getRRSIGTTL(const time_t now
, const std::shared_ptr
<RRSIGRecordContent
>& rrsig
)
1615 if (now
< rrsig
->d_sigexpire
) {
1616 res
= static_cast<uint32_t>(rrsig
->d_sigexpire
) - now
;
1621 static const set
<uint16_t> nsecTypes
= {QType::NSEC
, QType::NSEC3
};
1623 /* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
1625 * \param records The records to parse for the authority SOA and NSEC(3) records
1626 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
1628 static void harvestNXRecords(const vector
<DNSRecord
>& records
, NegCache::NegCacheEntry
& ne
, const time_t now
, uint32_t* lowestTTL
) {
1629 for(const auto& rec
: records
) {
1630 if(rec
.d_place
!= DNSResourceRecord::AUTHORITY
)
1631 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
1632 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
1633 // records MUST be in the same section as the records they cover.
1634 // Hence, we ignore all records outside of the AUTHORITY section.
1637 if(rec
.d_type
== QType::RRSIG
) {
1638 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1640 if(rrsig
->d_type
== QType::SOA
) {
1641 ne
.authoritySOA
.signatures
.push_back(rec
);
1642 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1643 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1644 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1647 if(nsecTypes
.count(rrsig
->d_type
)) {
1648 ne
.DNSSECRecords
.signatures
.push_back(rec
);
1649 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1650 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1651 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1657 if(rec
.d_type
== QType::SOA
) {
1658 ne
.authoritySOA
.records
.push_back(rec
);
1660 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1664 if(nsecTypes
.count(rec
.d_type
)) {
1665 ne
.DNSSECRecords
.records
.push_back(rec
);
1667 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1674 static cspmap_t
harvestCSPFromNE(const NegCache::NegCacheEntry
& ne
)
1677 for(const auto& rec
: ne
.DNSSECRecords
.signatures
) {
1678 if(rec
.d_type
== QType::RRSIG
) {
1679 auto rrc
= getRR
<RRSIGRecordContent
>(rec
);
1681 cspmap
[{rec
.d_name
,rrc
->d_type
}].signatures
.push_back(rrc
);
1685 for(const auto& rec
: ne
.DNSSECRecords
.records
) {
1686 cspmap
[{rec
.d_name
, rec
.d_type
}].records
.push_back(rec
.d_content
);
1691 // TODO remove after processRecords is fixed!
1692 // Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
1693 static void addNXNSECS(vector
<DNSRecord
>&ret
, const vector
<DNSRecord
>& records
)
1695 NegCache::NegCacheEntry ne
;
1696 harvestNXRecords(records
, ne
, 0, nullptr);
1697 ret
.insert(ret
.end(), ne
.authoritySOA
.signatures
.begin(), ne
.authoritySOA
.signatures
.end());
1698 ret
.insert(ret
.end(), ne
.DNSSECRecords
.records
.begin(), ne
.DNSSECRecords
.records
.end());
1699 ret
.insert(ret
.end(), ne
.DNSSECRecords
.signatures
.begin(), ne
.DNSSECRecords
.signatures
.end());
1702 bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine
& dfe
, const NsSet
& nameservers
)
1705 for (auto const &ns
: nameservers
) {
1706 d_appliedPolicy
= dfe
.getProcessingPolicy(ns
.first
, d_discardedPolicies
);
1707 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1708 LOG(", however nameserver "<<ns
.first
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1712 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1713 for (auto const &address
: ns
.second
.first
) {
1714 d_appliedPolicy
= dfe
.getProcessingPolicy(address
, d_discardedPolicies
);
1715 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1716 LOG(", however nameserver "<<ns
.first
<<" IP address "<<address
.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1725 bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine
& dfe
, const ComboAddress
& remoteIP
)
1728 d_appliedPolicy
= dfe
.getProcessingPolicy(remoteIP
, d_discardedPolicies
);
1729 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) {
1730 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")+"')");
1737 vector
<ComboAddress
> SyncRes::retrieveAddressesForNS(const std::string
& prefix
, const DNSName
& qname
, std::vector
<std::pair
<DNSName
, double>>::const_iterator
& tns
, const unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, const vector
<std::pair
<DNSName
, double>>& rnameservers
, NsSet
& nameservers
, bool& sendRDQuery
, bool& pierceDontQuery
, bool& flawedNSSet
, bool cacheOnly
)
1739 vector
<ComboAddress
> result
;
1741 if(!tns
->first
.empty()) {
1742 LOG(prefix
<<qname
<<": Trying to resolve NS '"<<tns
->first
<< "' ("<<1+tns
-rnameservers
.begin()<<"/"<<(unsigned int)rnameservers
.size()<<")"<<endl
);
1743 result
= getAddrs(tns
->first
, depth
+2, beenthere
, cacheOnly
);
1744 pierceDontQuery
=false;
1747 LOG(prefix
<<qname
<<": Domain has hardcoded nameserver");
1749 if(nameservers
[tns
->first
].first
.size() > 1) {
1754 sendRDQuery
= nameservers
[tns
->first
].second
;
1755 result
= shuffleForwardSpeed(nameservers
[tns
->first
].first
, doLog() ? (prefix
+qname
.toString()+": ") : string(), sendRDQuery
);
1756 pierceDontQuery
=true;
1761 bool SyncRes::throttledOrBlocked(const std::string
& prefix
, const ComboAddress
& remoteIP
, const DNSName
& qname
, const QType
& qtype
, bool pierceDontQuery
)
1763 if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0))) {
1764 LOG(prefix
<<qname
<<": server throttled "<<endl
);
1765 s_throttledqueries
++; d_throttledqueries
++;
1768 else if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()))) {
1769 LOG(prefix
<<qname
<<": query throttled "<<remoteIP
.toString()<<", "<<qname
<<"; "<<qtype
.getName()<<endl
);
1770 s_throttledqueries
++; d_throttledqueries
++;
1773 else if(!pierceDontQuery
&& s_dontQuery
&& s_dontQuery
->match(&remoteIP
)) {
1774 LOG(prefix
<<qname
<<": not sending query to " << remoteIP
.toString() << ", blocked by 'dont-query' setting" << endl
);
1781 bool SyncRes::validationEnabled() const
1783 return g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
;
1786 uint32_t SyncRes::computeLowestTTD(const std::vector
<DNSRecord
>& records
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, uint32_t signaturesTTL
) const
1788 uint32_t lowestTTD
= std::numeric_limits
<uint32_t>::max();
1789 for(const auto& record
: records
)
1790 lowestTTD
= min(lowestTTD
, record
.d_ttl
);
1792 /* even if it was not requested for that request (Process, and neither AD nor DO set),
1793 it might be requested at a later time so we need to be careful with the TTL. */
1794 if (validationEnabled() && !signatures
.empty()) {
1795 /* if we are validating, we don't want to cache records after their signatures expire. */
1796 /* records TTL are now TTD, let's add 'now' to the signatures lowest TTL */
1797 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(signaturesTTL
+ d_now
.tv_sec
));
1799 for(const auto& sig
: signatures
) {
1800 if (isRRSIGNotExpired(d_now
.tv_sec
, sig
)) {
1801 // we don't decerement d_sigexpire by 'now' because we actually want a TTD, not a TTL */
1802 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(sig
->d_sigexpire
));
1810 void SyncRes::updateValidationState(vState
& state
, const vState stateUpdate
)
1812 LOG(d_prefix
<<"validation state was "<<std::string(vStates
[state
])<<", state update is "<<std::string(vStates
[stateUpdate
]));
1814 if (stateUpdate
== TA
) {
1817 else if (stateUpdate
== NTA
) {
1820 else if (stateUpdate
== Bogus
) {
1823 else if (state
== Indeterminate
) {
1824 state
= stateUpdate
;
1826 else if (stateUpdate
== Insecure
) {
1827 if (state
!= Bogus
) {
1831 LOG(", validation state is now "<<std::string(vStates
[state
])<<endl
);
1834 vState
SyncRes::getTA(const DNSName
& zone
, dsmap_t
& ds
)
1836 auto luaLocal
= g_luaconfs
.getLocal();
1838 if (luaLocal
->dsAnchors
.empty()) {
1839 LOG(d_prefix
<<": No trust anchors configured, everything is Insecure"<<endl
);
1840 /* We have no TA, everything is insecure */
1845 if (haveNegativeTrustAnchor(luaLocal
->negAnchors
, zone
, reason
)) {
1846 LOG(d_prefix
<<": got NTA for '"<<zone
<<"'"<<endl
);
1850 if (getTrustAnchor(luaLocal
->dsAnchors
, zone
, ds
)) {
1851 LOG(d_prefix
<<": got TA for '"<<zone
<<"'"<<endl
);
1855 LOG(d_prefix
<<": no TA found for '"<<zone
<<"' among "<< luaLocal
->dsAnchors
.size()<<endl
);
1858 if (zone
.isRoot()) {
1859 /* No TA for the root */
1863 return Indeterminate
;
1866 static size_t countSupportedDS(const dsmap_t
& dsmap
)
1870 for (const auto& ds
: dsmap
) {
1871 if (isSupportedDS(ds
)) {
1879 vState
SyncRes::getDSRecords(const DNSName
& zone
, dsmap_t
& ds
, bool taOnly
, unsigned int depth
, bool bogusOnNXD
, bool* foundCut
)
1881 vState result
= getTA(zone
, ds
);
1883 if (result
!= Indeterminate
|| taOnly
) {
1885 *foundCut
= (result
!= Indeterminate
);
1889 if (countSupportedDS(ds
) == 0) {
1897 else if (result
== NTA
) {
1904 bool oldSkipCNAME
= d_skipCNAMECheck
;
1905 d_skipCNAMECheck
= true;
1907 std::set
<GetBestNSAnswer
> beenthere
;
1908 std::vector
<DNSRecord
> dsrecords
;
1910 vState state
= Indeterminate
;
1911 int rcode
= doResolve(zone
, QType(QType::DS
), dsrecords
, depth
+ 1, beenthere
, state
);
1912 d_skipCNAMECheck
= oldSkipCNAME
;
1914 if (rcode
== RCode::NoError
|| (rcode
== RCode::NXDomain
&& !bogusOnNXD
)) {
1915 uint8_t bestDigestType
= 0;
1917 bool gotCNAME
= false;
1918 for (const auto& record
: dsrecords
) {
1919 if (record
.d_type
== QType::DS
) {
1920 const auto dscontent
= getRR
<DSRecordContent
>(record
);
1921 if (dscontent
&& isSupportedDS(*dscontent
)) {
1922 // Make GOST a lower prio than SHA256
1923 if (dscontent
->d_digesttype
== DNSSECKeeper::GOST
&& bestDigestType
== DNSSECKeeper::SHA256
) {
1926 if (dscontent
->d_digesttype
> bestDigestType
|| (bestDigestType
== DNSSECKeeper::GOST
&& dscontent
->d_digesttype
== DNSSECKeeper::SHA256
)) {
1927 bestDigestType
= dscontent
->d_digesttype
;
1929 ds
.insert(*dscontent
);
1932 else if (record
.d_type
== QType::CNAME
&& record
.d_name
== zone
) {
1937 /* RFC 4509 section 3: "Validator implementations SHOULD ignore DS RRs containing SHA-1
1938 * digests if DS RRs with SHA-256 digests are present in the DS RRset."
1939 * As SHA348 is specified as well, the spirit of the this line is "use the best algorithm".
1941 for (auto dsrec
= ds
.begin(); dsrec
!= ds
.end(); ) {
1942 if (dsrec
->d_digesttype
!= bestDigestType
) {
1943 dsrec
= ds
.erase(dsrec
);
1950 if (rcode
== RCode::NoError
) {
1952 /* we have no DS, it's either:
1953 - a delegation to a non-DNSSEC signed zone
1954 - no delegation, we stay in the same zone
1956 if (gotCNAME
|| denialProvesNoDelegation(zone
, dsrecords
)) {
1957 /* we are still inside the same zone */
1965 /* delegation with no DS, might be Secure -> Insecure */
1970 /* a delegation with no DS is either:
1971 - a signed zone (Secure) to an unsigned one (Insecure)
1972 - an unsigned zone to another unsigned one (Insecure stays Insecure, Bogus stays Bogus)
1974 return state
== Secure
? Insecure
: state
;
1986 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
1990 bool SyncRes::haveExactValidationStatus(const DNSName
& domain
)
1992 if (!shouldValidate()) {
1995 const auto& it
= d_cutStates
.find(domain
);
1996 if (it
!= d_cutStates
.cend()) {
2002 vState
SyncRes::getValidationStatus(const DNSName
& subdomain
, bool allowIndeterminate
)
2004 vState result
= Indeterminate
;
2006 if (!shouldValidate()) {
2009 DNSName
name(subdomain
);
2011 const auto& it
= d_cutStates
.find(name
);
2012 if (it
!= d_cutStates
.cend()) {
2013 if (allowIndeterminate
|| it
->second
!= Indeterminate
) {
2014 LOG(d_prefix
<<": got status "<<vStates
[it
->second
]<<" for name "<<subdomain
<<" (from "<<name
<<")"<<endl
);
2019 while (name
.chopOff());
2024 bool SyncRes::lookForCut(const DNSName
& qname
, unsigned int depth
, const vState existingState
, vState
& newState
)
2026 bool foundCut
= false;
2028 vState dsState
= getDSRecords(qname
, ds
, newState
== Bogus
|| existingState
== Insecure
|| existingState
== Bogus
, depth
, false, &foundCut
);
2030 if (dsState
!= Indeterminate
) {
2037 void SyncRes::computeZoneCuts(const DNSName
& begin
, const DNSName
& end
, unsigned int depth
)
2039 if(!begin
.isPartOf(end
)) {
2040 LOG(d_prefix
<<" "<<begin
.toLogString()<<" is not part of "<<end
.toLogString()<<endl
);
2041 throw PDNSException(begin
.toLogString() + " is not part of " + end
.toLogString());
2044 if (d_cutStates
.count(begin
) != 0) {
2049 vState cutState
= getDSRecords(end
, ds
, false, depth
);
2050 LOG(d_prefix
<<": setting cut state for "<<end
<<" to "<<vStates
[cutState
]<<endl
);
2051 d_cutStates
[end
] = cutState
;
2053 if (!shouldValidate()) {
2058 std::vector
<string
> labelsToAdd
= begin
.makeRelative(end
).getRawLabels();
2060 bool oldSkipCNAME
= d_skipCNAMECheck
;
2061 d_skipCNAMECheck
= true;
2063 while(qname
!= begin
) {
2064 if (labelsToAdd
.empty())
2067 qname
.prependRawLabel(labelsToAdd
.back());
2068 labelsToAdd
.pop_back();
2069 LOG(d_prefix
<<": - Looking for a cut at "<<qname
<<endl
);
2071 const auto cutIt
= d_cutStates
.find(qname
);
2072 if (cutIt
!= d_cutStates
.cend()) {
2073 if (cutIt
->second
!= Indeterminate
) {
2074 LOG(d_prefix
<<": - Cut already known at "<<qname
<<endl
);
2075 cutState
= cutIt
->second
;
2080 /* no need to look for NS and DS if we are already insecure or bogus,
2083 if (cutState
== Insecure
|| cutState
== Bogus
) {
2085 vState newState
= getDSRecords(qname
, cutDS
, true, depth
);
2086 if (newState
== Indeterminate
) {
2090 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[newState
]<<endl
);
2091 cutState
= newState
;
2093 d_cutStates
[qname
] = cutState
;
2098 vState newState
= Indeterminate
;
2099 /* temporarily mark as Indeterminate, so that we won't enter an endless loop
2100 trying to determine that zone cut again. */
2101 d_cutStates
[qname
] = newState
;
2102 bool foundCut
= lookForCut(qname
, depth
+ 1, cutState
, newState
);
2104 LOG(d_prefix
<<": - Found cut at "<<qname
<<endl
);
2105 if (newState
!= Indeterminate
) {
2106 cutState
= newState
;
2108 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[cutState
]<<endl
);
2109 d_cutStates
[qname
] = cutState
;
2112 /* remove the temporary cut */
2113 LOG(d_prefix
<<qname
<<": removing cut state for "<<qname
<<endl
);
2114 d_cutStates
.erase(qname
);
2118 d_skipCNAMECheck
= oldSkipCNAME
;
2120 LOG(d_prefix
<<": list of cuts from "<<begin
<<" to "<<end
<<endl
);
2121 for (const auto& cut
: d_cutStates
) {
2122 if (cut
.first
.isRoot() || (begin
.isPartOf(cut
.first
) && cut
.first
.isPartOf(end
))) {
2123 LOG(" - "<<cut
.first
<<": "<<vStates
[cut
.second
]<<endl
);
2128 vState
SyncRes::validateDNSKeys(const DNSName
& zone
, const std::vector
<DNSRecord
>& dnskeys
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, unsigned int depth
)
2131 if (!signatures
.empty()) {
2132 DNSName signer
= getSigner(signatures
);
2134 if (!signer
.empty() && zone
.isPartOf(signer
)) {
2135 vState state
= getDSRecords(signer
, ds
, false, depth
);
2137 if (state
!= Secure
) {
2143 skeyset_t tentativeKeys
;
2144 std::vector
<shared_ptr
<DNSRecordContent
> > toSign
;
2146 for (const auto& dnskey
: dnskeys
) {
2147 if (dnskey
.d_type
== QType::DNSKEY
) {
2148 auto content
= getRR
<DNSKEYRecordContent
>(dnskey
);
2150 tentativeKeys
.insert(content
);
2151 toSign
.push_back(content
);
2156 LOG(d_prefix
<<": trying to validate "<<std::to_string(tentativeKeys
.size())<<" DNSKEYs with "<<std::to_string(ds
.size())<<" DS"<<endl
);
2157 skeyset_t validatedKeys
;
2158 validateDNSKeysAgainstDS(d_now
.tv_sec
, zone
, ds
, tentativeKeys
, toSign
, signatures
, validatedKeys
);
2160 LOG(d_prefix
<<": we now have "<<std::to_string(validatedKeys
.size())<<" DNSKEYs"<<endl
);
2162 /* if we found at least one valid RRSIG covering the set,
2163 all tentative keys are validated keys. Otherwise it means
2164 we haven't found at least one DNSKEY and a matching RRSIG
2165 covering this set, this looks Bogus. */
2166 if (validatedKeys
.size() != tentativeKeys
.size()) {
2167 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
2174 vState
SyncRes::getDNSKeys(const DNSName
& signer
, skeyset_t
& keys
, unsigned int depth
)
2176 std::vector
<DNSRecord
> records
;
2177 std::set
<GetBestNSAnswer
> beenthere
;
2178 LOG(d_prefix
<<"Retrieving DNSKeys for "<<signer
<<endl
);
2180 vState state
= Indeterminate
;
2181 /* following CNAME might lead to us to the wrong DNSKEY */
2182 bool oldSkipCNAME
= d_skipCNAMECheck
;
2183 d_skipCNAMECheck
= true;
2184 int rcode
= doResolve(signer
, QType(QType::DNSKEY
), records
, depth
+ 1, beenthere
, state
);
2185 d_skipCNAMECheck
= oldSkipCNAME
;
2187 if (rcode
== RCode::NoError
) {
2188 if (state
== Secure
) {
2189 for (const auto& key
: records
) {
2190 if (key
.d_type
== QType::DNSKEY
) {
2191 auto content
= getRR
<DNSKEYRecordContent
>(key
);
2193 keys
.insert(content
);
2198 LOG(d_prefix
<<"Retrieved "<<keys
.size()<<" DNSKeys for "<<signer
<<", state is "<<vStates
[state
]<<endl
);
2202 LOG(d_prefix
<<"Returning Bogus state from "<<__func__
<<"("<<signer
<<")"<<endl
);
2206 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
)
2209 if (!signatures
.empty()) {
2210 const DNSName signer
= getSigner(signatures
);
2211 if (!signer
.empty() && name
.isPartOf(signer
)) {
2212 if ((qtype
== QType::DNSKEY
|| qtype
== QType::DS
) && signer
== qname
) {
2213 /* we are already retrieving those keys, sorry */
2214 if (qtype
== QType::DS
) {
2215 /* something is very wrong */
2216 LOG(d_prefix
<<"The DS for "<<qname
<<" is signed by itself, going Bogus"<<endl
);
2219 return Indeterminate
;
2221 vState state
= getDNSKeys(signer
, keys
, depth
);
2222 if (state
!= Secure
) {
2227 LOG(d_prefix
<<"Bogus!"<<endl
);
2231 std::vector
<std::shared_ptr
<DNSRecordContent
> > recordcontents
;
2232 for (const auto& record
: records
) {
2233 recordcontents
.push_back(record
.d_content
);
2236 LOG(d_prefix
<<"Going to validate "<<recordcontents
.size()<< " record contents with "<<signatures
.size()<<" sigs and "<<keys
.size()<<" keys for "<<name
<<endl
);
2237 if (validateWithKeySet(d_now
.tv_sec
, name
, recordcontents
, signatures
, keys
, false)) {
2238 LOG(d_prefix
<<"Secure!"<<endl
);
2242 LOG(d_prefix
<<"Bogus!"<<endl
);
2246 static bool allowAdditionalEntry(std::unordered_set
<DNSName
>& allowedAdditionals
, const DNSRecord
& rec
)
2248 switch(rec
.d_type
) {
2251 if (auto mxContent
= getRR
<MXRecordContent
>(rec
)) {
2252 allowedAdditionals
.insert(mxContent
->d_mxname
);
2258 if (auto nsContent
= getRR
<NSRecordContent
>(rec
)) {
2259 allowedAdditionals
.insert(nsContent
->getNS());
2265 if (auto srvContent
= getRR
<SRVRecordContent
>(rec
)) {
2266 allowedAdditionals
.insert(srvContent
->d_target
);
2275 void SyncRes::sanitizeRecords(const std::string
& prefix
, LWResult
& lwr
, const DNSName
& qname
, const QType
& qtype
, const DNSName
& auth
, bool wasForwarded
, bool rdQuery
)
2277 const bool wasForwardRecurse
= wasForwarded
&& rdQuery
;
2278 /* list of names for which we will allow A and AAAA records in the additional section
2280 std::unordered_set
<DNSName
> allowedAdditionals
= { qname
};
2281 bool haveAnswers
= false;
2282 bool isNXDomain
= false;
2283 bool isNXQType
= false;
2285 for(auto rec
= lwr
.d_records
.begin(); rec
!= lwr
.d_records
.end(); ) {
2287 if (rec
->d_type
== QType::OPT
) {
2292 if (rec
->d_class
!= QClass::IN
) {
2293 LOG(prefix
<<"Removing non internet-classed data received from "<<auth
<<endl
);
2294 rec
= lwr
.d_records
.erase(rec
);
2298 if (rec
->d_type
== QType::ANY
) {
2299 LOG(prefix
<<"Removing 'ANY'-typed data received from "<<auth
<<endl
);
2300 rec
= lwr
.d_records
.erase(rec
);
2304 if (!rec
->d_name
.isPartOf(auth
)) {
2305 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
);
2306 rec
= lwr
.d_records
.erase(rec
);
2310 /* dealing with the records in answer */
2311 if (!(lwr
.d_aabit
|| wasForwardRecurse
) && rec
->d_place
== DNSResourceRecord::ANSWER
) {
2312 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2313 are sending such responses */
2314 if (!(rec
->d_type
== QType::CNAME
&& qname
== rec
->d_name
)) {
2315 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
);
2316 rec
= lwr
.d_records
.erase(rec
);
2321 if (rec
->d_type
== QType::DNAME
&& (rec
->d_place
!= DNSResourceRecord::ANSWER
|| !qname
.isPartOf(rec
->d_name
))) {
2322 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
);
2323 rec
= lwr
.d_records
.erase(rec
);
2327 if (rec
->d_place
== DNSResourceRecord::ANSWER
&& (qtype
!= QType::ANY
&& rec
->d_type
!= qtype
.getCode() && s_redirectionQTypes
.count(rec
->d_type
) == 0 && rec
->d_type
!= QType::SOA
&& rec
->d_type
!= QType::RRSIG
)) {
2328 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
);
2329 rec
= lwr
.d_records
.erase(rec
);
2333 if (rec
->d_place
== DNSResourceRecord::ANSWER
&& !haveAnswers
) {
2337 if (rec
->d_place
== DNSResourceRecord::ANSWER
) {
2338 allowAdditionalEntry(allowedAdditionals
, *rec
);
2341 /* dealing with the records in authority */
2342 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
) {
2343 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
);
2344 rec
= lwr
.d_records
.erase(rec
);
2348 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::SOA
) {
2349 if (!qname
.isPartOf(rec
->d_name
)) {
2350 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
);
2351 rec
= lwr
.d_records
.erase(rec
);
2355 if (!(lwr
.d_aabit
|| wasForwardRecurse
)) {
2356 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
);
2357 rec
= lwr
.d_records
.erase(rec
);
2362 if (lwr
.d_rcode
== RCode::NXDomain
) {
2365 else if (lwr
.d_rcode
== RCode::NoError
) {
2371 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::NS
&& (isNXDomain
|| isNXQType
)) {
2372 /* we don't want to pick up NS records in AUTHORITY or ADDITIONAL sections of NXDomain answers
2373 because they are somewhat easy to insert into a large, fragmented UDP response
2374 for an off-path attacker by injecting spoofed UDP fragments.
2376 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
);
2377 rec
= lwr
.d_records
.erase(rec
);
2381 if (rec
->d_place
== DNSResourceRecord::AUTHORITY
&& rec
->d_type
== QType::NS
) {
2382 allowAdditionalEntry(allowedAdditionals
, *rec
);
2385 /* dealing with the records in additional */
2386 if (rec
->d_place
== DNSResourceRecord::ADDITIONAL
&& rec
->d_type
!= QType::A
&& rec
->d_type
!= QType::AAAA
&& rec
->d_type
!= QType::RRSIG
) {
2387 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
);
2388 rec
= lwr
.d_records
.erase(rec
);
2392 if (rec
->d_place
== DNSResourceRecord::ADDITIONAL
&& allowedAdditionals
.count(rec
->d_name
) == 0) {
2393 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
);
2394 rec
= lwr
.d_records
.erase(rec
);
2402 RCode::rcodes_
SyncRes::updateCacheFromRecords(unsigned int depth
, LWResult
& lwr
, const DNSName
& qname
, const QType
& qtype
, const DNSName
& auth
, bool wasForwarded
, const boost::optional
<Netmask
> ednsmask
, vState
& state
, bool& needWildcardProof
, bool& gatherWildcardProof
, unsigned int& wildcardLabelsCount
, bool rdQuery
)
2404 bool wasForwardRecurse
= wasForwarded
&& rdQuery
;
2410 prefix
.append(depth
, ' ');
2413 sanitizeRecords(prefix
, lwr
, qname
, qtype
, auth
, wasForwarded
, rdQuery
);
2415 std::vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
2416 const unsigned int labelCount
= qname
.countLabels();
2417 bool isCNAMEAnswer
= false;
2418 bool isDNAMEAnswer
= false;
2419 for(const auto& rec
: lwr
.d_records
) {
2420 if (rec
.d_class
!= QClass::IN
) {
2424 if(!isCNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
&& !isDNAMEAnswer
) {
2425 isCNAMEAnswer
= true;
2427 if(!isDNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::DNAME
&& qtype
!= QType(QType::DNAME
) && qname
.isPartOf(rec
.d_name
)) {
2428 isDNAMEAnswer
= true;
2429 isCNAMEAnswer
= false;
2432 /* if we have a positive answer synthetized from a wildcard,
2433 we need to store the corresponding NSEC/NSEC3 records proving
2434 that the exact name did not exist in the negative cache */
2435 if(gatherWildcardProof
) {
2436 if (nsecTypes
.count(rec
.d_type
)) {
2437 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
2439 else if (rec
.d_type
== QType::RRSIG
) {
2440 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
2441 if (rrsig
&& nsecTypes
.count(rrsig
->d_type
)) {
2442 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
2446 if(rec
.d_type
== QType::RRSIG
) {
2447 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
2449 /* As illustrated in rfc4035's Appendix B.6, the RRSIG label
2450 count can be lower than the name's label count if it was
2451 synthetized from the wildcard. Note that the difference might
2453 if (rec
.d_name
== qname
&& isWildcardExpanded(labelCount
, rrsig
)) {
2454 gatherWildcardProof
= true;
2455 if (!isWildcardExpandedOntoItself(rec
.d_name
, labelCount
, rrsig
)) {
2456 /* if we have a wildcard expanded onto itself, we don't need to prove
2457 that the exact name doesn't exist because it actually does.
2458 We still want to gather the corresponding NSEC/NSEC3 records
2459 to pass them to our client in case it wants to validate by itself.
2461 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthetized from a wildcard, we need a wildcard proof"<<endl
);
2462 needWildcardProof
= true;
2465 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthetized from a wildcard expanded onto itself, we need to gather wildcard proof"<<endl
);
2467 wildcardLabelsCount
= rrsig
->d_labels
;
2470 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
2471 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
2472 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
);
2477 // reap all answers from this packet that are acceptable
2478 for(auto& rec
: lwr
.d_records
) {
2479 if(rec
.d_type
== QType::OPT
) {
2480 LOG(prefix
<<qname
<<": OPT answer '"<<rec
.d_name
<<"' from '"<<auth
<<"' nameservers" <<endl
);
2483 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
<<" ");
2484 if(rec
.d_type
== QType::ANY
) {
2485 LOG("NO! - we don't accept 'ANY'-typed data"<<endl
);
2489 if(rec
.d_class
!= QClass::IN
) {
2490 LOG("NO! - we don't accept records for any other class than 'IN'"<<endl
);
2494 if (!(lwr
.d_aabit
|| wasForwardRecurse
) && rec
.d_place
== DNSResourceRecord::ANSWER
) {
2495 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2496 are sending such responses */
2497 if (!(rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
)) {
2498 LOG("NO! - we don't accept records in the answers section without the AA bit set"<<endl
);
2503 if(rec
.d_name
.isPartOf(auth
)) {
2504 if(rec
.d_type
== QType::RRSIG
) {
2505 LOG("RRSIG - separate"<<endl
);
2507 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
)) {
2508 LOG("NO! Is from delegation-only zone"<<endl
);
2510 return RCode::NXDomain
;
2513 bool haveLogged
= false;
2514 if (isDNAMEAnswer
&& rec
.d_type
== QType::CNAME
) {
2515 LOG("NO - we already have a DNAME answer for this domain");
2518 if (!t_sstorage
.domainmap
->empty()) {
2519 // Check if we are authoritative for a zone in this answer
2520 DNSName
tmp_qname(rec
.d_name
);
2521 auto auth_domain_iter
=getBestAuthZone(&tmp_qname
);
2522 if(auth_domain_iter
!=t_sstorage
.domainmap
->end() &&
2523 auth
.countLabels() <= auth_domain_iter
->first
.countLabels()) {
2524 if (auth_domain_iter
->first
!= auth
) {
2525 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter
->first
<<endl
);
2528 LOG("YES! - This answer was ");
2529 if (!wasForwarded
) {
2530 LOG("retrieved from the local auth store.");
2532 LOG("received from a server we forward to.");
2543 rec
.d_ttl
=min(s_maxcachettl
, rec
.d_ttl
);
2546 dr
.d_ttl
+= d_now
.tv_sec
;
2547 dr
.d_place
=DNSResourceRecord::ANSWER
;
2548 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(dr
);
2556 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2557 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)
2558 uint32_t lowestTTD
=computeLowestTTD(i
->second
.records
, i
->second
.signatures
, i
->second
.signaturesTTL
);
2560 for(auto& record
: i
->second
.records
)
2561 record
.d_ttl
= lowestTTD
; // boom
2564 // cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
2565 // cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
2568 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2570 if(i
->second
.records
.empty()) // this happens when we did store signatures, but passed on the records themselves
2573 /* Even if the AA bit is set, additional data cannot be considered
2574 as authoritative. This is especially important during validation
2575 because keeping records in the additional section is allowed even
2576 if the corresponding RRSIGs are not included, without setting the TC
2577 bit, as stated in rfc4035's section 3.1.1. Including RRSIG RRs in a Response:
2578 "When placing a signed RRset in the Additional section, the name
2579 server MUST also place its RRSIG RRs in the Additional section.
2580 If space does not permit inclusion of both the RRset and its
2581 associated RRSIG RRs, the name server MAY retain the RRset while
2582 dropping the RRSIG RRs. If this happens, the name server MUST NOT
2583 set the TC bit solely because these RRSIG RRs didn't fit."
2585 bool isAA
= lwr
.d_aabit
&& i
->first
.place
!= DNSResourceRecord::ADDITIONAL
;
2586 /* if we forwarded the query to a recursor, we can expect the answer to be signed,
2587 even if the answer is not AA. Of course that's not only true inside a Secure
2588 zone, but we check that below. */
2589 bool expectSignature
= i
->first
.place
== DNSResourceRecord::ANSWER
|| ((lwr
.d_aabit
|| wasForwardRecurse
) && i
->first
.place
!= DNSResourceRecord::ADDITIONAL
);
2590 if (isCNAMEAnswer
&& (i
->first
.place
!= DNSResourceRecord::ANSWER
|| i
->first
.type
!= QType::CNAME
|| i
->first
.name
!= qname
)) {
2593 Note that the answer section of an authoritative answer normally
2594 contains only authoritative data. However when the name sought is an
2595 alias (see section 10.1.1) only the record describing that alias is
2596 necessarily authoritative. Clients should assume that other records
2597 may have come from the server's cache. Where authoritative answers
2598 are required, the client should query again, using the canonical name
2599 associated with the alias.
2602 expectSignature
= false;
2605 if (isCNAMEAnswer
&& i
->first
.place
== DNSResourceRecord::AUTHORITY
&& i
->first
.type
== QType::NS
&& auth
== i
->first
.name
) {
2606 /* These NS can't be authoritative since we have a CNAME answer for which (see above) only the
2607 record describing that alias is necessarily authoritative.
2608 But if we allow the current auth, which might be serving the child zone, to raise the TTL
2609 of non-authoritative NS in the cache, they might be able to keep a "ghost" zone alive forever,
2610 even after the delegation is gone from the parent.
2611 So let's just do nothing with them, we can fetch them directly if we need them.
2613 LOG(d_prefix
<<": skipping authority NS from '"<<auth
<<"' nameservers in CNAME answer "<<i
->first
.name
<<"|"<<DNSRecordContent::NumberToType(i
->first
.type
)<<endl
);
2617 vState recordState
= getValidationStatus(i
->first
.name
, false);
2618 LOG(d_prefix
<<": got initial zone status "<<vStates
[recordState
]<<" for record "<<i
->first
.name
<<"|"<<DNSRecordContent::NumberToType(i
->first
.type
)<<endl
);
2620 if (shouldValidate() && recordState
== Secure
) {
2621 vState initialState
= recordState
;
2623 if (expectSignature
) {
2624 if (i
->first
.place
!= DNSResourceRecord::ADDITIONAL
) {
2625 /* the additional entries can be insecure,
2627 "Glue address RRsets associated with delegations MUST NOT be signed"
2629 if (i
->first
.type
== QType::DNSKEY
&& i
->first
.place
== DNSResourceRecord::ANSWER
) {
2630 LOG(d_prefix
<<"Validating DNSKEY for "<<i
->first
.name
<<endl
);
2631 recordState
= validateDNSKeys(i
->first
.name
, i
->second
.records
, i
->second
.signatures
, depth
);
2635 * RFC 6672 section 5.3.1
2636 * In any response, a signed DNAME RR indicates a non-terminal
2637 * redirection of the query. There might or might not be a server-
2638 * synthesized CNAME in the answer section; if there is, the CNAME will
2639 * never be signed. For a DNSSEC validator, verification of the DNAME
2640 * RR and then that the CNAME was properly synthesized is sufficient
2643 * We do the synthesis check in processRecords, here we make sure we
2644 * don't validate the CNAME.
2646 if (!(isDNAMEAnswer
&& i
->first
.type
== QType::CNAME
)) {
2647 LOG(d_prefix
<<"Validating non-additional record for "<<i
->first
.name
<<endl
);
2648 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2649 /* 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 */
2650 if (qtype
== QType::NS
&& i
->second
.signatures
.empty() && recordState
== Bogus
&& haveExactValidationStatus(i
->first
.name
) && getValidationStatus(i
->first
.name
) == Indeterminate
) {
2651 recordState
= Indeterminate
;
2658 recordState
= Indeterminate
;
2660 /* in a non authoritative answer, we only care about the DS record (or lack of) */
2661 if ((i
->first
.type
== QType::DS
|| i
->first
.type
== QType::NSEC
|| i
->first
.type
== QType::NSEC3
) && i
->first
.place
== DNSResourceRecord::AUTHORITY
) {
2662 LOG(d_prefix
<<"Validating DS record for "<<i
->first
.name
<<endl
);
2663 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2667 if (initialState
== Secure
&& state
!= recordState
&& expectSignature
) {
2668 updateValidationState(state
, recordState
);
2672 if (shouldValidate()) {
2673 LOG(d_prefix
<<"Skipping validation because the current state is "<<vStates
[recordState
]<<endl
);
2677 if (recordState
== Bogus
) {
2678 /* this is a TTD by now, be careful */
2679 for(auto& record
: i
->second
.records
) {
2680 record
.d_ttl
= std::min(record
.d_ttl
, static_cast<uint32_t>(s_maxbogusttl
+ d_now
.tv_sec
));
2684 /* We don't need to store NSEC3 records in the positive cache because:
2685 - we don't allow direct NSEC3 queries
2686 - denial of existence proofs in wildcard expanded positive responses are stored in authorityRecs
2687 - denial of existence proofs for negative responses are stored in the negative cache
2688 We also don't want to cache non-authoritative data except for:
2689 - records coming from non forward-recurse servers (those will never be AA)
2691 - NS, A and AAAA (used for infra queries)
2693 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
)) {
2695 bool doCache
= true;
2696 if (i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
) {
2697 // If ednsmask is relevant, we do not want to cache if the scope prefix length is large and TTL is small
2698 if (SyncRes::s_ecscachelimitttl
> 0) {
2699 bool manyMaskBits
= (ednsmask
->isIpv4() && ednsmask
->getBits() > SyncRes::s_ecsipv4cachelimit
) ||
2700 (ednsmask
->isIpv6() && ednsmask
->getBits() > SyncRes::s_ecsipv6cachelimit
);
2703 uint32_t minttl
= UINT32_MAX
;
2704 for (const auto &it
: i
->second
.records
) {
2705 if (it
.d_ttl
< minttl
)
2708 bool ttlIsSmall
= minttl
< SyncRes::s_ecscachelimitttl
+ d_now
.tv_sec
;
2710 // Case: many bits and ttlIsSmall
2717 t_RC
->replace(d_now
.tv_sec
, i
->first
.name
, QType(i
->first
.type
), i
->second
.records
, i
->second
.signatures
, authorityRecs
, i
->first
.type
== QType::DS
? true : isAA
, i
->first
.place
== DNSResourceRecord::ANSWER
? ednsmask
: boost::none
, recordState
);
2721 if(i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
)
2725 return RCode::NoError
;
2728 void SyncRes::updateDenialValidationState(vState
& neValidationState
, const DNSName
& neName
, vState
& state
, const dState denialState
, const dState expectedState
, bool allowOptOut
)
2730 if (denialState
== expectedState
) {
2731 neValidationState
= Secure
;
2734 if (denialState
== OPTOUT
&& allowOptOut
) {
2735 LOG(d_prefix
<<"OPT-out denial found for "<<neName
<<endl
);
2736 neValidationState
= Secure
;
2739 else if (denialState
== INSECURE
) {
2740 LOG(d_prefix
<<"Insecure denial found for "<<neName
<<", returning Insecure"<<endl
);
2741 neValidationState
= Insecure
;
2744 LOG(d_prefix
<<"Invalid denial found for "<<neName
<<", returning Bogus, res="<<denialState
<<", expectedState="<<expectedState
<<endl
);
2745 neValidationState
= Bogus
;
2747 updateValidationState(state
, neValidationState
);
2751 dState
SyncRes::getDenialValidationState(const NegCache::NegCacheEntry
& ne
, const vState state
, const dState expectedState
, bool referralToUnsigned
)
2753 cspmap_t csp
= harvestCSPFromNE(ne
);
2754 return getDenial(csp
, ne
.d_name
, ne
.d_qtype
.getCode(), referralToUnsigned
, expectedState
== NXQTYPE
);
2757 bool SyncRes::processRecords(const std::string
& prefix
, const DNSName
& qname
, const QType
& qtype
, const DNSName
& auth
, LWResult
& lwr
, const bool sendRDQuery
, vector
<DNSRecord
>& ret
, set
<DNSName
>& nsset
, DNSName
& newtarget
, DNSName
& newauth
, bool& realreferral
, bool& negindic
, vState
& state
, const bool needWildcardProof
, const bool gatherWildcardProof
, const unsigned int wildcardLabelsCount
)
2760 DNSName dnameTarget
, dnameOwner
;
2761 uint32_t dnameTTL
= 0;
2763 for(auto& rec
: lwr
.d_records
) {
2764 if (rec
.d_type
!=QType::OPT
&& rec
.d_class
!=QClass::IN
)
2767 if (rec
.d_place
==DNSResourceRecord::ANSWER
&& !(lwr
.d_aabit
|| sendRDQuery
)) {
2768 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2769 are sending such responses */
2770 if (!(rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
)) {
2775 if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2776 lwr
.d_rcode
==RCode::NXDomain
&& qname
.isPartOf(rec
.d_name
) && rec
.d_name
.isPartOf(auth
)) {
2777 LOG(prefix
<<qname
<<": got negative caching indication for name '"<<qname
<<"' (accept="<<rec
.d_name
.isPartOf(auth
)<<"), newtarget='"<<newtarget
<<"'"<<endl
);
2779 rec
.d_ttl
= min(rec
.d_ttl
, s_maxnegttl
);
2780 if(newtarget
.empty()) // only add a SOA if we're not going anywhere after this
2783 NegCache::NegCacheEntry ne
;
2785 uint32_t lowestTTL
= rec
.d_ttl
;
2786 /* if we get an NXDomain answer with a CNAME, the name
2787 does exist but the target does not */
2788 ne
.d_name
= newtarget
.empty() ? qname
: newtarget
;
2789 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2790 ne
.d_auth
= rec
.d_name
;
2791 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2793 if (state
== Secure
) {
2794 dState denialState
= getDenialValidationState(ne
, state
, NXDOMAIN
, false);
2795 updateDenialValidationState(ne
.d_validationState
, ne
.d_name
, state
, denialState
, NXDOMAIN
, false);
2798 ne
.d_validationState
= state
;
2801 if (ne
.d_validationState
== Bogus
) {
2802 lowestTTL
= min(lowestTTL
, s_maxbogusttl
);
2805 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2806 /* if we get an NXDomain answer with a CNAME, let's not cache the
2807 target, even the server was authoritative for it,
2808 and do an additional query for the CNAME target.
2809 We have a regression test making sure we do exactly that.
2811 if(!wasVariable() && newtarget
.empty()) {
2812 t_sstorage
.negcache
.add(ne
);
2813 if(s_rootNXTrust
&& ne
.d_auth
.isRoot() && auth
.isRoot() && lwr
.d_aabit
) {
2814 ne
.d_name
= ne
.d_name
.getLastLabel();
2815 t_sstorage
.negcache
.add(ne
);
2821 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& s_redirectionQTypes
.count(rec
.d_type
) > 0 && // CNAME or DNAME answer
2822 s_redirectionQTypes
.count(qtype
.getCode()) == 0) { // But not in response to a CNAME or DNAME query
2823 if (rec
.d_type
== QType::CNAME
&& rec
.d_name
== qname
) {
2824 if (!dnameOwner
.empty()) { // We synthesize ourselves
2828 if (auto content
= getRR
<CNAMERecordContent
>(rec
)) {
2829 newtarget
=content
->getTarget();
2831 } else if (rec
.d_type
== QType::DNAME
&& qname
.isPartOf(rec
.d_name
)) { // DNAME
2833 if (auto content
= getRR
<DNAMERecordContent
>(rec
)) {
2834 dnameOwner
= rec
.d_name
;
2835 dnameTarget
= content
->getTarget();
2836 dnameTTL
= rec
.d_ttl
;
2837 if (!newtarget
.empty()) { // We had a CNAME before, remove it from ret so we don't cache it
2838 ret
.erase(std::remove_if(
2841 [&qname
](DNSRecord
& rr
) {
2842 return (rr
.d_place
== DNSResourceRecord::ANSWER
&& rr
.d_type
== QType::CNAME
&& rr
.d_name
== qname
);
2847 newtarget
= qname
.makeRelative(dnameOwner
) + dnameTarget
;
2848 } catch (const std::exception
&e
) {
2849 // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
2850 // But there is no way to set the RCODE from this function
2851 throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + dnameOwner
.toLogString() +
2852 "', DNAME target: '" + dnameTarget
.toLogString() + "', substituted name: '" +
2853 qname
.makeRelative(dnameOwner
).toLogString() + "." + dnameTarget
.toLogString() +
2859 /* if we have a positive answer synthetized from a wildcard, we need to
2860 return the corresponding NSEC/NSEC3 records from the AUTHORITY section
2861 proving that the exact name did not exist */
2862 else if(gatherWildcardProof
&& (rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::AUTHORITY
) {
2863 ret
.push_back(rec
); // enjoy your DNSSEC
2865 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
2866 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&&
2868 rec
.d_type
==qtype
.getCode() || ((lwr
.d_aabit
|| sendRDQuery
) && qtype
== QType(QType::ANY
))
2872 LOG(prefix
<<qname
<<": answer is in: resolved to '"<< rec
.d_content
->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"'"<<endl
);
2876 if (state
== Secure
&& needWildcardProof
) {
2877 /* We have a positive answer synthetized from a wildcard, we need to check that we have
2878 proof that the exact name doesn't exist so the wildcard can be used,
2879 as described in section 5.3.4 of RFC 4035 and 5.3 of FRC 7129.
2881 NegCache::NegCacheEntry ne
;
2883 uint32_t lowestTTL
= rec
.d_ttl
;
2885 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2886 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2888 cspmap_t csp
= harvestCSPFromNE(ne
);
2889 dState res
= getDenial(csp
, qname
, ne
.d_qtype
.getCode(), false, false, false, wildcardLabelsCount
);
2890 if (res
!= NXDOMAIN
) {
2892 if (res
== INSECURE
) {
2893 /* Some part could not be validated, for example a NSEC3 record with a too large number of iterations,
2894 this is not enough to warrant a Bogus, but go Insecure. */
2896 LOG(d_prefix
<<"Unable to validate denial in wildcard expanded positive response found for "<<qname
<<", returning Insecure, res="<<res
<<endl
);
2899 LOG(d_prefix
<<"Invalid denial in wildcard expanded positive response found for "<<qname
<<", returning Bogus, res="<<res
<<endl
);
2900 rec
.d_ttl
= std::min(rec
.d_ttl
, s_maxbogusttl
);
2903 updateValidationState(state
, st
);
2904 /* we already stored the record with a different validation status, let's fix it */
2905 updateValidationStatusInCache(qname
, qtype
, lwr
.d_aabit
, st
);
2910 else if((rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::ANSWER
) {
2911 if(rec
.d_type
!= QType::RRSIG
|| rec
.d_name
== qname
) {
2912 ret
.push_back(rec
); // enjoy your DNSSEC
2913 } else if(rec
.d_type
== QType::RRSIG
&& qname
.isPartOf(rec
.d_name
)) {
2914 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
2915 if (rrsig
!= nullptr && rrsig
->d_type
== QType::DNAME
) {
2920 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::NS
&& qname
.isPartOf(rec
.d_name
)) {
2921 if(moreSpecificThan(rec
.d_name
,auth
)) {
2923 LOG(prefix
<<qname
<<": got NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2927 LOG(prefix
<<qname
<<": got upwards/level NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"', had '"<<auth
<<"'"<<endl
);
2929 if (auto content
= getRR
<NSRecordContent
>(rec
)) {
2930 nsset
.insert(content
->getNS());
2933 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::DS
&& qname
.isPartOf(rec
.d_name
)) {
2934 LOG(prefix
<<qname
<<": got DS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2936 else if(realreferral
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& (rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && newauth
.isPartOf(auth
)) {
2937 /* we might have received a denial of the DS, let's check */
2938 if (state
== Secure
) {
2939 NegCache::NegCacheEntry ne
;
2941 ne
.d_name
= newauth
;
2942 ne
.d_qtype
= QType::DS
;
2943 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2944 uint32_t lowestTTL
= rec
.d_ttl
;
2945 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2947 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, true);
2949 if (denialState
== NXQTYPE
|| denialState
== OPTOUT
|| denialState
== INSECURE
) {
2950 ne
.d_ttd
= lowestTTL
+ d_now
.tv_sec
;
2951 ne
.d_validationState
= Secure
;
2952 LOG(prefix
<<qname
<<": got negative indication of DS record for '"<<newauth
<<"'"<<endl
);
2954 if(!wasVariable()) {
2955 t_sstorage
.negcache
.add(ne
);
2958 if (qname
== newauth
&& qtype
== QType::DS
) {
2959 /* we are actually done! */
2966 else if(!done
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2967 lwr
.d_rcode
==RCode::NoError
&& qname
.isPartOf(rec
.d_name
)) {
2968 LOG(prefix
<<qname
<<": got negative caching indication for '"<< qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
2970 if(!newtarget
.empty()) {
2971 LOG(prefix
<<qname
<<": Hang on! Got a redirect to '"<<newtarget
<<"' already"<<endl
);
2974 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2976 NegCache::NegCacheEntry ne
;
2977 ne
.d_auth
= rec
.d_name
;
2978 uint32_t lowestTTL
= rec
.d_ttl
;
2981 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2983 if (state
== Secure
) {
2984 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, false);
2985 updateDenialValidationState(ne
.d_validationState
, ne
.d_name
, state
, denialState
, NXQTYPE
, qtype
== QType::DS
);
2987 ne
.d_validationState
= state
;
2990 if (ne
.d_validationState
== Bogus
) {
2991 lowestTTL
= min(lowestTTL
, s_maxbogusttl
);
2992 rec
.d_ttl
= min(rec
.d_ttl
, s_maxbogusttl
);
2994 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2996 if(!wasVariable()) {
2997 if(qtype
.getCode()) { // prevents us from blacking out a whole domain
2998 t_sstorage
.negcache
.add(ne
);
3008 if (!dnameTarget
.empty()) {
3009 // Synthesize a CNAME
3010 auto cnamerec
= DNSRecord();
3011 cnamerec
.d_name
= qname
;
3012 cnamerec
.d_type
= QType::CNAME
;
3013 cnamerec
.d_ttl
= dnameTTL
;
3014 cnamerec
.d_content
= std::make_shared
<CNAMERecordContent
>(CNAMERecordContent(newtarget
));
3015 ret
.push_back(cnamerec
);
3020 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
)
3022 bool chained
= false;
3023 int resolveret
= RCode::NoError
;
3027 if(d_outqueries
+ d_throttledqueries
> s_maxqperq
) {
3028 throw ImmediateServFailException("more than "+std::to_string(s_maxqperq
)+" (max-qperq) queries sent while resolving "+qname
.toLogString());
3031 if(s_maxtotusec
&& d_totUsec
> s_maxtotusec
) {
3032 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");
3036 LOG(prefix
<<qname
<<": using TCP with "<< remoteIP
.toStringWithPort() <<endl
);
3041 if(d_pdl
&& d_pdl
->preoutquery(remoteIP
, d_requestor
, qname
, qtype
, doTCP
, lwr
.d_records
, resolveret
)) {
3042 LOG(prefix
<<qname
<<": query handled by Lua"<<endl
);
3045 ednsmask
=getEDNSSubnetMask(qname
, remoteIP
);
3047 LOG(prefix
<<qname
<<": Adding EDNS Client Subnet Mask "<<ednsmask
->toString()<<" to query"<<endl
);
3050 resolveret
= asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, auth
, qtype
.getCode(),
3051 doTCP
, sendRDQuery
, &d_now
, ednsmask
, &lwr
, &chained
); // <- we go out on the wire!
3054 LOG(prefix
<<qname
<<": Received EDNS Client Subnet Mask "<<ednsmask
->toString()<<" on response"<<endl
);
3055 if (ednsmask
->getBits() > 0) {
3056 if (ednsmask
->isIpv4()) {
3057 ++SyncRes::s_ecsResponsesBySubnetSize4
.at(ednsmask
->getBits()-1);
3060 ++SyncRes::s_ecsResponsesBySubnetSize6
.at(ednsmask
->getBits()-1);
3066 /* preoutquery killed the query by setting dq.rcode to -3 */
3067 if(resolveret
==-3) {
3068 throw ImmediateServFailException("Query killed by policy");
3071 d_totUsec
+= lwr
.d_usec
;
3072 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
3074 bool dontThrottle
= false;
3076 auto dontThrottleNames
= g_dontThrottleNames
.getLocal();
3077 auto dontThrottleNetmasks
= g_dontThrottleNetmasks
.getLocal();
3078 dontThrottle
= dontThrottleNames
->check(nsName
) || dontThrottleNetmasks
->match(remoteIP
);
3081 if(resolveret
!= 1) {
3082 /* Error while resolving */
3083 if(resolveret
== 0) {
3086 LOG(prefix
<<qname
<<": timeout resolving after "<<lwr
.d_usec
/1000.0<<"msec "<< (doTCP
? "over TCP" : "")<<endl
);
3088 s_outgoingtimeouts
++;
3090 if(remoteIP
.sin4
.sin_family
== AF_INET
)
3091 s_outgoing4timeouts
++;
3093 s_outgoing6timeouts
++;
3096 t_timeouts
->push_back(remoteIP
);
3098 else if(resolveret
== -2) {
3099 /* OS resource limit reached */
3100 LOG(prefix
<<qname
<<": hit a local resource limit resolving"<< (doTCP
? " over TCP" : "")<<", probable error: "<<stringerror()<<endl
);
3101 g_stats
.resourceLimits
++;
3104 /* -1 means server unreachable */
3107 LOG(prefix
<<qname
<<": error resolving from "<<remoteIP
.toString()<< (doTCP
? " over TCP" : "") <<", possible error: "<<strerror(errno
)<< endl
);
3110 if(resolveret
!= -2 && !chained
&& !dontThrottle
) {
3111 // don't account for resource limits, they are our own fault
3112 // And don't throttle when the IP address is on the dontThrottleNetmasks list or the name is part of dontThrottleNames
3113 t_sstorage
.nsSpeeds
[nsName
.empty()? DNSName(remoteIP
.toStringWithPort()) : nsName
].submit(remoteIP
, 1000000, &d_now
); // 1 sec
3115 // code below makes sure we don't filter COM or the root
3116 if (s_serverdownmaxfails
> 0 && (auth
!= g_rootdnsname
) && t_sstorage
.fails
.incr(remoteIP
) >= s_serverdownmaxfails
) {
3117 LOG(prefix
<<qname
<<": Max fails reached resolving on "<< remoteIP
.toString() <<". Going full throttle for "<< s_serverdownthrottletime
<<" seconds" <<endl
);
3118 // mark server as down
3119 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0), s_serverdownthrottletime
, 10000);
3121 else if (resolveret
== -1) {
3122 // unreachable, 1 minute or 100 queries
3123 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 100);
3126 // timeout, 10 seconds or 5 queries
3127 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 10, 5);
3134 /* we got an answer */
3135 if(lwr
.d_rcode
==RCode::ServFail
|| lwr
.d_rcode
==RCode::Refused
) {
3136 LOG(prefix
<<qname
<<": "<<nsName
<<" ("<<remoteIP
.toString()<<") returned a "<< (lwr
.d_rcode
==RCode::ServFail
? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl
);
3137 if (!chained
&& !dontThrottle
) {
3138 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
3143 /* this server sent a valid answer, mark it backup up if it was down */
3144 if(s_serverdownmaxfails
> 0) {
3145 t_sstorage
.fails
.clear(remoteIP
);
3152 LOG(prefix
<<qname
<<": truncated bit set, over TCP?"<<endl
);
3153 if (!dontThrottle
) {
3154 /* let's treat that as a ServFail answer from this server */
3155 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
3159 LOG(prefix
<<qname
<<": truncated bit set, over UDP"<<endl
);
3167 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
)
3172 prefix
.append(depth
, ' ');
3176 for(auto& rec
: lwr
.d_records
) {
3177 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumTTL
);
3181 /* if the answer is ECS-specific, a minimum TTL is set for this kind of answers
3182 and it's higher than the global minimum TTL */
3183 if (ednsmask
&& s_minimumECSTTL
> 0 && (s_minimumTTL
== 0 || s_minimumECSTTL
> s_minimumTTL
)) {
3184 for(auto& rec
: lwr
.d_records
) {
3185 if (rec
.d_place
== DNSResourceRecord::ANSWER
) {
3186 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumECSTTL
);
3191 bool needWildcardProof
= false;
3192 bool gatherWildcardProof
= false;
3193 unsigned int wildcardLabelsCount
;
3194 *rcode
= updateCacheFromRecords(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, state
, needWildcardProof
, gatherWildcardProof
, wildcardLabelsCount
, sendRDQuery
);
3195 if (*rcode
!= RCode::NoError
) {
3199 LOG(prefix
<<qname
<<": determining status after receiving this packet"<<endl
);
3202 bool realreferral
=false, negindic
=false;
3206 bool done
= processRecords(prefix
, qname
, qtype
, auth
, lwr
, sendRDQuery
, ret
, nsset
, newtarget
, newauth
, realreferral
, negindic
, state
, needWildcardProof
, gatherWildcardProof
, wildcardLabelsCount
);
3209 LOG(prefix
<<qname
<<": status=got results, this level of recursion done"<<endl
);
3210 LOG(prefix
<<qname
<<": validation status is "<<vStates
[state
]<<endl
);
3211 *rcode
= RCode::NoError
;
3215 if(!newtarget
.empty()) {
3216 if(newtarget
== qname
) {
3217 LOG(prefix
<<qname
<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl
);
3218 *rcode
= RCode::ServFail
;
3223 LOG(prefix
<<qname
<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl
);
3224 *rcode
= RCode::ServFail
;
3228 if (qtype
== QType::DS
) {
3229 LOG(prefix
<<qname
<<": status=got a CNAME referral, but we are looking for a DS"<<endl
);
3232 addNXNSECS(ret
, lwr
.d_records
);
3234 *rcode
= RCode::NoError
;
3238 LOG(prefix
<<qname
<<": status=got a CNAME referral, starting over with "<<newtarget
<<endl
);
3240 set
<GetBestNSAnswer
> beenthere2
;
3241 vState cnameState
= Indeterminate
;
3242 *rcode
= doResolve(newtarget
, qtype
, ret
, depth
+ 1, beenthere2
, cnameState
);
3243 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
3244 updateValidationState(state
, cnameState
);
3249 if(lwr
.d_rcode
== RCode::NXDomain
) {
3250 LOG(prefix
<<qname
<<": status=NXDOMAIN, we are done "<<(negindic
? "(have negative SOA)" : "")<<endl
);
3253 addNXNSECS(ret
, lwr
.d_records
);
3255 *rcode
= RCode::NXDomain
;
3259 if(nsset
.empty() && !lwr
.d_rcode
&& (negindic
|| lwr
.d_aabit
|| sendRDQuery
)) {
3260 LOG(prefix
<<qname
<<": status=noerror, other types may exist, but we are done "<<(negindic
? "(have negative SOA) " : "")<<(lwr
.d_aabit
? "(have aa bit) " : "")<<endl
);
3262 if(state
== Secure
&& (lwr
.d_aabit
|| sendRDQuery
) && !negindic
) {
3263 updateValidationState(state
, Bogus
);
3267 addNXNSECS(ret
, lwr
.d_records
);
3269 *rcode
= RCode::NoError
;
3274 LOG(prefix
<<qname
<<": status=did not resolve, got "<<(unsigned int)nsset
.size()<<" NS, ");
3276 nameservers
.clear();
3277 for (auto const &nameserver
: nsset
) {
3279 d_appliedPolicy
= dfe
.getProcessingPolicy(nameserver
, d_discardedPolicies
);
3280 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
3281 LOG("however "<<nameserver
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
3286 nameservers
.insert({nameserver
, {{}, false}});
3288 LOG("looping to them"<<endl
);
3289 *gotNewServers
= true;
3299 * -1 in case of no results
3300 * -2 when a FilterEngine Policy was hit
3303 int SyncRes::doResolveAt(NsSet
&nameservers
, DNSName auth
, bool flawedNSSet
, const DNSName
&qname
, const QType
&qtype
,
3304 vector
<DNSRecord
>&ret
,
3305 unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
, vState
& state
, StopAtDelegation
* stopAtDelegation
)
3307 auto luaconfsLocal
= g_luaconfs
.getLocal();
3311 prefix
.append(depth
, ' ');
3314 LOG(prefix
<<qname
<<": Cache consultations done, have "<<(unsigned int)nameservers
.size()<<" NS to contact");
3316 if (nameserversBlockedByRPZ(luaconfsLocal
->dfe
, nameservers
)) {
3322 for(;;) { // we may get more specific nameservers
3323 auto rnameservers
= shuffleInSpeedOrder(nameservers
, doLog() ? (prefix
+qname
.toString()+": ") : string() );
3325 for(auto tns
=rnameservers
.cbegin();;++tns
) {
3326 if(tns
==rnameservers
.cend()) {
3327 LOG(prefix
<<qname
<<": Failed to resolve via any of the "<<(unsigned int)rnameservers
.size()<<" offered NS at level '"<<auth
<<"'"<<endl
);
3328 if(!auth
.isRoot() && flawedNSSet
) {
3329 LOG(prefix
<<qname
<<": Ageing nameservers for level '"<<auth
<<"', next query might succeed"<<endl
);
3331 if(t_RC
->doAgeCache(d_now
.tv_sec
, auth
, QType::NS
, 10))
3332 g_stats
.nsSetInvalidations
++;
3337 bool cacheOnly
= false;
3338 // this line needs to identify the 'self-resolving' behaviour
3339 if(qname
== tns
->first
&& (qtype
.getCode() == QType::A
|| qtype
.getCode() == QType::AAAA
)) {
3340 /* we might have a glue entry in cache so let's try this NS
3341 but only if we have enough in the cache to know how to reach it */
3342 LOG(prefix
<<qname
<<": Using NS to resolve itself, but only using what we have in cache ("<<(1+tns
-rnameservers
.cbegin())<<"/"<<rnameservers
.size()<<")"<<endl
);
3346 typedef vector
<ComboAddress
> remoteIPs_t
;
3347 remoteIPs_t remoteIPs
;
3348 remoteIPs_t::const_iterator remoteIP
;
3349 bool pierceDontQuery
=false;
3350 bool sendRDQuery
=false;
3351 boost::optional
<Netmask
> ednsmask
;
3353 const bool wasForwarded
= tns
->first
.empty() && (!nameservers
[tns
->first
].first
.empty());
3354 int rcode
= RCode::NoError
;
3355 bool gotNewServers
= false;
3357 if(tns
->first
.empty() && !wasForwarded
) {
3358 LOG(prefix
<<qname
<<": Domain is out-of-band"<<endl
);
3359 /* setting state to indeterminate since validation is disabled for local auth zone,
3360 and Insecure would be misleading. */
3361 state
= Indeterminate
;
3362 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, lwr
.d_records
, depth
, lwr
.d_rcode
);
3366 /* we have received an answer, are we done ? */
3367 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, false, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
3371 if (gotNewServers
) {
3372 if (stopAtDelegation
&& *stopAtDelegation
== Stop
) {
3373 *stopAtDelegation
= Stopped
;
3380 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
3381 remoteIPs
= retrieveAddressesForNS(prefix
, qname
, tns
, depth
, beenthere
, rnameservers
, nameservers
, sendRDQuery
, pierceDontQuery
, flawedNSSet
, cacheOnly
);
3383 if(remoteIPs
.empty()) {
3384 LOG(prefix
<<qname
<<": Failed to get IP for NS "<<tns
->first
<<", trying next if available"<<endl
);
3389 bool hitPolicy
{false};
3390 LOG(prefix
<<qname
<<": Resolved '"<<auth
<<"' NS "<<tns
->first
<<" to: ");
3391 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
3392 if(remoteIP
!= remoteIPs
.cbegin()) {
3395 LOG(remoteIP
->toString());
3396 if(nameserverIPBlockedByRPZ(luaconfsLocal
->dfe
, *remoteIP
)) {
3401 if (hitPolicy
) //implies d_wantsRPZ
3405 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
3406 LOG(prefix
<<qname
<<": Trying IP "<< remoteIP
->toStringWithPort() <<", asking '"<<qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
3408 if (throttledOrBlocked(prefix
, *remoteIP
, qname
, qtype
, pierceDontQuery
)) {
3412 bool truncated
= false;
3413 bool gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
3414 tns
->first
, *remoteIP
, false, &truncated
);
3415 if (gotAnswer
&& truncated
) {
3416 /* retry, over TCP this time */
3417 gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
3418 tns
->first
, *remoteIP
, true, &truncated
);
3425 LOG(prefix
<<qname
<<": Got "<<(unsigned int)lwr
.d_records
.size()<<" answers from "<<tns
->first
<<" ("<< remoteIP
->toString() <<"), rcode="<<lwr
.d_rcode
<<" ("<<RCode::to_s(lwr
.d_rcode
)<<"), aa="<<lwr
.d_aabit
<<", in "<<lwr
.d_usec
/1000<<"ms"<<endl
);
3427 /* // for you IPv6 fanatics :-)
3428 if(remoteIP->sin4.sin_family==AF_INET6)
3431 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
3433 t_sstorage
.nsSpeeds
[tns
->first
.empty()? DNSName(remoteIP
->toStringWithPort()) : tns
->first
].submit(*remoteIP
, lwr
.d_usec
, &d_now
);
3435 /* we have received an answer, are we done ? */
3436 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
3440 if (gotNewServers
) {
3441 if (stopAtDelegation
&& *stopAtDelegation
== Stop
) {
3442 *stopAtDelegation
= Stopped
;
3448 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100);
3451 if (gotNewServers
) {
3455 if(remoteIP
== remoteIPs
.cend()) // we tried all IP addresses, none worked
3464 void SyncRes::setQuerySource(const ComboAddress
& requestor
, boost::optional
<const EDNSSubnetOpts
&> incomingECS
)
3466 d_requestor
= requestor
;
3468 if (incomingECS
&& incomingECS
->source
.getBits() > 0) {
3469 d_cacheRemote
= incomingECS
->source
.getMaskedNetwork();
3470 uint8_t bits
= std::min(incomingECS
->source
.getBits(), (incomingECS
->source
.isIpv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
3471 ComboAddress trunc
= incomingECS
->source
.getNetwork();
3472 trunc
.truncate(bits
);
3473 d_outgoingECSNetwork
= boost::optional
<Netmask
>(Netmask(trunc
, bits
));
3475 d_cacheRemote
= d_requestor
;
3476 if(!incomingECS
&& s_ednslocalsubnets
.match(d_requestor
)) {
3477 ComboAddress trunc
= d_requestor
;
3478 uint8_t bits
= d_requestor
.isIPv4() ? 32 : 128;
3479 bits
= std::min(bits
, (trunc
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
3480 trunc
.truncate(bits
);
3481 d_outgoingECSNetwork
= boost::optional
<Netmask
>(Netmask(trunc
, bits
));
3482 } else if (s_ecsScopeZero
.source
.getBits() > 0) {
3483 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0.
3484 But using an empty ECS in that case would mean inserting
3485 a non ECS-specific entry into the cache, preventing any further
3486 ECS-specific query to be sent.
3487 So instead we use the trick described in section 7.1.2:
3488 "The subsequent Recursive Resolver query to the Authoritative Nameserver
3489 will then either not include an ECS option or MAY optionally include
3490 its own address information, which is what the Authoritative
3491 Nameserver will almost certainly use to generate any Tailored
3492 Response in lieu of an option. This allows the answer to be handled
3493 by the same caching mechanism as other queries, with an explicit
3494 indicator of the applicable scope. Subsequent Stub Resolver queries
3495 for /0 can then be answered from this cached response.
3497 d_outgoingECSNetwork
= boost::optional
<Netmask
>(s_ecsScopeZero
.source
.getMaskedNetwork());
3498 d_cacheRemote
= s_ecsScopeZero
.source
.getNetwork();
3500 // ECS disabled because no scope-zero address could be derived.
3501 d_outgoingECSNetwork
= boost::none
;
3506 boost::optional
<Netmask
> SyncRes::getEDNSSubnetMask(const DNSName
& dn
, const ComboAddress
& rem
)
3508 if(d_outgoingECSNetwork
&& (s_ednsdomains
.check(dn
) || s_ednsremotesubnets
.match(rem
))) {
3509 return d_outgoingECSNetwork
;
3514 void SyncRes::parseEDNSSubnetWhitelist(const std::string
& wlist
)
3516 vector
<string
> parts
;
3517 stringtok(parts
, wlist
, ",; ");
3518 for(const auto& a
: parts
) {
3520 s_ednsremotesubnets
.addMask(Netmask(a
));
3523 s_ednsdomains
.add(DNSName(a
));
3528 void SyncRes::parseEDNSSubnetAddFor(const std::string
& subnetlist
)
3530 vector
<string
> parts
;
3531 stringtok(parts
, subnetlist
, ",; ");
3532 for(const auto& a
: parts
) {
3533 s_ednslocalsubnets
.addMask(a
);
3537 // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
3538 int directResolve(const DNSName
& qname
, const QType
& qtype
, int qclass
, vector
<DNSRecord
>& ret
)
3541 gettimeofday(&now
, 0);
3546 res
= sr
.beginResolve(qname
, QType(qtype
), qclass
, ret
);
3548 catch(const PDNSException
& e
) {
3549 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got pdns exception: "<<e
.reason
<<endl
;
3552 catch(const ImmediateServFailException
& e
) {
3553 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got ImmediateServFailException: "<<e
.reason
<<endl
;
3556 catch(const std::exception
& e
) {
3557 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got STL error: "<<e
.what()<<endl
;
3561 g_log
<<Logger::Error
<<"Failed to resolve "<<qname
.toLogString()<<", got an exception"<<endl
;
3568 int SyncRes::getRootNS(struct timeval now
, asyncresolve_t asyncCallback
) {
3570 sr
.setDoEDNS0(true);
3571 sr
.setUpdatingRootNS();
3572 sr
.setDoDNSSEC(g_dnssecmode
!= DNSSECMode::Off
);
3573 sr
.setDNSSECValidationRequested(g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
);
3574 sr
.setAsyncCallback(asyncCallback
);
3576 vector
<DNSRecord
> ret
;
3579 res
=sr
.beginResolve(g_rootdnsname
, QType(QType::NS
), 1, ret
);
3580 if (g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
) {
3581 auto state
= sr
.getValidationState();
3583 throw PDNSException("Got Bogus validation result for .|NS");
3587 catch(const PDNSException
& e
) {
3588 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
3590 catch(const ImmediateServFailException
& e
) {
3591 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
3593 catch(const std::exception
& e
) {
3594 g_log
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.what()<<endl
;
3597 g_log
<<Logger::Error
<<"Failed to update . records, got an exception"<<endl
;
3601 g_log
<<Logger::Notice
<<"Refreshed . records"<<endl
;
3604 g_log
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;