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 (d_DNSSECValidationRequested
) {
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 if(!d_skipCNAMECheck
&& doCNAMECacheCheck(qname
,qtype
,ret
,depth
,res
,state
)) // will reroute us if needed
568 if(doCacheCheck(qname
,qtype
,ret
,depth
,res
,state
)) // we done
575 LOG(prefix
<<qname
<<": No cache hit for '"<<qname
<<"|"<<qtype
.getName()<<"', trying to find an appropriate NS record"<<endl
);
577 DNSName
subdomain(qname
);
578 if(qtype
== QType::DS
) subdomain
.chopOff();
581 bool flawedNSSet
=false;
583 /* we use subdomain here instead of qname because for DS queries we only care about the state of the parent zone */
584 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
586 // the two retries allow getBestNSNamesFromCache&co to reprime the root
587 // hints, in case they ever go missing
588 for(int tries
=0;tries
<2 && nsset
.empty();++tries
) {
589 subdomain
=getBestNSNamesFromCache(subdomain
, qtype
, nsset
, &flawedNSSet
, depth
, beenthere
); // pass beenthere to both occasions
592 state
= getValidationStatus(qname
, false);
594 LOG(prefix
<<qname
<<": initial validation status for "<<qname
<<" is "<<vStates
[state
]<<endl
);
596 if(!(res
=doResolveAt(nsset
, subdomain
, flawedNSSet
, qname
, qtype
, ret
, depth
, beenthere
, state
)))
599 LOG(prefix
<<qname
<<": failed (res="<<res
<<")"<<endl
);
604 return res
<0 ? RCode::ServFail
: res
;
608 // for testing purposes
609 static bool ipv6First(const ComboAddress
& a
, const ComboAddress
& b
)
611 return !(a
.sin4
.sin_family
< a
.sin4
.sin_family
);
617 speedOrderCA(std::map
<ComboAddress
,double>& speeds
): d_speeds(speeds
) {}
618 bool operator()(const ComboAddress
& a
, const ComboAddress
& b
) const
620 return d_speeds
[a
] < d_speeds
[b
];
622 std::map
<ComboAddress
, double>& d_speeds
;
625 /** This function explicitly goes out for A or AAAA addresses
627 vector
<ComboAddress
> SyncRes::getAddrs(const DNSName
&qname
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
, bool cacheOnly
)
629 typedef vector
<DNSRecord
> res_t
;
632 typedef vector
<ComboAddress
> ret_t
;
636 bool oldCacheOnly
= d_cacheonly
;
637 bool oldRequireAuthData
= d_requireAuthData
;
638 bool oldValidationRequested
= d_DNSSECValidationRequested
;
639 d_requireAuthData
= false;
640 d_DNSSECValidationRequested
= false;
641 d_cacheonly
= cacheOnly
;
643 for(int j
=1; j
<2+s_doIPv6
; j
++)
658 vState newState
= Indeterminate
;
659 if(!doResolve(qname
, type
, res
,depth
+1, beenthere
, newState
) && !res
.empty()) { // this consults cache, OR goes out
660 for(res_t::const_iterator i
=res
.begin(); i
!= res
.end(); ++i
) {
661 if(i
->d_type
== QType::A
|| i
->d_type
== QType::AAAA
) {
662 if(auto rec
= std::dynamic_pointer_cast
<ARecordContent
>(i
->d_content
))
663 ret
.push_back(rec
->getCA(53));
664 else if(auto aaaarec
= std::dynamic_pointer_cast
<AAAARecordContent
>(i
->d_content
))
665 ret
.push_back(aaaarec
->getCA(53));
671 if(j
==1 && s_doIPv6
) { // we got an A record, see if we have some AAAA lying around
672 vector
<DNSRecord
> cset
;
673 if(t_RC
->get(d_now
.tv_sec
, qname
, QType(QType::AAAA
), false, &cset
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
) > 0) {
674 for(auto k
=cset
.cbegin();k
!=cset
.cend();++k
) {
675 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
676 if (auto drc
= std::dynamic_pointer_cast
<AAAARecordContent
>(k
->d_content
)) {
677 ComboAddress ca
=drc
->getCA(53);
688 d_requireAuthData
= oldRequireAuthData
;
689 d_DNSSECValidationRequested
= oldValidationRequested
;
690 d_cacheonly
= oldCacheOnly
;
692 /* we need to remove from the nsSpeeds collection the existing IPs
693 for this nameserver that are no longer in the set, even if there
694 is only one or none at all in the current set.
696 map
<ComboAddress
, double> speeds
;
697 auto& collection
= t_sstorage
.nsSpeeds
[qname
].d_collection
;
698 for(const auto& val
: ret
) {
699 speeds
[val
] = collection
[val
].get(&d_now
);
702 t_sstorage
.nsSpeeds
[qname
].purge(speeds
);
705 random_shuffle(ret
.begin(), ret
.end(), dns_random
);
706 speedOrderCA
so(speeds
);
707 stable_sort(ret
.begin(), ret
.end(), so
);
710 string prefix
=d_prefix
;
711 prefix
.append(depth
, ' ');
712 LOG(prefix
<<"Nameserver "<<qname
<<" IPs: ");
714 for(const auto& addr
: ret
) {
721 LOG((addr
.toString())<<"(" << (boost::format("%0.2f") % (speeds
[addr
]/1000.0)).str() <<"ms)");
730 void SyncRes::getBestNSFromCache(const DNSName
&qname
, const QType
& qtype
, vector
<DNSRecord
>& bestns
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
)
733 DNSName
subdomain(qname
);
736 prefix
.append(depth
, ' ');
742 LOG(prefix
<<qname
<<": Checking if we have NS in cache for '"<<subdomain
<<"'"<<endl
);
743 vector
<DNSRecord
> ns
;
744 *flawedNSSet
= false;
746 if(t_RC
->get(d_now
.tv_sec
, subdomain
, QType(QType::NS
), false, &ns
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
) > 0) {
747 for(auto k
=ns
.cbegin();k
!=ns
.cend(); ++k
) {
748 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
749 vector
<DNSRecord
> aset
;
751 const DNSRecord
& dr
=*k
;
752 auto nrr
= getRR
<NSRecordContent
>(dr
);
753 if(nrr
&& (!nrr
->getNS().isPartOf(subdomain
) || t_RC
->get(d_now
.tv_sec
, nrr
->getNS(), s_doIPv6
? QType(QType::ADDR
) : QType(QType::A
),
754 false, doLog() ? &aset
: 0, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
) > 5)) {
755 bestns
.push_back(dr
);
756 LOG(prefix
<<qname
<<": NS (with ip, or non-glue) in cache for '"<<subdomain
<<"' -> '"<<nrr
->getNS()<<"'"<<endl
);
757 LOG(prefix
<<qname
<<": within bailiwick: "<< nrr
->getNS().isPartOf(subdomain
));
759 LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset
.begin()->d_ttl
- d_now
.tv_sec
))<<endl
);
762 LOG(", not in cache / did not look at cache"<<endl
);
767 LOG(prefix
<<qname
<<": NS in cache for '"<<subdomain
<<"', but needs glue ("<<nrr
->getNS()<<") which we miss or is expired"<<endl
);
772 if(!bestns
.empty()) {
773 GetBestNSAnswer answer
;
775 answer
.qtype
=qtype
.getCode();
776 for(const auto& dr
: bestns
)
777 answer
.bestns
.insert(make_pair(dr
.d_name
, getRR
<NSRecordContent
>(dr
)->getNS()));
779 if(beenthere
.count(answer
)) {
781 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' but part of LOOP (already seen "<<answer
.qname
<<")! Trying less specific NS"<<endl
);
784 for( set
<GetBestNSAnswer
>::const_iterator j
=beenthere
.begin();j
!=beenthere
.end();++j
) {
785 bool neo
= !(*j
< answer
|| answer
<*j
);
786 LOG(prefix
<<qname
<<": beenthere"<<(neo
?"*":"")<<": "<<j
->qname
<<"|"<<DNSRecordContent::NumberToType(j
->qtype
)<<" ("<<(unsigned int)j
->bestns
.size()<<")"<<endl
);
791 beenthere
.insert(answer
);
792 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' (flawedNSSet="<<*flawedNSSet
<<")"<<endl
);
797 LOG(prefix
<<qname
<<": no valid/useful NS in cache for '"<<subdomain
<<"'"<<endl
);
799 if(subdomain
.isRoot() && !brokeloop
) {
800 // We lost the root NS records
802 LOG(prefix
<<qname
<<": reprimed the root"<<endl
);
803 /* let's prevent an infinite loop */
804 if (!d_updatingRootNS
) {
805 getRootNS(d_now
, d_asyncResolve
);
808 } while(subdomain
.chopOff());
811 SyncRes::domainmap_t::const_iterator
SyncRes::getBestAuthZone(DNSName
* qname
) const
813 SyncRes::domainmap_t::const_iterator ret
;
815 ret
=t_sstorage
.domainmap
->find(*qname
);
816 if(ret
!=t_sstorage
.domainmap
->end())
818 }while(qname
->chopOff());
822 /** doesn't actually do the work, leaves that to getBestNSFromCache */
823 DNSName
SyncRes::getBestNSNamesFromCache(const DNSName
&qname
, const QType
& qtype
, NsSet
& nsset
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
)
825 DNSName
subdomain(qname
);
826 DNSName
authdomain(qname
);
828 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
829 if(iter
!=t_sstorage
.domainmap
->end()) {
830 if( iter
->second
.isAuth() )
831 // this gets picked up in doResolveAt, the empty DNSName, combined with the
832 // empty vector means 'we are auth for this zone'
833 nsset
.insert({DNSName(), {{}, false}});
835 // Again, picked up in doResolveAt. An empty DNSName, combined with a
836 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
837 // This is actually picked up in retrieveAddressesForNS called from doResolveAt.
838 nsset
.insert({DNSName(), {iter
->second
.d_servers
, iter
->second
.shouldRecurse() }});
843 vector
<DNSRecord
> bestns
;
844 getBestNSFromCache(subdomain
, qtype
, bestns
, flawedNSSet
, depth
, beenthere
);
846 for(auto k
=bestns
.cbegin() ; k
!= bestns
.cend(); ++k
) {
847 // The actual resolver code will not even look at the ComboAddress or bool
848 nsset
.insert({std::dynamic_pointer_cast
<NSRecordContent
>(k
->d_content
)->getNS(), {{}, false}});
849 if(k
==bestns
.cbegin())
855 bool SyncRes::doCNAMECacheCheck(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>& ret
, unsigned int depth
, int &res
, vState
& state
)
860 prefix
.append(depth
, ' ');
863 if((depth
>9 && d_outqueries
>10 && d_throttledqueries
>5) || depth
> 15) {
864 LOG(prefix
<<qname
<<": recursing (CNAME or other indirection) too deep, depth="<<depth
<<endl
);
869 LOG(prefix
<<qname
<<": Looking for CNAME cache hit of '"<<qname
<<"|CNAME"<<"'"<<endl
);
870 vector
<DNSRecord
> cset
;
871 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
872 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
874 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) {
876 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
877 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
879 if (d_DNSSECValidationRequested
&& wasAuth
&& state
== Indeterminate
&& d_requireAuthData
) {
880 /* This means we couldn't figure out the state when this entry was cached,
881 most likely because we hadn't computed the zone cuts yet. */
882 /* make sure they are computed before validating */
883 DNSName
subdomain(qname
);
884 /* if we are retrieving a DS, we only care about the state of the parent zone */
885 if(qtype
== QType::DS
)
888 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
890 vState recordState
= getValidationStatus(qname
, false);
891 if (recordState
== Secure
) {
892 LOG(prefix
<<qname
<<": got Indeterminate state from the CNAME cache, validating.."<<endl
);
893 state
= SyncRes::validateRecordsWithSigs(depth
, qname
, QType(QType::CNAME
), qname
, cset
, signatures
);
894 if (state
!= Indeterminate
) {
895 LOG(prefix
<<qname
<<": got Indeterminate state from the CNAME cache, new validation result is "<<vStates
[state
]<<endl
);
896 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, QType(QType::CNAME
), d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, d_requireAuthData
, state
);
901 LOG(prefix
<<qname
<<": Found cache CNAME hit for '"<< qname
<< "|CNAME" <<"' to '"<<j
->d_content
->getZoneRepresentation()<<"', validation state is "<<vStates
[state
]<<endl
);
904 dr
.d_ttl
-=d_now
.tv_sec
;
907 for(const auto& signature
: signatures
) {
909 sigdr
.d_type
=QType::RRSIG
;
911 sigdr
.d_ttl
=j
->d_ttl
- d_now
.tv_sec
;
912 sigdr
.d_content
=signature
;
913 sigdr
.d_place
=DNSResourceRecord::ANSWER
;
914 sigdr
.d_class
=QClass::IN
;
915 ret
.push_back(sigdr
);
918 for(const auto& rec
: authorityRecs
) {
919 DNSRecord
authDR(*rec
);
920 authDR
.d_ttl
=j
->d_ttl
- d_now
.tv_sec
;
921 ret
.push_back(authDR
);
924 if(qtype
!= QType::CNAME
) { // perhaps they really wanted a CNAME!
925 set
<GetBestNSAnswer
>beenthere
;
927 vState cnameState
= Indeterminate
;
928 res
=doResolve(std::dynamic_pointer_cast
<CNAMERecordContent
>(j
->d_content
)->getTarget(), qtype
, ret
, depth
+1, beenthere
, cnameState
);
929 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
930 updateValidationState(state
, cnameState
);
939 LOG(prefix
<<qname
<<": No CNAME cache hit of '"<< qname
<< "|CNAME" <<"' found"<<endl
);
946 vector
<DNSRecord
> records
;
947 vector
<shared_ptr
<RRSIGRecordContent
>> signatures
;
948 uint32_t signaturesTTL
{std::numeric_limits
<uint32_t>::max()};
954 DNSResourceRecord::Place place
;
955 bool operator<(const CacheKey
& rhs
) const {
956 return tie(name
, type
) < tie(rhs
.name
, rhs
.type
);
959 typedef map
<CacheKey
, CacheEntry
> tcache_t
;
962 static void reapRecordsFromNegCacheEntryForValidation(tcache_t
& tcache
, const vector
<DNSRecord
>& records
)
964 for (const auto& rec
: records
) {
965 if (rec
.d_type
== QType::RRSIG
) {
966 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
968 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
971 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(rec
);
977 * Convience function to push the records from records into ret with a new TTL
979 * \param records DNSRecords that need to go into ret
980 * \param ttl The new TTL for these records
981 * \param ret The vector of DNSRecords that should contian the records with the modified TTL
983 static void addTTLModifiedRecords(const vector
<DNSRecord
>& records
, const uint32_t ttl
, vector
<DNSRecord
>& ret
) {
984 for (const auto& rec
: records
) {
991 void SyncRes::computeNegCacheValidationStatus(NegCache::NegCacheEntry
& ne
, const DNSName
& qname
, const QType
& qtype
, const int res
, vState
& state
, unsigned int depth
)
993 DNSName
subdomain(qname
);
994 /* if we are retrieving a DS, we only care about the state of the parent zone */
995 if(qtype
== QType::DS
)
998 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1001 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.authoritySOA
.records
);
1002 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.authoritySOA
.signatures
);
1003 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.DNSSECRecords
.records
);
1004 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.DNSSECRecords
.signatures
);
1006 for (const auto& entry
: tcache
) {
1007 // this happens when we did store signatures, but passed on the records themselves
1008 if (entry
.second
.records
.empty()) {
1012 const DNSName
& owner
= entry
.first
.name
;
1014 vState recordState
= getValidationStatus(owner
, false);
1015 if (state
== Indeterminate
) {
1016 state
= recordState
;
1019 if (recordState
== Secure
) {
1020 recordState
= SyncRes::validateRecordsWithSigs(depth
, qname
, qtype
, owner
, entry
.second
.records
, entry
.second
.signatures
);
1023 if (recordState
!= Indeterminate
&& recordState
!= state
) {
1024 updateValidationState(state
, recordState
);
1025 if (state
!= Secure
) {
1031 if (state
== Secure
) {
1032 dState expectedState
= res
== RCode::NXDomain
? NXDOMAIN
: NXQTYPE
;
1033 dState denialState
= getDenialValidationState(ne
, state
, expectedState
, qtype
== QType::DS
);
1034 updateDenialValidationState(ne
, state
, denialState
, expectedState
, qtype
== QType::DS
);
1036 if (state
!= Indeterminate
) {
1037 /* validation succeeded, let's update the cache entry so we don't have to validate again */
1038 t_sstorage
.negcache
.updateValidationStatus(ne
.d_name
, ne
.d_qtype
, state
);
1042 bool SyncRes::doCacheCheck(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int &res
, vState
& state
)
1044 bool giveNegative
=false;
1049 prefix
.append(depth
, ' ');
1052 // 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)
1053 DNSName
sqname(qname
);
1056 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
1058 DNSName
authname(qname
);
1060 bool wasForwardedOrAuth
= false;
1061 bool wasAuth
= false;
1062 domainmap_t::const_iterator iter
=getBestAuthZone(&authname
);
1063 if(iter
!= t_sstorage
.domainmap
->end()) {
1064 wasForwardedOrAuth
= true;
1065 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
1066 if(servers
.empty()) {
1070 NegCache::NegCacheEntry ne
;
1073 t_sstorage
.negcache
.getRootNXTrust(qname
, d_now
, ne
) &&
1074 ne
.d_auth
.isRoot() &&
1075 !(wasForwardedOrAuth
&& !authname
.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
1076 sttl
= ne
.d_ttd
- d_now
.tv_sec
;
1077 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
.d_auth
<<"' & '"<<ne
.d_name
<<"' for another "<<sttl
<<" seconds"<<endl
);
1078 res
= RCode::NXDomain
;
1079 giveNegative
= true;
1080 cachedState
= ne
.d_validationState
;
1082 else if (t_sstorage
.negcache
.get(qname
, qtype
, d_now
, ne
) &&
1083 !(wasForwardedOrAuth
&& ne
.d_auth
!= authname
)) { // Only the authname nameserver can neg cache entries
1085 /* If we are looking for a DS, discard NXD if auth == qname
1086 and ask for a specific denial instead */
1087 if (qtype
!= QType::DS
|| ne
.d_qtype
.getCode() || ne
.d_auth
!= qname
||
1088 t_sstorage
.negcache
.get(qname
, qtype
, d_now
, ne
, true))
1091 sttl
= ne
.d_ttd
- d_now
.tv_sec
;
1092 giveNegative
= true;
1093 cachedState
= ne
.d_validationState
;
1094 if(ne
.d_qtype
.getCode()) {
1095 LOG(prefix
<<qname
<<": "<<qtype
.getName()<<" is negatively cached via '"<<ne
.d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1096 res
= RCode::NoError
;
1099 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
.d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1100 res
= RCode::NXDomain
;
1107 state
= cachedState
;
1109 if (d_DNSSECValidationRequested
&& state
== Indeterminate
) {
1110 LOG(prefix
<<qname
<<": got Indeterminate state for records retrieved from the negative cache, validating.."<<endl
);
1111 computeNegCacheValidationStatus(ne
, qname
, qtype
, res
, state
, depth
);
1114 // Transplant SOA to the returned packet
1115 addTTLModifiedRecords(ne
.authoritySOA
.records
, sttl
, ret
);
1117 addTTLModifiedRecords(ne
.authoritySOA
.signatures
, sttl
, ret
);
1118 addTTLModifiedRecords(ne
.DNSSECRecords
.records
, sttl
, ret
);
1119 addTTLModifiedRecords(ne
.DNSSECRecords
.signatures
, sttl
, ret
);
1122 LOG(prefix
<<qname
<<": updating validation state with negative cache content for "<<qname
<<" to "<<vStates
[state
]<<endl
);
1126 vector
<DNSRecord
> cset
;
1127 bool found
=false, expired
=false;
1128 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
1129 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1132 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) {
1134 LOG(prefix
<<sqname
<<": Found cache hit for "<<sqt
.getName()<<": ");
1136 if (d_DNSSECValidationRequested
&& wasCachedAuth
&& cachedState
== Indeterminate
&& d_requireAuthData
) {
1138 /* This means we couldn't figure out the state when this entry was cached,
1139 most likely because we hadn't computed the zone cuts yet. */
1140 /* make sure they are computed before validating */
1141 DNSName
subdomain(sqname
);
1142 /* if we are retrieving a DS, we only care about the state of the parent zone */
1143 if(qtype
== QType::DS
)
1144 subdomain
.chopOff();
1146 computeZoneCuts(subdomain
, g_rootdnsname
, depth
);
1148 vState recordState
= getValidationStatus(qname
, false);
1149 if (recordState
== Secure
) {
1150 LOG(prefix
<<sqname
<<": got Indeterminate state from the cache, validating.."<<endl
);
1151 cachedState
= SyncRes::validateRecordsWithSigs(depth
, sqname
, sqt
, sqname
, cset
, signatures
);
1154 cachedState
= recordState
;
1157 if (cachedState
!= Indeterminate
) {
1158 LOG(prefix
<<qname
<<": got Indeterminate state from the cache, validation result is "<<vStates
[cachedState
]<<endl
);
1159 t_RC
->updateValidationStatus(d_now
.tv_sec
, sqname
, sqt
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, d_requireAuthData
, cachedState
);
1163 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
1164 LOG(j
->d_content
->getZoneRepresentation());
1165 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
1167 ttl
= (dr
.d_ttl
-=d_now
.tv_sec
);
1169 LOG("[ttl="<<dr
.d_ttl
<<"] ");
1178 for(const auto& signature
: signatures
) {
1180 dr
.d_type
=QType::RRSIG
;
1183 dr
.d_content
=signature
;
1184 dr
.d_place
= DNSResourceRecord::ANSWER
;
1185 dr
.d_class
=QClass::IN
;
1189 for(const auto& rec
: authorityRecs
) {
1196 if(found
&& !expired
) {
1199 d_wasOutOfBand
= wasAuth
;
1200 LOG(prefix
<<qname
<<": updating validation state with cache content for "<<qname
<<" to "<<vStates
[cachedState
]<<endl
);
1201 state
= cachedState
;
1205 LOG(prefix
<<qname
<<": cache had only stale entries"<<endl
);
1211 bool SyncRes::moreSpecificThan(const DNSName
& a
, const DNSName
&b
) const
1213 return (a
.isPartOf(b
) && a
.countLabels() > b
.countLabels());
1218 speedOrder(map
<DNSName
,double> &speeds
) : d_speeds(speeds
) {}
1219 bool operator()(const DNSName
&a
, const DNSName
&b
) const
1221 return d_speeds
[a
] < d_speeds
[b
];
1223 map
<DNSName
, double>& d_speeds
;
1226 inline vector
<DNSName
> SyncRes::shuffleInSpeedOrder(NsSet
&tnameservers
, const string
&prefix
)
1228 vector
<DNSName
> rnameservers
;
1229 rnameservers
.reserve(tnameservers
.size());
1230 for(const auto& tns
: tnameservers
) {
1231 rnameservers
.push_back(tns
.first
);
1232 if(tns
.first
.empty()) // this was an authoritative OOB zone, don't pollute the nsSpeeds with that
1233 return rnameservers
;
1235 map
<DNSName
, double> speeds
;
1237 for(const auto& val
: rnameservers
) {
1239 speed
=t_sstorage
.nsSpeeds
[val
].get(&d_now
);
1242 random_shuffle(rnameservers
.begin(),rnameservers
.end(), dns_random
);
1243 speedOrder
so(speeds
);
1244 stable_sort(rnameservers
.begin(),rnameservers
.end(), so
);
1247 LOG(prefix
<<"Nameservers: ");
1248 for(vector
<DNSName
>::const_iterator i
=rnameservers
.begin();i
!=rnameservers
.end();++i
) {
1249 if(i
!=rnameservers
.begin()) {
1251 if(!((i
-rnameservers
.begin())%3)) {
1252 LOG(endl
<<prefix
<<" ");
1255 LOG((i
->empty() ? string("<empty>") : i
->toString())<<"(" << (boost::format("%0.2f") % (speeds
[*i
]/1000.0)).str() <<"ms)");
1259 return rnameservers
;
1262 static uint32_t getRRSIGTTL(const time_t now
, const std::shared_ptr
<RRSIGRecordContent
>& rrsig
)
1265 if (now
< rrsig
->d_sigexpire
) {
1266 res
= static_cast<uint32_t>(rrsig
->d_sigexpire
) - now
;
1271 static const set
<uint16_t> nsecTypes
= {QType::NSEC
, QType::NSEC3
};
1273 /* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
1275 * \param records The records to parse for the authority SOA and NSEC(3) records
1276 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
1278 static void harvestNXRecords(const vector
<DNSRecord
>& records
, NegCache::NegCacheEntry
& ne
, const time_t now
, uint32_t* lowestTTL
) {
1279 for(const auto& rec
: records
) {
1280 if(rec
.d_place
!= DNSResourceRecord::AUTHORITY
)
1281 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
1282 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
1283 // records MUST be in the same section as the records they cover.
1284 // Hence, we ignore all records outside of the AUTHORITY section.
1287 if(rec
.d_type
== QType::RRSIG
) {
1288 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1290 if(rrsig
->d_type
== QType::SOA
) {
1291 ne
.authoritySOA
.signatures
.push_back(rec
);
1292 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1293 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1294 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1297 if(nsecTypes
.count(rrsig
->d_type
)) {
1298 ne
.DNSSECRecords
.signatures
.push_back(rec
);
1299 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1300 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1301 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1307 if(rec
.d_type
== QType::SOA
) {
1308 ne
.authoritySOA
.records
.push_back(rec
);
1310 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1314 if(nsecTypes
.count(rec
.d_type
)) {
1315 ne
.DNSSECRecords
.records
.push_back(rec
);
1317 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1324 static cspmap_t
harvestCSPFromNE(const NegCache::NegCacheEntry
& ne
)
1327 for(const auto& rec
: ne
.DNSSECRecords
.signatures
) {
1328 if(rec
.d_type
== QType::RRSIG
) {
1329 auto rrc
= getRR
<RRSIGRecordContent
>(rec
);
1331 cspmap
[{rec
.d_name
,rrc
->d_type
}].signatures
.push_back(rrc
);
1335 for(const auto& rec
: ne
.DNSSECRecords
.records
) {
1336 cspmap
[{rec
.d_name
, rec
.d_type
}].records
.push_back(rec
.d_content
);
1341 // TODO remove after processRecords is fixed!
1342 // Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
1343 static void addNXNSECS(vector
<DNSRecord
>&ret
, const vector
<DNSRecord
>& records
)
1345 NegCache::NegCacheEntry ne
;
1346 harvestNXRecords(records
, ne
, 0, nullptr);
1347 ret
.insert(ret
.end(), ne
.authoritySOA
.signatures
.begin(), ne
.authoritySOA
.signatures
.end());
1348 ret
.insert(ret
.end(), ne
.DNSSECRecords
.records
.begin(), ne
.DNSSECRecords
.records
.end());
1349 ret
.insert(ret
.end(), ne
.DNSSECRecords
.signatures
.begin(), ne
.DNSSECRecords
.signatures
.end());
1352 bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine
& dfe
, const NsSet
& nameservers
)
1355 for (auto const &ns
: nameservers
) {
1356 d_appliedPolicy
= dfe
.getProcessingPolicy(ns
.first
, d_discardedPolicies
);
1357 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1358 LOG(", however nameserver "<<ns
.first
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1362 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1363 for (auto const &address
: ns
.second
.first
) {
1364 d_appliedPolicy
= dfe
.getProcessingPolicy(address
, d_discardedPolicies
);
1365 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1366 LOG(", however nameserver "<<ns
.first
<<" IP address "<<address
.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1375 bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine
& dfe
, const ComboAddress
& remoteIP
)
1378 d_appliedPolicy
= dfe
.getProcessingPolicy(remoteIP
, d_discardedPolicies
);
1379 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) {
1380 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")+"')");
1387 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
)
1389 vector
<ComboAddress
> result
;
1392 LOG(prefix
<<qname
<<": Trying to resolve NS '"<<*tns
<< "' ("<<1+tns
-rnameservers
.begin()<<"/"<<(unsigned int)rnameservers
.size()<<")"<<endl
);
1393 result
= getAddrs(*tns
, depth
+2, beenthere
, cacheOnly
);
1394 pierceDontQuery
=false;
1397 LOG(prefix
<<qname
<<": Domain has hardcoded nameserver");
1399 result
= nameservers
[*tns
].first
;
1400 if(result
.size() > 1) {
1405 sendRDQuery
= nameservers
[*tns
].second
;
1406 pierceDontQuery
=true;
1411 bool SyncRes::throttledOrBlocked(const std::string
& prefix
, const ComboAddress
& remoteIP
, const DNSName
& qname
, const QType
& qtype
, bool pierceDontQuery
)
1413 if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0))) {
1414 LOG(prefix
<<qname
<<": server throttled "<<endl
);
1415 s_throttledqueries
++; d_throttledqueries
++;
1418 else if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()))) {
1419 LOG(prefix
<<qname
<<": query throttled "<<remoteIP
.toString()<<", "<<qname
<<"; "<<qtype
.getName()<<endl
);
1420 s_throttledqueries
++; d_throttledqueries
++;
1423 else if(!pierceDontQuery
&& s_dontQuery
&& s_dontQuery
->match(&remoteIP
)) {
1424 LOG(prefix
<<qname
<<": not sending query to " << remoteIP
.toString() << ", blocked by 'dont-query' setting" << endl
);
1431 bool SyncRes::validationEnabled() const
1433 return g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
;
1436 uint32_t SyncRes::computeLowestTTD(const std::vector
<DNSRecord
>& records
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, uint32_t signaturesTTL
) const
1438 uint32_t lowestTTD
= std::numeric_limits
<uint32_t>::max();
1439 for(const auto& record
: records
)
1440 lowestTTD
= min(lowestTTD
, record
.d_ttl
);
1442 /* even if it was not requested for that request (Process, and neither AD nor DO set),
1443 it might be requested at a later time so we need to be careful with the TTL. */
1444 if (validationEnabled() && !signatures
.empty()) {
1445 /* if we are validating, we don't want to cache records after their signatures expire. */
1446 /* records TTL are now TTD, let's add 'now' to the signatures lowest TTL */
1447 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(signaturesTTL
+ d_now
.tv_sec
));
1449 for(const auto& sig
: signatures
) {
1450 if (isRRSIGNotExpired(d_now
.tv_sec
, sig
)) {
1451 // we don't decerement d_sigexpire by 'now' because we actually want a TTD, not a TTL */
1452 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(sig
->d_sigexpire
));
1460 void SyncRes::updateValidationState(vState
& state
, const vState stateUpdate
)
1462 LOG(d_prefix
<<"validation state was "<<std::string(vStates
[state
])<<", state update is "<<std::string(vStates
[stateUpdate
]));
1464 if (stateUpdate
== TA
) {
1467 else if (stateUpdate
== NTA
) {
1470 else if (stateUpdate
== Bogus
) {
1473 else if (state
== Indeterminate
) {
1474 state
= stateUpdate
;
1476 else if (stateUpdate
== Insecure
) {
1477 if (state
!= Bogus
) {
1481 LOG(", validation state is now "<<std::string(vStates
[state
])<<endl
);
1484 vState
SyncRes::getTA(const DNSName
& zone
, dsmap_t
& ds
)
1486 auto luaLocal
= g_luaconfs
.getLocal();
1488 if (luaLocal
->dsAnchors
.empty()) {
1489 LOG(d_prefix
<<": No trust anchors configured, everything is Insecure"<<endl
);
1490 /* We have no TA, everything is insecure */
1495 if (haveNegativeTrustAnchor(luaLocal
->negAnchors
, zone
, reason
)) {
1496 LOG(d_prefix
<<": got NTA for '"<<zone
<<"'"<<endl
);
1500 if (getTrustAnchor(luaLocal
->dsAnchors
, zone
, ds
)) {
1501 LOG(d_prefix
<<": got TA for '"<<zone
<<"'"<<endl
);
1505 LOG(d_prefix
<<": no TA found for '"<<zone
<<"' among "<< luaLocal
->dsAnchors
.size()<<endl
);
1508 if (zone
.isRoot()) {
1509 /* No TA for the root */
1513 return Indeterminate
;
1516 static size_t countSupportedDS(const dsmap_t
& dsmap
)
1520 for (const auto& ds
: dsmap
) {
1521 if (isSupportedDS(ds
)) {
1529 vState
SyncRes::getDSRecords(const DNSName
& zone
, dsmap_t
& ds
, bool taOnly
, unsigned int depth
, bool bogusOnNXD
, bool* foundCut
)
1531 vState result
= getTA(zone
, ds
);
1533 if (result
!= Indeterminate
|| taOnly
) {
1535 *foundCut
= (result
!= Indeterminate
);
1539 if (countSupportedDS(ds
) == 0) {
1547 else if (result
== NTA
) {
1554 bool oldSkipCNAME
= d_skipCNAMECheck
;
1555 d_skipCNAMECheck
= true;
1557 std::set
<GetBestNSAnswer
> beenthere
;
1558 std::vector
<DNSRecord
> dsrecords
;
1560 vState state
= Indeterminate
;
1561 int rcode
= doResolve(zone
, QType(QType::DS
), dsrecords
, depth
+ 1, beenthere
, state
);
1562 d_skipCNAMECheck
= oldSkipCNAME
;
1564 if (rcode
== RCode::NoError
|| (rcode
== RCode::NXDomain
&& !bogusOnNXD
)) {
1566 uint8_t bestDigestType
= 0;
1568 if (state
== Secure
) {
1569 bool gotCNAME
= false;
1570 for (const auto& record
: dsrecords
) {
1571 if (record
.d_type
== QType::DS
) {
1572 const auto dscontent
= getRR
<DSRecordContent
>(record
);
1573 if (dscontent
&& isSupportedDS(*dscontent
)) {
1574 // Make GOST a lower prio than SHA256
1575 if (dscontent
->d_digesttype
== DNSSECKeeper::GOST
&& bestDigestType
== DNSSECKeeper::SHA256
) {
1578 if (dscontent
->d_digesttype
> bestDigestType
|| (bestDigestType
== DNSSECKeeper::GOST
&& dscontent
->d_digesttype
== DNSSECKeeper::SHA256
)) {
1579 bestDigestType
= dscontent
->d_digesttype
;
1581 ds
.insert(*dscontent
);
1584 else if (record
.d_type
== QType::CNAME
&& record
.d_name
== zone
) {
1589 /* RFC 4509 section 3: "Validator implementations SHOULD ignore DS RRs containing SHA-1
1590 * digests if DS RRs with SHA-256 digests are present in the DS RRset."
1591 * As SHA348 is specified as well, the spirit of the this line is "use the best algorithm".
1593 for (auto dsrec
= ds
.begin(); dsrec
!= ds
.end(); ) {
1594 if (dsrec
->d_digesttype
!= bestDigestType
) {
1595 dsrec
= ds
.erase(dsrec
);
1602 if (rcode
== RCode::NoError
&& ds
.empty()) {
1604 if (gotCNAME
|| denialProvesNoDelegation(zone
, dsrecords
)) {
1605 /* we are still inside the same Secure zone */
1615 } else if (foundCut
&& rcode
== RCode::NoError
&& !ds
.empty()) {
1623 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
1627 bool SyncRes::haveExactValidationStatus(const DNSName
& domain
)
1629 if (!d_DNSSECValidationRequested
) {
1632 const auto& it
= d_cutStates
.find(domain
);
1633 if (it
!= d_cutStates
.cend()) {
1639 vState
SyncRes::getValidationStatus(const DNSName
& subdomain
, bool allowIndeterminate
)
1641 vState result
= Indeterminate
;
1643 if (!d_DNSSECValidationRequested
) {
1646 DNSName
name(subdomain
);
1648 const auto& it
= d_cutStates
.find(name
);
1649 if (it
!= d_cutStates
.cend()) {
1650 if (allowIndeterminate
|| it
->second
!= Indeterminate
) {
1651 LOG(d_prefix
<<": got status "<<vStates
[it
->second
]<<" for name "<<subdomain
<<" (from "<<name
<<")"<<endl
);
1656 while (name
.chopOff());
1661 bool SyncRes::lookForCut(const DNSName
& qname
, unsigned int depth
, const vState existingState
, vState
& newState
)
1663 bool foundCut
= false;
1665 vState dsState
= getDSRecords(qname
, ds
, newState
== Bogus
|| existingState
== Insecure
|| existingState
== Bogus
, depth
, false, &foundCut
);
1667 if (dsState
!= Indeterminate
) {
1674 void SyncRes::computeZoneCuts(const DNSName
& begin
, const DNSName
& end
, unsigned int depth
)
1676 if(!begin
.isPartOf(end
)) {
1677 LOG(d_prefix
<<" "<<begin
.toLogString()<<" is not part of "<<end
.toString()<<endl
);
1678 throw PDNSException(begin
.toLogString() + " is not part of " + end
.toString());
1681 if (d_cutStates
.count(begin
) != 0) {
1686 vState cutState
= getDSRecords(end
, ds
, false, depth
);
1687 LOG(d_prefix
<<": setting cut state for "<<end
<<" to "<<vStates
[cutState
]<<endl
);
1688 d_cutStates
[end
] = cutState
;
1690 if (!d_DNSSECValidationRequested
) {
1695 std::vector
<string
> labelsToAdd
= begin
.makeRelative(end
).getRawLabels();
1697 bool oldSkipCNAME
= d_skipCNAMECheck
;
1698 d_skipCNAMECheck
= true;
1700 while(qname
!= begin
) {
1701 if (labelsToAdd
.empty())
1704 qname
.prependRawLabel(labelsToAdd
.back());
1705 labelsToAdd
.pop_back();
1706 LOG(d_prefix
<<": - Looking for a cut at "<<qname
<<endl
);
1708 const auto cutIt
= d_cutStates
.find(qname
);
1709 if (cutIt
!= d_cutStates
.cend()) {
1710 if (cutIt
->second
!= Indeterminate
) {
1711 LOG(d_prefix
<<": - Cut already known at "<<qname
<<endl
);
1712 cutState
= cutIt
->second
;
1717 /* no need to look for NS and DS if we are already insecure or bogus,
1720 if (cutState
== Insecure
|| cutState
== Bogus
) {
1722 vState newState
= getDSRecords(qname
, cutDS
, true, depth
);
1723 if (newState
== Indeterminate
) {
1727 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[newState
]<<endl
);
1728 cutState
= newState
;
1730 d_cutStates
[qname
] = cutState
;
1735 vState newState
= Indeterminate
;
1736 /* temporarily mark as Indeterminate, so that we won't enter an endless loop
1737 trying to determine that zone cut again. */
1738 d_cutStates
[qname
] = newState
;
1739 bool foundCut
= lookForCut(qname
, depth
+ 1, cutState
, newState
);
1741 LOG(d_prefix
<<": - Found cut at "<<qname
<<endl
);
1742 if (newState
!= Indeterminate
) {
1743 cutState
= newState
;
1745 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[cutState
]<<endl
);
1746 d_cutStates
[qname
] = cutState
;
1749 /* remove the temporary cut */
1750 LOG(d_prefix
<<qname
<<": removing cut state for "<<qname
<<", was "<<vStates
[d_cutStates
[qname
]]<<endl
);
1751 d_cutStates
.erase(qname
);
1755 d_skipCNAMECheck
= oldSkipCNAME
;
1757 LOG(d_prefix
<<": list of cuts from "<<begin
<<" to "<<end
<<endl
);
1758 for (const auto& cut
: d_cutStates
) {
1759 if (cut
.first
.isRoot() || (begin
.isPartOf(cut
.first
) && cut
.first
.isPartOf(end
))) {
1760 LOG(" - "<<cut
.first
<<": "<<vStates
[cut
.second
]<<endl
);
1765 vState
SyncRes::validateDNSKeys(const DNSName
& zone
, const std::vector
<DNSRecord
>& dnskeys
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, unsigned int depth
)
1768 if (!signatures
.empty()) {
1769 DNSName signer
= getSigner(signatures
);
1771 if (!signer
.empty() && signer
.isPartOf(zone
)) {
1772 vState state
= getDSRecords(signer
, ds
, false, depth
);
1774 if (state
!= Secure
) {
1780 skeyset_t tentativeKeys
;
1781 std::vector
<shared_ptr
<DNSRecordContent
> > toSign
;
1783 for (const auto& dnskey
: dnskeys
) {
1784 if (dnskey
.d_type
== QType::DNSKEY
) {
1785 auto content
= getRR
<DNSKEYRecordContent
>(dnskey
);
1787 tentativeKeys
.insert(content
);
1788 toSign
.push_back(content
);
1793 LOG(d_prefix
<<": trying to validate "<<std::to_string(tentativeKeys
.size())<<" DNSKEYs with "<<std::to_string(ds
.size())<<" DS"<<endl
);
1794 skeyset_t validatedKeys
;
1795 validateDNSKeysAgainstDS(d_now
.tv_sec
, zone
, ds
, tentativeKeys
, toSign
, signatures
, validatedKeys
);
1797 LOG(d_prefix
<<": we now have "<<std::to_string(validatedKeys
.size())<<" DNSKEYs"<<endl
);
1799 /* if we found at least one valid RRSIG covering the set,
1800 all tentative keys are validated keys. Otherwise it means
1801 we haven't found at least one DNSKEY and a matching RRSIG
1802 covering this set, this looks Bogus. */
1803 if (validatedKeys
.size() != tentativeKeys
.size()) {
1804 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
1811 vState
SyncRes::getDNSKeys(const DNSName
& signer
, skeyset_t
& keys
, unsigned int depth
)
1813 std::vector
<DNSRecord
> records
;
1814 std::set
<GetBestNSAnswer
> beenthere
;
1815 LOG(d_prefix
<<"Retrieving DNSKeys for "<<signer
<<endl
);
1817 vState state
= Indeterminate
;
1818 /* following CNAME might lead to us to the wrong DNSKEY */
1819 bool oldSkipCNAME
= d_skipCNAMECheck
;
1820 d_skipCNAMECheck
= true;
1821 int rcode
= doResolve(signer
, QType(QType::DNSKEY
), records
, depth
+ 1, beenthere
, state
);
1822 d_skipCNAMECheck
= oldSkipCNAME
;
1824 if (rcode
== RCode::NoError
) {
1825 if (state
== Secure
) {
1826 for (const auto& key
: records
) {
1827 if (key
.d_type
== QType::DNSKEY
) {
1828 auto content
= getRR
<DNSKEYRecordContent
>(key
);
1830 keys
.insert(content
);
1835 LOG(d_prefix
<<"Retrieved "<<keys
.size()<<" DNSKeys for "<<signer
<<", state is "<<vStates
[state
]<<endl
);
1839 LOG(d_prefix
<<"Returning Bogus state from "<<__func__
<<"("<<signer
<<")"<<endl
);
1843 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
)
1846 if (!signatures
.empty()) {
1847 const DNSName signer
= getSigner(signatures
);
1848 if (!signer
.empty() && name
.isPartOf(signer
)) {
1849 if ((qtype
== QType::DNSKEY
|| qtype
== QType::DS
) && signer
== qname
) {
1850 /* we are already retrieving those keys, sorry */
1851 return Indeterminate
;
1853 vState state
= getDNSKeys(signer
, keys
, depth
);
1854 if (state
!= Secure
) {
1859 LOG(d_prefix
<<"Bogus!"<<endl
);
1863 std::vector
<std::shared_ptr
<DNSRecordContent
> > recordcontents
;
1864 for (const auto& record
: records
) {
1865 recordcontents
.push_back(record
.d_content
);
1868 LOG(d_prefix
<<"Going to validate "<<recordcontents
.size()<< " record contents with "<<signatures
.size()<<" sigs and "<<keys
.size()<<" keys for "<<name
<<endl
);
1869 if (validateWithKeySet(d_now
.tv_sec
, name
, recordcontents
, signatures
, keys
, false)) {
1870 LOG(d_prefix
<<"Secure!"<<endl
);
1874 LOG(d_prefix
<<"Bogus!"<<endl
);
1878 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
)
1885 prefix
.append(depth
, ' ');
1888 std::vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1889 const unsigned int labelCount
= qname
.countLabels();
1890 bool isCNAMEAnswer
= false;
1891 for(const auto& rec
: lwr
.d_records
) {
1892 if(!isCNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
) {
1893 isCNAMEAnswer
= true;
1896 /* if we have a positive answer synthetized from a wildcard,
1897 we need to store the corresponding NSEC/NSEC3 records proving
1898 that the exact name did not exist in the negative cache */
1899 if(needWildcardProof
) {
1900 if (nsecTypes
.count(rec
.d_type
)) {
1901 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
1903 else if (rec
.d_type
== QType::RRSIG
) {
1904 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1905 if (rrsig
&& nsecTypes
.count(rrsig
->d_type
)) {
1906 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
1910 if(rec
.d_type
== QType::RRSIG
) {
1911 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1913 /* As illustrated in rfc4035's Appendix B.6, the RRSIG label
1914 count can be lower than the name's label count if it was
1915 synthetized from the wildcard. Note that the difference might
1917 if (rec
.d_name
== qname
&& rrsig
->d_labels
< labelCount
) {
1918 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthetized from a wildcard, we need a wildcard proof"<<endl
);
1919 needWildcardProof
= true;
1922 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
1923 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
1924 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
);
1929 // reap all answers from this packet that are acceptable
1930 for(auto& rec
: lwr
.d_records
) {
1931 if(rec
.d_type
== QType::OPT
) {
1932 LOG(prefix
<<qname
<<": OPT answer '"<<rec
.d_name
<<"' from '"<<auth
<<"' nameservers" <<endl
);
1935 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
<<" ");
1936 if(rec
.d_type
== QType::ANY
) {
1937 LOG("NO! - we don't accept 'ANY' data"<<endl
);
1941 if(rec
.d_name
.isPartOf(auth
)) {
1942 if(rec
.d_type
== QType::RRSIG
) {
1943 LOG("RRSIG - separate"<<endl
);
1945 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
)) {
1946 LOG("NO! Is from delegation-only zone"<<endl
);
1948 return RCode::NXDomain
;
1951 bool haveLogged
= false;
1952 if (!t_sstorage
.domainmap
->empty()) {
1953 // Check if we are authoritative for a zone in this answer
1954 DNSName
tmp_qname(rec
.d_name
);
1955 auto auth_domain_iter
=getBestAuthZone(&tmp_qname
);
1956 if(auth_domain_iter
!=t_sstorage
.domainmap
->end() &&
1957 auth
.countLabels() <= auth_domain_iter
->first
.countLabels()) {
1958 if (auth_domain_iter
->first
!= auth
) {
1959 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter
->first
<<endl
);
1962 LOG("YES! - This answer was ");
1963 if (!wasForwarded
) {
1964 LOG("retrieved from the local auth store.");
1966 LOG("received from a server we forward to.");
1977 rec
.d_ttl
=min(s_maxcachettl
, rec
.d_ttl
);
1980 dr
.d_ttl
+= d_now
.tv_sec
;
1981 dr
.d_place
=DNSResourceRecord::ANSWER
;
1982 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(dr
);
1990 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
1991 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)
1992 uint32_t lowestTTD
=computeLowestTTD(i
->second
.records
, i
->second
.signatures
, i
->second
.signaturesTTL
);
1994 for(auto& record
: i
->second
.records
)
1995 record
.d_ttl
= lowestTTD
; // boom
1998 // cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
1999 // cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
2002 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
2004 if(i
->second
.records
.empty()) // this happens when we did store signatures, but passed on the records themselves
2007 bool isAA
= lwr
.d_aabit
;
2008 if (isAA
&& isCNAMEAnswer
&& (i
->first
.place
!= DNSResourceRecord::ANSWER
|| i
->first
.type
!= QType::CNAME
)) {
2011 Note that the answer section of an authoritative answer normally
2012 contains only authoritative data. However when the name sought is an
2013 alias (see section 10.1.1) only the record describing that alias is
2014 necessarily authoritative. Clients should assume that other records
2015 may have come from the server's cache. Where authoritative answers
2016 are required, the client should query again, using the canonical name
2017 associated with the alias.
2022 vState recordState
= getValidationStatus(i
->first
.name
, false);
2023 LOG(d_prefix
<<": got initial zone status "<<vStates
[recordState
]<<" for record "<<i
->first
.name
<<endl
);
2025 if (d_DNSSECValidationRequested
&& recordState
== Secure
) {
2026 vState initialState
= recordState
;
2029 if (i
->first
.place
!= DNSResourceRecord::ADDITIONAL
) {
2030 /* the additional entries can be insecure,
2032 "Glue address RRsets associated with delegations MUST NOT be signed"
2034 if (i
->first
.type
== QType::DNSKEY
&& i
->first
.place
== DNSResourceRecord::ANSWER
) {
2035 LOG(d_prefix
<<"Validating DNSKEY for "<<i
->first
.name
<<endl
);
2036 recordState
= validateDNSKeys(i
->first
.name
, i
->second
.records
, i
->second
.signatures
, depth
);
2039 LOG(d_prefix
<<"Validating non-additional record for "<<i
->first
.name
<<endl
);
2040 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2041 /* 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 */
2042 if (qtype
== QType::NS
&& i
->second
.signatures
.empty() && recordState
== Bogus
&& haveExactValidationStatus(i
->first
.name
) && getValidationStatus(i
->first
.name
) == Indeterminate
) {
2043 recordState
= Indeterminate
;
2049 /* in a non authoritative answer, we only care about the DS record (or lack of) */
2050 if ((i
->first
.type
== QType::DS
|| i
->first
.type
== QType::NSEC
|| i
->first
.type
== QType::NSEC3
) && i
->first
.place
== DNSResourceRecord::AUTHORITY
) {
2051 LOG(d_prefix
<<"Validating DS record for "<<i
->first
.name
<<endl
);
2052 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2056 if (initialState
== Secure
&& state
!= recordState
) {
2057 updateValidationState(state
, recordState
);
2061 if (d_DNSSECValidationRequested
) {
2062 LOG(d_prefix
<<"Skipping validation because the current state is "<<vStates
[recordState
]<<endl
);
2066 /* We don't need to store NSEC3 records in the positive cache because:
2067 - we don't allow direct NSEC3 queries
2068 - denial of existence proofs in wildcard expanded positive responses are stored in authorityRecs
2069 - denial of existence proofs for negative responses are stored in the negative cache
2071 if (i
->first
.type
!= QType::NSEC3
) {
2072 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
);
2075 if(i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
)
2079 return RCode::NoError
;
2082 void SyncRes::updateDenialValidationState(NegCache::NegCacheEntry
& ne
, vState
& state
, const dState denialState
, const dState expectedState
, bool allowOptOut
)
2084 if (denialState
!= expectedState
) {
2085 if (denialState
== OPTOUT
&& allowOptOut
) {
2086 LOG(d_prefix
<<"OPT-out denial found for "<<ne
.d_name
<<endl
);
2087 ne
.d_validationState
= Secure
;
2090 else if (denialState
== INSECURE
) {
2091 LOG(d_prefix
<<"Insecure denial found for "<<ne
.d_name
<<", returning Insecure"<<endl
);
2092 ne
.d_validationState
= Insecure
;
2095 LOG(d_prefix
<<"Invalid denial found for "<<ne
.d_name
<<", returning Bogus, res="<<denialState
<<", expectedState="<<expectedState
<<endl
);
2096 ne
.d_validationState
= Bogus
;
2098 updateValidationState(state
, ne
.d_validationState
);
2102 dState
SyncRes::getDenialValidationState(NegCache::NegCacheEntry
& ne
, const vState state
, const dState expectedState
, bool referralToUnsigned
)
2104 cspmap_t csp
= harvestCSPFromNE(ne
);
2105 return getDenial(csp
, ne
.d_name
, ne
.d_qtype
.getCode(), referralToUnsigned
, expectedState
== NXQTYPE
);
2108 bool SyncRes::processRecords(const std::string
& prefix
, const DNSName
& qname
, const QType
& qtype
, const DNSName
& auth
, LWResult
& lwr
, const bool sendRDQuery
, vector
<DNSRecord
>& ret
, set
<DNSName
>& nsset
, DNSName
& newtarget
, DNSName
& newauth
, bool& realreferral
, bool& negindic
, vState
& state
, bool needWildcardProof
)
2112 for(auto& rec
: lwr
.d_records
) {
2113 if (rec
.d_type
!=QType::OPT
&& rec
.d_class
!=QClass::IN
)
2116 if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2117 lwr
.d_rcode
==RCode::NXDomain
&& qname
.isPartOf(rec
.d_name
) && rec
.d_name
.isPartOf(auth
)) {
2118 LOG(prefix
<<qname
<<": got negative caching indication for name '"<<qname
<<"' (accept="<<rec
.d_name
.isPartOf(auth
)<<"), newtarget='"<<newtarget
<<"'"<<endl
);
2120 rec
.d_ttl
= min(rec
.d_ttl
, s_maxnegttl
);
2121 if(newtarget
.empty()) // only add a SOA if we're not going anywhere after this
2124 NegCache::NegCacheEntry ne
;
2126 uint32_t lowestTTL
= rec
.d_ttl
;
2127 /* if we get an NXDomain answer with a CNAME, the name
2128 does exist but the target does not */
2129 ne
.d_name
= newtarget
.empty() ? qname
: newtarget
;
2130 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2131 ne
.d_auth
= rec
.d_name
;
2132 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2133 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2135 if (state
== Secure
) {
2136 dState denialState
= getDenialValidationState(ne
, state
, NXDOMAIN
, false);
2137 updateDenialValidationState(ne
, state
, denialState
, NXDOMAIN
, false);
2140 ne
.d_validationState
= state
;
2143 /* if we get an NXDomain answer with a CNAME, let's not cache the
2144 target, even the server was authoritative for it,
2145 and do an additional query for the CNAME target.
2146 We have a regression test making sure we do exactly that.
2148 if(!wasVariable() && newtarget
.empty()) {
2149 t_sstorage
.negcache
.add(ne
);
2150 if(s_rootNXTrust
&& ne
.d_auth
.isRoot() && auth
.isRoot()) {
2151 ne
.d_name
= ne
.d_name
.getLastLabel();
2152 t_sstorage
.negcache
.add(ne
);
2158 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_type
==QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
) {
2160 if (auto content
= getRR
<CNAMERecordContent
>(rec
)) {
2161 newtarget
=content
->getTarget();
2164 /* if we have a positive answer synthetized from a wildcard, we need to
2165 return the corresponding NSEC/NSEC3 records from the AUTHORITY section
2166 proving that the exact name did not exist */
2167 else if(needWildcardProof
&& (rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::AUTHORITY
) {
2168 ret
.push_back(rec
); // enjoy your DNSSEC
2170 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
2171 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&&
2173 rec
.d_type
==qtype
.getCode() || ((lwr
.d_aabit
|| sendRDQuery
) && qtype
== QType(QType::ANY
))
2177 LOG(prefix
<<qname
<<": answer is in: resolved to '"<< rec
.d_content
->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"'"<<endl
);
2182 if (state
== Secure
&& needWildcardProof
) {
2183 /* We have a positive answer synthetized from a wildcard, we need to check that we have
2184 proof that the exact name doesn't exist so the wildcard can be used,
2185 as described in section 5.3.4 of RFC 4035 and 5.3 of FRC 7129.
2187 NegCache::NegCacheEntry ne
;
2189 uint32_t lowestTTL
= rec
.d_ttl
;
2191 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2192 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2194 cspmap_t csp
= harvestCSPFromNE(ne
);
2195 dState res
= getDenial(csp
, qname
, ne
.d_qtype
.getCode(), false, false, false);
2196 if (res
!= NXDOMAIN
) {
2198 if (res
== INSECURE
) {
2199 /* Some part could not be validated, for example a NSEC3 record with a too large number of iterations,
2200 this is not enough to warrant a Bogus, but go Insecure. */
2202 LOG(d_prefix
<<"Unable to validate denial in wildcard expanded positive response found for "<<qname
<<", returning Insecure, res="<<res
<<endl
);
2205 LOG(d_prefix
<<"Invalid denial in wildcard expanded positive response found for "<<qname
<<", returning Bogus, res="<<res
<<endl
);
2208 updateValidationState(state
, st
);
2209 /* we already stored the record with a different validation status, let's fix it */
2210 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qtype
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, lwr
.d_aabit
, st
);
2214 else if((rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::ANSWER
) {
2215 if(rec
.d_type
!= QType::RRSIG
|| rec
.d_name
== qname
)
2216 ret
.push_back(rec
); // enjoy your DNSSEC
2218 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::NS
&& qname
.isPartOf(rec
.d_name
)) {
2219 if(moreSpecificThan(rec
.d_name
,auth
)) {
2221 LOG(prefix
<<qname
<<": got NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2225 LOG(prefix
<<qname
<<": got upwards/level NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"', had '"<<auth
<<"'"<<endl
);
2227 if (auto content
= getRR
<NSRecordContent
>(rec
)) {
2228 nsset
.insert(content
->getNS());
2231 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::DS
&& qname
.isPartOf(rec
.d_name
)) {
2232 LOG(prefix
<<qname
<<": got DS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2234 else if(realreferral
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& (rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && newauth
.isPartOf(auth
)) {
2235 /* we might have received a denial of the DS, let's check */
2236 if (state
== Secure
) {
2237 NegCache::NegCacheEntry ne
;
2239 ne
.d_name
= newauth
;
2240 ne
.d_qtype
= QType::DS
;
2241 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2242 uint32_t lowestTTL
= rec
.d_ttl
;
2243 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2245 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, true);
2247 if (denialState
== NXQTYPE
|| denialState
== OPTOUT
|| denialState
== INSECURE
) {
2248 ne
.d_ttd
= lowestTTL
+ d_now
.tv_sec
;
2249 ne
.d_validationState
= Secure
;
2250 LOG(prefix
<<qname
<<": got negative indication of DS record for '"<<newauth
<<"'"<<endl
);
2252 if(!wasVariable()) {
2253 t_sstorage
.negcache
.add(ne
);
2256 if (qname
== newauth
&& qtype
== QType::DS
) {
2257 /* we are actually done! */
2264 else if(!done
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2265 lwr
.d_rcode
==RCode::NoError
&& qname
.isPartOf(rec
.d_name
)) {
2266 LOG(prefix
<<qname
<<": got negative caching indication for '"<< qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
2268 if(!newtarget
.empty()) {
2269 LOG(prefix
<<qname
<<": Hang on! Got a redirect to '"<<newtarget
<<"' already"<<endl
);
2272 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2275 NegCache::NegCacheEntry ne
;
2276 ne
.d_auth
= rec
.d_name
;
2277 uint32_t lowestTTL
= rec
.d_ttl
;
2280 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2281 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2283 if (state
== Secure
) {
2284 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, false);
2285 updateDenialValidationState(ne
, state
, denialState
, NXQTYPE
, qtype
== QType::DS
);
2287 ne
.d_validationState
= state
;
2290 if(!wasVariable()) {
2291 if(qtype
.getCode()) { // prevents us from blacking out a whole domain
2292 t_sstorage
.negcache
.add(ne
);
2303 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
)
2309 if(d_outqueries
+ d_throttledqueries
> s_maxqperq
) {
2310 throw ImmediateServFailException("more than "+std::to_string(s_maxqperq
)+" (max-qperq) queries sent while resolving "+qname
.toLogString());
2313 if(s_maxtotusec
&& d_totUsec
> s_maxtotusec
) {
2314 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");
2318 LOG(prefix
<<qname
<<": using TCP with "<< remoteIP
.toStringWithPort() <<endl
);
2323 if(d_pdl
&& d_pdl
->preoutquery(remoteIP
, d_requestor
, qname
, qtype
, doTCP
, lwr
.d_records
, resolveret
)) {
2324 LOG(prefix
<<qname
<<": query handled by Lua"<<endl
);
2327 ednsmask
=getEDNSSubnetMask(d_requestor
, qname
, remoteIP
);
2329 LOG(prefix
<<qname
<<": Adding EDNS Client Subnet Mask "<<ednsmask
->toString()<<" to query"<<endl
);
2332 resolveret
= asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(),
2333 doTCP
, sendRDQuery
, &d_now
, ednsmask
, &lwr
); // <- we go out on the wire!
2336 LOG(prefix
<<qname
<<": Received EDNS Client Subnet Mask "<<ednsmask
->toString()<<" on response"<<endl
);
2340 /* preoutquery killed the query by setting dq.rcode to -3 */
2341 if(resolveret
==-3) {
2342 throw ImmediateServFailException("Query killed by policy");
2345 d_totUsec
+= lwr
.d_usec
;
2346 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
2348 if(resolveret
!= 1) {
2349 /* Error while resolving */
2350 if(resolveret
== 0) {
2353 LOG(prefix
<<qname
<<": timeout resolving after "<<lwr
.d_usec
/1000.0<<"msec "<< (doTCP
? "over TCP" : "")<<endl
);
2355 s_outgoingtimeouts
++;
2357 if(remoteIP
.sin4
.sin_family
== AF_INET
)
2358 s_outgoing4timeouts
++;
2360 s_outgoing6timeouts
++;
2362 else if(resolveret
== -2) {
2363 /* OS resource limit reached */
2364 LOG(prefix
<<qname
<<": hit a local resource limit resolving"<< (doTCP
? " over TCP" : "")<<", probable error: "<<stringerror()<<endl
);
2365 g_stats
.resourceLimits
++;
2368 /* -1 means server unreachable */
2371 LOG(prefix
<<qname
<<": error resolving from "<<remoteIP
.toString()<< (doTCP
? " over TCP" : "") <<", possible error: "<<strerror(errno
)<< endl
);
2374 if(resolveret
!= -2) { // don't account for resource limits, they are our own fault
2375 t_sstorage
.nsSpeeds
[nsName
].submit(remoteIP
, 1000000, &d_now
); // 1 sec
2377 // code below makes sure we don't filter COM or the root
2378 if (s_serverdownmaxfails
> 0 && (auth
!= g_rootdnsname
) && t_sstorage
.fails
.incr(remoteIP
) >= s_serverdownmaxfails
) {
2379 LOG(prefix
<<qname
<<": Max fails reached resolving on "<< remoteIP
.toString() <<". Going full throttle for "<< s_serverdownthrottletime
<<" seconds" <<endl
);
2380 // mark server as down
2381 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0), s_serverdownthrottletime
, 10000);
2383 else if (resolveret
== -1) {
2384 // unreachable, 1 minute or 100 queries
2385 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 100);
2389 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 10, 5);
2396 /* we got an answer */
2397 if(lwr
.d_rcode
==RCode::ServFail
|| lwr
.d_rcode
==RCode::Refused
) {
2398 LOG(prefix
<<qname
<<": "<<nsName
<<" ("<<remoteIP
.toString()<<") returned a "<< (lwr
.d_rcode
==RCode::ServFail
? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl
);
2399 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
2403 /* this server sent a valid answer, mark it backup up if it was down */
2404 if(s_serverdownmaxfails
> 0) {
2405 t_sstorage
.fails
.clear(remoteIP
);
2412 LOG(prefix
<<qname
<<": truncated bit set, over TCP?"<<endl
);
2413 /* let's treat that as a ServFail answer from this server */
2414 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
2424 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
)
2429 prefix
.append(depth
, ' ');
2433 for(auto& rec
: lwr
.d_records
) {
2434 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumTTL
);
2438 bool needWildcardProof
= false;
2439 *rcode
= updateCacheFromRecords(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, state
, needWildcardProof
);
2440 if (*rcode
!= RCode::NoError
) {
2444 LOG(prefix
<<qname
<<": determining status after receiving this packet"<<endl
);
2447 bool realreferral
=false, negindic
=false;
2451 bool done
= processRecords(prefix
, qname
, qtype
, auth
, lwr
, sendRDQuery
, ret
, nsset
, newtarget
, newauth
, realreferral
, negindic
, state
, needWildcardProof
);
2454 LOG(prefix
<<qname
<<": status=got results, this level of recursion done"<<endl
);
2455 LOG(prefix
<<qname
<<": validation status is "<<vStates
[state
]<<endl
);
2456 *rcode
= RCode::NoError
;
2460 if(!newtarget
.empty()) {
2461 if(newtarget
== qname
) {
2462 LOG(prefix
<<qname
<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl
);
2463 *rcode
= RCode::ServFail
;
2468 LOG(prefix
<<qname
<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl
);
2469 *rcode
= RCode::ServFail
;
2473 if (qtype
== QType::DS
) {
2474 LOG(prefix
<<qname
<<": status=got a CNAME referral, but we are looking for a DS"<<endl
);
2477 addNXNSECS(ret
, lwr
.d_records
);
2479 *rcode
= RCode::NoError
;
2483 LOG(prefix
<<qname
<<": status=got a CNAME referral, starting over with "<<newtarget
<<endl
);
2485 set
<GetBestNSAnswer
> beenthere2
;
2486 vState cnameState
= Indeterminate
;
2487 *rcode
= doResolve(newtarget
, qtype
, ret
, depth
+ 1, beenthere2
, cnameState
);
2488 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
2489 updateValidationState(state
, cnameState
);
2494 if(lwr
.d_rcode
== RCode::NXDomain
) {
2495 LOG(prefix
<<qname
<<": status=NXDOMAIN, we are done "<<(negindic
? "(have negative SOA)" : "")<<endl
);
2498 addNXNSECS(ret
, lwr
.d_records
);
2500 *rcode
= RCode::NXDomain
;
2504 if(nsset
.empty() && !lwr
.d_rcode
&& (negindic
|| lwr
.d_aabit
|| sendRDQuery
)) {
2505 LOG(prefix
<<qname
<<": status=noerror, other types may exist, but we are done "<<(negindic
? "(have negative SOA) " : "")<<(lwr
.d_aabit
? "(have aa bit) " : "")<<endl
);
2507 if(state
== Secure
&& lwr
.d_aabit
&& !negindic
) {
2508 updateValidationState(state
, Bogus
);
2512 addNXNSECS(ret
, lwr
.d_records
);
2514 *rcode
= RCode::NoError
;
2519 LOG(prefix
<<qname
<<": status=did not resolve, got "<<(unsigned int)nsset
.size()<<" NS, ");
2521 nameservers
.clear();
2522 for (auto const &nameserver
: nsset
) {
2524 d_appliedPolicy
= dfe
.getProcessingPolicy(nameserver
, d_discardedPolicies
);
2525 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
2526 LOG("however "<<nameserver
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
2531 nameservers
.insert({nameserver
, {{}, false}});
2533 LOG("looping to them"<<endl
);
2534 *gotNewServers
= true;
2544 * -1 in case of no results
2545 * -2 when a FilterEngine Policy was hit
2548 int SyncRes::doResolveAt(NsSet
&nameservers
, DNSName auth
, bool flawedNSSet
, const DNSName
&qname
, const QType
&qtype
,
2549 vector
<DNSRecord
>&ret
,
2550 unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
, vState
& state
)
2552 auto luaconfsLocal
= g_luaconfs
.getLocal();
2556 prefix
.append(depth
, ' ');
2559 LOG(prefix
<<qname
<<": Cache consultations done, have "<<(unsigned int)nameservers
.size()<<" NS to contact");
2561 if (nameserversBlockedByRPZ(luaconfsLocal
->dfe
, nameservers
)) {
2567 for(;;) { // we may get more specific nameservers
2568 vector
<DNSName
> rnameservers
= shuffleInSpeedOrder(nameservers
, doLog() ? (prefix
+qname
.toString()+": ") : string() );
2570 for(auto tns
=rnameservers
.cbegin();;++tns
) {
2571 if(tns
==rnameservers
.cend()) {
2572 LOG(prefix
<<qname
<<": Failed to resolve via any of the "<<(unsigned int)rnameservers
.size()<<" offered NS at level '"<<auth
<<"'"<<endl
);
2573 if(!auth
.isRoot() && flawedNSSet
) {
2574 LOG(prefix
<<qname
<<": Ageing nameservers for level '"<<auth
<<"', next query might succeed"<<endl
);
2576 if(t_RC
->doAgeCache(d_now
.tv_sec
, auth
, QType::NS
, 10))
2577 g_stats
.nsSetInvalidations
++;
2582 bool cacheOnly
= false;
2583 // this line needs to identify the 'self-resolving' behaviour
2584 if(qname
== *tns
&& (qtype
.getCode() == QType::A
|| qtype
.getCode() == QType::AAAA
)) {
2585 /* we might have a glue entry in cache so let's try this NS
2586 but only if we have enough in the cache to know how to reach it */
2587 LOG(prefix
<<qname
<<": Using NS to resolve itself, but only using what we have in cache ("<<(1+tns
-rnameservers
.cbegin())<<"/"<<rnameservers
.size()<<")"<<endl
);
2591 typedef vector
<ComboAddress
> remoteIPs_t
;
2592 remoteIPs_t remoteIPs
;
2593 remoteIPs_t::const_iterator remoteIP
;
2594 bool pierceDontQuery
=false;
2595 bool sendRDQuery
=false;
2596 boost::optional
<Netmask
> ednsmask
;
2598 const bool wasForwarded
= tns
->empty() && (!nameservers
[*tns
].first
.empty());
2599 int rcode
= RCode::NoError
;
2600 bool gotNewServers
= false;
2602 if(tns
->empty() && !wasForwarded
) {
2603 LOG(prefix
<<qname
<<": Domain is out-of-band"<<endl
);
2605 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, lwr
.d_records
, depth
, lwr
.d_rcode
);
2609 /* we have received an answer, are we done ? */
2610 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, false, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
2614 if (gotNewServers
) {
2619 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
2620 remoteIPs
= retrieveAddressesForNS(prefix
, qname
, tns
, depth
, beenthere
, rnameservers
, nameservers
, sendRDQuery
, pierceDontQuery
, flawedNSSet
, cacheOnly
);
2622 if(remoteIPs
.empty()) {
2623 LOG(prefix
<<qname
<<": Failed to get IP for NS "<<*tns
<<", trying next if available"<<endl
);
2628 bool hitPolicy
{false};
2629 LOG(prefix
<<qname
<<": Resolved '"<<auth
<<"' NS "<<*tns
<<" to: ");
2630 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
2631 if(remoteIP
!= remoteIPs
.cbegin()) {
2634 LOG(remoteIP
->toString());
2635 if(nameserverIPBlockedByRPZ(luaconfsLocal
->dfe
, *remoteIP
)) {
2640 if (hitPolicy
) //implies d_wantsRPZ
2644 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
2645 LOG(prefix
<<qname
<<": Trying IP "<< remoteIP
->toStringWithPort() <<", asking '"<<qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
2647 if (throttledOrBlocked(prefix
, *remoteIP
, qname
, qtype
, pierceDontQuery
)) {
2651 bool truncated
= false;
2652 bool gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
2653 *tns
, *remoteIP
, false, &truncated
);
2654 if (gotAnswer
&& truncated
) {
2655 /* retry, over TCP this time */
2656 gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
2657 *tns
, *remoteIP
, true, &truncated
);
2664 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
);
2666 /* // for you IPv6 fanatics :-)
2667 if(remoteIP->sin4.sin_family==AF_INET6)
2670 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
2672 t_sstorage
.nsSpeeds
[*tns
].submit(*remoteIP
, lwr
.d_usec
, &d_now
);
2674 /* we have received an answer, are we done ? */
2675 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
2679 if (gotNewServers
) {
2683 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100);
2686 if (gotNewServers
) {
2690 if(remoteIP
== remoteIPs
.cend()) // we tried all IP addresses, none worked
2699 void SyncRes::setIncomingECS(boost::optional
<const EDNSSubnetOpts
&> incomingECS
)
2701 d_incomingECS
= incomingECS
;
2703 if (d_incomingECS
->source
.getBits() == 0) {
2704 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0.
2705 But using an empty ECS in that case would mean inserting
2706 a non ECS-specific entry into the cache, preventing any further
2707 ECS-specific query to be sent.
2708 So instead we use the trick described in section 7.1.2:
2709 "The subsequent Recursive Resolver query to the Authoritative Nameserver
2710 will then either not include an ECS option or MAY optionally include
2711 its own address information, which is what the Authoritative
2712 Nameserver will almost certainly use to generate any Tailored
2713 Response in lieu of an option. This allows the answer to be handled
2714 by the same caching mechanism as other queries, with an explicit
2715 indicator of the applicable scope. Subsequent Stub Resolver queries
2716 for /0 can then be answered from this cached response.
2718 d_incomingECS
= s_ecsScopeZero
;
2719 d_incomingECSNetwork
= s_ecsScopeZero
.source
.getMaskedNetwork();
2722 uint8_t bits
= std::min(incomingECS
->source
.getBits(), (incomingECS
->source
.isIpv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
2723 d_incomingECS
->source
= Netmask(incomingECS
->source
.getNetwork(), bits
);
2724 d_incomingECSNetwork
= d_incomingECS
->source
.getMaskedNetwork();
2728 d_incomingECSNetwork
= ComboAddress();
2732 boost::optional
<Netmask
> SyncRes::getEDNSSubnetMask(const ComboAddress
& local
, const DNSName
&dn
, const ComboAddress
& rem
)
2734 boost::optional
<Netmask
> result
;
2737 if(d_incomingECSFound
) {
2738 trunc
= d_incomingECSNetwork
;
2739 bits
= d_incomingECS
->source
.getBits();
2741 else if(!local
.isIPv4() || local
.sin4
.sin_addr
.s_addr
) { // detect unset 'requestor'
2743 bits
= local
.isIPv4() ? 32 : 128;
2744 bits
= std::min(bits
, (trunc
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
2747 /* nothing usable */
2751 if(s_ednsdomains
.check(dn
) || s_ednssubnets
.match(rem
)) {
2752 trunc
.truncate(bits
);
2753 return boost::optional
<Netmask
>(Netmask(trunc
, bits
));
2759 void SyncRes::parseEDNSSubnetWhitelist(const std::string
& wlist
)
2761 vector
<string
> parts
;
2762 stringtok(parts
, wlist
, ",; ");
2763 for(const auto& a
: parts
) {
2765 s_ednssubnets
.addMask(Netmask(a
));
2768 s_ednsdomains
.add(DNSName(a
));
2773 // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
2774 int directResolve(const DNSName
& qname
, const QType
& qtype
, int qclass
, vector
<DNSRecord
>& ret
)
2777 gettimeofday(&now
, 0);
2780 int res
= sr
.beginResolve(qname
, QType(qtype
), qclass
, ret
);
2785 int SyncRes::getRootNS(struct timeval now
, asyncresolve_t asyncCallback
) {
2787 sr
.setDoEDNS0(true);
2788 sr
.setUpdatingRootNS();
2789 sr
.setDoDNSSEC(g_dnssecmode
!= DNSSECMode::Off
);
2790 sr
.setDNSSECValidationRequested(g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
);
2791 sr
.setAsyncCallback(asyncCallback
);
2793 vector
<DNSRecord
> ret
;
2796 res
=sr
.beginResolve(g_rootdnsname
, QType(QType::NS
), 1, ret
);
2797 if (g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
) {
2798 auto state
= sr
.getValidationState();
2800 throw PDNSException("Got Bogus validation result for .|NS");
2804 catch(const PDNSException
& e
) {
2805 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
2807 catch(const ImmediateServFailException
& e
) {
2808 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
2810 catch(const std::exception
& e
) {
2811 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.what()<<endl
;
2814 L
<<Logger::Error
<<"Failed to update . records, got an exception"<<endl
;
2818 L
<<Logger::Notice
<<"Refreshed . records"<<endl
;
2821 L
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;