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
;
41 std::unordered_set
<DNSName
> SyncRes::s_delegationOnly
;
42 std::unique_ptr
<NetmaskGroup
> SyncRes::s_dontQuery
{nullptr};
43 NetmaskGroup
SyncRes::s_ednssubnets
;
44 SuffixMatchNode
SyncRes::s_ednsdomains
;
45 EDNSSubnetOpts
SyncRes::s_ecsScopeZero
;
46 string
SyncRes::s_serverID
;
47 SyncRes::LogMode
SyncRes::s_lm
;
49 unsigned int SyncRes::s_maxnegttl
;
50 unsigned int SyncRes::s_maxcachettl
;
51 unsigned int SyncRes::s_maxqperq
;
52 unsigned int SyncRes::s_maxtotusec
;
53 unsigned int SyncRes::s_maxdepth
;
54 unsigned int SyncRes::s_minimumTTL
;
55 unsigned int SyncRes::s_packetcachettl
;
56 unsigned int SyncRes::s_packetcacheservfailttl
;
57 unsigned int SyncRes::s_serverdownmaxfails
;
58 unsigned int SyncRes::s_serverdownthrottletime
;
59 std::atomic
<uint64_t> SyncRes::s_queries
;
60 std::atomic
<uint64_t> SyncRes::s_outgoingtimeouts
;
61 std::atomic
<uint64_t> SyncRes::s_outgoing4timeouts
;
62 std::atomic
<uint64_t> SyncRes::s_outgoing6timeouts
;
63 std::atomic
<uint64_t> SyncRes::s_outqueries
;
64 std::atomic
<uint64_t> SyncRes::s_tcpoutqueries
;
65 std::atomic
<uint64_t> SyncRes::s_throttledqueries
;
66 std::atomic
<uint64_t> SyncRes::s_dontqueries
;
67 std::atomic
<uint64_t> SyncRes::s_nodelegated
;
68 std::atomic
<uint64_t> SyncRes::s_unreachables
;
69 std::atomic
<uint64_t> SyncRes::s_ecsqueries
;
70 std::atomic
<uint64_t> SyncRes::s_ecsresponses
;
71 uint8_t SyncRes::s_ecsipv4limit
;
72 uint8_t SyncRes::s_ecsipv6limit
;
73 bool SyncRes::s_doIPv6
;
74 bool SyncRes::s_nopacketcache
;
75 bool SyncRes::s_rootNXTrust
;
76 bool SyncRes::s_noEDNS
;
78 #define LOG(x) if(d_lm == Log) { L <<Logger::Warning << x; } else if(d_lm == Store) { d_trace << x; }
80 static void accountAuthLatency(int usec
, int family
)
82 if(family
== AF_INET
) {
84 g_stats
.auth4Answers0_1
++;
86 g_stats
.auth4Answers1_10
++;
87 else if(usec
< 100000)
88 g_stats
.auth4Answers10_100
++;
89 else if(usec
< 1000000)
90 g_stats
.auth4Answers100_1000
++;
92 g_stats
.auth4AnswersSlow
++;
95 g_stats
.auth6Answers0_1
++;
97 g_stats
.auth6Answers1_10
++;
98 else if(usec
< 100000)
99 g_stats
.auth6Answers10_100
++;
100 else if(usec
< 1000000)
101 g_stats
.auth6Answers100_1000
++;
103 g_stats
.auth6AnswersSlow
++;
109 SyncRes::SyncRes(const struct timeval
& now
) : d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
110 d_totUsec(0), d_now(now
),
111 d_cacheonly(false), d_doDNSSEC(false), d_doEDNS0(false), d_lm(s_lm
)
116 /** everything begins here - this is the entry point just after receiving a packet */
117 int SyncRes::beginResolve(const DNSName
&qname
, const QType
&qtype
, uint16_t qclass
, vector
<DNSRecord
>&ret
)
119 vState state
= Indeterminate
;
122 d_wasOutOfBand
=false;
124 if (doSpecialNamesResolve(qname
, qtype
, qclass
, ret
)) {
125 d_queryValidationState
= Insecure
;
129 if( (qtype
.getCode() == QType::AXFR
) || (qtype
.getCode() == QType::IXFR
) || (qtype
.getCode() == QType::RRSIG
) || (qtype
.getCode() == QType::NSEC3
))
132 if(qclass
==QClass::ANY
)
134 else if(qclass
!=QClass::IN
)
137 set
<GetBestNSAnswer
> beenthere
;
138 int res
=doResolve(qname
, qtype
, ret
, 0, beenthere
, state
);
139 d_queryValidationState
= state
;
141 if (d_queryValidationState
!= Indeterminate
) {
142 g_stats
.dnssecValidations
++;
144 if (shouldValidate()) {
145 increaseDNSSECStateCounter(d_queryValidationState
);
151 /*! Handles all special, built-in names
152 * Fills ret with an answer and returns true if it handled the query.
154 * Handles the following queries (and their ANY variants):
157 * - localhost. IN AAAA
158 * - 1.0.0.127.in-addr.arpa. IN PTR
159 * - 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
160 * - version.bind. CH TXT
161 * - version.pdns. CH TXT
162 * - id.server. CH TXT
164 bool SyncRes::doSpecialNamesResolve(const DNSName
&qname
, const QType
&qtype
, const uint16_t qclass
, vector
<DNSRecord
> &ret
)
166 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."),
167 localhost("localhost."), versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns.");
169 bool handled
= false;
170 vector
<pair
<QType::typeenum
, string
> > answers
;
172 if ((qname
== arpa
|| qname
== ip6_arpa
) &&
173 qclass
== QClass::IN
) {
175 if (qtype
== QType::PTR
|| qtype
== QType::ANY
)
176 answers
.push_back({QType::PTR
, "localhost."});
179 if (qname
== localhost
&&
180 qclass
== QClass::IN
) {
182 if (qtype
== QType::A
|| qtype
== QType::ANY
)
183 answers
.push_back({QType::A
, "127.0.0.1"});
184 if (qtype
== QType::AAAA
|| qtype
== QType::ANY
)
185 answers
.push_back({QType::AAAA
, "::1"});
188 if ((qname
== versionbind
|| qname
== idserver
|| qname
== versionpdns
) &&
189 qclass
== QClass::CHAOS
) {
191 if (qtype
== QType::TXT
|| qtype
== QType::ANY
) {
192 if(qname
== versionbind
|| qname
== versionpdns
)
193 answers
.push_back({QType::TXT
, "\""+::arg()["version-string"]+"\""});
195 answers
.push_back({QType::TXT
, "\""+s_serverID
+"\""});
199 if (handled
&& !answers
.empty()) {
205 dr
.d_place
= DNSResourceRecord::ANSWER
;
208 for (const auto& ans
: answers
) {
209 dr
.d_type
= ans
.first
;
210 dr
.d_content
= DNSRecordContent::mastermake(ans
.first
, qclass
, ans
.second
);
219 //! This is the 'out of band resolver', in other words, the authoritative server
220 void SyncRes::AuthDomain::addSOA(std::vector
<DNSRecord
>& records
) const
222 SyncRes::AuthDomain::records_t::const_iterator ziter
= d_records
.find(boost::make_tuple(getName(), QType::SOA
));
223 if (ziter
!= d_records
.end()) {
224 DNSRecord dr
= *ziter
;
225 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
226 records
.push_back(dr
);
229 // cerr<<qname<<": can't find SOA record '"<<getName()<<"' in our zone!"<<endl;
233 int SyncRes::AuthDomain::getRecords(const DNSName
& qname
, uint16_t qtype
, std::vector
<DNSRecord
>& records
) const
235 int result
= RCode::NoError
;
239 std::pair
<records_t::const_iterator
,records_t::const_iterator
> range
= d_records
.equal_range(tie(qname
));
241 SyncRes::AuthDomain::records_t::const_iterator ziter
;
242 bool somedata
= false;
244 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
247 if(qtype
== QType::ANY
|| ziter
->d_type
== qtype
|| ziter
->d_type
== QType::CNAME
) {
248 // let rest of nameserver do the legwork on this one
249 records
.push_back(*ziter
);
251 else if (ziter
->d_type
== QType::NS
&& ziter
->d_name
.countLabels() > getName().countLabels()) {
252 // we hit a delegation point!
253 DNSRecord dr
= *ziter
;
254 dr
.d_place
=DNSResourceRecord::AUTHORITY
;
255 records
.push_back(dr
);
259 if (!records
.empty()) {
260 /* We have found an exact match, we're done */
261 // cerr<<qname<<": exact match in zone '"<<getName()<<"'"<<endl;
266 /* We have records for that name, but not of the wanted qtype */
267 // cerr<<qname<<": found record in '"<<getName()<<"', but nothing of the right type, sending SOA"<<endl;
273 // cerr<<qname<<": nothing found so far in '"<<getName()<<"', trying wildcards"<<endl;
274 DNSName
wcarddomain(qname
);
275 while(wcarddomain
!= getName() && wcarddomain
.chopOff()) {
276 // cerr<<qname<<": trying '*."<<wcarddomain<<"' in "<<getName()<<endl;
277 range
= d_records
.equal_range(boost::make_tuple(g_wildcarddnsname
+ wcarddomain
));
278 if (range
.first
==range
.second
)
281 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
282 DNSRecord dr
= *ziter
;
283 // if we hit a CNAME, just answer that - rest of recursor will do the needful & follow
284 if(dr
.d_type
== qtype
|| qtype
== QType::ANY
|| dr
.d_type
== QType::CNAME
) {
286 dr
.d_place
= DNSResourceRecord::ANSWER
;
287 records
.push_back(dr
);
291 if (records
.empty()) {
295 // cerr<<qname<<": in '"<<getName()<<"', had wildcard match on '*."<<wcarddomain<<"'"<<endl;
299 /* Nothing for this name, no wildcard, let's see if there is some NS */
300 DNSName
nsdomain(qname
);
301 while (nsdomain
.chopOff() && nsdomain
!= getName()) {
302 range
= d_records
.equal_range(boost::make_tuple(nsdomain
,QType::NS
));
303 if(range
.first
== range
.second
)
306 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
307 DNSRecord dr
= *ziter
;
308 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
309 records
.push_back(dr
);
313 if(records
.empty()) {
314 // cerr<<qname<<": no NS match in zone '"<<getName()<<"' either, handing out SOA"<<endl;
316 result
= RCode::NXDomain
;
322 bool SyncRes::doOOBResolve(const AuthDomain
& domain
, const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, int& res
) const
324 res
= domain
.getRecords(qname
, qtype
.getCode(), ret
);
328 bool SyncRes::doOOBResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int& res
)
333 prefix
.append(depth
, ' ');
336 DNSName
authdomain(qname
);
337 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
338 if(iter
==t_sstorage
.domainmap
->end() || !iter
->second
.isAuth()) {
339 LOG(prefix
<<qname
<<": auth storage has no zone for this query!"<<endl
);
343 LOG(prefix
<<qname
<<": auth storage has data, zone='"<<authdomain
<<"'"<<endl
);
344 return doOOBResolve(iter
->second
, qname
, qtype
, ret
, res
);
347 void SyncRes::doEDNSDumpAndClose(int fd
)
349 FILE* fp
=fdopen(fd
, "w");
353 fprintf(fp
,"IP Address\tMode\tMode last updated at\n");
354 for(const auto& eds
: t_sstorage
.ednsstatus
) {
355 fprintf(fp
, "%s\t%d\t%s", eds
.first
.toString().c_str(), (int)eds
.second
.mode
, ctime(&eds
.second
.modeSetAt
));
361 uint64_t SyncRes::doDumpNSSpeeds(int fd
)
363 FILE* fp
=fdopen(dup(fd
), "w");
366 fprintf(fp
, "; nsspeed dump from thread follows\n;\n");
369 for(const auto& i
: t_sstorage
.nsSpeeds
)
373 // an <empty> can appear hear in case of authoritative (hosted) zones
374 fprintf(fp
, "%s -> ", i
.first
.toLogString().c_str());
375 for(const auto& j
: i
.second
.d_collection
)
377 // typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
378 fprintf(fp
, "%s/%f ", j
.first
.toString().c_str(), j
.second
.peek());
386 /* so here is the story. First we complete the full resolution process for a domain name. And only THEN do we decide
387 to also do DNSSEC validation, which leads to new queries. To make this simple, we *always* ask for DNSSEC records
388 so that if there are RRSIGs for a name, we'll have them.
390 However, some hosts simply can't answer questions which ask for DNSSEC. This can manifest itself as:
395 The cause of "No answer" may be fragmentation, and it is tempting to probe if smaller answers would get through.
396 Another cause of "No answer" may simply be a network condition.
397 Nonsense answers are a clearer indication this host won't be able to do DNSSEC evah.
399 Previous implementations have suffered from turning off DNSSEC questions for an authoritative server based on timeouts.
400 A clever idea is to only turn off DNSSEC if we know a domain isn't signed anyhow. The problem with that really
401 clever idea however is that at this point in PowerDNS, we may simply not know that yet. All the DNSSEC thinking happens
402 elsewhere. It may not have happened yet.
404 For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish.
407 int SyncRes::asyncresolveWrapper(const ComboAddress
& ip
, bool ednsMANDATORY
, const DNSName
& domain
, int type
, bool doTCP
, bool sendRDQuery
, struct timeval
* now
, boost::optional
<Netmask
>& srcmask
, LWResult
* res
) const
409 /* what is your QUEST?
410 the goal is to get as many remotes as possible on the highest level of EDNS support
413 0) UNKNOWN Unknown state
414 1) EDNS: Honors EDNS0
415 2) EDNSIGNORANT: Ignores EDNS0, gives replies without EDNS0
416 3) NOEDNS: Generates FORMERR/NOTIMP on EDNS queries
418 Everybody starts out assumed to be '0'.
419 If '0', send out EDNS0
420 If you FORMERR us, go to '3',
421 If no EDNS in response, go to '2'
422 If '1', send out EDNS0
423 If FORMERR, downgrade to 3
424 If '2', keep on including EDNS0, see what happens
426 If '3', send bare queries
429 SyncRes::EDNSStatus
* ednsstatus
;
430 ednsstatus
= &t_sstorage
.ednsstatus
[ip
]; // does this include port? YES
432 if(ednsstatus
->modeSetAt
&& ednsstatus
->modeSetAt
+ 3600 < d_now
.tv_sec
) {
433 *ednsstatus
=SyncRes::EDNSStatus();
434 // cerr<<"Resetting EDNS Status for "<<ip.toString()<<endl);
437 SyncRes::EDNSStatus::EDNSMode
& mode
=ednsstatus
->mode
;
438 SyncRes::EDNSStatus::EDNSMode oldmode
= mode
;
440 auto luaconfsLocal
= g_luaconfs
.getLocal();
443 ctx
.d_initialRequestId
= d_initialRequestId
;
447 for(int tries
= 0; tries
< 3; ++tries
) {
448 // cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl;
450 if(mode
==EDNSStatus::NOEDNS
) {
451 g_stats
.noEdnsOutQueries
++;
452 EDNSLevel
= 0; // level != mode
454 else if(ednsMANDATORY
|| mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
==EDNSStatus::EDNSIGNORANT
)
457 DNSName
sendQname(domain
);
458 if (g_lowercaseOutgoing
)
459 sendQname
.makeUsLowerCase();
461 if (d_asyncResolve
) {
462 ret
= d_asyncResolve(ip
, sendQname
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, luaconfsLocal
->outgoingProtobufServer
, res
);
465 ret
=asyncresolve(ip
, sendQname
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, luaconfsLocal
->outgoingProtobufServer
, res
);
468 return ret
; // transport error, nothing to learn here
471 if(ret
== 0) { // timeout, not doing anything with it now
474 else if(mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
== EDNSStatus::EDNSIGNORANT
) {
475 if(res
->d_rcode
== RCode::FormErr
|| res
->d_rcode
== RCode::NotImp
) {
476 // cerr<<"Downgrading to NOEDNS because of "<<RCode::to_s(res->d_rcode)<<" for query to "<<ip.toString()<<" for '"<<domain<<"'"<<endl;
477 mode
= EDNSStatus::NOEDNS
;
480 else if(!res
->d_haveEDNS
) {
481 if(mode
!= EDNSStatus::EDNSIGNORANT
) {
482 mode
= EDNSStatus::EDNSIGNORANT
;
483 // cerr<<"We find that "<<ip.toString()<<" is an EDNS-ignorer for '"<<domain<<"', moving to mode 3"<<endl;
487 mode
= EDNSStatus::EDNSOK
;
488 // cerr<<"We find that "<<ip.toString()<<" is EDNS OK!"<<endl;
492 if(oldmode
!= mode
|| !ednsstatus
->modeSetAt
)
493 ednsstatus
->modeSetAt
=d_now
.tv_sec
;
494 // cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", new mode: "<<mode<<endl;
500 /*! This function will check the cache and go out to the internet if the answer is not in cache
502 * \param qname The name we need an answer for
504 * \param ret The vector of DNSRecords we need to fill with the answers
505 * \param depth The recursion depth we are in
507 * \return DNS RCODE or -1 (Error) or -2 (RPZ hit)
509 int SyncRes::doResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, vState
& state
)
514 prefix
.append(depth
, ' ');
517 LOG(prefix
<<qname
<<": Wants "<< (d_doDNSSEC
? "" : "NO ") << "DNSSEC processing, "<<(d_requireAuthData
? "" : "NO ")<<"auth data in query for "<<qtype
.getName()<<endl
);
519 state
= Indeterminate
;
521 if(s_maxdepth
&& depth
> s_maxdepth
)
522 throw ImmediateServFailException("More than "+std::to_string(s_maxdepth
)+" (max-recursion-depth) levels of recursion needed while resolving "+qname
.toLogString());
526 // This is a difficult way of expressing "this is a normal query", i.e. not getRootNS.
527 if(!(d_updatingRootNS
&& qtype
.getCode()==QType::NS
&& qname
.isRoot())) {
528 if(d_cacheonly
) { // very limited OOB support
530 LOG(prefix
<<qname
<<": Recursion not requested for '"<<qname
<<"|"<<qtype
.getName()<<"', peeking at auth/forward zones"<<endl
);
531 DNSName
authname(qname
);
532 domainmap_t::const_iterator iter
=getBestAuthZone(&authname
);
533 if(iter
!= t_sstorage
.domainmap
->end()) {
534 if(iter
->second
.isAuth()) {
536 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, ret
, depth
, res
);
540 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
541 const ComboAddress remoteIP
= servers
.front();
542 LOG(prefix
<<qname
<<": forwarding query to hardcoded nameserver '"<< remoteIP
.toStringWithPort()<<"' for zone '"<<authname
<<"'"<<endl
);
544 boost::optional
<Netmask
> nm
;
545 res
=asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(), false, false, &d_now
, nm
, &lwr
);
547 d_totUsec
+= lwr
.d_usec
;
548 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
550 // filter out the good stuff from lwr.result()
552 for(const auto& rec
: lwr
.d_records
) {
553 if(rec
.d_place
== DNSResourceRecord::ANSWER
)
559 return RCode::ServFail
;
565 DNSName
authname(qname
);
566 bool wasForwardedOrAuthZone
= false;
567 bool wasAuthZone
= false;
568 domainmap_t::const_iterator iter
= getBestAuthZone(&authname
);
569 if(iter
!= t_sstorage
.domainmap
->end()) {
570 wasForwardedOrAuthZone
= true;
571 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
572 if(servers
.empty()) {
577 if(!d_skipCNAMECheck
&& doCNAMECacheCheck(qname
, qtype
, ret
, depth
, res
, state
, wasAuthZone
)) { // will reroute us if needed
578 d_wasOutOfBand
= wasAuthZone
;
582 if(doCacheCheck(qname
, authname
, wasForwardedOrAuthZone
, wasAuthZone
, qtype
, ret
, depth
, res
, state
)) {
584 d_wasOutOfBand
= wasAuthZone
;
592 LOG(prefix
<<qname
<<": No cache hit for '"<<qname
<<"|"<<qtype
.getName()<<"', trying to find an appropriate NS record"<<endl
);
594 DNSName
subdomain(qname
);
595 if(qtype
== QType::DS
) subdomain
.chopOff();
598 bool flawedNSSet
=false;
600 /* we use subdomain here instead of qname because for DS queries we only care about the state of the parent zone */
601 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
603 // the two retries allow getBestNSNamesFromCache&co to reprime the root
604 // hints, in case they ever go missing
605 for(int tries
=0;tries
<2 && nsset
.empty();++tries
) {
606 subdomain
=getBestNSNamesFromCache(subdomain
, qtype
, nsset
, &flawedNSSet
, depth
, beenthere
); // pass beenthere to both occasions
609 state
= getValidationStatus(qname
, false);
611 LOG(prefix
<<qname
<<": initial validation status for "<<qname
<<" is "<<vStates
[state
]<<endl
);
613 if(!(res
=doResolveAt(nsset
, subdomain
, flawedNSSet
, qname
, qtype
, ret
, depth
, beenthere
, state
)))
616 LOG(prefix
<<qname
<<": failed (res="<<res
<<")"<<endl
);
621 return res
<0 ? RCode::ServFail
: res
;
625 // for testing purposes
626 static bool ipv6First(const ComboAddress
& a
, const ComboAddress
& b
)
628 return !(a
.sin4
.sin_family
< a
.sin4
.sin_family
);
634 speedOrderCA(std::map
<ComboAddress
,double>& speeds
): d_speeds(speeds
) {}
635 bool operator()(const ComboAddress
& a
, const ComboAddress
& b
) const
637 return d_speeds
[a
] < d_speeds
[b
];
639 std::map
<ComboAddress
, double>& d_speeds
;
642 /** This function explicitly goes out for A or AAAA addresses
644 vector
<ComboAddress
> SyncRes::getAddrs(const DNSName
&qname
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, bool cacheOnly
)
646 typedef vector
<DNSRecord
> res_t
;
649 typedef vector
<ComboAddress
> ret_t
;
653 bool oldCacheOnly
= d_cacheonly
;
654 bool oldRequireAuthData
= d_requireAuthData
;
655 bool oldValidationRequested
= d_DNSSECValidationRequested
;
656 d_requireAuthData
= false;
657 d_DNSSECValidationRequested
= false;
658 d_cacheonly
= cacheOnly
;
660 for(int j
=1; j
<2+s_doIPv6
; j
++)
675 vState newState
= Indeterminate
;
676 if(!doResolve(qname
, type
, res
,depth
+1, beenthere
, newState
) && !res
.empty()) { // this consults cache, OR goes out
677 for(res_t::const_iterator i
=res
.begin(); i
!= res
.end(); ++i
) {
678 if(i
->d_type
== QType::A
|| i
->d_type
== QType::AAAA
) {
679 if(auto rec
= getRR
<ARecordContent
>(*i
))
680 ret
.push_back(rec
->getCA(53));
681 else if(auto aaaarec
= getRR
<AAAARecordContent
>(*i
))
682 ret
.push_back(aaaarec
->getCA(53));
688 if(j
==1 && s_doIPv6
) { // we got an A record, see if we have some AAAA lying around
689 vector
<DNSRecord
> cset
;
690 if(t_RC
->get(d_now
.tv_sec
, qname
, QType(QType::AAAA
), false, &cset
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
) > 0) {
691 for(auto k
=cset
.cbegin();k
!=cset
.cend();++k
) {
692 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
693 if (auto drc
= getRR
<AAAARecordContent
>(*k
)) {
694 ComboAddress ca
=drc
->getCA(53);
705 d_requireAuthData
= oldRequireAuthData
;
706 d_DNSSECValidationRequested
= oldValidationRequested
;
707 d_cacheonly
= oldCacheOnly
;
709 /* we need to remove from the nsSpeeds collection the existing IPs
710 for this nameserver that are no longer in the set, even if there
711 is only one or none at all in the current set.
713 map
<ComboAddress
, double> speeds
;
714 auto& collection
= t_sstorage
.nsSpeeds
[qname
].d_collection
;
715 for(const auto& val
: ret
) {
716 speeds
[val
] = collection
[val
].get(&d_now
);
719 t_sstorage
.nsSpeeds
[qname
].purge(speeds
);
722 random_shuffle(ret
.begin(), ret
.end(), dns_random
);
723 speedOrderCA
so(speeds
);
724 stable_sort(ret
.begin(), ret
.end(), so
);
727 string prefix
=d_prefix
;
728 prefix
.append(depth
, ' ');
729 LOG(prefix
<<"Nameserver "<<qname
<<" IPs: ");
731 for(const auto& addr
: ret
) {
738 LOG((addr
.toString())<<"(" << (boost::format("%0.2f") % (speeds
[addr
]/1000.0)).str() <<"ms)");
747 void SyncRes::getBestNSFromCache(const DNSName
&qname
, const QType
& qtype
, vector
<DNSRecord
>& bestns
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
)
750 DNSName
subdomain(qname
);
753 prefix
.append(depth
, ' ');
759 LOG(prefix
<<qname
<<": Checking if we have NS in cache for '"<<subdomain
<<"'"<<endl
);
760 vector
<DNSRecord
> ns
;
761 *flawedNSSet
= false;
763 if(t_RC
->get(d_now
.tv_sec
, subdomain
, QType(QType::NS
), false, &ns
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
) > 0) {
764 for(auto k
=ns
.cbegin();k
!=ns
.cend(); ++k
) {
765 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
766 vector
<DNSRecord
> aset
;
768 const DNSRecord
& dr
=*k
;
769 auto nrr
= getRR
<NSRecordContent
>(dr
);
770 if(nrr
&& (!nrr
->getNS().isPartOf(subdomain
) || t_RC
->get(d_now
.tv_sec
, nrr
->getNS(), s_doIPv6
? QType(QType::ADDR
) : QType(QType::A
),
771 false, doLog() ? &aset
: 0, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
) > 5)) {
772 bestns
.push_back(dr
);
773 LOG(prefix
<<qname
<<": NS (with ip, or non-glue) in cache for '"<<subdomain
<<"' -> '"<<nrr
->getNS()<<"'"<<endl
);
774 LOG(prefix
<<qname
<<": within bailiwick: "<< nrr
->getNS().isPartOf(subdomain
));
776 LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset
.begin()->d_ttl
- d_now
.tv_sec
))<<endl
);
779 LOG(", not in cache / did not look at cache"<<endl
);
784 LOG(prefix
<<qname
<<": NS in cache for '"<<subdomain
<<"', but needs glue ("<<nrr
->getNS()<<") which we miss or is expired"<<endl
);
789 if(!bestns
.empty()) {
790 GetBestNSAnswer answer
;
792 answer
.qtype
=qtype
.getCode();
793 for(const auto& dr
: bestns
) {
794 if (auto nsContent
= getRR
<NSRecordContent
>(dr
)) {
795 answer
.bestns
.insert(make_pair(dr
.d_name
, nsContent
->getNS()));
799 if(beenthere
.count(answer
)) {
801 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' but part of LOOP (already seen "<<answer
.qname
<<")! Trying less specific NS"<<endl
);
804 for( set
<GetBestNSAnswer
>::const_iterator j
=beenthere
.begin();j
!=beenthere
.end();++j
) {
805 bool neo
= !(*j
< answer
|| answer
<*j
);
806 LOG(prefix
<<qname
<<": beenthere"<<(neo
?"*":"")<<": "<<j
->qname
<<"|"<<DNSRecordContent::NumberToType(j
->qtype
)<<" ("<<(unsigned int)j
->bestns
.size()<<")"<<endl
);
811 beenthere
.insert(answer
);
812 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' (flawedNSSet="<<*flawedNSSet
<<")"<<endl
);
817 LOG(prefix
<<qname
<<": no valid/useful NS in cache for '"<<subdomain
<<"'"<<endl
);
819 if(subdomain
.isRoot() && !brokeloop
) {
820 // We lost the root NS records
822 LOG(prefix
<<qname
<<": reprimed the root"<<endl
);
823 /* let's prevent an infinite loop */
824 if (!d_updatingRootNS
) {
825 getRootNS(d_now
, d_asyncResolve
);
828 } while(subdomain
.chopOff());
831 SyncRes::domainmap_t::const_iterator
SyncRes::getBestAuthZone(DNSName
* qname
) const
833 SyncRes::domainmap_t::const_iterator ret
;
835 ret
=t_sstorage
.domainmap
->find(*qname
);
836 if(ret
!=t_sstorage
.domainmap
->end())
838 }while(qname
->chopOff());
842 /** doesn't actually do the work, leaves that to getBestNSFromCache */
843 DNSName
SyncRes::getBestNSNamesFromCache(const DNSName
&qname
, const QType
& qtype
, NsSet
& nsset
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
)
845 DNSName
subdomain(qname
);
846 DNSName
authdomain(qname
);
848 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
849 if(iter
!=t_sstorage
.domainmap
->end()) {
850 if( iter
->second
.isAuth() )
851 // this gets picked up in doResolveAt, the empty DNSName, combined with the
852 // empty vector means 'we are auth for this zone'
853 nsset
.insert({DNSName(), {{}, false}});
855 // Again, picked up in doResolveAt. An empty DNSName, combined with a
856 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
857 // This is actually picked up in retrieveAddressesForNS called from doResolveAt.
858 nsset
.insert({DNSName(), {iter
->second
.d_servers
, iter
->second
.shouldRecurse() }});
863 vector
<DNSRecord
> bestns
;
864 getBestNSFromCache(subdomain
, qtype
, bestns
, flawedNSSet
, depth
, beenthere
);
866 for(auto k
=bestns
.cbegin() ; k
!= bestns
.cend(); ++k
) {
867 // The actual resolver code will not even look at the ComboAddress or bool
868 const auto nsContent
= getRR
<NSRecordContent
>(*k
);
870 nsset
.insert({nsContent
->getNS(), {{}, false}});
871 if(k
==bestns
.cbegin())
878 bool SyncRes::doCNAMECacheCheck(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>& ret
, unsigned int depth
, int &res
, vState
& state
, bool wasAuthZone
)
883 prefix
.append(depth
, ' ');
886 if((depth
>9 && d_outqueries
>10 && d_throttledqueries
>5) || depth
> 15) {
887 LOG(prefix
<<qname
<<": recursing (CNAME or other indirection) too deep, depth="<<depth
<<endl
);
892 LOG(prefix
<<qname
<<": Looking for CNAME cache hit of '"<<qname
<<"|CNAME"<<"'"<<endl
);
893 vector
<DNSRecord
> cset
;
894 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
895 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
897 if(t_RC
->get(d_now
.tv_sec
, qname
, QType(QType::CNAME
), d_requireAuthData
, &cset
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, d_doDNSSEC
? &signatures
: nullptr, d_doDNSSEC
? &authorityRecs
: nullptr, &d_wasVariable
, &state
, &wasAuth
) > 0) {
899 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
900 if (j
->d_class
!= QClass::IN
) {
904 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
906 if (!wasAuthZone
&& shouldValidate() && wasAuth
&& state
== Indeterminate
&& d_requireAuthData
) {
907 /* This means we couldn't figure out the state when this entry was cached,
908 most likely because we hadn't computed the zone cuts yet. */
909 /* make sure they are computed before validating */
910 DNSName
subdomain(qname
);
911 /* if we are retrieving a DS, we only care about the state of the parent zone */
912 if(qtype
== QType::DS
)
915 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
917 vState recordState
= getValidationStatus(qname
, false);
918 if (recordState
== Secure
) {
919 LOG(prefix
<<qname
<<": got Indeterminate state from the CNAME cache, validating.."<<endl
);
920 state
= SyncRes::validateRecordsWithSigs(depth
, qname
, QType(QType::CNAME
), qname
, cset
, signatures
);
921 if (state
!= Indeterminate
) {
922 LOG(prefix
<<qname
<<": got Indeterminate state from the CNAME cache, new validation result is "<<vStates
[state
]<<endl
);
923 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, QType(QType::CNAME
), d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, d_requireAuthData
, state
);
928 LOG(prefix
<<qname
<<": Found cache CNAME hit for '"<< qname
<< "|CNAME" <<"' to '"<<j
->d_content
->getZoneRepresentation()<<"', validation state is "<<vStates
[state
]<<endl
);
931 dr
.d_ttl
-=d_now
.tv_sec
;
934 for(const auto& signature
: signatures
) {
936 sigdr
.d_type
=QType::RRSIG
;
938 sigdr
.d_ttl
=j
->d_ttl
- d_now
.tv_sec
;
939 sigdr
.d_content
=signature
;
940 sigdr
.d_place
=DNSResourceRecord::ANSWER
;
941 sigdr
.d_class
=QClass::IN
;
942 ret
.push_back(sigdr
);
945 for(const auto& rec
: authorityRecs
) {
946 DNSRecord
authDR(*rec
);
947 authDR
.d_ttl
=j
->d_ttl
- d_now
.tv_sec
;
948 ret
.push_back(authDR
);
951 if(qtype
!= QType::CNAME
) { // perhaps they really wanted a CNAME!
952 set
<GetBestNSAnswer
>beenthere
;
954 vState cnameState
= Indeterminate
;
955 const auto cnameContent
= getRR
<CNAMERecordContent
>(*j
);
957 res
=doResolve(cnameContent
->getTarget(), qtype
, ret
, depth
+1, beenthere
, cnameState
);
958 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
959 updateValidationState(state
, cnameState
);
969 LOG(prefix
<<qname
<<": No CNAME cache hit of '"<< qname
<< "|CNAME" <<"' found"<<endl
);
976 vector
<DNSRecord
> records
;
977 vector
<shared_ptr
<RRSIGRecordContent
>> signatures
;
978 uint32_t signaturesTTL
{std::numeric_limits
<uint32_t>::max()};
984 DNSResourceRecord::Place place
;
985 bool operator<(const CacheKey
& rhs
) const {
986 return tie(name
, type
) < tie(rhs
.name
, rhs
.type
);
989 typedef map
<CacheKey
, CacheEntry
> tcache_t
;
992 static void reapRecordsFromNegCacheEntryForValidation(tcache_t
& tcache
, const vector
<DNSRecord
>& records
)
994 for (const auto& rec
: records
) {
995 if (rec
.d_type
== QType::RRSIG
) {
996 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
998 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
1001 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(rec
);
1007 * Convience function to push the records from records into ret with a new TTL
1009 * \param records DNSRecords that need to go into ret
1010 * \param ttl The new TTL for these records
1011 * \param ret The vector of DNSRecords that should contian the records with the modified TTL
1013 static void addTTLModifiedRecords(const vector
<DNSRecord
>& records
, const uint32_t ttl
, vector
<DNSRecord
>& ret
) {
1014 for (const auto& rec
: records
) {
1021 void SyncRes::computeNegCacheValidationStatus(NegCache::NegCacheEntry
& ne
, const DNSName
& qname
, const QType
& qtype
, const int res
, vState
& state
, unsigned int depth
)
1023 DNSName
subdomain(qname
);
1024 /* if we are retrieving a DS, we only care about the state of the parent zone */
1025 if(qtype
== QType::DS
)
1026 subdomain
.chopOff();
1028 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1031 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.authoritySOA
.records
);
1032 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.authoritySOA
.signatures
);
1033 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.DNSSECRecords
.records
);
1034 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.DNSSECRecords
.signatures
);
1036 for (const auto& entry
: tcache
) {
1037 // this happens when we did store signatures, but passed on the records themselves
1038 if (entry
.second
.records
.empty()) {
1042 const DNSName
& owner
= entry
.first
.name
;
1044 vState recordState
= getValidationStatus(owner
, false);
1045 if (state
== Indeterminate
) {
1046 state
= recordState
;
1049 if (recordState
== Secure
) {
1050 recordState
= SyncRes::validateRecordsWithSigs(depth
, qname
, qtype
, owner
, entry
.second
.records
, entry
.second
.signatures
);
1053 if (recordState
!= Indeterminate
&& recordState
!= state
) {
1054 updateValidationState(state
, recordState
);
1055 if (state
!= Secure
) {
1061 if (state
== Secure
) {
1062 dState expectedState
= res
== RCode::NXDomain
? NXDOMAIN
: NXQTYPE
;
1063 dState denialState
= getDenialValidationState(ne
, state
, expectedState
, false);
1064 updateDenialValidationState(ne
, state
, denialState
, expectedState
, qtype
== QType::DS
);
1066 if (state
!= Indeterminate
) {
1067 /* validation succeeded, let's update the cache entry so we don't have to validate again */
1068 t_sstorage
.negcache
.updateValidationStatus(ne
.d_name
, ne
.d_qtype
, state
);
1072 bool SyncRes::doCacheCheck(const DNSName
&qname
, const DNSName
& authname
, bool wasForwardedOrAuthZone
, bool wasAuthZone
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int &res
, vState
& state
)
1074 bool giveNegative
=false;
1079 prefix
.append(depth
, ' ');
1082 // 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)
1083 DNSName
sqname(qname
);
1086 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
1088 NegCache::NegCacheEntry ne
;
1091 t_sstorage
.negcache
.getRootNXTrust(qname
, d_now
, ne
) &&
1092 ne
.d_auth
.isRoot() &&
1093 !(wasForwardedOrAuthZone
&& !authname
.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
1094 sttl
= ne
.d_ttd
- d_now
.tv_sec
;
1095 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
.d_auth
<<"' & '"<<ne
.d_name
<<"' for another "<<sttl
<<" seconds"<<endl
);
1096 res
= RCode::NXDomain
;
1097 giveNegative
= true;
1098 cachedState
= ne
.d_validationState
;
1100 else if (t_sstorage
.negcache
.get(qname
, qtype
, d_now
, ne
) &&
1101 !(wasForwardedOrAuthZone
&& ne
.d_auth
!= authname
)) { // Only the authname nameserver can neg cache entries
1103 /* If we are looking for a DS, discard NXD if auth == qname
1104 and ask for a specific denial instead */
1105 if (qtype
!= QType::DS
|| ne
.d_qtype
.getCode() || ne
.d_auth
!= qname
||
1106 t_sstorage
.negcache
.get(qname
, qtype
, d_now
, ne
, true))
1109 sttl
= ne
.d_ttd
- d_now
.tv_sec
;
1110 giveNegative
= true;
1111 cachedState
= ne
.d_validationState
;
1112 if(ne
.d_qtype
.getCode()) {
1113 LOG(prefix
<<qname
<<": "<<qtype
.getName()<<" is negatively cached via '"<<ne
.d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1114 res
= RCode::NoError
;
1117 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
.d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1118 res
= RCode::NXDomain
;
1125 state
= cachedState
;
1127 if (!wasAuthZone
&& shouldValidate() && state
== Indeterminate
) {
1128 LOG(prefix
<<qname
<<": got Indeterminate state for records retrieved from the negative cache, validating.."<<endl
);
1129 computeNegCacheValidationStatus(ne
, qname
, qtype
, res
, state
, depth
);
1132 // Transplant SOA to the returned packet
1133 addTTLModifiedRecords(ne
.authoritySOA
.records
, sttl
, ret
);
1135 addTTLModifiedRecords(ne
.authoritySOA
.signatures
, sttl
, ret
);
1136 addTTLModifiedRecords(ne
.DNSSECRecords
.records
, sttl
, ret
);
1137 addTTLModifiedRecords(ne
.DNSSECRecords
.signatures
, sttl
, ret
);
1140 LOG(prefix
<<qname
<<": updating validation state with negative cache content for "<<qname
<<" to "<<vStates
[state
]<<endl
);
1144 vector
<DNSRecord
> cset
;
1145 bool found
=false, expired
=false;
1146 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
1147 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1150 if(t_RC
->get(d_now
.tv_sec
, sqname
, sqt
, d_requireAuthData
, &cset
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, d_doDNSSEC
? &signatures
: nullptr, d_doDNSSEC
? &authorityRecs
: nullptr, &d_wasVariable
, &cachedState
, &wasCachedAuth
) > 0) {
1152 LOG(prefix
<<sqname
<<": Found cache hit for "<<sqt
.getName()<<": ");
1154 if (!wasAuthZone
&& shouldValidate() && wasCachedAuth
&& cachedState
== Indeterminate
&& d_requireAuthData
) {
1156 /* This means we couldn't figure out the state when this entry was cached,
1157 most likely because we hadn't computed the zone cuts yet. */
1158 /* make sure they are computed before validating */
1159 DNSName
subdomain(sqname
);
1160 /* if we are retrieving a DS, we only care about the state of the parent zone */
1161 if(qtype
== QType::DS
)
1162 subdomain
.chopOff();
1164 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1166 vState recordState
= getValidationStatus(qname
, false);
1167 if (recordState
== Secure
) {
1168 LOG(prefix
<<sqname
<<": got Indeterminate state from the cache, validating.."<<endl
);
1169 cachedState
= SyncRes::validateRecordsWithSigs(depth
, sqname
, sqt
, sqname
, cset
, signatures
);
1172 cachedState
= recordState
;
1175 if (cachedState
!= Indeterminate
) {
1176 LOG(prefix
<<qname
<<": got Indeterminate state from the cache, validation result is "<<vStates
[cachedState
]<<endl
);
1177 t_RC
->updateValidationStatus(d_now
.tv_sec
, sqname
, sqt
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, d_requireAuthData
, cachedState
);
1181 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
1183 LOG(j
->d_content
->getZoneRepresentation());
1185 if (j
->d_class
!= QClass::IN
) {
1189 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
1191 ttl
= (dr
.d_ttl
-=d_now
.tv_sec
);
1193 LOG("[ttl="<<dr
.d_ttl
<<"] ");
1202 for(const auto& signature
: signatures
) {
1204 dr
.d_type
=QType::RRSIG
;
1207 dr
.d_content
=signature
;
1208 dr
.d_place
= DNSResourceRecord::ANSWER
;
1209 dr
.d_class
=QClass::IN
;
1213 for(const auto& rec
: authorityRecs
) {
1220 if(found
&& !expired
) {
1223 LOG(prefix
<<qname
<<": updating validation state with cache content for "<<qname
<<" to "<<vStates
[cachedState
]<<endl
);
1224 state
= cachedState
;
1228 LOG(prefix
<<qname
<<": cache had only stale entries"<<endl
);
1234 bool SyncRes::moreSpecificThan(const DNSName
& a
, const DNSName
&b
) const
1236 return (a
.isPartOf(b
) && a
.countLabels() > b
.countLabels());
1241 speedOrder(map
<DNSName
,double> &speeds
) : d_speeds(speeds
) {}
1242 bool operator()(const DNSName
&a
, const DNSName
&b
) const
1244 return d_speeds
[a
] < d_speeds
[b
];
1246 map
<DNSName
, double>& d_speeds
;
1249 inline vector
<DNSName
> SyncRes::shuffleInSpeedOrder(NsSet
&tnameservers
, const string
&prefix
)
1251 vector
<DNSName
> rnameservers
;
1252 rnameservers
.reserve(tnameservers
.size());
1253 for(const auto& tns
: tnameservers
) {
1254 rnameservers
.push_back(tns
.first
);
1255 if(tns
.first
.empty()) // this was an authoritative OOB zone, don't pollute the nsSpeeds with that
1256 return rnameservers
;
1258 map
<DNSName
, double> speeds
;
1260 for(const auto& val
: rnameservers
) {
1262 speed
=t_sstorage
.nsSpeeds
[val
].get(&d_now
);
1265 random_shuffle(rnameservers
.begin(),rnameservers
.end(), dns_random
);
1266 speedOrder
so(speeds
);
1267 stable_sort(rnameservers
.begin(),rnameservers
.end(), so
);
1270 LOG(prefix
<<"Nameservers: ");
1271 for(vector
<DNSName
>::const_iterator i
=rnameservers
.begin();i
!=rnameservers
.end();++i
) {
1272 if(i
!=rnameservers
.begin()) {
1274 if(!((i
-rnameservers
.begin())%3)) {
1275 LOG(endl
<<prefix
<<" ");
1278 LOG((i
->empty() ? string("<empty>") : i
->toString())<<"(" << (boost::format("%0.2f") % (speeds
[*i
]/1000.0)).str() <<"ms)");
1282 return rnameservers
;
1285 static uint32_t getRRSIGTTL(const time_t now
, const std::shared_ptr
<RRSIGRecordContent
>& rrsig
)
1288 if (now
< rrsig
->d_sigexpire
) {
1289 res
= static_cast<uint32_t>(rrsig
->d_sigexpire
) - now
;
1294 static const set
<uint16_t> nsecTypes
= {QType::NSEC
, QType::NSEC3
};
1296 /* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
1298 * \param records The records to parse for the authority SOA and NSEC(3) records
1299 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
1301 static void harvestNXRecords(const vector
<DNSRecord
>& records
, NegCache::NegCacheEntry
& ne
, const time_t now
, uint32_t* lowestTTL
) {
1302 for(const auto& rec
: records
) {
1303 if(rec
.d_place
!= DNSResourceRecord::AUTHORITY
)
1304 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
1305 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
1306 // records MUST be in the same section as the records they cover.
1307 // Hence, we ignore all records outside of the AUTHORITY section.
1310 if(rec
.d_type
== QType::RRSIG
) {
1311 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1313 if(rrsig
->d_type
== QType::SOA
) {
1314 ne
.authoritySOA
.signatures
.push_back(rec
);
1315 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1316 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1317 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1320 if(nsecTypes
.count(rrsig
->d_type
)) {
1321 ne
.DNSSECRecords
.signatures
.push_back(rec
);
1322 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1323 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1324 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1330 if(rec
.d_type
== QType::SOA
) {
1331 ne
.authoritySOA
.records
.push_back(rec
);
1333 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1337 if(nsecTypes
.count(rec
.d_type
)) {
1338 ne
.DNSSECRecords
.records
.push_back(rec
);
1340 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1347 static cspmap_t
harvestCSPFromNE(const NegCache::NegCacheEntry
& ne
)
1350 for(const auto& rec
: ne
.DNSSECRecords
.signatures
) {
1351 if(rec
.d_type
== QType::RRSIG
) {
1352 auto rrc
= getRR
<RRSIGRecordContent
>(rec
);
1354 cspmap
[{rec
.d_name
,rrc
->d_type
}].signatures
.push_back(rrc
);
1358 for(const auto& rec
: ne
.DNSSECRecords
.records
) {
1359 cspmap
[{rec
.d_name
, rec
.d_type
}].records
.push_back(rec
.d_content
);
1364 // TODO remove after processRecords is fixed!
1365 // Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
1366 static void addNXNSECS(vector
<DNSRecord
>&ret
, const vector
<DNSRecord
>& records
)
1368 NegCache::NegCacheEntry ne
;
1369 harvestNXRecords(records
, ne
, 0, nullptr);
1370 ret
.insert(ret
.end(), ne
.authoritySOA
.signatures
.begin(), ne
.authoritySOA
.signatures
.end());
1371 ret
.insert(ret
.end(), ne
.DNSSECRecords
.records
.begin(), ne
.DNSSECRecords
.records
.end());
1372 ret
.insert(ret
.end(), ne
.DNSSECRecords
.signatures
.begin(), ne
.DNSSECRecords
.signatures
.end());
1375 bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine
& dfe
, const NsSet
& nameservers
)
1378 for (auto const &ns
: nameservers
) {
1379 d_appliedPolicy
= dfe
.getProcessingPolicy(ns
.first
, d_discardedPolicies
);
1380 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1381 LOG(", however nameserver "<<ns
.first
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1385 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1386 for (auto const &address
: ns
.second
.first
) {
1387 d_appliedPolicy
= dfe
.getProcessingPolicy(address
, d_discardedPolicies
);
1388 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1389 LOG(", however nameserver "<<ns
.first
<<" IP address "<<address
.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1398 bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine
& dfe
, const ComboAddress
& remoteIP
)
1401 d_appliedPolicy
= dfe
.getProcessingPolicy(remoteIP
, d_discardedPolicies
);
1402 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) {
1403 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")+"')");
1410 vector
<ComboAddress
> SyncRes::retrieveAddressesForNS(const std::string
& prefix
, const DNSName
& qname
, vector
<DNSName
>::const_iterator
& tns
, const unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, const vector
<DNSName
>& rnameservers
, NsSet
& nameservers
, bool& sendRDQuery
, bool& pierceDontQuery
, bool& flawedNSSet
, bool cacheOnly
)
1412 vector
<ComboAddress
> result
;
1415 LOG(prefix
<<qname
<<": Trying to resolve NS '"<<*tns
<< "' ("<<1+tns
-rnameservers
.begin()<<"/"<<(unsigned int)rnameservers
.size()<<")"<<endl
);
1416 result
= getAddrs(*tns
, depth
+2, beenthere
, cacheOnly
);
1417 pierceDontQuery
=false;
1420 LOG(prefix
<<qname
<<": Domain has hardcoded nameserver");
1422 result
= nameservers
[*tns
].first
;
1423 if(result
.size() > 1) {
1428 sendRDQuery
= nameservers
[*tns
].second
;
1429 pierceDontQuery
=true;
1434 bool SyncRes::throttledOrBlocked(const std::string
& prefix
, const ComboAddress
& remoteIP
, const DNSName
& qname
, const QType
& qtype
, bool pierceDontQuery
)
1436 if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0))) {
1437 LOG(prefix
<<qname
<<": server throttled "<<endl
);
1438 s_throttledqueries
++; d_throttledqueries
++;
1441 else if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()))) {
1442 LOG(prefix
<<qname
<<": query throttled "<<remoteIP
.toString()<<", "<<qname
<<"; "<<qtype
.getName()<<endl
);
1443 s_throttledqueries
++; d_throttledqueries
++;
1446 else if(!pierceDontQuery
&& s_dontQuery
&& s_dontQuery
->match(&remoteIP
)) {
1447 LOG(prefix
<<qname
<<": not sending query to " << remoteIP
.toString() << ", blocked by 'dont-query' setting" << endl
);
1454 bool SyncRes::validationEnabled() const
1456 return g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
;
1459 uint32_t SyncRes::computeLowestTTD(const std::vector
<DNSRecord
>& records
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, uint32_t signaturesTTL
) const
1461 uint32_t lowestTTD
= std::numeric_limits
<uint32_t>::max();
1462 for(const auto& record
: records
)
1463 lowestTTD
= min(lowestTTD
, record
.d_ttl
);
1465 /* even if it was not requested for that request (Process, and neither AD nor DO set),
1466 it might be requested at a later time so we need to be careful with the TTL. */
1467 if (validationEnabled() && !signatures
.empty()) {
1468 /* if we are validating, we don't want to cache records after their signatures expire. */
1469 /* records TTL are now TTD, let's add 'now' to the signatures lowest TTL */
1470 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(signaturesTTL
+ d_now
.tv_sec
));
1472 for(const auto& sig
: signatures
) {
1473 if (isRRSIGNotExpired(d_now
.tv_sec
, sig
)) {
1474 // we don't decerement d_sigexpire by 'now' because we actually want a TTD, not a TTL */
1475 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(sig
->d_sigexpire
));
1483 void SyncRes::updateValidationState(vState
& state
, const vState stateUpdate
)
1485 LOG(d_prefix
<<"validation state was "<<std::string(vStates
[state
])<<", state update is "<<std::string(vStates
[stateUpdate
]));
1487 if (stateUpdate
== TA
) {
1490 else if (stateUpdate
== NTA
) {
1493 else if (stateUpdate
== Bogus
) {
1496 else if (state
== Indeterminate
) {
1497 state
= stateUpdate
;
1499 else if (stateUpdate
== Insecure
) {
1500 if (state
!= Bogus
) {
1504 LOG(", validation state is now "<<std::string(vStates
[state
])<<endl
);
1507 vState
SyncRes::getTA(const DNSName
& zone
, dsmap_t
& ds
)
1509 auto luaLocal
= g_luaconfs
.getLocal();
1511 if (luaLocal
->dsAnchors
.empty()) {
1512 LOG(d_prefix
<<": No trust anchors configured, everything is Insecure"<<endl
);
1513 /* We have no TA, everything is insecure */
1518 if (haveNegativeTrustAnchor(luaLocal
->negAnchors
, zone
, reason
)) {
1519 LOG(d_prefix
<<": got NTA for '"<<zone
<<"'"<<endl
);
1523 if (getTrustAnchor(luaLocal
->dsAnchors
, zone
, ds
)) {
1524 LOG(d_prefix
<<": got TA for '"<<zone
<<"'"<<endl
);
1528 LOG(d_prefix
<<": no TA found for '"<<zone
<<"' among "<< luaLocal
->dsAnchors
.size()<<endl
);
1531 if (zone
.isRoot()) {
1532 /* No TA for the root */
1536 return Indeterminate
;
1539 static size_t countSupportedDS(const dsmap_t
& dsmap
)
1543 for (const auto& ds
: dsmap
) {
1544 if (isSupportedDS(ds
)) {
1552 vState
SyncRes::getDSRecords(const DNSName
& zone
, dsmap_t
& ds
, bool taOnly
, unsigned int depth
, bool bogusOnNXD
, bool* foundCut
)
1554 vState result
= getTA(zone
, ds
);
1556 if (result
!= Indeterminate
|| taOnly
) {
1558 *foundCut
= (result
!= Indeterminate
);
1562 if (countSupportedDS(ds
) == 0) {
1570 else if (result
== NTA
) {
1577 bool oldSkipCNAME
= d_skipCNAMECheck
;
1578 d_skipCNAMECheck
= true;
1580 std::set
<GetBestNSAnswer
> beenthere
;
1581 std::vector
<DNSRecord
> dsrecords
;
1583 vState state
= Indeterminate
;
1584 int rcode
= doResolve(zone
, QType(QType::DS
), dsrecords
, depth
+ 1, beenthere
, state
);
1585 d_skipCNAMECheck
= oldSkipCNAME
;
1587 if (rcode
== RCode::NoError
|| (rcode
== RCode::NXDomain
&& !bogusOnNXD
)) {
1589 uint8_t bestDigestType
= 0;
1591 if (state
== Secure
) {
1592 bool gotCNAME
= false;
1593 for (const auto& record
: dsrecords
) {
1594 if (record
.d_type
== QType::DS
) {
1595 const auto dscontent
= getRR
<DSRecordContent
>(record
);
1596 if (dscontent
&& isSupportedDS(*dscontent
)) {
1597 // Make GOST a lower prio than SHA256
1598 if (dscontent
->d_digesttype
== DNSSECKeeper::GOST
&& bestDigestType
== DNSSECKeeper::SHA256
) {
1601 if (dscontent
->d_digesttype
> bestDigestType
|| (bestDigestType
== DNSSECKeeper::GOST
&& dscontent
->d_digesttype
== DNSSECKeeper::SHA256
)) {
1602 bestDigestType
= dscontent
->d_digesttype
;
1604 ds
.insert(*dscontent
);
1607 else if (record
.d_type
== QType::CNAME
&& record
.d_name
== zone
) {
1612 /* RFC 4509 section 3: "Validator implementations SHOULD ignore DS RRs containing SHA-1
1613 * digests if DS RRs with SHA-256 digests are present in the DS RRset."
1614 * As SHA348 is specified as well, the spirit of the this line is "use the best algorithm".
1616 for (auto dsrec
= ds
.begin(); dsrec
!= ds
.end(); ) {
1617 if (dsrec
->d_digesttype
!= bestDigestType
) {
1618 dsrec
= ds
.erase(dsrec
);
1625 if (rcode
== RCode::NoError
&& ds
.empty()) {
1627 if (gotCNAME
|| denialProvesNoDelegation(zone
, dsrecords
)) {
1628 /* we are still inside the same Secure zone */
1638 } else if (foundCut
&& rcode
== RCode::NoError
&& !ds
.empty()) {
1646 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
1650 bool SyncRes::haveExactValidationStatus(const DNSName
& domain
)
1652 if (!shouldValidate()) {
1655 const auto& it
= d_cutStates
.find(domain
);
1656 if (it
!= d_cutStates
.cend()) {
1662 vState
SyncRes::getValidationStatus(const DNSName
& subdomain
, bool allowIndeterminate
)
1664 vState result
= Indeterminate
;
1666 if (!shouldValidate()) {
1669 DNSName
name(subdomain
);
1671 const auto& it
= d_cutStates
.find(name
);
1672 if (it
!= d_cutStates
.cend()) {
1673 if (allowIndeterminate
|| it
->second
!= Indeterminate
) {
1674 LOG(d_prefix
<<": got status "<<vStates
[it
->second
]<<" for name "<<subdomain
<<" (from "<<name
<<")"<<endl
);
1679 while (name
.chopOff());
1684 bool SyncRes::lookForCut(const DNSName
& qname
, unsigned int depth
, const vState existingState
, vState
& newState
)
1686 bool foundCut
= false;
1688 vState dsState
= getDSRecords(qname
, ds
, newState
== Bogus
|| existingState
== Insecure
|| existingState
== Bogus
, depth
, false, &foundCut
);
1690 if (dsState
!= Indeterminate
) {
1697 void SyncRes::computeZoneCuts(const DNSName
& begin
, const DNSName
& end
, unsigned int depth
)
1699 if(!begin
.isPartOf(end
)) {
1700 LOG(d_prefix
<<" "<<begin
.toLogString()<<" is not part of "<<end
.toString()<<endl
);
1701 throw PDNSException(begin
.toLogString() + " is not part of " + end
.toString());
1704 if (d_cutStates
.count(begin
) != 0) {
1709 vState cutState
= getDSRecords(end
, ds
, false, depth
);
1710 LOG(d_prefix
<<": setting cut state for "<<end
<<" to "<<vStates
[cutState
]<<endl
);
1711 d_cutStates
[end
] = cutState
;
1713 if (!shouldValidate()) {
1718 std::vector
<string
> labelsToAdd
= begin
.makeRelative(end
).getRawLabels();
1720 bool oldSkipCNAME
= d_skipCNAMECheck
;
1721 d_skipCNAMECheck
= true;
1723 while(qname
!= begin
) {
1724 if (labelsToAdd
.empty())
1727 qname
.prependRawLabel(labelsToAdd
.back());
1728 labelsToAdd
.pop_back();
1729 LOG(d_prefix
<<": - Looking for a cut at "<<qname
<<endl
);
1731 const auto cutIt
= d_cutStates
.find(qname
);
1732 if (cutIt
!= d_cutStates
.cend()) {
1733 if (cutIt
->second
!= Indeterminate
) {
1734 LOG(d_prefix
<<": - Cut already known at "<<qname
<<endl
);
1735 cutState
= cutIt
->second
;
1740 /* no need to look for NS and DS if we are already insecure or bogus,
1743 if (cutState
== Insecure
|| cutState
== Bogus
) {
1745 vState newState
= getDSRecords(qname
, cutDS
, true, depth
);
1746 if (newState
== Indeterminate
) {
1750 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[newState
]<<endl
);
1751 cutState
= newState
;
1753 d_cutStates
[qname
] = cutState
;
1758 vState newState
= Indeterminate
;
1759 /* temporarily mark as Indeterminate, so that we won't enter an endless loop
1760 trying to determine that zone cut again. */
1761 d_cutStates
[qname
] = newState
;
1762 bool foundCut
= lookForCut(qname
, depth
+ 1, cutState
, newState
);
1764 LOG(d_prefix
<<": - Found cut at "<<qname
<<endl
);
1765 if (newState
!= Indeterminate
) {
1766 cutState
= newState
;
1768 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[cutState
]<<endl
);
1769 d_cutStates
[qname
] = cutState
;
1772 /* remove the temporary cut */
1773 LOG(d_prefix
<<qname
<<": removing cut state for "<<qname
<<endl
);
1774 d_cutStates
.erase(qname
);
1778 d_skipCNAMECheck
= oldSkipCNAME
;
1780 LOG(d_prefix
<<": list of cuts from "<<begin
<<" to "<<end
<<endl
);
1781 for (const auto& cut
: d_cutStates
) {
1782 if (cut
.first
.isRoot() || (begin
.isPartOf(cut
.first
) && cut
.first
.isPartOf(end
))) {
1783 LOG(" - "<<cut
.first
<<": "<<vStates
[cut
.second
]<<endl
);
1788 vState
SyncRes::validateDNSKeys(const DNSName
& zone
, const std::vector
<DNSRecord
>& dnskeys
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, unsigned int depth
)
1791 if (!signatures
.empty()) {
1792 DNSName signer
= getSigner(signatures
);
1794 if (!signer
.empty() && zone
.isPartOf(signer
)) {
1795 vState state
= getDSRecords(signer
, ds
, false, depth
);
1797 if (state
!= Secure
) {
1803 skeyset_t tentativeKeys
;
1804 std::vector
<shared_ptr
<DNSRecordContent
> > toSign
;
1806 for (const auto& dnskey
: dnskeys
) {
1807 if (dnskey
.d_type
== QType::DNSKEY
) {
1808 auto content
= getRR
<DNSKEYRecordContent
>(dnskey
);
1810 tentativeKeys
.insert(content
);
1811 toSign
.push_back(content
);
1816 LOG(d_prefix
<<": trying to validate "<<std::to_string(tentativeKeys
.size())<<" DNSKEYs with "<<std::to_string(ds
.size())<<" DS"<<endl
);
1817 skeyset_t validatedKeys
;
1818 validateDNSKeysAgainstDS(d_now
.tv_sec
, zone
, ds
, tentativeKeys
, toSign
, signatures
, validatedKeys
);
1820 LOG(d_prefix
<<": we now have "<<std::to_string(validatedKeys
.size())<<" DNSKEYs"<<endl
);
1822 /* if we found at least one valid RRSIG covering the set,
1823 all tentative keys are validated keys. Otherwise it means
1824 we haven't found at least one DNSKEY and a matching RRSIG
1825 covering this set, this looks Bogus. */
1826 if (validatedKeys
.size() != tentativeKeys
.size()) {
1827 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
1834 vState
SyncRes::getDNSKeys(const DNSName
& signer
, skeyset_t
& keys
, unsigned int depth
)
1836 std::vector
<DNSRecord
> records
;
1837 std::set
<GetBestNSAnswer
> beenthere
;
1838 LOG(d_prefix
<<"Retrieving DNSKeys for "<<signer
<<endl
);
1840 vState state
= Indeterminate
;
1841 /* following CNAME might lead to us to the wrong DNSKEY */
1842 bool oldSkipCNAME
= d_skipCNAMECheck
;
1843 d_skipCNAMECheck
= true;
1844 int rcode
= doResolve(signer
, QType(QType::DNSKEY
), records
, depth
+ 1, beenthere
, state
);
1845 d_skipCNAMECheck
= oldSkipCNAME
;
1847 if (rcode
== RCode::NoError
) {
1848 if (state
== Secure
) {
1849 for (const auto& key
: records
) {
1850 if (key
.d_type
== QType::DNSKEY
) {
1851 auto content
= getRR
<DNSKEYRecordContent
>(key
);
1853 keys
.insert(content
);
1858 LOG(d_prefix
<<"Retrieved "<<keys
.size()<<" DNSKeys for "<<signer
<<", state is "<<vStates
[state
]<<endl
);
1862 LOG(d_prefix
<<"Returning Bogus state from "<<__func__
<<"("<<signer
<<")"<<endl
);
1866 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
)
1869 if (!signatures
.empty()) {
1870 const DNSName signer
= getSigner(signatures
);
1871 if (!signer
.empty() && name
.isPartOf(signer
)) {
1872 if ((qtype
== QType::DNSKEY
|| qtype
== QType::DS
) && signer
== qname
) {
1873 /* we are already retrieving those keys, sorry */
1874 return Indeterminate
;
1876 vState state
= getDNSKeys(signer
, keys
, depth
);
1877 if (state
!= Secure
) {
1882 LOG(d_prefix
<<"Bogus!"<<endl
);
1886 std::vector
<std::shared_ptr
<DNSRecordContent
> > recordcontents
;
1887 for (const auto& record
: records
) {
1888 recordcontents
.push_back(record
.d_content
);
1891 LOG(d_prefix
<<"Going to validate "<<recordcontents
.size()<< " record contents with "<<signatures
.size()<<" sigs and "<<keys
.size()<<" keys for "<<name
<<endl
);
1892 if (validateWithKeySet(d_now
.tv_sec
, name
, recordcontents
, signatures
, keys
, false)) {
1893 LOG(d_prefix
<<"Secure!"<<endl
);
1897 LOG(d_prefix
<<"Bogus!"<<endl
);
1901 RCode::rcodes_
SyncRes::updateCacheFromRecords(unsigned int depth
, LWResult
& lwr
, const DNSName
& qname
, const QType
& qtype
, const DNSName
& auth
, bool wasForwarded
, const boost::optional
<Netmask
> ednsmask
, vState
& state
, bool& needWildcardProof
, unsigned int& wildcardLabelsCount
)
1908 prefix
.append(depth
, ' ');
1911 std::vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1912 const unsigned int labelCount
= qname
.countLabels();
1913 bool isCNAMEAnswer
= false;
1914 for(const auto& rec
: lwr
.d_records
) {
1915 if (rec
.d_class
!= QClass::IN
) {
1919 if(!isCNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
) {
1920 isCNAMEAnswer
= true;
1923 /* if we have a positive answer synthetized from a wildcard,
1924 we need to store the corresponding NSEC/NSEC3 records proving
1925 that the exact name did not exist in the negative cache */
1926 if(needWildcardProof
) {
1927 if (nsecTypes
.count(rec
.d_type
)) {
1928 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
1930 else if (rec
.d_type
== QType::RRSIG
) {
1931 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1932 if (rrsig
&& nsecTypes
.count(rrsig
->d_type
)) {
1933 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
1937 if(rec
.d_type
== QType::RRSIG
) {
1938 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1940 /* As illustrated in rfc4035's Appendix B.6, the RRSIG label
1941 count can be lower than the name's label count if it was
1942 synthetized from the wildcard. Note that the difference might
1944 if (rec
.d_name
== qname
&& rrsig
->d_labels
< labelCount
) {
1945 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthetized from a wildcard, we need a wildcard proof"<<endl
);
1946 needWildcardProof
= true;
1947 wildcardLabelsCount
= rrsig
->d_labels
;
1950 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
1951 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
1952 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
);
1957 // reap all answers from this packet that are acceptable
1958 for(auto& rec
: lwr
.d_records
) {
1959 if(rec
.d_type
== QType::OPT
) {
1960 LOG(prefix
<<qname
<<": OPT answer '"<<rec
.d_name
<<"' from '"<<auth
<<"' nameservers" <<endl
);
1963 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
<<" ");
1964 if(rec
.d_type
== QType::ANY
) {
1965 LOG("NO! - we don't accept 'ANY'-typed data"<<endl
);
1969 if(rec
.d_class
!= QClass::IN
) {
1970 LOG("NO! - we don't accept records for any other class than 'IN'"<<endl
);
1974 if(rec
.d_name
.isPartOf(auth
)) {
1975 if(rec
.d_type
== QType::RRSIG
) {
1976 LOG("RRSIG - separate"<<endl
);
1978 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
)) {
1979 LOG("NO! Is from delegation-only zone"<<endl
);
1981 return RCode::NXDomain
;
1984 bool haveLogged
= false;
1985 if (!t_sstorage
.domainmap
->empty()) {
1986 // Check if we are authoritative for a zone in this answer
1987 DNSName
tmp_qname(rec
.d_name
);
1988 auto auth_domain_iter
=getBestAuthZone(&tmp_qname
);
1989 if(auth_domain_iter
!=t_sstorage
.domainmap
->end() &&
1990 auth
.countLabels() <= auth_domain_iter
->first
.countLabels()) {
1991 if (auth_domain_iter
->first
!= auth
) {
1992 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter
->first
<<endl
);
1995 LOG("YES! - This answer was ");
1996 if (!wasForwarded
) {
1997 LOG("retrieved from the local auth store.");
1999 LOG("received from a server we forward to.");
2010 rec
.d_ttl
=min(s_maxcachettl
, rec
.d_ttl
);
2013 dr
.d_ttl
+= d_now
.tv_sec
;
2014 dr
.d_place
=DNSResourceRecord::ANSWER
;
2015 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(dr
);
2023 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2024 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)
2025 uint32_t lowestTTD
=computeLowestTTD(i
->second
.records
, i
->second
.signatures
, i
->second
.signaturesTTL
);
2027 for(auto& record
: i
->second
.records
)
2028 record
.d_ttl
= lowestTTD
; // boom
2031 // cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
2032 // cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
2035 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2037 if(i
->second
.records
.empty()) // this happens when we did store signatures, but passed on the records themselves
2040 /* Even if the AA bit is set, additional data cannot be considered
2041 as authoritative. This is especially important during validation
2042 because keeping records in the additional section is allowed even
2043 if the corresponding RRSIGs are not included, without setting the TC
2044 bit, as stated in rfc4035's section 3.1.1. Including RRSIG RRs in a Response:
2045 "When placing a signed RRset in the Additional section, the name
2046 server MUST also place its RRSIG RRs in the Additional section.
2047 If space does not permit inclusion of both the RRset and its
2048 associated RRSIG RRs, the name server MAY retain the RRset while
2049 dropping the RRSIG RRs. If this happens, the name server MUST NOT
2050 set the TC bit solely because these RRSIG RRs didn't fit."
2052 bool isAA
= lwr
.d_aabit
&& i
->first
.place
!= DNSResourceRecord::ADDITIONAL
;
2053 if (isAA
&& isCNAMEAnswer
&& (i
->first
.place
!= DNSResourceRecord::ANSWER
|| i
->first
.type
!= QType::CNAME
)) {
2056 Note that the answer section of an authoritative answer normally
2057 contains only authoritative data. However when the name sought is an
2058 alias (see section 10.1.1) only the record describing that alias is
2059 necessarily authoritative. Clients should assume that other records
2060 may have come from the server's cache. Where authoritative answers
2061 are required, the client should query again, using the canonical name
2062 associated with the alias.
2067 vState recordState
= getValidationStatus(i
->first
.name
, false);
2068 LOG(d_prefix
<<": got initial zone status "<<vStates
[recordState
]<<" for record "<<i
->first
.name
<<endl
);
2070 if (shouldValidate() && recordState
== Secure
) {
2071 vState initialState
= recordState
;
2074 if (i
->first
.place
!= DNSResourceRecord::ADDITIONAL
) {
2075 /* the additional entries can be insecure,
2077 "Glue address RRsets associated with delegations MUST NOT be signed"
2079 if (i
->first
.type
== QType::DNSKEY
&& i
->first
.place
== DNSResourceRecord::ANSWER
) {
2080 LOG(d_prefix
<<"Validating DNSKEY for "<<i
->first
.name
<<endl
);
2081 recordState
= validateDNSKeys(i
->first
.name
, i
->second
.records
, i
->second
.signatures
, depth
);
2084 LOG(d_prefix
<<"Validating non-additional record for "<<i
->first
.name
<<endl
);
2085 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2086 /* 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 */
2087 if (qtype
== QType::NS
&& i
->second
.signatures
.empty() && recordState
== Bogus
&& haveExactValidationStatus(i
->first
.name
) && getValidationStatus(i
->first
.name
) == Indeterminate
) {
2088 recordState
= Indeterminate
;
2094 /* in a non authoritative answer, we only care about the DS record (or lack of) */
2095 if ((i
->first
.type
== QType::DS
|| i
->first
.type
== QType::NSEC
|| i
->first
.type
== QType::NSEC3
) && i
->first
.place
== DNSResourceRecord::AUTHORITY
) {
2096 LOG(d_prefix
<<"Validating DS record for "<<i
->first
.name
<<endl
);
2097 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2101 if (initialState
== Secure
&& state
!= recordState
) {
2102 updateValidationState(state
, recordState
);
2106 if (shouldValidate()) {
2107 LOG(d_prefix
<<"Skipping validation because the current state is "<<vStates
[recordState
]<<endl
);
2111 /* We don't need to store NSEC3 records in the positive cache because:
2112 - we don't allow direct NSEC3 queries
2113 - denial of existence proofs in wildcard expanded positive responses are stored in authorityRecs
2114 - denial of existence proofs for negative responses are stored in the negative cache
2116 if (i
->first
.type
!= QType::NSEC3
) {
2117 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
);
2120 if(i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
)
2124 return RCode::NoError
;
2127 void SyncRes::updateDenialValidationState(NegCache::NegCacheEntry
& ne
, vState
& state
, const dState denialState
, const dState expectedState
, bool allowOptOut
)
2129 if (denialState
== expectedState
) {
2130 ne
.d_validationState
= Secure
;
2133 if (denialState
== OPTOUT
&& allowOptOut
) {
2134 LOG(d_prefix
<<"OPT-out denial found for "<<ne
.d_name
<<endl
);
2135 ne
.d_validationState
= Secure
;
2138 else if (denialState
== INSECURE
) {
2139 LOG(d_prefix
<<"Insecure denial found for "<<ne
.d_name
<<", returning Insecure"<<endl
);
2140 ne
.d_validationState
= Insecure
;
2143 LOG(d_prefix
<<"Invalid denial found for "<<ne
.d_name
<<", returning Bogus, res="<<denialState
<<", expectedState="<<expectedState
<<endl
);
2144 ne
.d_validationState
= Bogus
;
2146 updateValidationState(state
, ne
.d_validationState
);
2150 dState
SyncRes::getDenialValidationState(NegCache::NegCacheEntry
& ne
, const vState state
, const dState expectedState
, bool referralToUnsigned
)
2152 cspmap_t csp
= harvestCSPFromNE(ne
);
2153 return getDenial(csp
, ne
.d_name
, ne
.d_qtype
.getCode(), referralToUnsigned
, expectedState
== NXQTYPE
);
2156 bool SyncRes::processRecords(const std::string
& prefix
, const DNSName
& qname
, const QType
& qtype
, const DNSName
& auth
, LWResult
& lwr
, const bool sendRDQuery
, vector
<DNSRecord
>& ret
, set
<DNSName
>& nsset
, DNSName
& newtarget
, DNSName
& newauth
, bool& realreferral
, bool& negindic
, vState
& state
, const bool needWildcardProof
, const unsigned int wildcardLabelsCount
)
2160 for(auto& rec
: lwr
.d_records
) {
2161 if (rec
.d_type
!=QType::OPT
&& rec
.d_class
!=QClass::IN
)
2164 if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2165 lwr
.d_rcode
==RCode::NXDomain
&& qname
.isPartOf(rec
.d_name
) && rec
.d_name
.isPartOf(auth
)) {
2166 LOG(prefix
<<qname
<<": got negative caching indication for name '"<<qname
<<"' (accept="<<rec
.d_name
.isPartOf(auth
)<<"), newtarget='"<<newtarget
<<"'"<<endl
);
2168 rec
.d_ttl
= min(rec
.d_ttl
, s_maxnegttl
);
2169 if(newtarget
.empty()) // only add a SOA if we're not going anywhere after this
2172 NegCache::NegCacheEntry ne
;
2174 uint32_t lowestTTL
= rec
.d_ttl
;
2175 /* if we get an NXDomain answer with a CNAME, the name
2176 does exist but the target does not */
2177 ne
.d_name
= newtarget
.empty() ? qname
: newtarget
;
2178 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2179 ne
.d_auth
= rec
.d_name
;
2180 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2181 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2183 if (state
== Secure
) {
2184 dState denialState
= getDenialValidationState(ne
, state
, NXDOMAIN
, false);
2185 updateDenialValidationState(ne
, state
, denialState
, NXDOMAIN
, false);
2188 ne
.d_validationState
= state
;
2191 /* if we get an NXDomain answer with a CNAME, let's not cache the
2192 target, even the server was authoritative for it,
2193 and do an additional query for the CNAME target.
2194 We have a regression test making sure we do exactly that.
2196 if(!wasVariable() && newtarget
.empty()) {
2197 t_sstorage
.negcache
.add(ne
);
2198 if(s_rootNXTrust
&& ne
.d_auth
.isRoot() && auth
.isRoot()) {
2199 ne
.d_name
= ne
.d_name
.getLastLabel();
2200 t_sstorage
.negcache
.add(ne
);
2206 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_type
==QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
) {
2208 if (auto content
= getRR
<CNAMERecordContent
>(rec
)) {
2209 newtarget
=content
->getTarget();
2212 /* if we have a positive answer synthetized from a wildcard, we need to
2213 return the corresponding NSEC/NSEC3 records from the AUTHORITY section
2214 proving that the exact name did not exist */
2215 else if(needWildcardProof
&& (rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::AUTHORITY
) {
2216 ret
.push_back(rec
); // enjoy your DNSSEC
2218 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
2219 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&&
2221 rec
.d_type
==qtype
.getCode() || ((lwr
.d_aabit
|| sendRDQuery
) && qtype
== QType(QType::ANY
))
2225 LOG(prefix
<<qname
<<": answer is in: resolved to '"<< rec
.d_content
->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"'"<<endl
);
2230 if (state
== Secure
&& needWildcardProof
) {
2231 /* We have a positive answer synthetized from a wildcard, we need to check that we have
2232 proof that the exact name doesn't exist so the wildcard can be used,
2233 as described in section 5.3.4 of RFC 4035 and 5.3 of FRC 7129.
2235 NegCache::NegCacheEntry ne
;
2237 uint32_t lowestTTL
= rec
.d_ttl
;
2239 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2240 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2242 cspmap_t csp
= harvestCSPFromNE(ne
);
2243 dState res
= getDenial(csp
, qname
, ne
.d_qtype
.getCode(), false, false, false, wildcardLabelsCount
);
2244 if (res
!= NXDOMAIN
) {
2246 if (res
== INSECURE
) {
2247 /* Some part could not be validated, for example a NSEC3 record with a too large number of iterations,
2248 this is not enough to warrant a Bogus, but go Insecure. */
2250 LOG(d_prefix
<<"Unable to validate denial in wildcard expanded positive response found for "<<qname
<<", returning Insecure, res="<<res
<<endl
);
2253 LOG(d_prefix
<<"Invalid denial in wildcard expanded positive response found for "<<qname
<<", returning Bogus, res="<<res
<<endl
);
2256 updateValidationState(state
, st
);
2257 /* we already stored the record with a different validation status, let's fix it */
2258 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qtype
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, lwr
.d_aabit
, st
);
2262 else if((rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::ANSWER
) {
2263 if(rec
.d_type
!= QType::RRSIG
|| rec
.d_name
== qname
)
2264 ret
.push_back(rec
); // enjoy your DNSSEC
2266 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::NS
&& qname
.isPartOf(rec
.d_name
)) {
2267 if(moreSpecificThan(rec
.d_name
,auth
)) {
2269 LOG(prefix
<<qname
<<": got NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2273 LOG(prefix
<<qname
<<": got upwards/level NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"', had '"<<auth
<<"'"<<endl
);
2275 if (auto content
= getRR
<NSRecordContent
>(rec
)) {
2276 nsset
.insert(content
->getNS());
2279 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::DS
&& qname
.isPartOf(rec
.d_name
)) {
2280 LOG(prefix
<<qname
<<": got DS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2282 else if(realreferral
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& (rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && newauth
.isPartOf(auth
)) {
2283 /* we might have received a denial of the DS, let's check */
2284 if (state
== Secure
) {
2285 NegCache::NegCacheEntry ne
;
2287 ne
.d_name
= newauth
;
2288 ne
.d_qtype
= QType::DS
;
2289 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2290 uint32_t lowestTTL
= rec
.d_ttl
;
2291 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2293 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, true);
2295 if (denialState
== NXQTYPE
|| denialState
== OPTOUT
|| denialState
== INSECURE
) {
2296 ne
.d_ttd
= lowestTTL
+ d_now
.tv_sec
;
2297 ne
.d_validationState
= Secure
;
2298 LOG(prefix
<<qname
<<": got negative indication of DS record for '"<<newauth
<<"'"<<endl
);
2300 if(!wasVariable()) {
2301 t_sstorage
.negcache
.add(ne
);
2304 if (qname
== newauth
&& qtype
== QType::DS
) {
2305 /* we are actually done! */
2312 else if(!done
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2313 lwr
.d_rcode
==RCode::NoError
&& qname
.isPartOf(rec
.d_name
)) {
2314 LOG(prefix
<<qname
<<": got negative caching indication for '"<< qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
2316 if(!newtarget
.empty()) {
2317 LOG(prefix
<<qname
<<": Hang on! Got a redirect to '"<<newtarget
<<"' already"<<endl
);
2320 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2323 NegCache::NegCacheEntry ne
;
2324 ne
.d_auth
= rec
.d_name
;
2325 uint32_t lowestTTL
= rec
.d_ttl
;
2328 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2329 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2331 if (state
== Secure
) {
2332 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, false);
2333 updateDenialValidationState(ne
, state
, denialState
, NXQTYPE
, qtype
== QType::DS
);
2335 ne
.d_validationState
= state
;
2338 if(!wasVariable()) {
2339 if(qtype
.getCode()) { // prevents us from blacking out a whole domain
2340 t_sstorage
.negcache
.add(ne
);
2351 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
)
2357 if(d_outqueries
+ d_throttledqueries
> s_maxqperq
) {
2358 throw ImmediateServFailException("more than "+std::to_string(s_maxqperq
)+" (max-qperq) queries sent while resolving "+qname
.toLogString());
2361 if(s_maxtotusec
&& d_totUsec
> s_maxtotusec
) {
2362 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");
2366 LOG(prefix
<<qname
<<": using TCP with "<< remoteIP
.toStringWithPort() <<endl
);
2371 if(d_pdl
&& d_pdl
->preoutquery(remoteIP
, d_requestor
, qname
, qtype
, doTCP
, lwr
.d_records
, resolveret
)) {
2372 LOG(prefix
<<qname
<<": query handled by Lua"<<endl
);
2375 ednsmask
=getEDNSSubnetMask(d_requestor
, qname
, remoteIP
);
2377 LOG(prefix
<<qname
<<": Adding EDNS Client Subnet Mask "<<ednsmask
->toString()<<" to query"<<endl
);
2380 resolveret
= asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(),
2381 doTCP
, sendRDQuery
, &d_now
, ednsmask
, &lwr
); // <- we go out on the wire!
2384 LOG(prefix
<<qname
<<": Received EDNS Client Subnet Mask "<<ednsmask
->toString()<<" on response"<<endl
);
2388 /* preoutquery killed the query by setting dq.rcode to -3 */
2389 if(resolveret
==-3) {
2390 throw ImmediateServFailException("Query killed by policy");
2393 d_totUsec
+= lwr
.d_usec
;
2394 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
2396 if(resolveret
!= 1) {
2397 /* Error while resolving */
2398 if(resolveret
== 0) {
2401 LOG(prefix
<<qname
<<": timeout resolving after "<<lwr
.d_usec
/1000.0<<"msec "<< (doTCP
? "over TCP" : "")<<endl
);
2403 s_outgoingtimeouts
++;
2405 if(remoteIP
.sin4
.sin_family
== AF_INET
)
2406 s_outgoing4timeouts
++;
2408 s_outgoing6timeouts
++;
2410 else if(resolveret
== -2) {
2411 /* OS resource limit reached */
2412 LOG(prefix
<<qname
<<": hit a local resource limit resolving"<< (doTCP
? " over TCP" : "")<<", probable error: "<<stringerror()<<endl
);
2413 g_stats
.resourceLimits
++;
2416 /* -1 means server unreachable */
2419 LOG(prefix
<<qname
<<": error resolving from "<<remoteIP
.toString()<< (doTCP
? " over TCP" : "") <<", possible error: "<<strerror(errno
)<< endl
);
2422 if(resolveret
!= -2) { // don't account for resource limits, they are our own fault
2423 t_sstorage
.nsSpeeds
[nsName
].submit(remoteIP
, 1000000, &d_now
); // 1 sec
2425 // code below makes sure we don't filter COM or the root
2426 if (s_serverdownmaxfails
> 0 && (auth
!= g_rootdnsname
) && t_sstorage
.fails
.incr(remoteIP
) >= s_serverdownmaxfails
) {
2427 LOG(prefix
<<qname
<<": Max fails reached resolving on "<< remoteIP
.toString() <<". Going full throttle for "<< s_serverdownthrottletime
<<" seconds" <<endl
);
2428 // mark server as down
2429 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0), s_serverdownthrottletime
, 10000);
2431 else if (resolveret
== -1) {
2432 // unreachable, 1 minute or 100 queries
2433 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 100);
2437 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 10, 5);
2444 /* we got an answer */
2445 if(lwr
.d_rcode
==RCode::ServFail
|| lwr
.d_rcode
==RCode::Refused
) {
2446 LOG(prefix
<<qname
<<": "<<nsName
<<" ("<<remoteIP
.toString()<<") returned a "<< (lwr
.d_rcode
==RCode::ServFail
? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl
);
2447 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
2451 /* this server sent a valid answer, mark it backup up if it was down */
2452 if(s_serverdownmaxfails
> 0) {
2453 t_sstorage
.fails
.clear(remoteIP
);
2460 LOG(prefix
<<qname
<<": truncated bit set, over TCP?"<<endl
);
2461 /* let's treat that as a ServFail answer from this server */
2462 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
2472 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
)
2477 prefix
.append(depth
, ' ');
2481 for(auto& rec
: lwr
.d_records
) {
2482 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumTTL
);
2486 bool needWildcardProof
= false;
2487 unsigned int wildcardLabelsCount
;
2488 *rcode
= updateCacheFromRecords(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, state
, needWildcardProof
, wildcardLabelsCount
);
2489 if (*rcode
!= RCode::NoError
) {
2493 LOG(prefix
<<qname
<<": determining status after receiving this packet"<<endl
);
2496 bool realreferral
=false, negindic
=false;
2500 bool done
= processRecords(prefix
, qname
, qtype
, auth
, lwr
, sendRDQuery
, ret
, nsset
, newtarget
, newauth
, realreferral
, negindic
, state
, needWildcardProof
, wildcardLabelsCount
);
2503 LOG(prefix
<<qname
<<": status=got results, this level of recursion done"<<endl
);
2504 LOG(prefix
<<qname
<<": validation status is "<<vStates
[state
]<<endl
);
2505 *rcode
= RCode::NoError
;
2509 if(!newtarget
.empty()) {
2510 if(newtarget
== qname
) {
2511 LOG(prefix
<<qname
<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl
);
2512 *rcode
= RCode::ServFail
;
2517 LOG(prefix
<<qname
<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl
);
2518 *rcode
= RCode::ServFail
;
2522 if (qtype
== QType::DS
) {
2523 LOG(prefix
<<qname
<<": status=got a CNAME referral, but we are looking for a DS"<<endl
);
2526 addNXNSECS(ret
, lwr
.d_records
);
2528 *rcode
= RCode::NoError
;
2532 LOG(prefix
<<qname
<<": status=got a CNAME referral, starting over with "<<newtarget
<<endl
);
2534 set
<GetBestNSAnswer
> beenthere2
;
2535 vState cnameState
= Indeterminate
;
2536 *rcode
= doResolve(newtarget
, qtype
, ret
, depth
+ 1, beenthere2
, cnameState
);
2537 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
2538 updateValidationState(state
, cnameState
);
2543 if(lwr
.d_rcode
== RCode::NXDomain
) {
2544 LOG(prefix
<<qname
<<": status=NXDOMAIN, we are done "<<(negindic
? "(have negative SOA)" : "")<<endl
);
2547 addNXNSECS(ret
, lwr
.d_records
);
2549 *rcode
= RCode::NXDomain
;
2553 if(nsset
.empty() && !lwr
.d_rcode
&& (negindic
|| lwr
.d_aabit
|| sendRDQuery
)) {
2554 LOG(prefix
<<qname
<<": status=noerror, other types may exist, but we are done "<<(negindic
? "(have negative SOA) " : "")<<(lwr
.d_aabit
? "(have aa bit) " : "")<<endl
);
2556 if(state
== Secure
&& lwr
.d_aabit
&& !negindic
) {
2557 updateValidationState(state
, Bogus
);
2561 addNXNSECS(ret
, lwr
.d_records
);
2563 *rcode
= RCode::NoError
;
2568 LOG(prefix
<<qname
<<": status=did not resolve, got "<<(unsigned int)nsset
.size()<<" NS, ");
2570 nameservers
.clear();
2571 for (auto const &nameserver
: nsset
) {
2573 d_appliedPolicy
= dfe
.getProcessingPolicy(nameserver
, d_discardedPolicies
);
2574 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
2575 LOG("however "<<nameserver
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
2580 nameservers
.insert({nameserver
, {{}, false}});
2582 LOG("looping to them"<<endl
);
2583 *gotNewServers
= true;
2593 * -1 in case of no results
2594 * -2 when a FilterEngine Policy was hit
2597 int SyncRes::doResolveAt(NsSet
&nameservers
, DNSName auth
, bool flawedNSSet
, const DNSName
&qname
, const QType
&qtype
,
2598 vector
<DNSRecord
>&ret
,
2599 unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
, vState
& state
)
2601 auto luaconfsLocal
= g_luaconfs
.getLocal();
2605 prefix
.append(depth
, ' ');
2608 LOG(prefix
<<qname
<<": Cache consultations done, have "<<(unsigned int)nameservers
.size()<<" NS to contact");
2610 if (nameserversBlockedByRPZ(luaconfsLocal
->dfe
, nameservers
)) {
2616 for(;;) { // we may get more specific nameservers
2617 vector
<DNSName
> rnameservers
= shuffleInSpeedOrder(nameservers
, doLog() ? (prefix
+qname
.toString()+": ") : string() );
2619 for(auto tns
=rnameservers
.cbegin();;++tns
) {
2620 if(tns
==rnameservers
.cend()) {
2621 LOG(prefix
<<qname
<<": Failed to resolve via any of the "<<(unsigned int)rnameservers
.size()<<" offered NS at level '"<<auth
<<"'"<<endl
);
2622 if(!auth
.isRoot() && flawedNSSet
) {
2623 LOG(prefix
<<qname
<<": Ageing nameservers for level '"<<auth
<<"', next query might succeed"<<endl
);
2625 if(t_RC
->doAgeCache(d_now
.tv_sec
, auth
, QType::NS
, 10))
2626 g_stats
.nsSetInvalidations
++;
2631 bool cacheOnly
= false;
2632 // this line needs to identify the 'self-resolving' behaviour
2633 if(qname
== *tns
&& (qtype
.getCode() == QType::A
|| qtype
.getCode() == QType::AAAA
)) {
2634 /* we might have a glue entry in cache so let's try this NS
2635 but only if we have enough in the cache to know how to reach it */
2636 LOG(prefix
<<qname
<<": Using NS to resolve itself, but only using what we have in cache ("<<(1+tns
-rnameservers
.cbegin())<<"/"<<rnameservers
.size()<<")"<<endl
);
2640 typedef vector
<ComboAddress
> remoteIPs_t
;
2641 remoteIPs_t remoteIPs
;
2642 remoteIPs_t::const_iterator remoteIP
;
2643 bool pierceDontQuery
=false;
2644 bool sendRDQuery
=false;
2645 boost::optional
<Netmask
> ednsmask
;
2647 const bool wasForwarded
= tns
->empty() && (!nameservers
[*tns
].first
.empty());
2648 int rcode
= RCode::NoError
;
2649 bool gotNewServers
= false;
2651 if(tns
->empty() && !wasForwarded
) {
2652 LOG(prefix
<<qname
<<": Domain is out-of-band"<<endl
);
2653 /* setting state to indeterminate since validation is disabled for local auth zone,
2654 and Insecure would be misleading. */
2655 state
= Indeterminate
;
2656 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, lwr
.d_records
, depth
, lwr
.d_rcode
);
2660 /* we have received an answer, are we done ? */
2661 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, false, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
2665 if (gotNewServers
) {
2670 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
2671 remoteIPs
= retrieveAddressesForNS(prefix
, qname
, tns
, depth
, beenthere
, rnameservers
, nameservers
, sendRDQuery
, pierceDontQuery
, flawedNSSet
, cacheOnly
);
2673 if(remoteIPs
.empty()) {
2674 LOG(prefix
<<qname
<<": Failed to get IP for NS "<<*tns
<<", trying next if available"<<endl
);
2679 bool hitPolicy
{false};
2680 LOG(prefix
<<qname
<<": Resolved '"<<auth
<<"' NS "<<*tns
<<" to: ");
2681 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
2682 if(remoteIP
!= remoteIPs
.cbegin()) {
2685 LOG(remoteIP
->toString());
2686 if(nameserverIPBlockedByRPZ(luaconfsLocal
->dfe
, *remoteIP
)) {
2691 if (hitPolicy
) //implies d_wantsRPZ
2695 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
2696 LOG(prefix
<<qname
<<": Trying IP "<< remoteIP
->toStringWithPort() <<", asking '"<<qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
2698 if (throttledOrBlocked(prefix
, *remoteIP
, qname
, qtype
, pierceDontQuery
)) {
2702 bool truncated
= false;
2703 bool gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
2704 *tns
, *remoteIP
, false, &truncated
);
2705 if (gotAnswer
&& truncated
) {
2706 /* retry, over TCP this time */
2707 gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
2708 *tns
, *remoteIP
, true, &truncated
);
2715 LOG(prefix
<<qname
<<": Got "<<(unsigned int)lwr
.d_records
.size()<<" answers from "<<*tns
<<" ("<< remoteIP
->toString() <<"), rcode="<<lwr
.d_rcode
<<" ("<<RCode::to_s(lwr
.d_rcode
)<<"), aa="<<lwr
.d_aabit
<<", in "<<lwr
.d_usec
/1000<<"ms"<<endl
);
2717 /* // for you IPv6 fanatics :-)
2718 if(remoteIP->sin4.sin_family==AF_INET6)
2721 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
2723 t_sstorage
.nsSpeeds
[*tns
].submit(*remoteIP
, lwr
.d_usec
, &d_now
);
2725 /* we have received an answer, are we done ? */
2726 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
2730 if (gotNewServers
) {
2734 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100);
2737 if (gotNewServers
) {
2741 if(remoteIP
== remoteIPs
.cend()) // we tried all IP addresses, none worked
2750 void SyncRes::setIncomingECS(boost::optional
<const EDNSSubnetOpts
&> incomingECS
)
2752 d_incomingECS
= incomingECS
;
2754 if (d_incomingECS
->source
.getBits() == 0) {
2755 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0.
2756 But using an empty ECS in that case would mean inserting
2757 a non ECS-specific entry into the cache, preventing any further
2758 ECS-specific query to be sent.
2759 So instead we use the trick described in section 7.1.2:
2760 "The subsequent Recursive Resolver query to the Authoritative Nameserver
2761 will then either not include an ECS option or MAY optionally include
2762 its own address information, which is what the Authoritative
2763 Nameserver will almost certainly use to generate any Tailored
2764 Response in lieu of an option. This allows the answer to be handled
2765 by the same caching mechanism as other queries, with an explicit
2766 indicator of the applicable scope. Subsequent Stub Resolver queries
2767 for /0 can then be answered from this cached response.
2769 d_incomingECS
= s_ecsScopeZero
;
2770 d_incomingECSNetwork
= s_ecsScopeZero
.source
.getMaskedNetwork();
2773 uint8_t bits
= std::min(incomingECS
->source
.getBits(), (incomingECS
->source
.isIpv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
2774 d_incomingECS
->source
= Netmask(incomingECS
->source
.getNetwork(), bits
);
2775 d_incomingECSNetwork
= d_incomingECS
->source
.getMaskedNetwork();
2779 d_incomingECSNetwork
= ComboAddress();
2783 boost::optional
<Netmask
> SyncRes::getEDNSSubnetMask(const ComboAddress
& local
, const DNSName
&dn
, const ComboAddress
& rem
)
2785 boost::optional
<Netmask
> result
;
2788 if(d_incomingECSFound
) {
2789 trunc
= d_incomingECSNetwork
;
2790 bits
= d_incomingECS
->source
.getBits();
2792 else if(!local
.isIPv4() || local
.sin4
.sin_addr
.s_addr
) { // detect unset 'requestor'
2794 bits
= local
.isIPv4() ? 32 : 128;
2795 bits
= std::min(bits
, (trunc
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
2798 /* nothing usable */
2802 if(s_ednsdomains
.check(dn
) || s_ednssubnets
.match(rem
)) {
2803 trunc
.truncate(bits
);
2804 return boost::optional
<Netmask
>(Netmask(trunc
, bits
));
2810 void SyncRes::parseEDNSSubnetWhitelist(const std::string
& wlist
)
2812 vector
<string
> parts
;
2813 stringtok(parts
, wlist
, ",; ");
2814 for(const auto& a
: parts
) {
2816 s_ednssubnets
.addMask(Netmask(a
));
2819 s_ednsdomains
.add(DNSName(a
));
2824 // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
2825 int directResolve(const DNSName
& qname
, const QType
& qtype
, int qclass
, vector
<DNSRecord
>& ret
)
2828 gettimeofday(&now
, 0);
2831 int res
= sr
.beginResolve(qname
, QType(qtype
), qclass
, ret
);
2836 int SyncRes::getRootNS(struct timeval now
, asyncresolve_t asyncCallback
) {
2838 sr
.setDoEDNS0(true);
2839 sr
.setUpdatingRootNS();
2840 sr
.setDoDNSSEC(g_dnssecmode
!= DNSSECMode::Off
);
2841 sr
.setDNSSECValidationRequested(g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
);
2842 sr
.setAsyncCallback(asyncCallback
);
2844 vector
<DNSRecord
> ret
;
2847 res
=sr
.beginResolve(g_rootdnsname
, QType(QType::NS
), 1, ret
);
2848 if (g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
) {
2849 auto state
= sr
.getValidationState();
2851 throw PDNSException("Got Bogus validation result for .|NS");
2855 catch(const PDNSException
& e
) {
2856 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
2858 catch(const ImmediateServFailException
& e
) {
2859 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
2861 catch(const std::exception
& e
) {
2862 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.what()<<endl
;
2865 L
<<Logger::Error
<<"Failed to update . records, got an exception"<<endl
;
2869 L
<<Logger::Notice
<<"Refreshed . records"<<endl
;
2872 L
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;