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
= std::dynamic_pointer_cast
<ARecordContent
>(i
->d_content
))
680 ret
.push_back(rec
->getCA(53));
681 else if(auto aaaarec
= std::dynamic_pointer_cast
<AAAARecordContent
>(i
->d_content
))
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
= std::dynamic_pointer_cast
<AAAARecordContent
>(k
->d_content
)) {
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 answer
.bestns
.insert(make_pair(dr
.d_name
, getRR
<NSRecordContent
>(dr
)->getNS()));
796 if(beenthere
.count(answer
)) {
798 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' but part of LOOP (already seen "<<answer
.qname
<<")! Trying less specific NS"<<endl
);
801 for( set
<GetBestNSAnswer
>::const_iterator j
=beenthere
.begin();j
!=beenthere
.end();++j
) {
802 bool neo
= !(*j
< answer
|| answer
<*j
);
803 LOG(prefix
<<qname
<<": beenthere"<<(neo
?"*":"")<<": "<<j
->qname
<<"|"<<DNSRecordContent::NumberToType(j
->qtype
)<<" ("<<(unsigned int)j
->bestns
.size()<<")"<<endl
);
808 beenthere
.insert(answer
);
809 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' (flawedNSSet="<<*flawedNSSet
<<")"<<endl
);
814 LOG(prefix
<<qname
<<": no valid/useful NS in cache for '"<<subdomain
<<"'"<<endl
);
816 if(subdomain
.isRoot() && !brokeloop
) {
817 // We lost the root NS records
819 LOG(prefix
<<qname
<<": reprimed the root"<<endl
);
820 /* let's prevent an infinite loop */
821 if (!d_updatingRootNS
) {
822 getRootNS(d_now
, d_asyncResolve
);
825 } while(subdomain
.chopOff());
828 SyncRes::domainmap_t::const_iterator
SyncRes::getBestAuthZone(DNSName
* qname
) const
830 SyncRes::domainmap_t::const_iterator ret
;
832 ret
=t_sstorage
.domainmap
->find(*qname
);
833 if(ret
!=t_sstorage
.domainmap
->end())
835 }while(qname
->chopOff());
839 /** doesn't actually do the work, leaves that to getBestNSFromCache */
840 DNSName
SyncRes::getBestNSNamesFromCache(const DNSName
&qname
, const QType
& qtype
, NsSet
& nsset
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
)
842 DNSName
subdomain(qname
);
843 DNSName
authdomain(qname
);
845 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
846 if(iter
!=t_sstorage
.domainmap
->end()) {
847 if( iter
->second
.isAuth() )
848 // this gets picked up in doResolveAt, the empty DNSName, combined with the
849 // empty vector means 'we are auth for this zone'
850 nsset
.insert({DNSName(), {{}, false}});
852 // Again, picked up in doResolveAt. An empty DNSName, combined with a
853 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
854 // This is actually picked up in retrieveAddressesForNS called from doResolveAt.
855 nsset
.insert({DNSName(), {iter
->second
.d_servers
, iter
->second
.shouldRecurse() }});
860 vector
<DNSRecord
> bestns
;
861 getBestNSFromCache(subdomain
, qtype
, bestns
, flawedNSSet
, depth
, beenthere
);
863 for(auto k
=bestns
.cbegin() ; k
!= bestns
.cend(); ++k
) {
864 // The actual resolver code will not even look at the ComboAddress or bool
865 nsset
.insert({std::dynamic_pointer_cast
<NSRecordContent
>(k
->d_content
)->getNS(), {{}, false}});
866 if(k
==bestns
.cbegin())
872 bool SyncRes::doCNAMECacheCheck(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>& ret
, unsigned int depth
, int &res
, vState
& state
, bool wasAuthZone
)
877 prefix
.append(depth
, ' ');
880 if((depth
>9 && d_outqueries
>10 && d_throttledqueries
>5) || depth
> 15) {
881 LOG(prefix
<<qname
<<": recursing (CNAME or other indirection) too deep, depth="<<depth
<<endl
);
886 LOG(prefix
<<qname
<<": Looking for CNAME cache hit of '"<<qname
<<"|CNAME"<<"'"<<endl
);
887 vector
<DNSRecord
> cset
;
888 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
889 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
891 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) {
893 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
894 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
896 if (!wasAuthZone
&& shouldValidate() && wasAuth
&& state
== Indeterminate
&& d_requireAuthData
) {
897 /* This means we couldn't figure out the state when this entry was cached,
898 most likely because we hadn't computed the zone cuts yet. */
899 /* make sure they are computed before validating */
900 DNSName
subdomain(qname
);
901 /* if we are retrieving a DS, we only care about the state of the parent zone */
902 if(qtype
== QType::DS
)
905 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
907 vState recordState
= getValidationStatus(qname
, false);
908 if (recordState
== Secure
) {
909 LOG(prefix
<<qname
<<": got Indeterminate state from the CNAME cache, validating.."<<endl
);
910 state
= SyncRes::validateRecordsWithSigs(depth
, qname
, QType(QType::CNAME
), qname
, cset
, signatures
);
911 if (state
!= Indeterminate
) {
912 LOG(prefix
<<qname
<<": got Indeterminate state from the CNAME cache, new validation result is "<<vStates
[state
]<<endl
);
913 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, QType(QType::CNAME
), d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, d_requireAuthData
, state
);
918 LOG(prefix
<<qname
<<": Found cache CNAME hit for '"<< qname
<< "|CNAME" <<"' to '"<<j
->d_content
->getZoneRepresentation()<<"', validation state is "<<vStates
[state
]<<endl
);
921 dr
.d_ttl
-=d_now
.tv_sec
;
924 for(const auto& signature
: signatures
) {
926 sigdr
.d_type
=QType::RRSIG
;
928 sigdr
.d_ttl
=j
->d_ttl
- d_now
.tv_sec
;
929 sigdr
.d_content
=signature
;
930 sigdr
.d_place
=DNSResourceRecord::ANSWER
;
931 sigdr
.d_class
=QClass::IN
;
932 ret
.push_back(sigdr
);
935 for(const auto& rec
: authorityRecs
) {
936 DNSRecord
authDR(*rec
);
937 authDR
.d_ttl
=j
->d_ttl
- d_now
.tv_sec
;
938 ret
.push_back(authDR
);
941 if(qtype
!= QType::CNAME
) { // perhaps they really wanted a CNAME!
942 set
<GetBestNSAnswer
>beenthere
;
944 vState cnameState
= Indeterminate
;
945 res
=doResolve(std::dynamic_pointer_cast
<CNAMERecordContent
>(j
->d_content
)->getTarget(), qtype
, ret
, depth
+1, beenthere
, cnameState
);
946 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
947 updateValidationState(state
, cnameState
);
956 LOG(prefix
<<qname
<<": No CNAME cache hit of '"<< qname
<< "|CNAME" <<"' found"<<endl
);
963 vector
<DNSRecord
> records
;
964 vector
<shared_ptr
<RRSIGRecordContent
>> signatures
;
965 uint32_t signaturesTTL
{std::numeric_limits
<uint32_t>::max()};
971 DNSResourceRecord::Place place
;
972 bool operator<(const CacheKey
& rhs
) const {
973 return tie(name
, type
) < tie(rhs
.name
, rhs
.type
);
976 typedef map
<CacheKey
, CacheEntry
> tcache_t
;
979 static void reapRecordsFromNegCacheEntryForValidation(tcache_t
& tcache
, const vector
<DNSRecord
>& records
)
981 for (const auto& rec
: records
) {
982 if (rec
.d_type
== QType::RRSIG
) {
983 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
985 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
988 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(rec
);
994 * Convience function to push the records from records into ret with a new TTL
996 * \param records DNSRecords that need to go into ret
997 * \param ttl The new TTL for these records
998 * \param ret The vector of DNSRecords that should contian the records with the modified TTL
1000 static void addTTLModifiedRecords(const vector
<DNSRecord
>& records
, const uint32_t ttl
, vector
<DNSRecord
>& ret
) {
1001 for (const auto& rec
: records
) {
1008 void SyncRes::computeNegCacheValidationStatus(NegCache::NegCacheEntry
& ne
, const DNSName
& qname
, const QType
& qtype
, const int res
, vState
& state
, unsigned int depth
)
1010 DNSName
subdomain(qname
);
1011 /* if we are retrieving a DS, we only care about the state of the parent zone */
1012 if(qtype
== QType::DS
)
1013 subdomain
.chopOff();
1015 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1018 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.authoritySOA
.records
);
1019 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.authoritySOA
.signatures
);
1020 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.DNSSECRecords
.records
);
1021 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.DNSSECRecords
.signatures
);
1023 for (const auto& entry
: tcache
) {
1024 // this happens when we did store signatures, but passed on the records themselves
1025 if (entry
.second
.records
.empty()) {
1029 const DNSName
& owner
= entry
.first
.name
;
1031 vState recordState
= getValidationStatus(owner
, false);
1032 if (state
== Indeterminate
) {
1033 state
= recordState
;
1036 if (recordState
== Secure
) {
1037 recordState
= SyncRes::validateRecordsWithSigs(depth
, qname
, qtype
, owner
, entry
.second
.records
, entry
.second
.signatures
);
1040 if (recordState
!= Indeterminate
&& recordState
!= state
) {
1041 updateValidationState(state
, recordState
);
1042 if (state
!= Secure
) {
1048 if (state
== Secure
) {
1049 dState expectedState
= res
== RCode::NXDomain
? NXDOMAIN
: NXQTYPE
;
1050 dState denialState
= getDenialValidationState(ne
, state
, expectedState
, false);
1051 updateDenialValidationState(ne
, state
, denialState
, expectedState
, qtype
== QType::DS
);
1053 if (state
!= Indeterminate
) {
1054 /* validation succeeded, let's update the cache entry so we don't have to validate again */
1055 t_sstorage
.negcache
.updateValidationStatus(ne
.d_name
, ne
.d_qtype
, state
);
1059 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
)
1061 bool giveNegative
=false;
1066 prefix
.append(depth
, ' ');
1069 // 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)
1070 DNSName
sqname(qname
);
1073 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
1075 NegCache::NegCacheEntry ne
;
1078 t_sstorage
.negcache
.getRootNXTrust(qname
, d_now
, ne
) &&
1079 ne
.d_auth
.isRoot() &&
1080 !(wasForwardedOrAuthZone
&& !authname
.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
1081 sttl
= ne
.d_ttd
- d_now
.tv_sec
;
1082 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
.d_auth
<<"' & '"<<ne
.d_name
<<"' for another "<<sttl
<<" seconds"<<endl
);
1083 res
= RCode::NXDomain
;
1084 giveNegative
= true;
1085 cachedState
= ne
.d_validationState
;
1087 else if (t_sstorage
.negcache
.get(qname
, qtype
, d_now
, ne
) &&
1088 !(wasForwardedOrAuthZone
&& ne
.d_auth
!= authname
)) { // Only the authname nameserver can neg cache entries
1090 /* If we are looking for a DS, discard NXD if auth == qname
1091 and ask for a specific denial instead */
1092 if (qtype
!= QType::DS
|| ne
.d_qtype
.getCode() || ne
.d_auth
!= qname
||
1093 t_sstorage
.negcache
.get(qname
, qtype
, d_now
, ne
, true))
1096 sttl
= ne
.d_ttd
- d_now
.tv_sec
;
1097 giveNegative
= true;
1098 cachedState
= ne
.d_validationState
;
1099 if(ne
.d_qtype
.getCode()) {
1100 LOG(prefix
<<qname
<<": "<<qtype
.getName()<<" is negatively cached via '"<<ne
.d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1101 res
= RCode::NoError
;
1104 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
.d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1105 res
= RCode::NXDomain
;
1112 state
= cachedState
;
1114 if (!wasAuthZone
&& shouldValidate() && state
== Indeterminate
) {
1115 LOG(prefix
<<qname
<<": got Indeterminate state for records retrieved from the negative cache, validating.."<<endl
);
1116 computeNegCacheValidationStatus(ne
, qname
, qtype
, res
, state
, depth
);
1119 // Transplant SOA to the returned packet
1120 addTTLModifiedRecords(ne
.authoritySOA
.records
, sttl
, ret
);
1122 addTTLModifiedRecords(ne
.authoritySOA
.signatures
, sttl
, ret
);
1123 addTTLModifiedRecords(ne
.DNSSECRecords
.records
, sttl
, ret
);
1124 addTTLModifiedRecords(ne
.DNSSECRecords
.signatures
, sttl
, ret
);
1127 LOG(prefix
<<qname
<<": updating validation state with negative cache content for "<<qname
<<" to "<<vStates
[state
]<<endl
);
1131 vector
<DNSRecord
> cset
;
1132 bool found
=false, expired
=false;
1133 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
1134 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1137 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) {
1139 LOG(prefix
<<sqname
<<": Found cache hit for "<<sqt
.getName()<<": ");
1141 if (!wasAuthZone
&& shouldValidate() && wasCachedAuth
&& cachedState
== Indeterminate
&& d_requireAuthData
) {
1143 /* This means we couldn't figure out the state when this entry was cached,
1144 most likely because we hadn't computed the zone cuts yet. */
1145 /* make sure they are computed before validating */
1146 DNSName
subdomain(sqname
);
1147 /* if we are retrieving a DS, we only care about the state of the parent zone */
1148 if(qtype
== QType::DS
)
1149 subdomain
.chopOff();
1151 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1153 vState recordState
= getValidationStatus(qname
, false);
1154 if (recordState
== Secure
) {
1155 LOG(prefix
<<sqname
<<": got Indeterminate state from the cache, validating.."<<endl
);
1156 cachedState
= SyncRes::validateRecordsWithSigs(depth
, sqname
, sqt
, sqname
, cset
, signatures
);
1159 cachedState
= recordState
;
1162 if (cachedState
!= Indeterminate
) {
1163 LOG(prefix
<<qname
<<": got Indeterminate state from the cache, validation result is "<<vStates
[cachedState
]<<endl
);
1164 t_RC
->updateValidationStatus(d_now
.tv_sec
, sqname
, sqt
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, d_requireAuthData
, cachedState
);
1168 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
1169 LOG(j
->d_content
->getZoneRepresentation());
1170 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
1172 ttl
= (dr
.d_ttl
-=d_now
.tv_sec
);
1174 LOG("[ttl="<<dr
.d_ttl
<<"] ");
1183 for(const auto& signature
: signatures
) {
1185 dr
.d_type
=QType::RRSIG
;
1188 dr
.d_content
=signature
;
1189 dr
.d_place
= DNSResourceRecord::ANSWER
;
1190 dr
.d_class
=QClass::IN
;
1194 for(const auto& rec
: authorityRecs
) {
1201 if(found
&& !expired
) {
1204 LOG(prefix
<<qname
<<": updating validation state with cache content for "<<qname
<<" to "<<vStates
[cachedState
]<<endl
);
1205 state
= cachedState
;
1209 LOG(prefix
<<qname
<<": cache had only stale entries"<<endl
);
1215 bool SyncRes::moreSpecificThan(const DNSName
& a
, const DNSName
&b
) const
1217 return (a
.isPartOf(b
) && a
.countLabels() > b
.countLabels());
1222 speedOrder(map
<DNSName
,double> &speeds
) : d_speeds(speeds
) {}
1223 bool operator()(const DNSName
&a
, const DNSName
&b
) const
1225 return d_speeds
[a
] < d_speeds
[b
];
1227 map
<DNSName
, double>& d_speeds
;
1230 inline vector
<DNSName
> SyncRes::shuffleInSpeedOrder(NsSet
&tnameservers
, const string
&prefix
)
1232 vector
<DNSName
> rnameservers
;
1233 rnameservers
.reserve(tnameservers
.size());
1234 for(const auto& tns
: tnameservers
) {
1235 rnameservers
.push_back(tns
.first
);
1236 if(tns
.first
.empty()) // this was an authoritative OOB zone, don't pollute the nsSpeeds with that
1237 return rnameservers
;
1239 map
<DNSName
, double> speeds
;
1241 for(const auto& val
: rnameservers
) {
1243 speed
=t_sstorage
.nsSpeeds
[val
].get(&d_now
);
1246 random_shuffle(rnameservers
.begin(),rnameservers
.end(), dns_random
);
1247 speedOrder
so(speeds
);
1248 stable_sort(rnameservers
.begin(),rnameservers
.end(), so
);
1251 LOG(prefix
<<"Nameservers: ");
1252 for(vector
<DNSName
>::const_iterator i
=rnameservers
.begin();i
!=rnameservers
.end();++i
) {
1253 if(i
!=rnameservers
.begin()) {
1255 if(!((i
-rnameservers
.begin())%3)) {
1256 LOG(endl
<<prefix
<<" ");
1259 LOG((i
->empty() ? string("<empty>") : i
->toString())<<"(" << (boost::format("%0.2f") % (speeds
[*i
]/1000.0)).str() <<"ms)");
1263 return rnameservers
;
1266 static uint32_t getRRSIGTTL(const time_t now
, const std::shared_ptr
<RRSIGRecordContent
>& rrsig
)
1269 if (now
< rrsig
->d_sigexpire
) {
1270 res
= static_cast<uint32_t>(rrsig
->d_sigexpire
) - now
;
1275 static const set
<uint16_t> nsecTypes
= {QType::NSEC
, QType::NSEC3
};
1277 /* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
1279 * \param records The records to parse for the authority SOA and NSEC(3) records
1280 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
1282 static void harvestNXRecords(const vector
<DNSRecord
>& records
, NegCache::NegCacheEntry
& ne
, const time_t now
, uint32_t* lowestTTL
) {
1283 for(const auto& rec
: records
) {
1284 if(rec
.d_place
!= DNSResourceRecord::AUTHORITY
)
1285 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
1286 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
1287 // records MUST be in the same section as the records they cover.
1288 // Hence, we ignore all records outside of the AUTHORITY section.
1291 if(rec
.d_type
== QType::RRSIG
) {
1292 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1294 if(rrsig
->d_type
== QType::SOA
) {
1295 ne
.authoritySOA
.signatures
.push_back(rec
);
1296 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1297 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1298 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1301 if(nsecTypes
.count(rrsig
->d_type
)) {
1302 ne
.DNSSECRecords
.signatures
.push_back(rec
);
1303 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1304 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1305 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1311 if(rec
.d_type
== QType::SOA
) {
1312 ne
.authoritySOA
.records
.push_back(rec
);
1314 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1318 if(nsecTypes
.count(rec
.d_type
)) {
1319 ne
.DNSSECRecords
.records
.push_back(rec
);
1321 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1328 static cspmap_t
harvestCSPFromNE(const NegCache::NegCacheEntry
& ne
)
1331 for(const auto& rec
: ne
.DNSSECRecords
.signatures
) {
1332 if(rec
.d_type
== QType::RRSIG
) {
1333 auto rrc
= getRR
<RRSIGRecordContent
>(rec
);
1335 cspmap
[{rec
.d_name
,rrc
->d_type
}].signatures
.push_back(rrc
);
1339 for(const auto& rec
: ne
.DNSSECRecords
.records
) {
1340 cspmap
[{rec
.d_name
, rec
.d_type
}].records
.push_back(rec
.d_content
);
1345 // TODO remove after processRecords is fixed!
1346 // Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
1347 static void addNXNSECS(vector
<DNSRecord
>&ret
, const vector
<DNSRecord
>& records
)
1349 NegCache::NegCacheEntry ne
;
1350 harvestNXRecords(records
, ne
, 0, nullptr);
1351 ret
.insert(ret
.end(), ne
.authoritySOA
.signatures
.begin(), ne
.authoritySOA
.signatures
.end());
1352 ret
.insert(ret
.end(), ne
.DNSSECRecords
.records
.begin(), ne
.DNSSECRecords
.records
.end());
1353 ret
.insert(ret
.end(), ne
.DNSSECRecords
.signatures
.begin(), ne
.DNSSECRecords
.signatures
.end());
1356 bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine
& dfe
, const NsSet
& nameservers
)
1359 for (auto const &ns
: nameservers
) {
1360 d_appliedPolicy
= dfe
.getProcessingPolicy(ns
.first
, d_discardedPolicies
);
1361 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1362 LOG(", however nameserver "<<ns
.first
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1366 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1367 for (auto const &address
: ns
.second
.first
) {
1368 d_appliedPolicy
= dfe
.getProcessingPolicy(address
, d_discardedPolicies
);
1369 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1370 LOG(", however nameserver "<<ns
.first
<<" IP address "<<address
.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1379 bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine
& dfe
, const ComboAddress
& remoteIP
)
1382 d_appliedPolicy
= dfe
.getProcessingPolicy(remoteIP
, d_discardedPolicies
);
1383 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) {
1384 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")+"')");
1391 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
)
1393 vector
<ComboAddress
> result
;
1396 LOG(prefix
<<qname
<<": Trying to resolve NS '"<<*tns
<< "' ("<<1+tns
-rnameservers
.begin()<<"/"<<(unsigned int)rnameservers
.size()<<")"<<endl
);
1397 result
= getAddrs(*tns
, depth
+2, beenthere
, cacheOnly
);
1398 pierceDontQuery
=false;
1401 LOG(prefix
<<qname
<<": Domain has hardcoded nameserver");
1403 result
= nameservers
[*tns
].first
;
1404 if(result
.size() > 1) {
1409 sendRDQuery
= nameservers
[*tns
].second
;
1410 pierceDontQuery
=true;
1415 bool SyncRes::throttledOrBlocked(const std::string
& prefix
, const ComboAddress
& remoteIP
, const DNSName
& qname
, const QType
& qtype
, bool pierceDontQuery
)
1417 if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0))) {
1418 LOG(prefix
<<qname
<<": server throttled "<<endl
);
1419 s_throttledqueries
++; d_throttledqueries
++;
1422 else if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()))) {
1423 LOG(prefix
<<qname
<<": query throttled "<<remoteIP
.toString()<<", "<<qname
<<"; "<<qtype
.getName()<<endl
);
1424 s_throttledqueries
++; d_throttledqueries
++;
1427 else if(!pierceDontQuery
&& s_dontQuery
&& s_dontQuery
->match(&remoteIP
)) {
1428 LOG(prefix
<<qname
<<": not sending query to " << remoteIP
.toString() << ", blocked by 'dont-query' setting" << endl
);
1435 bool SyncRes::validationEnabled() const
1437 return g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
;
1440 uint32_t SyncRes::computeLowestTTD(const std::vector
<DNSRecord
>& records
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, uint32_t signaturesTTL
) const
1442 uint32_t lowestTTD
= std::numeric_limits
<uint32_t>::max();
1443 for(const auto& record
: records
)
1444 lowestTTD
= min(lowestTTD
, record
.d_ttl
);
1446 /* even if it was not requested for that request (Process, and neither AD nor DO set),
1447 it might be requested at a later time so we need to be careful with the TTL. */
1448 if (validationEnabled() && !signatures
.empty()) {
1449 /* if we are validating, we don't want to cache records after their signatures expire. */
1450 /* records TTL are now TTD, let's add 'now' to the signatures lowest TTL */
1451 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(signaturesTTL
+ d_now
.tv_sec
));
1453 for(const auto& sig
: signatures
) {
1454 if (isRRSIGNotExpired(d_now
.tv_sec
, sig
)) {
1455 // we don't decerement d_sigexpire by 'now' because we actually want a TTD, not a TTL */
1456 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(sig
->d_sigexpire
));
1464 void SyncRes::updateValidationState(vState
& state
, const vState stateUpdate
)
1466 LOG(d_prefix
<<"validation state was "<<std::string(vStates
[state
])<<", state update is "<<std::string(vStates
[stateUpdate
]));
1468 if (stateUpdate
== TA
) {
1471 else if (stateUpdate
== NTA
) {
1474 else if (stateUpdate
== Bogus
) {
1477 else if (state
== Indeterminate
) {
1478 state
= stateUpdate
;
1480 else if (stateUpdate
== Insecure
) {
1481 if (state
!= Bogus
) {
1485 LOG(", validation state is now "<<std::string(vStates
[state
])<<endl
);
1488 vState
SyncRes::getTA(const DNSName
& zone
, dsmap_t
& ds
)
1490 auto luaLocal
= g_luaconfs
.getLocal();
1492 if (luaLocal
->dsAnchors
.empty()) {
1493 LOG(d_prefix
<<": No trust anchors configured, everything is Insecure"<<endl
);
1494 /* We have no TA, everything is insecure */
1499 if (haveNegativeTrustAnchor(luaLocal
->negAnchors
, zone
, reason
)) {
1500 LOG(d_prefix
<<": got NTA for '"<<zone
<<"'"<<endl
);
1504 if (getTrustAnchor(luaLocal
->dsAnchors
, zone
, ds
)) {
1505 LOG(d_prefix
<<": got TA for '"<<zone
<<"'"<<endl
);
1509 LOG(d_prefix
<<": no TA found for '"<<zone
<<"' among "<< luaLocal
->dsAnchors
.size()<<endl
);
1512 if (zone
.isRoot()) {
1513 /* No TA for the root */
1517 return Indeterminate
;
1520 static size_t countSupportedDS(const dsmap_t
& dsmap
)
1524 for (const auto& ds
: dsmap
) {
1525 if (isSupportedDS(ds
)) {
1533 vState
SyncRes::getDSRecords(const DNSName
& zone
, dsmap_t
& ds
, bool taOnly
, unsigned int depth
, bool bogusOnNXD
, bool* foundCut
)
1535 vState result
= getTA(zone
, ds
);
1537 if (result
!= Indeterminate
|| taOnly
) {
1539 *foundCut
= (result
!= Indeterminate
);
1543 if (countSupportedDS(ds
) == 0) {
1551 else if (result
== NTA
) {
1558 bool oldSkipCNAME
= d_skipCNAMECheck
;
1559 d_skipCNAMECheck
= true;
1561 std::set
<GetBestNSAnswer
> beenthere
;
1562 std::vector
<DNSRecord
> dsrecords
;
1564 vState state
= Indeterminate
;
1565 int rcode
= doResolve(zone
, QType(QType::DS
), dsrecords
, depth
+ 1, beenthere
, state
);
1566 d_skipCNAMECheck
= oldSkipCNAME
;
1568 if (rcode
== RCode::NoError
|| (rcode
== RCode::NXDomain
&& !bogusOnNXD
)) {
1570 uint8_t bestDigestType
= 0;
1572 if (state
== Secure
) {
1573 bool gotCNAME
= false;
1574 for (const auto& record
: dsrecords
) {
1575 if (record
.d_type
== QType::DS
) {
1576 const auto dscontent
= getRR
<DSRecordContent
>(record
);
1577 if (dscontent
&& isSupportedDS(*dscontent
)) {
1578 // Make GOST a lower prio than SHA256
1579 if (dscontent
->d_digesttype
== DNSSECKeeper::GOST
&& bestDigestType
== DNSSECKeeper::SHA256
) {
1582 if (dscontent
->d_digesttype
> bestDigestType
|| (bestDigestType
== DNSSECKeeper::GOST
&& dscontent
->d_digesttype
== DNSSECKeeper::SHA256
)) {
1583 bestDigestType
= dscontent
->d_digesttype
;
1585 ds
.insert(*dscontent
);
1588 else if (record
.d_type
== QType::CNAME
&& record
.d_name
== zone
) {
1593 /* RFC 4509 section 3: "Validator implementations SHOULD ignore DS RRs containing SHA-1
1594 * digests if DS RRs with SHA-256 digests are present in the DS RRset."
1595 * As SHA348 is specified as well, the spirit of the this line is "use the best algorithm".
1597 for (auto dsrec
= ds
.begin(); dsrec
!= ds
.end(); ) {
1598 if (dsrec
->d_digesttype
!= bestDigestType
) {
1599 dsrec
= ds
.erase(dsrec
);
1606 if (rcode
== RCode::NoError
&& ds
.empty()) {
1608 if (gotCNAME
|| denialProvesNoDelegation(zone
, dsrecords
)) {
1609 /* we are still inside the same Secure zone */
1619 } else if (foundCut
&& rcode
== RCode::NoError
&& !ds
.empty()) {
1627 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
1631 bool SyncRes::haveExactValidationStatus(const DNSName
& domain
)
1633 if (!shouldValidate()) {
1636 const auto& it
= d_cutStates
.find(domain
);
1637 if (it
!= d_cutStates
.cend()) {
1643 vState
SyncRes::getValidationStatus(const DNSName
& subdomain
, bool allowIndeterminate
)
1645 vState result
= Indeterminate
;
1647 if (!shouldValidate()) {
1650 DNSName
name(subdomain
);
1652 const auto& it
= d_cutStates
.find(name
);
1653 if (it
!= d_cutStates
.cend()) {
1654 if (allowIndeterminate
|| it
->second
!= Indeterminate
) {
1655 LOG(d_prefix
<<": got status "<<vStates
[it
->second
]<<" for name "<<subdomain
<<" (from "<<name
<<")"<<endl
);
1660 while (name
.chopOff());
1665 bool SyncRes::lookForCut(const DNSName
& qname
, unsigned int depth
, const vState existingState
, vState
& newState
)
1667 bool foundCut
= false;
1669 vState dsState
= getDSRecords(qname
, ds
, newState
== Bogus
|| existingState
== Insecure
|| existingState
== Bogus
, depth
, false, &foundCut
);
1671 if (dsState
!= Indeterminate
) {
1678 void SyncRes::computeZoneCuts(const DNSName
& begin
, const DNSName
& end
, unsigned int depth
)
1680 if(!begin
.isPartOf(end
)) {
1681 LOG(d_prefix
<<" "<<begin
.toLogString()<<" is not part of "<<end
.toString()<<endl
);
1682 throw PDNSException(begin
.toLogString() + " is not part of " + end
.toString());
1685 if (d_cutStates
.count(begin
) != 0) {
1690 vState cutState
= getDSRecords(end
, ds
, false, depth
);
1691 LOG(d_prefix
<<": setting cut state for "<<end
<<" to "<<vStates
[cutState
]<<endl
);
1692 d_cutStates
[end
] = cutState
;
1694 if (!shouldValidate()) {
1699 std::vector
<string
> labelsToAdd
= begin
.makeRelative(end
).getRawLabels();
1701 bool oldSkipCNAME
= d_skipCNAMECheck
;
1702 d_skipCNAMECheck
= true;
1704 while(qname
!= begin
) {
1705 if (labelsToAdd
.empty())
1708 qname
.prependRawLabel(labelsToAdd
.back());
1709 labelsToAdd
.pop_back();
1710 LOG(d_prefix
<<": - Looking for a cut at "<<qname
<<endl
);
1712 const auto cutIt
= d_cutStates
.find(qname
);
1713 if (cutIt
!= d_cutStates
.cend()) {
1714 if (cutIt
->second
!= Indeterminate
) {
1715 LOG(d_prefix
<<": - Cut already known at "<<qname
<<endl
);
1716 cutState
= cutIt
->second
;
1721 /* no need to look for NS and DS if we are already insecure or bogus,
1724 if (cutState
== Insecure
|| cutState
== Bogus
) {
1726 vState newState
= getDSRecords(qname
, cutDS
, true, depth
);
1727 if (newState
== Indeterminate
) {
1731 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[newState
]<<endl
);
1732 cutState
= newState
;
1734 d_cutStates
[qname
] = cutState
;
1739 vState newState
= Indeterminate
;
1740 /* temporarily mark as Indeterminate, so that we won't enter an endless loop
1741 trying to determine that zone cut again. */
1742 d_cutStates
[qname
] = newState
;
1743 bool foundCut
= lookForCut(qname
, depth
+ 1, cutState
, newState
);
1745 LOG(d_prefix
<<": - Found cut at "<<qname
<<endl
);
1746 if (newState
!= Indeterminate
) {
1747 cutState
= newState
;
1749 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[cutState
]<<endl
);
1750 d_cutStates
[qname
] = cutState
;
1753 /* remove the temporary cut */
1754 LOG(d_prefix
<<qname
<<": removing cut state for "<<qname
<<endl
);
1755 d_cutStates
.erase(qname
);
1759 d_skipCNAMECheck
= oldSkipCNAME
;
1761 LOG(d_prefix
<<": list of cuts from "<<begin
<<" to "<<end
<<endl
);
1762 for (const auto& cut
: d_cutStates
) {
1763 if (cut
.first
.isRoot() || (begin
.isPartOf(cut
.first
) && cut
.first
.isPartOf(end
))) {
1764 LOG(" - "<<cut
.first
<<": "<<vStates
[cut
.second
]<<endl
);
1769 vState
SyncRes::validateDNSKeys(const DNSName
& zone
, const std::vector
<DNSRecord
>& dnskeys
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, unsigned int depth
)
1772 if (!signatures
.empty()) {
1773 DNSName signer
= getSigner(signatures
);
1775 if (!signer
.empty() && zone
.isPartOf(signer
)) {
1776 vState state
= getDSRecords(signer
, ds
, false, depth
);
1778 if (state
!= Secure
) {
1784 skeyset_t tentativeKeys
;
1785 std::vector
<shared_ptr
<DNSRecordContent
> > toSign
;
1787 for (const auto& dnskey
: dnskeys
) {
1788 if (dnskey
.d_type
== QType::DNSKEY
) {
1789 auto content
= getRR
<DNSKEYRecordContent
>(dnskey
);
1791 tentativeKeys
.insert(content
);
1792 toSign
.push_back(content
);
1797 LOG(d_prefix
<<": trying to validate "<<std::to_string(tentativeKeys
.size())<<" DNSKEYs with "<<std::to_string(ds
.size())<<" DS"<<endl
);
1798 skeyset_t validatedKeys
;
1799 validateDNSKeysAgainstDS(d_now
.tv_sec
, zone
, ds
, tentativeKeys
, toSign
, signatures
, validatedKeys
);
1801 LOG(d_prefix
<<": we now have "<<std::to_string(validatedKeys
.size())<<" DNSKEYs"<<endl
);
1803 /* if we found at least one valid RRSIG covering the set,
1804 all tentative keys are validated keys. Otherwise it means
1805 we haven't found at least one DNSKEY and a matching RRSIG
1806 covering this set, this looks Bogus. */
1807 if (validatedKeys
.size() != tentativeKeys
.size()) {
1808 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
1815 vState
SyncRes::getDNSKeys(const DNSName
& signer
, skeyset_t
& keys
, unsigned int depth
)
1817 std::vector
<DNSRecord
> records
;
1818 std::set
<GetBestNSAnswer
> beenthere
;
1819 LOG(d_prefix
<<"Retrieving DNSKeys for "<<signer
<<endl
);
1821 vState state
= Indeterminate
;
1822 /* following CNAME might lead to us to the wrong DNSKEY */
1823 bool oldSkipCNAME
= d_skipCNAMECheck
;
1824 d_skipCNAMECheck
= true;
1825 int rcode
= doResolve(signer
, QType(QType::DNSKEY
), records
, depth
+ 1, beenthere
, state
);
1826 d_skipCNAMECheck
= oldSkipCNAME
;
1828 if (rcode
== RCode::NoError
) {
1829 if (state
== Secure
) {
1830 for (const auto& key
: records
) {
1831 if (key
.d_type
== QType::DNSKEY
) {
1832 auto content
= getRR
<DNSKEYRecordContent
>(key
);
1834 keys
.insert(content
);
1839 LOG(d_prefix
<<"Retrieved "<<keys
.size()<<" DNSKeys for "<<signer
<<", state is "<<vStates
[state
]<<endl
);
1843 LOG(d_prefix
<<"Returning Bogus state from "<<__func__
<<"("<<signer
<<")"<<endl
);
1847 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
)
1850 if (!signatures
.empty()) {
1851 const DNSName signer
= getSigner(signatures
);
1852 if (!signer
.empty() && name
.isPartOf(signer
)) {
1853 if ((qtype
== QType::DNSKEY
|| qtype
== QType::DS
) && signer
== qname
) {
1854 /* we are already retrieving those keys, sorry */
1855 return Indeterminate
;
1857 vState state
= getDNSKeys(signer
, keys
, depth
);
1858 if (state
!= Secure
) {
1863 LOG(d_prefix
<<"Bogus!"<<endl
);
1867 std::vector
<std::shared_ptr
<DNSRecordContent
> > recordcontents
;
1868 for (const auto& record
: records
) {
1869 recordcontents
.push_back(record
.d_content
);
1872 LOG(d_prefix
<<"Going to validate "<<recordcontents
.size()<< " record contents with "<<signatures
.size()<<" sigs and "<<keys
.size()<<" keys for "<<name
<<endl
);
1873 if (validateWithKeySet(d_now
.tv_sec
, name
, recordcontents
, signatures
, keys
, false)) {
1874 LOG(d_prefix
<<"Secure!"<<endl
);
1878 LOG(d_prefix
<<"Bogus!"<<endl
);
1882 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
)
1889 prefix
.append(depth
, ' ');
1892 std::vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1893 const unsigned int labelCount
= qname
.countLabels();
1894 bool isCNAMEAnswer
= false;
1895 for(const auto& rec
: lwr
.d_records
) {
1896 if(!isCNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
) {
1897 isCNAMEAnswer
= true;
1900 /* if we have a positive answer synthetized from a wildcard,
1901 we need to store the corresponding NSEC/NSEC3 records proving
1902 that the exact name did not exist in the negative cache */
1903 if(needWildcardProof
) {
1904 if (nsecTypes
.count(rec
.d_type
)) {
1905 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
1907 else if (rec
.d_type
== QType::RRSIG
) {
1908 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1909 if (rrsig
&& nsecTypes
.count(rrsig
->d_type
)) {
1910 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
1914 if(rec
.d_type
== QType::RRSIG
) {
1915 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1917 /* As illustrated in rfc4035's Appendix B.6, the RRSIG label
1918 count can be lower than the name's label count if it was
1919 synthetized from the wildcard. Note that the difference might
1921 if (rec
.d_name
== qname
&& rrsig
->d_labels
< labelCount
) {
1922 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthetized from a wildcard, we need a wildcard proof"<<endl
);
1923 needWildcardProof
= true;
1926 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
1927 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
1928 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
);
1933 // reap all answers from this packet that are acceptable
1934 for(auto& rec
: lwr
.d_records
) {
1935 if(rec
.d_type
== QType::OPT
) {
1936 LOG(prefix
<<qname
<<": OPT answer '"<<rec
.d_name
<<"' from '"<<auth
<<"' nameservers" <<endl
);
1939 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
<<" ");
1940 if(rec
.d_type
== QType::ANY
) {
1941 LOG("NO! - we don't accept 'ANY' data"<<endl
);
1945 if(rec
.d_name
.isPartOf(auth
)) {
1946 if(rec
.d_type
== QType::RRSIG
) {
1947 LOG("RRSIG - separate"<<endl
);
1949 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
)) {
1950 LOG("NO! Is from delegation-only zone"<<endl
);
1952 return RCode::NXDomain
;
1955 bool haveLogged
= false;
1956 if (!t_sstorage
.domainmap
->empty()) {
1957 // Check if we are authoritative for a zone in this answer
1958 DNSName
tmp_qname(rec
.d_name
);
1959 auto auth_domain_iter
=getBestAuthZone(&tmp_qname
);
1960 if(auth_domain_iter
!=t_sstorage
.domainmap
->end() &&
1961 auth
.countLabels() <= auth_domain_iter
->first
.countLabels()) {
1962 if (auth_domain_iter
->first
!= auth
) {
1963 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter
->first
<<endl
);
1966 LOG("YES! - This answer was ");
1967 if (!wasForwarded
) {
1968 LOG("retrieved from the local auth store.");
1970 LOG("received from a server we forward to.");
1981 rec
.d_ttl
=min(s_maxcachettl
, rec
.d_ttl
);
1984 dr
.d_ttl
+= d_now
.tv_sec
;
1985 dr
.d_place
=DNSResourceRecord::ANSWER
;
1986 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(dr
);
1994 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
1995 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)
1996 uint32_t lowestTTD
=computeLowestTTD(i
->second
.records
, i
->second
.signatures
, i
->second
.signaturesTTL
);
1998 for(auto& record
: i
->second
.records
)
1999 record
.d_ttl
= lowestTTD
; // boom
2002 // cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
2003 // cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
2006 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2008 if(i
->second
.records
.empty()) // this happens when we did store signatures, but passed on the records themselves
2011 /* Even if the AA bit is set, additional data cannot be considered
2012 as authoritative. This is especially important during validation
2013 because keeping records in the additional section is allowed even
2014 if the corresponding RRSIGs are not included, without setting the TC
2015 bit, as stated in rfc4035's section 3.1.1. Including RRSIG RRs in a Response:
2016 "When placing a signed RRset in the Additional section, the name
2017 server MUST also place its RRSIG RRs in the Additional section.
2018 If space does not permit inclusion of both the RRset and its
2019 associated RRSIG RRs, the name server MAY retain the RRset while
2020 dropping the RRSIG RRs. If this happens, the name server MUST NOT
2021 set the TC bit solely because these RRSIG RRs didn't fit."
2023 bool isAA
= lwr
.d_aabit
&& i
->first
.place
!= DNSResourceRecord::ADDITIONAL
;
2024 if (isAA
&& isCNAMEAnswer
&& (i
->first
.place
!= DNSResourceRecord::ANSWER
|| i
->first
.type
!= QType::CNAME
)) {
2027 Note that the answer section of an authoritative answer normally
2028 contains only authoritative data. However when the name sought is an
2029 alias (see section 10.1.1) only the record describing that alias is
2030 necessarily authoritative. Clients should assume that other records
2031 may have come from the server's cache. Where authoritative answers
2032 are required, the client should query again, using the canonical name
2033 associated with the alias.
2038 vState recordState
= getValidationStatus(i
->first
.name
, false);
2039 LOG(d_prefix
<<": got initial zone status "<<vStates
[recordState
]<<" for record "<<i
->first
.name
<<endl
);
2041 if (shouldValidate() && recordState
== Secure
) {
2042 vState initialState
= recordState
;
2045 if (i
->first
.place
!= DNSResourceRecord::ADDITIONAL
) {
2046 /* the additional entries can be insecure,
2048 "Glue address RRsets associated with delegations MUST NOT be signed"
2050 if (i
->first
.type
== QType::DNSKEY
&& i
->first
.place
== DNSResourceRecord::ANSWER
) {
2051 LOG(d_prefix
<<"Validating DNSKEY for "<<i
->first
.name
<<endl
);
2052 recordState
= validateDNSKeys(i
->first
.name
, i
->second
.records
, i
->second
.signatures
, depth
);
2055 LOG(d_prefix
<<"Validating non-additional record for "<<i
->first
.name
<<endl
);
2056 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2057 /* 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 */
2058 if (qtype
== QType::NS
&& i
->second
.signatures
.empty() && recordState
== Bogus
&& haveExactValidationStatus(i
->first
.name
) && getValidationStatus(i
->first
.name
) == Indeterminate
) {
2059 recordState
= Indeterminate
;
2065 /* in a non authoritative answer, we only care about the DS record (or lack of) */
2066 if ((i
->first
.type
== QType::DS
|| i
->first
.type
== QType::NSEC
|| i
->first
.type
== QType::NSEC3
) && i
->first
.place
== DNSResourceRecord::AUTHORITY
) {
2067 LOG(d_prefix
<<"Validating DS record for "<<i
->first
.name
<<endl
);
2068 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2072 if (initialState
== Secure
&& state
!= recordState
) {
2073 updateValidationState(state
, recordState
);
2077 if (shouldValidate()) {
2078 LOG(d_prefix
<<"Skipping validation because the current state is "<<vStates
[recordState
]<<endl
);
2082 /* We don't need to store NSEC3 records in the positive cache because:
2083 - we don't allow direct NSEC3 queries
2084 - denial of existence proofs in wildcard expanded positive responses are stored in authorityRecs
2085 - denial of existence proofs for negative responses are stored in the negative cache
2087 if (i
->first
.type
!= QType::NSEC3
) {
2088 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
);
2091 if(i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
)
2095 return RCode::NoError
;
2098 void SyncRes::updateDenialValidationState(NegCache::NegCacheEntry
& ne
, vState
& state
, const dState denialState
, const dState expectedState
, bool allowOptOut
)
2100 if (denialState
== expectedState
) {
2101 ne
.d_validationState
= Secure
;
2104 if (denialState
== OPTOUT
&& allowOptOut
) {
2105 LOG(d_prefix
<<"OPT-out denial found for "<<ne
.d_name
<<endl
);
2106 ne
.d_validationState
= Secure
;
2109 else if (denialState
== INSECURE
) {
2110 LOG(d_prefix
<<"Insecure denial found for "<<ne
.d_name
<<", returning Insecure"<<endl
);
2111 ne
.d_validationState
= Insecure
;
2114 LOG(d_prefix
<<"Invalid denial found for "<<ne
.d_name
<<", returning Bogus, res="<<denialState
<<", expectedState="<<expectedState
<<endl
);
2115 ne
.d_validationState
= Bogus
;
2117 updateValidationState(state
, ne
.d_validationState
);
2121 dState
SyncRes::getDenialValidationState(NegCache::NegCacheEntry
& ne
, const vState state
, const dState expectedState
, bool referralToUnsigned
)
2123 cspmap_t csp
= harvestCSPFromNE(ne
);
2124 return getDenial(csp
, ne
.d_name
, ne
.d_qtype
.getCode(), referralToUnsigned
, expectedState
== NXQTYPE
);
2127 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
, bool needWildcardProof
)
2131 for(auto& rec
: lwr
.d_records
) {
2132 if (rec
.d_type
!=QType::OPT
&& rec
.d_class
!=QClass::IN
)
2135 if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2136 lwr
.d_rcode
==RCode::NXDomain
&& qname
.isPartOf(rec
.d_name
) && rec
.d_name
.isPartOf(auth
)) {
2137 LOG(prefix
<<qname
<<": got negative caching indication for name '"<<qname
<<"' (accept="<<rec
.d_name
.isPartOf(auth
)<<"), newtarget='"<<newtarget
<<"'"<<endl
);
2139 rec
.d_ttl
= min(rec
.d_ttl
, s_maxnegttl
);
2140 if(newtarget
.empty()) // only add a SOA if we're not going anywhere after this
2143 NegCache::NegCacheEntry ne
;
2145 uint32_t lowestTTL
= rec
.d_ttl
;
2146 /* if we get an NXDomain answer with a CNAME, the name
2147 does exist but the target does not */
2148 ne
.d_name
= newtarget
.empty() ? qname
: newtarget
;
2149 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2150 ne
.d_auth
= rec
.d_name
;
2151 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2152 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2154 if (state
== Secure
) {
2155 dState denialState
= getDenialValidationState(ne
, state
, NXDOMAIN
, false);
2156 updateDenialValidationState(ne
, state
, denialState
, NXDOMAIN
, false);
2159 ne
.d_validationState
= state
;
2162 /* if we get an NXDomain answer with a CNAME, let's not cache the
2163 target, even the server was authoritative for it,
2164 and do an additional query for the CNAME target.
2165 We have a regression test making sure we do exactly that.
2167 if(!wasVariable() && newtarget
.empty()) {
2168 t_sstorage
.negcache
.add(ne
);
2169 if(s_rootNXTrust
&& ne
.d_auth
.isRoot() && auth
.isRoot()) {
2170 ne
.d_name
= ne
.d_name
.getLastLabel();
2171 t_sstorage
.negcache
.add(ne
);
2177 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_type
==QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
) {
2179 if (auto content
= getRR
<CNAMERecordContent
>(rec
)) {
2180 newtarget
=content
->getTarget();
2183 /* if we have a positive answer synthetized from a wildcard, we need to
2184 return the corresponding NSEC/NSEC3 records from the AUTHORITY section
2185 proving that the exact name did not exist */
2186 else if(needWildcardProof
&& (rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::AUTHORITY
) {
2187 ret
.push_back(rec
); // enjoy your DNSSEC
2189 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
2190 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&&
2192 rec
.d_type
==qtype
.getCode() || ((lwr
.d_aabit
|| sendRDQuery
) && qtype
== QType(QType::ANY
))
2196 LOG(prefix
<<qname
<<": answer is in: resolved to '"<< rec
.d_content
->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"'"<<endl
);
2201 if (state
== Secure
&& needWildcardProof
) {
2202 /* We have a positive answer synthetized from a wildcard, we need to check that we have
2203 proof that the exact name doesn't exist so the wildcard can be used,
2204 as described in section 5.3.4 of RFC 4035 and 5.3 of FRC 7129.
2206 NegCache::NegCacheEntry ne
;
2208 uint32_t lowestTTL
= rec
.d_ttl
;
2210 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2211 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2213 cspmap_t csp
= harvestCSPFromNE(ne
);
2214 dState res
= getDenial(csp
, qname
, ne
.d_qtype
.getCode(), false, false, false);
2215 if (res
!= NXDOMAIN
) {
2217 if (res
== INSECURE
) {
2218 /* Some part could not be validated, for example a NSEC3 record with a too large number of iterations,
2219 this is not enough to warrant a Bogus, but go Insecure. */
2221 LOG(d_prefix
<<"Unable to validate denial in wildcard expanded positive response found for "<<qname
<<", returning Insecure, res="<<res
<<endl
);
2224 LOG(d_prefix
<<"Invalid denial in wildcard expanded positive response found for "<<qname
<<", returning Bogus, res="<<res
<<endl
);
2227 updateValidationState(state
, st
);
2228 /* we already stored the record with a different validation status, let's fix it */
2229 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qtype
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, lwr
.d_aabit
, st
);
2233 else if((rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::ANSWER
) {
2234 if(rec
.d_type
!= QType::RRSIG
|| rec
.d_name
== qname
)
2235 ret
.push_back(rec
); // enjoy your DNSSEC
2237 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::NS
&& qname
.isPartOf(rec
.d_name
)) {
2238 if(moreSpecificThan(rec
.d_name
,auth
)) {
2240 LOG(prefix
<<qname
<<": got NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2244 LOG(prefix
<<qname
<<": got upwards/level NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"', had '"<<auth
<<"'"<<endl
);
2246 if (auto content
= getRR
<NSRecordContent
>(rec
)) {
2247 nsset
.insert(content
->getNS());
2250 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::DS
&& qname
.isPartOf(rec
.d_name
)) {
2251 LOG(prefix
<<qname
<<": got DS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2253 else if(realreferral
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& (rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && newauth
.isPartOf(auth
)) {
2254 /* we might have received a denial of the DS, let's check */
2255 if (state
== Secure
) {
2256 NegCache::NegCacheEntry ne
;
2258 ne
.d_name
= newauth
;
2259 ne
.d_qtype
= QType::DS
;
2260 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2261 uint32_t lowestTTL
= rec
.d_ttl
;
2262 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2264 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, true);
2266 if (denialState
== NXQTYPE
|| denialState
== OPTOUT
|| denialState
== INSECURE
) {
2267 ne
.d_ttd
= lowestTTL
+ d_now
.tv_sec
;
2268 ne
.d_validationState
= Secure
;
2269 LOG(prefix
<<qname
<<": got negative indication of DS record for '"<<newauth
<<"'"<<endl
);
2271 if(!wasVariable()) {
2272 t_sstorage
.negcache
.add(ne
);
2275 if (qname
== newauth
&& qtype
== QType::DS
) {
2276 /* we are actually done! */
2283 else if(!done
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2284 lwr
.d_rcode
==RCode::NoError
&& qname
.isPartOf(rec
.d_name
)) {
2285 LOG(prefix
<<qname
<<": got negative caching indication for '"<< qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
2287 if(!newtarget
.empty()) {
2288 LOG(prefix
<<qname
<<": Hang on! Got a redirect to '"<<newtarget
<<"' already"<<endl
);
2291 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2294 NegCache::NegCacheEntry ne
;
2295 ne
.d_auth
= rec
.d_name
;
2296 uint32_t lowestTTL
= rec
.d_ttl
;
2299 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2300 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2302 if (state
== Secure
) {
2303 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, false);
2304 updateDenialValidationState(ne
, state
, denialState
, NXQTYPE
, qtype
== QType::DS
);
2306 ne
.d_validationState
= state
;
2309 if(!wasVariable()) {
2310 if(qtype
.getCode()) { // prevents us from blacking out a whole domain
2311 t_sstorage
.negcache
.add(ne
);
2322 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
)
2328 if(d_outqueries
+ d_throttledqueries
> s_maxqperq
) {
2329 throw ImmediateServFailException("more than "+std::to_string(s_maxqperq
)+" (max-qperq) queries sent while resolving "+qname
.toLogString());
2332 if(s_maxtotusec
&& d_totUsec
> s_maxtotusec
) {
2333 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");
2337 LOG(prefix
<<qname
<<": using TCP with "<< remoteIP
.toStringWithPort() <<endl
);
2342 if(d_pdl
&& d_pdl
->preoutquery(remoteIP
, d_requestor
, qname
, qtype
, doTCP
, lwr
.d_records
, resolveret
)) {
2343 LOG(prefix
<<qname
<<": query handled by Lua"<<endl
);
2346 ednsmask
=getEDNSSubnetMask(d_requestor
, qname
, remoteIP
);
2348 LOG(prefix
<<qname
<<": Adding EDNS Client Subnet Mask "<<ednsmask
->toString()<<" to query"<<endl
);
2351 resolveret
= asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(),
2352 doTCP
, sendRDQuery
, &d_now
, ednsmask
, &lwr
); // <- we go out on the wire!
2355 LOG(prefix
<<qname
<<": Received EDNS Client Subnet Mask "<<ednsmask
->toString()<<" on response"<<endl
);
2359 /* preoutquery killed the query by setting dq.rcode to -3 */
2360 if(resolveret
==-3) {
2361 throw ImmediateServFailException("Query killed by policy");
2364 d_totUsec
+= lwr
.d_usec
;
2365 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
2367 if(resolveret
!= 1) {
2368 /* Error while resolving */
2369 if(resolveret
== 0) {
2372 LOG(prefix
<<qname
<<": timeout resolving after "<<lwr
.d_usec
/1000.0<<"msec "<< (doTCP
? "over TCP" : "")<<endl
);
2374 s_outgoingtimeouts
++;
2376 if(remoteIP
.sin4
.sin_family
== AF_INET
)
2377 s_outgoing4timeouts
++;
2379 s_outgoing6timeouts
++;
2381 else if(resolveret
== -2) {
2382 /* OS resource limit reached */
2383 LOG(prefix
<<qname
<<": hit a local resource limit resolving"<< (doTCP
? " over TCP" : "")<<", probable error: "<<stringerror()<<endl
);
2384 g_stats
.resourceLimits
++;
2387 /* -1 means server unreachable */
2390 LOG(prefix
<<qname
<<": error resolving from "<<remoteIP
.toString()<< (doTCP
? " over TCP" : "") <<", possible error: "<<strerror(errno
)<< endl
);
2393 if(resolveret
!= -2) { // don't account for resource limits, they are our own fault
2394 t_sstorage
.nsSpeeds
[nsName
].submit(remoteIP
, 1000000, &d_now
); // 1 sec
2396 // code below makes sure we don't filter COM or the root
2397 if (s_serverdownmaxfails
> 0 && (auth
!= g_rootdnsname
) && t_sstorage
.fails
.incr(remoteIP
) >= s_serverdownmaxfails
) {
2398 LOG(prefix
<<qname
<<": Max fails reached resolving on "<< remoteIP
.toString() <<". Going full throttle for "<< s_serverdownthrottletime
<<" seconds" <<endl
);
2399 // mark server as down
2400 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0), s_serverdownthrottletime
, 10000);
2402 else if (resolveret
== -1) {
2403 // unreachable, 1 minute or 100 queries
2404 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 100);
2408 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 10, 5);
2415 /* we got an answer */
2416 if(lwr
.d_rcode
==RCode::ServFail
|| lwr
.d_rcode
==RCode::Refused
) {
2417 LOG(prefix
<<qname
<<": "<<nsName
<<" ("<<remoteIP
.toString()<<") returned a "<< (lwr
.d_rcode
==RCode::ServFail
? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl
);
2418 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
2422 /* this server sent a valid answer, mark it backup up if it was down */
2423 if(s_serverdownmaxfails
> 0) {
2424 t_sstorage
.fails
.clear(remoteIP
);
2431 LOG(prefix
<<qname
<<": truncated bit set, over TCP?"<<endl
);
2432 /* let's treat that as a ServFail answer from this server */
2433 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
2443 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
)
2448 prefix
.append(depth
, ' ');
2452 for(auto& rec
: lwr
.d_records
) {
2453 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumTTL
);
2457 bool needWildcardProof
= false;
2458 *rcode
= updateCacheFromRecords(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, state
, needWildcardProof
);
2459 if (*rcode
!= RCode::NoError
) {
2463 LOG(prefix
<<qname
<<": determining status after receiving this packet"<<endl
);
2466 bool realreferral
=false, negindic
=false;
2470 bool done
= processRecords(prefix
, qname
, qtype
, auth
, lwr
, sendRDQuery
, ret
, nsset
, newtarget
, newauth
, realreferral
, negindic
, state
, needWildcardProof
);
2473 LOG(prefix
<<qname
<<": status=got results, this level of recursion done"<<endl
);
2474 LOG(prefix
<<qname
<<": validation status is "<<vStates
[state
]<<endl
);
2475 *rcode
= RCode::NoError
;
2479 if(!newtarget
.empty()) {
2480 if(newtarget
== qname
) {
2481 LOG(prefix
<<qname
<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl
);
2482 *rcode
= RCode::ServFail
;
2487 LOG(prefix
<<qname
<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl
);
2488 *rcode
= RCode::ServFail
;
2492 if (qtype
== QType::DS
) {
2493 LOG(prefix
<<qname
<<": status=got a CNAME referral, but we are looking for a DS"<<endl
);
2496 addNXNSECS(ret
, lwr
.d_records
);
2498 *rcode
= RCode::NoError
;
2502 LOG(prefix
<<qname
<<": status=got a CNAME referral, starting over with "<<newtarget
<<endl
);
2504 set
<GetBestNSAnswer
> beenthere2
;
2505 vState cnameState
= Indeterminate
;
2506 *rcode
= doResolve(newtarget
, qtype
, ret
, depth
+ 1, beenthere2
, cnameState
);
2507 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
2508 updateValidationState(state
, cnameState
);
2513 if(lwr
.d_rcode
== RCode::NXDomain
) {
2514 LOG(prefix
<<qname
<<": status=NXDOMAIN, we are done "<<(negindic
? "(have negative SOA)" : "")<<endl
);
2517 addNXNSECS(ret
, lwr
.d_records
);
2519 *rcode
= RCode::NXDomain
;
2523 if(nsset
.empty() && !lwr
.d_rcode
&& (negindic
|| lwr
.d_aabit
|| sendRDQuery
)) {
2524 LOG(prefix
<<qname
<<": status=noerror, other types may exist, but we are done "<<(negindic
? "(have negative SOA) " : "")<<(lwr
.d_aabit
? "(have aa bit) " : "")<<endl
);
2526 if(state
== Secure
&& lwr
.d_aabit
&& !negindic
) {
2527 updateValidationState(state
, Bogus
);
2531 addNXNSECS(ret
, lwr
.d_records
);
2533 *rcode
= RCode::NoError
;
2538 LOG(prefix
<<qname
<<": status=did not resolve, got "<<(unsigned int)nsset
.size()<<" NS, ");
2540 nameservers
.clear();
2541 for (auto const &nameserver
: nsset
) {
2543 d_appliedPolicy
= dfe
.getProcessingPolicy(nameserver
, d_discardedPolicies
);
2544 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
2545 LOG("however "<<nameserver
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
2550 nameservers
.insert({nameserver
, {{}, false}});
2552 LOG("looping to them"<<endl
);
2553 *gotNewServers
= true;
2563 * -1 in case of no results
2564 * -2 when a FilterEngine Policy was hit
2567 int SyncRes::doResolveAt(NsSet
&nameservers
, DNSName auth
, bool flawedNSSet
, const DNSName
&qname
, const QType
&qtype
,
2568 vector
<DNSRecord
>&ret
,
2569 unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
, vState
& state
)
2571 auto luaconfsLocal
= g_luaconfs
.getLocal();
2575 prefix
.append(depth
, ' ');
2578 LOG(prefix
<<qname
<<": Cache consultations done, have "<<(unsigned int)nameservers
.size()<<" NS to contact");
2580 if (nameserversBlockedByRPZ(luaconfsLocal
->dfe
, nameservers
)) {
2586 for(;;) { // we may get more specific nameservers
2587 vector
<DNSName
> rnameservers
= shuffleInSpeedOrder(nameservers
, doLog() ? (prefix
+qname
.toString()+": ") : string() );
2589 for(auto tns
=rnameservers
.cbegin();;++tns
) {
2590 if(tns
==rnameservers
.cend()) {
2591 LOG(prefix
<<qname
<<": Failed to resolve via any of the "<<(unsigned int)rnameservers
.size()<<" offered NS at level '"<<auth
<<"'"<<endl
);
2592 if(!auth
.isRoot() && flawedNSSet
) {
2593 LOG(prefix
<<qname
<<": Ageing nameservers for level '"<<auth
<<"', next query might succeed"<<endl
);
2595 if(t_RC
->doAgeCache(d_now
.tv_sec
, auth
, QType::NS
, 10))
2596 g_stats
.nsSetInvalidations
++;
2601 bool cacheOnly
= false;
2602 // this line needs to identify the 'self-resolving' behaviour
2603 if(qname
== *tns
&& (qtype
.getCode() == QType::A
|| qtype
.getCode() == QType::AAAA
)) {
2604 /* we might have a glue entry in cache so let's try this NS
2605 but only if we have enough in the cache to know how to reach it */
2606 LOG(prefix
<<qname
<<": Using NS to resolve itself, but only using what we have in cache ("<<(1+tns
-rnameservers
.cbegin())<<"/"<<rnameservers
.size()<<")"<<endl
);
2610 typedef vector
<ComboAddress
> remoteIPs_t
;
2611 remoteIPs_t remoteIPs
;
2612 remoteIPs_t::const_iterator remoteIP
;
2613 bool pierceDontQuery
=false;
2614 bool sendRDQuery
=false;
2615 boost::optional
<Netmask
> ednsmask
;
2617 const bool wasForwarded
= tns
->empty() && (!nameservers
[*tns
].first
.empty());
2618 int rcode
= RCode::NoError
;
2619 bool gotNewServers
= false;
2621 if(tns
->empty() && !wasForwarded
) {
2622 LOG(prefix
<<qname
<<": Domain is out-of-band"<<endl
);
2623 /* setting state to indeterminate since validation is disabled for local auth zone,
2624 and Insecure would be misleading. */
2625 state
= Indeterminate
;
2626 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, lwr
.d_records
, depth
, lwr
.d_rcode
);
2630 /* we have received an answer, are we done ? */
2631 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, false, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
2635 if (gotNewServers
) {
2640 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
2641 remoteIPs
= retrieveAddressesForNS(prefix
, qname
, tns
, depth
, beenthere
, rnameservers
, nameservers
, sendRDQuery
, pierceDontQuery
, flawedNSSet
, cacheOnly
);
2643 if(remoteIPs
.empty()) {
2644 LOG(prefix
<<qname
<<": Failed to get IP for NS "<<*tns
<<", trying next if available"<<endl
);
2649 bool hitPolicy
{false};
2650 LOG(prefix
<<qname
<<": Resolved '"<<auth
<<"' NS "<<*tns
<<" to: ");
2651 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
2652 if(remoteIP
!= remoteIPs
.cbegin()) {
2655 LOG(remoteIP
->toString());
2656 if(nameserverIPBlockedByRPZ(luaconfsLocal
->dfe
, *remoteIP
)) {
2661 if (hitPolicy
) //implies d_wantsRPZ
2665 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
2666 LOG(prefix
<<qname
<<": Trying IP "<< remoteIP
->toStringWithPort() <<", asking '"<<qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
2668 if (throttledOrBlocked(prefix
, *remoteIP
, qname
, qtype
, pierceDontQuery
)) {
2672 bool truncated
= false;
2673 bool gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
2674 *tns
, *remoteIP
, false, &truncated
);
2675 if (gotAnswer
&& truncated
) {
2676 /* retry, over TCP this time */
2677 gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
2678 *tns
, *remoteIP
, true, &truncated
);
2685 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
);
2687 /* // for you IPv6 fanatics :-)
2688 if(remoteIP->sin4.sin_family==AF_INET6)
2691 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
2693 t_sstorage
.nsSpeeds
[*tns
].submit(*remoteIP
, lwr
.d_usec
, &d_now
);
2695 /* we have received an answer, are we done ? */
2696 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
2700 if (gotNewServers
) {
2704 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100);
2707 if (gotNewServers
) {
2711 if(remoteIP
== remoteIPs
.cend()) // we tried all IP addresses, none worked
2720 void SyncRes::setIncomingECS(boost::optional
<const EDNSSubnetOpts
&> incomingECS
)
2722 d_incomingECS
= incomingECS
;
2724 if (d_incomingECS
->source
.getBits() == 0) {
2725 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0.
2726 But using an empty ECS in that case would mean inserting
2727 a non ECS-specific entry into the cache, preventing any further
2728 ECS-specific query to be sent.
2729 So instead we use the trick described in section 7.1.2:
2730 "The subsequent Recursive Resolver query to the Authoritative Nameserver
2731 will then either not include an ECS option or MAY optionally include
2732 its own address information, which is what the Authoritative
2733 Nameserver will almost certainly use to generate any Tailored
2734 Response in lieu of an option. This allows the answer to be handled
2735 by the same caching mechanism as other queries, with an explicit
2736 indicator of the applicable scope. Subsequent Stub Resolver queries
2737 for /0 can then be answered from this cached response.
2739 d_incomingECS
= s_ecsScopeZero
;
2740 d_incomingECSNetwork
= s_ecsScopeZero
.source
.getMaskedNetwork();
2743 uint8_t bits
= std::min(incomingECS
->source
.getBits(), (incomingECS
->source
.isIpv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
2744 d_incomingECS
->source
= Netmask(incomingECS
->source
.getNetwork(), bits
);
2745 d_incomingECSNetwork
= d_incomingECS
->source
.getMaskedNetwork();
2749 d_incomingECSNetwork
= ComboAddress();
2753 boost::optional
<Netmask
> SyncRes::getEDNSSubnetMask(const ComboAddress
& local
, const DNSName
&dn
, const ComboAddress
& rem
)
2755 boost::optional
<Netmask
> result
;
2758 if(d_incomingECSFound
) {
2759 trunc
= d_incomingECSNetwork
;
2760 bits
= d_incomingECS
->source
.getBits();
2762 else if(!local
.isIPv4() || local
.sin4
.sin_addr
.s_addr
) { // detect unset 'requestor'
2764 bits
= local
.isIPv4() ? 32 : 128;
2765 bits
= std::min(bits
, (trunc
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
2768 /* nothing usable */
2772 if(s_ednsdomains
.check(dn
) || s_ednssubnets
.match(rem
)) {
2773 trunc
.truncate(bits
);
2774 return boost::optional
<Netmask
>(Netmask(trunc
, bits
));
2780 void SyncRes::parseEDNSSubnetWhitelist(const std::string
& wlist
)
2782 vector
<string
> parts
;
2783 stringtok(parts
, wlist
, ",; ");
2784 for(const auto& a
: parts
) {
2786 s_ednssubnets
.addMask(Netmask(a
));
2789 s_ednsdomains
.add(DNSName(a
));
2794 // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
2795 int directResolve(const DNSName
& qname
, const QType
& qtype
, int qclass
, vector
<DNSRecord
>& ret
)
2798 gettimeofday(&now
, 0);
2801 int res
= sr
.beginResolve(qname
, QType(qtype
), qclass
, ret
);
2806 int SyncRes::getRootNS(struct timeval now
, asyncresolve_t asyncCallback
) {
2808 sr
.setDoEDNS0(true);
2809 sr
.setUpdatingRootNS();
2810 sr
.setDoDNSSEC(g_dnssecmode
!= DNSSECMode::Off
);
2811 sr
.setDNSSECValidationRequested(g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
);
2812 sr
.setAsyncCallback(asyncCallback
);
2814 vector
<DNSRecord
> ret
;
2817 res
=sr
.beginResolve(g_rootdnsname
, QType(QType::NS
), 1, ret
);
2818 if (g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
) {
2819 auto state
= sr
.getValidationState();
2821 throw PDNSException("Got Bogus validation result for .|NS");
2825 catch(const PDNSException
& e
) {
2826 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
2828 catch(const ImmediateServFailException
& e
) {
2829 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
2831 catch(const std::exception
& e
) {
2832 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.what()<<endl
;
2835 L
<<Logger::Error
<<"Failed to update . records, got an exception"<<endl
;
2839 L
<<Logger::Notice
<<"Refreshed . records"<<endl
;
2842 L
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;