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
)
629 typedef vector
<DNSRecord
> res_t
;
632 typedef vector
<ComboAddress
> ret_t
;
636 bool oldRequireAuthData
= d_requireAuthData
;
637 bool oldValidationRequested
= d_DNSSECValidationRequested
;
638 d_requireAuthData
= false;
639 d_DNSSECValidationRequested
= false;
641 for(int j
=1; j
<2+s_doIPv6
; j
++)
656 vState newState
= Indeterminate
;
657 if(!doResolve(qname
, type
, res
,depth
+1, beenthere
, newState
) && !res
.empty()) { // this consults cache, OR goes out
658 for(res_t::const_iterator i
=res
.begin(); i
!= res
.end(); ++i
) {
659 if(i
->d_type
== QType::A
|| i
->d_type
== QType::AAAA
) {
660 if(auto rec
= std::dynamic_pointer_cast
<ARecordContent
>(i
->d_content
))
661 ret
.push_back(rec
->getCA(53));
662 else if(auto aaaarec
= std::dynamic_pointer_cast
<AAAARecordContent
>(i
->d_content
))
663 ret
.push_back(aaaarec
->getCA(53));
669 if(j
==1 && s_doIPv6
) { // we got an A record, see if we have some AAAA lying around
670 vector
<DNSRecord
> cset
;
671 if(t_RC
->get(d_now
.tv_sec
, qname
, QType(QType::AAAA
), false, &cset
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
) > 0) {
672 for(auto k
=cset
.cbegin();k
!=cset
.cend();++k
) {
673 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
674 if (auto drc
= std::dynamic_pointer_cast
<AAAARecordContent
>(k
->d_content
)) {
675 ComboAddress ca
=drc
->getCA(53);
686 d_requireAuthData
= oldRequireAuthData
;
687 d_DNSSECValidationRequested
= oldValidationRequested
;
689 /* we need to remove from the nsSpeeds collection the existing IPs
690 for this nameserver that are no longer in the set, even if there
691 is only one or none at all in the current set.
693 map
<ComboAddress
, double> speeds
;
694 auto& collection
= t_sstorage
.nsSpeeds
[qname
].d_collection
;
695 for(const auto& val
: ret
) {
696 speeds
[val
] = collection
[val
].get(&d_now
);
699 t_sstorage
.nsSpeeds
[qname
].purge(speeds
);
702 random_shuffle(ret
.begin(), ret
.end(), dns_random
);
703 speedOrderCA
so(speeds
);
704 stable_sort(ret
.begin(), ret
.end(), so
);
707 string prefix
=d_prefix
;
708 prefix
.append(depth
, ' ');
709 LOG(prefix
<<"Nameserver "<<qname
<<" IPs: ");
711 for(const auto& addr
: ret
) {
718 LOG((addr
.toString())<<"(" << (boost::format("%0.2f") % (speeds
[addr
]/1000.0)).str() <<"ms)");
727 void SyncRes::getBestNSFromCache(const DNSName
&qname
, const QType
& qtype
, vector
<DNSRecord
>& bestns
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>& beenthere
)
730 DNSName
subdomain(qname
);
733 prefix
.append(depth
, ' ');
739 LOG(prefix
<<qname
<<": Checking if we have NS in cache for '"<<subdomain
<<"'"<<endl
);
740 vector
<DNSRecord
> ns
;
741 *flawedNSSet
= false;
743 if(t_RC
->get(d_now
.tv_sec
, subdomain
, QType(QType::NS
), false, &ns
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
) > 0) {
744 for(auto k
=ns
.cbegin();k
!=ns
.cend(); ++k
) {
745 if(k
->d_ttl
> (unsigned int)d_now
.tv_sec
) {
746 vector
<DNSRecord
> aset
;
748 const DNSRecord
& dr
=*k
;
749 auto nrr
= getRR
<NSRecordContent
>(dr
);
750 if(nrr
&& (!nrr
->getNS().isPartOf(subdomain
) || t_RC
->get(d_now
.tv_sec
, nrr
->getNS(), s_doIPv6
? QType(QType::ADDR
) : QType(QType::A
),
751 false, doLog() ? &aset
: 0, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
) > 5)) {
752 bestns
.push_back(dr
);
753 LOG(prefix
<<qname
<<": NS (with ip, or non-glue) in cache for '"<<subdomain
<<"' -> '"<<nrr
->getNS()<<"'"<<endl
);
754 LOG(prefix
<<qname
<<": within bailiwick: "<< nrr
->getNS().isPartOf(subdomain
));
756 LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset
.begin()->d_ttl
- d_now
.tv_sec
))<<endl
);
759 LOG(", not in cache / did not look at cache"<<endl
);
764 LOG(prefix
<<qname
<<": NS in cache for '"<<subdomain
<<"', but needs glue ("<<nrr
->getNS()<<") which we miss or is expired"<<endl
);
769 if(!bestns
.empty()) {
770 GetBestNSAnswer answer
;
772 answer
.qtype
=qtype
.getCode();
773 for(const auto& dr
: bestns
)
774 answer
.bestns
.insert(make_pair(dr
.d_name
, getRR
<NSRecordContent
>(dr
)->getNS()));
776 if(beenthere
.count(answer
)) {
778 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' but part of LOOP (already seen "<<answer
.qname
<<")! Trying less specific NS"<<endl
);
781 for( set
<GetBestNSAnswer
>::const_iterator j
=beenthere
.begin();j
!=beenthere
.end();++j
) {
782 bool neo
= !(*j
< answer
|| answer
<*j
);
783 LOG(prefix
<<qname
<<": beenthere"<<(neo
?"*":"")<<": "<<j
->qname
<<"|"<<DNSRecordContent::NumberToType(j
->qtype
)<<" ("<<(unsigned int)j
->bestns
.size()<<")"<<endl
);
788 beenthere
.insert(answer
);
789 LOG(prefix
<<qname
<<": We have NS in cache for '"<<subdomain
<<"' (flawedNSSet="<<*flawedNSSet
<<")"<<endl
);
794 LOG(prefix
<<qname
<<": no valid/useful NS in cache for '"<<subdomain
<<"'"<<endl
);
796 if(subdomain
.isRoot() && !brokeloop
) {
797 // We lost the root NS records
799 LOG(prefix
<<qname
<<": reprimed the root"<<endl
);
800 /* let's prevent an infinite loop */
801 if (!d_updatingRootNS
) {
802 getRootNS(d_now
, d_asyncResolve
);
805 } while(subdomain
.chopOff());
808 SyncRes::domainmap_t::const_iterator
SyncRes::getBestAuthZone(DNSName
* qname
) const
810 SyncRes::domainmap_t::const_iterator ret
;
812 ret
=t_sstorage
.domainmap
->find(*qname
);
813 if(ret
!=t_sstorage
.domainmap
->end())
815 }while(qname
->chopOff());
819 /** doesn't actually do the work, leaves that to getBestNSFromCache */
820 DNSName
SyncRes::getBestNSNamesFromCache(const DNSName
&qname
, const QType
& qtype
, NsSet
& nsset
, bool* flawedNSSet
, unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
)
822 DNSName
subdomain(qname
);
823 DNSName
authdomain(qname
);
825 domainmap_t::const_iterator iter
=getBestAuthZone(&authdomain
);
826 if(iter
!=t_sstorage
.domainmap
->end()) {
827 if( iter
->second
.isAuth() )
828 // this gets picked up in doResolveAt, the empty DNSName, combined with the
829 // empty vector means 'we are auth for this zone'
830 nsset
.insert({DNSName(), {{}, false}});
832 // Again, picked up in doResolveAt. An empty DNSName, combined with a
833 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
834 // This is actually picked up in retrieveAddressesForNS called from doResolveAt.
835 nsset
.insert({DNSName(), {iter
->second
.d_servers
, iter
->second
.shouldRecurse() }});
840 vector
<DNSRecord
> bestns
;
841 getBestNSFromCache(subdomain
, qtype
, bestns
, flawedNSSet
, depth
, beenthere
);
843 for(auto k
=bestns
.cbegin() ; k
!= bestns
.cend(); ++k
) {
844 // The actual resolver code will not even look at the ComboAddress or bool
845 nsset
.insert({std::dynamic_pointer_cast
<NSRecordContent
>(k
->d_content
)->getNS(), {{}, false}});
846 if(k
==bestns
.cbegin())
852 bool SyncRes::doCNAMECacheCheck(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>& ret
, unsigned int depth
, int &res
, vState
& state
)
857 prefix
.append(depth
, ' ');
860 if((depth
>9 && d_outqueries
>10 && d_throttledqueries
>5) || depth
> 15) {
861 LOG(prefix
<<qname
<<": recursing (CNAME or other indirection) too deep, depth="<<depth
<<endl
);
866 LOG(prefix
<<qname
<<": Looking for CNAME cache hit of '"<<qname
<<"|CNAME"<<"'"<<endl
);
867 vector
<DNSRecord
> cset
;
868 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
869 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
871 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) {
873 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
874 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
876 if (d_DNSSECValidationRequested
&& wasAuth
&& state
== Indeterminate
&& d_requireAuthData
) {
877 /* This means we couldn't figure out the state when this entry was cached,
878 most likely because we hadn't computed the zone cuts yet. */
879 /* make sure they are computed before validating */
880 computeZoneCuts(qname
, g_rootdnsname
, depth
);
882 vState recordState
= getValidationStatus(qname
, false);
883 if (recordState
== Secure
) {
884 LOG(prefix
<<qname
<<": got Indeterminate state from the CNAME cache, validating.."<<endl
);
885 state
= SyncRes::validateRecordsWithSigs(depth
, qname
, QType(QType::CNAME
), qname
, cset
, signatures
);
886 if (state
!= Indeterminate
) {
887 LOG(prefix
<<qname
<<": got Indeterminate state from the CNAME cache, new validation result is "<<vStates
[state
]<<endl
);
888 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, QType(QType::CNAME
), d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, d_requireAuthData
, state
);
893 LOG(prefix
<<qname
<<": Found cache CNAME hit for '"<< qname
<< "|CNAME" <<"' to '"<<j
->d_content
->getZoneRepresentation()<<"', validation state is "<<vStates
[state
]<<endl
);
896 dr
.d_ttl
-=d_now
.tv_sec
;
899 for(const auto& signature
: signatures
) {
901 sigdr
.d_type
=QType::RRSIG
;
903 sigdr
.d_ttl
=j
->d_ttl
- d_now
.tv_sec
;
904 sigdr
.d_content
=signature
;
905 sigdr
.d_place
=DNSResourceRecord::ANSWER
;
906 sigdr
.d_class
=QClass::IN
;
907 ret
.push_back(sigdr
);
910 for(const auto& rec
: authorityRecs
) {
911 DNSRecord
authDR(*rec
);
912 authDR
.d_ttl
=j
->d_ttl
- d_now
.tv_sec
;
913 ret
.push_back(authDR
);
916 if(qtype
!= QType::CNAME
) { // perhaps they really wanted a CNAME!
917 set
<GetBestNSAnswer
>beenthere
;
919 vState cnameState
= Indeterminate
;
920 res
=doResolve(std::dynamic_pointer_cast
<CNAMERecordContent
>(j
->d_content
)->getTarget(), qtype
, ret
, depth
+1, beenthere
, cnameState
);
921 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
922 updateValidationState(state
, cnameState
);
931 LOG(prefix
<<qname
<<": No CNAME cache hit of '"<< qname
<< "|CNAME" <<"' found"<<endl
);
938 vector
<DNSRecord
> records
;
939 vector
<shared_ptr
<RRSIGRecordContent
>> signatures
;
940 uint32_t signaturesTTL
{std::numeric_limits
<uint32_t>::max()};
946 DNSResourceRecord::Place place
;
947 bool operator<(const CacheKey
& rhs
) const {
948 return tie(name
, type
) < tie(rhs
.name
, rhs
.type
);
951 typedef map
<CacheKey
, CacheEntry
> tcache_t
;
954 static void reapRecordsFromNegCacheEntryForValidation(tcache_t
& tcache
, const vector
<DNSRecord
>& records
)
956 for (const auto& rec
: records
) {
957 if (rec
.d_type
== QType::RRSIG
) {
958 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
960 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
963 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(rec
);
969 * Convience function to push the records from records into ret with a new TTL
971 * \param records DNSRecords that need to go into ret
972 * \param ttl The new TTL for these records
973 * \param ret The vector of DNSRecords that should contian the records with the modified TTL
975 static void addTTLModifiedRecords(const vector
<DNSRecord
>& records
, const uint32_t ttl
, vector
<DNSRecord
>& ret
) {
976 for (const auto& rec
: records
) {
983 void SyncRes::computeNegCacheValidationStatus(NegCache::NegCacheEntry
& ne
, const DNSName
& qname
, const QType
& qtype
, const int res
, vState
& state
, unsigned int depth
)
985 computeZoneCuts(qname
, g_rootdnsname
, depth
);
988 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.authoritySOA
.records
);
989 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.authoritySOA
.signatures
);
990 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.DNSSECRecords
.records
);
991 reapRecordsFromNegCacheEntryForValidation(tcache
, ne
.DNSSECRecords
.signatures
);
993 for (const auto& entry
: tcache
) {
994 // this happens when we did store signatures, but passed on the records themselves
995 if (entry
.second
.records
.empty()) {
999 const DNSName
& owner
= entry
.first
.name
;
1001 vState recordState
= getValidationStatus(owner
, false);
1002 if (state
== Indeterminate
) {
1003 state
= recordState
;
1006 if (recordState
== Secure
) {
1007 vState cachedState
= SyncRes::validateRecordsWithSigs(depth
, qname
, qtype
, owner
, entry
.second
.records
, entry
.second
.signatures
);
1009 if (state
== Secure
&& cachedState
!= recordState
) {
1010 updateValidationState(state
, cachedState
);
1011 if (state
!= Secure
) {
1018 if (state
== Secure
) {
1019 dState expectedState
= res
== RCode::NXDomain
? NXDOMAIN
: NXQTYPE
;
1020 dState denialState
= getDenialValidationState(ne
, state
, expectedState
, qtype
== QType::DS
);
1021 updateDenialValidationState(ne
, state
, denialState
, expectedState
, qtype
== QType::DS
);
1023 if (state
!= Indeterminate
) {
1024 /* validation succeeded, let's update the cache entry so we don't have to validate again */
1025 t_sstorage
.negcache
.updateValidationStatus(ne
.d_name
, ne
.d_qtype
, state
);
1029 bool SyncRes::doCacheCheck(const DNSName
&qname
, const QType
&qtype
, vector
<DNSRecord
>&ret
, unsigned int depth
, int &res
, vState
& state
)
1031 bool giveNegative
=false;
1036 prefix
.append(depth
, ' ');
1039 // 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)
1040 DNSName
sqname(qname
);
1043 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
1045 DNSName
authname(qname
);
1047 bool wasForwardedOrAuth
= false;
1048 bool wasAuth
= false;
1049 domainmap_t::const_iterator iter
=getBestAuthZone(&authname
);
1050 if(iter
!= t_sstorage
.domainmap
->end()) {
1051 wasForwardedOrAuth
= true;
1052 const vector
<ComboAddress
>& servers
= iter
->second
.d_servers
;
1053 if(servers
.empty()) {
1057 NegCache::NegCacheEntry ne
;
1060 t_sstorage
.negcache
.getRootNXTrust(qname
, d_now
, ne
) &&
1061 ne
.d_auth
.isRoot() &&
1062 !(wasForwardedOrAuth
&& !authname
.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
1063 sttl
= ne
.d_ttd
- d_now
.tv_sec
;
1064 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
.d_auth
<<"' & '"<<ne
.d_name
<<"' for another "<<sttl
<<" seconds"<<endl
);
1065 res
= RCode::NXDomain
;
1066 giveNegative
= true;
1067 cachedState
= ne
.d_validationState
;
1069 else if (t_sstorage
.negcache
.get(qname
, qtype
, d_now
, ne
) &&
1070 !(wasForwardedOrAuth
&& ne
.d_auth
!= authname
)) { // Only the authname nameserver can neg cache entries
1072 /* If we are looking for a DS, discard NXD if auth == qname
1073 and ask for a specific denial instead */
1074 if (qtype
!= QType::DS
|| ne
.d_qtype
.getCode() || ne
.d_auth
!= qname
||
1075 t_sstorage
.negcache
.get(qname
, qtype
, d_now
, ne
, true))
1078 sttl
= ne
.d_ttd
- d_now
.tv_sec
;
1079 giveNegative
= true;
1080 cachedState
= ne
.d_validationState
;
1081 if(ne
.d_qtype
.getCode()) {
1082 LOG(prefix
<<qname
<<": "<<qtype
.getName()<<" is negatively cached via '"<<ne
.d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1083 res
= RCode::NoError
;
1086 LOG(prefix
<<qname
<<": Entire name '"<<qname
<<"', is negatively cached via '"<<ne
.d_auth
<<"' for another "<<sttl
<<" seconds"<<endl
);
1087 res
= RCode::NXDomain
;
1094 state
= cachedState
;
1096 if (d_DNSSECValidationRequested
&& state
== Indeterminate
) {
1097 LOG(prefix
<<qname
<<": got Indeterminate state for records retrieved from the negative cache, validating.."<<endl
);
1098 computeNegCacheValidationStatus(ne
, qname
, qtype
, res
, state
, depth
);
1101 // Transplant SOA to the returned packet
1102 addTTLModifiedRecords(ne
.authoritySOA
.records
, sttl
, ret
);
1104 addTTLModifiedRecords(ne
.authoritySOA
.signatures
, sttl
, ret
);
1105 addTTLModifiedRecords(ne
.DNSSECRecords
.records
, sttl
, ret
);
1106 addTTLModifiedRecords(ne
.DNSSECRecords
.signatures
, sttl
, ret
);
1109 LOG(prefix
<<qname
<<": updating validation state with negative cache content for "<<qname
<<" to "<<vStates
[state
]<<endl
);
1113 vector
<DNSRecord
> cset
;
1114 bool found
=false, expired
=false;
1115 vector
<std::shared_ptr
<RRSIGRecordContent
>> signatures
;
1116 vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1119 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) {
1121 LOG(prefix
<<sqname
<<": Found cache hit for "<<sqt
.getName()<<": ");
1123 if (d_DNSSECValidationRequested
&& wasCachedAuth
&& cachedState
== Indeterminate
&& d_requireAuthData
) {
1125 /* This means we couldn't figure out the state when this entry was cached,
1126 most likely because we hadn't computed the zone cuts yet. */
1127 /* make sure they are computed before validating */
1128 computeZoneCuts(sqname
, g_rootdnsname
, depth
);
1130 vState recordState
= getValidationStatus(qname
, false);
1131 if (recordState
== Secure
) {
1132 LOG(prefix
<<sqname
<<": got Indeterminate state from the cache, validating.."<<endl
);
1133 cachedState
= SyncRes::validateRecordsWithSigs(depth
, sqname
, sqt
, sqname
, cset
, signatures
);
1135 if (cachedState
!= Indeterminate
) {
1136 LOG(prefix
<<qname
<<": got Indeterminate state from the cache, validation result is "<<vStates
[cachedState
]<<endl
);
1137 t_RC
->updateValidationStatus(d_now
.tv_sec
, sqname
, sqt
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, d_requireAuthData
, cachedState
);
1142 for(auto j
=cset
.cbegin() ; j
!= cset
.cend() ; ++j
) {
1143 LOG(j
->d_content
->getZoneRepresentation());
1144 if(j
->d_ttl
>(unsigned int) d_now
.tv_sec
) {
1146 ttl
= (dr
.d_ttl
-=d_now
.tv_sec
);
1148 LOG("[ttl="<<dr
.d_ttl
<<"] ");
1157 for(const auto& signature
: signatures
) {
1159 dr
.d_type
=QType::RRSIG
;
1162 dr
.d_content
=signature
;
1163 dr
.d_place
= DNSResourceRecord::ANSWER
;
1164 dr
.d_class
=QClass::IN
;
1168 for(const auto& rec
: authorityRecs
) {
1175 if(found
&& !expired
) {
1178 d_wasOutOfBand
= wasAuth
;
1179 LOG(prefix
<<qname
<<": updating validation state with cache content for "<<qname
<<" to "<<vStates
[cachedState
]<<endl
);
1180 state
= cachedState
;
1184 LOG(prefix
<<qname
<<": cache had only stale entries"<<endl
);
1190 bool SyncRes::moreSpecificThan(const DNSName
& a
, const DNSName
&b
) const
1192 return (a
.isPartOf(b
) && a
.countLabels() > b
.countLabels());
1197 speedOrder(map
<DNSName
,double> &speeds
) : d_speeds(speeds
) {}
1198 bool operator()(const DNSName
&a
, const DNSName
&b
) const
1200 return d_speeds
[a
] < d_speeds
[b
];
1202 map
<DNSName
, double>& d_speeds
;
1205 inline vector
<DNSName
> SyncRes::shuffleInSpeedOrder(NsSet
&tnameservers
, const string
&prefix
)
1207 vector
<DNSName
> rnameservers
;
1208 rnameservers
.reserve(tnameservers
.size());
1209 for(const auto& tns
: tnameservers
) {
1210 rnameservers
.push_back(tns
.first
);
1211 if(tns
.first
.empty()) // this was an authoritative OOB zone, don't pollute the nsSpeeds with that
1212 return rnameservers
;
1214 map
<DNSName
, double> speeds
;
1216 for(const auto& val
: rnameservers
) {
1218 speed
=t_sstorage
.nsSpeeds
[val
].get(&d_now
);
1221 random_shuffle(rnameservers
.begin(),rnameservers
.end(), dns_random
);
1222 speedOrder
so(speeds
);
1223 stable_sort(rnameservers
.begin(),rnameservers
.end(), so
);
1226 LOG(prefix
<<"Nameservers: ");
1227 for(vector
<DNSName
>::const_iterator i
=rnameservers
.begin();i
!=rnameservers
.end();++i
) {
1228 if(i
!=rnameservers
.begin()) {
1230 if(!((i
-rnameservers
.begin())%3)) {
1231 LOG(endl
<<prefix
<<" ");
1234 LOG((i
->empty() ? string("<empty>") : i
->toString())<<"(" << (boost::format("%0.2f") % (speeds
[*i
]/1000.0)).str() <<"ms)");
1238 return rnameservers
;
1241 static bool magicAddrMatch(const QType
& query
, const QType
& answer
)
1243 if(query
.getCode() != QType::ADDR
)
1245 return answer
.getCode() == QType::A
|| answer
.getCode() == QType::AAAA
;
1248 static uint32_t getRRSIGTTL(const time_t now
, const std::shared_ptr
<RRSIGRecordContent
>& rrsig
)
1251 if (now
< rrsig
->d_sigexpire
) {
1252 res
= static_cast<uint32_t>(rrsig
->d_sigexpire
) - now
;
1257 static const set
<uint16_t> nsecTypes
= {QType::NSEC
, QType::NSEC3
};
1259 /* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
1261 * \param records The records to parse for the authority SOA and NSEC(3) records
1262 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
1264 static void harvestNXRecords(const vector
<DNSRecord
>& records
, NegCache::NegCacheEntry
& ne
, const time_t now
, uint32_t* lowestTTL
) {
1265 for(const auto& rec
: records
) {
1266 if(rec
.d_place
!= DNSResourceRecord::AUTHORITY
)
1267 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
1268 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
1269 // records MUST be in the same section as the records they cover.
1270 // Hence, we ignore all records outside of the AUTHORITY section.
1273 if(rec
.d_type
== QType::RRSIG
) {
1274 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1276 if(rrsig
->d_type
== QType::SOA
) {
1277 ne
.authoritySOA
.signatures
.push_back(rec
);
1278 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1279 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1280 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1283 if(nsecTypes
.count(rrsig
->d_type
)) {
1284 ne
.DNSSECRecords
.signatures
.push_back(rec
);
1285 if (lowestTTL
&& isRRSIGNotExpired(now
, rrsig
)) {
1286 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1287 *lowestTTL
= min(*lowestTTL
, getRRSIGTTL(now
, rrsig
));
1293 if(rec
.d_type
== QType::SOA
) {
1294 ne
.authoritySOA
.records
.push_back(rec
);
1296 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1300 if(nsecTypes
.count(rec
.d_type
)) {
1301 ne
.DNSSECRecords
.records
.push_back(rec
);
1303 *lowestTTL
= min(*lowestTTL
, rec
.d_ttl
);
1310 static cspmap_t
harvestCSPFromNE(const NegCache::NegCacheEntry
& ne
)
1313 for(const auto& rec
: ne
.DNSSECRecords
.signatures
) {
1314 if(rec
.d_type
== QType::RRSIG
) {
1315 auto rrc
= getRR
<RRSIGRecordContent
>(rec
);
1317 cspmap
[{rec
.d_name
,rrc
->d_type
}].signatures
.push_back(rrc
);
1321 for(const auto& rec
: ne
.DNSSECRecords
.records
) {
1322 cspmap
[{rec
.d_name
, rec
.d_type
}].records
.push_back(rec
.d_content
);
1327 // TODO remove after processRecords is fixed!
1328 // Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
1329 static void addNXNSECS(vector
<DNSRecord
>&ret
, const vector
<DNSRecord
>& records
)
1331 NegCache::NegCacheEntry ne
;
1332 harvestNXRecords(records
, ne
, 0, nullptr);
1333 ret
.insert(ret
.end(), ne
.authoritySOA
.signatures
.begin(), ne
.authoritySOA
.signatures
.end());
1334 ret
.insert(ret
.end(), ne
.DNSSECRecords
.records
.begin(), ne
.DNSSECRecords
.records
.end());
1335 ret
.insert(ret
.end(), ne
.DNSSECRecords
.signatures
.begin(), ne
.DNSSECRecords
.signatures
.end());
1338 bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine
& dfe
, const NsSet
& nameservers
)
1341 for (auto const &ns
: nameservers
) {
1342 d_appliedPolicy
= dfe
.getProcessingPolicy(ns
.first
, d_discardedPolicies
);
1343 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1344 LOG(", however nameserver "<<ns
.first
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1348 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1349 for (auto const &address
: ns
.second
.first
) {
1350 d_appliedPolicy
= dfe
.getProcessingPolicy(address
, d_discardedPolicies
);
1351 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
1352 LOG(", however nameserver "<<ns
.first
<<" IP address "<<address
.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
1361 bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine
& dfe
, const ComboAddress
& remoteIP
)
1364 d_appliedPolicy
= dfe
.getProcessingPolicy(remoteIP
, d_discardedPolicies
);
1365 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) {
1366 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")+"')");
1373 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
)
1375 vector
<ComboAddress
> result
;
1378 LOG(prefix
<<qname
<<": Trying to resolve NS '"<<*tns
<< "' ("<<1+tns
-rnameservers
.begin()<<"/"<<(unsigned int)rnameservers
.size()<<")"<<endl
);
1379 result
= getAddrs(*tns
, depth
+2, beenthere
);
1380 pierceDontQuery
=false;
1383 LOG(prefix
<<qname
<<": Domain has hardcoded nameserver");
1385 result
= nameservers
[*tns
].first
;
1386 if(result
.size() > 1) {
1391 sendRDQuery
= nameservers
[*tns
].second
;
1392 pierceDontQuery
=true;
1397 bool SyncRes::throttledOrBlocked(const std::string
& prefix
, const ComboAddress
& remoteIP
, const DNSName
& qname
, const QType
& qtype
, bool pierceDontQuery
)
1399 if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0))) {
1400 LOG(prefix
<<qname
<<": server throttled "<<endl
);
1401 s_throttledqueries
++; d_throttledqueries
++;
1404 else if(t_sstorage
.throttle
.shouldThrottle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()))) {
1405 LOG(prefix
<<qname
<<": query throttled "<<remoteIP
.toString()<<", "<<qname
<<"; "<<qtype
.getName()<<endl
);
1406 s_throttledqueries
++; d_throttledqueries
++;
1409 else if(!pierceDontQuery
&& s_dontQuery
&& s_dontQuery
->match(&remoteIP
)) {
1410 LOG(prefix
<<qname
<<": not sending query to " << remoteIP
.toString() << ", blocked by 'dont-query' setting" << endl
);
1417 bool SyncRes::validationEnabled() const
1419 return g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
;
1422 uint32_t SyncRes::computeLowestTTD(const std::vector
<DNSRecord
>& records
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, uint32_t signaturesTTL
) const
1424 uint32_t lowestTTD
= std::numeric_limits
<uint32_t>::max();
1425 for(const auto& record
: records
)
1426 lowestTTD
= min(lowestTTD
, record
.d_ttl
);
1428 /* even if it was not requested for that request (Process, and neither AD nor DO set),
1429 it might be requested at a later time so we need to be careful with the TTL. */
1430 if (validationEnabled() && !signatures
.empty()) {
1431 /* if we are validating, we don't want to cache records after their signatures expire. */
1432 /* records TTL are now TTD, let's add 'now' to the signatures lowest TTL */
1433 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(signaturesTTL
+ d_now
.tv_sec
));
1435 for(const auto& sig
: signatures
) {
1436 if (isRRSIGNotExpired(d_now
.tv_sec
, sig
)) {
1437 // we don't decerement d_sigexpire by 'now' because we actually want a TTD, not a TTL */
1438 lowestTTD
= min(lowestTTD
, static_cast<uint32_t>(sig
->d_sigexpire
));
1446 void SyncRes::updateValidationState(vState
& state
, const vState stateUpdate
)
1448 LOG(d_prefix
<<"validation state was "<<std::string(vStates
[state
])<<", state update is "<<std::string(vStates
[stateUpdate
]));
1450 if (stateUpdate
== TA
) {
1453 else if (stateUpdate
== NTA
) {
1456 else if (stateUpdate
== Bogus
) {
1459 else if (state
== Indeterminate
) {
1460 state
= stateUpdate
;
1462 else if (stateUpdate
== Insecure
) {
1463 if (state
!= Bogus
) {
1467 LOG(", validation state is now "<<std::string(vStates
[state
])<<endl
);
1470 vState
SyncRes::getTA(const DNSName
& zone
, dsmap_t
& ds
)
1472 auto luaLocal
= g_luaconfs
.getLocal();
1474 if (luaLocal
->dsAnchors
.empty()) {
1475 LOG(d_prefix
<<": No trust anchors configured, everything is Insecure"<<endl
);
1476 /* We have no TA, everything is insecure */
1481 if (haveNegativeTrustAnchor(luaLocal
->negAnchors
, zone
, reason
)) {
1482 LOG(d_prefix
<<": got NTA for '"<<zone
<<"'"<<endl
);
1486 if (getTrustAnchor(luaLocal
->dsAnchors
, zone
, ds
)) {
1487 LOG(d_prefix
<<": got TA for '"<<zone
<<"'"<<endl
);
1491 LOG(d_prefix
<<": no TA found for '"<<zone
<<"' among "<< luaLocal
->dsAnchors
.size()<<endl
);
1494 if (zone
.isRoot()) {
1495 /* No TA for the root */
1499 return Indeterminate
;
1502 static size_t countSupportedDS(const dsmap_t
& dsmap
)
1506 for (const auto& ds
: dsmap
) {
1507 if (isSupportedDS(ds
)) {
1515 vState
SyncRes::getDSRecords(const DNSName
& zone
, dsmap_t
& ds
, bool taOnly
, unsigned int depth
, bool bogusOnNXD
, bool* foundCut
)
1517 vState result
= getTA(zone
, ds
);
1519 if (result
!= Indeterminate
|| taOnly
) {
1521 *foundCut
= (result
!= Indeterminate
);
1525 if (countSupportedDS(ds
) == 0) {
1533 else if (result
== NTA
) {
1540 bool oldSkipCNAME
= d_skipCNAMECheck
;
1541 d_skipCNAMECheck
= true;
1543 std::set
<GetBestNSAnswer
> beenthere
;
1544 std::vector
<DNSRecord
> dsrecords
;
1546 vState state
= Indeterminate
;
1547 int rcode
= doResolve(zone
, QType(QType::DS
), dsrecords
, depth
+ 1, beenthere
, state
);
1548 d_skipCNAMECheck
= oldSkipCNAME
;
1550 if (rcode
== RCode::NoError
|| (rcode
== RCode::NXDomain
&& !bogusOnNXD
)) {
1552 uint8_t bestDigestType
= 0;
1554 if (state
== Secure
) {
1555 bool gotCNAME
= false;
1556 for (const auto& record
: dsrecords
) {
1557 if (record
.d_type
== QType::DS
) {
1558 const auto dscontent
= getRR
<DSRecordContent
>(record
);
1559 if (dscontent
&& isSupportedDS(*dscontent
)) {
1560 // Make GOST a lower prio than SHA256
1561 if (dscontent
->d_digesttype
== DNSSECKeeper::GOST
&& bestDigestType
== DNSSECKeeper::SHA256
) {
1564 if (dscontent
->d_digesttype
> bestDigestType
|| (bestDigestType
== DNSSECKeeper::GOST
&& dscontent
->d_digesttype
== DNSSECKeeper::SHA256
)) {
1565 bestDigestType
= dscontent
->d_digesttype
;
1567 ds
.insert(*dscontent
);
1570 else if (record
.d_type
== QType::CNAME
&& record
.d_name
== zone
) {
1575 /* RFC 4509 section 3: "Validator implementations SHOULD ignore DS RRs containing SHA-1
1576 * digests if DS RRs with SHA-256 digests are present in the DS RRset."
1577 * As SHA348 is specified as well, the spirit of the this line is "use the best algorithm".
1579 for (const auto& dsrec
: ds
) {
1580 if (dsrec
.d_digesttype
!= bestDigestType
) {
1585 if (rcode
== RCode::NoError
&& ds
.empty()) {
1587 if (gotCNAME
|| denialProvesNoDelegation(zone
, dsrecords
)) {
1588 /* we are still inside the same Secure zone */
1598 } else if (foundCut
&& rcode
== RCode::NoError
&& !ds
.empty()) {
1606 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
1610 bool SyncRes::haveExactValidationStatus(const DNSName
& domain
)
1612 if (!d_DNSSECValidationRequested
) {
1615 const auto& it
= d_cutStates
.find(domain
);
1616 if (it
!= d_cutStates
.cend()) {
1622 vState
SyncRes::getValidationStatus(const DNSName
& subdomain
, bool allowIndeterminate
)
1624 vState result
= Indeterminate
;
1626 if (!d_DNSSECValidationRequested
) {
1629 DNSName
name(subdomain
);
1631 const auto& it
= d_cutStates
.find(name
);
1632 if (it
!= d_cutStates
.cend()) {
1633 if (allowIndeterminate
|| it
->second
!= Indeterminate
) {
1634 LOG(d_prefix
<<": got status "<<vStates
[it
->second
]<<" for name "<<subdomain
<<" (from "<<name
<<")"<<endl
);
1639 while (name
.chopOff());
1644 bool SyncRes::lookForCut(const DNSName
& qname
, unsigned int depth
, const vState existingState
, vState
& newState
)
1646 bool foundCut
= false;
1648 vState dsState
= getDSRecords(qname
, ds
, newState
== Bogus
|| existingState
== Insecure
|| existingState
== Bogus
, depth
, false, &foundCut
);
1650 if (dsState
!= Indeterminate
) {
1657 void SyncRes::computeZoneCuts(const DNSName
& begin
, const DNSName
& end
, unsigned int depth
)
1659 if(!begin
.isPartOf(end
)) {
1660 LOG(d_prefix
<<" "<<begin
.toLogString()<<" is not part of "<<end
.toString()<<endl
);
1661 throw PDNSException(begin
.toLogString() + " is not part of " + end
.toString());
1664 if (d_cutStates
.count(begin
) != 0) {
1669 vState cutState
= getDSRecords(end
, ds
, false, depth
);
1670 LOG(d_prefix
<<": setting cut state for "<<end
<<" to "<<vStates
[cutState
]<<endl
);
1671 d_cutStates
[end
] = cutState
;
1673 if (!d_DNSSECValidationRequested
) {
1678 std::vector
<string
> labelsToAdd
= begin
.makeRelative(end
).getRawLabels();
1680 bool oldSkipCNAME
= d_skipCNAMECheck
;
1681 d_skipCNAMECheck
= true;
1683 while(qname
!= begin
) {
1684 if (labelsToAdd
.empty())
1687 qname
.prependRawLabel(labelsToAdd
.back());
1688 labelsToAdd
.pop_back();
1689 LOG(d_prefix
<<": - Looking for a cut at "<<qname
<<endl
);
1691 const auto cutIt
= d_cutStates
.find(qname
);
1692 if (cutIt
!= d_cutStates
.cend()) {
1693 if (cutIt
->second
!= Indeterminate
) {
1694 LOG(d_prefix
<<": - Cut already known at "<<qname
<<endl
);
1695 cutState
= cutIt
->second
;
1700 /* no need to look for NS and DS if we are already insecure or bogus,
1703 if (cutState
== Insecure
|| cutState
== Bogus
) {
1705 vState newState
= getDSRecords(qname
, cutDS
, true, depth
);
1706 if (newState
== Indeterminate
) {
1710 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[newState
]<<endl
);
1711 cutState
= newState
;
1713 d_cutStates
[qname
] = cutState
;
1718 vState newState
= Indeterminate
;
1719 /* temporarily mark as Indeterminate, so that we won't enter an endless loop
1720 trying to determine that zone cut again. */
1721 d_cutStates
[qname
] = newState
;
1722 bool foundCut
= lookForCut(qname
, depth
+ 1, cutState
, newState
);
1724 LOG(d_prefix
<<": - Found cut at "<<qname
<<endl
);
1725 if (newState
!= Indeterminate
) {
1726 cutState
= newState
;
1728 LOG(d_prefix
<<": New state for "<<qname
<<" is "<<vStates
[cutState
]<<endl
);
1729 d_cutStates
[qname
] = cutState
;
1732 /* remove the temporary cut */
1733 LOG(d_prefix
<<qname
<<": removing cut state for "<<qname
<<", was "<<vStates
[d_cutStates
[qname
]]<<endl
);
1734 d_cutStates
.erase(qname
);
1738 d_skipCNAMECheck
= oldSkipCNAME
;
1740 LOG(d_prefix
<<": list of cuts from "<<begin
<<" to "<<end
<<endl
);
1741 for (const auto& cut
: d_cutStates
) {
1742 if (cut
.first
.isRoot() || (begin
.isPartOf(cut
.first
) && cut
.first
.isPartOf(end
))) {
1743 LOG(" - "<<cut
.first
<<": "<<vStates
[cut
.second
]<<endl
);
1748 vState
SyncRes::validateDNSKeys(const DNSName
& zone
, const std::vector
<DNSRecord
>& dnskeys
, const std::vector
<std::shared_ptr
<RRSIGRecordContent
> >& signatures
, unsigned int depth
)
1751 if (!signatures
.empty()) {
1752 DNSName signer
= getSigner(signatures
);
1754 if (!signer
.empty() && signer
.isPartOf(zone
)) {
1755 vState state
= getDSRecords(signer
, ds
, false, depth
);
1757 if (state
!= Secure
) {
1763 skeyset_t tentativeKeys
;
1764 std::vector
<shared_ptr
<DNSRecordContent
> > toSign
;
1766 for (const auto& dnskey
: dnskeys
) {
1767 if (dnskey
.d_type
== QType::DNSKEY
) {
1768 auto content
= getRR
<DNSKEYRecordContent
>(dnskey
);
1770 tentativeKeys
.insert(content
);
1771 toSign
.push_back(content
);
1776 LOG(d_prefix
<<": trying to validate "<<std::to_string(tentativeKeys
.size())<<" DNSKEYs with "<<std::to_string(ds
.size())<<" DS"<<endl
);
1777 skeyset_t validatedKeys
;
1778 validateDNSKeysAgainstDS(d_now
.tv_sec
, zone
, ds
, tentativeKeys
, toSign
, signatures
, validatedKeys
);
1780 LOG(d_prefix
<<": we now have "<<std::to_string(validatedKeys
.size())<<" DNSKEYs"<<endl
);
1782 /* if we found at least one valid RRSIG covering the set,
1783 all tentative keys are validated keys. Otherwise it means
1784 we haven't found at least one DNSKEY and a matching RRSIG
1785 covering this set, this looks Bogus. */
1786 if (validatedKeys
.size() != tentativeKeys
.size()) {
1787 LOG(d_prefix
<<": returning Bogus state from "<<__func__
<<"("<<zone
<<")"<<endl
);
1794 vState
SyncRes::getDNSKeys(const DNSName
& signer
, skeyset_t
& keys
, unsigned int depth
)
1796 std::vector
<DNSRecord
> records
;
1797 std::set
<GetBestNSAnswer
> beenthere
;
1798 LOG(d_prefix
<<"Retrieving DNSKeys for "<<signer
<<endl
);
1800 vState state
= Indeterminate
;
1801 /* following CNAME might lead to us to the wrong DNSKEY */
1802 bool oldSkipCNAME
= d_skipCNAMECheck
;
1803 d_skipCNAMECheck
= true;
1804 int rcode
= doResolve(signer
, QType(QType::DNSKEY
), records
, depth
+ 1, beenthere
, state
);
1805 d_skipCNAMECheck
= oldSkipCNAME
;
1807 if (rcode
== RCode::NoError
) {
1808 if (state
== Secure
) {
1809 for (const auto& key
: records
) {
1810 if (key
.d_type
== QType::DNSKEY
) {
1811 auto content
= getRR
<DNSKEYRecordContent
>(key
);
1813 keys
.insert(content
);
1818 LOG(d_prefix
<<"Retrieved "<<keys
.size()<<" DNSKeys for "<<signer
<<", state is "<<vStates
[state
]<<endl
);
1822 LOG(d_prefix
<<"Returning Bogus state from "<<__func__
<<"("<<signer
<<")"<<endl
);
1826 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
)
1829 if (!signatures
.empty()) {
1830 const DNSName signer
= getSigner(signatures
);
1831 if (!signer
.empty() && name
.isPartOf(signer
)) {
1832 if ((qtype
== QType::DNSKEY
|| qtype
== QType::DS
) && signer
== qname
) {
1833 /* we are already retrieving those keys, sorry */
1834 return Indeterminate
;
1836 vState state
= getDNSKeys(signer
, keys
, depth
);
1837 if (state
!= Secure
) {
1842 LOG(d_prefix
<<"Bogus!"<<endl
);
1846 std::vector
<std::shared_ptr
<DNSRecordContent
> > recordcontents
;
1847 for (const auto& record
: records
) {
1848 recordcontents
.push_back(record
.d_content
);
1851 LOG(d_prefix
<<"Going to validate "<<recordcontents
.size()<< " record contents with "<<signatures
.size()<<" sigs and "<<keys
.size()<<" keys for "<<name
<<endl
);
1852 if (validateWithKeySet(d_now
.tv_sec
, name
, recordcontents
, signatures
, keys
, false)) {
1853 LOG(d_prefix
<<"Secure!"<<endl
);
1857 LOG(d_prefix
<<"Bogus!"<<endl
);
1861 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
)
1868 prefix
.append(depth
, ' ');
1871 std::vector
<std::shared_ptr
<DNSRecord
>> authorityRecs
;
1872 const unsigned int labelCount
= qname
.countLabels();
1873 bool isCNAMEAnswer
= false;
1874 for(const auto& rec
: lwr
.d_records
) {
1875 if(!isCNAMEAnswer
&& rec
.d_place
== DNSResourceRecord::ANSWER
&& rec
.d_type
== QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
) {
1876 isCNAMEAnswer
= true;
1879 /* if we have a positive answer synthetized from a wildcard,
1880 we need to store the corresponding NSEC/NSEC3 records proving
1881 that the exact name did not exist in the negative cache */
1882 if(needWildcardProof
) {
1883 if (nsecTypes
.count(rec
.d_type
)) {
1884 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
1886 else if (rec
.d_type
== QType::RRSIG
) {
1887 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1888 if (rrsig
&& nsecTypes
.count(rrsig
->d_type
)) {
1889 authorityRecs
.push_back(std::make_shared
<DNSRecord
>(rec
));
1893 if(rec
.d_type
== QType::RRSIG
) {
1894 auto rrsig
= getRR
<RRSIGRecordContent
>(rec
);
1896 /* As illustrated in rfc4035's Appendix B.6, the RRSIG label
1897 count can be lower than the name's label count if it was
1898 synthetized from the wildcard. Note that the difference might
1900 if (rec
.d_name
== qname
&& rrsig
->d_labels
< labelCount
) {
1901 LOG(prefix
<<qname
<<": RRSIG indicates the name was synthetized from a wildcard, we need a wildcard proof"<<endl
);
1902 needWildcardProof
= true;
1905 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
1906 tcache
[{rec
.d_name
, rrsig
->d_type
, rec
.d_place
}].signatures
.push_back(rrsig
);
1907 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
);
1912 // reap all answers from this packet that are acceptable
1913 for(auto& rec
: lwr
.d_records
) {
1914 if(rec
.d_type
== QType::OPT
) {
1915 LOG(prefix
<<qname
<<": OPT answer '"<<rec
.d_name
<<"' from '"<<auth
<<"' nameservers" <<endl
);
1918 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
<<" ");
1919 if(rec
.d_type
== QType::ANY
) {
1920 LOG("NO! - we don't accept 'ANY' data"<<endl
);
1924 if(rec
.d_name
.isPartOf(auth
)) {
1925 if(rec
.d_type
== QType::RRSIG
) {
1926 LOG("RRSIG - separate"<<endl
);
1928 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
)) {
1929 LOG("NO! Is from delegation-only zone"<<endl
);
1931 return RCode::NXDomain
;
1934 bool haveLogged
= false;
1935 if (!t_sstorage
.domainmap
->empty()) {
1936 // Check if we are authoritative for a zone in this answer
1937 DNSName
tmp_qname(rec
.d_name
);
1938 auto auth_domain_iter
=getBestAuthZone(&tmp_qname
);
1939 if(auth_domain_iter
!=t_sstorage
.domainmap
->end() &&
1940 auth
.countLabels() <= auth_domain_iter
->first
.countLabels()) {
1941 if (auth_domain_iter
->first
!= auth
) {
1942 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter
->first
<<endl
);
1945 LOG("YES! - This answer was ");
1946 if (!wasForwarded
) {
1947 LOG("retrieved from the local auth store.");
1949 LOG("received from a server we forward to.");
1960 rec
.d_ttl
=min(s_maxcachettl
, rec
.d_ttl
);
1963 dr
.d_ttl
+= d_now
.tv_sec
;
1964 dr
.d_place
=DNSResourceRecord::ANSWER
;
1965 tcache
[{rec
.d_name
,rec
.d_type
,rec
.d_place
}].records
.push_back(dr
);
1973 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
1974 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)
1975 uint32_t lowestTTD
=computeLowestTTD(i
->second
.records
, i
->second
.signatures
, i
->second
.signaturesTTL
);
1977 for(auto& record
: i
->second
.records
)
1978 record
.d_ttl
= lowestTTD
; // boom
1981 // cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
1982 // cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
1985 for(tcache_t::iterator i
= tcache
.begin(); i
!= tcache
.end(); ++i
) {
1987 if(i
->second
.records
.empty()) // this happens when we did store signatures, but passed on the records themselves
1990 bool isAA
= lwr
.d_aabit
;
1991 if (isAA
&& isCNAMEAnswer
&& (i
->first
.place
!= DNSResourceRecord::ANSWER
|| i
->first
.type
!= QType::CNAME
)) {
1994 Note that the answer section of an authoritative answer normally
1995 contains only authoritative data. However when the name sought is an
1996 alias (see section 10.1.1) only the record describing that alias is
1997 necessarily authoritative. Clients should assume that other records
1998 may have come from the server's cache. Where authoritative answers
1999 are required, the client should query again, using the canonical name
2000 associated with the alias.
2005 vState recordState
= getValidationStatus(i
->first
.name
, false);
2006 LOG(d_prefix
<<": got initial zone status "<<vStates
[recordState
]<<" for record "<<i
->first
.name
<<endl
);
2008 if (d_DNSSECValidationRequested
&& recordState
== Secure
) {
2009 vState initialState
= recordState
;
2012 if (i
->first
.place
!= DNSResourceRecord::ADDITIONAL
) {
2013 /* the additional entries can be insecure,
2015 "Glue address RRsets associated with delegations MUST NOT be signed"
2017 if (i
->first
.type
== QType::DNSKEY
&& i
->first
.place
== DNSResourceRecord::ANSWER
) {
2018 LOG(d_prefix
<<"Validating DNSKEY for "<<i
->first
.name
<<endl
);
2019 recordState
= validateDNSKeys(i
->first
.name
, i
->second
.records
, i
->second
.signatures
, depth
);
2022 LOG(d_prefix
<<"Validating non-additional record for "<<i
->first
.name
<<endl
);
2023 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2024 /* 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 */
2025 if (qtype
== QType::NS
&& i
->second
.signatures
.empty() && recordState
== Bogus
&& haveExactValidationStatus(i
->first
.name
) && getValidationStatus(i
->first
.name
) == Indeterminate
) {
2026 recordState
= Indeterminate
;
2032 /* in a non authoritative answer, we only care about the DS record (or lack of) */
2033 if ((i
->first
.type
== QType::DS
|| i
->first
.type
== QType::NSEC
|| i
->first
.type
== QType::NSEC3
) && i
->first
.place
== DNSResourceRecord::AUTHORITY
) {
2034 LOG(d_prefix
<<"Validating DS record for "<<i
->first
.name
<<endl
);
2035 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2039 if (initialState
== Secure
&& state
!= recordState
) {
2040 updateValidationState(state
, recordState
);
2044 if (d_DNSSECValidationRequested
) {
2045 LOG(d_prefix
<<"Skipping validation because the current state is "<<vStates
[recordState
]<<endl
);
2049 /* We don't need to store NSEC3 records in the positive cache because:
2050 - we don't allow direct NSEC3 queries
2051 - denial of existence proofs in wildcard expanded positive responses are stored in authorityRecs
2052 - denial of existence proofs for negative responses are stored in the negative cache
2054 if (i
->first
.type
!= QType::NSEC3
) {
2055 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
);
2058 if(i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
)
2062 return RCode::NoError
;
2065 void SyncRes::updateDenialValidationState(NegCache::NegCacheEntry
& ne
, vState
& state
, const dState denialState
, const dState expectedState
, bool allowOptOut
)
2067 if (denialState
!= expectedState
) {
2068 if (denialState
== OPTOUT
&& allowOptOut
) {
2069 LOG(d_prefix
<<"OPT-out denial found for "<<ne
.d_name
<<endl
);
2070 ne
.d_validationState
= Secure
;
2073 else if (denialState
== INSECURE
) {
2074 LOG(d_prefix
<<"Insecure denial found for "<<ne
.d_name
<<", returning Insecure"<<endl
);
2075 ne
.d_validationState
= Insecure
;
2078 LOG(d_prefix
<<"Invalid denial found for "<<ne
.d_name
<<", returning Bogus, res="<<denialState
<<", expectedState="<<expectedState
<<endl
);
2079 ne
.d_validationState
= Bogus
;
2081 updateValidationState(state
, ne
.d_validationState
);
2085 dState
SyncRes::getDenialValidationState(NegCache::NegCacheEntry
& ne
, const vState state
, const dState expectedState
, bool referralToUnsigned
)
2087 cspmap_t csp
= harvestCSPFromNE(ne
);
2088 return getDenial(csp
, ne
.d_name
, ne
.d_qtype
.getCode(), referralToUnsigned
, expectedState
== NXQTYPE
);
2091 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
)
2095 for(auto& rec
: lwr
.d_records
) {
2096 if (rec
.d_type
!=QType::OPT
&& rec
.d_class
!=QClass::IN
)
2099 if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2100 lwr
.d_rcode
==RCode::NXDomain
&& qname
.isPartOf(rec
.d_name
) && rec
.d_name
.isPartOf(auth
)) {
2101 LOG(prefix
<<qname
<<": got negative caching indication for name '"<<qname
<<"' (accept="<<rec
.d_name
.isPartOf(auth
)<<"), newtarget='"<<newtarget
<<"'"<<endl
);
2103 rec
.d_ttl
= min(rec
.d_ttl
, s_maxnegttl
);
2104 if(newtarget
.empty()) // only add a SOA if we're not going anywhere after this
2107 NegCache::NegCacheEntry ne
;
2109 uint32_t lowestTTL
= rec
.d_ttl
;
2110 /* if we get an NXDomain answer with a CNAME, the name
2111 does exist but the target does not */
2112 ne
.d_name
= newtarget
.empty() ? qname
: newtarget
;
2113 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2114 ne
.d_auth
= rec
.d_name
;
2115 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2116 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2118 if (state
== Secure
) {
2119 dState denialState
= getDenialValidationState(ne
, state
, NXDOMAIN
, false);
2120 updateDenialValidationState(ne
, state
, denialState
, NXDOMAIN
, false);
2123 ne
.d_validationState
= state
;
2126 /* if we get an NXDomain answer with a CNAME, let's not cache the
2127 target, even the server was authoritative for it,
2128 and do an additional query for the CNAME target.
2129 We have a regression test making sure we do exactly that.
2131 if(!wasVariable() && newtarget
.empty()) {
2132 t_sstorage
.negcache
.add(ne
);
2133 if(s_rootNXTrust
&& ne
.d_auth
.isRoot() && auth
.isRoot()) {
2134 ne
.d_name
= ne
.d_name
.getLastLabel();
2135 t_sstorage
.negcache
.add(ne
);
2141 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_type
==QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
) {
2143 if (auto content
= getRR
<CNAMERecordContent
>(rec
)) {
2144 newtarget
=content
->getTarget();
2147 /* if we have a positive answer synthetized from a wildcard, we need to
2148 return the corresponding NSEC/NSEC3 records from the AUTHORITY section
2149 proving that the exact name did not exist */
2150 else if(needWildcardProof
&& (rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::AUTHORITY
) {
2151 ret
.push_back(rec
); // enjoy your DNSSEC
2153 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
2154 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&&
2156 rec
.d_type
==qtype
.getCode() || (lwr
.d_aabit
&& (qtype
==QType(QType::ANY
) || magicAddrMatch(qtype
, QType(rec
.d_type
)) ) ) || sendRDQuery
2160 LOG(prefix
<<qname
<<": answer is in: resolved to '"<< rec
.d_content
->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"'"<<endl
);
2165 if (state
== Secure
&& needWildcardProof
) {
2166 /* We have a positive answer synthetized from a wildcard, we need to check that we have
2167 proof that the exact name doesn't exist so the wildcard can be used,
2168 as described in section 5.3.4 of RFC 4035 and 5.3 of FRC 7129.
2170 NegCache::NegCacheEntry ne
;
2172 uint32_t lowestTTL
= rec
.d_ttl
;
2174 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2175 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2177 cspmap_t csp
= harvestCSPFromNE(ne
);
2178 dState res
= getDenial(csp
, qname
, ne
.d_qtype
.getCode(), false, false, false);
2179 if (res
!= NXDOMAIN
) {
2180 LOG(d_prefix
<<"Invalid denial in wildcard expanded positive response found for "<<qname
<<", returning Bogus, res="<<res
<<endl
);
2181 updateValidationState(state
, Bogus
);
2182 /* we already store the record with a different validation status, let's fix it */
2183 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qtype
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, lwr
.d_aabit
, Bogus
);
2187 else if((rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::ANSWER
) {
2188 if(rec
.d_type
!= QType::RRSIG
|| rec
.d_name
== qname
)
2189 ret
.push_back(rec
); // enjoy your DNSSEC
2191 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::NS
&& qname
.isPartOf(rec
.d_name
)) {
2192 if(moreSpecificThan(rec
.d_name
,auth
)) {
2194 LOG(prefix
<<qname
<<": got NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2198 LOG(prefix
<<qname
<<": got upwards/level NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"', had '"<<auth
<<"'"<<endl
);
2200 if (auto content
= getRR
<NSRecordContent
>(rec
)) {
2201 nsset
.insert(content
->getNS());
2204 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::DS
&& qname
.isPartOf(rec
.d_name
)) {
2205 LOG(prefix
<<qname
<<": got DS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2207 else if(realreferral
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& (rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && newauth
.isPartOf(auth
)) {
2208 /* we might have received a denial of the DS, let's check */
2209 if (state
== Secure
) {
2210 NegCache::NegCacheEntry ne
;
2212 ne
.d_name
= newauth
;
2213 ne
.d_qtype
= QType::DS
;
2214 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2215 uint32_t lowestTTL
= rec
.d_ttl
;
2216 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2218 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, true);
2220 if (denialState
== NXQTYPE
|| denialState
== OPTOUT
|| denialState
== INSECURE
) {
2221 ne
.d_ttd
= lowestTTL
+ d_now
.tv_sec
;
2222 ne
.d_validationState
= Secure
;
2223 LOG(prefix
<<qname
<<": got negative indication of DS record for '"<<newauth
<<"'"<<endl
);
2225 if(!wasVariable()) {
2226 t_sstorage
.negcache
.add(ne
);
2229 if (qname
== newauth
&& qtype
== QType::DS
) {
2230 /* we are actually done! */
2237 else if(!done
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2238 lwr
.d_rcode
==RCode::NoError
&& qname
.isPartOf(rec
.d_name
)) {
2239 LOG(prefix
<<qname
<<": got negative caching indication for '"<< qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
2241 if(!newtarget
.empty()) {
2242 LOG(prefix
<<qname
<<": Hang on! Got a redirect to '"<<newtarget
<<"' already"<<endl
);
2245 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2248 NegCache::NegCacheEntry ne
;
2249 ne
.d_auth
= rec
.d_name
;
2250 uint32_t lowestTTL
= rec
.d_ttl
;
2253 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2254 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2256 if (state
== Secure
) {
2257 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, false);
2258 updateDenialValidationState(ne
, state
, denialState
, NXQTYPE
, qtype
== QType::DS
);
2260 ne
.d_validationState
= state
;
2263 if(!wasVariable()) {
2264 if(qtype
.getCode()) { // prevents us from blacking out a whole domain
2265 t_sstorage
.negcache
.add(ne
);
2276 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
)
2282 if(d_outqueries
+ d_throttledqueries
> s_maxqperq
) {
2283 throw ImmediateServFailException("more than "+std::to_string(s_maxqperq
)+" (max-qperq) queries sent while resolving "+qname
.toLogString());
2286 if(s_maxtotusec
&& d_totUsec
> s_maxtotusec
) {
2287 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");
2291 LOG(prefix
<<qname
<<": using TCP with "<< remoteIP
.toStringWithPort() <<endl
);
2296 if(d_pdl
&& d_pdl
->preoutquery(remoteIP
, d_requestor
, qname
, qtype
, doTCP
, lwr
.d_records
, resolveret
)) {
2297 LOG(prefix
<<qname
<<": query handled by Lua"<<endl
);
2300 ednsmask
=getEDNSSubnetMask(d_requestor
, qname
, remoteIP
);
2302 LOG(prefix
<<qname
<<": Adding EDNS Client Subnet Mask "<<ednsmask
->toString()<<" to query"<<endl
);
2305 resolveret
= asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(),
2306 doTCP
, sendRDQuery
, &d_now
, ednsmask
, &lwr
); // <- we go out on the wire!
2309 LOG(prefix
<<qname
<<": Received EDNS Client Subnet Mask "<<ednsmask
->toString()<<" on response"<<endl
);
2313 /* preoutquery killed the query by setting dq.rcode to -3 */
2314 if(resolveret
==-3) {
2315 throw ImmediateServFailException("Query killed by policy");
2318 d_totUsec
+= lwr
.d_usec
;
2319 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
2321 if(resolveret
!= 1) {
2322 /* Error while resolving */
2323 if(resolveret
== 0) {
2326 LOG(prefix
<<qname
<<": timeout resolving after "<<lwr
.d_usec
/1000.0<<"msec "<< (doTCP
? "over TCP" : "")<<endl
);
2328 s_outgoingtimeouts
++;
2330 if(remoteIP
.sin4
.sin_family
== AF_INET
)
2331 s_outgoing4timeouts
++;
2333 s_outgoing6timeouts
++;
2335 else if(resolveret
== -2) {
2336 /* OS resource limit reached */
2337 LOG(prefix
<<qname
<<": hit a local resource limit resolving"<< (doTCP
? " over TCP" : "")<<", probable error: "<<stringerror()<<endl
);
2338 g_stats
.resourceLimits
++;
2341 /* -1 means server unreachable */
2344 LOG(prefix
<<qname
<<": error resolving from "<<remoteIP
.toString()<< (doTCP
? " over TCP" : "") <<", possible error: "<<strerror(errno
)<< endl
);
2347 if(resolveret
!= -2) { // don't account for resource limits, they are our own fault
2348 t_sstorage
.nsSpeeds
[nsName
].submit(remoteIP
, 1000000, &d_now
); // 1 sec
2350 // code below makes sure we don't filter COM or the root
2351 if (s_serverdownmaxfails
> 0 && (auth
!= g_rootdnsname
) && t_sstorage
.fails
.incr(remoteIP
) >= s_serverdownmaxfails
) {
2352 LOG(prefix
<<qname
<<": Max fails reached resolving on "<< remoteIP
.toString() <<". Going full throttle for "<< s_serverdownthrottletime
<<" seconds" <<endl
);
2353 // mark server as down
2354 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0), s_serverdownthrottletime
, 10000);
2356 else if (resolveret
== -1) {
2357 // unreachable, 1 minute or 100 queries
2358 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 100);
2362 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 10, 5);
2369 /* we got an answer */
2370 if(lwr
.d_rcode
==RCode::ServFail
|| lwr
.d_rcode
==RCode::Refused
) {
2371 LOG(prefix
<<qname
<<": "<<nsName
<<" ("<<remoteIP
.toString()<<") returned a "<< (lwr
.d_rcode
==RCode::ServFail
? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl
);
2372 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
2376 /* this server sent a valid answer, mark it backup up if it was down */
2377 if(s_serverdownmaxfails
> 0) {
2378 t_sstorage
.fails
.clear(remoteIP
);
2385 LOG(prefix
<<qname
<<": truncated bit set, over TCP?"<<endl
);
2386 /* let's treat that as a ServFail answer from this server */
2387 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
2397 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
)
2402 prefix
.append(depth
, ' ');
2406 for(auto& rec
: lwr
.d_records
) {
2407 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumTTL
);
2411 bool needWildcardProof
= false;
2412 *rcode
= updateCacheFromRecords(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, state
, needWildcardProof
);
2413 if (*rcode
!= RCode::NoError
) {
2417 LOG(prefix
<<qname
<<": determining status after receiving this packet"<<endl
);
2420 bool realreferral
=false, negindic
=false;
2424 bool done
= processRecords(prefix
, qname
, qtype
, auth
, lwr
, sendRDQuery
, ret
, nsset
, newtarget
, newauth
, realreferral
, negindic
, state
, needWildcardProof
);
2427 LOG(prefix
<<qname
<<": status=got results, this level of recursion done"<<endl
);
2428 LOG(prefix
<<qname
<<": validation status is "<<vStates
[state
]<<endl
);
2429 *rcode
= RCode::NoError
;
2433 if(!newtarget
.empty()) {
2434 if(newtarget
== qname
) {
2435 LOG(prefix
<<qname
<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl
);
2436 *rcode
= RCode::ServFail
;
2441 LOG(prefix
<<qname
<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl
);
2442 *rcode
= RCode::ServFail
;
2446 if (qtype
== QType::DS
) {
2447 LOG(prefix
<<qname
<<": status=got a CNAME referral, but we are looking for a DS"<<endl
);
2450 addNXNSECS(ret
, lwr
.d_records
);
2452 *rcode
= RCode::NoError
;
2456 LOG(prefix
<<qname
<<": status=got a CNAME referral, starting over with "<<newtarget
<<endl
);
2458 set
<GetBestNSAnswer
> beenthere2
;
2459 vState cnameState
= Indeterminate
;
2460 *rcode
= doResolve(newtarget
, qtype
, ret
, depth
+ 1, beenthere2
, cnameState
);
2461 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
2462 updateValidationState(state
, cnameState
);
2467 if(lwr
.d_rcode
== RCode::NXDomain
) {
2468 LOG(prefix
<<qname
<<": status=NXDOMAIN, we are done "<<(negindic
? "(have negative SOA)" : "")<<endl
);
2471 addNXNSECS(ret
, lwr
.d_records
);
2473 *rcode
= RCode::NXDomain
;
2477 if(nsset
.empty() && !lwr
.d_rcode
&& (negindic
|| lwr
.d_aabit
|| sendRDQuery
)) {
2478 LOG(prefix
<<qname
<<": status=noerror, other types may exist, but we are done "<<(negindic
? "(have negative SOA) " : "")<<(lwr
.d_aabit
? "(have aa bit) " : "")<<endl
);
2480 if(state
== Secure
&& lwr
.d_aabit
&& !negindic
) {
2481 updateValidationState(state
, Bogus
);
2485 addNXNSECS(ret
, lwr
.d_records
);
2487 *rcode
= RCode::NoError
;
2492 LOG(prefix
<<qname
<<": status=did not resolve, got "<<(unsigned int)nsset
.size()<<" NS, ");
2494 nameservers
.clear();
2495 for (auto const &nameserver
: nsset
) {
2497 d_appliedPolicy
= dfe
.getProcessingPolicy(nameserver
, d_discardedPolicies
);
2498 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
2499 LOG("however "<<nameserver
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
2504 nameservers
.insert({nameserver
, {{}, false}});
2506 LOG("looping to them"<<endl
);
2507 *gotNewServers
= true;
2517 * -1 in case of no results
2518 * -2 when a FilterEngine Policy was hit
2521 int SyncRes::doResolveAt(NsSet
&nameservers
, DNSName auth
, bool flawedNSSet
, const DNSName
&qname
, const QType
&qtype
,
2522 vector
<DNSRecord
>&ret
,
2523 unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
, vState
& state
)
2525 auto luaconfsLocal
= g_luaconfs
.getLocal();
2529 prefix
.append(depth
, ' ');
2532 LOG(prefix
<<qname
<<": Cache consultations done, have "<<(unsigned int)nameservers
.size()<<" NS to contact");
2534 if (nameserversBlockedByRPZ(luaconfsLocal
->dfe
, nameservers
)) {
2540 for(;;) { // we may get more specific nameservers
2541 vector
<DNSName
> rnameservers
= shuffleInSpeedOrder(nameservers
, doLog() ? (prefix
+qname
.toString()+": ") : string() );
2543 for(auto tns
=rnameservers
.cbegin();;++tns
) {
2544 if(tns
==rnameservers
.cend()) {
2545 LOG(prefix
<<qname
<<": Failed to resolve via any of the "<<(unsigned int)rnameservers
.size()<<" offered NS at level '"<<auth
<<"'"<<endl
);
2546 if(!auth
.isRoot() && flawedNSSet
) {
2547 LOG(prefix
<<qname
<<": Ageing nameservers for level '"<<auth
<<"', next query might succeed"<<endl
);
2549 if(t_RC
->doAgeCache(d_now
.tv_sec
, auth
, QType::NS
, 10))
2550 g_stats
.nsSetInvalidations
++;
2555 // this line needs to identify the 'self-resolving' behaviour, but we get it wrong now
2556 if(qname
== *tns
&& qtype
.getCode()==QType::A
&& rnameservers
.size() > (size_t)(1+1*s_doIPv6
)) {
2557 LOG(prefix
<<qname
<<": Not using NS to resolve itself! ("<<(1+tns
-rnameservers
.cbegin())<<"/"<<rnameservers
.size()<<")"<<endl
);
2561 typedef vector
<ComboAddress
> remoteIPs_t
;
2562 remoteIPs_t remoteIPs
;
2563 remoteIPs_t::const_iterator remoteIP
;
2564 bool pierceDontQuery
=false;
2565 bool sendRDQuery
=false;
2566 boost::optional
<Netmask
> ednsmask
;
2568 const bool wasForwarded
= tns
->empty() && (!nameservers
[*tns
].first
.empty());
2569 int rcode
= RCode::NoError
;
2570 bool gotNewServers
= false;
2572 if(tns
->empty() && !wasForwarded
) {
2573 LOG(prefix
<<qname
<<": Domain is out-of-band"<<endl
);
2575 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, lwr
.d_records
, depth
, lwr
.d_rcode
);
2579 /* we have received an answer, are we done ? */
2580 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, false, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
2584 if (gotNewServers
) {
2589 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
2590 remoteIPs
= retrieveAddressesForNS(prefix
, qname
, tns
, depth
, beenthere
, rnameservers
, nameservers
, sendRDQuery
, pierceDontQuery
, flawedNSSet
);
2592 if(remoteIPs
.empty()) {
2593 LOG(prefix
<<qname
<<": Failed to get IP for NS "<<*tns
<<", trying next if available"<<endl
);
2598 bool hitPolicy
{false};
2599 LOG(prefix
<<qname
<<": Resolved '"<<auth
<<"' NS "<<*tns
<<" to: ");
2600 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
2601 if(remoteIP
!= remoteIPs
.cbegin()) {
2604 LOG(remoteIP
->toString());
2605 if(nameserverIPBlockedByRPZ(luaconfsLocal
->dfe
, *remoteIP
)) {
2610 if (hitPolicy
) //implies d_wantsRPZ
2614 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
2615 LOG(prefix
<<qname
<<": Trying IP "<< remoteIP
->toStringWithPort() <<", asking '"<<qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
2617 if (throttledOrBlocked(prefix
, *remoteIP
, qname
, qtype
, pierceDontQuery
)) {
2621 bool truncated
= false;
2622 bool gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
2623 *tns
, *remoteIP
, false, &truncated
);
2624 if (gotAnswer
&& truncated
) {
2625 /* retry, over TCP this time */
2626 gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
2627 *tns
, *remoteIP
, true, &truncated
);
2634 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
);
2636 /* // for you IPv6 fanatics :-)
2637 if(remoteIP->sin4.sin_family==AF_INET6)
2640 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
2642 t_sstorage
.nsSpeeds
[*tns
].submit(*remoteIP
, lwr
.d_usec
, &d_now
);
2644 /* we have received an answer, are we done ? */
2645 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
2649 if (gotNewServers
) {
2653 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100);
2656 if (gotNewServers
) {
2660 if(remoteIP
== remoteIPs
.cend()) // we tried all IP addresses, none worked
2669 void SyncRes::setIncomingECS(boost::optional
<const EDNSSubnetOpts
&> incomingECS
)
2671 d_incomingECS
= incomingECS
;
2673 if (d_incomingECS
->source
.getBits() == 0) {
2674 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0.
2675 But using an empty ECS in that case would mean inserting
2676 a non ECS-specific entry into the cache, preventing any further
2677 ECS-specific query to be sent.
2678 So instead we use the trick described in section 7.1.2:
2679 "The subsequent Recursive Resolver query to the Authoritative Nameserver
2680 will then either not include an ECS option or MAY optionally include
2681 its own address information, which is what the Authoritative
2682 Nameserver will almost certainly use to generate any Tailored
2683 Response in lieu of an option. This allows the answer to be handled
2684 by the same caching mechanism as other queries, with an explicit
2685 indicator of the applicable scope. Subsequent Stub Resolver queries
2686 for /0 can then be answered from this cached response.
2688 d_incomingECS
= s_ecsScopeZero
;
2689 d_incomingECSNetwork
= s_ecsScopeZero
.source
.getMaskedNetwork();
2692 uint8_t bits
= std::min(incomingECS
->source
.getBits(), (incomingECS
->source
.isIpv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
2693 d_incomingECS
->source
= Netmask(incomingECS
->source
.getNetwork(), bits
);
2694 d_incomingECSNetwork
= d_incomingECS
->source
.getMaskedNetwork();
2698 d_incomingECSNetwork
= ComboAddress();
2702 boost::optional
<Netmask
> SyncRes::getEDNSSubnetMask(const ComboAddress
& local
, const DNSName
&dn
, const ComboAddress
& rem
)
2704 boost::optional
<Netmask
> result
;
2707 if(d_incomingECSFound
) {
2708 trunc
= d_incomingECSNetwork
;
2709 bits
= d_incomingECS
->source
.getBits();
2711 else if(!local
.isIPv4() || local
.sin4
.sin_addr
.s_addr
) { // detect unset 'requestor'
2713 bits
= local
.isIPv4() ? 32 : 128;
2714 bits
= std::min(bits
, (trunc
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
2717 /* nothing usable */
2721 if(s_ednsdomains
.check(dn
) || s_ednssubnets
.match(rem
)) {
2722 trunc
.truncate(bits
);
2723 return boost::optional
<Netmask
>(Netmask(trunc
, bits
));
2729 void SyncRes::parseEDNSSubnetWhitelist(const std::string
& wlist
)
2731 vector
<string
> parts
;
2732 stringtok(parts
, wlist
, ",; ");
2733 for(const auto& a
: parts
) {
2735 s_ednssubnets
.addMask(Netmask(a
));
2738 s_ednsdomains
.add(DNSName(a
));
2743 // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
2744 int directResolve(const DNSName
& qname
, const QType
& qtype
, int qclass
, vector
<DNSRecord
>& ret
)
2747 gettimeofday(&now
, 0);
2750 int res
= sr
.beginResolve(qname
, QType(qtype
), qclass
, ret
);
2755 int SyncRes::getRootNS(struct timeval now
, asyncresolve_t asyncCallback
) {
2757 sr
.setDoEDNS0(true);
2758 sr
.setUpdatingRootNS();
2759 sr
.setDoDNSSEC(g_dnssecmode
!= DNSSECMode::Off
);
2760 sr
.setDNSSECValidationRequested(g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
);
2761 sr
.setAsyncCallback(asyncCallback
);
2763 vector
<DNSRecord
> ret
;
2766 res
=sr
.beginResolve(g_rootdnsname
, QType(QType::NS
), 1, ret
);
2767 if (g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
) {
2768 auto state
= sr
.getValidationState();
2770 throw PDNSException("Got Bogus validation result for .|NS");
2774 catch(const PDNSException
& e
) {
2775 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
2777 catch(const ImmediateServFailException
& e
) {
2778 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
2780 catch(const std::exception
& e
) {
2781 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.what()<<endl
;
2784 L
<<Logger::Error
<<"Failed to update . records, got an exception"<<endl
;
2788 L
<<Logger::Notice
<<"Refreshed . records"<<endl
;
2791 L
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;