]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/syncres.cc
Merge pull request #8662 from rgacogne/ddist-default-tls-provider
[thirdparty/pdns.git] / pdns / syncres.cc
CommitLineData
86c152f2 1/*
6edbf68a
PL
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
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.
8 *
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.
12 *
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.
17 *
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.
21 */
870a0fe4
AT
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
fa8fd4d2 25
86c152f2 26#include "arguments.hh"
6dfff36f 27#include "cachecleaner.hh"
51e2144e 28#include "dns_random.hh"
6dfff36f
RG
29#include "dnsparser.hh"
30#include "dnsrecords.hh"
376effcf 31#include "ednssubnet.hh"
6dfff36f
RG
32#include "logger.hh"
33#include "lua-recursor4.hh"
ad42489c 34#include "rec-lua-conf.hh"
6dfff36f 35#include "syncres.hh"
1e332f68 36#include "dnsseckeeper.hh"
4d2be65d 37#include "validate-recursor.hh"
6dfff36f 38
a712cb56 39thread_local SyncRes::ThreadLocalStorage SyncRes::t_sstorage;
be9078b3 40thread_local std::unique_ptr<addrringbuf_t> t_timeouts;
bb4bdbaf 41
3337c2f7
RG
42std::unordered_set<DNSName> SyncRes::s_delegationOnly;
43std::unique_ptr<NetmaskGroup> SyncRes::s_dontQuery{nullptr};
2fe3354d
CH
44NetmaskGroup SyncRes::s_ednslocalsubnets;
45NetmaskGroup SyncRes::s_ednsremotesubnets;
3337c2f7 46SuffixMatchNode SyncRes::s_ednsdomains;
8a3a3822 47EDNSSubnetOpts SyncRes::s_ecsScopeZero;
3337c2f7
RG
48string SyncRes::s_serverID;
49SyncRes::LogMode SyncRes::s_lm;
123da0f8 50const std::unordered_set<uint16_t> SyncRes::s_redirectionQTypes = {QType::CNAME, QType::DNAME};
3337c2f7 51
a9af3782 52unsigned int SyncRes::s_maxnegttl;
b9473937 53unsigned int SyncRes::s_maxbogusttl;
c3e753c7 54unsigned int SyncRes::s_maxcachettl;
3337c2f7
RG
55unsigned int SyncRes::s_maxqperq;
56unsigned int SyncRes::s_maxtotusec;
57unsigned int SyncRes::s_maxdepth;
58unsigned int SyncRes::s_minimumTTL;
5cf4b2e7 59unsigned int SyncRes::s_minimumECSTTL;
1051f8a9
BH
60unsigned int SyncRes::s_packetcachettl;
61unsigned int SyncRes::s_packetcacheservfailttl;
628e2c7b
PA
62unsigned int SyncRes::s_serverdownmaxfails;
63unsigned int SyncRes::s_serverdownthrottletime;
e7861cc4 64unsigned int SyncRes::s_ecscachelimitttl;
e9a628a2 65std::atomic<uint64_t> SyncRes::s_authzonequeries;
aebb81e4 66std::atomic<uint64_t> SyncRes::s_queries;
67std::atomic<uint64_t> SyncRes::s_outgoingtimeouts;
68std::atomic<uint64_t> SyncRes::s_outgoing4timeouts;
69std::atomic<uint64_t> SyncRes::s_outgoing6timeouts;
70std::atomic<uint64_t> SyncRes::s_outqueries;
71std::atomic<uint64_t> SyncRes::s_tcpoutqueries;
72std::atomic<uint64_t> SyncRes::s_throttledqueries;
73std::atomic<uint64_t> SyncRes::s_dontqueries;
c701672a 74std::atomic<uint64_t> SyncRes::s_qnameminfallbacksuccess;
aebb81e4 75std::atomic<uint64_t> SyncRes::s_nodelegated;
76std::atomic<uint64_t> SyncRes::s_unreachables;
d6923beb 77std::atomic<uint64_t> SyncRes::s_ecsqueries;
78std::atomic<uint64_t> SyncRes::s_ecsresponses;
c9783016
RG
79std::map<uint8_t, std::atomic<uint64_t>> SyncRes::s_ecsResponsesBySubnetSize4;
80std::map<uint8_t, std::atomic<uint64_t>> SyncRes::s_ecsResponsesBySubnetSize6;
81
e9f9b8ec
RG
82uint8_t SyncRes::s_ecsipv4limit;
83uint8_t SyncRes::s_ecsipv6limit;
fd8898fb 84uint8_t SyncRes::s_ecsipv4cachelimit;
85uint8_t SyncRes::s_ecsipv6cachelimit;
ed9019c9 86
996c89cc 87bool SyncRes::s_doIPv6;
1051f8a9 88bool SyncRes::s_nopacketcache;
01402d56 89bool SyncRes::s_rootNXTrust;
3337c2f7 90bool SyncRes::s_noEDNS;
116d1288 91bool SyncRes::s_qnameminimization;
d40a915b 92SyncRes::HardenNXD SyncRes::s_hardenNXD;
c836dc19 93
e6a9dde5 94#define LOG(x) if(d_lm == Log) { g_log <<Logger::Warning << x; } else if(d_lm == Store) { d_trace << x; }
728485ca 95
69cbdef9 96static void accountAuthLatency(int usec, int family)
11adfdd3 97{
7b75810e 98 if(family == AF_INET) {
99 if(usec < 1000)
100 g_stats.auth4Answers0_1++;
101 else if(usec < 10000)
102 g_stats.auth4Answers1_10++;
103 else if(usec < 100000)
104 g_stats.auth4Answers10_100++;
105 else if(usec < 1000000)
106 g_stats.auth4Answers100_1000++;
107 else
108 g_stats.auth4AnswersSlow++;
109 } else {
110 if(usec < 1000)
111 g_stats.auth6Answers0_1++;
112 else if(usec < 10000)
113 g_stats.auth6Answers1_10++;
114 else if(usec < 100000)
115 g_stats.auth6Answers10_100++;
116 else if(usec < 1000000)
117 g_stats.auth6Answers100_1000++;
118 else
119 g_stats.auth6AnswersSlow++;
120 }
121
11adfdd3 122}
123
4465e941 124
14d9aade 125SyncRes::SyncRes(const struct timeval& now) : d_authzonequeries(0), d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
30ee601a 126 d_totUsec(0), d_now(now),
116d1288
OM
127 d_cacheonly(false), d_doDNSSEC(false), d_doEDNS0(false), d_qNameMinimization(s_qnameminimization), d_lm(s_lm)
128
129{
ac0e821b
BH
130}
131
728485ca 132/** everything begins here - this is the entry point just after receiving a packet */
e325f20c 133int SyncRes::beginResolve(const DNSName &qname, const QType &qtype, uint16_t qclass, vector<DNSRecord>&ret)
728485ca 134{
4d2be65d 135 vState state = Indeterminate;
c836dc19 136 s_queries++;
3762e821 137 d_wasVariable=false;
9fc36e90 138 d_wasOutOfBand=false;
710af846 139
4d2be65d 140 if (doSpecialNamesResolve(qname, qtype, qclass, ret)) {
d04ac108 141 d_queryValidationState = Insecure; // this could fool our stats into thinking a validation took place
142 return 0; // so do check before updating counters (we do now)
4d2be65d 143 }
db50a7f4 144
25e654f7
RG
145 auto qtypeCode = qtype.getCode();
146 /* rfc6895 section 3.1 */
147 if ((qtypeCode >= 128 && qtypeCode <= 254) || qtypeCode == QType::RRSIG || qtypeCode == QType::NSEC3 || qtypeCode == QType::OPT || qtypeCode == 65535) {
693dbe65 148 return -1;
3f8a73d6 149 }
710af846 150
db50a7f4
PL
151 if(qclass==QClass::ANY)
152 qclass=QClass::IN;
153 else if(qclass!=QClass::IN)
154 return -1;
8171ab83 155
db50a7f4 156 set<GetBestNSAnswer> beenthere;
51b6b728 157 int res=doResolve(qname, qtype, ret, 0, beenthere, state);
4d2be65d 158 d_queryValidationState = state;
0c43f455 159
e1636f82 160 if (shouldValidate()) {
3b54c577 161 if (d_queryValidationState != Indeterminate) {
162 g_stats.dnssecValidations++;
163 }
0c43f455
RG
164 increaseDNSSECStateCounter(d_queryValidationState);
165 }
166
db50a7f4
PL
167 return res;
168}
169
170/*! Handles all special, built-in names
171 * Fills ret with an answer and returns true if it handled the query.
172 *
d03c1b70 173 * Handles the following queries (and their ANY variants):
db50a7f4
PL
174 *
175 * - localhost. IN A
176 * - localhost. IN AAAA
177 * - 1.0.0.127.in-addr.arpa. IN PTR
178 * - 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
179 * - version.bind. CH TXT
180 * - version.pdns. CH TXT
181 * - id.server. CH TXT
c1d92d73 182 * - trustanchor.server CH TXT
0b7de4d7 183 * - negativetrustanchor.server CH TXT
db50a7f4 184 */
6dfff36f 185bool SyncRes::doSpecialNamesResolve(const DNSName &qname, const QType &qtype, const uint16_t qclass, vector<DNSRecord> &ret)
db50a7f4
PL
186{
187 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."),
0b7de4d7
PL
188 localhost("localhost."), versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns."), trustanchorserver("trustanchor.server."),
189 negativetrustanchorserver("negativetrustanchor.server.");
db50a7f4
PL
190
191 bool handled = false;
d03c1b70 192 vector<pair<QType::typeenum, string> > answers;
db50a7f4 193
d03c1b70
PL
194 if ((qname == arpa || qname == ip6_arpa) &&
195 qclass == QClass::IN) {
db50a7f4 196 handled = true;
d03c1b70
PL
197 if (qtype == QType::PTR || qtype == QType::ANY)
198 answers.push_back({QType::PTR, "localhost."});
db50a7f4
PL
199 }
200
d03c1b70
PL
201 if (qname == localhost &&
202 qclass == QClass::IN) {
db50a7f4 203 handled = true;
d03c1b70
PL
204 if (qtype == QType::A || qtype == QType::ANY)
205 answers.push_back({QType::A, "127.0.0.1"});
206 if (qtype == QType::AAAA || qtype == QType::ANY)
207 answers.push_back({QType::AAAA, "::1"});
db50a7f4
PL
208 }
209
d03c1b70
PL
210 if ((qname == versionbind || qname == idserver || qname == versionpdns) &&
211 qclass == QClass::CHAOS) {
db50a7f4 212 handled = true;
d03c1b70
PL
213 if (qtype == QType::TXT || qtype == QType::ANY) {
214 if(qname == versionbind || qname == versionpdns)
215 answers.push_back({QType::TXT, "\""+::arg()["version-string"]+"\""});
950626be 216 else if (s_serverID != "disabled")
d03c1b70
PL
217 answers.push_back({QType::TXT, "\""+s_serverID+"\""});
218 }
31ad43ab
BH
219 }
220
c1d92d73
PL
221 if (qname == trustanchorserver && qclass == QClass::CHAOS &&
222 ::arg().mustDo("allow-trust-anchor-query")) {
223 handled = true;
224 if (qtype == QType::TXT || qtype == QType::ANY) {
225 auto luaLocal = g_luaconfs.getLocal();
226 for (auto const &dsAnchor : luaLocal->dsAnchors) {
227 ostringstream ans;
228 ans<<"\"";
229 ans<<dsAnchor.first.toString(); // Explicit toString to have a trailing dot
230 for (auto const &dsRecord : dsAnchor.second) {
231 ans<<" ";
232 ans<<dsRecord.d_tag;
233 }
234 ans << "\"";
235 answers.push_back({QType::TXT, ans.str()});
236 }
237 }
238 }
239
0b7de4d7
PL
240 if (qname == negativetrustanchorserver && qclass == QClass::CHAOS &&
241 ::arg().mustDo("allow-trust-anchor-query")) {
242 handled = true;
243 if (qtype == QType::TXT || qtype == QType::ANY) {
244 auto luaLocal = g_luaconfs.getLocal();
245 for (auto const &negAnchor : luaLocal->negAnchors) {
246 ostringstream ans;
247 ans<<"\"";
248 ans<<negAnchor.first.toString(); // Explicit toString to have a trailing dot
249 if (negAnchor.second.length())
250 ans<<" "<<negAnchor.second;
251 ans << "\"";
252 answers.push_back({QType::TXT, ans.str()});
253 }
254 }
255 }
256
d03c1b70 257 if (handled && !answers.empty()) {
a9af3782 258 ret.clear();
db50a7f4
PL
259 d_wasOutOfBand=true;
260
e325f20c 261 DNSRecord dr;
db50a7f4 262 dr.d_name = qname;
e693ff5a 263 dr.d_place = DNSResourceRecord::ANSWER;
db50a7f4
PL
264 dr.d_class = qclass;
265 dr.d_ttl = 86400;
d03c1b70
PL
266 for (const auto& ans : answers) {
267 dr.d_type = ans.first;
6177a176 268 dr.d_content = DNSRecordContent::mastermake(ans.first, qclass, ans.second);
d03c1b70
PL
269 ret.push_back(dr);
270 }
a9af3782 271 }
710af846 272
db50a7f4 273 return handled;
728485ca 274}
afbe2787 275
db50a7f4 276
ab5c053d 277//! This is the 'out of band resolver', in other words, the authoritative server
3337c2f7 278void SyncRes::AuthDomain::addSOA(std::vector<DNSRecord>& records) const
e93c956b 279{
3337c2f7
RG
280 SyncRes::AuthDomain::records_t::const_iterator ziter = d_records.find(boost::make_tuple(getName(), QType::SOA));
281 if (ziter != d_records.end()) {
282 DNSRecord dr = *ziter;
283 dr.d_place = DNSResourceRecord::AUTHORITY;
284 records.push_back(dr);
5605c067 285 }
3337c2f7
RG
286 else {
287 // cerr<<qname<<": can't find SOA record '"<<getName()<<"' in our zone!"<<endl;
288 }
289}
5605c067 290
3337c2f7
RG
291int SyncRes::AuthDomain::getRecords(const DNSName& qname, uint16_t qtype, std::vector<DNSRecord>& records) const
292{
293 int result = RCode::NoError;
294 records.clear();
5605c067 295
3337c2f7
RG
296 // partial lookup
297 std::pair<records_t::const_iterator,records_t::const_iterator> range = d_records.equal_range(tie(qname));
298
299 SyncRes::AuthDomain::records_t::const_iterator ziter;
300 bool somedata = false;
301
302 for(ziter = range.first; ziter != range.second; ++ziter) {
303 somedata = true;
304
305 if(qtype == QType::ANY || ziter->d_type == qtype || ziter->d_type == QType::CNAME) {
306 // let rest of nameserver do the legwork on this one
307 records.push_back(*ziter);
308 }
309 else if (ziter->d_type == QType::NS && ziter->d_name.countLabels() > getName().countLabels()) {
310 // we hit a delegation point!
311 DNSRecord dr = *ziter;
39eb8051 312 dr.d_place=DNSResourceRecord::AUTHORITY;
3337c2f7 313 records.push_back(dr);
39eb8051 314 }
5605c067 315 }
3337c2f7
RG
316
317 if (!records.empty()) {
318 /* We have found an exact match, we're done */
319 // cerr<<qname<<": exact match in zone '"<<getName()<<"'"<<endl;
320 return result;
5605c067 321 }
3337c2f7
RG
322
323 if (somedata) {
324 /* We have records for that name, but not of the wanted qtype */
325 // cerr<<qname<<": found record in '"<<getName()<<"', but nothing of the right type, sending SOA"<<endl;
326 addSOA(records);
327
328 return result;
9e9844e2 329 }
5605c067 330
3337c2f7 331 // cerr<<qname<<": nothing found so far in '"<<getName()<<"', trying wildcards"<<endl;
c5c066bf 332 DNSName wcarddomain(qname);
3337c2f7
RG
333 while(wcarddomain != getName() && wcarddomain.chopOff()) {
334 // cerr<<qname<<": trying '*."<<wcarddomain<<"' in "<<getName()<<endl;
335 range = d_records.equal_range(boost::make_tuple(g_wildcarddnsname + wcarddomain));
336 if (range.first==range.second)
0d1e259a
BH
337 continue;
338
3337c2f7
RG
339 for(ziter = range.first; ziter != range.second; ++ziter) {
340 DNSRecord dr = *ziter;
0f05b02b 341 // if we hit a CNAME, just answer that - rest of recursor will do the needful & follow
3337c2f7 342 if(dr.d_type == qtype || qtype == QType::ANY || dr.d_type == QType::CNAME) {
e325f20c 343 dr.d_name = qname;
3337c2f7
RG
344 dr.d_place = DNSResourceRecord::ANSWER;
345 records.push_back(dr);
0d1e259a
BH
346 }
347 }
3337c2f7
RG
348
349 if (records.empty()) {
350 addSOA(records);
351 }
352
353 // cerr<<qname<<": in '"<<getName()<<"', had wildcard match on '*."<<wcarddomain<<"'"<<endl;
354 return result;
0d1e259a
BH
355 }
356
3337c2f7 357 /* Nothing for this name, no wildcard, let's see if there is some NS */
c5c066bf 358 DNSName nsdomain(qname);
3337c2f7
RG
359 while (nsdomain.chopOff() && nsdomain != getName()) {
360 range = d_records.equal_range(boost::make_tuple(nsdomain,QType::NS));
361 if(range.first == range.second)
5605c067
BH
362 continue;
363
3337c2f7
RG
364 for(ziter = range.first; ziter != range.second; ++ziter) {
365 DNSRecord dr = *ziter;
366 dr.d_place = DNSResourceRecord::AUTHORITY;
367 records.push_back(dr);
5605c067
BH
368 }
369 }
3337c2f7
RG
370
371 if(records.empty()) {
372 // cerr<<qname<<": no NS match in zone '"<<getName()<<"' either, handing out SOA"<<endl;
373 addSOA(records);
374 result = RCode::NXDomain;
5605c067 375 }
5605c067 376
3337c2f7
RG
377 return result;
378}
379
f7b8cffa 380bool SyncRes::doOOBResolve(const AuthDomain& domain, const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, int& res)
3337c2f7 381{
f7b8cffa 382 d_authzonequeries++;
e9a628a2 383 s_authzonequeries++;
f7b8cffa 384
3337c2f7 385 res = domain.getRecords(qname, qtype.getCode(), ret);
9e9844e2 386 return true;
e93c956b
BH
387}
388
3337c2f7
RG
389bool SyncRes::doOOBResolve(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int& res)
390{
391 string prefix;
392 if(doLog()) {
393 prefix=d_prefix;
394 prefix.append(depth, ' ');
395 }
396
397 DNSName authdomain(qname);
398 domainmap_t::const_iterator iter=getBestAuthZone(&authdomain);
399 if(iter==t_sstorage.domainmap->end() || !iter->second.isAuth()) {
400 LOG(prefix<<qname<<": auth storage has no zone for this query!"<<endl);
401 return false;
402 }
403
404 LOG(prefix<<qname<<": auth storage has data, zone='"<<authdomain<<"'"<<endl);
405 return doOOBResolve(iter->second, qname, qtype, ret, res);
406}
407
8949a3e0
OM
408bool SyncRes::isForwardOrAuth(const DNSName &qname) const {
409 DNSName authname(qname);
410 domainmap_t::const_iterator iter = getBestAuthZone(&authname);
411 return iter != t_sstorage.domainmap->end();
412}
413
addde5c1 414uint64_t SyncRes::doEDNSDump(int fd)
ff1872cf 415{
a3284c1a
OM
416 int newfd = dup(fd);
417 if (newfd == -1) {
418 return 0;
419 }
420 auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fdopen(newfd, "w"), fclose);
a82f68f0 421 if (!fp) {
a3284c1a 422 close(newfd);
addde5c1 423 return 0;
a82f68f0 424 }
addde5c1 425 uint64_t count = 0;
426
5e1f23ca 427 fprintf(fp.get(),"; edns from thread follows\n;\n");
a712cb56 428 for(const auto& eds : t_sstorage.ednsstatus) {
addde5c1 429 count++;
f0dbdd62 430 char tmp[26];
b9715061 431 fprintf(fp.get(), "%s\t%d\t%s", eds.address.toString().c_str(), (int)eds.mode, ctime_r(&eds.modeSetAt, tmp));
ff1872cf 432 }
addde5c1 433 return count;
ff1872cf
BH
434}
435
9065eb05
RG
436uint64_t SyncRes::doDumpNSSpeeds(int fd)
437{
a3284c1a
OM
438 int newfd = dup(fd);
439 if (newfd == -1) {
9065eb05 440 return 0;
a3284c1a
OM
441 }
442 auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fdopen(newfd, "w"), fclose);
443 if (!fp) {
444 close(newfd);
445 return 0;
446 }
5e1f23ca 447 fprintf(fp.get(), "; nsspeed dump from thread follows\n;\n");
9065eb05
RG
448 uint64_t count=0;
449
a712cb56 450 for(const auto& i : t_sstorage.nsSpeeds)
9065eb05
RG
451 {
452 count++;
a2d65f83 453
454 // an <empty> can appear hear in case of authoritative (hosted) zones
5e1f23ca 455 fprintf(fp.get(), "%s -> ", i.first.toLogString().c_str());
9065eb05
RG
456 for(const auto& j : i.second.d_collection)
457 {
458 // typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
5e1f23ca 459 fprintf(fp.get(), "%s/%f ", j.first.toString().c_str(), j.second.peek());
9065eb05 460 }
5e1f23ca 461 fprintf(fp.get(), "\n");
9065eb05 462 }
9065eb05
RG
463 return count;
464}
465
c1e20fba 466uint64_t SyncRes::doDumpThrottleMap(int fd)
467{
a3284c1a
OM
468 int newfd = dup(fd);
469 if (newfd == -1) {
470 return 0;
471 }
472 auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fdopen(newfd, "w"), fclose);
473 if (!fp) {
474 close(newfd);
c1e20fba 475 return 0;
a3284c1a 476 }
5e1f23ca
RG
477 fprintf(fp.get(), "; throttle map dump follows\n");
478 fprintf(fp.get(), "; remote IP\tqname\tqtype\tcount\tttd\n");
c1e20fba 479 uint64_t count=0;
480
96e2f64f 481 const auto& throttleMap = t_sstorage.throttle.getThrottleMap();
b9715061 482 for(const auto i : throttleMap)
c1e20fba 483 {
484 count++;
f0dbdd62 485 char tmp[26];
96e2f64f 486 // remote IP, dns name, qtype, count, ttd
b9715061 487 fprintf(fp.get(), "%s\t%s\t%d\t%u\t%s", i.thing.get<0>().toString().c_str(), i.thing.get<1>().toLogString().c_str(), i.thing.get<2>(), i.count, ctime_r(&i.ttd, tmp));
c1e20fba 488 }
5e1f23ca 489
c1e20fba 490 return count;
491}
492
60e5208a
OM
493uint64_t SyncRes::doDumpFailedServers(int fd)
494{
a3284c1a
OM
495 int newfd = dup(fd);
496 if (newfd == -1) {
60e5208a 497 return 0;
a3284c1a
OM
498 }
499 auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fdopen(newfd, "w"), fclose);
500 if (!fp) {
501 close(newfd);
502 return 0;
503 }
60e5208a
OM
504 fprintf(fp.get(), "; failed servers dump follows\n");
505 fprintf(fp.get(), "; remote IP\tcount\ttimestamp\n");
506 uint64_t count=0;
507
508 for(const auto& i : t_sstorage.fails.getMap())
509 {
510 count++;
511 char tmp[26];
b9715061
OM
512 ctime_r(&i.last, tmp);
513 fprintf(fp.get(), "%s\t%lld\t%s", i.address.toString().c_str(),
514 static_cast<long long>(i.value), tmp);
60e5208a
OM
515 }
516
517 return count;
518}
519
9d534f2a 520/* so here is the story. First we complete the full resolution process for a domain name. And only THEN do we decide
521 to also do DNSSEC validation, which leads to new queries. To make this simple, we *always* ask for DNSSEC records
522 so that if there are RRSIGs for a name, we'll have them.
523
524 However, some hosts simply can't answer questions which ask for DNSSEC. This can manifest itself as:
525 * No answer
526 * FormErr
527 * Nonsense answer
528
529 The cause of "No answer" may be fragmentation, and it is tempting to probe if smaller answers would get through.
530 Another cause of "No answer" may simply be a network condition.
531 Nonsense answers are a clearer indication this host won't be able to do DNSSEC evah.
532
533 Previous implementations have suffered from turning off DNSSEC questions for an authoritative server based on timeouts.
534 A clever idea is to only turn off DNSSEC if we know a domain isn't signed anyhow. The problem with that really
535 clever idea however is that at this point in PowerDNS, we may simply not know that yet. All the DNSSEC thinking happens
536 elsewhere. It may not have happened yet.
537
538 For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish.
539*/
540
6de48f75 541int SyncRes::asyncresolveWrapper(const ComboAddress& ip, bool ednsMANDATORY, const DNSName& domain, const DNSName& auth, int type, bool doTCP, bool sendRDQuery, struct timeval* now, boost::optional<Netmask>& srcmask, LWResult* res, bool* chained) const
81883dcc
BH
542{
543 /* what is your QUEST?
57769f13 544 the goal is to get as many remotes as possible on the highest level of EDNS support
81883dcc
BH
545 The levels are:
546
81883dcc 547 0) UNKNOWN Unknown state
57769f13 548 1) EDNS: Honors EDNS0
549 2) EDNSIGNORANT: Ignores EDNS0, gives replies without EDNS0
269ac73d 550 3) NOEDNS: Generates FORMERR on EDNS queries
81883dcc
BH
551
552 Everybody starts out assumed to be '0'.
57769f13 553 If '0', send out EDNS0
554 If you FORMERR us, go to '3',
555 If no EDNS in response, go to '2'
556 If '1', send out EDNS0
557 If FORMERR, downgrade to 3
558 If '2', keep on including EDNS0, see what happens
81883dcc 559 Same behaviour as 0
57769f13 560 If '3', send bare queries
81883dcc
BH
561 */
562
b9715061
OM
563 auto ednsstatus = t_sstorage.ednsstatus.insert(ip).first; // does this include port? YES
564 auto &ind = t_sstorage.ednsstatus.get<ComboAddress>();
90e8ea71 565 if (ednsstatus->modeSetAt && ednsstatus->modeSetAt + 3600 < d_now.tv_sec) {
b9715061 566 t_sstorage.ednsstatus.reset(ind, ednsstatus);
77499b05 567 // cerr<<"Resetting EDNS Status for "<<ip.toString()<<endl);
81883dcc
BH
568 }
569
b9715061
OM
570 const SyncRes::EDNSStatus::EDNSMode *mode = &ednsstatus->mode;
571 const SyncRes::EDNSStatus::EDNSMode oldmode = *mode;
fe61f5d8 572 int EDNSLevel = 0;
4898a348
RG
573 auto luaconfsLocal = g_luaconfs.getLocal();
574 ResolveContext ctx;
575#ifdef HAVE_PROTOBUF
576 ctx.d_initialRequestId = d_initialRequestId;
577#endif
6de48f75
OM
578#ifdef HAVE_FSTRM
579 ctx.d_auth = auth;
580#endif
81883dcc
BH
581
582 int ret;
ff1872cf 583 for(int tries = 0; tries < 3; ++tries) {
e325f20c 584 // cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl;
57769f13 585
90e8ea71 586 if (*mode == EDNSStatus::NOEDNS) {
81883dcc 587 g_stats.noEdnsOutQueries++;
9d534f2a 588 EDNSLevel = 0; // level != mode
81883dcc 589 }
90e8ea71 590 else if (ednsMANDATORY || *mode == EDNSStatus::UNKNOWN || *mode == EDNSStatus::EDNSOK || *mode == EDNSStatus::EDNSIGNORANT)
9d534f2a 591 EDNSLevel = 1;
30ee601a 592
c1c29961
PL
593 DNSName sendQname(domain);
594 if (g_lowercaseOutgoing)
595 sendQname.makeUsLowerCase();
596
30ee601a 597 if (d_asyncResolve) {
0bd2e252 598 ret = d_asyncResolve(ip, sendQname, type, doTCP, sendRDQuery, EDNSLevel, now, srcmask, ctx, res, chained);
30ee601a
RG
599 }
600 else {
b9fa43e0 601 ret=asyncresolve(ip, sendQname, type, doTCP, sendRDQuery, EDNSLevel, now, srcmask, ctx, d_outgoingProtobufServers, d_frameStreamServers, luaconfsLocal->outgoingProtobufExportConfig.exportTypes, res, chained);
30ee601a 602 }
90e8ea71 603 // ednsstatus might be cleared, so do a new lookup
b9715061 604 ednsstatus = t_sstorage.ednsstatus.insert(ip).first;
90e8ea71 605 mode = &ednsstatus->mode;
9d534f2a 606 if(ret < 0) {
607 return ret; // transport error, nothing to learn here
608 }
57769f13 609
9d534f2a 610 if(ret == 0) { // timeout, not doing anything with it now
81883dcc
BH
611 return ret;
612 }
90e8ea71 613 else if (*mode == EDNSStatus::UNKNOWN || *mode == EDNSStatus::EDNSOK || *mode == EDNSStatus::EDNSIGNORANT ) {
27ae17df 614 if(res->d_validpacket && !res->d_haveEDNS && res->d_rcode == RCode::FormErr) {
2189085d 615 // cerr<<"Downgrading to NOEDNS because of "<<RCode::to_s(res->d_rcode)<<" for query to "<<ip.toString()<<" for '"<<domain<<"'"<<endl;
b9715061 616 t_sstorage.ednsstatus.setMode(ind, ednsstatus, EDNSStatus::NOEDNS);
4957a608 617 continue;
81883dcc 618 }
81883dcc 619 else if(!res->d_haveEDNS) {
90e8ea71 620 if (*mode != EDNSStatus::EDNSIGNORANT) {
b9715061 621 t_sstorage.ednsstatus.setMode(ind, ednsstatus, EDNSStatus::EDNSIGNORANT);
269ac73d 622 // cerr<<"We find that "<<ip.toString()<<" is an EDNS-ignorer for '"<<domain<<"', moving to mode 2"<<endl;
57769f13 623 }
81883dcc 624 }
57769f13 625 else {
b9715061 626 t_sstorage.ednsstatus.setMode(ind, ednsstatus, EDNSStatus::EDNSOK);
e325f20c 627 // cerr<<"We find that "<<ip.toString()<<" is EDNS OK!"<<endl;
81883dcc 628 }
57769f13 629
81883dcc 630 }
90e8ea71 631 if (oldmode != *mode || !ednsstatus->modeSetAt)
b9715061 632 t_sstorage.ednsstatus.setTS(ind, ednsstatus, d_now.tv_sec);
e325f20c 633 // cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", new mode: "<<mode<<endl;
81883dcc
BH
634 return ret;
635 }
636 return ret;
637}
638
116d1288
OM
639#define QLOG(x) LOG(prefix << " child=" << child << ": " << x << endl)
640
641int SyncRes::doResolve(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, set<GetBestNSAnswer>& beenthere, vState& state) {
642
8949a3e0 643 if (!getQNameMinimization() || isForwardOrAuth(qname)) {
116d1288
OM
644 return doResolveNoQNameMinimization(qname, qtype, ret, depth, beenthere, state);
645 }
646
647 // The qname minimization algorithm is a simplified version of the one in RFC 7816 (bis).
648 // It could be simplified because the cache maintenance (both positive and negative)
649 // is already done by doResolveNoQNameMinimization().
650 //
651 // Sketch of algorithm:
652 // Check cache
653 // If result found: done
654 // Otherwise determine closes ancestor from cache data
655 // Repeat querying A, adding more labels of the original qname
656 // If we get a delegation continue at ancestor determination
657 // Until we have the full name.
658 //
659 // The algorithm starts with adding a single label per iteration, and
660 // moves to three labels per iteration after three iterations.
661
662 DNSName child;
663 string prefix = d_prefix;
664 prefix.append(depth, ' ');
665 prefix.append(string("QM ") + qname.toString() + "|" + qtype.getName());
666
667 QLOG("doResolve");
668
669 // Look in cache only
670 vector<DNSRecord> retq;
671 bool old = setCacheOnly(true);
672 bool fromCache = false;
673 int res = doResolveNoQNameMinimization(qname, qtype, retq, depth + 1, beenthere, state, &fromCache);
674 setCacheOnly(old);
675 if (fromCache) {
676 QLOG("Step0 Found in cache");
677 ret.insert(ret.end(), retq.begin(), retq.end());
678 return res;
679 }
680 QLOG("Step0 Not cached");
681
682 const unsigned int qnamelen = qname.countLabels();
683
684 for (unsigned int i = 0; i <= qnamelen; ) {
685
686 // Step 1
687 vector<DNSRecord> bestns;
688 // the two retries allow getBestNSFromCache&co to reprime the root
689 // hints, in case they ever go missing
690 for (int tries = 0; tries < 2 && bestns.empty(); ++tries) {
691 bool flawedNSSet = false;
692 set<GetBestNSAnswer> beenthereIgnored;
693 getBestNSFromCache(qname, qtype, bestns, &flawedNSSet, depth + 1, beenthereIgnored);
694 }
239c8386
OM
695
696 if (bestns.size() == 0) {
697 // Something terrible is wrong
116d1288
OM
698 QLOG("Step1 No ancestor found return ServFail");
699 return RCode::ServFail;
700 }
701
239c8386
OM
702 const DNSName& ancestor(bestns[0].d_name);
703 QLOG("Step1 Ancestor from cache is " << ancestor.toString());
116d1288
OM
704 child = ancestor;
705
706 unsigned int targetlen = std::min(child.countLabels() + (i > 3 ? 3 : 1), qnamelen);
707
708 for (; i <= qnamelen; i++) {
709 // Step 2
710 while (child.countLabels() < targetlen) {
711 child.prependRawLabel(qname.getRawLabel(qnamelen - child.countLabels() - 1));
712 }
713 targetlen += i > 3 ? 3 : 1;
714 targetlen = std::min(targetlen, qnamelen);
715
716 QLOG("Step2 New child");
717
718 // Step 3 resolve
719 if (child == qname) {
720 QLOG("Step3 Going to do final resolve");
721 res = doResolveNoQNameMinimization(qname, qtype, ret, depth + 1, beenthere, state);
239c8386 722 QLOG("Step3 Final resolve: " << RCode::to_s(res) << "/" << ret.size());
116d1288
OM
723 return res;
724 }
725
726 // Step 6
727 QLOG("Step4 Resolve A for child");
728 retq.resize(0);
729 StopAtDelegation stopAtDelegation = Stop;
730 res = doResolveNoQNameMinimization(child, QType::A, retq, depth + 1, beenthere, state, NULL, &stopAtDelegation);
731 QLOG("Step4 Resolve A result is " << RCode::to_s(res) << "/" << retq.size() << "/" << stopAtDelegation);
732 if (stopAtDelegation == Stopped) {
733 QLOG("Delegation seen, continue at step 1");
734 break;
735 }
736 if (res != RCode::NoError) {
737 // Case 5: unexpected answer
738 QLOG("Step5: other rcode, last effort final resolve");
739 setQNameMinimization(false);
740 res = doResolveNoQNameMinimization(qname, qtype, ret, depth + 1, beenthere, state);
c701672a 741
742 if(res == RCode::NoError) {
743 s_qnameminfallbacksuccess++;
744 }
745
239c8386 746 QLOG("Step5 End resolve: " << RCode::to_s(res) << "/" << ret.size());
116d1288
OM
747 return res;
748 }
749 }
750 }
751
752 // Should not be reached
753 QLOG("Max iterations reached, return ServFail");
754 return RCode::ServFail;
755}
756
b88526ce
PL
757/*! This function will check the cache and go out to the internet if the answer is not in cache
758 *
759 * \param qname The name we need an answer for
760 * \param qtype
761 * \param ret The vector of DNSRecords we need to fill with the answers
762 * \param depth The recursion depth we are in
763 * \param beenthere
239c8386
OM
764 * \param fromCache tells the caller the result came from the cache, may be nullptr
765 * \param stopAtDelegation if non-nullptr and pointed-to value is Stop requests the callee to stop at a delegation, if so pointed-to value is set to Stopped
b88526ce
PL
766 * \return DNS RCODE or -1 (Error) or -2 (RPZ hit)
767 */
116d1288 768int SyncRes::doResolveNoQNameMinimization(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, set<GetBestNSAnswer>& beenthere, vState& state, bool *fromCache, StopAtDelegation *stopAtDelegation)
afbe2787 769{
ded77b10 770 string prefix;
77499b05 771 if(doLog()) {
ded77b10
BH
772 prefix=d_prefix;
773 prefix.append(depth, ' ');
774 }
b8470add 775
4d2be65d
RG
776 LOG(prefix<<qname<<": Wants "<< (d_doDNSSEC ? "" : "NO ") << "DNSSEC processing, "<<(d_requireAuthData ? "" : "NO ")<<"auth data in query for "<<qtype.getName()<<endl);
777
778 state = Indeterminate;
710af846 779
7c3398aa
RG
780 if(s_maxdepth && depth > s_maxdepth)
781 throw ImmediateServFailException("More than "+std::to_string(s_maxdepth)+" (max-recursion-depth) levels of recursion needed while resolving "+qname.toLogString());
782
f4df5e89 783 int res=0;
b88526ce
PL
784
785 // This is a difficult way of expressing "this is a normal query", i.e. not getRootNS.
0b29b9c5 786 if(!(d_updatingRootNS && qtype.getCode()==QType::NS && qname.isRoot())) {
115d07ad 787 if(d_cacheonly) { // very limited OOB support
263f6a5a 788 LWResult lwr;
2189085d 789 LOG(prefix<<qname<<": Recursion not requested for '"<<qname<<"|"<<qtype.getName()<<"', peeking at auth/forward zones"<<endl);
c5c066bf 790 DNSName authname(qname);
115d07ad 791 domainmap_t::const_iterator iter=getBestAuthZone(&authname);
a712cb56 792 if(iter != t_sstorage.domainmap->end()) {
3337c2f7 793 if(iter->second.isAuth()) {
4957a608 794 ret.clear();
9fc36e90 795 d_wasOutOfBand = doOOBResolve(qname, qtype, ret, depth, res);
116d1288
OM
796 if (fromCache)
797 *fromCache = d_wasOutOfBand;
4957a608
BH
798 return res;
799 }
800 else {
3337c2f7 801 const vector<ComboAddress>& servers = iter->second.d_servers;
4957a608 802 const ComboAddress remoteIP = servers.front();
2189085d 803 LOG(prefix<<qname<<": forwarding query to hardcoded nameserver '"<< remoteIP.toStringWithPort()<<"' for zone '"<<authname<<"'"<<endl);
4957a608 804
6148fa97 805 boost::optional<Netmask> nm;
deca7d8f 806 bool chained = false;
6de48f75 807 res=asyncresolveWrapper(remoteIP, d_doDNSSEC, qname, authname, qtype.getCode(), false, false, &d_now, nm, &lwr, &chained);
fabef7e0 808
809 d_totUsec += lwr.d_usec;
810 accountAuthLatency(lwr.d_usec, remoteIP.sin4.sin_family);
116d1288
OM
811 if (fromCache)
812 *fromCache = true;
813
4957a608 814 // filter out the good stuff from lwr.result()
ab33a095
RG
815 if (res == 1) {
816 for(const auto& rec : lwr.d_records) {
817 if(rec.d_place == DNSResourceRecord::ANSWER)
818 ret.push_back(rec);
819 }
820 return 0;
821 }
822 else {
823 return RCode::ServFail;
4957a608 824 }
4957a608 825 }
115d07ad
BH
826 }
827 }
828
e1636f82
RG
829 DNSName authname(qname);
830 bool wasForwardedOrAuthZone = false;
831 bool wasAuthZone = false;
ad797d94 832 bool wasForwardRecurse = false;
e1636f82
RG
833 domainmap_t::const_iterator iter = getBestAuthZone(&authname);
834 if(iter != t_sstorage.domainmap->end()) {
ad797d94 835 const auto& domain = iter->second;
e1636f82 836 wasForwardedOrAuthZone = true;
ad797d94
RG
837
838 if (domain.isAuth()) {
e1636f82 839 wasAuthZone = true;
ad797d94
RG
840 } else if (domain.shouldRecurse()) {
841 wasForwardRecurse = true;
e1636f82
RG
842 }
843 }
844
ad797d94 845 if(!d_skipCNAMECheck && doCNAMECacheCheck(qname, qtype, ret, depth, res, state, wasAuthZone, wasForwardRecurse)) { // will reroute us if needed
e1636f82 846 d_wasOutOfBand = wasAuthZone;
c836dc19 847 return res;
e1636f82 848 }
710af846 849
ad797d94 850 if(doCacheCheck(qname, authname, wasForwardedOrAuthZone, wasAuthZone, wasForwardRecurse, qtype, ret, depth, res, state)) {
e1636f82
RG
851 // we done
852 d_wasOutOfBand = wasAuthZone;
116d1288
OM
853 if (fromCache)
854 *fromCache = true;
c836dc19 855 return res;
e1636f82 856 }
c836dc19 857 }
afbe2787 858
115d07ad 859 if(d_cacheonly)
c836dc19 860 return 0;
728485ca 861
2189085d 862 LOG(prefix<<qname<<": No cache hit for '"<<qname<<"|"<<qtype.getName()<<"', trying to find an appropriate NS record"<<endl);
710af846 863
c5c066bf 864 DNSName subdomain(qname);
d8049162 865 if(qtype == QType::DS) subdomain.chopOff();
728485ca 866
fa1b87ff 867 NsSet nsset;
7305df82 868 bool flawedNSSet=false;
97df07f8 869
3cef03e9
RG
870 /* we use subdomain here instead of qname because for DS queries we only care about the state of the parent zone */
871 computeZoneCuts(subdomain, g_rootdnsname, depth);
70b3fe7a 872
97df07f8
PD
873 // the two retries allow getBestNSNamesFromCache&co to reprime the root
874 // hints, in case they ever go missing
bdf40704 875 for(int tries=0;tries<2 && nsset.empty();++tries) {
891fbf88 876 subdomain=getBestNSNamesFromCache(subdomain, qtype, nsset, &flawedNSSet, depth, beenthere); // pass beenthere to both occasions
bdf40704
BH
877 }
878
5374b03b 879 state = getValidationStatus(qname, false);
70b3fe7a 880
5374b03b 881 LOG(prefix<<qname<<": initial validation status for "<<qname<<" is "<<vStates[state]<<endl);
4d2be65d 882
116d1288 883 if(!(res=doResolveAt(nsset, subdomain, flawedNSSet, qname, qtype, ret, depth, beenthere, state, stopAtDelegation)))
728485ca 884 return 0;
3ddb9247 885
2189085d 886 LOG(prefix<<qname<<": failed (res="<<res<<")"<<endl);
b8470add
PL
887
888 if (res == -2)
889 return res;
890
20177d1d 891 return res<0 ? RCode::ServFail : res;
afbe2787
BH
892}
893
c2567ad1 894#if 0
a67dd0cf 895// for testing purposes
fdf05fd4
BH
896static bool ipv6First(const ComboAddress& a, const ComboAddress& b)
897{
898 return !(a.sin4.sin_family < a.sin4.sin_family);
899}
c2567ad1 900#endif
fdf05fd4 901
0e4675a9
RG
902struct speedOrderCA
903{
b9715061 904 speedOrderCA(std::map<ComboAddress,float>& speeds): d_speeds(speeds) {}
0e4675a9
RG
905 bool operator()(const ComboAddress& a, const ComboAddress& b) const
906 {
907 return d_speeds[a] < d_speeds[b];
908 }
b9715061 909 std::map<ComboAddress, float>& d_speeds;
0e4675a9
RG
910};
911
21f0f88b 912/** This function explicitly goes out for A or AAAA addresses
996c89cc 913*/
b4c8789a 914vector<ComboAddress> SyncRes::getAddrs(const DNSName &qname, unsigned int depth, set<GetBestNSAnswer>& beenthere, bool cacheOnly)
75b49099 915{
e325f20c 916 typedef vector<DNSRecord> res_t;
996c89cc
BH
917 typedef vector<ComboAddress> ret_t;
918 ret_t ret;
75b49099 919
116d1288 920 bool oldCacheOnly = setCacheOnly(cacheOnly);
24bb9b58 921 bool oldRequireAuthData = d_requireAuthData;
5597f804 922 bool oldValidationRequested = d_DNSSECValidationRequested;
24bb9b58 923 d_requireAuthData = false;
5597f804 924 d_DNSSECValidationRequested = false;
92011b8f 925
d11e155d 926 vState newState = Indeterminate;
b84ce13e 927 res_t resv4;
d11e155d 928 // If IPv4 ever becomes second class, we should revisit this
b84ce13e 929 if (doResolve(qname, QType::A, resv4, depth+1, beenthere, newState) == 0) { // this consults cache, OR goes out
dcdcbe7d
OM
930 for (auto const &i : resv4) {
931 if (i.d_type == QType::A) {
932 if (auto rec = getRR<ARecordContent>(i)) {
d11e155d 933 ret.push_back(rec->getCA(53));
d96e88da 934 }
42724edf 935 }
f4df5e89 936 }
493f5682
OM
937 }
938 if (s_doIPv6) {
939 if (ret.empty()) {
940 // We did not find IPv4 addresses, try to get IPv6 ones
b84ce13e
OM
941 newState = Indeterminate;
942 res_t resv6;
943 if (doResolve(qname, QType::AAAA, resv6, depth+1, beenthere, newState) == 0) { // this consults cache, OR goes out
dcdcbe7d
OM
944 for (const auto &i : resv6) {
945 if (i.d_type == QType::AAAA) {
946 if (auto rec = getRR<AAAARecordContent>(i))
493f5682
OM
947 ret.push_back(rec->getCA(53));
948 }
949 }
950 }
951 } else {
952 // We have some IPv4 records, don't bother with going out to get IPv6, but do consult the cache
953 // Once IPv6 adoption matters, this needs to be revisited
954 res_t cset;
955 if (t_RC->get(d_now.tv_sec, qname, QType(QType::AAAA), false, &cset, d_cacheRemote) > 0) {
dcdcbe7d
OM
956 for (const auto &i : cset) {
957 if (i.d_ttl > (unsigned int)d_now.tv_sec ) {
958 if (auto rec = getRR<AAAARecordContent>(i)) {
493f5682
OM
959 ret.push_back(rec->getCA(53));
960 }
961 }
962 }
60c9a54f 963 }
60c9a54f 964 }
bfea0d0b 965 }
710af846 966
24bb9b58 967 d_requireAuthData = oldRequireAuthData;
5597f804 968 d_DNSSECValidationRequested = oldValidationRequested;
116d1288 969 setCacheOnly(oldCacheOnly);
24bb9b58 970
c767798a
RG
971 /* we need to remove from the nsSpeeds collection the existing IPs
972 for this nameserver that are no longer in the set, even if there
973 is only one or none at all in the current set.
974 */
b9715061 975 map<ComboAddress, float> speeds;
133b4cfc
OM
976 auto& collection = t_sstorage.nsSpeeds[qname];
977 float factor = collection.getFactor(d_now);
c767798a 978 for(const auto& val: ret) {
133b4cfc 979 speeds[val] = collection.d_collection[val].get(factor);
c767798a 980 }
996c89cc 981
c767798a 982 t_sstorage.nsSpeeds[qname].purge(speeds);
996c89cc 983
c767798a 984 if(ret.size() > 1) {
feccaf7f 985 random_shuffle(ret.begin(), ret.end());
0e4675a9
RG
986 speedOrderCA so(speeds);
987 stable_sort(ret.begin(), ret.end(), so);
988
989 if(doLog()) {
990 string prefix=d_prefix;
991 prefix.append(depth, ' ');
992 LOG(prefix<<"Nameserver "<<qname<<" IPs: ");
993 bool first = true;
994 for(const auto& addr : ret) {
995 if (first) {
996 first = false;
4957a608 997 }
0e4675a9
RG
998 else {
999 LOG(", ");
1000 }
1001 LOG((addr.toString())<<"(" << (boost::format("%0.2f") % (speeds[addr]/1000.0)).str() <<"ms)");
996c89cc 1002 }
0e4675a9
RG
1003 LOG(endl);
1004 }
996c89cc 1005 }
fdf05fd4 1006
728485ca 1007 return ret;
75b49099
BH
1008}
1009
7c3398aa 1010void SyncRes::getBestNSFromCache(const DNSName &qname, const QType& qtype, vector<DNSRecord>& bestns, bool* flawedNSSet, unsigned int depth, set<GetBestNSAnswer>& beenthere)
86c152f2 1011{
c5c066bf
PD
1012 string prefix;
1013 DNSName subdomain(qname);
77499b05 1014 if(doLog()) {
ded77b10
BH
1015 prefix=d_prefix;
1016 prefix.append(depth, ' ');
1017 }
75b49099 1018 bestns.clear();
2b1b4054 1019 bool brokeloop;
75b49099 1020 do {
2b1b4054 1021 brokeloop=false;
2189085d 1022 LOG(prefix<<qname<<": Checking if we have NS in cache for '"<<subdomain<<"'"<<endl);
e325f20c 1023 vector<DNSRecord> ns;
7305df82 1024 *flawedNSSet = false;
4d2be65d 1025
2fe3354d 1026 if(t_RC->get(d_now.tv_sec, subdomain, QType(QType::NS), false, &ns, d_cacheRemote) > 0) {
feccaf7f
RG
1027 bestns.reserve(ns.size());
1028
e325f20c 1029 for(auto k=ns.cbegin();k!=ns.cend(); ++k) {
1030 if(k->d_ttl > (unsigned int)d_now.tv_sec ) {
1031 vector<DNSRecord> aset;
4957a608 1032
e325f20c 1033 const DNSRecord& dr=*k;
ba3c54cb
RG
1034 auto nrr = getRR<NSRecordContent>(dr);
1035 if(nrr && (!nrr->getNS().isPartOf(subdomain) || t_RC->get(d_now.tv_sec, nrr->getNS(), s_doIPv6 ? QType(QType::ADDR) : QType(QType::A),
2fe3354d 1036 false, doLog() ? &aset : 0, d_cacheRemote) > 5)) {
e325f20c 1037 bestns.push_back(dr);
2189085d
PL
1038 LOG(prefix<<qname<<": NS (with ip, or non-glue) in cache for '"<<subdomain<<"' -> '"<<nrr->getNS()<<"'"<<endl);
1039 LOG(prefix<<qname<<": within bailiwick: "<< nrr->getNS().isPartOf(subdomain));
4957a608 1040 if(!aset.empty()) {
e325f20c 1041 LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset.begin()->d_ttl- d_now.tv_sec ))<<endl);
4957a608
BH
1042 }
1043 else {
77499b05 1044 LOG(", not in cache / did not look at cache"<<endl);
4957a608
BH
1045 }
1046 }
1047 else {
1048 *flawedNSSet=true;
e325f20c 1049 LOG(prefix<<qname<<": NS in cache for '"<<subdomain<<"', but needs glue ("<<nrr->getNS()<<") which we miss or is expired"<<endl);
4957a608
BH
1050 }
1051 }
afbe2787 1052 }
4d2be65d 1053
75b49099 1054 if(!bestns.empty()) {
4957a608 1055 GetBestNSAnswer answer;
891fbf88 1056 answer.qname=qname;
1057 answer.qtype=qtype.getCode();
38c2ba02
RG
1058 for(const auto& dr : bestns) {
1059 if (auto nsContent = getRR<NSRecordContent>(dr)) {
1060 answer.bestns.insert(make_pair(dr.d_name, nsContent->getNS()));
1061 }
1062 }
891fbf88 1063
6493dfc0
RG
1064 auto insertionPair = beenthere.insert(std::move(answer));
1065 if(!insertionPair.second) {
2b1b4054 1066 brokeloop=true;
2189085d 1067 LOG(prefix<<qname<<": We have NS in cache for '"<<subdomain<<"' but part of LOOP (already seen "<<answer.qname<<")! Trying less specific NS"<<endl);
e325f20c 1068 ;
77499b05
BH
1069 if(doLog())
1070 for( set<GetBestNSAnswer>::const_iterator j=beenthere.begin();j!=beenthere.end();++j) {
6493dfc0 1071 bool neo = (j == insertionPair.first);
2189085d 1072 LOG(prefix<<qname<<": beenthere"<<(neo?"*":"")<<": "<<j->qname<<"|"<<DNSRecordContent::NumberToType(j->qtype)<<" ("<<(unsigned int)j->bestns.size()<<")"<<endl);
77499b05 1073 }
4957a608
BH
1074 bestns.clear();
1075 }
1076 else {
2189085d 1077 LOG(prefix<<qname<<": We have NS in cache for '"<<subdomain<<"' (flawedNSSet="<<*flawedNSSet<<")"<<endl);
4957a608
BH
1078 return;
1079 }
75b49099 1080 }
afbe2787 1081 }
2189085d 1082 LOG(prefix<<qname<<": no valid/useful NS in cache for '"<<subdomain<<"'"<<endl);
4d2be65d 1083
52683ca3 1084 if(subdomain.isRoot() && !brokeloop) {
7836f7b4 1085 // We lost the root NS records
3ddb9247 1086 primeHints();
159b1242 1087 primeRootNSZones(g_dnssecmode != DNSSECMode::Off);
2189085d 1088 LOG(prefix<<qname<<": reprimed the root"<<endl);
0b29b9c5
RG
1089 /* let's prevent an infinite loop */
1090 if (!d_updatingRootNS) {
1091 getRootNS(d_now, d_asyncResolve);
1092 }
6576051d 1093 }
4d2be65d 1094 } while(subdomain.chopOff());
75b49099
BH
1095}
1096
69cbdef9 1097SyncRes::domainmap_t::const_iterator SyncRes::getBestAuthZone(DNSName* qname) const
5605c067 1098{
6493dfc0
RG
1099 if (t_sstorage.domainmap->empty()) {
1100 return t_sstorage.domainmap->end();
1101 }
1102
5605c067
BH
1103 SyncRes::domainmap_t::const_iterator ret;
1104 do {
a712cb56
RG
1105 ret=t_sstorage.domainmap->find(*qname);
1106 if(ret!=t_sstorage.domainmap->end())
5605c067 1107 break;
c5c066bf 1108 }while(qname->chopOff());
5605c067
BH
1109 return ret;
1110}
288f4aa9 1111
7bf26383 1112/** doesn't actually do the work, leaves that to getBestNSFromCache */
7c3398aa 1113DNSName SyncRes::getBestNSNamesFromCache(const DNSName &qname, const QType& qtype, NsSet& nsset, bool* flawedNSSet, unsigned int depth, set<GetBestNSAnswer>&beenthere)
75b49099 1114{
c5c066bf 1115 DNSName authdomain(qname);
3ddb9247 1116
5605c067 1117 domainmap_t::const_iterator iter=getBestAuthZone(&authdomain);
a712cb56 1118 if(iter!=t_sstorage.domainmap->end()) {
3337c2f7 1119 if( iter->second.isAuth() )
fa1b87ff
PL
1120 // this gets picked up in doResolveAt, the empty DNSName, combined with the
1121 // empty vector means 'we are auth for this zone'
1122 nsset.insert({DNSName(), {{}, false}});
2e5ae2b2 1123 else {
fa1b87ff
PL
1124 // Again, picked up in doResolveAt. An empty DNSName, combined with a
1125 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
6dfff36f 1126 // This is actually picked up in retrieveAddressesForNS called from doResolveAt.
3337c2f7 1127 nsset.insert({DNSName(), {iter->second.d_servers, iter->second.shouldRecurse() }});
2e5ae2b2 1128 }
5605c067
BH
1129 return authdomain;
1130 }
1131
6493dfc0 1132 DNSName subdomain(qname);
e325f20c 1133 vector<DNSRecord> bestns;
891fbf88 1134 getBestNSFromCache(subdomain, qtype, bestns, flawedNSSet, depth, beenthere);
75b49099 1135
e325f20c 1136 for(auto k=bestns.cbegin() ; k != bestns.cend(); ++k) {
fa1b87ff 1137 // The actual resolver code will not even look at the ComboAddress or bool
38c2ba02
RG
1138 const auto nsContent = getRR<NSRecordContent>(*k);
1139 if (nsContent) {
1140 nsset.insert({nsContent->getNS(), {{}, false}});
1141 if(k==bestns.cbegin())
1142 subdomain=k->d_name;
1143 }
86c152f2 1144 }
75b49099 1145 return subdomain;
afbe2787
BH
1146}
1147
b9473937
RG
1148void SyncRes::updateValidationStatusInCache(const DNSName &qname, const QType& qt, bool aa, vState newState) const
1149{
1150 if (newState == Bogus) {
1151 t_RC->updateValidationStatus(d_now.tv_sec, qname, qt, d_cacheRemote, aa, newState, s_maxbogusttl + d_now.tv_sec);
1152 }
1153 else {
1154 t_RC->updateValidationStatus(d_now.tv_sec, qname, qt, d_cacheRemote, aa, newState, boost::none);
1155 }
1156}
1157
ad797d94 1158bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>& ret, unsigned int depth, int &res, vState& state, bool wasAuthZone, bool wasForwardRecurse)
afbe2787 1159{
ded77b10 1160 string prefix;
77499b05 1161 if(doLog()) {
710af846 1162 prefix=d_prefix;
ded77b10
BH
1163 prefix.append(depth, ' ');
1164 }
36f5e3db 1165
40de2910 1166 if((depth>9 && d_outqueries>10 && d_throttledqueries>5) || depth > 15) {
2189085d 1167 LOG(prefix<<qname<<": recursing (CNAME or other indirection) too deep, depth="<<depth<<endl);
c6644fc5
BH
1168 res=RCode::ServFail;
1169 return true;
1170 }
3ddb9247 1171
e325f20c 1172 vector<DNSRecord> cset;
1f77f479 1173 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
2b984251 1174 vector<std::shared_ptr<DNSRecord>> authorityRecs;
428f41b7 1175 bool wasAuth;
b9473937 1176 uint32_t capTTL = std::numeric_limits<uint32_t>::max();
d30b5493
PL
1177 DNSName foundName;
1178 QType foundQT = QType(0); // 0 == QTYPE::ENT
1179
e686a798 1180 LOG(prefix<<qname<<": Looking for CNAME cache hit of '"<<qname<<"|CNAME"<<"'"<<endl);
ad797d94 1181 /* we don't require auth data for forward-recurse lookups */
e686a798
PL
1182 if (t_RC->get(d_now.tv_sec, qname, QType(QType::CNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth) > 0) {
1183 foundName = qname;
1184 foundQT = QType(QType::CNAME);
1185 }
1186
1187 if (foundName.empty() && qname != g_rootdnsname) {
d30b5493
PL
1188 // look for a DNAME cache hit
1189 auto labels = qname.getRawLabels();
1190 DNSName dnameName(g_rootdnsname);
1191
adbd867b 1192 LOG(prefix<<qname<<": Looking for DNAME cache hit of '"<<qname<<"|DNAME' or its ancestors"<<endl);
d30b5493
PL
1193 do {
1194 dnameName.prependRawLabel(labels.back());
1195 labels.pop_back();
71e9cc53
PL
1196 if (dnameName == qname && qtype != QType::DNAME) { // The client does not want a DNAME, but we've reached the QNAME already. So there is no match
1197 break;
1198 }
d30b5493 1199 if (t_RC->get(d_now.tv_sec, dnameName, QType(QType::DNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth) > 0) {
71e9cc53
PL
1200 foundName = dnameName;
1201 foundQT = QType(QType::DNAME);
1202 break;
d30b5493
PL
1203 }
1204 } while(!labels.empty());
1205 }
36c5ee42 1206
8d11c508
PL
1207 if (foundName.empty()) {
1208 LOG(prefix<<qname<<": No CNAME or DNAME cache hit of '"<< qname <<"' found"<<endl);
1209 return false;
1210 }
1211
0de8295b
PL
1212 for(auto const &record : cset) {
1213 if (record.d_class != QClass::IN) {
8d11c508
PL
1214 continue;
1215 }
c5310862 1216
0de8295b 1217 if(record.d_ttl > (unsigned int) d_now.tv_sec) {
8d11c508
PL
1218
1219 if (!wasAuthZone && shouldValidate() && (wasAuth || wasForwardRecurse) && state == Indeterminate && d_requireAuthData) {
1220 /* This means we couldn't figure out the state when this entry was cached,
1221 most likely because we hadn't computed the zone cuts yet. */
1222 /* make sure they are computed before validating */
1223 DNSName subdomain(foundName);
1224 /* if we are retrieving a DS, we only care about the state of the parent zone */
1225 if(qtype == QType::DS)
1226 subdomain.chopOff();
1227
1228 computeZoneCuts(subdomain, g_rootdnsname, depth);
1229
1230 vState recordState = getValidationStatus(foundName, false);
1231 if (recordState == Secure) {
1232 LOG(prefix<<qname<<": got Indeterminate state from the "<<foundQT.getName()<<" cache, validating.."<<endl);
1233 state = SyncRes::validateRecordsWithSigs(depth, foundName, foundQT, foundName, cset, signatures);
1234 if (state != Indeterminate) {
1235 LOG(prefix<<qname<<": got Indeterminate state from the CNAME cache, new validation result is "<<vStates[state]<<endl);
1236 if (state == Bogus) {
1237 capTTL = s_maxbogusttl;
787737ae 1238 }
8d11c508 1239 updateValidationStatusInCache(foundName, foundQT, wasAuth, state);
787737ae 1240 }
428f41b7 1241 }
8d11c508 1242 }
428f41b7 1243
0de8295b 1244 LOG(prefix<<qname<<": Found cache "<<foundQT.getName()<<" hit for '"<< foundName << "|"<<foundQT.getName()<<"' to '"<<record.d_content->getZoneRepresentation()<<"', validation state is "<<vStates[state]<<endl);
1f77f479 1245
0de8295b 1246 DNSRecord dr = record;
8d11c508
PL
1247 dr.d_ttl -= d_now.tv_sec;
1248 dr.d_ttl = std::min(dr.d_ttl, capTTL);
1249 const uint32_t ttl = dr.d_ttl;
1250 ret.reserve(ret.size() + 2 + signatures.size() + authorityRecs.size());
1251 ret.push_back(dr);
2b984251 1252
8d11c508
PL
1253 for(const auto& signature : signatures) {
1254 DNSRecord sigdr;
1255 sigdr.d_type=QType::RRSIG;
1256 sigdr.d_name=foundName;
1257 sigdr.d_ttl=ttl;
1258 sigdr.d_content=signature;
1259 sigdr.d_place=DNSResourceRecord::ANSWER;
1260 sigdr.d_class=QClass::IN;
1261 ret.push_back(sigdr);
1262 }
4d2be65d 1263
8d11c508
PL
1264 for(const auto& rec : authorityRecs) {
1265 DNSRecord authDR(*rec);
1266 authDR.d_ttl=ttl;
1267 ret.push_back(authDR);
1268 }
d30b5493 1269
8d11c508
PL
1270 DNSName newTarget;
1271 if (foundQT == QType::DNAME) {
1272 if (qtype == QType::DNAME && qname == foundName) { // client wanted the DNAME, no need to synthesize a CNAME
d30b5493
PL
1273 res = 0;
1274 return true;
1275 }
8d11c508 1276 // Synthesize a CNAME
0de8295b 1277 auto dnameRR = getRR<DNAMERecordContent>(record);
8d11c508
PL
1278 if (dnameRR == nullptr) {
1279 throw ImmediateServFailException("Unable to get record content for "+foundName.toLogString()+"|DNAME cache entry");
1280 }
1281 const auto& dnameSuffix = dnameRR->getTarget();
1282 DNSName targetPrefix = qname.makeRelative(foundName);
1283 try {
1284 dr.d_type = QType::CNAME;
1285 dr.d_name = targetPrefix + foundName;
1286 newTarget = targetPrefix + dnameSuffix;
1287 dr.d_content = std::make_shared<CNAMERecordContent>(CNAMERecordContent(newTarget));
1288 ret.push_back(dr);
1289 } catch (const std::exception &e) {
1290 // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
1291 // But this is consistent with processRecords
1292 throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + foundName.toLogString() +
1293 "', DNAME target: '" + dnameSuffix.toLogString() + "', substituted name: '" +
1294 targetPrefix.toLogString() + "." + dnameSuffix.toLogString() +
1295 "' : " + e.what());
4957a608 1296 }
d30b5493 1297
8d11c508
PL
1298 LOG(prefix<<qname<<": Synthesized "<<dr.d_name<<"|CNAME "<<newTarget<<endl);
1299 }
4d2be65d 1300
8d11c508
PL
1301 if(qtype == QType::CNAME) { // perhaps they really wanted a CNAME!
1302 res = 0;
4957a608 1303 return true;
ac539791 1304 }
8d11c508
PL
1305
1306 // We have a DNAME _or_ CNAME cache hit and the client wants something else than those two.
1307 // Let's find the answer!
1308 if (foundQT == QType::CNAME) {
0de8295b 1309 const auto cnameContent = getRR<CNAMERecordContent>(record);
8d11c508
PL
1310 if (cnameContent == nullptr) {
1311 throw ImmediateServFailException("Unable to get record content for "+foundName.toLogString()+"|CNAME cache entry");
1312 }
1313 newTarget = cnameContent->getTarget();
1314 }
1315
1316 set<GetBestNSAnswer>beenthere;
1317 vState cnameState = Indeterminate;
1318 res = doResolve(newTarget, qtype, ret, depth+1, beenthere, cnameState);
1319 LOG(prefix<<qname<<": updating validation state for response to "<<qname<<" from "<<vStates[state]<<" with the state from the DNAME/CNAME quest: "<<vStates[cnameState]<<endl);
1320 updateValidationState(state, cnameState);
1321
1322 return true;
ac539791 1323 }
afbe2787 1324 }
8d11c508 1325 throw ImmediateServFailException("Could not determine whether or not there was a CNAME or DNAME in cache for '" + qname.toLogString() + "'");
75b49099
BH
1326}
1327
f984e703 1328namespace {
142ab370
RG
1329struct CacheEntry
1330{
1331 vector<DNSRecord> records;
1332 vector<shared_ptr<RRSIGRecordContent>> signatures;
1333 uint32_t signaturesTTL{std::numeric_limits<uint32_t>::max()};
1334};
1335struct CacheKey
1336{
1337 DNSName name;
1338 uint16_t type;
1339 DNSResourceRecord::Place place;
1340 bool operator<(const CacheKey& rhs) const {
186e99c9 1341 return tie(type, place, name) < tie(rhs.type, rhs.place, rhs.name);
142ab370
RG
1342 }
1343};
1344typedef map<CacheKey, CacheEntry> tcache_t;
f984e703 1345}
142ab370
RG
1346
1347static void reapRecordsFromNegCacheEntryForValidation(tcache_t& tcache, const vector<DNSRecord>& records)
1348{
1349 for (const auto& rec : records) {
1350 if (rec.d_type == QType::RRSIG) {
1351 auto rrsig = getRR<RRSIGRecordContent>(rec);
1352 if (rrsig) {
1353 tcache[{rec.d_name, rrsig->d_type, rec.d_place}].signatures.push_back(rrsig);
1354 }
1355 } else {
1356 tcache[{rec.d_name,rec.d_type,rec.d_place}].records.push_back(rec);
1357 }
1358 }
1359}
1360
6909b8c5
PL
1361/*!
1362 * Convience function to push the records from records into ret with a new TTL
1363 *
1364 * \param records DNSRecords that need to go into ret
1365 * \param ttl The new TTL for these records
1366 * \param ret The vector of DNSRecords that should contian the records with the modified TTL
1367 */
1368static void addTTLModifiedRecords(const vector<DNSRecord>& records, const uint32_t ttl, vector<DNSRecord>& ret) {
39ce10b2
PL
1369 for (const auto& rec : records) {
1370 DNSRecord r(rec);
1371 r.d_ttl = ttl;
1372 ret.push_back(r);
1373 }
1374}
1375
28364e4b 1376void SyncRes::computeNegCacheValidationStatus(const NegCache::NegCacheEntry* ne, const DNSName& qname, const QType& qtype, const int res, vState& state, unsigned int depth)
142ab370 1377{
f4de85a3
RG
1378 DNSName subdomain(qname);
1379 /* if we are retrieving a DS, we only care about the state of the parent zone */
1380 if(qtype == QType::DS)
1381 subdomain.chopOff();
1382
1383 computeZoneCuts(subdomain, g_rootdnsname, depth);
142ab370
RG
1384
1385 tcache_t tcache;
28364e4b
RG
1386 reapRecordsFromNegCacheEntryForValidation(tcache, ne->authoritySOA.records);
1387 reapRecordsFromNegCacheEntryForValidation(tcache, ne->authoritySOA.signatures);
1388 reapRecordsFromNegCacheEntryForValidation(tcache, ne->DNSSECRecords.records);
1389 reapRecordsFromNegCacheEntryForValidation(tcache, ne->DNSSECRecords.signatures);
142ab370
RG
1390
1391 for (const auto& entry : tcache) {
1392 // this happens when we did store signatures, but passed on the records themselves
1393 if (entry.second.records.empty()) {
1394 continue;
1395 }
1396
1397 const DNSName& owner = entry.first.name;
1398
1399 vState recordState = getValidationStatus(owner, false);
1400 if (state == Indeterminate) {
1401 state = recordState;
1402 }
1403
1404 if (recordState == Secure) {
f4de85a3
RG
1405 recordState = SyncRes::validateRecordsWithSigs(depth, qname, qtype, owner, entry.second.records, entry.second.signatures);
1406 }
142ab370 1407
f4de85a3
RG
1408 if (recordState != Indeterminate && recordState != state) {
1409 updateValidationState(state, recordState);
1410 if (state != Secure) {
1411 break;
142ab370
RG
1412 }
1413 }
1414 }
1415
1416 if (state == Secure) {
28364e4b 1417 vState neValidationState = ne->d_validationState;
142ab370 1418 dState expectedState = res == RCode::NXDomain ? NXDOMAIN : NXQTYPE;
28364e4b
RG
1419 dState denialState = getDenialValidationState(*ne, state, expectedState, false);
1420 updateDenialValidationState(neValidationState, ne->d_name, state, denialState, expectedState, qtype == QType::DS);
142ab370
RG
1421 }
1422 if (state != Indeterminate) {
1423 /* validation succeeded, let's update the cache entry so we don't have to validate again */
b9473937
RG
1424 boost::optional<uint32_t> capTTD = boost::none;
1425 if (state == Bogus) {
1426 capTTD = d_now.tv_sec + s_maxbogusttl;
1427 }
1428 t_sstorage.negcache.updateValidationStatus(ne->d_name, ne->d_qtype, state, capTTD);
142ab370
RG
1429 }
1430}
e325f20c 1431
ad797d94 1432bool SyncRes::doCacheCheck(const DNSName &qname, const DNSName& authname, bool wasForwardedOrAuthZone, bool wasAuthZone, bool wasForwardRecurse, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res, vState& state)
75b49099 1433{
fd8bc993 1434 bool giveNegative=false;
710af846 1435
be718669 1436 string prefix;
77499b05 1437 if(doLog()) {
ded77b10
BH
1438 prefix=d_prefix;
1439 prefix.append(depth, ' ');
1440 }
afbe2787 1441
30e9bd93 1442 // 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)
c5c066bf 1443 DNSName sqname(qname);
288f4aa9 1444 QType sqt(qtype);
092f210a 1445 uint32_t sttl=0;
2189085d 1446 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
4d2be65d 1447 vState cachedState;
28364e4b 1448 const NegCache::NegCacheEntry* ne = nullptr;
64a8b6a1 1449
710af846 1450 if(s_rootNXTrust &&
157647ec 1451 t_sstorage.negcache.getRootNXTrust(qname, d_now, &ne) &&
28364e4b 1452 ne->d_auth.isRoot() &&
e1636f82 1453 !(wasForwardedOrAuthZone && !authname.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
28364e4b
RG
1454 sttl = ne->d_ttd - d_now.tv_sec;
1455 LOG(prefix<<qname<<": Entire name '"<<qname<<"', is negatively cached via '"<<ne->d_auth<<"' & '"<<ne->d_name<<"' for another "<<sttl<<" seconds"<<endl);
3ddb9247 1456 res = RCode::NXDomain;
39ce10b2 1457 giveNegative = true;
28364e4b 1458 cachedState = ne->d_validationState;
157647ec 1459 } else if (t_sstorage.negcache.get(qname, qtype, d_now, &ne)) {
b0c164a2
RG
1460 /* If we are looking for a DS, discard NXD if auth == qname
1461 and ask for a specific denial instead */
28364e4b
RG
1462 if (qtype != QType::DS || ne->d_qtype.getCode() || ne->d_auth != qname ||
1463 t_sstorage.negcache.get(qname, qtype, d_now, &ne, true))
b0c164a2 1464 {
157647ec 1465 res = RCode::NXDomain;
28364e4b 1466 sttl = ne->d_ttd - d_now.tv_sec;
b0c164a2 1467 giveNegative = true;
28364e4b 1468 cachedState = ne->d_validationState;
157647ec 1469 if (ne->d_qtype.getCode()) {
28364e4b 1470 LOG(prefix<<qname<<": "<<qtype.getName()<<" is negatively cached via '"<<ne->d_auth<<"' for another "<<sttl<<" seconds"<<endl);
b0c164a2 1471 res = RCode::NoError;
157647ec
PL
1472 } else {
1473 LOG(prefix<<qname<<": Entire name '"<<qname<<" is negatively cached via '"<<ne->d_auth<<"' for another "<<sttl<<" seconds"<<endl);
b0c164a2 1474 }
157647ec 1475 }
d40a915b 1476 } else if (s_hardenNXD != HardenNXD::No && !qname.isRoot() && !wasForwardedOrAuthZone) {
157647ec
PL
1477 auto labels = qname.getRawLabels();
1478 DNSName negCacheName(g_rootdnsname);
1479 negCacheName.prependRawLabel(labels.back());
1480 labels.pop_back();
1481 while(!labels.empty()) {
1482 if (t_sstorage.negcache.get(negCacheName, QType(0), d_now, &ne, true)) {
d40a915b
OM
1483 if (ne->d_validationState == Indeterminate && validationEnabled()) {
1484 // LOG(prefix << negCacheName << " negatively cached and Indeterminate, trying to validate NXDOMAIN" << endl);
1485 // ...
1486 // And get the updated ne struct
1487 //t_sstorage.negcache.get(negCacheName, QType(0), d_now, &ne, true);
1488 }
7ce0efaa 1489 if ((s_hardenNXD == HardenNXD::Yes && ne->d_validationState != Bogus) || ne->d_validationState == Secure) {
d40a915b
OM
1490 res = RCode::NXDomain;
1491 sttl = ne->d_ttd - d_now.tv_sec;
1492 giveNegative = true;
1493 cachedState = ne->d_validationState;
1494 LOG(prefix<<qname<<": Name '"<<negCacheName<<"' and below, is negatively cached via '"<<ne->d_auth<<"' for another "<<sttl<<" seconds"<<endl);
1495 break;
1496 }
b0c164a2 1497 }
157647ec
PL
1498 negCacheName.prependRawLabel(labels.back());
1499 labels.pop_back();
39ce10b2 1500 }
39ce10b2
PL
1501 }
1502
1503 if (giveNegative) {
142ab370
RG
1504
1505 state = cachedState;
1506
e1636f82 1507 if (!wasAuthZone && shouldValidate() && state == Indeterminate) {
142ab370
RG
1508 LOG(prefix<<qname<<": got Indeterminate state for records retrieved from the negative cache, validating.."<<endl);
1509 computeNegCacheValidationStatus(ne, qname, qtype, res, state, depth);
b9473937
RG
1510
1511 if (state != cachedState && state == Bogus) {
1512 sttl = std::min(sttl, s_maxbogusttl);
1513 }
142ab370
RG
1514 }
1515
39ce10b2 1516 // Transplant SOA to the returned packet
28364e4b 1517 addTTLModifiedRecords(ne->authoritySOA.records, sttl, ret);
4d00b38b 1518 if(d_doDNSSEC) {
28364e4b
RG
1519 addTTLModifiedRecords(ne->authoritySOA.signatures, sttl, ret);
1520 addTTLModifiedRecords(ne->DNSSECRecords.records, sttl, ret);
1521 addTTLModifiedRecords(ne->DNSSECRecords.signatures, sttl, ret);
4d00b38b 1522 }
4d2be65d 1523
142ab370 1524 LOG(prefix<<qname<<": updating validation state with negative cache content for "<<qname<<" to "<<vStates[state]<<endl);
39ce10b2 1525 return true;
fd8bc993 1526 }
39ce10b2 1527
e325f20c 1528 vector<DNSRecord> cset;
75b49099 1529 bool found=false, expired=false;
57769f13 1530 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
2b984251 1531 vector<std::shared_ptr<DNSRecord>> authorityRecs;
57769f13 1532 uint32_t ttl=0;
b9473937 1533 uint32_t capTTL = std::numeric_limits<uint32_t>::max();
428f41b7 1534 bool wasCachedAuth;
ad797d94 1535 if(t_RC->get(d_now.tv_sec, sqname, sqt, !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &cachedState, &wasCachedAuth) > 0) {
428f41b7 1536
2189085d 1537 LOG(prefix<<sqname<<": Found cache hit for "<<sqt.getName()<<": ");
428f41b7 1538
dff3ef07 1539 if (!wasAuthZone && shouldValidate() && (wasCachedAuth || wasForwardRecurse) && cachedState == Indeterminate && d_requireAuthData) {
428f41b7
RG
1540
1541 /* This means we couldn't figure out the state when this entry was cached,
1542 most likely because we hadn't computed the zone cuts yet. */
aa30ad7e 1543 /* make sure they are computed before validating */
f4de85a3
RG
1544 DNSName subdomain(sqname);
1545 /* if we are retrieving a DS, we only care about the state of the parent zone */
1546 if(qtype == QType::DS)
1547 subdomain.chopOff();
1548
1549 computeZoneCuts(subdomain, g_rootdnsname, depth);
aa30ad7e 1550
142ab370 1551 vState recordState = getValidationStatus(qname, false);
787737ae
RG
1552 if (recordState == Secure) {
1553 LOG(prefix<<sqname<<": got Indeterminate state from the cache, validating.."<<endl);
1554 cachedState = SyncRes::validateRecordsWithSigs(depth, sqname, sqt, sqname, cset, signatures);
f4de85a3
RG
1555 }
1556 else {
1557 cachedState = recordState;
1558 }
787737ae 1559
f4de85a3
RG
1560 if (cachedState != Indeterminate) {
1561 LOG(prefix<<qname<<": got Indeterminate state from the cache, validation result is "<<vStates[cachedState]<<endl);
b9473937
RG
1562 if (cachedState == Bogus) {
1563 capTTL = s_maxbogusttl;
1564 }
1565 updateValidationStatusInCache(sqname, sqt, wasCachedAuth, cachedState);
787737ae 1566 }
428f41b7
RG
1567 }
1568
e325f20c 1569 for(auto j=cset.cbegin() ; j != cset.cend() ; ++j) {
c5310862 1570
e325f20c 1571 LOG(j->d_content->getZoneRepresentation());
c5310862
RG
1572
1573 if (j->d_class != QClass::IN) {
1574 continue;
1575 }
1576
e325f20c 1577 if(j->d_ttl>(unsigned int) d_now.tv_sec) {
1578 DNSRecord dr=*j;
b9473937
RG
1579 dr.d_ttl -= d_now.tv_sec;
1580 dr.d_ttl = std::min(dr.d_ttl, capTTL);
1581 ttl = dr.d_ttl;
e325f20c 1582 ret.push_back(dr);
1583 LOG("[ttl="<<dr.d_ttl<<"] ");
4957a608 1584 found=true;
ac539791 1585 }
75b49099 1586 else {
77499b05 1587 LOG("[expired] ");
4957a608 1588 expired=true;
75b49099 1589 }
afbe2787 1590 }
57769f13 1591
f128d20d
RG
1592 ret.reserve(ret.size() + signatures.size() + authorityRecs.size());
1593
57769f13 1594 for(const auto& signature : signatures) {
e325f20c 1595 DNSRecord dr;
1596 dr.d_type=QType::RRSIG;
1597 dr.d_name=sqname;
1598 dr.d_ttl=ttl;
1599 dr.d_content=signature;
39ce10b2 1600 dr.d_place = DNSResourceRecord::ANSWER;
4d2be65d 1601 dr.d_class=QClass::IN;
e325f20c 1602 ret.push_back(dr);
57769f13 1603 }
2b984251
RG
1604
1605 for(const auto& rec : authorityRecs) {
1606 DNSRecord dr(*rec);
1607 dr.d_ttl=ttl;
1608 ret.push_back(dr);
1609 }
1610
77499b05 1611 LOG(endl);
f4df5e89 1612 if(found && !expired) {
4d2be65d 1613 if (!giveNegative)
4957a608 1614 res=0;
bcb05770 1615 LOG(prefix<<qname<<": updating validation state with cache content for "<<qname<<" to "<<vStates[cachedState]<<endl);
4d2be65d 1616 state = cachedState;
75b49099 1617 return true;
f4df5e89 1618 }
75b49099 1619 else
2189085d 1620 LOG(prefix<<qname<<": cache had only stale entries"<<endl);
afbe2787 1621 }
f4df5e89 1622
75b49099
BH
1623 return false;
1624}
afbe2787 1625
69cbdef9 1626bool SyncRes::moreSpecificThan(const DNSName& a, const DNSName &b) const
75b49099 1627{
6a1010f7 1628 return (a.isPartOf(b) && a.countLabels() > b.countLabels());
afbe2787
BH
1629}
1630
d8d0bb8f 1631struct speedOrder
eefd15f9 1632{
b9715061 1633 bool operator()(const std::pair<DNSName, float> &a, const std::pair<DNSName, float> &b) const
c3d9d009 1634 {
feccaf7f 1635 return a.second < b.second;
c3d9d009 1636 }
c3d9d009
BH
1637};
1638
b9715061 1639inline std::vector<std::pair<DNSName, float>> SyncRes::shuffleInSpeedOrder(NsSet &tnameservers, const string &prefix)
afbe2787 1640{
b9715061 1641 std::vector<std::pair<DNSName, float>> rnameservers;
5ea6f7de 1642 rnameservers.reserve(tnameservers.size());
a2d65f83 1643 for(const auto& tns: tnameservers) {
b9715061 1644 float speed = t_sstorage.nsSpeeds[tns.first].get(d_now);
feccaf7f 1645 rnameservers.push_back({tns.first, speed});
a2d65f83 1646 if(tns.first.empty()) // this was an authoritative OOB zone, don't pollute the nsSpeeds with that
1647 return rnameservers;
21f0f88b 1648 }
461df9d2 1649
feccaf7f
RG
1650 random_shuffle(rnameservers.begin(),rnameservers.end());
1651 speedOrder so;
996c89cc 1652 stable_sort(rnameservers.begin(),rnameservers.end(), so);
710af846 1653
77499b05
BH
1654 if(doLog()) {
1655 LOG(prefix<<"Nameservers: ");
feccaf7f
RG
1656 for(auto i=rnameservers.begin();i!=rnameservers.end();++i) {
1657 if(i!=rnameservers.begin()) {
77499b05
BH
1658 LOG(", ");
1659 if(!((i-rnameservers.begin())%3)) {
1660 LOG(endl<<prefix<<" ");
1661 }
d8d0bb8f 1662 }
feccaf7f 1663 LOG(i->first.toLogString()<<"(" << (boost::format("%0.2f") % (i->second/1000.0)).str() <<"ms)");
d8d0bb8f 1664 }
77499b05 1665 LOG(endl);
d8d0bb8f 1666 }
728485ca 1667 return rnameservers;
afbe2787
BH
1668}
1669
cc11d7f4 1670inline vector<ComboAddress> SyncRes::shuffleForwardSpeed(const vector<ComboAddress> &rnameservers, const string &prefix, const bool wasRd)
589884b8 1671{
cc11d7f4 1672 vector<ComboAddress> nameservers = rnameservers;
b9715061 1673 map<ComboAddress, float> speeds;
589884b8 1674
cc11d7f4 1675 for(const auto& val: nameservers) {
b9715061 1676 float speed;
6ed0c28a 1677 DNSName nsName = DNSName(val.toStringWithPort());
b9715061 1678 speed=t_sstorage.nsSpeeds[nsName].get(d_now);
589884b8 1679 speeds[val]=speed;
1680 }
feccaf7f 1681 random_shuffle(nameservers.begin(),nameservers.end());
6ed0c28a 1682 speedOrderCA so(speeds);
cc11d7f4 1683 stable_sort(nameservers.begin(),nameservers.end(), so);
589884b8 1684
589884b8 1685 if(doLog()) {
1686 LOG(prefix<<"Nameservers: ");
cc11d7f4 1687 for(vector<ComboAddress>::const_iterator i=nameservers.cbegin();i!=nameservers.cend();++i) {
1688 if(i!=nameservers.cbegin()) {
589884b8 1689 LOG(", ");
cc11d7f4 1690 if(!((i-nameservers.cbegin())%3)) {
589884b8 1691 LOG(endl<<prefix<<" ");
1692 }
1693 }
6ed0c28a 1694 LOG((wasRd ? string("+") : string("-")) << i->toStringWithPort() <<"(" << (boost::format("%0.2f") % (speeds[*i]/1000.0)).str() <<"ms)");
589884b8 1695 }
1696 LOG(endl);
1697 }
cc11d7f4 1698 return nameservers;
589884b8 1699}
1700
dbbef467
RG
1701static uint32_t getRRSIGTTL(const time_t now, const std::shared_ptr<RRSIGRecordContent>& rrsig)
1702{
1703 uint32_t res = 0;
1704 if (now < rrsig->d_sigexpire) {
1705 res = static_cast<uint32_t>(rrsig->d_sigexpire) - now;
1706 }
1707 return res;
1708}
1709
2b984251
RG
1710static const set<uint16_t> nsecTypes = {QType::NSEC, QType::NSEC3};
1711
39ce10b2
PL
1712/* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
1713 *
1714 * \param records The records to parse for the authority SOA and NSEC(3) records
1715 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
1716 */
dbbef467 1717static void harvestNXRecords(const vector<DNSRecord>& records, NegCache::NegCacheEntry& ne, const time_t now, uint32_t* lowestTTL) {
620db2c8 1718 for(const auto& rec : records) {
39ce10b2
PL
1719 if(rec.d_place != DNSResourceRecord::AUTHORITY)
1720 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
1721 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
1722 // records MUST be in the same section as the records they cover.
1723 // Hence, we ignore all records outside of the AUTHORITY section.
1724 continue;
1725
620db2c8 1726 if(rec.d_type == QType::RRSIG) {
39ce10b2
PL
1727 auto rrsig = getRR<RRSIGRecordContent>(rec);
1728 if(rrsig) {
1729 if(rrsig->d_type == QType::SOA) {
1730 ne.authoritySOA.signatures.push_back(rec);
dbbef467
RG
1731 if (lowestTTL && isRRSIGNotExpired(now, rrsig)) {
1732 *lowestTTL = min(*lowestTTL, rec.d_ttl);
1733 *lowestTTL = min(*lowestTTL, getRRSIGTTL(now, rrsig));
1734 }
39ce10b2
PL
1735 }
1736 if(nsecTypes.count(rrsig->d_type)) {
1737 ne.DNSSECRecords.signatures.push_back(rec);
dbbef467
RG
1738 if (lowestTTL && isRRSIGNotExpired(now, rrsig)) {
1739 *lowestTTL = min(*lowestTTL, rec.d_ttl);
1740 *lowestTTL = min(*lowestTTL, getRRSIGTTL(now, rrsig));
1741 }
39ce10b2
PL
1742 }
1743 }
1744 continue;
1745 }
1746 if(rec.d_type == QType::SOA) {
1747 ne.authoritySOA.records.push_back(rec);
dbbef467
RG
1748 if (lowestTTL) {
1749 *lowestTTL = min(*lowestTTL, rec.d_ttl);
1750 }
39ce10b2
PL
1751 continue;
1752 }
1753 if(nsecTypes.count(rec.d_type)) {
1754 ne.DNSSECRecords.records.push_back(rec);
dbbef467
RG
1755 if (lowestTTL) {
1756 *lowestTTL = min(*lowestTTL, rec.d_ttl);
1757 }
39ce10b2 1758 continue;
620db2c8 1759 }
620db2c8 1760 }
620db2c8 1761}
1762
4d2be65d
RG
1763static cspmap_t harvestCSPFromNE(const NegCache::NegCacheEntry& ne)
1764{
1765 cspmap_t cspmap;
1766 for(const auto& rec : ne.DNSSECRecords.signatures) {
1767 if(rec.d_type == QType::RRSIG) {
1768 auto rrc = getRR<RRSIGRecordContent>(rec);
1769 if (rrc) {
1770 cspmap[{rec.d_name,rrc->d_type}].signatures.push_back(rrc);
1771 }
1772 }
1773 }
1774 for(const auto& rec : ne.DNSSECRecords.records) {
c1e7b833 1775 cspmap[{rec.d_name, rec.d_type}].records.insert(rec.d_content);
4d2be65d
RG
1776 }
1777 return cspmap;
1778}
1779
39ce10b2
PL
1780// TODO remove after processRecords is fixed!
1781// Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
620db2c8 1782static void addNXNSECS(vector<DNSRecord>&ret, const vector<DNSRecord>& records)
1783{
39ce10b2 1784 NegCache::NegCacheEntry ne;
dbbef467 1785 harvestNXRecords(records, ne, 0, nullptr);
39ce10b2
PL
1786 ret.insert(ret.end(), ne.authoritySOA.signatures.begin(), ne.authoritySOA.signatures.end());
1787 ret.insert(ret.end(), ne.DNSSECRecords.records.begin(), ne.DNSSECRecords.records.end());
1788 ret.insert(ret.end(), ne.DNSSECRecords.signatures.begin(), ne.DNSSECRecords.signatures.end());
620db2c8 1789}
1790
69cbdef9 1791bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine& dfe, const NsSet& nameservers)
26ca3513
RG
1792{
1793 if(d_wantsRPZ) {
1794 for (auto const &ns : nameservers) {
69cbdef9 1795 d_appliedPolicy = dfe.getProcessingPolicy(ns.first, d_discardedPolicies);
26ca3513
RG
1796 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
1797 LOG(", however nameserver "<<ns.first<<" was blocked by RPZ policy '"<<(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")<<"'"<<endl);
1798 return true;
1799 }
1800
1801 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1802 for (auto const &address : ns.second.first) {
69cbdef9 1803 d_appliedPolicy = dfe.getProcessingPolicy(address, d_discardedPolicies);
26ca3513
RG
1804 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
1805 LOG(", however nameserver "<<ns.first<<" IP address "<<address.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")<<"'"<<endl);
1806 return true;
1807 }
1808 }
1809 }
1810 }
1811 return false;
1812}
1813
69cbdef9 1814bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine& dfe, const ComboAddress& remoteIP)
26ca3513
RG
1815{
1816 if (d_wantsRPZ) {
69cbdef9 1817 d_appliedPolicy = dfe.getProcessingPolicy(remoteIP, d_discardedPolicies);
26ca3513
RG
1818 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) {
1819 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")+"')");
1820 return true;
1821 }
1822 }
1823 return false;
1824}
1825
b9715061 1826vector<ComboAddress> SyncRes::retrieveAddressesForNS(const std::string& prefix, const DNSName& qname, std::vector<std::pair<DNSName, float>>::const_iterator& tns, const unsigned int depth, set<GetBestNSAnswer>& beenthere, const vector<std::pair<DNSName, float>>& rnameservers, NsSet& nameservers, bool& sendRDQuery, bool& pierceDontQuery, bool& flawedNSSet, bool cacheOnly)
26ca3513
RG
1827{
1828 vector<ComboAddress> result;
1829
feccaf7f
RG
1830 if(!tns->first.empty()) {
1831 LOG(prefix<<qname<<": Trying to resolve NS '"<<tns->first<< "' ("<<1+tns-rnameservers.begin()<<"/"<<(unsigned int)rnameservers.size()<<")"<<endl);
1832 result = getAddrs(tns->first, depth+2, beenthere, cacheOnly);
26ca3513
RG
1833 pierceDontQuery=false;
1834 }
1835 else {
1836 LOG(prefix<<qname<<": Domain has hardcoded nameserver");
1837
feccaf7f 1838 if(nameservers[tns->first].first.size() > 1) {
26ca3513
RG
1839 LOG("s");
1840 }
1841 LOG(endl);
1842
feccaf7f
RG
1843 sendRDQuery = nameservers[tns->first].second;
1844 result = shuffleForwardSpeed(nameservers[tns->first].first, doLog() ? (prefix+qname.toString()+": ") : string(), sendRDQuery);
26ca3513
RG
1845 pierceDontQuery=true;
1846 }
1847 return result;
1848}
1849
1850bool SyncRes::throttledOrBlocked(const std::string& prefix, const ComboAddress& remoteIP, const DNSName& qname, const QType& qtype, bool pierceDontQuery)
1851{
a712cb56 1852 if(t_sstorage.throttle.shouldThrottle(d_now.tv_sec, boost::make_tuple(remoteIP, "", 0))) {
26ca3513
RG
1853 LOG(prefix<<qname<<": server throttled "<<endl);
1854 s_throttledqueries++; d_throttledqueries++;
1855 return true;
1856 }
a712cb56 1857 else if(t_sstorage.throttle.shouldThrottle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()))) {
6dfff36f 1858 LOG(prefix<<qname<<": query throttled "<<remoteIP.toString()<<", "<<qname<<"; "<<qtype.getName()<<endl);
26ca3513
RG
1859 s_throttledqueries++; d_throttledqueries++;
1860 return true;
1861 }
9065eb05 1862 else if(!pierceDontQuery && s_dontQuery && s_dontQuery->match(&remoteIP)) {
26ca3513
RG
1863 LOG(prefix<<qname<<": not sending query to " << remoteIP.toString() << ", blocked by 'dont-query' setting" << endl);
1864 s_dontqueries++;
1865 return true;
1866 }
1867 return false;
1868}
1869
4d2be65d
RG
1870bool SyncRes::validationEnabled() const
1871{
8455425c 1872 return g_dnssecmode != DNSSECMode::Off && g_dnssecmode != DNSSECMode::ProcessNoValidate;
4d2be65d
RG
1873}
1874
1875uint32_t SyncRes::computeLowestTTD(const std::vector<DNSRecord>& records, const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures, uint32_t signaturesTTL) const
26ca3513 1876{
4d2be65d
RG
1877 uint32_t lowestTTD = std::numeric_limits<uint32_t>::max();
1878 for(const auto& record : records)
1879 lowestTTD = min(lowestTTD, record.d_ttl);
1880
0c43f455
RG
1881 /* even if it was not requested for that request (Process, and neither AD nor DO set),
1882 it might be requested at a later time so we need to be careful with the TTL. */
4d2be65d 1883 if (validationEnabled() && !signatures.empty()) {
3cef03e9 1884 /* if we are validating, we don't want to cache records after their signatures expire. */
4d2be65d
RG
1885 /* records TTL are now TTD, let's add 'now' to the signatures lowest TTL */
1886 lowestTTD = min(lowestTTD, static_cast<uint32_t>(signaturesTTL + d_now.tv_sec));
1887
1888 for(const auto& sig : signatures) {
dbbef467
RG
1889 if (isRRSIGNotExpired(d_now.tv_sec, sig)) {
1890 // we don't decerement d_sigexpire by 'now' because we actually want a TTD, not a TTL */
4d2be65d
RG
1891 lowestTTD = min(lowestTTD, static_cast<uint32_t>(sig->d_sigexpire));
1892 }
1893 }
1894 }
1895
1896 return lowestTTD;
1897}
1898
1899void SyncRes::updateValidationState(vState& state, const vState stateUpdate)
1900{
f715542c 1901 LOG(d_prefix<<"validation state was "<<std::string(vStates[state])<<", state update is "<<std::string(vStates[stateUpdate]));
4d2be65d 1902
895449a5
RG
1903 if (stateUpdate == TA) {
1904 state = Secure;
4d2be65d
RG
1905 }
1906 else if (stateUpdate == NTA) {
1907 state = Insecure;
1908 }
895449a5
RG
1909 else if (stateUpdate == Bogus) {
1910 state = Bogus;
1911 }
1912 else if (state == Indeterminate) {
1913 state = stateUpdate;
1914 }
4d2be65d
RG
1915 else if (stateUpdate == Insecure) {
1916 if (state != Bogus) {
1917 state = Insecure;
1918 }
1919 }
f715542c 1920 LOG(", validation state is now "<<std::string(vStates[state])<<endl);
4d2be65d
RG
1921}
1922
1923vState SyncRes::getTA(const DNSName& zone, dsmap_t& ds)
1924{
1925 auto luaLocal = g_luaconfs.getLocal();
1926
1927 if (luaLocal->dsAnchors.empty()) {
e77f01d1 1928 LOG(d_prefix<<": No trust anchors configured, everything is Insecure"<<endl);
4d2be65d
RG
1929 /* We have no TA, everything is insecure */
1930 return Insecure;
1931 }
1932
1933 std::string reason;
1934 if (haveNegativeTrustAnchor(luaLocal->negAnchors, zone, reason)) {
e77f01d1 1935 LOG(d_prefix<<": got NTA for '"<<zone<<"'"<<endl);
4d2be65d
RG
1936 return NTA;
1937 }
1938
1939 if (getTrustAnchor(luaLocal->dsAnchors, zone, ds)) {
e77f01d1 1940 LOG(d_prefix<<": got TA for '"<<zone<<"'"<<endl);
895449a5 1941 return TA;
4d2be65d 1942 }
e77f01d1 1943 else {
1944 LOG(d_prefix<<": no TA found for '"<<zone<<"' among "<< luaLocal->dsAnchors.size()<<endl);
1945 }
4d2be65d
RG
1946
1947 if (zone.isRoot()) {
1948 /* No TA for the root */
1949 return Insecure;
1950 }
1951
1952 return Indeterminate;
1953}
1954
8455425c
RG
1955static size_t countSupportedDS(const dsmap_t& dsmap)
1956{
1957 size_t count = 0;
1958
1959 for (const auto& ds : dsmap) {
1960 if (isSupportedDS(ds)) {
1961 count++;
1962 }
1963 }
1964
1965 return count;
1966}
1967
5374b03b 1968vState SyncRes::getDSRecords(const DNSName& zone, dsmap_t& ds, bool taOnly, unsigned int depth, bool bogusOnNXD, bool* foundCut)
4d2be65d
RG
1969{
1970 vState result = getTA(zone, ds);
1971
1972 if (result != Indeterminate || taOnly) {
5374b03b
RG
1973 if (foundCut) {
1974 *foundCut = (result != Indeterminate);
1975 }
1976
18159e92
RG
1977 if (result == TA) {
1978 if (countSupportedDS(ds) == 0) {
1979 ds.clear();
1980 result = Insecure;
1981 }
1982 else {
1983 result = Secure;
1984 }
1985 }
1986 else if (result == NTA) {
8455425c
RG
1987 result = Insecure;
1988 }
1989
4d2be65d
RG
1990 return result;
1991 }
1992
1993 bool oldSkipCNAME = d_skipCNAMECheck;
4d2be65d 1994 d_skipCNAMECheck = true;
4d2be65d
RG
1995
1996 std::set<GetBestNSAnswer> beenthere;
1997 std::vector<DNSRecord> dsrecords;
1998
1999 vState state = Indeterminate;
51b6b728 2000 int rcode = doResolve(zone, QType(QType::DS), dsrecords, depth + 1, beenthere, state);
4d2be65d 2001 d_skipCNAMECheck = oldSkipCNAME;
4d2be65d 2002
3ca6d908 2003 if (rcode == RCode::NoError || (rcode == RCode::NXDomain && !bogusOnNXD)) {
1e332f68
PL
2004 uint8_t bestDigestType = 0;
2005
dd359a9f
RG
2006 bool gotCNAME = false;
2007 for (const auto& record : dsrecords) {
2008 if (record.d_type == QType::DS) {
2009 const auto dscontent = getRR<DSRecordContent>(record);
2010 if (dscontent && isSupportedDS(*dscontent)) {
2011 // Make GOST a lower prio than SHA256
690b86b7 2012 if (dscontent->d_digesttype == DNSSECKeeper::DIGEST_GOST && bestDigestType == DNSSECKeeper::DIGEST_SHA256) {
dd359a9f 2013 continue;
4d2be65d 2014 }
690b86b7 2015 if (dscontent->d_digesttype > bestDigestType || (bestDigestType == DNSSECKeeper::DIGEST_GOST && dscontent->d_digesttype == DNSSECKeeper::DIGEST_SHA256)) {
dd359a9f
RG
2016 bestDigestType = dscontent->d_digesttype;
2017 }
2018 ds.insert(*dscontent);
1c39e884 2019 }
4d2be65d 2020 }
dd359a9f
RG
2021 else if (record.d_type == QType::CNAME && record.d_name == zone) {
2022 gotCNAME = true;
2023 }
2024 }
4d2be65d 2025
dd359a9f
RG
2026 /* RFC 4509 section 3: "Validator implementations SHOULD ignore DS RRs containing SHA-1
2027 * digests if DS RRs with SHA-256 digests are present in the DS RRset."
2028 * As SHA348 is specified as well, the spirit of the this line is "use the best algorithm".
2029 */
2030 for (auto dsrec = ds.begin(); dsrec != ds.end(); ) {
2031 if (dsrec->d_digesttype != bestDigestType) {
2032 dsrec = ds.erase(dsrec);
1e332f68 2033 }
dd359a9f
RG
2034 else {
2035 ++dsrec;
2036 }
2037 }
1e332f68 2038
dd359a9f
RG
2039 if (rcode == RCode::NoError) {
2040 if (ds.empty()) {
46df9251
RG
2041 /* we have no DS, it's either:
2042 - a delegation to a non-DNSSEC signed zone
2043 - no delegation, we stay in the same zone
2044 */
dd359a9f
RG
2045 if (gotCNAME || denialProvesNoDelegation(zone, dsrecords)) {
2046 /* we are still inside the same zone */
5374b03b 2047
dd359a9f 2048 if (foundCut) {
5374b03b 2049 *foundCut = false;
5374b03b 2050 }
dd359a9f
RG
2051 return state;
2052 }
5374b03b 2053
dd359a9f
RG
2054 /* delegation with no DS, might be Secure -> Insecure */
2055 if (foundCut) {
5374b03b
RG
2056 *foundCut = true;
2057 }
2058
46df9251
RG
2059 /* a delegation with no DS is either:
2060 - a signed zone (Secure) to an unsigned one (Insecure)
2061 - an unsigned zone to another unsigned one (Insecure stays Insecure, Bogus stays Bogus)
2062 */
dd359a9f
RG
2063 return state == Secure ? Insecure : state;
2064 } else {
2065 /* we have a DS */
2066 if (foundCut) {
2067 *foundCut = true;
2068 }
b7f378d1 2069 }
4d2be65d 2070 }
b7f378d1 2071
4d2be65d
RG
2072 return state;
2073 }
2074
bcb05770 2075 LOG(d_prefix<<": returning Bogus state from "<<__func__<<"("<<zone<<")"<<endl);
4d2be65d
RG
2076 return Bogus;
2077}
2078
0735b60f
RG
2079bool SyncRes::haveExactValidationStatus(const DNSName& domain)
2080{
e1636f82 2081 if (!shouldValidate()) {
0735b60f
RG
2082 return false;
2083 }
2084 const auto& it = d_cutStates.find(domain);
2085 if (it != d_cutStates.cend()) {
2086 return true;
2087 }
2088 return false;
2089}
2090
5374b03b 2091vState SyncRes::getValidationStatus(const DNSName& subdomain, bool allowIndeterminate)
70b3fe7a
RG
2092{
2093 vState result = Indeterminate;
2094
e1636f82 2095 if (!shouldValidate()) {
70b3fe7a
RG
2096 return result;
2097 }
2098 DNSName name(subdomain);
2099 do {
51b6b728
RG
2100 const auto& it = d_cutStates.find(name);
2101 if (it != d_cutStates.cend()) {
5374b03b
RG
2102 if (allowIndeterminate || it->second != Indeterminate) {
2103 LOG(d_prefix<<": got status "<<vStates[it->second]<<" for name "<<subdomain<<" (from "<<name<<")"<<endl);
2104 return it->second;
2105 }
70b3fe7a
RG
2106 }
2107 }
2108 while (name.chopOff());
2109
2110 return result;
2111}
2112
c405e222
RG
2113bool SyncRes::lookForCut(const DNSName& qname, unsigned int depth, const vState existingState, vState& newState)
2114{
2115 bool foundCut = false;
5374b03b
RG
2116 dsmap_t ds;
2117 vState dsState = getDSRecords(qname, ds, newState == Bogus || existingState == Insecure || existingState == Bogus, depth, false, &foundCut);
c405e222 2118
5374b03b
RG
2119 if (dsState != Indeterminate) {
2120 newState = dsState;
2121 }
c405e222 2122
c405e222
RG
2123 return foundCut;
2124}
2125
51b6b728 2126void SyncRes::computeZoneCuts(const DNSName& begin, const DNSName& end, unsigned int depth)
4d2be65d 2127{
428f41b7 2128 if(!begin.isPartOf(end)) {
86f1af1c
KM
2129 LOG(d_prefix<<" "<<begin.toLogString()<<" is not part of "<<end.toLogString()<<endl);
2130 throw PDNSException(begin.toLogString() + " is not part of " + end.toLogString());
428f41b7
RG
2131 }
2132
51b6b728 2133 if (d_cutStates.count(begin) != 0) {
ad75fdbd 2134 return;
4d2be65d
RG
2135 }
2136
0eb07f3a
OM
2137 const bool oldCacheOnly = setCacheOnly(false);
2138
4d2be65d 2139 dsmap_t ds;
51b6b728 2140 vState cutState = getDSRecords(end, ds, false, depth);
bcb05770 2141 LOG(d_prefix<<": setting cut state for "<<end<<" to "<<vStates[cutState]<<endl);
51b6b728 2142 d_cutStates[end] = cutState;
70b3fe7a 2143
e1636f82 2144 if (!shouldValidate()) {
0eb07f3a 2145 setCacheOnly(oldCacheOnly);
ad75fdbd 2146 return;
70b3fe7a
RG
2147 }
2148
70b3fe7a
RG
2149 DNSName qname(end);
2150 std::vector<string> labelsToAdd = begin.makeRelative(end).getRawLabels();
2151
ad75fdbd 2152 bool oldSkipCNAME = d_skipCNAMECheck;
ad75fdbd 2153 d_skipCNAMECheck = true;
ad75fdbd 2154
70b3fe7a 2155 while(qname != begin) {
70b3fe7a
RG
2156 if (labelsToAdd.empty())
2157 break;
2158
2159 qname.prependRawLabel(labelsToAdd.back());
2160 labelsToAdd.pop_back();
bcb05770
RG
2161 LOG(d_prefix<<": - Looking for a cut at "<<qname<<endl);
2162
2163 const auto cutIt = d_cutStates.find(qname);
2164 if (cutIt != d_cutStates.cend()) {
2165 if (cutIt->second != Indeterminate) {
2166 LOG(d_prefix<<": - Cut already known at "<<qname<<endl);
3d4e836e 2167 cutState = cutIt->second;
bcb05770
RG
2168 continue;
2169 }
2170 }
70b3fe7a 2171
3d4e836e
RG
2172 /* no need to look for NS and DS if we are already insecure or bogus,
2173 just look for (N)TA
2174 */
2175 if (cutState == Insecure || cutState == Bogus) {
2010ac95
RG
2176 dsmap_t cutDS;
2177 vState newState = getDSRecords(qname, cutDS, true, depth);
3d4e836e
RG
2178 if (newState == Indeterminate) {
2179 continue;
2180 }
2181
2182 LOG(d_prefix<<": New state for "<<qname<<" is "<<vStates[newState]<<endl);
3d4e836e
RG
2183 cutState = newState;
2184
2185 d_cutStates[qname] = cutState;
2186
2187 continue;
2188 }
70b3fe7a 2189
c405e222 2190 vState newState = Indeterminate;
428f41b7
RG
2191 /* temporarily mark as Indeterminate, so that we won't enter an endless loop
2192 trying to determine that zone cut again. */
c405e222
RG
2193 d_cutStates[qname] = newState;
2194 bool foundCut = lookForCut(qname, depth + 1, cutState, newState);
2195 if (foundCut) {
2196 LOG(d_prefix<<": - Found cut at "<<qname<<endl);
2197 if (newState != Indeterminate) {
2198 cutState = newState;
70b3fe7a 2199 }
c405e222
RG
2200 LOG(d_prefix<<": New state for "<<qname<<" is "<<vStates[cutState]<<endl);
2201 d_cutStates[qname] = cutState;
70b3fe7a 2202 }
c405e222 2203 else {
428f41b7 2204 /* remove the temporary cut */
b25712fd 2205 LOG(d_prefix<<qname<<": removing cut state for "<<qname<<endl);
51b6b728 2206 d_cutStates.erase(qname);
428f41b7 2207 }
70b3fe7a
RG
2208 }
2209
ad75fdbd 2210 d_skipCNAMECheck = oldSkipCNAME;
ad75fdbd 2211
bcb05770 2212 LOG(d_prefix<<": list of cuts from "<<begin<<" to "<<end<<endl);
51b6b728 2213 for (const auto& cut : d_cutStates) {
bcb05770 2214 if (cut.first.isRoot() || (begin.isPartOf(cut.first) && cut.first.isPartOf(end))) {
51b6b728
RG
2215 LOG(" - "<<cut.first<<": "<<vStates[cut.second]<<endl);
2216 }
70b3fe7a 2217 }
0eb07f3a 2218 setCacheOnly(oldCacheOnly);
4d2be65d
RG
2219}
2220
51b6b728 2221vState SyncRes::validateDNSKeys(const DNSName& zone, const std::vector<DNSRecord>& dnskeys, const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures, unsigned int depth)
4d2be65d
RG
2222{
2223 dsmap_t ds;
2224 if (!signatures.empty()) {
2225 DNSName signer = getSigner(signatures);
2226
8d2e7fa1 2227 if (!signer.empty() && zone.isPartOf(signer)) {
51b6b728 2228 vState state = getDSRecords(signer, ds, false, depth);
b7f378d1 2229
4d2be65d
RG
2230 if (state != Secure) {
2231 return state;
2232 }
2233 }
2234 }
2235
2236 skeyset_t tentativeKeys;
c1e7b833 2237 sortedRecords_t toSign;
4d2be65d
RG
2238
2239 for (const auto& dnskey : dnskeys) {
2240 if (dnskey.d_type == QType::DNSKEY) {
2241 auto content = getRR<DNSKEYRecordContent>(dnskey);
2242 if (content) {
2243 tentativeKeys.insert(content);
c1e7b833 2244 toSign.insert(content);
4d2be65d
RG
2245 }
2246 }
2247 }
2248
bcb05770 2249 LOG(d_prefix<<": trying to validate "<<std::to_string(tentativeKeys.size())<<" DNSKEYs with "<<std::to_string(ds.size())<<" DS"<<endl);
4d2be65d
RG
2250 skeyset_t validatedKeys;
2251 validateDNSKeysAgainstDS(d_now.tv_sec, zone, ds, tentativeKeys, toSign, signatures, validatedKeys);
2252
bcb05770 2253 LOG(d_prefix<<": we now have "<<std::to_string(validatedKeys.size())<<" DNSKEYs"<<endl);
4d2be65d 2254
82fbd934
RG
2255 /* if we found at least one valid RRSIG covering the set,
2256 all tentative keys are validated keys. Otherwise it means
2257 we haven't found at least one DNSKEY and a matching RRSIG
2258 covering this set, this looks Bogus. */
4d2be65d 2259 if (validatedKeys.size() != tentativeKeys.size()) {
bcb05770 2260 LOG(d_prefix<<": returning Bogus state from "<<__func__<<"("<<zone<<")"<<endl);
4d2be65d
RG
2261 return Bogus;
2262 }
2263
2264 return Secure;
2265}
2266
51b6b728 2267vState SyncRes::getDNSKeys(const DNSName& signer, skeyset_t& keys, unsigned int depth)
4d2be65d
RG
2268{
2269 std::vector<DNSRecord> records;
2270 std::set<GetBestNSAnswer> beenthere;
bcb05770 2271 LOG(d_prefix<<"Retrieving DNSKeys for "<<signer<<endl);
4d2be65d
RG
2272
2273 vState state = Indeterminate;
c7385ddb
RG
2274 /* following CNAME might lead to us to the wrong DNSKEY */
2275 bool oldSkipCNAME = d_skipCNAMECheck;
2276 d_skipCNAMECheck = true;
51b6b728 2277 int rcode = doResolve(signer, QType(QType::DNSKEY), records, depth + 1, beenthere, state);
c7385ddb 2278 d_skipCNAMECheck = oldSkipCNAME;
4d2be65d
RG
2279
2280 if (rcode == RCode::NoError) {
2281 if (state == Secure) {
2282 for (const auto& key : records) {
2283 if (key.d_type == QType::DNSKEY) {
2284 auto content = getRR<DNSKEYRecordContent>(key);
2285 if (content) {
2286 keys.insert(content);
2287 }
2288 }
2289 }
2290 }
bcb05770 2291 LOG(d_prefix<<"Retrieved "<<keys.size()<<" DNSKeys for "<<signer<<", state is "<<vStates[state]<<endl);
4d2be65d
RG
2292 return state;
2293 }
2294
bcb05770 2295 LOG(d_prefix<<"Returning Bogus state from "<<__func__<<"("<<signer<<")"<<endl);
4d2be65d
RG
2296 return Bogus;
2297}
2298
51b6b728 2299vState 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)
4d2be65d
RG
2300{
2301 skeyset_t keys;
2302 if (!signatures.empty()) {
2303 const DNSName signer = getSigner(signatures);
2304 if (!signer.empty() && name.isPartOf(signer)) {
f715542c 2305 if ((qtype == QType::DNSKEY || qtype == QType::DS) && signer == qname) {
15f44f1d 2306 /* we are already retrieving those keys, sorry */
dd359a9f
RG
2307 if (qtype == QType::DS) {
2308 /* something is very wrong */
2309 LOG(d_prefix<<"The DS for "<<qname<<" is signed by itself, going Bogus"<<endl);
2310 return Bogus;
2311 }
15f44f1d
RG
2312 return Indeterminate;
2313 }
51b6b728 2314 vState state = getDNSKeys(signer, keys, depth);
4d2be65d
RG
2315 if (state != Secure) {
2316 return state;
2317 }
2318 }
2319 } else {
bcb05770 2320 LOG(d_prefix<<"Bogus!"<<endl);
4d2be65d
RG
2321 return Bogus;
2322 }
2323
c1e7b833 2324 sortedRecords_t recordcontents;
4d2be65d 2325 for (const auto& record : records) {
c1e7b833 2326 recordcontents.insert(record.d_content);
4d2be65d
RG
2327 }
2328
bcb05770 2329 LOG(d_prefix<<"Going to validate "<<recordcontents.size()<< " record contents with "<<signatures.size()<<" sigs and "<<keys.size()<<" keys for "<<name<<endl);
4d2be65d 2330 if (validateWithKeySet(d_now.tv_sec, name, recordcontents, signatures, keys, false)) {
bcb05770 2331 LOG(d_prefix<<"Secure!"<<endl);
4d2be65d
RG
2332 return Secure;
2333 }
2334
bcb05770 2335 LOG(d_prefix<<"Bogus!"<<endl);
4d2be65d
RG
2336 return Bogus;
2337}
2338
7155c3e5
RG
2339static bool allowAdditionalEntry(std::unordered_set<DNSName>& allowedAdditionals, const DNSRecord& rec)
2340{
2341 switch(rec.d_type) {
2342 case QType::MX:
2343 {
2344 if (auto mxContent = getRR<MXRecordContent>(rec)) {
2345 allowedAdditionals.insert(mxContent->d_mxname);
2346 }
2347 return true;
2348 }
2349 case QType::NS:
2350 {
2351 if (auto nsContent = getRR<NSRecordContent>(rec)) {
2352 allowedAdditionals.insert(nsContent->getNS());
2353 }
2354 return true;
2355 }
2356 case QType::SRV:
2357 {
2358 if (auto srvContent = getRR<SRVRecordContent>(rec)) {
2359 allowedAdditionals.insert(srvContent->d_target);
2360 }
2361 return true;
2362 }
2363 default:
2364 return false;
2365 }
2366}
2367
2368void SyncRes::sanitizeRecords(const std::string& prefix, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, bool rdQuery)
2369{
2370 const bool wasForwardRecurse = wasForwarded && rdQuery;
2371 /* list of names for which we will allow A and AAAA records in the additional section
2372 to remain */
2373 std::unordered_set<DNSName> allowedAdditionals = { qname };
2374 bool haveAnswers = false;
2375 bool isNXDomain = false;
2376 bool isNXQType = false;
2377
2378 for(auto rec = lwr.d_records.begin(); rec != lwr.d_records.end(); ) {
2379
2380 if (rec->d_type == QType::OPT) {
2381 ++rec;
2382 continue;
2383 }
2384
2385 if (rec->d_class != QClass::IN) {
2386 LOG(prefix<<"Removing non internet-classed data received from "<<auth<<endl);
2387 rec = lwr.d_records.erase(rec);
2388 continue;
2389 }
2390
2391 if (rec->d_type == QType::ANY) {
2392 LOG(prefix<<"Removing 'ANY'-typed data received from "<<auth<<endl);
2393 rec = lwr.d_records.erase(rec);
2394 continue;
2395 }
2396
2397 if (!rec->d_name.isPartOf(auth)) {
2398 LOG(prefix<<"Removing record '"<<rec->d_name<<"|"<<DNSRecordContent::NumberToType(rec->d_type)<<"|"<<rec->d_content->getZoneRepresentation()<<"' in the "<<(int)rec->d_place<<" section received from "<<auth<<endl);
2399 rec = lwr.d_records.erase(rec);
2400 continue;
2401 }
2402
2403 /* dealing with the records in answer */
2404 if (!(lwr.d_aabit || wasForwardRecurse) && rec->d_place == DNSResourceRecord::ANSWER) {
9870af40
RG
2405 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2406 are sending such responses */
2407 if (!(rec->d_type == QType::CNAME && qname == rec->d_name)) {
2408 LOG(prefix<<"Removing record '"<<rec->d_name<<"|"<<DNSRecordContent::NumberToType(rec->d_type)<<"|"<<rec->d_content->getZoneRepresentation()<<"' in the answer section without the AA bit set received from "<<auth<<endl);
2409 rec = lwr.d_records.erase(rec);
2410 continue;
2411 }
7155c3e5
RG
2412 }
2413
2414 if (rec->d_type == QType::DNAME && (rec->d_place != DNSResourceRecord::ANSWER || !qname.isPartOf(rec->d_name))) {
2415 LOG(prefix<<"Removing invalid DNAME record '"<<rec->d_name<<"|"<<DNSRecordContent::NumberToType(rec->d_type)<<"|"<<rec->d_content->getZoneRepresentation()<<"' in the "<<(int)rec->d_place<<" section received from "<<auth<<endl);
2416 rec = lwr.d_records.erase(rec);
2417 continue;
2418 }
2419
123da0f8 2420 if (rec->d_place == DNSResourceRecord::ANSWER && (qtype != QType::ANY && rec->d_type != qtype.getCode() && s_redirectionQTypes.count(rec->d_type) == 0 && rec->d_type != QType::SOA && rec->d_type != QType::RRSIG)) {
7155c3e5
RG
2421 LOG(prefix<<"Removing irrelevant record '"<<rec->d_name<<"|"<<DNSRecordContent::NumberToType(rec->d_type)<<"|"<<rec->d_content->getZoneRepresentation()<<"' in the "<<(int)rec->d_place<<" section received from "<<auth<<endl);
2422 rec = lwr.d_records.erase(rec);
2423 continue;
2424 }
2425
2426 if (rec->d_place == DNSResourceRecord::ANSWER && !haveAnswers) {
2427 haveAnswers = true;
2428 }
2429
2430 if (rec->d_place == DNSResourceRecord::ANSWER) {
2431 allowAdditionalEntry(allowedAdditionals, *rec);
2432 }
2433
2434 /* dealing with the records in authority */
2435 if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type != QType::NS && rec->d_type != QType::DS && rec->d_type != QType::SOA && rec->d_type != QType::RRSIG && rec->d_type != QType::NSEC && rec->d_type != QType::NSEC3) {
2436 LOG(prefix<<"Removing irrelevant record '"<<rec->d_name<<"|"<<DNSRecordContent::NumberToType(rec->d_type)<<"|"<<rec->d_content->getZoneRepresentation()<<"' in the "<<(int)rec->d_place<<" section received from "<<auth<<endl);
2437 rec = lwr.d_records.erase(rec);
2438 continue;
2439 }
2440
2441 if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type == QType::SOA) {
2442 if (!qname.isPartOf(rec->d_name)) {
2443 LOG(prefix<<"Removing irrelevant record '"<<rec->d_name<<"|"<<DNSRecordContent::NumberToType(rec->d_type)<<"|"<<rec->d_content->getZoneRepresentation()<<"' in the "<<(int)rec->d_place<<" section received from "<<auth<<endl);
2444 rec = lwr.d_records.erase(rec);
2445 continue;
2446 }
2447
215c16f9
RG
2448 if (!(lwr.d_aabit || wasForwardRecurse)) {
2449 LOG(prefix<<"Removing irrelevant record '"<<rec->d_name<<"|"<<DNSRecordContent::NumberToType(rec->d_type)<<"|"<<rec->d_content->getZoneRepresentation()<<"' in the "<<(int)rec->d_place<<" section received from "<<auth<<endl);
2450 rec = lwr.d_records.erase(rec);
2451 continue;
2452 }
2453
7155c3e5
RG
2454 if (!haveAnswers) {
2455 if (lwr.d_rcode == RCode::NXDomain) {
2456 isNXDomain = true;
2457 }
2458 else if (lwr.d_rcode == RCode::NoError) {
2459 isNXQType = true;
2460 }
2461 }
2462 }
2463
2464 if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type == QType::NS && (isNXDomain || isNXQType)) {
2465 /* we don't want to pick up NS records in AUTHORITY or ADDITIONAL sections of NXDomain answers
2466 because they are somewhat easy to insert into a large, fragmented UDP response
1bb97c02 2467 for an off-path attacker by injecting spoofed UDP fragments.
7155c3e5
RG
2468 */
2469 LOG(prefix<<"Removing NS record '"<<rec->d_name<<"|"<<DNSRecordContent::NumberToType(rec->d_type)<<"|"<<rec->d_content->getZoneRepresentation()<<"' in the "<<(int)rec->d_place<<" section of a "<<(isNXDomain ? "NXD" : "NXQTYPE")<<" response received from "<<auth<<endl);
2470 rec = lwr.d_records.erase(rec);
1bb97c02 2471 continue;
7155c3e5
RG
2472 }
2473
2474 if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type == QType::NS) {
2475 allowAdditionalEntry(allowedAdditionals, *rec);
2476 }
2477
2478 /* dealing with the records in additional */
2479 if (rec->d_place == DNSResourceRecord::ADDITIONAL && rec->d_type != QType::A && rec->d_type != QType::AAAA && rec->d_type != QType::RRSIG) {
2480 LOG(prefix<<"Removing irrelevant record '"<<rec->d_name<<"|"<<DNSRecordContent::NumberToType(rec->d_type)<<"|"<<rec->d_content->getZoneRepresentation()<<"' in the "<<(int)rec->d_place<<" section received from "<<auth<<endl);
2481 rec = lwr.d_records.erase(rec);
2482 continue;
2483 }
2484
2485 if (rec->d_place == DNSResourceRecord::ADDITIONAL && allowedAdditionals.count(rec->d_name) == 0) {
2486 LOG(prefix<<"Removing irrelevant additional record '"<<rec->d_name<<"|"<<DNSRecordContent::NumberToType(rec->d_type)<<"|"<<rec->d_content->getZoneRepresentation()<<"' in the "<<(int)rec->d_place<<" section received from "<<auth<<endl);
2487 rec = lwr.d_records.erase(rec);
2488 continue;
2489 }
2490
2491 ++rec;
2492 }
2493}
2494
78cdf520 2495RCode::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, bool& gatherWildcardProof, unsigned int& wildcardLabelsCount, bool rdQuery)
4d2be65d 2496{
ba40d3d7 2497 bool wasForwardRecurse = wasForwarded && rdQuery;
26ca3513
RG
2498 tcache_t tcache;
2499
4d2be65d
RG
2500 string prefix;
2501 if(doLog()) {
2502 prefix=d_prefix;
2503 prefix.append(depth, ' ');
2504 }
2505
7155c3e5
RG
2506 sanitizeRecords(prefix, lwr, qname, qtype, auth, wasForwarded, rdQuery);
2507
2b984251 2508 std::vector<std::shared_ptr<DNSRecord>> authorityRecs;
142ab370 2509 const unsigned int labelCount = qname.countLabels();
a82d4e27 2510 bool isCNAMEAnswer = false;
8838c88f 2511 bool isDNAMEAnswer = false;
26ca3513 2512 for(const auto& rec : lwr.d_records) {
c5310862
RG
2513 if (rec.d_class != QClass::IN) {
2514 continue;
2515 }
2516
d30b5493 2517 if(!isCNAMEAnswer && rec.d_place == DNSResourceRecord::ANSWER && rec.d_type == QType::CNAME && (!(qtype==QType(QType::CNAME))) && rec.d_name == qname && !isDNAMEAnswer) {
a82d4e27
RG
2518 isCNAMEAnswer = true;
2519 }
d30b5493 2520 if(!isDNAMEAnswer && rec.d_place == DNSResourceRecord::ANSWER && rec.d_type == QType::DNAME && qtype != QType(QType::DNAME) && qname.isPartOf(rec.d_name)) {
8838c88f 2521 isDNAMEAnswer = true;
d30b5493 2522 isCNAMEAnswer = false;
8838c88f 2523 }
a82d4e27 2524
9b061cf5
RG
2525 /* if we have a positive answer synthetized from a wildcard,
2526 we need to store the corresponding NSEC/NSEC3 records proving
2527 that the exact name did not exist in the negative cache */
78cdf520 2528 if(gatherWildcardProof) {
2b984251
RG
2529 if (nsecTypes.count(rec.d_type)) {
2530 authorityRecs.push_back(std::make_shared<DNSRecord>(rec));
2531 }
2532 else if (rec.d_type == QType::RRSIG) {
2533 auto rrsig = getRR<RRSIGRecordContent>(rec);
2534 if (rrsig && nsecTypes.count(rrsig->d_type)) {
2535 authorityRecs.push_back(std::make_shared<DNSRecord>(rec));
2536 }
2537 }
2538 }
26ca3513
RG
2539 if(rec.d_type == QType::RRSIG) {
2540 auto rrsig = getRR<RRSIGRecordContent>(rec);
2541 if (rrsig) {
bb07ad8e
RG
2542 /* As illustrated in rfc4035's Appendix B.6, the RRSIG label
2543 count can be lower than the name's label count if it was
9b061cf5 2544 synthetized from the wildcard. Note that the difference might
bb07ad8e 2545 be > 1. */
78cdf520
RG
2546 if (rec.d_name == qname && isWildcardExpanded(labelCount, rrsig)) {
2547 gatherWildcardProof = true;
2548 if (!isWildcardExpandedOntoItself(rec.d_name, labelCount, rrsig)) {
2549 /* if we have a wildcard expanded onto itself, we don't need to prove
2550 that the exact name doesn't exist because it actually does.
2551 We still want to gather the corresponding NSEC/NSEC3 records
2552 to pass them to our client in case it wants to validate by itself.
2553 */
2554 LOG(prefix<<qname<<": RRSIG indicates the name was synthetized from a wildcard, we need a wildcard proof"<<endl);
2555 needWildcardProof = true;
2556 }
2557 else {
2558 LOG(prefix<<qname<<": RRSIG indicates the name was synthetized from a wildcard expanded onto itself, we need to gather wildcard proof"<<endl);
2559 }
e4894ce0 2560 wildcardLabelsCount = rrsig->d_labels;
2b984251
RG
2561 }
2562
26ca3513
RG
2563 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
2564 tcache[{rec.d_name, rrsig->d_type, rec.d_place}].signatures.push_back(rrsig);
4d2be65d 2565 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);
26ca3513
RG
2566 }
2567 }
2568 }
2569
2570 // reap all answers from this packet that are acceptable
2571 for(auto& rec : lwr.d_records) {
2572 if(rec.d_type == QType::OPT) {
2573 LOG(prefix<<qname<<": OPT answer '"<<rec.d_name<<"' from '"<<auth<<"' nameservers" <<endl);
2574 continue;
2575 }
e77f01d1 2576 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<<" ");
26ca3513 2577 if(rec.d_type == QType::ANY) {
c5310862
RG
2578 LOG("NO! - we don't accept 'ANY'-typed data"<<endl);
2579 continue;
2580 }
2581
2582 if(rec.d_class != QClass::IN) {
2583 LOG("NO! - we don't accept records for any other class than 'IN'"<<endl);
26ca3513
RG
2584 continue;
2585 }
2586
70ea0c65 2587 if (!(lwr.d_aabit || wasForwardRecurse) && rec.d_place == DNSResourceRecord::ANSWER) {
9870af40
RG
2588 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2589 are sending such responses */
2590 if (!(rec.d_type == QType::CNAME && rec.d_name == qname)) {
2591 LOG("NO! - we don't accept records in the answers section without the AA bit set"<<endl);
2592 continue;
2593 }
70ea0c65
RG
2594 }
2595
26ca3513
RG
2596 if(rec.d_name.isPartOf(auth)) {
2597 if(rec.d_type == QType::RRSIG) {
2598 LOG("RRSIG - separate"<<endl);
2599 }
4d2be65d 2600 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)) {
26ca3513
RG
2601 LOG("NO! Is from delegation-only zone"<<endl);
2602 s_nodelegated++;
2603 return RCode::NXDomain;
2604 }
2605 else {
2606 bool haveLogged = false;
d30b5493
PL
2607 if (isDNAMEAnswer && rec.d_type == QType::CNAME) {
2608 LOG("NO - we already have a DNAME answer for this domain");
2609 continue;
2610 }
a712cb56 2611 if (!t_sstorage.domainmap->empty()) {
26ca3513
RG
2612 // Check if we are authoritative for a zone in this answer
2613 DNSName tmp_qname(rec.d_name);
2614 auto auth_domain_iter=getBestAuthZone(&tmp_qname);
a712cb56 2615 if(auth_domain_iter!=t_sstorage.domainmap->end() &&
26ca3513
RG
2616 auth.countLabels() <= auth_domain_iter->first.countLabels()) {
2617 if (auth_domain_iter->first != auth) {
2618 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter->first<<endl);
2619 continue;
2620 } else {
2621 LOG("YES! - This answer was ");
6dfff36f 2622 if (!wasForwarded) {
26ca3513
RG
2623 LOG("retrieved from the local auth store.");
2624 } else {
2625 LOG("received from a server we forward to.");
2626 }
2627 haveLogged = true;
2628 LOG(endl);
2629 }
2630 }
2631 }
2632 if (!haveLogged) {
2633 LOG("YES!"<<endl);
2634 }
2635
2636 rec.d_ttl=min(s_maxcachettl, rec.d_ttl);
2637
2638 DNSRecord dr(rec);
26ca3513 2639 dr.d_ttl += d_now.tv_sec;
2b984251 2640 dr.d_place=DNSResourceRecord::ANSWER;
26ca3513
RG
2641 tcache[{rec.d_name,rec.d_type,rec.d_place}].records.push_back(dr);
2642 }
2643 }
2644 else
2645 LOG("NO!"<<endl);
2646 }
2647
2648 // supplant
4d2be65d
RG
2649 for(tcache_t::iterator i = tcache.begin(); i != tcache.end(); ++i) {
2650 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)
2651 uint32_t lowestTTD=computeLowestTTD(i->second.records, i->second.signatures, i->second.signaturesTTL);
26ca3513
RG
2652
2653 for(auto& record : i->second.records)
4d2be65d 2654 record.d_ttl = lowestTTD; // boom
26ca3513
RG
2655 }
2656
2657// cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
2658// cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
4d2be65d
RG
2659 }
2660
2661 for(tcache_t::iterator i = tcache.begin(); i != tcache.end(); ++i) {
4d2be65d 2662
26ca3513
RG
2663 if(i->second.records.empty()) // this happens when we did store signatures, but passed on the records themselves
2664 continue;
6dfff36f 2665
405a26bd
RG
2666 /* Even if the AA bit is set, additional data cannot be considered
2667 as authoritative. This is especially important during validation
2668 because keeping records in the additional section is allowed even
2669 if the corresponding RRSIGs are not included, without setting the TC
2670 bit, as stated in rfc4035's section 3.1.1. Including RRSIG RRs in a Response:
2671 "When placing a signed RRset in the Additional section, the name
2672 server MUST also place its RRSIG RRs in the Additional section.
2673 If space does not permit inclusion of both the RRset and its
2674 associated RRSIG RRs, the name server MAY retain the RRset while
2675 dropping the RRSIG RRs. If this happens, the name server MUST NOT
2676 set the TC bit solely because these RRSIG RRs didn't fit."
2677 */
2678 bool isAA = lwr.d_aabit && i->first.place != DNSResourceRecord::ADDITIONAL;
dff3ef07
RG
2679 /* if we forwarded the query to a recursor, we can expect the answer to be signed,
2680 even if the answer is not AA. Of course that's not only true inside a Secure
2681 zone, but we check that below. */
70ea0c65 2682 bool expectSignature = i->first.place == DNSResourceRecord::ANSWER || ((lwr.d_aabit || wasForwardRecurse) && i->first.place != DNSResourceRecord::ADDITIONAL);
dff3ef07 2683 if (isCNAMEAnswer && (i->first.place != DNSResourceRecord::ANSWER || i->first.type != QType::CNAME || i->first.name != qname)) {
a82d4e27
RG
2684 /*
2685 rfc2181 states:
2686 Note that the answer section of an authoritative answer normally
2687 contains only authoritative data. However when the name sought is an
2688 alias (see section 10.1.1) only the record describing that alias is
2689 necessarily authoritative. Clients should assume that other records
2690 may have come from the server's cache. Where authoritative answers
2691 are required, the client should query again, using the canonical name
2692 associated with the alias.
2693 */
2694 isAA = false;
dff3ef07 2695 expectSignature = false;
a82d4e27
RG
2696 }
2697
d9c32b52
RG
2698 if (isCNAMEAnswer && i->first.place == DNSResourceRecord::AUTHORITY && i->first.type == QType::NS && auth == i->first.name) {
2699 /* These NS can't be authoritative since we have a CNAME answer for which (see above) only the
2700 record describing that alias is necessarily authoritative.
2701 But if we allow the current auth, which might be serving the child zone, to raise the TTL
2702 of non-authoritative NS in the cache, they might be able to keep a "ghost" zone alive forever,
2703 even after the delegation is gone from the parent.
2704 So let's just do nothing with them, we can fetch them directly if we need them.
2705 */
2706 LOG(d_prefix<<": skipping authority NS from '"<<auth<<"' nameservers in CNAME answer "<<i->first.name<<"|"<<DNSRecordContent::NumberToType(i->first.type)<<endl);
2707 continue;
2708 }
2709
5374b03b 2710 vState recordState = getValidationStatus(i->first.name, false);
1a8d6a9e 2711 LOG(d_prefix<<": got initial zone status "<<vStates[recordState]<<" for record "<<i->first.name<<"|"<<DNSRecordContent::NumberToType(i->first.type)<<endl);
70b3fe7a 2712
e1636f82 2713 if (shouldValidate() && recordState == Secure) {
5374b03b
RG
2714 vState initialState = recordState;
2715
dff3ef07 2716 if (expectSignature) {
4d2be65d
RG
2717 if (i->first.place != DNSResourceRecord::ADDITIONAL) {
2718 /* the additional entries can be insecure,
2719 like glue:
2720 "Glue address RRsets associated with delegations MUST NOT be signed"
2721 */
2722 if (i->first.type == QType::DNSKEY && i->first.place == DNSResourceRecord::ANSWER) {
bcb05770 2723 LOG(d_prefix<<"Validating DNSKEY for "<<i->first.name<<endl);
51b6b728 2724 recordState = validateDNSKeys(i->first.name, i->second.records, i->second.signatures, depth);
4d2be65d
RG
2725 }
2726 else {
8838c88f
PL
2727 /*
2728 * RFC 6672 section 5.3.1
2729 * In any response, a signed DNAME RR indicates a non-terminal
2730 * redirection of the query. There might or might not be a server-
2731 * synthesized CNAME in the answer section; if there is, the CNAME will
2732 * never be signed. For a DNSSEC validator, verification of the DNAME
2733 * RR and then that the CNAME was properly synthesized is sufficient
2734 * proof.
2735 *
2736 * We do the synthesis check in processRecords, here we make sure we
2737 * don't validate the CNAME.
2738 */
2739 if (!(isDNAMEAnswer && i->first.type == QType::CNAME)) {
2740 LOG(d_prefix<<"Validating non-additional record for "<<i->first.name<<endl);
2741 recordState = validateRecordsWithSigs(depth, qname, qtype, i->first.name, i->second.records, i->second.signatures);
2742 /* 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 */
2743 if (qtype == QType::NS && i->second.signatures.empty() && recordState == Bogus && haveExactValidationStatus(i->first.name) && getValidationStatus(i->first.name) == Indeterminate) {
2744 recordState = Indeterminate;
2745 }
0735b60f 2746 }
4d2be65d
RG
2747 }
2748 }
2749 }
2750 else {
933299e8
RG
2751 recordState = Indeterminate;
2752
a82d4e27 2753 /* in a non authoritative answer, we only care about the DS record (or lack of) */
88cb0fe0 2754 if ((i->first.type == QType::DS || i->first.type == QType::NSEC || i->first.type == QType::NSEC3) && i->first.place == DNSResourceRecord::AUTHORITY) {
bcb05770 2755 LOG(d_prefix<<"Validating DS record for "<<i->first.name<<endl);
51b6b728 2756 recordState = validateRecordsWithSigs(depth, qname, qtype, i->first.name, i->second.records, i->second.signatures);
4d2be65d
RG
2757 }
2758 }
0735b60f 2759
dff3ef07 2760 if (initialState == Secure && state != recordState && expectSignature) {
5374b03b
RG
2761 updateValidationState(state, recordState);
2762 }
4d2be65d
RG
2763 }
2764 else {
e1636f82 2765 if (shouldValidate()) {
bcb05770 2766 LOG(d_prefix<<"Skipping validation because the current state is "<<vStates[recordState]<<endl);
4d2be65d
RG
2767 }
2768 }
2769
b9473937
RG
2770 if (recordState == Bogus) {
2771 /* this is a TTD by now, be careful */
2772 for(auto& record : i->second.records) {
2773 record.d_ttl = std::min(record.d_ttl, static_cast<uint32_t>(s_maxbogusttl + d_now.tv_sec));
2774 }
2775 }
2776
005b4b98
RG
2777 /* We don't need to store NSEC3 records in the positive cache because:
2778 - we don't allow direct NSEC3 queries
2779 - denial of existence proofs in wildcard expanded positive responses are stored in authorityRecs
2780 - denial of existence proofs for negative responses are stored in the negative cache
a321baf9
RG
2781 We also don't want to cache non-authoritative data except for:
2782 - records coming from non forward-recurse servers (those will never be AA)
2783 - DS (special case)
2784 - NS, A and AAAA (used for infra queries)
005b4b98 2785 */
a321baf9 2786 if (i->first.type != QType::NSEC3 && (i->first.type == QType::DS || i->first.type == QType::NS || i->first.type == QType::A || i->first.type == QType::AAAA || isAA || wasForwardRecurse)) {
e7861cc4 2787
73d9bf3a
OM
2788 bool doCache = true;
2789 if (i->first.place == DNSResourceRecord::ANSWER && ednsmask) {
2790 // If ednsmask is relevant, we do not want to cache if the scope prefix length is large and TTL is small
2791 if (SyncRes::s_ecscachelimitttl > 0) {
d14121a8 2792 bool manyMaskBits = (ednsmask->isIPv4() && ednsmask->getBits() > SyncRes::s_ecsipv4cachelimit) ||
37e35fbc 2793 (ednsmask->isIPv6() && ednsmask->getBits() > SyncRes::s_ecsipv6cachelimit);
e7861cc4 2794
e7861cc4
OM
2795 if (manyMaskBits) {
2796 uint32_t minttl = UINT32_MAX;
2797 for (const auto &it : i->second.records) {
2798 if (it.d_ttl < minttl)
2799 minttl = it.d_ttl;
2800 }
2801 bool ttlIsSmall = minttl < SyncRes::s_ecscachelimitttl + d_now.tv_sec;
2802 if (ttlIsSmall) {
2803 // Case: many bits and ttlIsSmall
2804 doCache = false;
2805 }
e7861cc4 2806 }
ed9019c9 2807 }
e7861cc4
OM
2808 }
2809 if (doCache) {
2810 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);
bdceeb7e 2811 }
005b4b98 2812 }
6dfff36f 2813
26ca3513
RG
2814 if(i->first.place == DNSResourceRecord::ANSWER && ednsmask)
2815 d_wasVariable=true;
2816 }
2817
2818 return RCode::NoError;
2819}
2820
28364e4b 2821void SyncRes::updateDenialValidationState(vState& neValidationState, const DNSName& neName, vState& state, const dState denialState, const dState expectedState, bool allowOptOut)
4d2be65d 2822{
b25712fd 2823 if (denialState == expectedState) {
28364e4b 2824 neValidationState = Secure;
b25712fd
RG
2825 }
2826 else {
142ab370 2827 if (denialState == OPTOUT && allowOptOut) {
28364e4b
RG
2828 LOG(d_prefix<<"OPT-out denial found for "<<neName<<endl);
2829 neValidationState = Secure;
142ab370 2830 return;
4d2be65d 2831 }
142ab370 2832 else if (denialState == INSECURE) {
28364e4b
RG
2833 LOG(d_prefix<<"Insecure denial found for "<<neName<<", returning Insecure"<<endl);
2834 neValidationState = Insecure;
4d2be65d 2835 }
142ab370 2836 else {
28364e4b
RG
2837 LOG(d_prefix<<"Invalid denial found for "<<neName<<", returning Bogus, res="<<denialState<<", expectedState="<<expectedState<<endl);
2838 neValidationState = Bogus;
142ab370 2839 }
28364e4b 2840 updateValidationState(state, neValidationState);
4d2be65d
RG
2841 }
2842}
2843
28364e4b 2844dState SyncRes::getDenialValidationState(const NegCache::NegCacheEntry& ne, const vState state, const dState expectedState, bool referralToUnsigned)
142ab370
RG
2845{
2846 cspmap_t csp = harvestCSPFromNE(ne);
2847 return getDenial(csp, ne.d_name, ne.d_qtype.getCode(), referralToUnsigned, expectedState == NXQTYPE);
2848}
2849
78cdf520 2850bool SyncRes::processRecords(const std::string& prefix, const DNSName& qname, const QType& qtype, const DNSName& auth, LWResult& lwr, const bool sendRDQuery, vector<DNSRecord>& ret, set<DNSName>& nsset, DNSName& newtarget, DNSName& newauth, bool& realreferral, bool& negindic, vState& state, const bool needWildcardProof, const bool gatherWildcardProof, const unsigned int wildcardLabelsCount)
26ca3513
RG
2851{
2852 bool done = false;
123da0f8 2853 DNSName dnameTarget, dnameOwner;
ee936074 2854 uint32_t dnameTTL = 0;
26ca3513
RG
2855
2856 for(auto& rec : lwr.d_records) {
2857 if (rec.d_type!=QType::OPT && rec.d_class!=QClass::IN)
2858 continue;
2859
70ea0c65 2860 if (rec.d_place==DNSResourceRecord::ANSWER && !(lwr.d_aabit || sendRDQuery)) {
9870af40
RG
2861 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2862 are sending such responses */
2863 if (!(rec.d_type == QType::CNAME && rec.d_name == qname)) {
2864 continue;
2865 }
70ea0c65
RG
2866 }
2867
26ca3513
RG
2868 if(rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::SOA &&
2869 lwr.d_rcode==RCode::NXDomain && qname.isPartOf(rec.d_name) && rec.d_name.isPartOf(auth)) {
2870 LOG(prefix<<qname<<": got negative caching indication for name '"<<qname<<"' (accept="<<rec.d_name.isPartOf(auth)<<"), newtarget='"<<newtarget<<"'"<<endl);
2871
2872 rec.d_ttl = min(rec.d_ttl, s_maxnegttl);
2873 if(newtarget.empty()) // only add a SOA if we're not going anywhere after this
2874 ret.push_back(rec);
39ce10b2 2875
114829cc
RG
2876 NegCache::NegCacheEntry ne;
2877
dbbef467 2878 uint32_t lowestTTL = rec.d_ttl;
9b061cf5
RG
2879 /* if we get an NXDomain answer with a CNAME, the name
2880 does exist but the target does not */
2881 ne.d_name = newtarget.empty() ? qname : newtarget;
114829cc
RG
2882 ne.d_qtype = QType(0); // this encodes 'whole record'
2883 ne.d_auth = rec.d_name;
dbbef467 2884 harvestNXRecords(lwr.d_records, ne, d_now.tv_sec, &lowestTTL);
dbbef467 2885
142ab370
RG
2886 if (state == Secure) {
2887 dState denialState = getDenialValidationState(ne, state, NXDOMAIN, false);
28364e4b 2888 updateDenialValidationState(ne.d_validationState, ne.d_name, state, denialState, NXDOMAIN, false);
142ab370
RG
2889 }
2890 else {
2891 ne.d_validationState = state;
2892 }
114829cc 2893
b9473937
RG
2894 if (ne.d_validationState == Bogus) {
2895 lowestTTL = min(lowestTTL, s_maxbogusttl);
2896 }
2897
2898 ne.d_ttd = d_now.tv_sec + lowestTTL;
9b061cf5
RG
2899 /* if we get an NXDomain answer with a CNAME, let's not cache the
2900 target, even the server was authoritative for it,
2901 and do an additional query for the CNAME target.
2902 We have a regression test making sure we do exactly that.
2903 */
2904 if(!wasVariable() && newtarget.empty()) {
a712cb56 2905 t_sstorage.negcache.add(ne);
2ef32aec 2906 if(s_rootNXTrust && ne.d_auth.isRoot() && auth.isRoot() && lwr.d_aabit) {
9a1e060b 2907 ne.d_name = ne.d_name.getLastLabel();
a712cb56 2908 t_sstorage.negcache.add(ne);
26ca3513
RG
2909 }
2910 }
2911
2912 negindic=true;
2913 }
123da0f8
PL
2914 else if(rec.d_place==DNSResourceRecord::ANSWER && s_redirectionQTypes.count(rec.d_type) > 0 && // CNAME or DNAME answer
2915 s_redirectionQTypes.count(qtype.getCode()) == 0) { // But not in response to a CNAME or DNAME query
2916 if (rec.d_type == QType::CNAME && rec.d_name == qname) {
ee936074
PL
2917 if (!dnameOwner.empty()) { // We synthesize ourselves
2918 continue;
2919 }
123da0f8
PL
2920 ret.push_back(rec);
2921 if (auto content = getRR<CNAMERecordContent>(rec)) {
2922 newtarget=content->getTarget();
2923 }
2924 } else if (rec.d_type == QType::DNAME && qname.isPartOf(rec.d_name)) { // DNAME
2925 ret.push_back(rec);
2926 if (auto content = getRR<DNAMERecordContent>(rec)) {
2927 dnameOwner = rec.d_name;
2928 dnameTarget = content->getTarget();
ee936074 2929 dnameTTL = rec.d_ttl;
29ec25aa
PL
2930 if (!newtarget.empty()) { // We had a CNAME before, remove it from ret so we don't cache it
2931 ret.erase(std::remove_if(
2932 ret.begin(),
2933 ret.end(),
2934 [&qname](DNSRecord& rr) {
2935 return (rr.d_place == DNSResourceRecord::ANSWER && rr.d_type == QType::CNAME && rr.d_name == qname);
2936 }),
2937 ret.end());
2938 }
ee936074
PL
2939 try {
2940 newtarget = qname.makeRelative(dnameOwner) + dnameTarget;
2941 } catch (const std::exception &e) {
2942 // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
2943 // But there is no way to set the RCODE from this function
2944 throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + dnameOwner.toLogString() +
2945 "', DNAME target: '" + dnameTarget.toLogString() + "', substituted name: '" +
2946 qname.makeRelative(dnameOwner).toLogString() + "." + dnameTarget.toLogString() +
2947 "' : " + e.what());
2948 }
123da0f8 2949 }
26ca3513
RG
2950 }
2951 }
9b061cf5
RG
2952 /* if we have a positive answer synthetized from a wildcard, we need to
2953 return the corresponding NSEC/NSEC3 records from the AUTHORITY section
2954 proving that the exact name did not exist */
78cdf520 2955 else if(gatherWildcardProof && (rec.d_type==QType::RRSIG || rec.d_type==QType::NSEC || rec.d_type==QType::NSEC3) && rec.d_place==DNSResourceRecord::AUTHORITY) {
2b984251
RG
2956 ret.push_back(rec); // enjoy your DNSSEC
2957 }
26ca3513
RG
2958 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
2959 else if(rec.d_place==DNSResourceRecord::ANSWER && rec.d_name == qname &&
2960 (
331222c4 2961 rec.d_type==qtype.getCode() || ((lwr.d_aabit || sendRDQuery) && qtype == QType(QType::ANY))
26ca3513
RG
2962 )
2963 )
2964 {
2965 LOG(prefix<<qname<<": answer is in: resolved to '"<< rec.d_content->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec.d_type)<<"'"<<endl);
2966
2967 done=true;
9b061cf5
RG
2968
2969 if (state == Secure && needWildcardProof) {
2970 /* We have a positive answer synthetized from a wildcard, we need to check that we have
2971 proof that the exact name doesn't exist so the wildcard can be used,
d0d39496 2972 as described in section 5.3.4 of RFC 4035 and 5.3 of RFC 7129.
9b061cf5
RG
2973 */
2974 NegCache::NegCacheEntry ne;
2975
2976 uint32_t lowestTTL = rec.d_ttl;
2977 ne.d_name = qname;
2978 ne.d_qtype = QType(0); // this encodes 'whole record'
2979 harvestNXRecords(lwr.d_records, ne, d_now.tv_sec, &lowestTTL);
2980
2981 cspmap_t csp = harvestCSPFromNE(ne);
e4894ce0 2982 dState res = getDenial(csp, qname, ne.d_qtype.getCode(), false, false, false, wildcardLabelsCount);
9b061cf5 2983 if (res != NXDOMAIN) {
b7c40613
RG
2984 vState st = Bogus;
2985 if (res == INSECURE) {
2986 /* Some part could not be validated, for example a NSEC3 record with a too large number of iterations,
2987 this is not enough to warrant a Bogus, but go Insecure. */
2988 st = Insecure;
2989 LOG(d_prefix<<"Unable to validate denial in wildcard expanded positive response found for "<<qname<<", returning Insecure, res="<<res<<endl);
2990 }
2991 else {
2992 LOG(d_prefix<<"Invalid denial in wildcard expanded positive response found for "<<qname<<", returning Bogus, res="<<res<<endl);
b9473937 2993 rec.d_ttl = std::min(rec.d_ttl, s_maxbogusttl);
b7c40613
RG
2994 }
2995
2996 updateValidationState(state, st);
2997 /* we already stored the record with a different validation status, let's fix it */
b9473937 2998 updateValidationStatusInCache(qname, qtype, lwr.d_aabit, st);
9b061cf5
RG
2999 }
3000 }
b9473937 3001 ret.push_back(rec);
26ca3513 3002 }
7030a59b 3003 else if((rec.d_type==QType::RRSIG || rec.d_type==QType::NSEC || rec.d_type==QType::NSEC3) && rec.d_place==DNSResourceRecord::ANSWER) {
123da0f8 3004 if(rec.d_type != QType::RRSIG || rec.d_name == qname) {
7030a59b 3005 ret.push_back(rec); // enjoy your DNSSEC
123da0f8
PL
3006 } else if(rec.d_type == QType::RRSIG && qname.isPartOf(rec.d_name)) {
3007 auto rrsig = getRR<RRSIGRecordContent>(rec);
3008 if (rrsig != nullptr && rrsig->d_type == QType::DNAME) {
3009 ret.push_back(rec);
3010 }
3011 }
7030a59b 3012 }
4d2be65d 3013 else if(rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::NS && qname.isPartOf(rec.d_name)) {
26ca3513
RG
3014 if(moreSpecificThan(rec.d_name,auth)) {
3015 newauth=rec.d_name;
3016 LOG(prefix<<qname<<": got NS record '"<<rec.d_name<<"' -> '"<<rec.d_content->getZoneRepresentation()<<"'"<<endl);
3017 realreferral=true;
3018 }
3019 else {
3020 LOG(prefix<<qname<<": got upwards/level NS record '"<<rec.d_name<<"' -> '"<<rec.d_content->getZoneRepresentation()<<"', had '"<<auth<<"'"<<endl);
3021 }
3022 if (auto content = getRR<NSRecordContent>(rec)) {
3023 nsset.insert(content->getNS());
3024 }
3025 }
4d2be65d 3026 else if(rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::DS && qname.isPartOf(rec.d_name)) {
26ca3513 3027 LOG(prefix<<qname<<": got DS record '"<<rec.d_name<<"' -> '"<<rec.d_content->getZoneRepresentation()<<"'"<<endl);
26ca3513 3028 }
860d5e8e 3029 else if(realreferral && rec.d_place==DNSResourceRecord::AUTHORITY && (rec.d_type==QType::NSEC || rec.d_type==QType::NSEC3) && newauth.isPartOf(auth)) {
4d2be65d
RG
3030 /* we might have received a denial of the DS, let's check */
3031 if (state == Secure) {
3032 NegCache::NegCacheEntry ne;
3033 ne.d_auth = auth;
860d5e8e
RG
3034 ne.d_name = newauth;
3035 ne.d_qtype = QType::DS;
dbbef467
RG
3036 rec.d_ttl = min(s_maxnegttl, rec.d_ttl);
3037 uint32_t lowestTTL = rec.d_ttl;
3038 harvestNXRecords(lwr.d_records, ne, d_now.tv_sec, &lowestTTL);
3039
142ab370
RG
3040 dState denialState = getDenialValidationState(ne, state, NXQTYPE, true);
3041
d377bb54 3042 if (denialState == NXQTYPE || denialState == OPTOUT || denialState == INSECURE) {
dbbef467 3043 ne.d_ttd = lowestTTL + d_now.tv_sec;
860d5e8e 3044 ne.d_validationState = Secure;
812c3a69 3045 LOG(prefix<<qname<<": got negative indication of DS record for '"<<newauth<<"'"<<endl);
5374b03b 3046
4d2be65d
RG
3047 if(!wasVariable()) {
3048 t_sstorage.negcache.add(ne);
3049 }
5374b03b
RG
3050
3051 if (qname == newauth && qtype == QType::DS) {
3052 /* we are actually done! */
3053 negindic=true;
3054 nsset.clear();
3055 }
4d2be65d
RG
3056 }
3057 }
3058 }
3059 else if(!done && rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::SOA &&
3060 lwr.d_rcode==RCode::NoError && qname.isPartOf(rec.d_name)) {
26ca3513
RG
3061 LOG(prefix<<qname<<": got negative caching indication for '"<< qname<<"|"<<qtype.getName()<<"'"<<endl);
3062
3063 if(!newtarget.empty()) {
3064 LOG(prefix<<qname<<": Hang on! Got a redirect to '"<<newtarget<<"' already"<<endl);
3065 }
3066 else {
3067 rec.d_ttl = min(s_maxnegttl, rec.d_ttl);
114829cc
RG
3068
3069 NegCache::NegCacheEntry ne;
3070 ne.d_auth = rec.d_name;
dbbef467 3071 uint32_t lowestTTL = rec.d_ttl;
114829cc
RG
3072 ne.d_name = qname;
3073 ne.d_qtype = qtype;
dbbef467 3074 harvestNXRecords(lwr.d_records, ne, d_now.tv_sec, &lowestTTL);
dbbef467 3075
142ab370
RG
3076 if (state == Secure) {
3077 dState denialState = getDenialValidationState(ne, state, NXQTYPE, false);
28364e4b 3078 updateDenialValidationState(ne.d_validationState, ne.d_name, state, denialState, NXQTYPE, qtype == QType::DS);
142ab370
RG
3079 } else {
3080 ne.d_validationState = state;
3081 }
114829cc 3082
b9473937
RG
3083 if (ne.d_validationState == Bogus) {
3084 lowestTTL = min(lowestTTL, s_maxbogusttl);
3085 rec.d_ttl = min(rec.d_ttl, s_maxbogusttl);
3086 }
3087 ne.d_ttd = d_now.tv_sec + lowestTTL;
3088
26ca3513 3089 if(!wasVariable()) {
26ca3513 3090 if(qtype.getCode()) { // prevents us from blacking out a whole domain
a712cb56 3091 t_sstorage.negcache.add(ne);
26ca3513
RG
3092 }
3093 }
b9473937
RG
3094
3095 ret.push_back(rec);
26ca3513
RG
3096 negindic=true;
3097 }
3098 }
3099 }
3100
ee936074
PL
3101 if (!dnameTarget.empty()) {
3102 // Synthesize a CNAME
3103 auto cnamerec = DNSRecord();
3104 cnamerec.d_name = qname;
3105 cnamerec.d_type = QType::CNAME;
3106 cnamerec.d_ttl = dnameTTL;
3107 cnamerec.d_content = std::make_shared<CNAMERecordContent>(CNAMERecordContent(newtarget));
3108 ret.push_back(cnamerec);
123da0f8 3109 }
26ca3513
RG
3110 return done;
3111}
3112
6dfff36f
RG
3113bool 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)
3114{
deca7d8f 3115 bool chained = false;
17cecc84 3116 int resolveret = RCode::NoError;
6dfff36f
RG
3117 s_outqueries++;
3118 d_outqueries++;
3119
3120 if(d_outqueries + d_throttledqueries > s_maxqperq) {
3121 throw ImmediateServFailException("more than "+std::to_string(s_maxqperq)+" (max-qperq) queries sent while resolving "+qname.toLogString());
3122 }
3123
3124 if(s_maxtotusec && d_totUsec > s_maxtotusec) {
3125 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");
3126 }
3127
3128 if(doTCP) {
3129 LOG(prefix<<qname<<": using TCP with "<< remoteIP.toStringWithPort() <<endl);
3130 s_tcpoutqueries++;
3131 d_tcpoutqueries++;
3132 }
3133
3134 if(d_pdl && d_pdl->preoutquery(remoteIP, d_requestor, qname, qtype, doTCP, lwr.d_records, resolveret)) {
3135 LOG(prefix<<qname<<": query handled by Lua"<<endl);
3136 }
3137 else {
2fe3354d 3138 ednsmask=getEDNSSubnetMask(qname, remoteIP);
6dfff36f
RG
3139 if(ednsmask) {
3140 LOG(prefix<<qname<<": Adding EDNS Client Subnet Mask "<<ednsmask->toString()<<" to query"<<endl);
d6923beb 3141 s_ecsqueries++;
6dfff36f 3142 }
6de48f75 3143 resolveret = asyncresolveWrapper(remoteIP, d_doDNSSEC, qname, auth, qtype.getCode(),
deca7d8f 3144 doTCP, sendRDQuery, &d_now, ednsmask, &lwr, &chained); // <- we go out on the wire!
6dfff36f 3145 if(ednsmask) {
d6923beb 3146 s_ecsresponses++;
6dfff36f 3147 LOG(prefix<<qname<<": Received EDNS Client Subnet Mask "<<ednsmask->toString()<<" on response"<<endl);
c9783016 3148 if (ednsmask->getBits() > 0) {
d14121a8 3149 if (ednsmask->isIPv4()) {
c9783016
RG
3150 ++SyncRes::s_ecsResponsesBySubnetSize4.at(ednsmask->getBits()-1);
3151 }
3152 else {
3153 ++SyncRes::s_ecsResponsesBySubnetSize6.at(ednsmask->getBits()-1);
3154 }
3155 }
6dfff36f
RG
3156 }
3157 }
3158
3159 /* preoutquery killed the query by setting dq.rcode to -3 */
3160 if(resolveret==-3) {
3161 throw ImmediateServFailException("Query killed by policy");
3162 }
3163
3164 d_totUsec += lwr.d_usec;
3165 accountAuthLatency(lwr.d_usec, remoteIP.sin4.sin_family);
3166
5c8c72bf
PL
3167 bool dontThrottle = false;
3168 {
3169 auto dontThrottleNames = g_dontThrottleNames.getLocal();
3170 auto dontThrottleNetmasks = g_dontThrottleNetmasks.getLocal();
3171 dontThrottle = dontThrottleNames->check(nsName) || dontThrottleNetmasks->match(remoteIP);
3172 }
3173
6dfff36f
RG
3174 if(resolveret != 1) {
3175 /* Error while resolving */
3176 if(resolveret == 0) {
3177 /* Time out */
3178
3179 LOG(prefix<<qname<<": timeout resolving after "<<lwr.d_usec/1000.0<<"msec "<< (doTCP ? "over TCP" : "")<<endl);
3180 d_timeouts++;
3181 s_outgoingtimeouts++;
3182
3183 if(remoteIP.sin4.sin_family == AF_INET)
3184 s_outgoing4timeouts++;
3185 else
3186 s_outgoing6timeouts++;
be9078b3 3187
3188 if(t_timeouts)
3189 t_timeouts->push_back(remoteIP);
6dfff36f
RG
3190 }
3191 else if(resolveret == -2) {
3192 /* OS resource limit reached */
3193 LOG(prefix<<qname<<": hit a local resource limit resolving"<< (doTCP ? " over TCP" : "")<<", probable error: "<<stringerror()<<endl);
3194 g_stats.resourceLimits++;
3195 }
3196 else {
3197 /* -1 means server unreachable */
3198 s_unreachables++;
3199 d_unreachables++;
a702a96c
OM
3200 // XXX questionable use of errno
3201 LOG(prefix<<qname<<": error resolving from "<<remoteIP.toString()<< (doTCP ? " over TCP" : "") <<", possible error: "<<stringerror()<< endl);
6dfff36f
RG
3202 }
3203
5c8c72bf 3204 if(resolveret != -2 && !chained && !dontThrottle) {
559b6c93
PL
3205 // don't account for resource limits, they are our own fault
3206 // And don't throttle when the IP address is on the dontThrottleNetmasks list or the name is part of dontThrottleNames
b9715061 3207 t_sstorage.nsSpeeds[nsName.empty()? DNSName(remoteIP.toStringWithPort()) : nsName].submit(remoteIP, 1000000, d_now); // 1 sec
6dfff36f
RG
3208
3209 // code below makes sure we don't filter COM or the root
60e5208a 3210 if (s_serverdownmaxfails > 0 && (auth != g_rootdnsname) && t_sstorage.fails.incr(remoteIP, d_now) >= s_serverdownmaxfails) {
6dfff36f
RG
3211 LOG(prefix<<qname<<": Max fails reached resolving on "<< remoteIP.toString() <<". Going full throttle for "<< s_serverdownthrottletime <<" seconds" <<endl);
3212 // mark server as down
3213 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, "", 0), s_serverdownthrottletime, 10000);
3214 }
3215 else if (resolveret == -1) {
3216 // unreachable, 1 minute or 100 queries
3217 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 60, 100);
3218 }
3219 else {
559b6c93 3220 // timeout, 10 seconds or 5 queries
6dfff36f
RG
3221 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 10, 5);
3222 }
3223 }
3224
3225 return false;
3226 }
3227
3228 /* we got an answer */
3229 if(lwr.d_rcode==RCode::ServFail || lwr.d_rcode==RCode::Refused) {
3230 LOG(prefix<<qname<<": "<<nsName<<" ("<<remoteIP.toString()<<") returned a "<< (lwr.d_rcode==RCode::ServFail ? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl);
5c8c72bf 3231 if (!chained && !dontThrottle) {
deca7d8f
RG
3232 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 60, 3);
3233 }
6dfff36f
RG
3234 return false;
3235 }
3236
3237 /* this server sent a valid answer, mark it backup up if it was down */
3238 if(s_serverdownmaxfails > 0) {
3239 t_sstorage.fails.clear(remoteIP);
3240 }
3241
3242 if(lwr.d_tcbit) {
3243 *truncated = true;
3244
4ab4187c 3245 if (doTCP) {
6dfff36f 3246 LOG(prefix<<qname<<": truncated bit set, over TCP?"<<endl);
4ab4187c
PD
3247 if (!dontThrottle) {
3248 /* let's treat that as a ServFail answer from this server */
3249 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 60, 3);
3250 }
6dfff36f
RG
3251 return false;
3252 }
b1f2295b 3253 LOG(prefix<<qname<<": truncated bit set, over UDP"<<endl);
6dfff36f
RG
3254
3255 return true;
3256 }
3257
3258 return true;
3259}
3260
51b6b728 3261bool 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)
6dfff36f
RG
3262{
3263 string prefix;
3264 if(doLog()) {
3265 prefix=d_prefix;
3266 prefix.append(depth, ' ');
3267 }
3268
3269 if(s_minimumTTL) {
3270 for(auto& rec : lwr.d_records) {
3271 rec.d_ttl = max(rec.d_ttl, s_minimumTTL);
3272 }
3273 }
3274
5cf4b2e7
RG
3275 /* if the answer is ECS-specific, a minimum TTL is set for this kind of answers
3276 and it's higher than the global minimum TTL */
3277 if (ednsmask && s_minimumECSTTL > 0 && (s_minimumTTL == 0 || s_minimumECSTTL > s_minimumTTL)) {
3278 for(auto& rec : lwr.d_records) {
3279 if (rec.d_place == DNSResourceRecord::ANSWER) {
3280 rec.d_ttl = max(rec.d_ttl, s_minimumECSTTL);
3281 }
3282 }
3283 }
3284
2b984251 3285 bool needWildcardProof = false;
78cdf520 3286 bool gatherWildcardProof = false;
e4894ce0 3287 unsigned int wildcardLabelsCount;
78cdf520 3288 *rcode = updateCacheFromRecords(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, state, needWildcardProof, gatherWildcardProof, wildcardLabelsCount, sendRDQuery);
6dfff36f
RG
3289 if (*rcode != RCode::NoError) {
3290 return true;
3291 }
3292
3293 LOG(prefix<<qname<<": determining status after receiving this packet"<<endl);
3294
3295 set<DNSName> nsset;
3296 bool realreferral=false, negindic=false;
3297 DNSName newauth;
3298 DNSName newtarget;
3299
78cdf520 3300 bool done = processRecords(prefix, qname, qtype, auth, lwr, sendRDQuery, ret, nsset, newtarget, newauth, realreferral, negindic, state, needWildcardProof, gatherWildcardProof, wildcardLabelsCount);
6dfff36f
RG
3301
3302 if(done){
3303 LOG(prefix<<qname<<": status=got results, this level of recursion done"<<endl);
5374b03b 3304 LOG(prefix<<qname<<": validation status is "<<vStates[state]<<endl);
6dfff36f
RG
3305 *rcode = RCode::NoError;
3306 return true;
3307 }
3308
3309 if(!newtarget.empty()) {
3310 if(newtarget == qname) {
3311 LOG(prefix<<qname<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl);
3312 *rcode = RCode::ServFail;
3313 return true;
3314 }
3315
3316 if(depth > 10) {
3317 LOG(prefix<<qname<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl);
3318 *rcode = RCode::ServFail;
3319 return true;
3320 }
3321
5374b03b
RG
3322 if (qtype == QType::DS) {
3323 LOG(prefix<<qname<<": status=got a CNAME referral, but we are looking for a DS"<<endl);
6dfff36f 3324
1c39e884
RG
3325 if(d_doDNSSEC)
3326 addNXNSECS(ret, lwr.d_records);
3327
3328 *rcode = RCode::NoError;
3329 return true;
5374b03b
RG
3330 }
3331 else {
3332 LOG(prefix<<qname<<": status=got a CNAME referral, starting over with "<<newtarget<<endl);
6dfff36f 3333
5374b03b
RG
3334 set<GetBestNSAnswer> beenthere2;
3335 vState cnameState = Indeterminate;
3336 *rcode = doResolve(newtarget, qtype, ret, depth + 1, beenthere2, cnameState);
3337 LOG(prefix<<qname<<": updating validation state for response to "<<qname<<" from "<<vStates[state]<<" with the state from the CNAME quest: "<<vStates[cnameState]<<endl);
3338 updateValidationState(state, cnameState);
3339 return true;
3340 }
6dfff36f
RG
3341 }
3342
3343 if(lwr.d_rcode == RCode::NXDomain) {
3344 LOG(prefix<<qname<<": status=NXDOMAIN, we are done "<<(negindic ? "(have negative SOA)" : "")<<endl);
3345
3346 if(d_doDNSSEC)
3347 addNXNSECS(ret, lwr.d_records);
3348
3349 *rcode = RCode::NXDomain;
3350 return true;
3351 }
3352
3353 if(nsset.empty() && !lwr.d_rcode && (negindic || lwr.d_aabit || sendRDQuery)) {
3354 LOG(prefix<<qname<<": status=noerror, other types may exist, but we are done "<<(negindic ? "(have negative SOA) " : "")<<(lwr.d_aabit ? "(have aa bit) " : "")<<endl);
3355
6e9d3cae 3356 if(state == Secure && (lwr.d_aabit || sendRDQuery) && !negindic) {
114829cc
RG
3357 updateValidationState(state, Bogus);
3358 }
3359
6dfff36f
RG
3360 if(d_doDNSSEC)
3361 addNXNSECS(ret, lwr.d_records);
3362
3363 *rcode = RCode::NoError;
3364 return true;
3365 }
3366
3367 if(realreferral) {
3368 LOG(prefix<<qname<<": status=did not resolve, got "<<(unsigned int)nsset.size()<<" NS, ");
6dfff36f
RG
3369
3370 nameservers.clear();
3371 for (auto const &nameserver : nsset) {
3372 if (d_wantsRPZ) {
3373 d_appliedPolicy = dfe.getProcessingPolicy(nameserver, d_discardedPolicies);
3374 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
3375 LOG("however "<<nameserver<<" was blocked by RPZ policy '"<<(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")<<"'"<<endl);
3376 *rcode = -2;
3377 return true;
3378 }
3379 }
3380 nameservers.insert({nameserver, {{}, false}});
3381 }
3382 LOG("looping to them"<<endl);
3383 *gotNewServers = true;
812c3a69 3384 auth=newauth;
4d2be65d 3385
6dfff36f
RG
3386 return false;
3387 }
3388
3389 return false;
3390}
3391
b8470add
PL
3392/** returns:
3393 * -1 in case of no results
3394 * -2 when a FilterEngine Policy was hit
3395 * rcode otherwise
3396 */
fa1b87ff 3397int SyncRes::doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype,
e325f20c 3398 vector<DNSRecord>&ret,
116d1288 3399 unsigned int depth, set<GetBestNSAnswer>&beenthere, vState& state, StopAtDelegation* stopAtDelegation)
86c152f2 3400{
69cbdef9 3401 auto luaconfsLocal = g_luaconfs.getLocal();
ded77b10 3402 string prefix;
77499b05 3403 if(doLog()) {
ded77b10
BH
3404 prefix=d_prefix;
3405 prefix.append(depth, ' ');
3406 }
3ddb9247 3407
b8470add
PL
3408 LOG(prefix<<qname<<": Cache consultations done, have "<<(unsigned int)nameservers.size()<<" NS to contact");
3409
69cbdef9 3410 if (nameserversBlockedByRPZ(luaconfsLocal->dfe, nameservers)) {
26ca3513 3411 return -2;
b8470add
PL
3412 }
3413
3414 LOG(endl);
afbe2787
BH
3415
3416 for(;;) { // we may get more specific nameservers
feccaf7f 3417 auto rnameservers = shuffleInSpeedOrder(nameservers, doLog() ? (prefix+qname.toString()+": ") : string() );
3ddb9247 3418
26ca3513
RG
3419 for(auto tns=rnameservers.cbegin();;++tns) {
3420 if(tns==rnameservers.cend()) {
2189085d 3421 LOG(prefix<<qname<<": Failed to resolve via any of the "<<(unsigned int)rnameservers.size()<<" offered NS at level '"<<auth<<"'"<<endl);
03c09afe 3422 if(!auth.isRoot() && flawedNSSet) {
2189085d 3423 LOG(prefix<<qname<<": Ageing nameservers for level '"<<auth<<"', next query might succeed"<<endl);
88490c03 3424
49a699c4 3425 if(t_RC->doAgeCache(d_now.tv_sec, auth, QType::NS, 10))
4957a608
BH
3426 g_stats.nsSetInvalidations++;
3427 }
3428 return -1;
afbe2787 3429 }
6dfff36f 3430
b4c8789a
RG
3431 bool cacheOnly = false;
3432 // this line needs to identify the 'self-resolving' behaviour
feccaf7f 3433 if(qname == tns->first && (qtype.getCode() == QType::A || qtype.getCode() == QType::AAAA)) {
b4c8789a
RG
3434 /* we might have a glue entry in cache so let's try this NS
3435 but only if we have enough in the cache to know how to reach it */
3436 LOG(prefix<<qname<<": Using NS to resolve itself, but only using what we have in cache ("<<(1+tns-rnameservers.cbegin())<<"/"<<rnameservers.size()<<")"<<endl);
3437 cacheOnly = true;
20177d1d 3438 }
5605c067 3439
996c89cc 3440 typedef vector<ComboAddress> remoteIPs_t;
5605c067 3441 remoteIPs_t remoteIPs;
bfea0d0b 3442 remoteIPs_t::const_iterator remoteIP;
1c21f389 3443 bool pierceDontQuery=false;
c1d73d94 3444 bool sendRDQuery=false;
376effcf 3445 boost::optional<Netmask> ednsmask;
263f6a5a 3446 LWResult lwr;
feccaf7f 3447 const bool wasForwarded = tns->first.empty() && (!nameservers[tns->first].first.empty());
6dfff36f
RG
3448 int rcode = RCode::NoError;
3449 bool gotNewServers = false;
3450
feccaf7f 3451 if(tns->first.empty() && !wasForwarded) {
2189085d 3452 LOG(prefix<<qname<<": Domain is out-of-band"<<endl);
e1636f82
RG
3453 /* setting state to indeterminate since validation is disabled for local auth zone,
3454 and Insecure would be misleading. */
3455 state = Indeterminate;
9fc36e90 3456 d_wasOutOfBand = doOOBResolve(qname, qtype, lwr.d_records, depth, lwr.d_rcode);
4957a608
BH
3457 lwr.d_tcbit=false;
3458 lwr.d_aabit=true;
6dfff36f
RG
3459
3460 /* we have received an answer, are we done ? */
51b6b728 3461 bool done = processAnswer(depth, lwr, qname, qtype, auth, false, ednsmask, sendRDQuery, nameservers, ret, luaconfsLocal->dfe, &gotNewServers, &rcode, state);
6dfff36f
RG
3462 if (done) {
3463 return rcode;
3464 }
3465 if (gotNewServers) {
116d1288
OM
3466 if (stopAtDelegation && *stopAtDelegation == Stop) {
3467 *stopAtDelegation = Stopped;
3468 return rcode;
3469 }
6dfff36f
RG
3470 break;
3471 }
5605c067
BH
3472 }
3473 else {
6dfff36f 3474 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
b4c8789a 3475 remoteIPs = retrieveAddressesForNS(prefix, qname, tns, depth, beenthere, rnameservers, nameservers, sendRDQuery, pierceDontQuery, flawedNSSet, cacheOnly);
4957a608
BH
3476
3477 if(remoteIPs.empty()) {
feccaf7f 3478 LOG(prefix<<qname<<": Failed to get IP for NS "<<tns->first<<", trying next if available"<<endl);
4957a608
BH
3479 flawedNSSet=true;
3480 continue;
3481 }
3482 else {
b8470add 3483 bool hitPolicy{false};
feccaf7f 3484 LOG(prefix<<qname<<": Resolved '"<<auth<<"' NS "<<tns->first<<" to: ");
26ca3513
RG
3485 for(remoteIP = remoteIPs.cbegin(); remoteIP != remoteIPs.cend(); ++remoteIP) {
3486 if(remoteIP != remoteIPs.cbegin()) {
77499b05
BH
3487 LOG(", ");
3488 }
3489 LOG(remoteIP->toString());
69cbdef9 3490 if(nameserverIPBlockedByRPZ(luaconfsLocal->dfe, *remoteIP)) {
26ca3513 3491 hitPolicy = true;
b8470add 3492 }
4957a608 3493 }
77499b05 3494 LOG(endl);
b8470add
PL
3495 if (hitPolicy) //implies d_wantsRPZ
3496 return -2;
4957a608
BH
3497 }
3498
26ca3513 3499 for(remoteIP = remoteIPs.cbegin(); remoteIP != remoteIPs.cend(); ++remoteIP) {
2189085d 3500 LOG(prefix<<qname<<": Trying IP "<< remoteIP->toStringWithPort() <<", asking '"<<qname<<"|"<<qtype.getName()<<"'"<<endl);
6dfff36f 3501
26ca3513 3502 if (throttledOrBlocked(prefix, *remoteIP, qname, qtype, pierceDontQuery)) {
4957a608
BH
3503 continue;
3504 }
9de3e034 3505
6dfff36f
RG
3506 bool truncated = false;
3507 bool gotAnswer = doResolveAtThisIP(prefix, qname, qtype, lwr, ednsmask, auth, sendRDQuery,
feccaf7f 3508 tns->first, *remoteIP, false, &truncated);
6dfff36f
RG
3509 if (gotAnswer && truncated ) {
3510 /* retry, over TCP this time */
3511 gotAnswer = doResolveAtThisIP(prefix, qname, qtype, lwr, ednsmask, auth, sendRDQuery,
feccaf7f 3512 tns->first, *remoteIP, true, &truncated);
6dfff36f 3513 }
710af846 3514
6dfff36f
RG
3515 if (!gotAnswer) {
3516 continue;
3517 }
352b4183 3518
feccaf7f 3519 LOG(prefix<<qname<<": Got "<<(unsigned int)lwr.d_records.size()<<" answers from "<<tns->first<<" ("<< remoteIP->toString() <<"), rcode="<<lwr.d_rcode<<" ("<<RCode::to_s(lwr.d_rcode)<<"), aa="<<lwr.d_aabit<<", in "<<lwr.d_usec/1000<<"ms"<<endl);
92011b8f 3520
6dfff36f
RG
3521 /* // for you IPv6 fanatics :-)
3522 if(remoteIP->sin4.sin_family==AF_INET6)
3523 lwr.d_usec/=3;
3524 */
3525 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
710af846 3526
b9715061 3527 t_sstorage.nsSpeeds[tns->first.empty()? DNSName(remoteIP->toStringWithPort()) : tns->first].submit(*remoteIP, lwr.d_usec, d_now);
628e2c7b 3528
6dfff36f 3529 /* we have received an answer, are we done ? */
51b6b728 3530 bool done = processAnswer(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, sendRDQuery, nameservers, ret, luaconfsLocal->dfe, &gotNewServers, &rcode, state);
6dfff36f
RG
3531 if (done) {
3532 return rcode;
4957a608 3533 }
6dfff36f 3534 if (gotNewServers) {
116d1288
OM
3535 if (stopAtDelegation && *stopAtDelegation == Stop) {
3536 *stopAtDelegation = Stopped;
3537 return rcode;
3538 }
6dfff36f 3539 break;
4957a608 3540 }
6dfff36f
RG
3541 /* was lame */
3542 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100);
4957a608 3543 }
aadceba8 3544
6dfff36f
RG
3545 if (gotNewServers) {
3546 break;
4957a608 3547 }
620db2c8 3548
6dfff36f
RG
3549 if(remoteIP == remoteIPs.cend()) // we tried all IP addresses, none worked
3550 continue;
620db2c8 3551
86c152f2
BH
3552 }
3553 }
86c152f2 3554 }
ac539791 3555 return -1;
86c152f2
BH
3556}
3557
2fe3354d 3558void SyncRes::setQuerySource(const ComboAddress& requestor, boost::optional<const EDNSSubnetOpts&> incomingECS)
8a3a3822 3559{
2fe3354d
CH
3560 d_requestor = requestor;
3561
3562 if (incomingECS && incomingECS->source.getBits() > 0) {
3563 d_cacheRemote = incomingECS->source.getMaskedNetwork();
d14121a8 3564 uint8_t bits = std::min(incomingECS->source.getBits(), (incomingECS->source.isIPv4() ? s_ecsipv4limit : s_ecsipv6limit));
2fe3354d
CH
3565 ComboAddress trunc = incomingECS->source.getNetwork();
3566 trunc.truncate(bits);
3567 d_outgoingECSNetwork = boost::optional<Netmask>(Netmask(trunc, bits));
3568 } else {
3569 d_cacheRemote = d_requestor;
3570 if(!incomingECS && s_ednslocalsubnets.match(d_requestor)) {
3571 ComboAddress trunc = d_requestor;
3572 uint8_t bits = d_requestor.isIPv4() ? 32 : 128;
3573 bits = std::min(bits, (trunc.isIPv4() ? s_ecsipv4limit : s_ecsipv6limit));
3574 trunc.truncate(bits);
3575 d_outgoingECSNetwork = boost::optional<Netmask>(Netmask(trunc, bits));
3576 } else if (s_ecsScopeZero.source.getBits() > 0) {
8a3a3822
RG
3577 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0.
3578 But using an empty ECS in that case would mean inserting
3579 a non ECS-specific entry into the cache, preventing any further
3580 ECS-specific query to be sent.
3581 So instead we use the trick described in section 7.1.2:
3582 "The subsequent Recursive Resolver query to the Authoritative Nameserver
3583 will then either not include an ECS option or MAY optionally include
3584 its own address information, which is what the Authoritative
3585 Nameserver will almost certainly use to generate any Tailored
3586 Response in lieu of an option. This allows the answer to be handled
3587 by the same caching mechanism as other queries, with an explicit
3588 indicator of the applicable scope. Subsequent Stub Resolver queries
3589 for /0 can then be answered from this cached response.
3590 */
2fe3354d
CH
3591 d_outgoingECSNetwork = boost::optional<Netmask>(s_ecsScopeZero.source.getMaskedNetwork());
3592 d_cacheRemote = s_ecsScopeZero.source.getNetwork();
3593 } else {
3594 // ECS disabled because no scope-zero address could be derived.
3595 d_outgoingECSNetwork = boost::none;
8a3a3822
RG
3596 }
3597 }
8a3a3822
RG
3598}
3599
2fe3354d 3600boost::optional<Netmask> SyncRes::getEDNSSubnetMask(const DNSName& dn, const ComboAddress& rem)
e9f9b8ec 3601{
2fe3354d
CH
3602 if(d_outgoingECSNetwork && (s_ednsdomains.check(dn) || s_ednsremotesubnets.match(rem))) {
3603 return d_outgoingECSNetwork;
e9f9b8ec 3604 }
2fe3354d 3605 return boost::none;
e9f9b8ec 3606}
bd53ea9d 3607
9065eb05
RG
3608void SyncRes::parseEDNSSubnetWhitelist(const std::string& wlist)
3609{
3610 vector<string> parts;
3611 stringtok(parts, wlist, ",; ");
3612 for(const auto& a : parts) {
3613 try {
2fe3354d 3614 s_ednsremotesubnets.addMask(Netmask(a));
9065eb05
RG
3615 }
3616 catch(...) {
3617 s_ednsdomains.add(DNSName(a));
3618 }
3619 }
3620}
3621
2fe3354d
CH
3622void SyncRes::parseEDNSSubnetAddFor(const std::string& subnetlist)
3623{
3624 vector<string> parts;
3625 stringtok(parts, subnetlist, ",; ");
3626 for(const auto& a : parts) {
3627 s_ednslocalsubnets.addMask(a);
3628 }
3629}
3630
8ce79a22 3631// used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
a3e7b735 3632int directResolve(const DNSName& qname, const QType& qtype, int qclass, vector<DNSRecord>& ret)
bd53ea9d
PD
3633{
3634 struct timeval now;
3635 gettimeofday(&now, 0);
710af846 3636
bd53ea9d 3637 SyncRes sr(now);
13658071
RB
3638 int res = -1;
3639 try {
3640 res = sr.beginResolve(qname, QType(qtype), qclass, ret);
3641 }
3642 catch(const PDNSException& e) {
3643 g_log<<Logger::Error<<"Failed to resolve "<<qname.toLogString()<<", got pdns exception: "<<e.reason<<endl;
3644 ret.clear();
3645 }
3646 catch(const ImmediateServFailException& e) {
3647 g_log<<Logger::Error<<"Failed to resolve "<<qname.toLogString()<<", got ImmediateServFailException: "<<e.reason<<endl;
3648 ret.clear();
3649 }
3650 catch(const std::exception& e) {
3651 g_log<<Logger::Error<<"Failed to resolve "<<qname.toLogString()<<", got STL error: "<<e.what()<<endl;
3652 ret.clear();
3653 }
3654 catch(...) {
3655 g_log<<Logger::Error<<"Failed to resolve "<<qname.toLogString()<<", got an exception"<<endl;
3656 ret.clear();
3657 }
e325f20c 3658
bd53ea9d
PD
3659 return res;
3660}
30ee601a 3661
30ee601a
RG
3662int SyncRes::getRootNS(struct timeval now, asyncresolve_t asyncCallback) {
3663 SyncRes sr(now);
3664 sr.setDoEDNS0(true);
0b29b9c5 3665 sr.setUpdatingRootNS();
30ee601a 3666 sr.setDoDNSSEC(g_dnssecmode != DNSSECMode::Off);
0c43f455 3667 sr.setDNSSECValidationRequested(g_dnssecmode != DNSSECMode::Off && g_dnssecmode != DNSSECMode::ProcessNoValidate);
30ee601a
RG
3668 sr.setAsyncCallback(asyncCallback);
3669
3670 vector<DNSRecord> ret;
3671 int res=-1;
3672 try {
3673 res=sr.beginResolve(g_rootdnsname, QType(QType::NS), 1, ret);
3674 if (g_dnssecmode != DNSSECMode::Off && g_dnssecmode != DNSSECMode::ProcessNoValidate) {
4d2be65d 3675 auto state = sr.getValidationState();
30ee601a
RG
3676 if (state == Bogus)
3677 throw PDNSException("Got Bogus validation result for .|NS");
3678 }
3679 return res;
3680 }
c78ceb39 3681 catch(const PDNSException& e) {
e6a9dde5 3682 g_log<<Logger::Error<<"Failed to update . records, got an exception: "<<e.reason<<endl;
30ee601a 3683 }
c78ceb39 3684 catch(const ImmediateServFailException& e) {
e6a9dde5 3685 g_log<<Logger::Error<<"Failed to update . records, got an exception: "<<e.reason<<endl;
c78ceb39
RG
3686 }
3687 catch(const std::exception& e) {
e6a9dde5 3688 g_log<<Logger::Error<<"Failed to update . records, got an exception: "<<e.what()<<endl;
30ee601a 3689 }
c78ceb39 3690 catch(...) {
e6a9dde5 3691 g_log<<Logger::Error<<"Failed to update . records, got an exception"<<endl;
30ee601a 3692 }
c78ceb39 3693
30ee601a 3694 if(!res) {
e6a9dde5 3695 g_log<<Logger::Notice<<"Refreshed . records"<<endl;
30ee601a
RG
3696 }
3697 else
e6a9dde5 3698 g_log<<Logger::Error<<"Failed to update . records, RCODE="<<res<<endl;
c78ceb39 3699
30ee601a
RG
3700 return res;
3701}