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
, false);
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
<<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 /* Even if the AA bit is set, additional data cannot be considered
2008 as authoritative. This is especially important during validation
2009 because keeping records in the additional section is allowed even
2010 if the corresponding RRSIGs are not included, without setting the TC
2011 bit, as stated in rfc4035's section 3.1.1. Including RRSIG RRs in a Response:
2012 "When placing a signed RRset in the Additional section, the name
2013 server MUST also place its RRSIG RRs in the Additional section.
2014 If space does not permit inclusion of both the RRset and its
2015 associated RRSIG RRs, the name server MAY retain the RRset while
2016 dropping the RRSIG RRs. If this happens, the name server MUST NOT
2017 set the TC bit solely because these RRSIG RRs didn't fit."
2019 bool isAA
= lwr
.d_aabit
&& i
->first
.place
!= DNSResourceRecord::ADDITIONAL
;
2020 if (isAA
&& isCNAMEAnswer
&& (i
->first
.place
!= DNSResourceRecord::ANSWER
|| i
->first
.type
!= QType::CNAME
)) {
2023 Note that the answer section of an authoritative answer normally
2024 contains only authoritative data. However when the name sought is an
2025 alias (see section 10.1.1) only the record describing that alias is
2026 necessarily authoritative. Clients should assume that other records
2027 may have come from the server's cache. Where authoritative answers
2028 are required, the client should query again, using the canonical name
2029 associated with the alias.
2034 vState recordState
= getValidationStatus(i
->first
.name
, false);
2035 LOG(d_prefix
<<": got initial zone status "<<vStates
[recordState
]<<" for record "<<i
->first
.name
<<endl
);
2037 if (d_DNSSECValidationRequested
&& recordState
== Secure
) {
2038 vState initialState
= recordState
;
2041 if (i
->first
.place
!= DNSResourceRecord::ADDITIONAL
) {
2042 /* the additional entries can be insecure,
2044 "Glue address RRsets associated with delegations MUST NOT be signed"
2046 if (i
->first
.type
== QType::DNSKEY
&& i
->first
.place
== DNSResourceRecord::ANSWER
) {
2047 LOG(d_prefix
<<"Validating DNSKEY for "<<i
->first
.name
<<endl
);
2048 recordState
= validateDNSKeys(i
->first
.name
, i
->second
.records
, i
->second
.signatures
, depth
);
2051 LOG(d_prefix
<<"Validating non-additional record for "<<i
->first
.name
<<endl
);
2052 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2053 /* 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 */
2054 if (qtype
== QType::NS
&& i
->second
.signatures
.empty() && recordState
== Bogus
&& haveExactValidationStatus(i
->first
.name
) && getValidationStatus(i
->first
.name
) == Indeterminate
) {
2055 recordState
= Indeterminate
;
2061 /* in a non authoritative answer, we only care about the DS record (or lack of) */
2062 if ((i
->first
.type
== QType::DS
|| i
->first
.type
== QType::NSEC
|| i
->first
.type
== QType::NSEC3
) && i
->first
.place
== DNSResourceRecord::AUTHORITY
) {
2063 LOG(d_prefix
<<"Validating DS record for "<<i
->first
.name
<<endl
);
2064 recordState
= validateRecordsWithSigs(depth
, qname
, qtype
, i
->first
.name
, i
->second
.records
, i
->second
.signatures
);
2068 if (initialState
== Secure
&& state
!= recordState
) {
2069 updateValidationState(state
, recordState
);
2073 if (d_DNSSECValidationRequested
) {
2074 LOG(d_prefix
<<"Skipping validation because the current state is "<<vStates
[recordState
]<<endl
);
2078 /* We don't need to store NSEC3 records in the positive cache because:
2079 - we don't allow direct NSEC3 queries
2080 - denial of existence proofs in wildcard expanded positive responses are stored in authorityRecs
2081 - denial of existence proofs for negative responses are stored in the negative cache
2083 if (i
->first
.type
!= QType::NSEC3
) {
2084 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
);
2087 if(i
->first
.place
== DNSResourceRecord::ANSWER
&& ednsmask
)
2091 return RCode::NoError
;
2094 void SyncRes::updateDenialValidationState(NegCache::NegCacheEntry
& ne
, vState
& state
, const dState denialState
, const dState expectedState
, bool allowOptOut
)
2096 if (denialState
== expectedState
) {
2097 ne
.d_validationState
= Secure
;
2100 if (denialState
== OPTOUT
&& allowOptOut
) {
2101 LOG(d_prefix
<<"OPT-out denial found for "<<ne
.d_name
<<endl
);
2102 ne
.d_validationState
= Secure
;
2105 else if (denialState
== INSECURE
) {
2106 LOG(d_prefix
<<"Insecure denial found for "<<ne
.d_name
<<", returning Insecure"<<endl
);
2107 ne
.d_validationState
= Insecure
;
2110 LOG(d_prefix
<<"Invalid denial found for "<<ne
.d_name
<<", returning Bogus, res="<<denialState
<<", expectedState="<<expectedState
<<endl
);
2111 ne
.d_validationState
= Bogus
;
2113 updateValidationState(state
, ne
.d_validationState
);
2117 dState
SyncRes::getDenialValidationState(NegCache::NegCacheEntry
& ne
, const vState state
, const dState expectedState
, bool referralToUnsigned
)
2119 cspmap_t csp
= harvestCSPFromNE(ne
);
2120 return getDenial(csp
, ne
.d_name
, ne
.d_qtype
.getCode(), referralToUnsigned
, expectedState
== NXQTYPE
);
2123 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
)
2127 for(auto& rec
: lwr
.d_records
) {
2128 if (rec
.d_type
!=QType::OPT
&& rec
.d_class
!=QClass::IN
)
2131 if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2132 lwr
.d_rcode
==RCode::NXDomain
&& qname
.isPartOf(rec
.d_name
) && rec
.d_name
.isPartOf(auth
)) {
2133 LOG(prefix
<<qname
<<": got negative caching indication for name '"<<qname
<<"' (accept="<<rec
.d_name
.isPartOf(auth
)<<"), newtarget='"<<newtarget
<<"'"<<endl
);
2135 rec
.d_ttl
= min(rec
.d_ttl
, s_maxnegttl
);
2136 if(newtarget
.empty()) // only add a SOA if we're not going anywhere after this
2139 NegCache::NegCacheEntry ne
;
2141 uint32_t lowestTTL
= rec
.d_ttl
;
2142 /* if we get an NXDomain answer with a CNAME, the name
2143 does exist but the target does not */
2144 ne
.d_name
= newtarget
.empty() ? qname
: newtarget
;
2145 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2146 ne
.d_auth
= rec
.d_name
;
2147 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2148 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2150 if (state
== Secure
) {
2151 dState denialState
= getDenialValidationState(ne
, state
, NXDOMAIN
, false);
2152 updateDenialValidationState(ne
, state
, denialState
, NXDOMAIN
, false);
2155 ne
.d_validationState
= state
;
2158 /* if we get an NXDomain answer with a CNAME, let's not cache the
2159 target, even the server was authoritative for it,
2160 and do an additional query for the CNAME target.
2161 We have a regression test making sure we do exactly that.
2163 if(!wasVariable() && newtarget
.empty()) {
2164 t_sstorage
.negcache
.add(ne
);
2165 if(s_rootNXTrust
&& ne
.d_auth
.isRoot() && auth
.isRoot()) {
2166 ne
.d_name
= ne
.d_name
.getLastLabel();
2167 t_sstorage
.negcache
.add(ne
);
2173 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_type
==QType::CNAME
&& (!(qtype
==QType(QType::CNAME
))) && rec
.d_name
== qname
) {
2175 if (auto content
= getRR
<CNAMERecordContent
>(rec
)) {
2176 newtarget
=content
->getTarget();
2179 /* if we have a positive answer synthetized from a wildcard, we need to
2180 return the corresponding NSEC/NSEC3 records from the AUTHORITY section
2181 proving that the exact name did not exist */
2182 else if(needWildcardProof
&& (rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::AUTHORITY
) {
2183 ret
.push_back(rec
); // enjoy your DNSSEC
2185 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
2186 else if(rec
.d_place
==DNSResourceRecord::ANSWER
&& rec
.d_name
== qname
&&
2188 rec
.d_type
==qtype
.getCode() || ((lwr
.d_aabit
|| sendRDQuery
) && qtype
== QType(QType::ANY
))
2192 LOG(prefix
<<qname
<<": answer is in: resolved to '"<< rec
.d_content
->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec
.d_type
)<<"'"<<endl
);
2197 if (state
== Secure
&& needWildcardProof
) {
2198 /* We have a positive answer synthetized from a wildcard, we need to check that we have
2199 proof that the exact name doesn't exist so the wildcard can be used,
2200 as described in section 5.3.4 of RFC 4035 and 5.3 of FRC 7129.
2202 NegCache::NegCacheEntry ne
;
2204 uint32_t lowestTTL
= rec
.d_ttl
;
2206 ne
.d_qtype
= QType(0); // this encodes 'whole record'
2207 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2209 cspmap_t csp
= harvestCSPFromNE(ne
);
2210 dState res
= getDenial(csp
, qname
, ne
.d_qtype
.getCode(), false, false, false);
2211 if (res
!= NXDOMAIN
) {
2213 if (res
== INSECURE
) {
2214 /* Some part could not be validated, for example a NSEC3 record with a too large number of iterations,
2215 this is not enough to warrant a Bogus, but go Insecure. */
2217 LOG(d_prefix
<<"Unable to validate denial in wildcard expanded positive response found for "<<qname
<<", returning Insecure, res="<<res
<<endl
);
2220 LOG(d_prefix
<<"Invalid denial in wildcard expanded positive response found for "<<qname
<<", returning Bogus, res="<<res
<<endl
);
2223 updateValidationState(state
, st
);
2224 /* we already stored the record with a different validation status, let's fix it */
2225 t_RC
->updateValidationStatus(d_now
.tv_sec
, qname
, qtype
, d_incomingECSFound
? d_incomingECSNetwork
: d_requestor
, lwr
.d_aabit
, st
);
2229 else if((rec
.d_type
==QType::RRSIG
|| rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && rec
.d_place
==DNSResourceRecord::ANSWER
) {
2230 if(rec
.d_type
!= QType::RRSIG
|| rec
.d_name
== qname
)
2231 ret
.push_back(rec
); // enjoy your DNSSEC
2233 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::NS
&& qname
.isPartOf(rec
.d_name
)) {
2234 if(moreSpecificThan(rec
.d_name
,auth
)) {
2236 LOG(prefix
<<qname
<<": got NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2240 LOG(prefix
<<qname
<<": got upwards/level NS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"', had '"<<auth
<<"'"<<endl
);
2242 if (auto content
= getRR
<NSRecordContent
>(rec
)) {
2243 nsset
.insert(content
->getNS());
2246 else if(rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::DS
&& qname
.isPartOf(rec
.d_name
)) {
2247 LOG(prefix
<<qname
<<": got DS record '"<<rec
.d_name
<<"' -> '"<<rec
.d_content
->getZoneRepresentation()<<"'"<<endl
);
2249 else if(realreferral
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& (rec
.d_type
==QType::NSEC
|| rec
.d_type
==QType::NSEC3
) && newauth
.isPartOf(auth
)) {
2250 /* we might have received a denial of the DS, let's check */
2251 if (state
== Secure
) {
2252 NegCache::NegCacheEntry ne
;
2254 ne
.d_name
= newauth
;
2255 ne
.d_qtype
= QType::DS
;
2256 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2257 uint32_t lowestTTL
= rec
.d_ttl
;
2258 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2260 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, true);
2262 if (denialState
== NXQTYPE
|| denialState
== OPTOUT
|| denialState
== INSECURE
) {
2263 ne
.d_ttd
= lowestTTL
+ d_now
.tv_sec
;
2264 ne
.d_validationState
= Secure
;
2265 LOG(prefix
<<qname
<<": got negative indication of DS record for '"<<newauth
<<"'"<<endl
);
2267 if(!wasVariable()) {
2268 t_sstorage
.negcache
.add(ne
);
2271 if (qname
== newauth
&& qtype
== QType::DS
) {
2272 /* we are actually done! */
2279 else if(!done
&& rec
.d_place
==DNSResourceRecord::AUTHORITY
&& rec
.d_type
==QType::SOA
&&
2280 lwr
.d_rcode
==RCode::NoError
&& qname
.isPartOf(rec
.d_name
)) {
2281 LOG(prefix
<<qname
<<": got negative caching indication for '"<< qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
2283 if(!newtarget
.empty()) {
2284 LOG(prefix
<<qname
<<": Hang on! Got a redirect to '"<<newtarget
<<"' already"<<endl
);
2287 rec
.d_ttl
= min(s_maxnegttl
, rec
.d_ttl
);
2290 NegCache::NegCacheEntry ne
;
2291 ne
.d_auth
= rec
.d_name
;
2292 uint32_t lowestTTL
= rec
.d_ttl
;
2295 harvestNXRecords(lwr
.d_records
, ne
, d_now
.tv_sec
, &lowestTTL
);
2296 ne
.d_ttd
= d_now
.tv_sec
+ lowestTTL
;
2298 if (state
== Secure
) {
2299 dState denialState
= getDenialValidationState(ne
, state
, NXQTYPE
, false);
2300 updateDenialValidationState(ne
, state
, denialState
, NXQTYPE
, qtype
== QType::DS
);
2302 ne
.d_validationState
= state
;
2305 if(!wasVariable()) {
2306 if(qtype
.getCode()) { // prevents us from blacking out a whole domain
2307 t_sstorage
.negcache
.add(ne
);
2318 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
)
2324 if(d_outqueries
+ d_throttledqueries
> s_maxqperq
) {
2325 throw ImmediateServFailException("more than "+std::to_string(s_maxqperq
)+" (max-qperq) queries sent while resolving "+qname
.toLogString());
2328 if(s_maxtotusec
&& d_totUsec
> s_maxtotusec
) {
2329 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");
2333 LOG(prefix
<<qname
<<": using TCP with "<< remoteIP
.toStringWithPort() <<endl
);
2338 if(d_pdl
&& d_pdl
->preoutquery(remoteIP
, d_requestor
, qname
, qtype
, doTCP
, lwr
.d_records
, resolveret
)) {
2339 LOG(prefix
<<qname
<<": query handled by Lua"<<endl
);
2342 ednsmask
=getEDNSSubnetMask(d_requestor
, qname
, remoteIP
);
2344 LOG(prefix
<<qname
<<": Adding EDNS Client Subnet Mask "<<ednsmask
->toString()<<" to query"<<endl
);
2347 resolveret
= asyncresolveWrapper(remoteIP
, d_doDNSSEC
, qname
, qtype
.getCode(),
2348 doTCP
, sendRDQuery
, &d_now
, ednsmask
, &lwr
); // <- we go out on the wire!
2351 LOG(prefix
<<qname
<<": Received EDNS Client Subnet Mask "<<ednsmask
->toString()<<" on response"<<endl
);
2355 /* preoutquery killed the query by setting dq.rcode to -3 */
2356 if(resolveret
==-3) {
2357 throw ImmediateServFailException("Query killed by policy");
2360 d_totUsec
+= lwr
.d_usec
;
2361 accountAuthLatency(lwr
.d_usec
, remoteIP
.sin4
.sin_family
);
2363 if(resolveret
!= 1) {
2364 /* Error while resolving */
2365 if(resolveret
== 0) {
2368 LOG(prefix
<<qname
<<": timeout resolving after "<<lwr
.d_usec
/1000.0<<"msec "<< (doTCP
? "over TCP" : "")<<endl
);
2370 s_outgoingtimeouts
++;
2372 if(remoteIP
.sin4
.sin_family
== AF_INET
)
2373 s_outgoing4timeouts
++;
2375 s_outgoing6timeouts
++;
2377 else if(resolveret
== -2) {
2378 /* OS resource limit reached */
2379 LOG(prefix
<<qname
<<": hit a local resource limit resolving"<< (doTCP
? " over TCP" : "")<<", probable error: "<<stringerror()<<endl
);
2380 g_stats
.resourceLimits
++;
2383 /* -1 means server unreachable */
2386 LOG(prefix
<<qname
<<": error resolving from "<<remoteIP
.toString()<< (doTCP
? " over TCP" : "") <<", possible error: "<<strerror(errno
)<< endl
);
2389 if(resolveret
!= -2) { // don't account for resource limits, they are our own fault
2390 t_sstorage
.nsSpeeds
[nsName
].submit(remoteIP
, 1000000, &d_now
); // 1 sec
2392 // code below makes sure we don't filter COM or the root
2393 if (s_serverdownmaxfails
> 0 && (auth
!= g_rootdnsname
) && t_sstorage
.fails
.incr(remoteIP
) >= s_serverdownmaxfails
) {
2394 LOG(prefix
<<qname
<<": Max fails reached resolving on "<< remoteIP
.toString() <<". Going full throttle for "<< s_serverdownthrottletime
<<" seconds" <<endl
);
2395 // mark server as down
2396 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, "", 0), s_serverdownthrottletime
, 10000);
2398 else if (resolveret
== -1) {
2399 // unreachable, 1 minute or 100 queries
2400 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 100);
2404 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 10, 5);
2411 /* we got an answer */
2412 if(lwr
.d_rcode
==RCode::ServFail
|| lwr
.d_rcode
==RCode::Refused
) {
2413 LOG(prefix
<<qname
<<": "<<nsName
<<" ("<<remoteIP
.toString()<<") returned a "<< (lwr
.d_rcode
==RCode::ServFail
? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl
);
2414 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
2418 /* this server sent a valid answer, mark it backup up if it was down */
2419 if(s_serverdownmaxfails
> 0) {
2420 t_sstorage
.fails
.clear(remoteIP
);
2427 LOG(prefix
<<qname
<<": truncated bit set, over TCP?"<<endl
);
2428 /* let's treat that as a ServFail answer from this server */
2429 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(remoteIP
, qname
, qtype
.getCode()), 60, 3);
2439 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
)
2444 prefix
.append(depth
, ' ');
2448 for(auto& rec
: lwr
.d_records
) {
2449 rec
.d_ttl
= max(rec
.d_ttl
, s_minimumTTL
);
2453 bool needWildcardProof
= false;
2454 *rcode
= updateCacheFromRecords(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, state
, needWildcardProof
);
2455 if (*rcode
!= RCode::NoError
) {
2459 LOG(prefix
<<qname
<<": determining status after receiving this packet"<<endl
);
2462 bool realreferral
=false, negindic
=false;
2466 bool done
= processRecords(prefix
, qname
, qtype
, auth
, lwr
, sendRDQuery
, ret
, nsset
, newtarget
, newauth
, realreferral
, negindic
, state
, needWildcardProof
);
2469 LOG(prefix
<<qname
<<": status=got results, this level of recursion done"<<endl
);
2470 LOG(prefix
<<qname
<<": validation status is "<<vStates
[state
]<<endl
);
2471 *rcode
= RCode::NoError
;
2475 if(!newtarget
.empty()) {
2476 if(newtarget
== qname
) {
2477 LOG(prefix
<<qname
<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl
);
2478 *rcode
= RCode::ServFail
;
2483 LOG(prefix
<<qname
<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl
);
2484 *rcode
= RCode::ServFail
;
2488 if (qtype
== QType::DS
) {
2489 LOG(prefix
<<qname
<<": status=got a CNAME referral, but we are looking for a DS"<<endl
);
2492 addNXNSECS(ret
, lwr
.d_records
);
2494 *rcode
= RCode::NoError
;
2498 LOG(prefix
<<qname
<<": status=got a CNAME referral, starting over with "<<newtarget
<<endl
);
2500 set
<GetBestNSAnswer
> beenthere2
;
2501 vState cnameState
= Indeterminate
;
2502 *rcode
= doResolve(newtarget
, qtype
, ret
, depth
+ 1, beenthere2
, cnameState
);
2503 LOG(prefix
<<qname
<<": updating validation state for response to "<<qname
<<" from "<<vStates
[state
]<<" with the state from the CNAME quest: "<<vStates
[cnameState
]<<endl
);
2504 updateValidationState(state
, cnameState
);
2509 if(lwr
.d_rcode
== RCode::NXDomain
) {
2510 LOG(prefix
<<qname
<<": status=NXDOMAIN, we are done "<<(negindic
? "(have negative SOA)" : "")<<endl
);
2513 addNXNSECS(ret
, lwr
.d_records
);
2515 *rcode
= RCode::NXDomain
;
2519 if(nsset
.empty() && !lwr
.d_rcode
&& (negindic
|| lwr
.d_aabit
|| sendRDQuery
)) {
2520 LOG(prefix
<<qname
<<": status=noerror, other types may exist, but we are done "<<(negindic
? "(have negative SOA) " : "")<<(lwr
.d_aabit
? "(have aa bit) " : "")<<endl
);
2522 if(state
== Secure
&& lwr
.d_aabit
&& !negindic
) {
2523 updateValidationState(state
, Bogus
);
2527 addNXNSECS(ret
, lwr
.d_records
);
2529 *rcode
= RCode::NoError
;
2534 LOG(prefix
<<qname
<<": status=did not resolve, got "<<(unsigned int)nsset
.size()<<" NS, ");
2536 nameservers
.clear();
2537 for (auto const &nameserver
: nsset
) {
2539 d_appliedPolicy
= dfe
.getProcessingPolicy(nameserver
, d_discardedPolicies
);
2540 if (d_appliedPolicy
.d_kind
!= DNSFilterEngine::PolicyKind::NoAction
) { // client query needs an RPZ response
2541 LOG("however "<<nameserver
<<" was blocked by RPZ policy '"<<(d_appliedPolicy
.d_name
? *d_appliedPolicy
.d_name
: "")<<"'"<<endl
);
2546 nameservers
.insert({nameserver
, {{}, false}});
2548 LOG("looping to them"<<endl
);
2549 *gotNewServers
= true;
2559 * -1 in case of no results
2560 * -2 when a FilterEngine Policy was hit
2563 int SyncRes::doResolveAt(NsSet
&nameservers
, DNSName auth
, bool flawedNSSet
, const DNSName
&qname
, const QType
&qtype
,
2564 vector
<DNSRecord
>&ret
,
2565 unsigned int depth
, set
<GetBestNSAnswer
>&beenthere
, vState
& state
)
2567 auto luaconfsLocal
= g_luaconfs
.getLocal();
2571 prefix
.append(depth
, ' ');
2574 LOG(prefix
<<qname
<<": Cache consultations done, have "<<(unsigned int)nameservers
.size()<<" NS to contact");
2576 if (nameserversBlockedByRPZ(luaconfsLocal
->dfe
, nameservers
)) {
2582 for(;;) { // we may get more specific nameservers
2583 vector
<DNSName
> rnameservers
= shuffleInSpeedOrder(nameservers
, doLog() ? (prefix
+qname
.toString()+": ") : string() );
2585 for(auto tns
=rnameservers
.cbegin();;++tns
) {
2586 if(tns
==rnameservers
.cend()) {
2587 LOG(prefix
<<qname
<<": Failed to resolve via any of the "<<(unsigned int)rnameservers
.size()<<" offered NS at level '"<<auth
<<"'"<<endl
);
2588 if(!auth
.isRoot() && flawedNSSet
) {
2589 LOG(prefix
<<qname
<<": Ageing nameservers for level '"<<auth
<<"', next query might succeed"<<endl
);
2591 if(t_RC
->doAgeCache(d_now
.tv_sec
, auth
, QType::NS
, 10))
2592 g_stats
.nsSetInvalidations
++;
2597 bool cacheOnly
= false;
2598 // this line needs to identify the 'self-resolving' behaviour
2599 if(qname
== *tns
&& (qtype
.getCode() == QType::A
|| qtype
.getCode() == QType::AAAA
)) {
2600 /* we might have a glue entry in cache so let's try this NS
2601 but only if we have enough in the cache to know how to reach it */
2602 LOG(prefix
<<qname
<<": Using NS to resolve itself, but only using what we have in cache ("<<(1+tns
-rnameservers
.cbegin())<<"/"<<rnameservers
.size()<<")"<<endl
);
2606 typedef vector
<ComboAddress
> remoteIPs_t
;
2607 remoteIPs_t remoteIPs
;
2608 remoteIPs_t::const_iterator remoteIP
;
2609 bool pierceDontQuery
=false;
2610 bool sendRDQuery
=false;
2611 boost::optional
<Netmask
> ednsmask
;
2613 const bool wasForwarded
= tns
->empty() && (!nameservers
[*tns
].first
.empty());
2614 int rcode
= RCode::NoError
;
2615 bool gotNewServers
= false;
2617 if(tns
->empty() && !wasForwarded
) {
2618 LOG(prefix
<<qname
<<": Domain is out-of-band"<<endl
);
2620 d_wasOutOfBand
= doOOBResolve(qname
, qtype
, lwr
.d_records
, depth
, lwr
.d_rcode
);
2624 /* we have received an answer, are we done ? */
2625 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, false, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
2629 if (gotNewServers
) {
2634 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
2635 remoteIPs
= retrieveAddressesForNS(prefix
, qname
, tns
, depth
, beenthere
, rnameservers
, nameservers
, sendRDQuery
, pierceDontQuery
, flawedNSSet
, cacheOnly
);
2637 if(remoteIPs
.empty()) {
2638 LOG(prefix
<<qname
<<": Failed to get IP for NS "<<*tns
<<", trying next if available"<<endl
);
2643 bool hitPolicy
{false};
2644 LOG(prefix
<<qname
<<": Resolved '"<<auth
<<"' NS "<<*tns
<<" to: ");
2645 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
2646 if(remoteIP
!= remoteIPs
.cbegin()) {
2649 LOG(remoteIP
->toString());
2650 if(nameserverIPBlockedByRPZ(luaconfsLocal
->dfe
, *remoteIP
)) {
2655 if (hitPolicy
) //implies d_wantsRPZ
2659 for(remoteIP
= remoteIPs
.cbegin(); remoteIP
!= remoteIPs
.cend(); ++remoteIP
) {
2660 LOG(prefix
<<qname
<<": Trying IP "<< remoteIP
->toStringWithPort() <<", asking '"<<qname
<<"|"<<qtype
.getName()<<"'"<<endl
);
2662 if (throttledOrBlocked(prefix
, *remoteIP
, qname
, qtype
, pierceDontQuery
)) {
2666 bool truncated
= false;
2667 bool gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
2668 *tns
, *remoteIP
, false, &truncated
);
2669 if (gotAnswer
&& truncated
) {
2670 /* retry, over TCP this time */
2671 gotAnswer
= doResolveAtThisIP(prefix
, qname
, qtype
, lwr
, ednsmask
, auth
, sendRDQuery
,
2672 *tns
, *remoteIP
, true, &truncated
);
2679 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
);
2681 /* // for you IPv6 fanatics :-)
2682 if(remoteIP->sin4.sin_family==AF_INET6)
2685 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
2687 t_sstorage
.nsSpeeds
[*tns
].submit(*remoteIP
, lwr
.d_usec
, &d_now
);
2689 /* we have received an answer, are we done ? */
2690 bool done
= processAnswer(depth
, lwr
, qname
, qtype
, auth
, wasForwarded
, ednsmask
, sendRDQuery
, nameservers
, ret
, luaconfsLocal
->dfe
, &gotNewServers
, &rcode
, state
);
2694 if (gotNewServers
) {
2698 t_sstorage
.throttle
.throttle(d_now
.tv_sec
, boost::make_tuple(*remoteIP
, qname
, qtype
.getCode()), 60, 100);
2701 if (gotNewServers
) {
2705 if(remoteIP
== remoteIPs
.cend()) // we tried all IP addresses, none worked
2714 void SyncRes::setIncomingECS(boost::optional
<const EDNSSubnetOpts
&> incomingECS
)
2716 d_incomingECS
= incomingECS
;
2718 if (d_incomingECS
->source
.getBits() == 0) {
2719 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0.
2720 But using an empty ECS in that case would mean inserting
2721 a non ECS-specific entry into the cache, preventing any further
2722 ECS-specific query to be sent.
2723 So instead we use the trick described in section 7.1.2:
2724 "The subsequent Recursive Resolver query to the Authoritative Nameserver
2725 will then either not include an ECS option or MAY optionally include
2726 its own address information, which is what the Authoritative
2727 Nameserver will almost certainly use to generate any Tailored
2728 Response in lieu of an option. This allows the answer to be handled
2729 by the same caching mechanism as other queries, with an explicit
2730 indicator of the applicable scope. Subsequent Stub Resolver queries
2731 for /0 can then be answered from this cached response.
2733 d_incomingECS
= s_ecsScopeZero
;
2734 d_incomingECSNetwork
= s_ecsScopeZero
.source
.getMaskedNetwork();
2737 uint8_t bits
= std::min(incomingECS
->source
.getBits(), (incomingECS
->source
.isIpv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
2738 d_incomingECS
->source
= Netmask(incomingECS
->source
.getNetwork(), bits
);
2739 d_incomingECSNetwork
= d_incomingECS
->source
.getMaskedNetwork();
2743 d_incomingECSNetwork
= ComboAddress();
2747 boost::optional
<Netmask
> SyncRes::getEDNSSubnetMask(const ComboAddress
& local
, const DNSName
&dn
, const ComboAddress
& rem
)
2749 boost::optional
<Netmask
> result
;
2752 if(d_incomingECSFound
) {
2753 trunc
= d_incomingECSNetwork
;
2754 bits
= d_incomingECS
->source
.getBits();
2756 else if(!local
.isIPv4() || local
.sin4
.sin_addr
.s_addr
) { // detect unset 'requestor'
2758 bits
= local
.isIPv4() ? 32 : 128;
2759 bits
= std::min(bits
, (trunc
.isIPv4() ? s_ecsipv4limit
: s_ecsipv6limit
));
2762 /* nothing usable */
2766 if(s_ednsdomains
.check(dn
) || s_ednssubnets
.match(rem
)) {
2767 trunc
.truncate(bits
);
2768 return boost::optional
<Netmask
>(Netmask(trunc
, bits
));
2774 void SyncRes::parseEDNSSubnetWhitelist(const std::string
& wlist
)
2776 vector
<string
> parts
;
2777 stringtok(parts
, wlist
, ",; ");
2778 for(const auto& a
: parts
) {
2780 s_ednssubnets
.addMask(Netmask(a
));
2783 s_ednsdomains
.add(DNSName(a
));
2788 // used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
2789 int directResolve(const DNSName
& qname
, const QType
& qtype
, int qclass
, vector
<DNSRecord
>& ret
)
2792 gettimeofday(&now
, 0);
2795 int res
= sr
.beginResolve(qname
, QType(qtype
), qclass
, ret
);
2800 int SyncRes::getRootNS(struct timeval now
, asyncresolve_t asyncCallback
) {
2802 sr
.setDoEDNS0(true);
2803 sr
.setUpdatingRootNS();
2804 sr
.setDoDNSSEC(g_dnssecmode
!= DNSSECMode::Off
);
2805 sr
.setDNSSECValidationRequested(g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
);
2806 sr
.setAsyncCallback(asyncCallback
);
2808 vector
<DNSRecord
> ret
;
2811 res
=sr
.beginResolve(g_rootdnsname
, QType(QType::NS
), 1, ret
);
2812 if (g_dnssecmode
!= DNSSECMode::Off
&& g_dnssecmode
!= DNSSECMode::ProcessNoValidate
) {
2813 auto state
= sr
.getValidationState();
2815 throw PDNSException("Got Bogus validation result for .|NS");
2819 catch(const PDNSException
& e
) {
2820 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
2822 catch(const ImmediateServFailException
& e
) {
2823 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.reason
<<endl
;
2825 catch(const std::exception
& e
) {
2826 L
<<Logger::Error
<<"Failed to update . records, got an exception: "<<e
.what()<<endl
;
2829 L
<<Logger::Error
<<"Failed to update . records, got an exception"<<endl
;
2833 L
<<Logger::Notice
<<"Refreshed . records"<<endl
;
2836 L
<<Logger::Error
<<"Failed to update . records, RCODE="<<res
<<endl
;