2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "arguments.hh"
27 #include "cachecleaner.hh"
28 #include "dns_random.hh"
29 #include "dnsparser.hh"
30 #include "dnsrecords.hh"
31 #include "ednssubnet.hh"
33 #include "lua-recursor4.hh"
34 #include "rec-lua-conf.hh"
36 #include "dnsseckeeper.hh"
37 #include "validate-recursor.hh"
39 thread_local
SyncRes::ThreadLocalStorage
SyncRes::t_sstorage
;
41 std::unordered_set
<DNSName
> SyncRes::s_delegationOnly
;
42 std::unique_ptr
<NetmaskGroup
> SyncRes::s_dontQuery
{nullptr};
43 NetmaskGroup
SyncRes::s_ednssubnets
;
44 SuffixMatchNode
SyncRes::s_ednsdomains
;
45 EDNSSubnetOpts
SyncRes::s_ecsScopeZero
;
46 string
SyncRes::s_serverID
;
47 SyncRes::LogMode
SyncRes::s_lm
;
49 unsigned int SyncRes::s_maxnegttl
;
50 unsigned int SyncRes::s_maxcachettl
;
51 unsigned int SyncRes::s_maxqperq
;
52 unsigned int SyncRes::s_maxtotusec
;
53 unsigned int SyncRes::s_maxdepth
;
54 unsigned int SyncRes::s_minimumTTL
;
55 unsigned int SyncRes::s_packetcachettl
;
56 unsigned int SyncRes::s_packetcacheservfailttl
;
57 unsigned int SyncRes::s_serverdownmaxfails
;
58 unsigned int SyncRes::s_serverdownthrottletime
;
59 std::atomic
<uint64_t> SyncRes::s_queries
;
60 std::atomic
<uint64_t> SyncRes::s_outgoingtimeouts
;
61 std::atomic
<uint64_t> SyncRes::s_outgoing4timeouts
;
62 std::atomic
<uint64_t> SyncRes::s_outgoing6timeouts
;
63 std::atomic
<uint64_t> SyncRes::s_outqueries
;
64 std::atomic
<uint64_t> SyncRes::s_tcpoutqueries
;
65 std::atomic
<uint64_t> SyncRes::s_throttledqueries
;
66 std::atomic
<uint64_t> SyncRes::s_dontqueries
;
67 std::atomic
<uint64_t> SyncRes::s_nodelegated
;
68 std::atomic
<uint64_t> SyncRes::s_unreachables
;
69 std::atomic
<uint64_t> SyncRes::s_ecsqueries
;
70 std::atomic
<uint64_t> SyncRes::s_ecsresponses
;
71 uint8_t SyncRes::s_ecsipv4limit
;
72 uint8_t SyncRes::s_ecsipv6limit
;
73 bool SyncRes::s_doIPv6
;
74 bool SyncRes::s_nopacketcache
;
75 bool SyncRes::s_rootNXTrust
;
76 bool SyncRes::s_noEDNS
;
78 #define LOG(x) if(d_lm == Log) { L <<Logger::Warning << x; } else if(d_lm == Store) { d_trace << x; }
80 static void accountAuthLatency(int usec
, int family
)
82 if(family
== AF_INET
) {
84 g_stats
.auth4Answers0_1
++;
86 g_stats
.auth4Answers1_10
++;
87 else if(usec
< 100000)
88 g_stats
.auth4Answers10_100
++;
89 else if(usec
< 1000000)
90 g_stats
.auth4Answers100_1000
++;
92 g_stats
.auth4AnswersSlow
++;
95 g_stats
.auth6Answers0_1
++;
97 g_stats
.auth6Answers1_10
++;
98 else if(usec
< 100000)
99 g_stats
.auth6Answers10_100
++;
100 else if(usec
< 1000000)
101 g_stats
.auth6Answers100_1000
++;
103 g_stats
.auth6AnswersSlow
++;
109 SyncRes::SyncRes(const struct timeval
& now
) : d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
110 d_totUsec(0), d_now(now
),
111 d_cacheonly(false), d_doDNSSEC(false), d_doEDNS0(false), d_lm(s_lm
)
116 /** everything begins here - this is the entry point just after receiving a packet */
117 int SyncRes::beginResolve(const DNSName
&qname
, const QType
&qtype
, uint16_t qclass
, vector
<DNSRecord
>&ret
)
119 vState state
= Indeterminate
;
122 d_wasOutOfBand
=false;
124 if (doSpecialNamesResolve(qname
, qtype
, qclass
, ret
)) {
125 d_queryValidationState
= Insecure
;
129 if( (qtype
.getCode() == QType::AXFR
) || (qtype
.getCode() == QType::IXFR
) || (qtype
.getCode() == QType::RRSIG
) || (qtype
.getCode() == QType::NSEC3
))
132 if(qclass
==QClass::ANY
)
134 else if(qclass
!=QClass::IN
)
137 set
<GetBestNSAnswer
> beenthere
;
138 int res
=doResolve(qname
, qtype
, ret
, 0, beenthere
, state
);
139 d_queryValidationState
= state
;
141 if (d_queryValidationState
!= Indeterminate
) {
142 g_stats
.dnssecValidations
++;
144 if (shouldValidate()) {
145 increaseDNSSECStateCounter(d_queryValidationState
);
151 /*! Handles all special, built-in names
152 * Fills ret with an answer and returns true if it handled the query.
154 * Handles the following queries (and their ANY variants):
157 * - localhost. IN AAAA
158 * - 1.0.0.127.in-addr.arpa. IN PTR
159 * - 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. IN PTR
160 * - version.bind. CH TXT
161 * - version.pdns. CH TXT
162 * - id.server. CH TXT
164 bool SyncRes::doSpecialNamesResolve(const DNSName
&qname
, const QType
&qtype
, const uint16_t qclass
, vector
<DNSRecord
> &ret
)
166 static const DNSName
arpa("1.0.0.127.in-addr.arpa."), ip6_arpa("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa."),
167 localhost("localhost."), versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns.");
169 bool handled
= false;
170 vector
<pair
<QType::typeenum
, string
> > answers
;
172 if ((qname
== arpa
|| qname
== ip6_arpa
) &&
173 qclass
== QClass::IN
) {
175 if (qtype
== QType::PTR
|| qtype
== QType::ANY
)
176 answers
.push_back({QType::PTR
, "localhost."});
179 if (qname
== localhost
&&
180 qclass
== QClass::IN
) {
182 if (qtype
== QType::A
|| qtype
== QType::ANY
)
183 answers
.push_back({QType::A
, "127.0.0.1"});
184 if (qtype
== QType::AAAA
|| qtype
== QType::ANY
)
185 answers
.push_back({QType::AAAA
, "::1"});
188 if ((qname
== versionbind
|| qname
== idserver
|| qname
== versionpdns
) &&
189 qclass
== QClass::CHAOS
) {
191 if (qtype
== QType::TXT
|| qtype
== QType::ANY
) {
192 if(qname
== versionbind
|| qname
== versionpdns
)
193 answers
.push_back({QType::TXT
, "\""+::arg()["version-string"]+"\""});
195 answers
.push_back({QType::TXT
, "\""+s_serverID
+"\""});
199 if (handled
&& !answers
.empty()) {
205 dr
.d_place
= DNSResourceRecord::ANSWER
;
208 for (const auto& ans
: answers
) {
209 dr
.d_type
= ans
.first
;
210 dr
.d_content
= DNSRecordContent::mastermake(ans
.first
, qclass
, ans
.second
);
219 //! This is the 'out of band resolver', in other words, the authoritative server
220 void SyncRes::AuthDomain::addSOA(std::vector
<DNSRecord
>& records
) const
222 SyncRes::AuthDomain::records_t::const_iterator ziter
= d_records
.find(boost::make_tuple(getName(), QType::SOA
));
223 if (ziter
!= d_records
.end()) {
224 DNSRecord dr
= *ziter
;
225 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
226 records
.push_back(dr
);
229 // cerr<<qname<<": can't find SOA record '"<<getName()<<"' in our zone!"<<endl;
233 int SyncRes::AuthDomain::getRecords(const DNSName
& qname
, uint16_t qtype
, std::vector
<DNSRecord
>& records
) const
235 int result
= RCode::NoError
;
239 std::pair
<records_t::const_iterator
,records_t::const_iterator
> range
= d_records
.equal_range(tie(qname
));
241 SyncRes::AuthDomain::records_t::const_iterator ziter
;
242 bool somedata
= false;
244 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
247 if(qtype
== QType::ANY
|| ziter
->d_type
== qtype
|| ziter
->d_type
== QType::CNAME
) {
248 // let rest of nameserver do the legwork on this one
249 records
.push_back(*ziter
);
251 else if (ziter
->d_type
== QType::NS
&& ziter
->d_name
.countLabels() > getName().countLabels()) {
252 // we hit a delegation point!
253 DNSRecord dr
= *ziter
;
254 dr
.d_place
=DNSResourceRecord::AUTHORITY
;
255 records
.push_back(dr
);
259 if (!records
.empty()) {
260 /* We have found an exact match, we're done */
261 // cerr<<qname<<": exact match in zone '"<<getName()<<"'"<<endl;
266 /* We have records for that name, but not of the wanted qtype */
267 // cerr<<qname<<": found record in '"<<getName()<<"', but nothing of the right type, sending SOA"<<endl;
273 // cerr<<qname<<": nothing found so far in '"<<getName()<<"', trying wildcards"<<endl;
274 DNSName
wcarddomain(qname
);
275 while(wcarddomain
!= getName() && wcarddomain
.chopOff()) {
276 // cerr<<qname<<": trying '*."<<wcarddomain<<"' in "<<getName()<<endl;
277 range
= d_records
.equal_range(boost::make_tuple(g_wildcarddnsname
+ wcarddomain
));
278 if (range
.first
==range
.second
)
281 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
282 DNSRecord dr
= *ziter
;
283 // if we hit a CNAME, just answer that - rest of recursor will do the needful & follow
284 if(dr
.d_type
== qtype
|| qtype
== QType::ANY
|| dr
.d_type
== QType::CNAME
) {
286 dr
.d_place
= DNSResourceRecord::ANSWER
;
287 records
.push_back(dr
);
291 if (records
.empty()) {
295 // cerr<<qname<<": in '"<<getName()<<"', had wildcard match on '*."<<wcarddomain<<"'"<<endl;
299 /* Nothing for this name, no wildcard, let's see if there is some NS */
300 DNSName
nsdomain(qname
);
301 while (nsdomain
.chopOff() && nsdomain
!= getName()) {
302 range
= d_records
.equal_range(boost::make_tuple(nsdomain
,QType::NS
));
303 if(range
.first
== range
.second
)
306 for(ziter
= range
.first
; ziter
!= range
.second
; ++ziter
) {
307 DNSRecord dr
= *ziter
;
308 dr
.d_place
= DNSResourceRecord::AUTHORITY
;
309 records
.push_back(dr
);
313 if(records
.empty()) {
314 // cerr<<qname<<": no NS match in zone '"<<getName()<<"' either, handing out SOA"<<endl;
316 result
= RCode::NXDomain
;
322 bool SyncRes::doOOBResolve(const AuthDomain
& domain
, const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, int& res
) const
324 res
= domain
.getRecords(qname
, qtype
.getCode(), ret
);
328 bool SyncRes::doOOBResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int& res
)
333 prefix
.append(depth
, ' ');
336 DNSName
authdomain(qname
);
337 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
338 if(iter
==t_sstorage
.domainmap
->end() || !iter
->second
.isAuth()) {
339 LOG(prefix
<<qname
<<": auth storage has no zone for this query!"<<endl
);
343 LOG(prefix
<<qname
<<": auth storage has data, zone='"<<authdomain
<<"'"<<endl
);
344 return doOOBResolve(iter
->second
, qname
, qtype
, ret
, res
);
347 void SyncRes::doEDNSDumpAndClose(int fd
)
349 FILE* fp
=fdopen(fd
, "w");
353 fprintf(fp
,"IP Address\tMode\tMode last updated at\n");
354 for(const auto& eds
: t_sstorage
.ednsstatus
) {
355 fprintf(fp
, "%s\t%d\t%s", eds
.first
.toString().c_str(), (int)eds
.second
.mode
, ctime(&eds
.second
.modeSetAt
));
361 uint64_t SyncRes::doDumpNSSpeeds(int fd
)
363 FILE* fp
=fdopen(dup(fd
), "w");
366 fprintf(fp
, "; nsspeed dump from thread follows\n;\n");
369 for(const auto& i
: t_sstorage
.nsSpeeds
)
373 // an <empty> can appear hear in case of authoritative (hosted) zones
374 fprintf(fp
, "%s -> ", i
.first
.toLogString().c_str());
375 for(const auto& j
: i
.second
.d_collection
)
377 // typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
378 fprintf(fp
, "%s/%f ", j
.first
.toString().c_str(), j
.second
.peek());
386 /* so here is the story. First we complete the full resolution process for a domain name. And only THEN do we decide
387 to also do DNSSEC validation, which leads to new queries. To make this simple, we *always* ask for DNSSEC records
388 so that if there are RRSIGs for a name, we'll have them.
390 However, some hosts simply can't answer questions which ask for DNSSEC. This can manifest itself as:
395 The cause of "No answer" may be fragmentation, and it is tempting to probe if smaller answers would get through.
396 Another cause of "No answer" may simply be a network condition.
397 Nonsense answers are a clearer indication this host won't be able to do DNSSEC evah.
399 Previous implementations have suffered from turning off DNSSEC questions for an authoritative server based on timeouts.
400 A clever idea is to only turn off DNSSEC if we know a domain isn't signed anyhow. The problem with that really
401 clever idea however is that at this point in PowerDNS, we may simply not know that yet. All the DNSSEC thinking happens
402 elsewhere. It may not have happened yet.
404 For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish.
407 int SyncRes::asyncresolveWrapper(const ComboAddress
& ip
, bool ednsMANDATORY
, const DNSName
& domain
, int type
, bool doTCP
, bool sendRDQuery
, struct timeval
* now
, boost::optional
<Netmask
>& srcmask
, LWResult
* res
) const
409 /* what is your QUEST?
410 the goal is to get as many remotes as possible on the highest level of EDNS support
413 0) UNKNOWN Unknown state
414 1) EDNS: Honors EDNS0
415 2) EDNSIGNORANT: Ignores EDNS0, gives replies without EDNS0
416 3) NOEDNS: Generates FORMERR/NOTIMP on EDNS queries
418 Everybody starts out assumed to be '0'.
419 If '0', send out EDNS0
420 If you FORMERR us, go to '3',
421 If no EDNS in response, go to '2'
422 If '1', send out EDNS0
423 If FORMERR, downgrade to 3
424 If '2', keep on including EDNS0, see what happens
426 If '3', send bare queries
429 SyncRes::EDNSStatus
* ednsstatus
;
430 ednsstatus
= &t_sstorage
.ednsstatus
[ip
]; // does this include port? YES
432 if(ednsstatus
->modeSetAt
&& ednsstatus
->modeSetAt
+ 3600 < d_now
.tv_sec
) {
433 *ednsstatus
=SyncRes::EDNSStatus();
434 // cerr<<"Resetting EDNS Status for "<<ip.toString()<<endl);
437 SyncRes::EDNSStatus::EDNSMode
& mode
=ednsstatus
->mode
;
438 SyncRes::EDNSStatus::EDNSMode oldmode
= mode
;
440 auto luaconfsLocal
= g_luaconfs
.getLocal();
443 ctx
.d_initialRequestId
= d_initialRequestId
;
447 for(int tries
= 0; tries
< 3; ++tries
) {
448 // cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl;
450 if(mode
==EDNSStatus::NOEDNS
) {
451 g_stats
.noEdnsOutQueries
++;
452 EDNSLevel
= 0; // level != mode
454 else if(ednsMANDATORY
|| mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
==EDNSStatus::EDNSIGNORANT
)
457 DNSName
sendQname(domain
);
458 if (g_lowercaseOutgoing
)
459 sendQname
.makeUsLowerCase();
461 if (d_asyncResolve
) {
462 ret
= d_asyncResolve(ip
, sendQname
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, luaconfsLocal
->outgoingProtobufServer
, res
);
465 ret
=asyncresolve(ip
, sendQname
, type
, doTCP
, sendRDQuery
, EDNSLevel
, now
, srcmask
, ctx
, luaconfsLocal
->outgoingProtobufServer
, res
);
468 return ret
; // transport error, nothing to learn here
471 if(ret
== 0) { // timeout, not doing anything with it now
474 else if(mode
==EDNSStatus::UNKNOWN
|| mode
==EDNSStatus::EDNSOK
|| mode
== EDNSStatus::EDNSIGNORANT
) {
475 if(res
->d_rcode
== RCode::FormErr
|| res
->d_rcode
== RCode::NotImp
) {
476 // cerr<<"Downgrading to NOEDNS because of "<<RCode::to_s(res->d_rcode)<<" for query to "<<ip.toString()<<" for '"<<domain<<"'"<<endl;
477 mode
= EDNSStatus::NOEDNS
;
480 else if(!res
->d_haveEDNS
) {
481 if(mode
!= EDNSStatus::EDNSIGNORANT
) {
482 mode
= EDNSStatus::EDNSIGNORANT
;
483 // cerr<<"We find that "<<ip.toString()<<" is an EDNS-ignorer for '"<<domain<<"', moving to mode 3"<<endl;
487 mode
= EDNSStatus::EDNSOK
;
488 // cerr<<"We find that "<<ip.toString()<<" is EDNS OK!"<<endl;
492 if(oldmode
!= mode
|| !ednsstatus
->modeSetAt
)
493 ednsstatus
->modeSetAt
=d_now
.tv_sec
;
494 // cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", new mode: "<<mode<<endl;
500 /*! This function will check the cache and go out to the internet if the answer is not in cache
502 * \param qname The name we need an answer for
504 * \param ret The vector of DNSRecords we need to fill with the answers
505 * \param depth The recursion depth we are in
507 * \return DNS RCODE or -1 (Error) or -2 (RPZ hit)
509 int SyncRes::doResolve(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, vState
& state
)
514 prefix
.append(depth
, ' ');
517 LOG(prefix
<<qname
<<": Wants "<< (d_doDNSSEC
? "" : "NO ") << "DNSSEC processing, "<<(d_requireAuthData
? "" : "NO ")<<"auth data in query for "<<qtype
.getName()<<endl
);
519 state
= Indeterminate
;
521 if(s_maxdepth
&& depth
> s_maxdepth
)
522 throw ImmediateServFailException("More than "+std::to_string(s_maxdepth
)+" (max-recursion-depth) levels of recursion needed while resolving "+qname
.toLogString());
526 // This is a difficult way of expressing "this is a normal query", i.e. not getRootNS.
527 if(!(d_updatingRootNS
&& qtype
.getCode()==QType::NS
&& qname
.isRoot())) {
528 if(d_cacheonly
) { // very limited OOB support
530 LOG(prefix
<<qname
<<": Recursion not requested for '"<<qname
<<"|"<<qtype
.getName()<<"', peeking at auth/forward zones"<<endl
);
531 DNSName
authname(qname
);
532 domainmap_t::const_iterator iter
=getBestAuthZone(&authname
);
533 if(iter
!= t_sstorage
.domainmap
->end()) {
534 if(iter
->second
.isAuth()) {
536 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, ret
, depth
, res
);
540 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
541 const ComboAddress remoteIP
= servers
.front();
542 LOG(prefix
<<qname
<<": forwarding query to hardcoded nameserver '"<< remoteIP
.toStringWithPort()<<"' for zone '"<<authname
<<"'"<<endl
);
544 boost::optional
<Netmask
> nm
;
545 res
=asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(), false, false, &d_now
, nm
, &lwr
);
547 d_totUsec
+= lwr
.d_usec
;
548 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
550 // filter out the good stuff from lwr.result()
552 for(const auto& rec
: lwr
.d_records
) {
553 if(rec
.d_place
== DNSResourceRecord::ANSWER
)
559 return RCode::ServFail
;
565 DNSName
authname(qname
);
566 bool wasForwardedOrAuthZone
= false;
567 bool wasAuthZone
= false;
568 domainmap_t::const_iterator iter
= getBestAuthZone(&authname
);
569 if(iter
!= t_sstorage
.domainmap
->end()) {
570 wasForwardedOrAuthZone
= true;
571 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
572 if(servers
.empty()) {
577 if(!d_skipCNAMECheck
&& doCNAMECacheCheck(qname
, qtype
, ret
, depth
, res
, state
, wasAuthZone
)) { // will reroute us if needed
578 d_wasOutOfBand
= wasAuthZone
;
582 if(doCacheCheck(qname
, authname
, wasForwardedOrAuthZone
, wasAuthZone
, qtype
, ret
, depth
, res
, state
)) {
584 d_wasOutOfBand
= wasAuthZone
;
592 LOG(prefix
<<qname
<<": No cache hit for '"<<qname
<<"|"<<qtype
.getName()<<"', trying to find an appropriate NS record"<<endl
);
594 DNSName
subdomain(qname
);
595 if(qtype
== QType::DS
) subdomain
.chopOff();
598 bool flawedNSSet
=false;
600 /* we use subdomain here instead of qname because for DS queries we only care about the state of the parent zone */
601 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
603 // the two retries allow getBestNSNamesFromCache&co to reprime the root
604 // hints, in case they ever go missing
605 for(int tries
=0;tries
<2 && nsset
.empty();++tries
) {
606 subdomain
=getBestNSNamesFromCache(subdomain
, qtype
, nsset
, &flawedNSSet
, depth
, beenthere
); // pass beenthere to both occasions
609 state
= getValidationStatus(qname
, false);
611 LOG(prefix
<<qname
<<": initial validation status for "<<qname
<<" is "<<vStates
[state
]<<endl
);
613 if(!(res
=doResolveAt(nsset
, subdomain
, flawedNSSet
, qname
, qtype
, ret
, depth
, beenthere
, state
)))
616 LOG(prefix
<<qname
<<": failed (res="<<res
<<")"<<endl
);
621 return res
<0 ? RCode::ServFail
: res
;
625 // for testing purposes
626 static bool ipv6First(const ComboAddress
& a
, const ComboAddress
& b
)
628 return !(a
.sin4
.sin_family
< a
.sin4
.sin_family
);
634 speedOrderCA(std::map
<ComboAddress
,double>& speeds
): d_speeds(speeds
) {}
635 bool operator()(const ComboAddress
& a
, const ComboAddress
& b
) const
637 return d_speeds
[a
] < d_speeds
[b
];
639 std::map
<ComboAddress
, double>& d_speeds
;
642 /** This function explicitly goes out for A or AAAA addresses
644 vector
<ComboAddress
> SyncRes::getAddrs(const DNSName
&qname
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, bool cacheOnly
)
646 typedef vector
<DNSRecord
> res_t
;
649 typedef vector
<ComboAddress
> ret_t
;
653 bool oldCacheOnly
= d_cacheonly
;
654 bool oldRequireAuthData
= d_requireAuthData
;
655 bool oldValidationRequested
= d_DNSSECValidationRequested
;
656 d_requireAuthData
= false;
657 d_DNSSECValidationRequested
= false;
658 d_cacheonly
= cacheOnly
;
660 for(int j
=1; j
<2+s_doIPv6
; j
++)
675 vState newState
= Indeterminate
;
676 if(!doResolve(qname
, type
, res
,depth
+1, beenthere
, newState
) && !res
.empty()) { // this consults cache, OR goes out
677 for(res_t::const_iterator i
=res
.begin(); i
!= res
.end(); ++i
) {
678 if(i
->d_type
== QType::A
|| i
->d_type
== QType::AAAA
) {
679 if(auto rec
= getRR
<ARecordContent
>(*i
))
680 ret
.push_back(rec
->getCA(53));
681 else if(auto aaaarec
= getRR
<AAAARecordContent
>(*i
))
682 ret
.push_back(aaaarec
->getCA(53));
688 if(j
==1 && s_doIPv6
) { // we got an A record, see if we have some AAAA lying around
689 vector
<DNSRecord
> cset
;
690 if(t_RC
->get(d_now
.tv_sec
, qname
, QType(QType::AAAA
), false, &cset
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
) > 0) {
691 for(auto k
=cset
.cbegin();k
!=cset
.cend();++k
) {
692 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
693 if (auto drc
= getRR
<AAAARecordContent
>(*k
)) {
694 ComboAddress ca
=drc
->getCA(53);
705 d_requireAuthData
= oldRequireAuthData
;
706 d_DNSSECValidationRequested
= oldValidationRequested
;
707 d_cacheonly
= oldCacheOnly
;
709 /* we need to remove from the nsSpeeds collection the existing IPs
710 for this nameserver that are no longer in the set, even if there
711 is only one or none at all in the current set.
713 map
<ComboAddress
, double> speeds
;
714 auto& collection
= t_sstorage
.nsSpeeds
[qname
].d_collection
;
715 for(const auto& val
: ret
) {
716 speeds
[val
] = collection
[val
].get(&d_now
);
719 t_sstorage
.nsSpeeds
[qname
].purge(speeds
);
722 random_shuffle(ret
.begin(), ret
.end(), dns_random
);
723 speedOrderCA
so(speeds
);
724 stable_sort(ret
.begin(), ret
.end(), so
);
727 string prefix
=d_prefix
;
728 prefix
.append(depth
, ' ');
729 LOG(prefix
<<"Nameserver "<<qname
<<" IPs: ");
731 for(const auto& addr
: ret
) {
738 LOG((addr
.toString())<<"(" << (boost::format("%0.2f") % (speeds
[addr
]/1000.0)).str() <<"ms)");
747 void SyncRes::getBestNSFromCache(const DNSName
&qname
, const QType
& qtype
, vector
<DNSRecord
>& bestns
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
)
750 DNSName
subdomain(qname
);
753 prefix
.append(depth
, ' ');
759 LOG(prefix
<<qname
<<": Checking if we have NS in cache for '"<<subdomain
<<"'"<<endl
);
760 vector
<DNSRecord
> ns
;
761 *flawedNSSet
= false;
763 if(t_RC
->get(d_now
.tv_sec
, subdomain
, QType(QType::NS
), false, &ns
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
) > 0) {
764 for(auto k
=ns
.cbegin();k
!=ns
.cend(); ++k
) {
765 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
766 vector
<DNSRecord
> aset
;
768 const DNSRecord
& dr
=*k
;
769 auto nrr
= getRR
<NSRecordContent
>(dr
);
770 if(nrr
&& (!nrr
->getNS().isPartOf(subdomain
) || t_RC
->get(d_now
.tv_sec
, nrr
->getNS(), s_doIPv6
? QType(QType::ADDR
) : QType(QType::A
),
771 false, doLog() ? &aset
: 0, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
) > 5)) {
772 bestns
.push_back(dr
);
773 LOG(prefix
<<qname
<<": NS (with ip, or non-glue) in cache for '"<<subdomain
<<"' -> '"<<nrr
->getNS()<<"'"<<endl
);
774 LOG(prefix
<<qname
<<": within bailiwick: "<< nrr
->getNS().isPartOf(subdomain
));
776 LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset
.begin()->d_ttl
- d_now
.tv_sec
))<<endl
);
779 LOG(", not in cache / did not look at cache"<<endl
);
784 LOG(prefix
<<qname
<<": NS in cache for '"<<subdomain
<<"', but needs glue ("<<nrr
->getNS()<<") which we miss or is expired"<<endl
);
789 if(!bestns
.empty()) {
790 GetBestNSAnswer answer
;
792 answer
.qtype
=qtype
.getCode();
793 for(const auto& dr
: bestns
) {
794 if (auto nsContent
= getRR
<NSRecordContent
>(dr
)) {
795 answer
.bestns
.insert(make_pair(dr
.d_name
, nsContent
->getNS()));
799 if(beenthere
.count(answer
)) {
801 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' but part of LOOP (already seen "<<answer
.qname
<<")! Trying less specific NS"<<endl
);
804 for( set
<GetBestNSAnswer
>::const_iterator j
=beenthere
.begin();j
!=beenthere
.end();++j
) {
805 bool neo
= !(*j
< answer
|| answer
<*j
);
806 LOG(prefix
<<qname
<<": beenthere"<<(neo
?"*":"")<<": "<<j
->qname
<<"|"<<DNSRecordContent::NumberToType(j
->qtype
)<<" ("<<(unsigned int)j
->bestns
.size()<<")"<<endl
);
811 beenthere
.insert(answer
);
812 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' (flawedNSSet="<<*flawedNSSet
<<")"<<endl
);
817 LOG(prefix
<<qname
<<": no valid/useful NS in cache for '"<<subdomain
<<"'"<<endl
);
819 if(subdomain
.isRoot() && !brokeloop
) {
820 // We lost the root NS records
822 LOG(prefix
<<qname
<<": reprimed the root"<<endl
);
823 /* let's prevent an infinite loop */
824 if (!d_updatingRootNS
) {
825 getRootNS(d_now
, d_asyncResolve
);
828 } while(subdomain
.chopOff());
831 SyncRes::domainmap_t::const_iterator
SyncRes::getBestAuthZone(DNSName
* qname
) const
833 SyncRes::domainmap_t::const_iterator ret
;
835 ret
=t_sstorage
.domainmap
->find(*qname
);
836 if(ret
!=t_sstorage
.domainmap
->end())
838 }while(qname
->chopOff());
842 /** doesn't actually do the work, leaves that to getBestNSFromCache */
843 DNSName
SyncRes::getBestNSNamesFromCache(const DNSName
&qname
, const QType
& qtype
, NsSet
& nsset
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
)
845 DNSName
subdomain(qname
);
846 DNSName
authdomain(qname
);
848 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
849 if(iter
!=t_sstorage
.domainmap
->end()) {
850 if( iter
->second
.isAuth() )
851 // this gets picked up in doResolveAt, the empty DNSName, combined with the
852 // empty vector means 'we are auth for this zone'
853 nsset
.insert({DNSName(), {{}, false}});
855 // Again, picked up in doResolveAt. An empty DNSName, combined with a
856 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
857 // This is actually picked up in retrieveAddressesForNS called from doResolveAt.
858 nsset
.insert({DNSName(), {iter
->second
.d_servers
, iter
->second
.shouldRecurse() }});
863 vector
<DNSRecord
> bestns
;
864 getBestNSFromCache(subdomain
, qtype
, bestns
, flawedNSSet
, depth
, beenthere
);
866 for(auto k
=bestns
.cbegin() ; k
!= bestns
.cend(); ++k
) {
867 // The actual resolver code will not even look at the ComboAddress or bool
868 const auto nsContent
= getRR
<NSRecordContent
>(*k
);
870 nsset
.insert({nsContent
->getNS(), {{}, false}});
871 if(k
==bestns
.cbegin())
878 bool SyncRes::doCNAMECacheCheck(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>& ret
, unsigned int depth
, int &res
, vState
& state
, bool wasAuthZone
)
883 prefix
.append(depth
, ' ');
886 if((depth
>9 && d_outqueries
>10 && d_throttledqueries
>5) || depth
> 15) {
887 LOG(prefix
<<qname
<<": recursing (CNAME or other indirection) too deep, depth="<<depth
<<endl
);
892 LOG(prefix
<<qname
<<": Looking for CNAME cache hit of '"<<qname
<<"|CNAME"<<"'"<<endl
);
893 vector
<DNSRecord
> cset
;
894 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
895 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
897 if(t_RC
->get(d_now
.tv_sec
, qname
, QType(QType::CNAME
), d_requireAuthData
, &cset
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, d_doDNSSEC
? &signatures
: nullptr, d_doDNSSEC
? &authorityRecs
: nullptr, &d_wasVariable
, &state
, &wasAuth
) > 0) {
899 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
900 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
902 if (!wasAuthZone
&& shouldValidate() && wasAuth
&& state
== Indeterminate
&& d_requireAuthData
) {
903 /* This means we couldn't figure out the state when this entry was cached,
904 most likely because we hadn't computed the zone cuts yet. */
905 /* make sure they are computed before validating */
906 DNSName
subdomain(qname
);
907 /* if we are retrieving a DS, we only care about the state of the parent zone */
908 if(qtype
== QType::DS
)
911 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
913 vState recordState
= getValidationStatus(qname
, false);
914 if (recordState
== Secure
) {
915 LOG(prefix
<<qname
<<": got Indeterminate state from the CNAME cache, validating.."<<endl
);
916 state
= SyncRes::validateRecordsWithSigs(depth
, qname
, QType(QType::CNAME
), qname
, cset
, signatures
);
917 if (state
!= Indeterminate
) {
918 LOG(prefix
<<qname
<<": got Indeterminate state from the CNAME cache, new validation result is "<<vStates
[state
]<<endl
);
919 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, QType(QType::CNAME
), d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, d_requireAuthData
, state
);
924 LOG(prefix
<<qname
<<": Found cache CNAME hit for '"<< qname
<< "|CNAME" <<"' to '"<<j
->d_content
->getZoneRepresentation()<<"', validation state is "<<vStates
[state
]<<endl
);
927 dr
.d_ttl
-=d_now
.tv_sec
;
930 for(const auto& signature
: signatures
) {
932 sigdr
.d_type
=QType::RRSIG
;
934 sigdr
.d_ttl
=j
->d_ttl
- d_now
.tv_sec
;
935 sigdr
.d_content
=signature
;
936 sigdr
.d_place
=DNSResourceRecord::ANSWER
;
937 sigdr
.d_class
=QClass::IN
;
938 ret
.push_back(sigdr
);
941 for(const auto& rec
: authorityRecs
) {
942 DNSRecord
authDR(*rec
);
943 authDR
.d_ttl
=j
->d_ttl
- d_now
.tv_sec
;
944 ret
.push_back(authDR
);
947 if(qtype
!= QType::CNAME
) { // perhaps they really wanted a CNAME!
948 set
<GetBestNSAnswer
>beenthere
;
950 vState cnameState
= Indeterminate
;
951 const auto cnameContent
= getRR
<CNAMERecordContent
>(*j
);
953 res
=doResolve(cnameContent
->getTarget(), qtype
, ret
, depth
+1, beenthere
, cnameState
);
954 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
955 updateValidationState(state
, cnameState
);
965 LOG(prefix
<<qname
<<": No CNAME cache hit of '"<< qname
<< "|CNAME" <<"' found"<<endl
);
972 vector
<DNSRecord
> records
;
973 vector
<shared_ptr
<RRSIGRecordContent
>> signatures
;
974 uint32_t signaturesTTL
{std::numeric_limits
<uint32_t>::max()};
980 DNSResourceRecord::Place place
;
981 bool operator<(const CacheKey
& rhs
) const {
982 return tie(name
, type
) < tie(rhs
.name
, rhs
.type
);
985 typedef map
<CacheKey
, CacheEntry
> tcache_t
;
988 static void reapRecordsFromNegCacheEntryForValidation(tcache_t
& tcache
, const vector
<DNSRecord
>& records
)
990 for (const auto& rec
: records
) {
991 if (rec
.d_type
== QType::RRSIG
) {
992 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
994 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
997 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(rec
);
1003 * Convience function to push the records from records into ret with a new TTL
1005 * \param records DNSRecords that need to go into ret
1006 * \param ttl The new TTL for these records
1007 * \param ret The vector of DNSRecords that should contian the records with the modified TTL
1009 static void addTTLModifiedRecords(const vector
<DNSRecord
>& records
, const uint32_t ttl
, vector
<DNSRecord
>& ret
) {
1010 for (const auto& rec
: records
) {
1017 void SyncRes::computeNegCacheValidationStatus(NegCache::NegCacheEntry
& ne
, const DNSName
& qname
, const QType
& qtype
, const int res
, vState
& state
, unsigned int depth
)
1019 DNSName
subdomain(qname
);
1020 /* if we are retrieving a DS, we only care about the state of the parent zone */
1021 if(qtype
== QType::DS
)
1022 subdomain
.chopOff();
1024 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1027 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.authoritySOA
.records
);
1028 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.authoritySOA
.signatures
);
1029 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.DNSSECRecords
.records
);
1030 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.DNSSECRecords
.signatures
);
1032 for (const auto& entry
: tcache
) {
1033 // this happens when we did store signatures, but passed on the records themselves
1034 if (entry
.second
.records
.empty()) {
1038 const DNSName
& owner
= entry
.first
.name
;
1040 vState recordState
= getValidationStatus(owner
, false);
1041 if (state
== Indeterminate
) {
1042 state
= recordState
;
1045 if (recordState
== Secure
) {
1046 recordState
= SyncRes::validateRecordsWithSigs(depth
, qname
, qtype
, owner
, entry
.second
.records
, entry
.second
.signatures
);
1049 if (recordState
!= Indeterminate
&& recordState
!= state
) {
1050 updateValidationState(state
, recordState
);
1051 if (state
!= Secure
) {
1057 if (state
== Secure
) {
1058 dState expectedState
= res
== RCode::NXDomain
? NXDOMAIN
: NXQTYPE
;
1059 dState denialState
= getDenialValidationState(ne
, state
, expectedState
, false);
1060 updateDenialValidationState(ne
, state
, denialState
, expectedState
, qtype
== QType::DS
);
1062 if (state
!= Indeterminate
) {
1063 /* validation succeeded, let's update the cache entry so we don't have to validate again */
1064 t_sstorage
.negcache
.updateValidationStatus(ne
.d_name
, ne
.d_qtype
, state
);
1068 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
)
1070 bool giveNegative
=false;
1075 prefix
.append(depth
, ' ');
1078 // 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)
1079 DNSName
sqname(qname
);
1082 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
1084 NegCache::NegCacheEntry ne
;
1087 t_sstorage
.negcache
.getRootNXTrust(qname
, d_now
, ne
) &&
1088 ne
.d_auth
.isRoot() &&
1089 !(wasForwardedOrAuthZone
&& !authname
.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
1090 sttl
= ne
.d_ttd
- d_now
.tv_sec
;
1091 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
.d_auth
<<"' & '"<<ne
.d_name
<<"' for another "<<sttl
<<" seconds"<<endl
);
1092 res
= RCode::NXDomain
;
1093 giveNegative
= true;
1094 cachedState
= ne
.d_validationState
;
1096 else if (t_sstorage
.negcache
.get(qname
, qtype
, d_now
, ne
) &&
1097 !(wasForwardedOrAuthZone
&& ne
.d_auth
!= authname
)) { // Only the authname nameserver can neg cache entries
1099 /* If we are looking for a DS, discard NXD if auth == qname
1100 and ask for a specific denial instead */
1101 if (qtype
!= QType::DS
|| ne
.d_qtype
.getCode() || ne
.d_auth
!= qname
||
1102 t_sstorage
.negcache
.get(qname
, qtype
, d_now
, ne
, true))
1105 sttl
= ne
.d_ttd
- d_now
.tv_sec
;
1106 giveNegative
= true;
1107 cachedState
= ne
.d_validationState
;
1108 if(ne
.d_qtype
.getCode()) {
1109 LOG(prefix
<<qname
<<": "<<qtype
.getName()<<" is negatively cached via '"<<ne
.d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1110 res
= RCode::NoError
;
1113 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
.d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1114 res
= RCode::NXDomain
;
1121 state
= cachedState
;
1123 if (!wasAuthZone
&& shouldValidate() && state
== Indeterminate
) {
1124 LOG(prefix
<<qname
<<": got Indeterminate state for records retrieved from the negative cache, validating.."<<endl
);
1125 computeNegCacheValidationStatus(ne
, qname
, qtype
, res
, state
, depth
);
1128 // Transplant SOA to the returned packet
1129 addTTLModifiedRecords(ne
.authoritySOA
.records
, sttl
, ret
);
1131 addTTLModifiedRecords(ne
.authoritySOA
.signatures
, sttl
, ret
);
1132 addTTLModifiedRecords(ne
.DNSSECRecords
.records
, sttl
, ret
);
1133 addTTLModifiedRecords(ne
.DNSSECRecords
.signatures
, sttl
, ret
);
1136 LOG(prefix
<<qname
<<": updating validation state with negative cache content for "<<qname
<<" to "<<vStates
[state
]<<endl
);
1140 vector
<DNSRecord
> cset
;
1141 bool found
=false, expired
=false;
1142 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
1143 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1146 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) {
1148 LOG(prefix
<<sqname
<<": Found cache hit for "<<sqt
.getName()<<": ");
1150 if (!wasAuthZone
&& shouldValidate() && wasCachedAuth
&& cachedState
== Indeterminate
&& d_requireAuthData
) {
1152 /* This means we couldn't figure out the state when this entry was cached,
1153 most likely because we hadn't computed the zone cuts yet. */
1154 /* make sure they are computed before validating */
1155 DNSName
subdomain(sqname
);
1156 /* if we are retrieving a DS, we only care about the state of the parent zone */
1157 if(qtype
== QType::DS
)
1158 subdomain
.chopOff();
1160 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1162 vState recordState
= getValidationStatus(qname
, false);
1163 if (recordState
== Secure
) {
1164 LOG(prefix
<<sqname
<<": got Indeterminate state from the cache, validating.."<<endl
);
1165 cachedState
= SyncRes::validateRecordsWithSigs(depth
, sqname
, sqt
, sqname
, cset
, signatures
);
1168 cachedState
= recordState
;
1171 if (cachedState
!= Indeterminate
) {
1172 LOG(prefix
<<qname
<<": got Indeterminate state from the cache, validation result is "<<vStates
[cachedState
]<<endl
);
1173 t_RC
->updateValidationStatus(d_now
.tv_sec
, sqname
, sqt
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, d_requireAuthData
, cachedState
);
1177 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
1178 LOG(j
->d_content
->getZoneRepresentation());
1179 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
1181 ttl
= (dr
.d_ttl
-=d_now
.tv_sec
);
1183 LOG("[ttl="<<dr
.d_ttl
<<"] ");
1192 for(const auto& signature
: signatures
) {
1194 dr
.d_type
=QType::RRSIG
;
1197 dr
.d_content
=signature
;
1198 dr
.d_place
= DNSResourceRecord::ANSWER
;
1199 dr
.d_class
=QClass::IN
;
1203 for(const auto& rec
: authorityRecs
) {
1210 if(found
&& !expired
) {
1213 LOG(prefix
<<qname
<<": updating validation state with cache content for "<<qname
<<" to "<<vStates
[cachedState
]<<endl
);
1214 state
= cachedState
;
1218 LOG(prefix
<<qname
<<": cache had only stale entries"<<endl
);
1224 bool SyncRes::moreSpecificThan(const DNSName
& a
, const DNSName
&b
) const
1226 return (a
.isPartOf(b
) && a
.countLabels() > b
.countLabels());
1231 speedOrder(map
<DNSName
,double> &speeds
) : d_speeds(speeds
) {}
1232 bool operator()(const DNSName
&a
, const DNSName
&b
) const
1234 return d_speeds
[a
] < d_speeds
[b
];
1236 map
<DNSName
, double>& d_speeds
;
1239 inline vector
<DNSName
> SyncRes::shuffleInSpeedOrder(NsSet
&tnameservers
, const string
&prefix
)
1241 vector
<DNSName
> rnameservers
;
1242 rnameservers
.reserve(tnameservers
.size());
1243 for(const auto& tns
: tnameservers
) {
1244 rnameservers
.push_back(tns
.first
);
1245 if(tns
.first
.empty()) // this was an authoritative OOB zone, don't pollute the nsSpeeds with that
1246 return rnameservers
;
1248 map
<DNSName
, double> speeds
;
1250 for(const auto& val
: rnameservers
) {
1252 speed
=t_sstorage
.nsSpeeds
[val
].get(&d_now
);
1255 random_shuffle(rnameservers
.begin(),rnameservers
.end(), dns_random
);
1256 speedOrder
so(speeds
);
1257 stable_sort(rnameservers
.begin(),rnameservers
.end(), so
);
1260 LOG(prefix
<<"Nameservers: ");
1261 for(vector
<DNSName
>::const_iterator i
=rnameservers
.begin();i
!=rnameservers
.end();++i
) {
1262 if(i
!=rnameservers
.begin()) {
1264 if(!((i
-rnameservers
.begin())%3)) {
1265 LOG(endl
<<prefix
<<" ");
1268 LOG((i
->empty() ? string("<empty>") : i
->toString())<<"(" << (boost::format("%0.2f") % (speeds
[*i
]/1000.0)).str() <<"ms)");
1272 return rnameservers
;
1275 static uint32_t getRRSIGTTL(const time_t now
, const std::shared_ptr
<RRSIGRecordContent
>& rrsig
)
1278 if (now
< rrsig
->d_sigexpire
) {
1279 res
= static_cast<uint32_t>(rrsig
->d_sigexpire
) - now
;
1284 static const set
<uint16_t> nsecTypes
= {QType::NSEC
, QType::NSEC3
};
1286 /* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
1288 * \param records The records to parse for the authority SOA and NSEC(3) records
1289 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
1291 static void harvestNXRecords(const vector
<DNSRecord
>& records
, NegCache::NegCacheEntry
& ne
, const time_t now
, uint32_t* lowestTTL
) {
1292 for(const auto& rec
: records
) {
1293 if(rec
.d_place
!= DNSResourceRecord::AUTHORITY
)
1294 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
1295 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
1296 // records MUST be in the same section as the records they cover.
1297 // Hence, we ignore all records outside of the AUTHORITY section.
1300 if(rec
.d_type
== QType::RRSIG
) {
1301 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1303 if(rrsig
->d_type
== QType::SOA
) {
1304 ne
.authoritySOA
.signatures
.push_back(rec
);
1305 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1306 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1307 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1310 if(nsecTypes
.count(rrsig
->d_type
)) {
1311 ne
.DNSSECRecords
.signatures
.push_back(rec
);
1312 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1313 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1314 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1320 if(rec
.d_type
== QType::SOA
) {
1321 ne
.authoritySOA
.records
.push_back(rec
);
1323 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1327 if(nsecTypes
.count(rec
.d_type
)) {
1328 ne
.DNSSECRecords
.records
.push_back(rec
);
1330 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1337 static cspmap_t
harvestCSPFromNE(const NegCache::NegCacheEntry
& ne
)
1340 for(const auto& rec
: ne
.DNSSECRecords
.signatures
) {
1341 if(rec
.d_type
== QType::RRSIG
) {
1342 auto rrc
= getRR
<RRSIGRecordContent
>(rec
);
1344 cspmap
[{rec
.d_name
,rrc
->d_type
}].signatures
.push_back(rrc
);
1348 for(const auto& rec
: ne
.DNSSECRecords
.records
) {
1349 cspmap
[{rec
.d_name
, rec
.d_type
}].records
.push_back(rec
.d_content
);
1354 // TODO remove after processRecords is fixed!
1355 // Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
1356 static void addNXNSECS(vector
<DNSRecord
>&ret
, const vector
<DNSRecord
>& records
)
1358 NegCache::NegCacheEntry ne
;
1359 harvestNXRecords(records
, ne
, 0, nullptr);
1360 ret
.insert(ret
.end(), ne
.authoritySOA
.signatures
.begin(), ne
.authoritySOA
.signatures
.end());
1361 ret
.insert(ret
.end(), ne
.DNSSECRecords
.records
.begin(), ne
.DNSSECRecords
.records
.end());
1362 ret
.insert(ret
.end(), ne
.DNSSECRecords
.signatures
.begin(), ne
.DNSSECRecords
.signatures
.end());
1365 bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine
& dfe
, const NsSet
& nameservers
)
1368 for (auto const &ns
: nameservers
) {
1369 d_appliedPolicy
= dfe
.getProcessingPolicy(ns
.first
, d_discardedPolicies
);
1370 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1371 LOG(", however nameserver "<<ns
.first
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1375 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1376 for (auto const &address
: ns
.second
.first
) {
1377 d_appliedPolicy
= dfe
.getProcessingPolicy(address
, d_discardedPolicies
);
1378 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1379 LOG(", however nameserver "<<ns
.first
<<" IP address "<<address
.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1388 bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine
& dfe
, const ComboAddress
& remoteIP
)
1391 d_appliedPolicy
= dfe
.getProcessingPolicy(remoteIP
, d_discardedPolicies
);
1392 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) {
1393 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")+"')");
1400 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
)
1402 vector
<ComboAddress
> result
;
1405 LOG(prefix
<<qname
<<": Trying to resolve NS '"<<*tns
<< "' ("<<1+tns
-rnameservers
.begin()<<"/"<<(unsigned int)rnameservers
.size()<<")"<<endl
);
1406 result
= getAddrs(*tns
, depth
+2, beenthere
, cacheOnly
);
1407 pierceDontQuery
=false;
1410 LOG(prefix
<<qname
<<": Domain has hardcoded nameserver");
1412 result
= nameservers
[*tns
].first
;
1413 if(result
.size() > 1) {
1418 sendRDQuery
= nameservers
[*tns
].second
;
1419 pierceDontQuery
=true;
1424 bool SyncRes::throttledOrBlocked(const std::string
& prefix
, const ComboAddress
& remoteIP
, const DNSName
& qname
, const QType
& qtype
, bool pierceDontQuery
)
1426 if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0))) {
1427 LOG(prefix
<<qname
<<": server throttled "<<endl
);
1428 s_throttledqueries
++; d_throttledqueries
++;
1431 else if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()))) {
1432 LOG(prefix
<<qname
<<": query throttled "<<remoteIP
.toString()<<", "<<qname
<<"; "<<qtype
.getName()<<endl
);
1433 s_throttledqueries
++; d_throttledqueries
++;
1436 else if(!pierceDontQuery
&& s_dontQuery
&& s_dontQuery
->match(&remoteIP
)) {
1437 LOG(prefix
<<qname
<<": not sending query to " << remoteIP
.toString() << ", blocked by 'dont-query' setting" << endl
);
1444 bool SyncRes::validationEnabled() const
1446 return g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
;
1449 uint32_t SyncRes::computeLowestTTD(const std::vector
<DNSRecord
>& records
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, uint32_t signaturesTTL
) const
1451 uint32_t lowestTTD
= std::numeric_limits
<uint32_t>::max();
1452 for(const auto& record
: records
)
1453 lowestTTD
= min(lowestTTD
, record
.d_ttl
);
1455 /* even if it was not requested for that request (Process, and neither AD nor DO set),
1456 it might be requested at a later time so we need to be careful with the TTL. */
1457 if (validationEnabled() && !signatures
.empty()) {
1458 /* if we are validating, we don't want to cache records after their signatures expire. */
1459 /* records TTL are now TTD, let's add 'now' to the signatures lowest TTL */
1460 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(signaturesTTL
+ d_now
.tv_sec
));
1462 for(const auto& sig
: signatures
) {
1463 if (isRRSIGNotExpired(d_now
.tv_sec
, sig
)) {
1464 // we don't decerement d_sigexpire by 'now' because we actually want a TTD, not a TTL */
1465 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(sig
->d_sigexpire
));
1473 void SyncRes::updateValidationState(vState
& state
, const vState stateUpdate
)
1475 LOG(d_prefix
<<"validation state was "<<std::string(vStates
[state
])<<", state update is "<<std::string(vStates
[stateUpdate
]));
1477 if (stateUpdate
== TA
) {
1480 else if (stateUpdate
== NTA
) {
1483 else if (stateUpdate
== Bogus
) {
1486 else if (state
== Indeterminate
) {
1487 state
= stateUpdate
;
1489 else if (stateUpdate
== Insecure
) {
1490 if (state
!= Bogus
) {
1494 LOG(", validation state is now "<<std::string(vStates
[state
])<<endl
);
1497 vState
SyncRes::getTA(const DNSName
& zone
, dsmap_t
& ds
)
1499 auto luaLocal
= g_luaconfs
.getLocal();
1501 if (luaLocal
->dsAnchors
.empty()) {
1502 LOG(d_prefix
<<": No trust anchors configured, everything is Insecure"<<endl
);
1503 /* We have no TA, everything is insecure */
1508 if (haveNegativeTrustAnchor(luaLocal
->negAnchors
, zone
, reason
)) {
1509 LOG(d_prefix
<<": got NTA for '"<<zone
<<"'"<<endl
);
1513 if (getTrustAnchor(luaLocal
->dsAnchors
, zone
, ds
)) {
1514 LOG(d_prefix
<<": got TA for '"<<zone
<<"'"<<endl
);
1518 LOG(d_prefix
<<": no TA found for '"<<zone
<<"' among "<< luaLocal
->dsAnchors
.size()<<endl
);
1521 if (zone
.isRoot()) {
1522 /* No TA for the root */
1526 return Indeterminate
;
1529 static size_t countSupportedDS(const dsmap_t
& dsmap
)
1533 for (const auto& ds
: dsmap
) {
1534 if (isSupportedDS(ds
)) {
1542 vState
SyncRes::getDSRecords(const DNSName
& zone
, dsmap_t
& ds
, bool taOnly
, unsigned int depth
, bool bogusOnNXD
, bool* foundCut
)
1544 vState result
= getTA(zone
, ds
);
1546 if (result
!= Indeterminate
|| taOnly
) {
1548 *foundCut
= (result
!= Indeterminate
);
1552 if (countSupportedDS(ds
) == 0) {
1560 else if (result
== NTA
) {
1567 bool oldSkipCNAME
= d_skipCNAMECheck
;
1568 d_skipCNAMECheck
= true;
1570 std::set
<GetBestNSAnswer
> beenthere
;
1571 std::vector
<DNSRecord
> dsrecords
;
1573 vState state
= Indeterminate
;
1574 int rcode
= doResolve(zone
, QType(QType::DS
), dsrecords
, depth
+ 1, beenthere
, state
);
1575 d_skipCNAMECheck
= oldSkipCNAME
;
1577 if (rcode
== RCode::NoError
|| (rcode
== RCode::NXDomain
&& !bogusOnNXD
)) {
1579 uint8_t bestDigestType
= 0;
1581 if (state
== Secure
) {
1582 bool gotCNAME
= false;
1583 for (const auto& record
: dsrecords
) {
1584 if (record
.d_type
== QType::DS
) {
1585 const auto dscontent
= getRR
<DSRecordContent
>(record
);
1586 if (dscontent
&& isSupportedDS(*dscontent
)) {
1587 // Make GOST a lower prio than SHA256
1588 if (dscontent
->d_digesttype
== DNSSECKeeper::GOST
&& bestDigestType
== DNSSECKeeper::SHA256
) {
1591 if (dscontent
->d_digesttype
> bestDigestType
|| (bestDigestType
== DNSSECKeeper::GOST
&& dscontent
->d_digesttype
== DNSSECKeeper::SHA256
)) {
1592 bestDigestType
= dscontent
->d_digesttype
;
1594 ds
.insert(*dscontent
);
1597 else if (record
.d_type
== QType::CNAME
&& record
.d_name
== zone
) {
1602 /* RFC 4509 section 3: "Validator implementations SHOULD ignore DS RRs containing SHA-1
1603 * digests if DS RRs with SHA-256 digests are present in the DS RRset."
1604 * As SHA348 is specified as well, the spirit of the this line is "use the best algorithm".
1606 for (auto dsrec
= ds
.begin(); dsrec
!= ds
.end(); ) {
1607 if (dsrec
->d_digesttype
!= bestDigestType
) {
1608 dsrec
= ds
.erase(dsrec
);
1615 if (rcode
== RCode::NoError
&& ds
.empty()) {
1617 if (gotCNAME
|| denialProvesNoDelegation(zone
, dsrecords
)) {
1618 /* we are still inside the same Secure zone */
1628 } else if (foundCut
&& rcode
== RCode::NoError
&& !ds
.empty()) {
1636 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
1640 bool SyncRes::haveExactValidationStatus(const DNSName
& domain
)
1642 if (!shouldValidate()) {
1645 const auto& it
= d_cutStates
.find(domain
);
1646 if (it
!= d_cutStates
.cend()) {
1652 vState
SyncRes::getValidationStatus(const DNSName
& subdomain
, bool allowIndeterminate
)
1654 vState result
= Indeterminate
;
1656 if (!shouldValidate()) {
1659 DNSName
name(subdomain
);
1661 const auto& it
= d_cutStates
.find(name
);
1662 if (it
!= d_cutStates
.cend()) {
1663 if (allowIndeterminate
|| it
->second
!= Indeterminate
) {
1664 LOG(d_prefix
<<": got status "<<vStates
[it
->second
]<<" for name "<<subdomain
<<" (from "<<name
<<")"<<endl
);
1669 while (name
.chopOff());
1674 bool SyncRes::lookForCut(const DNSName
& qname
, unsigned int depth
, const vState existingState
, vState
& newState
)
1676 bool foundCut
= false;
1678 vState dsState
= getDSRecords(qname
, ds
, newState
== Bogus
|| existingState
== Insecure
|| existingState
== Bogus
, depth
, false, &foundCut
);
1680 if (dsState
!= Indeterminate
) {
1687 void SyncRes::computeZoneCuts(const DNSName
& begin
, const DNSName
& end
, unsigned int depth
)
1689 if(!begin
.isPartOf(end
)) {
1690 LOG(d_prefix
<<" "<<begin
.toLogString()<<" is not part of "<<end
.toString()<<endl
);
1691 throw PDNSException(begin
.toLogString() + " is not part of " + end
.toString());
1694 if (d_cutStates
.count(begin
) != 0) {
1699 vState cutState
= getDSRecords(end
, ds
, false, depth
);
1700 LOG(d_prefix
<<": setting cut state for "<<end
<<" to "<<vStates
[cutState
]<<endl
);
1701 d_cutStates
[end
] = cutState
;
1703 if (!shouldValidate()) {
1708 std::vector
<string
> labelsToAdd
= begin
.makeRelative(end
).getRawLabels();
1710 bool oldSkipCNAME
= d_skipCNAMECheck
;
1711 d_skipCNAMECheck
= true;
1713 while(qname
!= begin
) {
1714 if (labelsToAdd
.empty())
1717 qname
.prependRawLabel(labelsToAdd
.back());
1718 labelsToAdd
.pop_back();
1719 LOG(d_prefix
<<": - Looking for a cut at "<<qname
<<endl
);
1721 const auto cutIt
= d_cutStates
.find(qname
);
1722 if (cutIt
!= d_cutStates
.cend()) {
1723 if (cutIt
->second
!= Indeterminate
) {
1724 LOG(d_prefix
<<": - Cut already known at "<<qname
<<endl
);
1725 cutState
= cutIt
->second
;
1730 /* no need to look for NS and DS if we are already insecure or bogus,
1733 if (cutState
== Insecure
|| cutState
== Bogus
) {
1735 vState newState
= getDSRecords(qname
, cutDS
, true, depth
);
1736 if (newState
== Indeterminate
) {
1740 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[newState
]<<endl
);
1741 cutState
= newState
;
1743 d_cutStates
[qname
] = cutState
;
1748 vState newState
= Indeterminate
;
1749 /* temporarily mark as Indeterminate, so that we won't enter an endless loop
1750 trying to determine that zone cut again. */
1751 d_cutStates
[qname
] = newState
;
1752 bool foundCut
= lookForCut(qname
, depth
+ 1, cutState
, newState
);
1754 LOG(d_prefix
<<": - Found cut at "<<qname
<<endl
);
1755 if (newState
!= Indeterminate
) {
1756 cutState
= newState
;
1758 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[cutState
]<<endl
);
1759 d_cutStates
[qname
] = cutState
;
1762 /* remove the temporary cut */
1763 LOG(d_prefix
<<qname
<<": removing cut state for "<<qname
<<endl
);
1764 d_cutStates
.erase(qname
);
1768 d_skipCNAMECheck
= oldSkipCNAME
;
1770 LOG(d_prefix
<<": list of cuts from "<<begin
<<" to "<<end
<<endl
);
1771 for (const auto& cut
: d_cutStates
) {
1772 if (cut
.first
.isRoot() || (begin
.isPartOf(cut
.first
) && cut
.first
.isPartOf(end
))) {
1773 LOG(" - "<<cut
.first
<<": "<<vStates
[cut
.second
]<<endl
);
1778 vState
SyncRes::validateDNSKeys(const DNSName
& zone
, const std::vector
<DNSRecord
>& dnskeys
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, unsigned int depth
)
1781 if (!signatures
.empty()) {
1782 DNSName signer
= getSigner(signatures
);
1784 if (!signer
.empty() && zone
.isPartOf(signer
)) {
1785 vState state
= getDSRecords(signer
, ds
, false, depth
);
1787 if (state
!= Secure
) {
1793 skeyset_t tentativeKeys
;
1794 std::vector
<shared_ptr
<DNSRecordContent
> > toSign
;
1796 for (const auto& dnskey
: dnskeys
) {
1797 if (dnskey
.d_type
== QType::DNSKEY
) {
1798 auto content
= getRR
<DNSKEYRecordContent
>(dnskey
);
1800 tentativeKeys
.insert(content
);
1801 toSign
.push_back(content
);
1806 LOG(d_prefix
<<": trying to validate "<<std::to_string(tentativeKeys
.size())<<" DNSKEYs with "<<std::to_string(ds
.size())<<" DS"<<endl
);
1807 skeyset_t validatedKeys
;
1808 validateDNSKeysAgainstDS(d_now
.tv_sec
, zone
, ds
, tentativeKeys
, toSign
, signatures
, validatedKeys
);
1810 LOG(d_prefix
<<": we now have "<<std::to_string(validatedKeys
.size())<<" DNSKEYs"<<endl
);
1812 /* if we found at least one valid RRSIG covering the set,
1813 all tentative keys are validated keys. Otherwise it means
1814 we haven't found at least one DNSKEY and a matching RRSIG
1815 covering this set, this looks Bogus. */
1816 if (validatedKeys
.size() != tentativeKeys
.size()) {
1817 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
1824 vState
SyncRes::getDNSKeys(const DNSName
& signer
, skeyset_t
& keys
, unsigned int depth
)
1826 std::vector
<DNSRecord
> records
;
1827 std::set
<GetBestNSAnswer
> beenthere
;
1828 LOG(d_prefix
<<"Retrieving DNSKeys for "<<signer
<<endl
);
1830 vState state
= Indeterminate
;
1831 /* following CNAME might lead to us to the wrong DNSKEY */
1832 bool oldSkipCNAME
= d_skipCNAMECheck
;
1833 d_skipCNAMECheck
= true;
1834 int rcode
= doResolve(signer
, QType(QType::DNSKEY
), records
, depth
+ 1, beenthere
, state
);
1835 d_skipCNAMECheck
= oldSkipCNAME
;
1837 if (rcode
== RCode::NoError
) {
1838 if (state
== Secure
) {
1839 for (const auto& key
: records
) {
1840 if (key
.d_type
== QType::DNSKEY
) {
1841 auto content
= getRR
<DNSKEYRecordContent
>(key
);
1843 keys
.insert(content
);
1848 LOG(d_prefix
<<"Retrieved "<<keys
.size()<<" DNSKeys for "<<signer
<<", state is "<<vStates
[state
]<<endl
);
1852 LOG(d_prefix
<<"Returning Bogus state from "<<__func__
<<"("<<signer
<<")"<<endl
);
1856 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
)
1859 if (!signatures
.empty()) {
1860 const DNSName signer
= getSigner(signatures
);
1861 if (!signer
.empty() && name
.isPartOf(signer
)) {
1862 if ((qtype
== QType::DNSKEY
|| qtype
== QType::DS
) && signer
== qname
) {
1863 /* we are already retrieving those keys, sorry */
1864 return Indeterminate
;
1866 vState state
= getDNSKeys(signer
, keys
, depth
);
1867 if (state
!= Secure
) {
1872 LOG(d_prefix
<<"Bogus!"<<endl
);
1876 std::vector
<std::shared_ptr
<DNSRecordContent
> > recordcontents
;
1877 for (const auto& record
: records
) {
1878 recordcontents
.push_back(record
.d_content
);
1881 LOG(d_prefix
<<"Going to validate "<<recordcontents
.size()<< " record contents with "<<signatures
.size()<<" sigs and "<<keys
.size()<<" keys for "<<name
<<endl
);
1882 if (validateWithKeySet(d_now
.tv_sec
, name
, recordcontents
, signatures
, keys
, false)) {
1883 LOG(d_prefix
<<"Secure!"<<endl
);
1887 LOG(d_prefix
<<"Bogus!"<<endl
);
1891 RCode::rcodes_
SyncRes::updateCacheFromRecords(unsigned int depth
, LWResult
& lwr
, const DNSName
& qname
, const QType
& qtype
, const DNSName
& auth
, bool wasForwarded
, const boost::optional
<Netmask
> ednsmask
, vState
& state
, bool& needWildcardProof
, unsigned int& wildcardLabelsCount
)
1898 prefix
.append(depth
, ' ');
1901 std::vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1902 const unsigned int labelCount
= qname
.countLabels();
1903 bool isCNAMEAnswer
= false;
1904 for(const auto& rec
: lwr
.d_records
) {
1905 if(!isCNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
) {
1906 isCNAMEAnswer
= true;
1909 /* if we have a positive answer synthetized from a wildcard,
1910 we need to store the corresponding NSEC/NSEC3 records proving
1911 that the exact name did not exist in the negative cache */
1912 if(needWildcardProof
) {
1913 if (nsecTypes
.count(rec
.d_type
)) {
1914 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
1916 else if (rec
.d_type
== QType::RRSIG
) {
1917 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1918 if (rrsig
&& nsecTypes
.count(rrsig
->d_type
)) {
1919 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
1923 if(rec
.d_type
== QType::RRSIG
) {
1924 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1926 /* As illustrated in rfc4035's Appendix B.6, the RRSIG label
1927 count can be lower than the name's label count if it was
1928 synthetized from the wildcard. Note that the difference might
1930 if (rec
.d_name
== qname
&& rrsig
->d_labels
< labelCount
) {
1931 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthetized from a wildcard, we need a wildcard proof"<<endl
);
1932 needWildcardProof
= true;
1933 wildcardLabelsCount
= rrsig
->d_labels
;
1936 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
1937 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
1938 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
);
1943 // reap all answers from this packet that are acceptable
1944 for(auto& rec
: lwr
.d_records
) {
1945 if(rec
.d_type
== QType::OPT
) {
1946 LOG(prefix
<<qname
<<": OPT answer '"<<rec
.d_name
<<"' from '"<<auth
<<"' nameservers" <<endl
);
1949 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
<<" ");
1950 if(rec
.d_type
== QType::ANY
) {
1951 LOG("NO! - we don't accept 'ANY' data"<<endl
);
1955 if(rec
.d_name
.isPartOf(auth
)) {
1956 if(rec
.d_type
== QType::RRSIG
) {
1957 LOG("RRSIG - separate"<<endl
);
1959 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
)) {
1960 LOG("NO! Is from delegation-only zone"<<endl
);
1962 return RCode::NXDomain
;
1965 bool haveLogged
= false;
1966 if (!t_sstorage
.domainmap
->empty()) {
1967 // Check if we are authoritative for a zone in this answer
1968 DNSName
tmp_qname(rec
.d_name
);
1969 auto auth_domain_iter
=getBestAuthZone(&tmp_qname
);
1970 if(auth_domain_iter
!=t_sstorage
.domainmap
->end() &&
1971 auth
.countLabels() <= auth_domain_iter
->first
.countLabels()) {
1972 if (auth_domain_iter
->first
!= auth
) {
1973 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter
->first
<<endl
);
1976 LOG("YES! - This answer was ");
1977 if (!wasForwarded
) {
1978 LOG("retrieved from the local auth store.");
1980 LOG("received from a server we forward to.");
1991 rec
.d_ttl
=min(s_maxcachettl
, rec
.d_ttl
);
1994 dr
.d_ttl
+= d_now
.tv_sec
;
1995 dr
.d_place
=DNSResourceRecord::ANSWER
;
1996 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(dr
);
2004 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2005 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)
2006 uint32_t lowestTTD
=computeLowestTTD(i
->second
.records
, i
->second
.signatures
, i
->second
.signaturesTTL
);
2008 for(auto& record
: i
->second
.records
)
2009 record
.d_ttl
= lowestTTD
; // boom
2012 // cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
2013 // cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
2016 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2018 if(i
->second
.records
.empty()) // this happens when we did store signatures, but passed on the records themselves
2021 /* Even if the AA bit is set, additional data cannot be considered
2022 as authoritative. This is especially important during validation
2023 because keeping records in the additional section is allowed even
2024 if the corresponding RRSIGs are not included, without setting the TC
2025 bit, as stated in rfc4035's section 3.1.1. Including RRSIG RRs in a Response:
2026 "When placing a signed RRset in the Additional section, the name
2027 server MUST also place its RRSIG RRs in the Additional section.
2028 If space does not permit inclusion of both the RRset and its
2029 associated RRSIG RRs, the name server MAY retain the RRset while
2030 dropping the RRSIG RRs. If this happens, the name server MUST NOT
2031 set the TC bit solely because these RRSIG RRs didn't fit."
2033 bool isAA
= lwr
.d_aabit
&& i
->first
.place
!= DNSResourceRecord::ADDITIONAL
;
2034 if (isAA
&& isCNAMEAnswer
&& (i
->first
.place
!= DNSResourceRecord::ANSWER
|| i
->first
.type
!= QType::CNAME
)) {
2037 Note that the answer section of an authoritative answer normally
2038 contains only authoritative data. However when the name sought is an
2039 alias (see section 10.1.1) only the record describing that alias is
2040 necessarily authoritative. Clients should assume that other records
2041 may have come from the server's cache. Where authoritative answers
2042 are required, the client should query again, using the canonical name
2043 associated with the alias.
2048 vState recordState
= getValidationStatus(i
->first
.name
, false);
2049 LOG(d_prefix
<<": got initial zone status "<<vStates
[recordState
]<<" for record "<<i
->first
.name
<<endl
);
2051 if (shouldValidate() && recordState
== Secure
) {
2052 vState initialState
= recordState
;
2055 if (i
->first
.place
!= DNSResourceRecord::ADDITIONAL
) {
2056 /* the additional entries can be insecure,
2058 "Glue address RRsets associated with delegations MUST NOT be signed"
2060 if (i
->first
.type
== QType::DNSKEY
&& i
->first
.place
== DNSResourceRecord::ANSWER
) {
2061 LOG(d_prefix
<<"Validating DNSKEY for "<<i
->first
.name
<<endl
);
2062 recordState
= validateDNSKeys(i
->first
.name
, i
->second
.records
, i
->second
.signatures
, depth
);
2065 LOG(d_prefix
<<"Validating non-additional record for "<<i
->first
.name
<<endl
);
2066 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2067 /* 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 */
2068 if (qtype
== QType::NS
&& i
->second
.signatures
.empty() && recordState
== Bogus
&& haveExactValidationStatus(i
->first
.name
) && getValidationStatus(i
->first
.name
) == Indeterminate
) {
2069 recordState
= Indeterminate
;
2075 /* in a non authoritative answer, we only care about the DS record (or lack of) */
2076 if ((i
->first
.type
== QType::DS
|| i
->first
.type
== QType::NSEC
|| i
->first
.type
== QType::NSEC3
) && i
->first
.place
== DNSResourceRecord::AUTHORITY
) {
2077 LOG(d_prefix
<<"Validating DS record for "<<i
->first
.name
<<endl
);
2078 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2082 if (initialState
== Secure
&& state
!= recordState
) {
2083 updateValidationState(state
, recordState
);
2087 if (shouldValidate()) {
2088 LOG(d_prefix
<<"Skipping validation because the current state is "<<vStates
[recordState
]<<endl
);
2092 /* We don't need to store NSEC3 records in the positive cache because:
2093 - we don't allow direct NSEC3 queries
2094 - denial of existence proofs in wildcard expanded positive responses are stored in authorityRecs
2095 - denial of existence proofs for negative responses are stored in the negative cache
2097 if (i
->first
.type
!= QType::NSEC3
) {
2098 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
);
2101 if(i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
)
2105 return RCode::NoError
;
2108 void SyncRes::updateDenialValidationState(NegCache::NegCacheEntry
& ne
, vState
& state
, const dState denialState
, const dState expectedState
, bool allowOptOut
)
2110 if (denialState
== expectedState
) {
2111 ne
.d_validationState
= Secure
;
2114 if (denialState
== OPTOUT
&& allowOptOut
) {
2115 LOG(d_prefix
<<"OPT-out denial found for "<<ne
.d_name
<<endl
);
2116 ne
.d_validationState
= Secure
;
2119 else if (denialState
== INSECURE
) {
2120 LOG(d_prefix
<<"Insecure denial found for "<<ne
.d_name
<<", returning Insecure"<<endl
);
2121 ne
.d_validationState
= Insecure
;
2124 LOG(d_prefix
<<"Invalid denial found for "<<ne
.d_name
<<", returning Bogus, res="<<denialState
<<", expectedState="<<expectedState
<<endl
);
2125 ne
.d_validationState
= Bogus
;
2127 updateValidationState(state
, ne
.d_validationState
);
2131 dState
SyncRes::getDenialValidationState(NegCache::NegCacheEntry
& ne
, const vState state
, const dState expectedState
, bool referralToUnsigned
)
2133 cspmap_t csp
= harvestCSPFromNE(ne
);
2134 return getDenial(csp
, ne
.d_name
, ne
.d_qtype
.getCode(), referralToUnsigned
, expectedState
== NXQTYPE
);
2137 bool SyncRes::processRecords(const std::string
& prefix
, const DNSName
& qname
, const QType
& qtype
, const DNSName
& auth
, LWResult
& lwr
, const bool sendRDQuery
, vector
<DNSRecord
>& ret
, set
<DNSName
>& nsset
, DNSName
& newtarget
, DNSName
& newauth
, bool& realreferral
, bool& negindic
, vState
& state
, const bool needWildcardProof
, const unsigned int wildcardLabelsCount
)
2141 for(auto& rec
: lwr
.d_records
) {
2142 if (rec
.d_type
!=QType::OPT
&& rec
.d_class
!=QClass::IN
)
2145 if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2146 lwr
.d_rcode
==RCode::NXDomain
&& qname
.isPartOf(rec
.d_name
) && rec
.d_name
.isPartOf(auth
)) {
2147 LOG(prefix
<<qname
<<": got negative caching indication for name '"<<qname
<<"' (accept="<<rec
.d_name
.isPartOf(auth
)<<"), newtarget='"<<newtarget
<<"'"<<endl
);
2149 rec
.d_ttl
= min(rec
.d_ttl
, s_maxnegttl
);
2150 if(newtarget
.empty()) // only add a SOA if we're not going anywhere after this
2153 NegCache::NegCacheEntry ne
;
2155 uint32_t lowestTTL
= rec
.d_ttl
;
2156 /* if we get an NXDomain answer with a CNAME, the name
2157 does exist but the target does not */
2158 ne
.d_name
= newtarget
.empty() ? qname
: newtarget
;
2159 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2160 ne
.d_auth
= rec
.d_name
;
2161 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2162 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2164 if (state
== Secure
) {
2165 dState denialState
= getDenialValidationState(ne
, state
, NXDOMAIN
, false);
2166 updateDenialValidationState(ne
, state
, denialState
, NXDOMAIN
, false);
2169 ne
.d_validationState
= state
;
2172 /* if we get an NXDomain answer with a CNAME, let's not cache the
2173 target, even the server was authoritative for it,
2174 and do an additional query for the CNAME target.
2175 We have a regression test making sure we do exactly that.
2177 if(!wasVariable() && newtarget
.empty()) {
2178 t_sstorage
.negcache
.add(ne
);
2179 if(s_rootNXTrust
&& ne
.d_auth
.isRoot() && auth
.isRoot()) {
2180 ne
.d_name
= ne
.d_name
.getLastLabel();
2181 t_sstorage
.negcache
.add(ne
);
2187 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_type
==QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
) {
2189 if (auto content
= getRR
<CNAMERecordContent
>(rec
)) {
2190 newtarget
=content
->getTarget();
2193 /* if we have a positive answer synthetized from a wildcard, we need to
2194 return the corresponding NSEC/NSEC3 records from the AUTHORITY section
2195 proving that the exact name did not exist */
2196 else if(needWildcardProof
&& (rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::AUTHORITY
) {
2197 ret
.push_back(rec
); // enjoy your DNSSEC
2199 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
2200 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&&
2202 rec
.d_type
==qtype
.getCode() || ((lwr
.d_aabit
|| sendRDQuery
) && qtype
== QType(QType::ANY
))
2206 LOG(prefix
<<qname
<<": answer is in: resolved to '"<< rec
.d_content
->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"'"<<endl
);
2211 if (state
== Secure
&& needWildcardProof
) {
2212 /* We have a positive answer synthetized from a wildcard, we need to check that we have
2213 proof that the exact name doesn't exist so the wildcard can be used,
2214 as described in section 5.3.4 of RFC 4035 and 5.3 of FRC 7129.
2216 NegCache::NegCacheEntry ne
;
2218 uint32_t lowestTTL
= rec
.d_ttl
;
2220 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2221 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2223 cspmap_t csp
= harvestCSPFromNE(ne
);
2224 dState res
= getDenial(csp
, qname
, ne
.d_qtype
.getCode(), false, false, false, wildcardLabelsCount
);
2225 if (res
!= NXDOMAIN
) {
2227 if (res
== INSECURE
) {
2228 /* Some part could not be validated, for example a NSEC3 record with a too large number of iterations,
2229 this is not enough to warrant a Bogus, but go Insecure. */
2231 LOG(d_prefix
<<"Unable to validate denial in wildcard expanded positive response found for "<<qname
<<", returning Insecure, res="<<res
<<endl
);
2234 LOG(d_prefix
<<"Invalid denial in wildcard expanded positive response found for "<<qname
<<", returning Bogus, res="<<res
<<endl
);
2237 updateValidationState(state
, st
);
2238 /* we already stored the record with a different validation status, let's fix it */
2239 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qtype
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, lwr
.d_aabit
, st
);
2243 else if((rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::ANSWER
) {
2244 if(rec
.d_type
!= QType::RRSIG
|| rec
.d_name
== qname
)
2245 ret
.push_back(rec
); // enjoy your DNSSEC
2247 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::NS
&& qname
.isPartOf(rec
.d_name
)) {
2248 if(moreSpecificThan(rec
.d_name
,auth
)) {
2250 LOG(prefix
<<qname
<<": got NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2254 LOG(prefix
<<qname
<<": got upwards/level NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"', had '"<<auth
<<"'"<<endl
);
2256 if (auto content
= getRR
<NSRecordContent
>(rec
)) {
2257 nsset
.insert(content
->getNS());
2260 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::DS
&& qname
.isPartOf(rec
.d_name
)) {
2261 LOG(prefix
<<qname
<<": got DS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2263 else if(realreferral
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& (rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && newauth
.isPartOf(auth
)) {
2264 /* we might have received a denial of the DS, let's check */
2265 if (state
== Secure
) {
2266 NegCache::NegCacheEntry ne
;
2268 ne
.d_name
= newauth
;
2269 ne
.d_qtype
= QType::DS
;
2270 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2271 uint32_t lowestTTL
= rec
.d_ttl
;
2272 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2274 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, true);
2276 if (denialState
== NXQTYPE
|| denialState
== OPTOUT
|| denialState
== INSECURE
) {
2277 ne
.d_ttd
= lowestTTL
+ d_now
.tv_sec
;
2278 ne
.d_validationState
= Secure
;
2279 LOG(prefix
<<qname
<<": got negative indication of DS record for '"<<newauth
<<"'"<<endl
);
2281 if(!wasVariable()) {
2282 t_sstorage
.negcache
.add(ne
);
2285 if (qname
== newauth
&& qtype
== QType::DS
) {
2286 /* we are actually done! */
2293 else if(!done
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2294 lwr
.d_rcode
==RCode::NoError
&& qname
.isPartOf(rec
.d_name
)) {
2295 LOG(prefix
<<qname
<<": got negative caching indication for '"<< qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
2297 if(!newtarget
.empty()) {
2298 LOG(prefix
<<qname
<<": Hang on! Got a redirect to '"<<newtarget
<<"' already"<<endl
);
2301 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2304 NegCache::NegCacheEntry ne
;
2305 ne
.d_auth
= rec
.d_name
;
2306 uint32_t lowestTTL
= rec
.d_ttl
;
2309 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2310 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2312 if (state
== Secure
) {
2313 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, false);
2314 updateDenialValidationState(ne
, state
, denialState
, NXQTYPE
, qtype
== QType::DS
);
2316 ne
.d_validationState
= state
;
2319 if(!wasVariable()) {
2320 if(qtype
.getCode()) { // prevents us from blacking out a whole domain
2321 t_sstorage
.negcache
.add(ne
);
2332 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
)
2338 if(d_outqueries
+ d_throttledqueries
> s_maxqperq
) {
2339 throw ImmediateServFailException("more than "+std::to_string(s_maxqperq
)+" (max-qperq) queries sent while resolving "+qname
.toLogString());
2342 if(s_maxtotusec
&& d_totUsec
> s_maxtotusec
) {
2343 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");
2347 LOG(prefix
<<qname
<<": using TCP with "<< remoteIP
.toStringWithPort() <<endl
);
2352 if(d_pdl
&& d_pdl
->preoutquery(remoteIP
, d_requestor
, qname
, qtype
, doTCP
, lwr
.d_records
, resolveret
)) {
2353 LOG(prefix
<<qname
<<": query handled by Lua"<<endl
);
2356 ednsmask
=getEDNSSubnetMask(d_requestor
, qname
, remoteIP
);
2358 LOG(prefix
<<qname
<<": Adding EDNS Client Subnet Mask "<<ednsmask
->toString()<<" to query"<<endl
);
2361 resolveret
= asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(),
2362 doTCP
, sendRDQuery
, &d_now
, ednsmask
, &lwr
); // <- we go out on the wire!
2365 LOG(prefix
<<qname
<<": Received EDNS Client Subnet Mask "<<ednsmask
->toString()<<" on response"<<endl
);
2369 /* preoutquery killed the query by setting dq.rcode to -3 */
2370 if(resolveret
==-3) {
2371 throw ImmediateServFailException("Query killed by policy");
2374 d_totUsec
+= lwr
.d_usec
;
2375 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
2377 if(resolveret
!= 1) {
2378 /* Error while resolving */
2379 if(resolveret
== 0) {
2382 LOG(prefix
<<qname
<<": timeout resolving after "<<lwr
.d_usec
/1000.0<<"msec "<< (doTCP
? "over TCP" : "")<<endl
);
2384 s_outgoingtimeouts
++;
2386 if(remoteIP
.sin4
.sin_family
== AF_INET
)
2387 s_outgoing4timeouts
++;
2389 s_outgoing6timeouts
++;
2391 else if(resolveret
== -2) {
2392 /* OS resource limit reached */
2393 LOG(prefix
<<qname
<<": hit a local resource limit resolving"<< (doTCP
? " over TCP" : "")<<", probable error: "<<stringerror()<<endl
);
2394 g_stats
.resourceLimits
++;
2397 /* -1 means server unreachable */
2400 LOG(prefix
<<qname
<<": error resolving from "<<remoteIP
.toString()<< (doTCP
? " over TCP" : "") <<", possible error: "<<strerror(errno
)<< endl
);
2403 if(resolveret
!= -2) { // don't account for resource limits, they are our own fault
2404 t_sstorage
.nsSpeeds
[nsName
].submit(remoteIP
, 1000000, &d_now
); // 1 sec
2406 // code below makes sure we don't filter COM or the root
2407 if (s_serverdownmaxfails
> 0 && (auth
!= g_rootdnsname
) && t_sstorage
.fails
.incr(remoteIP
) >= s_serverdownmaxfails
) {
2408 LOG(prefix
<<qname
<<": Max fails reached resolving on "<< remoteIP
.toString() <<". Going full throttle for "<< s_serverdownthrottletime
<<" seconds" <<endl
);
2409 // mark server as down
2410 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0), s_serverdownthrottletime
, 10000);
2412 else if (resolveret
== -1) {
2413 // unreachable, 1 minute or 100 queries
2414 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 100);
2418 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 10, 5);
2425 /* we got an answer */
2426 if(lwr
.d_rcode
==RCode::ServFail
|| lwr
.d_rcode
==RCode::Refused
) {
2427 LOG(prefix
<<qname
<<": "<<nsName
<<" ("<<remoteIP
.toString()<<") returned a "<< (lwr
.d_rcode
==RCode::ServFail
? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl
);
2428 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
2432 /* this server sent a valid answer, mark it backup up if it was down */
2433 if(s_serverdownmaxfails
> 0) {
2434 t_sstorage
.fails
.clear(remoteIP
);
2441 LOG(prefix
<<qname
<<": truncated bit set, over TCP?"<<endl
);
2442 /* let's treat that as a ServFail answer from this server */
2443 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
2453 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
)
2458 prefix
.append(depth
, ' ');
2462 for(auto& rec
: lwr
.d_records
) {
2463 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumTTL
);
2467 bool needWildcardProof
= false;
2468 unsigned int wildcardLabelsCount
;
2469 *rcode
= updateCacheFromRecords(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, state
, needWildcardProof
, wildcardLabelsCount
);
2470 if (*rcode
!= RCode::NoError
) {
2474 LOG(prefix
<<qname
<<": determining status after receiving this packet"<<endl
);
2477 bool realreferral
=false, negindic
=false;
2481 bool done
= processRecords(prefix
, qname
, qtype
, auth
, lwr
, sendRDQuery
, ret
, nsset
, newtarget
, newauth
, realreferral
, negindic
, state
, needWildcardProof
, wildcardLabelsCount
);
2484 LOG(prefix
<<qname
<<": status=got results, this level of recursion done"<<endl
);
2485 LOG(prefix
<<qname
<<": validation status is "<<vStates
[state
]<<endl
);
2486 *rcode
= RCode::NoError
;
2490 if(!newtarget
.empty()) {
2491 if(newtarget
== qname
) {
2492 LOG(prefix
<<qname
<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl
);
2493 *rcode
= RCode::ServFail
;
2498 LOG(prefix
<<qname
<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl
);
2499 *rcode
= RCode::ServFail
;
2503 if (qtype
== QType::DS
) {
2504 LOG(prefix
<<qname
<<": status=got a CNAME referral, but we are looking for a DS"<<endl
);
2507 addNXNSECS(ret
, lwr
.d_records
);
2509 *rcode
= RCode::NoError
;
2513 LOG(prefix
<<qname
<<": status=got a CNAME referral, starting over with "<<newtarget
<<endl
);
2515 set
<GetBestNSAnswer
> beenthere2
;
2516 vState cnameState
= Indeterminate
;
2517 *rcode
= doResolve(newtarget
, qtype
, ret
, depth
+ 1, beenthere2
, cnameState
);
2518 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
2519 updateValidationState(state
, cnameState
);
2524 if(lwr
.d_rcode
== RCode::NXDomain
) {
2525 LOG(prefix
<<qname
<<": status=NXDOMAIN, we are done "<<(negindic
? "(have negative SOA)" : "")<<endl
);
2528 addNXNSECS(ret
, lwr
.d_records
);
2530 *rcode
= RCode::NXDomain
;
2534 if(nsset
.empty() && !lwr
.d_rcode
&& (negindic
|| lwr
.d_aabit
|| sendRDQuery
)) {
2535 LOG(prefix
<<qname
<<": status=noerror, other types may exist, but we are done "<<(negindic
? "(have negative SOA) " : "")<<(lwr
.d_aabit
? "(have aa bit) " : "")<<endl
);
2537 if(state
== Secure
&& lwr
.d_aabit
&& !negindic
) {
2538 updateValidationState(state
, Bogus
);
2542 addNXNSECS(ret
, lwr
.d_records
);
2544 *rcode
= RCode::NoError
;
2549 LOG(prefix
<<qname
<<": status=did not resolve, got "<<(unsigned int)nsset
.size()<<" NS, ");
2551 nameservers
.clear();
2552 for (auto const &nameserver
: nsset
) {
2554 d_appliedPolicy
= dfe
.getProcessingPolicy(nameserver
, d_discardedPolicies
);
2555 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
2556 LOG("however "<<nameserver
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
2561 nameservers
.insert({nameserver
, {{}, false}});
2563 LOG("looping to them"<<endl
);
2564 *gotNewServers
= true;
2574 * -1 in case of no results
2575 * -2 when a FilterEngine Policy was hit
2578 int SyncRes::doResolveAt(NsSet
&nameservers
, DNSName auth
, bool flawedNSSet
, const DNSName
&qname
, const QType
&qtype
,
2579 vector
<DNSRecord
>&ret
,
2580 unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
, vState
& state
)
2582 auto luaconfsLocal
= g_luaconfs
.getLocal();
2586 prefix
.append(depth
, ' ');
2589 LOG(prefix
<<qname
<<": Cache consultations done, have "<<(unsigned int)nameservers
.size()<<" NS to contact");
2591 if (nameserversBlockedByRPZ(luaconfsLocal
->dfe
, nameservers
)) {
2597 for(;;) { // we may get more specific nameservers
2598 vector
<DNSName
> rnameservers
= shuffleInSpeedOrder(nameservers
, doLog() ? (prefix
+qname
.toString()+": ") : string() );
2600 for(auto tns
=rnameservers
.cbegin();;++tns
) {
2601 if(tns
==rnameservers
.cend()) {
2602 LOG(prefix
<<qname
<<": Failed to resolve via any of the "<<(unsigned int)rnameservers
.size()<<" offered NS at level '"<<auth
<<"'"<<endl
);
2603 if(!auth
.isRoot() && flawedNSSet
) {
2604 LOG(prefix
<<qname
<<": Ageing nameservers for level '"<<auth
<<"', next query might succeed"<<endl
);
2606 if(t_RC
->doAgeCache(d_now
.tv_sec
, auth
, QType::NS
, 10))
2607 g_stats
.nsSetInvalidations
++;
2612 bool cacheOnly
= false;
2613 // this line needs to identify the 'self-resolving' behaviour
2614 if(qname
== *tns
&& (qtype
.getCode() == QType::A
|| qtype
.getCode() == QType::AAAA
)) {
2615 /* we might have a glue entry in cache so let's try this NS
2616 but only if we have enough in the cache to know how to reach it */
2617 LOG(prefix
<<qname
<<": Using NS to resolve itself, but only using what we have in cache ("<<(1+tns
-rnameservers
.cbegin())<<"/"<<rnameservers
.size()<<")"<<endl
);
2621 typedef vector
<ComboAddress
> remoteIPs_t
;
2622 remoteIPs_t remoteIPs
;
2623 remoteIPs_t::const_iterator remoteIP
;
2624 bool pierceDontQuery
=false;
2625 bool sendRDQuery
=false;
2626 boost::optional
<Netmask
> ednsmask
;
2628 const bool wasForwarded
= tns
->empty() && (!nameservers
[*tns
].first
.empty());
2629 int rcode
= RCode::NoError
;
2630 bool gotNewServers
= false;
2632 if(tns
->empty() && !wasForwarded
) {
2633 LOG(prefix
<<qname
<<": Domain is out-of-band"<<endl
);
2634 /* setting state to indeterminate since validation is disabled for local auth zone,
2635 and Insecure would be misleading. */
2636 state
= Indeterminate
;
2637 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, lwr
.d_records
, depth
, lwr
.d_rcode
);
2641 /* we have received an answer, are we done ? */
2642 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, false, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
2646 if (gotNewServers
) {
2651 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
2652 remoteIPs
= retrieveAddressesForNS(prefix
, qname
, tns
, depth
, beenthere
, rnameservers
, nameservers
, sendRDQuery
, pierceDontQuery
, flawedNSSet
, cacheOnly
);
2654 if(remoteIPs
.empty()) {
2655 LOG(prefix
<<qname
<<": Failed to get IP for NS "<<*tns
<<", trying next if available"<<endl
);
2660 bool hitPolicy
{false};
2661 LOG(prefix
<<qname
<<": Resolved '"<<auth
<<"' NS "<<*tns
<<" to: ");
2662 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
2663 if(remoteIP
!= remoteIPs
.cbegin()) {
2666 LOG(remoteIP
->toString());
2667 if(nameserverIPBlockedByRPZ(luaconfsLocal
->dfe
, *remoteIP
)) {
2672 if (hitPolicy
) //implies d_wantsRPZ
2676 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
2677 LOG(prefix
<<qname
<<": Trying IP "<< remoteIP
->toStringWithPort() <<", asking '"<<qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
2679 if (throttledOrBlocked(prefix
, *remoteIP
, qname
, qtype
, pierceDontQuery
)) {
2683 bool truncated
= false;
2684 bool gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
2685 *tns
, *remoteIP
, false, &truncated
);
2686 if (gotAnswer
&& truncated
) {
2687 /* retry, over TCP this time */
2688 gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
2689 *tns
, *remoteIP
, true, &truncated
);
2696 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
);
2698 /* // for you IPv6 fanatics :-)
2699 if(remoteIP->sin4.sin_family==AF_INET6)
2702 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
2704 t_sstorage
.nsSpeeds
[*tns
].submit(*remoteIP
, lwr
.d_usec
, &d_now
);
2706 /* we have received an answer, are we done ? */
2707 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
2711 if (gotNewServers
) {
2715 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100);
2718 if (gotNewServers
) {
2722 if(remoteIP
== remoteIPs
.cend()) // we tried all IP addresses, none worked
2731 void SyncRes::setIncomingECS(boost::optional
<const EDNSSubnetOpts
&> incomingECS
)
2733 d_incomingECS
= incomingECS
;
2735 if (d_incomingECS
->source
.getBits() == 0) {
2736 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0.
2737 But using an empty ECS in that case would mean inserting
2738 a non ECS-specific entry into the cache, preventing any further
2739 ECS-specific query to be sent.
2740 So instead we use the trick described in section 7.1.2:
2741 "The subsequent Recursive Resolver query to the Authoritative Nameserver
2742 will then either not include an ECS option or MAY optionally include
2743 its own address information, which is what the Authoritative
2744 Nameserver will almost certainly use to generate any Tailored
2745 Response in lieu of an option. This allows the answer to be handled
2746 by the same caching mechanism as other queries, with an explicit
2747 indicator of the applicable scope. Subsequent Stub Resolver queries
2748 for /0 can then be answered from this cached response.
2750 d_incomingECS
= s_ecsScopeZero
;
2751 d_incomingECSNetwork
= s_ecsScopeZero
.source
.getMaskedNetwork();
2754 uint8_t bits
= std::min(incomingECS
->source
.getBits(), (incomingECS
->source
.isIpv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
2755 d_incomingECS
->source
= Netmask(incomingECS
->source
.getNetwork(), bits
);
2756 d_incomingECSNetwork
= d_incomingECS
->source
.getMaskedNetwork();
2760 d_incomingECSNetwork
= ComboAddress();
2764 boost::optional
<Netmask
> SyncRes::getEDNSSubnetMask(const ComboAddress
& local
, const DNSName
&dn
, const ComboAddress
& rem
)
2766 boost::optional
<Netmask
> result
;
2769 if(d_incomingECSFound
) {
2770 trunc
= d_incomingECSNetwork
;
2771 bits
= d_incomingECS
->source
.getBits();
2773 else if(!local
.isIPv4() || local
.sin4
.sin_addr
.s_addr
) { // detect unset 'requestor'
2775 bits
= local
.isIPv4() ? 32 : 128;
2776 bits
= std::min(bits
, (trunc
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
2779 /* nothing usable */
2783 if(s_ednsdomains
.check(dn
) || s_ednssubnets
.match(rem
)) {
2784 trunc
.truncate(bits
);
2785 return boost::optional
<Netmask
>(Netmask(trunc
, bits
));
2791 void SyncRes::parseEDNSSubnetWhitelist(const std::string
& wlist
)
2793 vector
<string
> parts
;
2794 stringtok(parts
, wlist
, ",; ");
2795 for(const auto& a
: parts
) {
2797 s_ednssubnets
.addMask(Netmask(a
));
2800 s_ednsdomains
.add(DNSName(a
));
2805 // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
2806 int directResolve(const DNSName
& qname
, const QType
& qtype
, int qclass
, vector
<DNSRecord
>& ret
)
2809 gettimeofday(&now
, 0);
2812 int res
= sr
.beginResolve(qname
, QType(qtype
), qclass
, ret
);
2817 int SyncRes::getRootNS(struct timeval now
, asyncresolve_t asyncCallback
) {
2819 sr
.setDoEDNS0(true);
2820 sr
.setUpdatingRootNS();
2821 sr
.setDoDNSSEC(g_dnssecmode
!= DNSSECMode::Off
);
2822 sr
.setDNSSECValidationRequested(g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
);
2823 sr
.setAsyncCallback(asyncCallback
);
2825 vector
<DNSRecord
> ret
;
2828 res
=sr
.beginResolve(g_rootdnsname
, QType(QType::NS
), 1, ret
);
2829 if (g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
) {
2830 auto state
= sr
.getValidationState();
2832 throw PDNSException("Got Bogus validation result for .|NS");
2836 catch(const PDNSException
& e
) {
2837 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
2839 catch(const ImmediateServFailException
& e
) {
2840 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
2842 catch(const std::exception
& e
) {
2843 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.what()<<endl
;
2846 L
<<Logger::Error
<<"Failed to update . records, got an exception"<<endl
;
2850 L
<<Logger::Notice
<<"Refreshed . records"<<endl
;
2853 L
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;