]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/syncres.cc
global: Normalize isIpv6 to isIPv6
[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
OM
430 char tmp[26];
431 fprintf(fp.get(), "%s\t%d\t%s", eds.first.toString().c_str(), (int)eds.second.mode, ctime_r(&eds.second.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();
482 for(const auto& i : throttleMap)
c1e20fba 483 {
484 count++;
f0dbdd62 485 char tmp[26];
96e2f64f 486 // remote IP, dns name, qtype, count, ttd
f0dbdd62 487 fprintf(fp.get(), "%s\t%s\t%d\t%u\t%s", i.first.get<0>().toString().c_str(), i.first.get<1>().toLogString().c_str(), i.first.get<2>(), i.second.count, ctime_r(&i.second.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];
512 ctime_r(&i.second.last, tmp);
513 fprintf(fp.get(), "%s\t%lld\t%s", i.first.toString().c_str(),
514 static_cast<long long>(i.second.value), tmp);
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
90e8ea71 563 SyncRes::EDNSStatus* ednsstatus = &t_sstorage.ednsstatus[ip]; // does this include port? YES
81883dcc 564
90e8ea71
OM
565 if (ednsstatus->modeSetAt && ednsstatus->modeSetAt + 3600 < d_now.tv_sec) {
566 *ednsstatus = SyncRes::EDNSStatus();
77499b05 567 // cerr<<"Resetting EDNS Status for "<<ip.toString()<<endl);
81883dcc
BH
568 }
569
90e8ea71
OM
570 SyncRes::EDNSStatus::EDNSMode *mode = &ednsstatus->mode;
571 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
OM
603 // ednsstatus might be cleared, so do a new lookup
604 ednsstatus = &t_sstorage.ednsstatus[ip]; // does this include port? YES
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;
90e8ea71 616 *mode = EDNSStatus::NOEDNS;
4957a608 617 continue;
81883dcc 618 }
81883dcc 619 else if(!res->d_haveEDNS) {
90e8ea71
OM
620 if (*mode != EDNSStatus::EDNSIGNORANT) {
621 *mode = 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 {
90e8ea71 626 *mode = 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)
bb4bdbaf 632 ednsstatus->modeSetAt=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{
904 speedOrderCA(std::map<ComboAddress,double>& speeds): d_speeds(speeds) {}
905 bool operator()(const ComboAddress& a, const ComboAddress& b) const
906 {
907 return d_speeds[a] < d_speeds[b];
908 }
909 std::map<ComboAddress, double>& d_speeds;
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 */
975 map<ComboAddress, double> speeds;
976 auto& collection = t_sstorage.nsSpeeds[qname].d_collection;
977 for(const auto& val: ret) {
7881a640 978 speeds[val] = collection[val].get(&d_now);
c767798a 979 }
996c89cc 980
c767798a 981 t_sstorage.nsSpeeds[qname].purge(speeds);
996c89cc 982
c767798a 983 if(ret.size() > 1) {
feccaf7f 984 random_shuffle(ret.begin(), ret.end());
0e4675a9
RG
985 speedOrderCA so(speeds);
986 stable_sort(ret.begin(), ret.end(), so);
987
988 if(doLog()) {
989 string prefix=d_prefix;
990 prefix.append(depth, ' ');
991 LOG(prefix<<"Nameserver "<<qname<<" IPs: ");
992 bool first = true;
993 for(const auto& addr : ret) {
994 if (first) {
995 first = false;
4957a608 996 }
0e4675a9
RG
997 else {
998 LOG(", ");
999 }
1000 LOG((addr.toString())<<"(" << (boost::format("%0.2f") % (speeds[addr]/1000.0)).str() <<"ms)");
996c89cc 1001 }
0e4675a9
RG
1002 LOG(endl);
1003 }
996c89cc 1004 }
fdf05fd4 1005
728485ca 1006 return ret;
75b49099
BH
1007}
1008
7c3398aa 1009void SyncRes::getBestNSFromCache(const DNSName &qname, const QType& qtype, vector<DNSRecord>& bestns, bool* flawedNSSet, unsigned int depth, set<GetBestNSAnswer>& beenthere)
86c152f2 1010{
c5c066bf
PD
1011 string prefix;
1012 DNSName subdomain(qname);
77499b05 1013 if(doLog()) {
ded77b10
BH
1014 prefix=d_prefix;
1015 prefix.append(depth, ' ');
1016 }
75b49099 1017 bestns.clear();
2b1b4054 1018 bool brokeloop;
75b49099 1019 do {
2b1b4054 1020 brokeloop=false;
2189085d 1021 LOG(prefix<<qname<<": Checking if we have NS in cache for '"<<subdomain<<"'"<<endl);
e325f20c 1022 vector<DNSRecord> ns;
7305df82 1023 *flawedNSSet = false;
4d2be65d 1024
2fe3354d 1025 if(t_RC->get(d_now.tv_sec, subdomain, QType(QType::NS), false, &ns, d_cacheRemote) > 0) {
feccaf7f
RG
1026 bestns.reserve(ns.size());
1027
e325f20c 1028 for(auto k=ns.cbegin();k!=ns.cend(); ++k) {
1029 if(k->d_ttl > (unsigned int)d_now.tv_sec ) {
1030 vector<DNSRecord> aset;
4957a608 1031
e325f20c 1032 const DNSRecord& dr=*k;
ba3c54cb
RG
1033 auto nrr = getRR<NSRecordContent>(dr);
1034 if(nrr && (!nrr->getNS().isPartOf(subdomain) || t_RC->get(d_now.tv_sec, nrr->getNS(), s_doIPv6 ? QType(QType::ADDR) : QType(QType::A),
2fe3354d 1035 false, doLog() ? &aset : 0, d_cacheRemote) > 5)) {
e325f20c 1036 bestns.push_back(dr);
2189085d
PL
1037 LOG(prefix<<qname<<": NS (with ip, or non-glue) in cache for '"<<subdomain<<"' -> '"<<nrr->getNS()<<"'"<<endl);
1038 LOG(prefix<<qname<<": within bailiwick: "<< nrr->getNS().isPartOf(subdomain));
4957a608 1039 if(!aset.empty()) {
e325f20c 1040 LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset.begin()->d_ttl- d_now.tv_sec ))<<endl);
4957a608
BH
1041 }
1042 else {
77499b05 1043 LOG(", not in cache / did not look at cache"<<endl);
4957a608
BH
1044 }
1045 }
1046 else {
1047 *flawedNSSet=true;
e325f20c 1048 LOG(prefix<<qname<<": NS in cache for '"<<subdomain<<"', but needs glue ("<<nrr->getNS()<<") which we miss or is expired"<<endl);
4957a608
BH
1049 }
1050 }
afbe2787 1051 }
4d2be65d 1052
75b49099 1053 if(!bestns.empty()) {
4957a608 1054 GetBestNSAnswer answer;
891fbf88 1055 answer.qname=qname;
1056 answer.qtype=qtype.getCode();
38c2ba02
RG
1057 for(const auto& dr : bestns) {
1058 if (auto nsContent = getRR<NSRecordContent>(dr)) {
1059 answer.bestns.insert(make_pair(dr.d_name, nsContent->getNS()));
1060 }
1061 }
891fbf88 1062
6493dfc0
RG
1063 auto insertionPair = beenthere.insert(std::move(answer));
1064 if(!insertionPair.second) {
2b1b4054 1065 brokeloop=true;
2189085d 1066 LOG(prefix<<qname<<": We have NS in cache for '"<<subdomain<<"' but part of LOOP (already seen "<<answer.qname<<")! Trying less specific NS"<<endl);
e325f20c 1067 ;
77499b05
BH
1068 if(doLog())
1069 for( set<GetBestNSAnswer>::const_iterator j=beenthere.begin();j!=beenthere.end();++j) {
6493dfc0 1070 bool neo = (j == insertionPair.first);
2189085d 1071 LOG(prefix<<qname<<": beenthere"<<(neo?"*":"")<<": "<<j->qname<<"|"<<DNSRecordContent::NumberToType(j->qtype)<<" ("<<(unsigned int)j->bestns.size()<<")"<<endl);
77499b05 1072 }
4957a608
BH
1073 bestns.clear();
1074 }
1075 else {
2189085d 1076 LOG(prefix<<qname<<": We have NS in cache for '"<<subdomain<<"' (flawedNSSet="<<*flawedNSSet<<")"<<endl);
4957a608
BH
1077 return;
1078 }
75b49099 1079 }
afbe2787 1080 }
2189085d 1081 LOG(prefix<<qname<<": no valid/useful NS in cache for '"<<subdomain<<"'"<<endl);
4d2be65d 1082
52683ca3 1083 if(subdomain.isRoot() && !brokeloop) {
7836f7b4 1084 // We lost the root NS records
3ddb9247 1085 primeHints();
159b1242 1086 primeRootNSZones(g_dnssecmode != DNSSECMode::Off);
2189085d 1087 LOG(prefix<<qname<<": reprimed the root"<<endl);
0b29b9c5
RG
1088 /* let's prevent an infinite loop */
1089 if (!d_updatingRootNS) {
1090 getRootNS(d_now, d_asyncResolve);
1091 }
6576051d 1092 }
4d2be65d 1093 } while(subdomain.chopOff());
75b49099
BH
1094}
1095
69cbdef9 1096SyncRes::domainmap_t::const_iterator SyncRes::getBestAuthZone(DNSName* qname) const
5605c067 1097{
6493dfc0
RG
1098 if (t_sstorage.domainmap->empty()) {
1099 return t_sstorage.domainmap->end();
1100 }
1101
5605c067
BH
1102 SyncRes::domainmap_t::const_iterator ret;
1103 do {
a712cb56
RG
1104 ret=t_sstorage.domainmap->find(*qname);
1105 if(ret!=t_sstorage.domainmap->end())
5605c067 1106 break;
c5c066bf 1107 }while(qname->chopOff());
5605c067
BH
1108 return ret;
1109}
288f4aa9 1110
7bf26383 1111/** doesn't actually do the work, leaves that to getBestNSFromCache */
7c3398aa 1112DNSName SyncRes::getBestNSNamesFromCache(const DNSName &qname, const QType& qtype, NsSet& nsset, bool* flawedNSSet, unsigned int depth, set<GetBestNSAnswer>&beenthere)
75b49099 1113{
c5c066bf 1114 DNSName authdomain(qname);
3ddb9247 1115
5605c067 1116 domainmap_t::const_iterator iter=getBestAuthZone(&authdomain);
a712cb56 1117 if(iter!=t_sstorage.domainmap->end()) {
3337c2f7 1118 if( iter->second.isAuth() )
fa1b87ff
PL
1119 // this gets picked up in doResolveAt, the empty DNSName, combined with the
1120 // empty vector means 'we are auth for this zone'
1121 nsset.insert({DNSName(), {{}, false}});
2e5ae2b2 1122 else {
fa1b87ff
PL
1123 // Again, picked up in doResolveAt. An empty DNSName, combined with a
1124 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
6dfff36f 1125 // This is actually picked up in retrieveAddressesForNS called from doResolveAt.
3337c2f7 1126 nsset.insert({DNSName(), {iter->second.d_servers, iter->second.shouldRecurse() }});
2e5ae2b2 1127 }
5605c067
BH
1128 return authdomain;
1129 }
1130
6493dfc0 1131 DNSName subdomain(qname);
e325f20c 1132 vector<DNSRecord> bestns;
891fbf88 1133 getBestNSFromCache(subdomain, qtype, bestns, flawedNSSet, depth, beenthere);
75b49099 1134
e325f20c 1135 for(auto k=bestns.cbegin() ; k != bestns.cend(); ++k) {
fa1b87ff 1136 // The actual resolver code will not even look at the ComboAddress or bool
38c2ba02
RG
1137 const auto nsContent = getRR<NSRecordContent>(*k);
1138 if (nsContent) {
1139 nsset.insert({nsContent->getNS(), {{}, false}});
1140 if(k==bestns.cbegin())
1141 subdomain=k->d_name;
1142 }
86c152f2 1143 }
75b49099 1144 return subdomain;
afbe2787
BH
1145}
1146
b9473937
RG
1147void SyncRes::updateValidationStatusInCache(const DNSName &qname, const QType& qt, bool aa, vState newState) const
1148{
1149 if (newState == Bogus) {
1150 t_RC->updateValidationStatus(d_now.tv_sec, qname, qt, d_cacheRemote, aa, newState, s_maxbogusttl + d_now.tv_sec);
1151 }
1152 else {
1153 t_RC->updateValidationStatus(d_now.tv_sec, qname, qt, d_cacheRemote, aa, newState, boost::none);
1154 }
1155}
1156
ad797d94 1157bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>& ret, unsigned int depth, int &res, vState& state, bool wasAuthZone, bool wasForwardRecurse)
afbe2787 1158{
ded77b10 1159 string prefix;
77499b05 1160 if(doLog()) {
710af846 1161 prefix=d_prefix;
ded77b10
BH
1162 prefix.append(depth, ' ');
1163 }
36f5e3db 1164
40de2910 1165 if((depth>9 && d_outqueries>10 && d_throttledqueries>5) || depth > 15) {
2189085d 1166 LOG(prefix<<qname<<": recursing (CNAME or other indirection) too deep, depth="<<depth<<endl);
c6644fc5
BH
1167 res=RCode::ServFail;
1168 return true;
1169 }
3ddb9247 1170
e325f20c 1171 vector<DNSRecord> cset;
1f77f479 1172 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
2b984251 1173 vector<std::shared_ptr<DNSRecord>> authorityRecs;
428f41b7 1174 bool wasAuth;
b9473937 1175 uint32_t capTTL = std::numeric_limits<uint32_t>::max();
d30b5493
PL
1176 DNSName foundName;
1177 QType foundQT = QType(0); // 0 == QTYPE::ENT
1178
e686a798 1179 LOG(prefix<<qname<<": Looking for CNAME cache hit of '"<<qname<<"|CNAME"<<"'"<<endl);
ad797d94 1180 /* we don't require auth data for forward-recurse lookups */
e686a798
PL
1181 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) {
1182 foundName = qname;
1183 foundQT = QType(QType::CNAME);
1184 }
1185
1186 if (foundName.empty() && qname != g_rootdnsname) {
d30b5493
PL
1187 // look for a DNAME cache hit
1188 auto labels = qname.getRawLabels();
1189 DNSName dnameName(g_rootdnsname);
1190
adbd867b 1191 LOG(prefix<<qname<<": Looking for DNAME cache hit of '"<<qname<<"|DNAME' or its ancestors"<<endl);
d30b5493
PL
1192 do {
1193 dnameName.prependRawLabel(labels.back());
1194 labels.pop_back();
71e9cc53
PL
1195 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
1196 break;
1197 }
d30b5493 1198 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
1199 foundName = dnameName;
1200 foundQT = QType(QType::DNAME);
1201 break;
d30b5493
PL
1202 }
1203 } while(!labels.empty());
1204 }
36c5ee42 1205
8d11c508
PL
1206 if (foundName.empty()) {
1207 LOG(prefix<<qname<<": No CNAME or DNAME cache hit of '"<< qname <<"' found"<<endl);
1208 return false;
1209 }
1210
0de8295b
PL
1211 for(auto const &record : cset) {
1212 if (record.d_class != QClass::IN) {
8d11c508
PL
1213 continue;
1214 }
c5310862 1215
0de8295b 1216 if(record.d_ttl > (unsigned int) d_now.tv_sec) {
8d11c508
PL
1217
1218 if (!wasAuthZone && shouldValidate() && (wasAuth || wasForwardRecurse) && state == Indeterminate && d_requireAuthData) {
1219 /* This means we couldn't figure out the state when this entry was cached,
1220 most likely because we hadn't computed the zone cuts yet. */
1221 /* make sure they are computed before validating */
1222 DNSName subdomain(foundName);
1223 /* if we are retrieving a DS, we only care about the state of the parent zone */
1224 if(qtype == QType::DS)
1225 subdomain.chopOff();
1226
1227 computeZoneCuts(subdomain, g_rootdnsname, depth);
1228
1229 vState recordState = getValidationStatus(foundName, false);
1230 if (recordState == Secure) {
1231 LOG(prefix<<qname<<": got Indeterminate state from the "<<foundQT.getName()<<" cache, validating.."<<endl);
1232 state = SyncRes::validateRecordsWithSigs(depth, foundName, foundQT, foundName, cset, signatures);
1233 if (state != Indeterminate) {
1234 LOG(prefix<<qname<<": got Indeterminate state from the CNAME cache, new validation result is "<<vStates[state]<<endl);
1235 if (state == Bogus) {
1236 capTTL = s_maxbogusttl;
787737ae 1237 }
8d11c508 1238 updateValidationStatusInCache(foundName, foundQT, wasAuth, state);
787737ae 1239 }
428f41b7 1240 }
8d11c508 1241 }
428f41b7 1242
0de8295b 1243 LOG(prefix<<qname<<": Found cache "<<foundQT.getName()<<" hit for '"<< foundName << "|"<<foundQT.getName()<<"' to '"<<record.d_content->getZoneRepresentation()<<"', validation state is "<<vStates[state]<<endl);
1f77f479 1244
0de8295b 1245 DNSRecord dr = record;
8d11c508
PL
1246 dr.d_ttl -= d_now.tv_sec;
1247 dr.d_ttl = std::min(dr.d_ttl, capTTL);
1248 const uint32_t ttl = dr.d_ttl;
1249 ret.reserve(ret.size() + 2 + signatures.size() + authorityRecs.size());
1250 ret.push_back(dr);
2b984251 1251
8d11c508
PL
1252 for(const auto& signature : signatures) {
1253 DNSRecord sigdr;
1254 sigdr.d_type=QType::RRSIG;
1255 sigdr.d_name=foundName;
1256 sigdr.d_ttl=ttl;
1257 sigdr.d_content=signature;
1258 sigdr.d_place=DNSResourceRecord::ANSWER;
1259 sigdr.d_class=QClass::IN;
1260 ret.push_back(sigdr);
1261 }
4d2be65d 1262
8d11c508
PL
1263 for(const auto& rec : authorityRecs) {
1264 DNSRecord authDR(*rec);
1265 authDR.d_ttl=ttl;
1266 ret.push_back(authDR);
1267 }
d30b5493 1268
8d11c508
PL
1269 DNSName newTarget;
1270 if (foundQT == QType::DNAME) {
1271 if (qtype == QType::DNAME && qname == foundName) { // client wanted the DNAME, no need to synthesize a CNAME
d30b5493
PL
1272 res = 0;
1273 return true;
1274 }
8d11c508 1275 // Synthesize a CNAME
0de8295b 1276 auto dnameRR = getRR<DNAMERecordContent>(record);
8d11c508
PL
1277 if (dnameRR == nullptr) {
1278 throw ImmediateServFailException("Unable to get record content for "+foundName.toLogString()+"|DNAME cache entry");
1279 }
1280 const auto& dnameSuffix = dnameRR->getTarget();
1281 DNSName targetPrefix = qname.makeRelative(foundName);
1282 try {
1283 dr.d_type = QType::CNAME;
1284 dr.d_name = targetPrefix + foundName;
1285 newTarget = targetPrefix + dnameSuffix;
1286 dr.d_content = std::make_shared<CNAMERecordContent>(CNAMERecordContent(newTarget));
1287 ret.push_back(dr);
1288 } catch (const std::exception &e) {
1289 // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
1290 // But this is consistent with processRecords
1291 throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + foundName.toLogString() +
1292 "', DNAME target: '" + dnameSuffix.toLogString() + "', substituted name: '" +
1293 targetPrefix.toLogString() + "." + dnameSuffix.toLogString() +
1294 "' : " + e.what());
4957a608 1295 }
d30b5493 1296
8d11c508
PL
1297 LOG(prefix<<qname<<": Synthesized "<<dr.d_name<<"|CNAME "<<newTarget<<endl);
1298 }
4d2be65d 1299
8d11c508
PL
1300 if(qtype == QType::CNAME) { // perhaps they really wanted a CNAME!
1301 res = 0;
4957a608 1302 return true;
ac539791 1303 }
8d11c508
PL
1304
1305 // We have a DNAME _or_ CNAME cache hit and the client wants something else than those two.
1306 // Let's find the answer!
1307 if (foundQT == QType::CNAME) {
0de8295b 1308 const auto cnameContent = getRR<CNAMERecordContent>(record);
8d11c508
PL
1309 if (cnameContent == nullptr) {
1310 throw ImmediateServFailException("Unable to get record content for "+foundName.toLogString()+"|CNAME cache entry");
1311 }
1312 newTarget = cnameContent->getTarget();
1313 }
1314
1315 set<GetBestNSAnswer>beenthere;
1316 vState cnameState = Indeterminate;
1317 res = doResolve(newTarget, qtype, ret, depth+1, beenthere, cnameState);
1318 LOG(prefix<<qname<<": updating validation state for response to "<<qname<<" from "<<vStates[state]<<" with the state from the DNAME/CNAME quest: "<<vStates[cnameState]<<endl);
1319 updateValidationState(state, cnameState);
1320
1321 return true;
ac539791 1322 }
afbe2787 1323 }
8d11c508 1324 throw ImmediateServFailException("Could not determine whether or not there was a CNAME or DNAME in cache for '" + qname.toLogString() + "'");
75b49099
BH
1325}
1326
f984e703 1327namespace {
142ab370
RG
1328struct CacheEntry
1329{
1330 vector<DNSRecord> records;
1331 vector<shared_ptr<RRSIGRecordContent>> signatures;
1332 uint32_t signaturesTTL{std::numeric_limits<uint32_t>::max()};
1333};
1334struct CacheKey
1335{
1336 DNSName name;
1337 uint16_t type;
1338 DNSResourceRecord::Place place;
1339 bool operator<(const CacheKey& rhs) const {
186e99c9 1340 return tie(type, place, name) < tie(rhs.type, rhs.place, rhs.name);
142ab370
RG
1341 }
1342};
1343typedef map<CacheKey, CacheEntry> tcache_t;
f984e703 1344}
142ab370
RG
1345
1346static void reapRecordsFromNegCacheEntryForValidation(tcache_t& tcache, const vector<DNSRecord>& records)
1347{
1348 for (const auto& rec : records) {
1349 if (rec.d_type == QType::RRSIG) {
1350 auto rrsig = getRR<RRSIGRecordContent>(rec);
1351 if (rrsig) {
1352 tcache[{rec.d_name, rrsig->d_type, rec.d_place}].signatures.push_back(rrsig);
1353 }
1354 } else {
1355 tcache[{rec.d_name,rec.d_type,rec.d_place}].records.push_back(rec);
1356 }
1357 }
1358}
1359
6909b8c5
PL
1360/*!
1361 * Convience function to push the records from records into ret with a new TTL
1362 *
1363 * \param records DNSRecords that need to go into ret
1364 * \param ttl The new TTL for these records
1365 * \param ret The vector of DNSRecords that should contian the records with the modified TTL
1366 */
1367static void addTTLModifiedRecords(const vector<DNSRecord>& records, const uint32_t ttl, vector<DNSRecord>& ret) {
39ce10b2
PL
1368 for (const auto& rec : records) {
1369 DNSRecord r(rec);
1370 r.d_ttl = ttl;
1371 ret.push_back(r);
1372 }
1373}
1374
28364e4b 1375void SyncRes::computeNegCacheValidationStatus(const NegCache::NegCacheEntry* ne, const DNSName& qname, const QType& qtype, const int res, vState& state, unsigned int depth)
142ab370 1376{
f4de85a3
RG
1377 DNSName subdomain(qname);
1378 /* if we are retrieving a DS, we only care about the state of the parent zone */
1379 if(qtype == QType::DS)
1380 subdomain.chopOff();
1381
1382 computeZoneCuts(subdomain, g_rootdnsname, depth);
142ab370
RG
1383
1384 tcache_t tcache;
28364e4b
RG
1385 reapRecordsFromNegCacheEntryForValidation(tcache, ne->authoritySOA.records);
1386 reapRecordsFromNegCacheEntryForValidation(tcache, ne->authoritySOA.signatures);
1387 reapRecordsFromNegCacheEntryForValidation(tcache, ne->DNSSECRecords.records);
1388 reapRecordsFromNegCacheEntryForValidation(tcache, ne->DNSSECRecords.signatures);
142ab370
RG
1389
1390 for (const auto& entry : tcache) {
1391 // this happens when we did store signatures, but passed on the records themselves
1392 if (entry.second.records.empty()) {
1393 continue;
1394 }
1395
1396 const DNSName& owner = entry.first.name;
1397
1398 vState recordState = getValidationStatus(owner, false);
1399 if (state == Indeterminate) {
1400 state = recordState;
1401 }
1402
1403 if (recordState == Secure) {
f4de85a3
RG
1404 recordState = SyncRes::validateRecordsWithSigs(depth, qname, qtype, owner, entry.second.records, entry.second.signatures);
1405 }
142ab370 1406
f4de85a3
RG
1407 if (recordState != Indeterminate && recordState != state) {
1408 updateValidationState(state, recordState);
1409 if (state != Secure) {
1410 break;
142ab370
RG
1411 }
1412 }
1413 }
1414
1415 if (state == Secure) {
28364e4b 1416 vState neValidationState = ne->d_validationState;
142ab370 1417 dState expectedState = res == RCode::NXDomain ? NXDOMAIN : NXQTYPE;
28364e4b
RG
1418 dState denialState = getDenialValidationState(*ne, state, expectedState, false);
1419 updateDenialValidationState(neValidationState, ne->d_name, state, denialState, expectedState, qtype == QType::DS);
142ab370
RG
1420 }
1421 if (state != Indeterminate) {
1422 /* validation succeeded, let's update the cache entry so we don't have to validate again */
b9473937
RG
1423 boost::optional<uint32_t> capTTD = boost::none;
1424 if (state == Bogus) {
1425 capTTD = d_now.tv_sec + s_maxbogusttl;
1426 }
1427 t_sstorage.negcache.updateValidationStatus(ne->d_name, ne->d_qtype, state, capTTD);
142ab370
RG
1428 }
1429}
e325f20c 1430
ad797d94 1431bool 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 1432{
fd8bc993 1433 bool giveNegative=false;
710af846 1434
be718669 1435 string prefix;
77499b05 1436 if(doLog()) {
ded77b10
BH
1437 prefix=d_prefix;
1438 prefix.append(depth, ' ');
1439 }
afbe2787 1440
30e9bd93 1441 // 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 1442 DNSName sqname(qname);
288f4aa9 1443 QType sqt(qtype);
092f210a 1444 uint32_t sttl=0;
2189085d 1445 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
4d2be65d 1446 vState cachedState;
28364e4b 1447 const NegCache::NegCacheEntry* ne = nullptr;
64a8b6a1 1448
710af846 1449 if(s_rootNXTrust &&
157647ec 1450 t_sstorage.negcache.getRootNXTrust(qname, d_now, &ne) &&
28364e4b 1451 ne->d_auth.isRoot() &&
e1636f82 1452 !(wasForwardedOrAuthZone && !authname.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
28364e4b
RG
1453 sttl = ne->d_ttd - d_now.tv_sec;
1454 LOG(prefix<<qname<<": Entire name '"<<qname<<"', is negatively cached via '"<<ne->d_auth<<"' & '"<<ne->d_name<<"' for another "<<sttl<<" seconds"<<endl);
3ddb9247 1455 res = RCode::NXDomain;
39ce10b2 1456 giveNegative = true;
28364e4b 1457 cachedState = ne->d_validationState;
157647ec 1458 } else if (t_sstorage.negcache.get(qname, qtype, d_now, &ne)) {
b0c164a2
RG
1459 /* If we are looking for a DS, discard NXD if auth == qname
1460 and ask for a specific denial instead */
28364e4b
RG
1461 if (qtype != QType::DS || ne->d_qtype.getCode() || ne->d_auth != qname ||
1462 t_sstorage.negcache.get(qname, qtype, d_now, &ne, true))
b0c164a2 1463 {
157647ec 1464 res = RCode::NXDomain;
28364e4b 1465 sttl = ne->d_ttd - d_now.tv_sec;
b0c164a2 1466 giveNegative = true;
28364e4b 1467 cachedState = ne->d_validationState;
157647ec 1468 if (ne->d_qtype.getCode()) {
28364e4b 1469 LOG(prefix<<qname<<": "<<qtype.getName()<<" is negatively cached via '"<<ne->d_auth<<"' for another "<<sttl<<" seconds"<<endl);
b0c164a2 1470 res = RCode::NoError;
157647ec
PL
1471 } else {
1472 LOG(prefix<<qname<<": Entire name '"<<qname<<" is negatively cached via '"<<ne->d_auth<<"' for another "<<sttl<<" seconds"<<endl);
b0c164a2 1473 }
157647ec 1474 }
d40a915b 1475 } else if (s_hardenNXD != HardenNXD::No && !qname.isRoot() && !wasForwardedOrAuthZone) {
157647ec
PL
1476 auto labels = qname.getRawLabels();
1477 DNSName negCacheName(g_rootdnsname);
1478 negCacheName.prependRawLabel(labels.back());
1479 labels.pop_back();
1480 while(!labels.empty()) {
1481 if (t_sstorage.negcache.get(negCacheName, QType(0), d_now, &ne, true)) {
d40a915b
OM
1482 if (ne->d_validationState == Indeterminate && validationEnabled()) {
1483 // LOG(prefix << negCacheName << " negatively cached and Indeterminate, trying to validate NXDOMAIN" << endl);
1484 // ...
1485 // And get the updated ne struct
1486 //t_sstorage.negcache.get(negCacheName, QType(0), d_now, &ne, true);
1487 }
7ce0efaa 1488 if ((s_hardenNXD == HardenNXD::Yes && ne->d_validationState != Bogus) || ne->d_validationState == Secure) {
d40a915b
OM
1489 res = RCode::NXDomain;
1490 sttl = ne->d_ttd - d_now.tv_sec;
1491 giveNegative = true;
1492 cachedState = ne->d_validationState;
1493 LOG(prefix<<qname<<": Name '"<<negCacheName<<"' and below, is negatively cached via '"<<ne->d_auth<<"' for another "<<sttl<<" seconds"<<endl);
1494 break;
1495 }
b0c164a2 1496 }
157647ec
PL
1497 negCacheName.prependRawLabel(labels.back());
1498 labels.pop_back();
39ce10b2 1499 }
39ce10b2
PL
1500 }
1501
1502 if (giveNegative) {
142ab370
RG
1503
1504 state = cachedState;
1505
e1636f82 1506 if (!wasAuthZone && shouldValidate() && state == Indeterminate) {
142ab370
RG
1507 LOG(prefix<<qname<<": got Indeterminate state for records retrieved from the negative cache, validating.."<<endl);
1508 computeNegCacheValidationStatus(ne, qname, qtype, res, state, depth);
b9473937
RG
1509
1510 if (state != cachedState && state == Bogus) {
1511 sttl = std::min(sttl, s_maxbogusttl);
1512 }
142ab370
RG
1513 }
1514
39ce10b2 1515 // Transplant SOA to the returned packet
28364e4b 1516 addTTLModifiedRecords(ne->authoritySOA.records, sttl, ret);
4d00b38b 1517 if(d_doDNSSEC) {
28364e4b
RG
1518 addTTLModifiedRecords(ne->authoritySOA.signatures, sttl, ret);
1519 addTTLModifiedRecords(ne->DNSSECRecords.records, sttl, ret);
1520 addTTLModifiedRecords(ne->DNSSECRecords.signatures, sttl, ret);
4d00b38b 1521 }
4d2be65d 1522
142ab370 1523 LOG(prefix<<qname<<": updating validation state with negative cache content for "<<qname<<" to "<<vStates[state]<<endl);
39ce10b2 1524 return true;
fd8bc993 1525 }
39ce10b2 1526
e325f20c 1527 vector<DNSRecord> cset;
75b49099 1528 bool found=false, expired=false;
57769f13 1529 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
2b984251 1530 vector<std::shared_ptr<DNSRecord>> authorityRecs;
57769f13 1531 uint32_t ttl=0;
b9473937 1532 uint32_t capTTL = std::numeric_limits<uint32_t>::max();
428f41b7 1533 bool wasCachedAuth;
ad797d94 1534 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 1535
2189085d 1536 LOG(prefix<<sqname<<": Found cache hit for "<<sqt.getName()<<": ");
428f41b7 1537
dff3ef07 1538 if (!wasAuthZone && shouldValidate() && (wasCachedAuth || wasForwardRecurse) && cachedState == Indeterminate && d_requireAuthData) {
428f41b7
RG
1539
1540 /* This means we couldn't figure out the state when this entry was cached,
1541 most likely because we hadn't computed the zone cuts yet. */
aa30ad7e 1542 /* make sure they are computed before validating */
f4de85a3
RG
1543 DNSName subdomain(sqname);
1544 /* if we are retrieving a DS, we only care about the state of the parent zone */
1545 if(qtype == QType::DS)
1546 subdomain.chopOff();
1547
1548 computeZoneCuts(subdomain, g_rootdnsname, depth);
aa30ad7e 1549
142ab370 1550 vState recordState = getValidationStatus(qname, false);
787737ae
RG
1551 if (recordState == Secure) {
1552 LOG(prefix<<sqname<<": got Indeterminate state from the cache, validating.."<<endl);
1553 cachedState = SyncRes::validateRecordsWithSigs(depth, sqname, sqt, sqname, cset, signatures);
f4de85a3
RG
1554 }
1555 else {
1556 cachedState = recordState;
1557 }
787737ae 1558
f4de85a3
RG
1559 if (cachedState != Indeterminate) {
1560 LOG(prefix<<qname<<": got Indeterminate state from the cache, validation result is "<<vStates[cachedState]<<endl);
b9473937
RG
1561 if (cachedState == Bogus) {
1562 capTTL = s_maxbogusttl;
1563 }
1564 updateValidationStatusInCache(sqname, sqt, wasCachedAuth, cachedState);
787737ae 1565 }
428f41b7
RG
1566 }
1567
e325f20c 1568 for(auto j=cset.cbegin() ; j != cset.cend() ; ++j) {
c5310862 1569
e325f20c 1570 LOG(j->d_content->getZoneRepresentation());
c5310862
RG
1571
1572 if (j->d_class != QClass::IN) {
1573 continue;
1574 }
1575
e325f20c 1576 if(j->d_ttl>(unsigned int) d_now.tv_sec) {
1577 DNSRecord dr=*j;
b9473937
RG
1578 dr.d_ttl -= d_now.tv_sec;
1579 dr.d_ttl = std::min(dr.d_ttl, capTTL);
1580 ttl = dr.d_ttl;
e325f20c 1581 ret.push_back(dr);
1582 LOG("[ttl="<<dr.d_ttl<<"] ");
4957a608 1583 found=true;
ac539791 1584 }
75b49099 1585 else {
77499b05 1586 LOG("[expired] ");
4957a608 1587 expired=true;
75b49099 1588 }
afbe2787 1589 }
57769f13 1590
f128d20d
RG
1591 ret.reserve(ret.size() + signatures.size() + authorityRecs.size());
1592
57769f13 1593 for(const auto& signature : signatures) {
e325f20c 1594 DNSRecord dr;
1595 dr.d_type=QType::RRSIG;
1596 dr.d_name=sqname;
1597 dr.d_ttl=ttl;
1598 dr.d_content=signature;
39ce10b2 1599 dr.d_place = DNSResourceRecord::ANSWER;
4d2be65d 1600 dr.d_class=QClass::IN;
e325f20c 1601 ret.push_back(dr);
57769f13 1602 }
2b984251
RG
1603
1604 for(const auto& rec : authorityRecs) {
1605 DNSRecord dr(*rec);
1606 dr.d_ttl=ttl;
1607 ret.push_back(dr);
1608 }
1609
77499b05 1610 LOG(endl);
f4df5e89 1611 if(found && !expired) {
4d2be65d 1612 if (!giveNegative)
4957a608 1613 res=0;
bcb05770 1614 LOG(prefix<<qname<<": updating validation state with cache content for "<<qname<<" to "<<vStates[cachedState]<<endl);
4d2be65d 1615 state = cachedState;
75b49099 1616 return true;
f4df5e89 1617 }
75b49099 1618 else
2189085d 1619 LOG(prefix<<qname<<": cache had only stale entries"<<endl);
afbe2787 1620 }
f4df5e89 1621
75b49099
BH
1622 return false;
1623}
afbe2787 1624
69cbdef9 1625bool SyncRes::moreSpecificThan(const DNSName& a, const DNSName &b) const
75b49099 1626{
6a1010f7 1627 return (a.isPartOf(b) && a.countLabels() > b.countLabels());
afbe2787
BH
1628}
1629
d8d0bb8f 1630struct speedOrder
eefd15f9 1631{
feccaf7f 1632 bool operator()(const std::pair<DNSName, double> &a, const std::pair<DNSName, double> &b) const
c3d9d009 1633 {
feccaf7f 1634 return a.second < b.second;
c3d9d009 1635 }
c3d9d009
BH
1636};
1637
feccaf7f 1638inline std::vector<std::pair<DNSName, double>> SyncRes::shuffleInSpeedOrder(NsSet &tnameservers, const string &prefix)
afbe2787 1639{
feccaf7f 1640 std::vector<std::pair<DNSName, double>> rnameservers;
5ea6f7de 1641 rnameservers.reserve(tnameservers.size());
a2d65f83 1642 for(const auto& tns: tnameservers) {
feccaf7f
RG
1643 double speed = t_sstorage.nsSpeeds[tns.first].get(&d_now);
1644 rnameservers.push_back({tns.first, speed});
a2d65f83 1645 if(tns.first.empty()) // this was an authoritative OOB zone, don't pollute the nsSpeeds with that
1646 return rnameservers;
21f0f88b 1647 }
461df9d2 1648
feccaf7f
RG
1649 random_shuffle(rnameservers.begin(),rnameservers.end());
1650 speedOrder so;
996c89cc 1651 stable_sort(rnameservers.begin(),rnameservers.end(), so);
710af846 1652
77499b05
BH
1653 if(doLog()) {
1654 LOG(prefix<<"Nameservers: ");
feccaf7f
RG
1655 for(auto i=rnameservers.begin();i!=rnameservers.end();++i) {
1656 if(i!=rnameservers.begin()) {
77499b05
BH
1657 LOG(", ");
1658 if(!((i-rnameservers.begin())%3)) {
1659 LOG(endl<<prefix<<" ");
1660 }
d8d0bb8f 1661 }
feccaf7f 1662 LOG(i->first.toLogString()<<"(" << (boost::format("%0.2f") % (i->second/1000.0)).str() <<"ms)");
d8d0bb8f 1663 }
77499b05 1664 LOG(endl);
d8d0bb8f 1665 }
728485ca 1666 return rnameservers;
afbe2787
BH
1667}
1668
cc11d7f4 1669inline vector<ComboAddress> SyncRes::shuffleForwardSpeed(const vector<ComboAddress> &rnameservers, const string &prefix, const bool wasRd)
589884b8 1670{
cc11d7f4 1671 vector<ComboAddress> nameservers = rnameservers;
6ed0c28a 1672 map<ComboAddress, double> speeds;
589884b8 1673
cc11d7f4 1674 for(const auto& val: nameservers) {
589884b8 1675 double speed;
6ed0c28a 1676 DNSName nsName = DNSName(val.toStringWithPort());
1677 speed=t_sstorage.nsSpeeds[nsName].get(&d_now);
589884b8 1678 speeds[val]=speed;
1679 }
feccaf7f 1680 random_shuffle(nameservers.begin(),nameservers.end());
6ed0c28a 1681 speedOrderCA so(speeds);
cc11d7f4 1682 stable_sort(nameservers.begin(),nameservers.end(), so);
589884b8 1683
589884b8 1684 if(doLog()) {
1685 LOG(prefix<<"Nameservers: ");
cc11d7f4 1686 for(vector<ComboAddress>::const_iterator i=nameservers.cbegin();i!=nameservers.cend();++i) {
1687 if(i!=nameservers.cbegin()) {
589884b8 1688 LOG(", ");
cc11d7f4 1689 if(!((i-nameservers.cbegin())%3)) {
589884b8 1690 LOG(endl<<prefix<<" ");
1691 }
1692 }
6ed0c28a 1693 LOG((wasRd ? string("+") : string("-")) << i->toStringWithPort() <<"(" << (boost::format("%0.2f") % (speeds[*i]/1000.0)).str() <<"ms)");
589884b8 1694 }
1695 LOG(endl);
1696 }
cc11d7f4 1697 return nameservers;
589884b8 1698}
1699
dbbef467
RG
1700static uint32_t getRRSIGTTL(const time_t now, const std::shared_ptr<RRSIGRecordContent>& rrsig)
1701{
1702 uint32_t res = 0;
1703 if (now < rrsig->d_sigexpire) {
1704 res = static_cast<uint32_t>(rrsig->d_sigexpire) - now;
1705 }
1706 return res;
1707}
1708
2b984251
RG
1709static const set<uint16_t> nsecTypes = {QType::NSEC, QType::NSEC3};
1710
39ce10b2
PL
1711/* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
1712 *
1713 * \param records The records to parse for the authority SOA and NSEC(3) records
1714 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
1715 */
dbbef467 1716static void harvestNXRecords(const vector<DNSRecord>& records, NegCache::NegCacheEntry& ne, const time_t now, uint32_t* lowestTTL) {
620db2c8 1717 for(const auto& rec : records) {
39ce10b2
PL
1718 if(rec.d_place != DNSResourceRecord::AUTHORITY)
1719 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
1720 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
1721 // records MUST be in the same section as the records they cover.
1722 // Hence, we ignore all records outside of the AUTHORITY section.
1723 continue;
1724
620db2c8 1725 if(rec.d_type == QType::RRSIG) {
39ce10b2
PL
1726 auto rrsig = getRR<RRSIGRecordContent>(rec);
1727 if(rrsig) {
1728 if(rrsig->d_type == QType::SOA) {
1729 ne.authoritySOA.signatures.push_back(rec);
dbbef467
RG
1730 if (lowestTTL && isRRSIGNotExpired(now, rrsig)) {
1731 *lowestTTL = min(*lowestTTL, rec.d_ttl);
1732 *lowestTTL = min(*lowestTTL, getRRSIGTTL(now, rrsig));
1733 }
39ce10b2
PL
1734 }
1735 if(nsecTypes.count(rrsig->d_type)) {
1736 ne.DNSSECRecords.signatures.push_back(rec);
dbbef467
RG
1737 if (lowestTTL && isRRSIGNotExpired(now, rrsig)) {
1738 *lowestTTL = min(*lowestTTL, rec.d_ttl);
1739 *lowestTTL = min(*lowestTTL, getRRSIGTTL(now, rrsig));
1740 }
39ce10b2
PL
1741 }
1742 }
1743 continue;
1744 }
1745 if(rec.d_type == QType::SOA) {
1746 ne.authoritySOA.records.push_back(rec);
dbbef467
RG
1747 if (lowestTTL) {
1748 *lowestTTL = min(*lowestTTL, rec.d_ttl);
1749 }
39ce10b2
PL
1750 continue;
1751 }
1752 if(nsecTypes.count(rec.d_type)) {
1753 ne.DNSSECRecords.records.push_back(rec);
dbbef467
RG
1754 if (lowestTTL) {
1755 *lowestTTL = min(*lowestTTL, rec.d_ttl);
1756 }
39ce10b2 1757 continue;
620db2c8 1758 }
620db2c8 1759 }
620db2c8 1760}
1761
4d2be65d
RG
1762static cspmap_t harvestCSPFromNE(const NegCache::NegCacheEntry& ne)
1763{
1764 cspmap_t cspmap;
1765 for(const auto& rec : ne.DNSSECRecords.signatures) {
1766 if(rec.d_type == QType::RRSIG) {
1767 auto rrc = getRR<RRSIGRecordContent>(rec);
1768 if (rrc) {
1769 cspmap[{rec.d_name,rrc->d_type}].signatures.push_back(rrc);
1770 }
1771 }
1772 }
1773 for(const auto& rec : ne.DNSSECRecords.records) {
1774 cspmap[{rec.d_name, rec.d_type}].records.push_back(rec.d_content);
1775 }
1776 return cspmap;
1777}
1778
39ce10b2
PL
1779// TODO remove after processRecords is fixed!
1780// Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
620db2c8 1781static void addNXNSECS(vector<DNSRecord>&ret, const vector<DNSRecord>& records)
1782{
39ce10b2 1783 NegCache::NegCacheEntry ne;
dbbef467 1784 harvestNXRecords(records, ne, 0, nullptr);
39ce10b2
PL
1785 ret.insert(ret.end(), ne.authoritySOA.signatures.begin(), ne.authoritySOA.signatures.end());
1786 ret.insert(ret.end(), ne.DNSSECRecords.records.begin(), ne.DNSSECRecords.records.end());
1787 ret.insert(ret.end(), ne.DNSSECRecords.signatures.begin(), ne.DNSSECRecords.signatures.end());
620db2c8 1788}
1789
69cbdef9 1790bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine& dfe, const NsSet& nameservers)
26ca3513
RG
1791{
1792 if(d_wantsRPZ) {
1793 for (auto const &ns : nameservers) {
69cbdef9 1794 d_appliedPolicy = dfe.getProcessingPolicy(ns.first, d_discardedPolicies);
26ca3513
RG
1795 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
1796 LOG(", however nameserver "<<ns.first<<" was blocked by RPZ policy '"<<(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")<<"'"<<endl);
1797 return true;
1798 }
1799
1800 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1801 for (auto const &address : ns.second.first) {
69cbdef9 1802 d_appliedPolicy = dfe.getProcessingPolicy(address, d_discardedPolicies);
26ca3513
RG
1803 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
1804 LOG(", however nameserver "<<ns.first<<" IP address "<<address.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")<<"'"<<endl);
1805 return true;
1806 }
1807 }
1808 }
1809 }
1810 return false;
1811}
1812
69cbdef9 1813bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine& dfe, const ComboAddress& remoteIP)
26ca3513
RG
1814{
1815 if (d_wantsRPZ) {
69cbdef9 1816 d_appliedPolicy = dfe.getProcessingPolicy(remoteIP, d_discardedPolicies);
26ca3513
RG
1817 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) {
1818 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")+"')");
1819 return true;
1820 }
1821 }
1822 return false;
1823}
1824
feccaf7f 1825vector<ComboAddress> SyncRes::retrieveAddressesForNS(const std::string& prefix, const DNSName& qname, std::vector<std::pair<DNSName, double>>::const_iterator& tns, const unsigned int depth, set<GetBestNSAnswer>& beenthere, const vector<std::pair<DNSName, double>>& rnameservers, NsSet& nameservers, bool& sendRDQuery, bool& pierceDontQuery, bool& flawedNSSet, bool cacheOnly)
26ca3513
RG
1826{
1827 vector<ComboAddress> result;
1828
feccaf7f
RG
1829 if(!tns->first.empty()) {
1830 LOG(prefix<<qname<<": Trying to resolve NS '"<<tns->first<< "' ("<<1+tns-rnameservers.begin()<<"/"<<(unsigned int)rnameservers.size()<<")"<<endl);
1831 result = getAddrs(tns->first, depth+2, beenthere, cacheOnly);
26ca3513
RG
1832 pierceDontQuery=false;
1833 }
1834 else {
1835 LOG(prefix<<qname<<": Domain has hardcoded nameserver");
1836
feccaf7f 1837 if(nameservers[tns->first].first.size() > 1) {
26ca3513
RG
1838 LOG("s");
1839 }
1840 LOG(endl);
1841
feccaf7f
RG
1842 sendRDQuery = nameservers[tns->first].second;
1843 result = shuffleForwardSpeed(nameservers[tns->first].first, doLog() ? (prefix+qname.toString()+": ") : string(), sendRDQuery);
26ca3513
RG
1844 pierceDontQuery=true;
1845 }
1846 return result;
1847}
1848
1849bool SyncRes::throttledOrBlocked(const std::string& prefix, const ComboAddress& remoteIP, const DNSName& qname, const QType& qtype, bool pierceDontQuery)
1850{
a712cb56 1851 if(t_sstorage.throttle.shouldThrottle(d_now.tv_sec, boost::make_tuple(remoteIP, "", 0))) {
26ca3513
RG
1852 LOG(prefix<<qname<<": server throttled "<<endl);
1853 s_throttledqueries++; d_throttledqueries++;
1854 return true;
1855 }
a712cb56 1856 else if(t_sstorage.throttle.shouldThrottle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()))) {
6dfff36f 1857 LOG(prefix<<qname<<": query throttled "<<remoteIP.toString()<<", "<<qname<<"; "<<qtype.getName()<<endl);
26ca3513
RG
1858 s_throttledqueries++; d_throttledqueries++;
1859 return true;
1860 }
9065eb05 1861 else if(!pierceDontQuery && s_dontQuery && s_dontQuery->match(&remoteIP)) {
26ca3513
RG
1862 LOG(prefix<<qname<<": not sending query to " << remoteIP.toString() << ", blocked by 'dont-query' setting" << endl);
1863 s_dontqueries++;
1864 return true;
1865 }
1866 return false;
1867}
1868
4d2be65d
RG
1869bool SyncRes::validationEnabled() const
1870{
8455425c 1871 return g_dnssecmode != DNSSECMode::Off && g_dnssecmode != DNSSECMode::ProcessNoValidate;
4d2be65d
RG
1872}
1873
1874uint32_t SyncRes::computeLowestTTD(const std::vector<DNSRecord>& records, const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures, uint32_t signaturesTTL) const
26ca3513 1875{
4d2be65d
RG
1876 uint32_t lowestTTD = std::numeric_limits<uint32_t>::max();
1877 for(const auto& record : records)
1878 lowestTTD = min(lowestTTD, record.d_ttl);
1879
0c43f455
RG
1880 /* even if it was not requested for that request (Process, and neither AD nor DO set),
1881 it might be requested at a later time so we need to be careful with the TTL. */
4d2be65d 1882 if (validationEnabled() && !signatures.empty()) {
3cef03e9 1883 /* if we are validating, we don't want to cache records after their signatures expire. */
4d2be65d
RG
1884 /* records TTL are now TTD, let's add 'now' to the signatures lowest TTL */
1885 lowestTTD = min(lowestTTD, static_cast<uint32_t>(signaturesTTL + d_now.tv_sec));
1886
1887 for(const auto& sig : signatures) {
dbbef467
RG
1888 if (isRRSIGNotExpired(d_now.tv_sec, sig)) {
1889 // we don't decerement d_sigexpire by 'now' because we actually want a TTD, not a TTL */
4d2be65d
RG
1890 lowestTTD = min(lowestTTD, static_cast<uint32_t>(sig->d_sigexpire));
1891 }
1892 }
1893 }
1894
1895 return lowestTTD;
1896}
1897
1898void SyncRes::updateValidationState(vState& state, const vState stateUpdate)
1899{
f715542c 1900 LOG(d_prefix<<"validation state was "<<std::string(vStates[state])<<", state update is "<<std::string(vStates[stateUpdate]));
4d2be65d 1901
895449a5
RG
1902 if (stateUpdate == TA) {
1903 state = Secure;
4d2be65d
RG
1904 }
1905 else if (stateUpdate == NTA) {
1906 state = Insecure;
1907 }
895449a5
RG
1908 else if (stateUpdate == Bogus) {
1909 state = Bogus;
1910 }
1911 else if (state == Indeterminate) {
1912 state = stateUpdate;
1913 }
4d2be65d
RG
1914 else if (stateUpdate == Insecure) {
1915 if (state != Bogus) {
1916 state = Insecure;
1917 }
1918 }
f715542c 1919 LOG(", validation state is now "<<std::string(vStates[state])<<endl);
4d2be65d
RG
1920}
1921
1922vState SyncRes::getTA(const DNSName& zone, dsmap_t& ds)
1923{
1924 auto luaLocal = g_luaconfs.getLocal();
1925
1926 if (luaLocal->dsAnchors.empty()) {
e77f01d1 1927 LOG(d_prefix<<": No trust anchors configured, everything is Insecure"<<endl);
4d2be65d
RG
1928 /* We have no TA, everything is insecure */
1929 return Insecure;
1930 }
1931
1932 std::string reason;
1933 if (haveNegativeTrustAnchor(luaLocal->negAnchors, zone, reason)) {
e77f01d1 1934 LOG(d_prefix<<": got NTA for '"<<zone<<"'"<<endl);
4d2be65d
RG
1935 return NTA;
1936 }
1937
1938 if (getTrustAnchor(luaLocal->dsAnchors, zone, ds)) {
e77f01d1 1939 LOG(d_prefix<<": got TA for '"<<zone<<"'"<<endl);
895449a5 1940 return TA;
4d2be65d 1941 }
e77f01d1 1942 else {
1943 LOG(d_prefix<<": no TA found for '"<<zone<<"' among "<< luaLocal->dsAnchors.size()<<endl);
1944 }
4d2be65d
RG
1945
1946 if (zone.isRoot()) {
1947 /* No TA for the root */
1948 return Insecure;
1949 }
1950
1951 return Indeterminate;
1952}
1953
8455425c
RG
1954static size_t countSupportedDS(const dsmap_t& dsmap)
1955{
1956 size_t count = 0;
1957
1958 for (const auto& ds : dsmap) {
1959 if (isSupportedDS(ds)) {
1960 count++;
1961 }
1962 }
1963
1964 return count;
1965}
1966
5374b03b 1967vState SyncRes::getDSRecords(const DNSName& zone, dsmap_t& ds, bool taOnly, unsigned int depth, bool bogusOnNXD, bool* foundCut)
4d2be65d
RG
1968{
1969 vState result = getTA(zone, ds);
1970
1971 if (result != Indeterminate || taOnly) {
5374b03b
RG
1972 if (foundCut) {
1973 *foundCut = (result != Indeterminate);
1974 }
1975
18159e92
RG
1976 if (result == TA) {
1977 if (countSupportedDS(ds) == 0) {
1978 ds.clear();
1979 result = Insecure;
1980 }
1981 else {
1982 result = Secure;
1983 }
1984 }
1985 else if (result == NTA) {
8455425c
RG
1986 result = Insecure;
1987 }
1988
4d2be65d
RG
1989 return result;
1990 }
1991
1992 bool oldSkipCNAME = d_skipCNAMECheck;
4d2be65d 1993 d_skipCNAMECheck = true;
4d2be65d
RG
1994
1995 std::set<GetBestNSAnswer> beenthere;
1996 std::vector<DNSRecord> dsrecords;
1997
1998 vState state = Indeterminate;
51b6b728 1999 int rcode = doResolve(zone, QType(QType::DS), dsrecords, depth + 1, beenthere, state);
4d2be65d 2000 d_skipCNAMECheck = oldSkipCNAME;
4d2be65d 2001
3ca6d908 2002 if (rcode == RCode::NoError || (rcode == RCode::NXDomain && !bogusOnNXD)) {
1e332f68
PL
2003 uint8_t bestDigestType = 0;
2004
dd359a9f
RG
2005 bool gotCNAME = false;
2006 for (const auto& record : dsrecords) {
2007 if (record.d_type == QType::DS) {
2008 const auto dscontent = getRR<DSRecordContent>(record);
2009 if (dscontent && isSupportedDS(*dscontent)) {
2010 // Make GOST a lower prio than SHA256
690b86b7 2011 if (dscontent->d_digesttype == DNSSECKeeper::DIGEST_GOST && bestDigestType == DNSSECKeeper::DIGEST_SHA256) {
dd359a9f 2012 continue;
4d2be65d 2013 }
690b86b7 2014 if (dscontent->d_digesttype > bestDigestType || (bestDigestType == DNSSECKeeper::DIGEST_GOST && dscontent->d_digesttype == DNSSECKeeper::DIGEST_SHA256)) {
dd359a9f
RG
2015 bestDigestType = dscontent->d_digesttype;
2016 }
2017 ds.insert(*dscontent);
1c39e884 2018 }
4d2be65d 2019 }
dd359a9f
RG
2020 else if (record.d_type == QType::CNAME && record.d_name == zone) {
2021 gotCNAME = true;
2022 }
2023 }
4d2be65d 2024
dd359a9f
RG
2025 /* RFC 4509 section 3: "Validator implementations SHOULD ignore DS RRs containing SHA-1
2026 * digests if DS RRs with SHA-256 digests are present in the DS RRset."
2027 * As SHA348 is specified as well, the spirit of the this line is "use the best algorithm".
2028 */
2029 for (auto dsrec = ds.begin(); dsrec != ds.end(); ) {
2030 if (dsrec->d_digesttype != bestDigestType) {
2031 dsrec = ds.erase(dsrec);
1e332f68 2032 }
dd359a9f
RG
2033 else {
2034 ++dsrec;
2035 }
2036 }
1e332f68 2037
dd359a9f
RG
2038 if (rcode == RCode::NoError) {
2039 if (ds.empty()) {
46df9251
RG
2040 /* we have no DS, it's either:
2041 - a delegation to a non-DNSSEC signed zone
2042 - no delegation, we stay in the same zone
2043 */
dd359a9f
RG
2044 if (gotCNAME || denialProvesNoDelegation(zone, dsrecords)) {
2045 /* we are still inside the same zone */
5374b03b 2046
dd359a9f 2047 if (foundCut) {
5374b03b 2048 *foundCut = false;
5374b03b 2049 }
dd359a9f
RG
2050 return state;
2051 }
5374b03b 2052
dd359a9f
RG
2053 /* delegation with no DS, might be Secure -> Insecure */
2054 if (foundCut) {
5374b03b
RG
2055 *foundCut = true;
2056 }
2057
46df9251
RG
2058 /* a delegation with no DS is either:
2059 - a signed zone (Secure) to an unsigned one (Insecure)
2060 - an unsigned zone to another unsigned one (Insecure stays Insecure, Bogus stays Bogus)
2061 */
dd359a9f
RG
2062 return state == Secure ? Insecure : state;
2063 } else {
2064 /* we have a DS */
2065 if (foundCut) {
2066 *foundCut = true;
2067 }
b7f378d1 2068 }
4d2be65d 2069 }
b7f378d1 2070
4d2be65d
RG
2071 return state;
2072 }
2073
bcb05770 2074 LOG(d_prefix<<": returning Bogus state from "<<__func__<<"("<<zone<<")"<<endl);
4d2be65d
RG
2075 return Bogus;
2076}
2077
0735b60f
RG
2078bool SyncRes::haveExactValidationStatus(const DNSName& domain)
2079{
e1636f82 2080 if (!shouldValidate()) {
0735b60f
RG
2081 return false;
2082 }
2083 const auto& it = d_cutStates.find(domain);
2084 if (it != d_cutStates.cend()) {
2085 return true;
2086 }
2087 return false;
2088}
2089
5374b03b 2090vState SyncRes::getValidationStatus(const DNSName& subdomain, bool allowIndeterminate)
70b3fe7a
RG
2091{
2092 vState result = Indeterminate;
2093
e1636f82 2094 if (!shouldValidate()) {
70b3fe7a
RG
2095 return result;
2096 }
2097 DNSName name(subdomain);
2098 do {
51b6b728
RG
2099 const auto& it = d_cutStates.find(name);
2100 if (it != d_cutStates.cend()) {
5374b03b
RG
2101 if (allowIndeterminate || it->second != Indeterminate) {
2102 LOG(d_prefix<<": got status "<<vStates[it->second]<<" for name "<<subdomain<<" (from "<<name<<")"<<endl);
2103 return it->second;
2104 }
70b3fe7a
RG
2105 }
2106 }
2107 while (name.chopOff());
2108
2109 return result;
2110}
2111
c405e222
RG
2112bool SyncRes::lookForCut(const DNSName& qname, unsigned int depth, const vState existingState, vState& newState)
2113{
2114 bool foundCut = false;
5374b03b
RG
2115 dsmap_t ds;
2116 vState dsState = getDSRecords(qname, ds, newState == Bogus || existingState == Insecure || existingState == Bogus, depth, false, &foundCut);
c405e222 2117
5374b03b
RG
2118 if (dsState != Indeterminate) {
2119 newState = dsState;
2120 }
c405e222 2121
c405e222
RG
2122 return foundCut;
2123}
2124
51b6b728 2125void SyncRes::computeZoneCuts(const DNSName& begin, const DNSName& end, unsigned int depth)
4d2be65d 2126{
428f41b7 2127 if(!begin.isPartOf(end)) {
86f1af1c
KM
2128 LOG(d_prefix<<" "<<begin.toLogString()<<" is not part of "<<end.toLogString()<<endl);
2129 throw PDNSException(begin.toLogString() + " is not part of " + end.toLogString());
428f41b7
RG
2130 }
2131
51b6b728 2132 if (d_cutStates.count(begin) != 0) {
ad75fdbd 2133 return;
4d2be65d
RG
2134 }
2135
2136 dsmap_t ds;
51b6b728 2137 vState cutState = getDSRecords(end, ds, false, depth);
bcb05770 2138 LOG(d_prefix<<": setting cut state for "<<end<<" to "<<vStates[cutState]<<endl);
51b6b728 2139 d_cutStates[end] = cutState;
70b3fe7a 2140
e1636f82 2141 if (!shouldValidate()) {
ad75fdbd 2142 return;
70b3fe7a
RG
2143 }
2144
70b3fe7a
RG
2145 DNSName qname(end);
2146 std::vector<string> labelsToAdd = begin.makeRelative(end).getRawLabels();
2147
ad75fdbd 2148 bool oldSkipCNAME = d_skipCNAMECheck;
ad75fdbd 2149 d_skipCNAMECheck = true;
ad75fdbd 2150
70b3fe7a 2151 while(qname != begin) {
70b3fe7a
RG
2152 if (labelsToAdd.empty())
2153 break;
2154
2155 qname.prependRawLabel(labelsToAdd.back());
2156 labelsToAdd.pop_back();
bcb05770
RG
2157 LOG(d_prefix<<": - Looking for a cut at "<<qname<<endl);
2158
2159 const auto cutIt = d_cutStates.find(qname);
2160 if (cutIt != d_cutStates.cend()) {
2161 if (cutIt->second != Indeterminate) {
2162 LOG(d_prefix<<": - Cut already known at "<<qname<<endl);
3d4e836e 2163 cutState = cutIt->second;
bcb05770
RG
2164 continue;
2165 }
2166 }
70b3fe7a 2167
3d4e836e
RG
2168 /* no need to look for NS and DS if we are already insecure or bogus,
2169 just look for (N)TA
2170 */
2171 if (cutState == Insecure || cutState == Bogus) {
2010ac95
RG
2172 dsmap_t cutDS;
2173 vState newState = getDSRecords(qname, cutDS, true, depth);
3d4e836e
RG
2174 if (newState == Indeterminate) {
2175 continue;
2176 }
2177
2178 LOG(d_prefix<<": New state for "<<qname<<" is "<<vStates[newState]<<endl);
3d4e836e
RG
2179 cutState = newState;
2180
2181 d_cutStates[qname] = cutState;
2182
2183 continue;
2184 }
70b3fe7a 2185
c405e222 2186 vState newState = Indeterminate;
428f41b7
RG
2187 /* temporarily mark as Indeterminate, so that we won't enter an endless loop
2188 trying to determine that zone cut again. */
c405e222
RG
2189 d_cutStates[qname] = newState;
2190 bool foundCut = lookForCut(qname, depth + 1, cutState, newState);
2191 if (foundCut) {
2192 LOG(d_prefix<<": - Found cut at "<<qname<<endl);
2193 if (newState != Indeterminate) {
2194 cutState = newState;
70b3fe7a 2195 }
c405e222
RG
2196 LOG(d_prefix<<": New state for "<<qname<<" is "<<vStates[cutState]<<endl);
2197 d_cutStates[qname] = cutState;
70b3fe7a 2198 }
c405e222 2199 else {
428f41b7 2200 /* remove the temporary cut */
b25712fd 2201 LOG(d_prefix<<qname<<": removing cut state for "<<qname<<endl);
51b6b728 2202 d_cutStates.erase(qname);
428f41b7 2203 }
70b3fe7a
RG
2204 }
2205
ad75fdbd 2206 d_skipCNAMECheck = oldSkipCNAME;
ad75fdbd 2207
bcb05770 2208 LOG(d_prefix<<": list of cuts from "<<begin<<" to "<<end<<endl);
51b6b728 2209 for (const auto& cut : d_cutStates) {
bcb05770 2210 if (cut.first.isRoot() || (begin.isPartOf(cut.first) && cut.first.isPartOf(end))) {
51b6b728
RG
2211 LOG(" - "<<cut.first<<": "<<vStates[cut.second]<<endl);
2212 }
70b3fe7a 2213 }
4d2be65d
RG
2214}
2215
51b6b728 2216vState SyncRes::validateDNSKeys(const DNSName& zone, const std::vector<DNSRecord>& dnskeys, const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures, unsigned int depth)
4d2be65d
RG
2217{
2218 dsmap_t ds;
2219 if (!signatures.empty()) {
2220 DNSName signer = getSigner(signatures);
2221
8d2e7fa1 2222 if (!signer.empty() && zone.isPartOf(signer)) {
51b6b728 2223 vState state = getDSRecords(signer, ds, false, depth);
b7f378d1 2224
4d2be65d
RG
2225 if (state != Secure) {
2226 return state;
2227 }
2228 }
2229 }
2230
2231 skeyset_t tentativeKeys;
2232 std::vector<shared_ptr<DNSRecordContent> > toSign;
2233
2234 for (const auto& dnskey : dnskeys) {
2235 if (dnskey.d_type == QType::DNSKEY) {
2236 auto content = getRR<DNSKEYRecordContent>(dnskey);
2237 if (content) {
2238 tentativeKeys.insert(content);
2239 toSign.push_back(content);
2240 }
2241 }
2242 }
2243
bcb05770 2244 LOG(d_prefix<<": trying to validate "<<std::to_string(tentativeKeys.size())<<" DNSKEYs with "<<std::to_string(ds.size())<<" DS"<<endl);
4d2be65d
RG
2245 skeyset_t validatedKeys;
2246 validateDNSKeysAgainstDS(d_now.tv_sec, zone, ds, tentativeKeys, toSign, signatures, validatedKeys);
2247
bcb05770 2248 LOG(d_prefix<<": we now have "<<std::to_string(validatedKeys.size())<<" DNSKEYs"<<endl);
4d2be65d 2249
82fbd934
RG
2250 /* if we found at least one valid RRSIG covering the set,
2251 all tentative keys are validated keys. Otherwise it means
2252 we haven't found at least one DNSKEY and a matching RRSIG
2253 covering this set, this looks Bogus. */
4d2be65d 2254 if (validatedKeys.size() != tentativeKeys.size()) {
bcb05770 2255 LOG(d_prefix<<": returning Bogus state from "<<__func__<<"("<<zone<<")"<<endl);
4d2be65d
RG
2256 return Bogus;
2257 }
2258
2259 return Secure;
2260}
2261
51b6b728 2262vState SyncRes::getDNSKeys(const DNSName& signer, skeyset_t& keys, unsigned int depth)
4d2be65d
RG
2263{
2264 std::vector<DNSRecord> records;
2265 std::set<GetBestNSAnswer> beenthere;
bcb05770 2266 LOG(d_prefix<<"Retrieving DNSKeys for "<<signer<<endl);
4d2be65d
RG
2267
2268 vState state = Indeterminate;
c7385ddb
RG
2269 /* following CNAME might lead to us to the wrong DNSKEY */
2270 bool oldSkipCNAME = d_skipCNAMECheck;
2271 d_skipCNAMECheck = true;
51b6b728 2272 int rcode = doResolve(signer, QType(QType::DNSKEY), records, depth + 1, beenthere, state);
c7385ddb 2273 d_skipCNAMECheck = oldSkipCNAME;
4d2be65d
RG
2274
2275 if (rcode == RCode::NoError) {
2276 if (state == Secure) {
2277 for (const auto& key : records) {
2278 if (key.d_type == QType::DNSKEY) {
2279 auto content = getRR<DNSKEYRecordContent>(key);
2280 if (content) {
2281 keys.insert(content);
2282 }
2283 }
2284 }
2285 }
bcb05770 2286 LOG(d_prefix<<"Retrieved "<<keys.size()<<" DNSKeys for "<<signer<<", state is "<<vStates[state]<<endl);
4d2be65d
RG
2287 return state;
2288 }
2289
bcb05770 2290 LOG(d_prefix<<"Returning Bogus state from "<<__func__<<"("<<signer<<")"<<endl);
4d2be65d
RG
2291 return Bogus;
2292}
2293
51b6b728 2294vState 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
2295{
2296 skeyset_t keys;
2297 if (!signatures.empty()) {
2298 const DNSName signer = getSigner(signatures);
2299 if (!signer.empty() && name.isPartOf(signer)) {
f715542c 2300 if ((qtype == QType::DNSKEY || qtype == QType::DS) && signer == qname) {
15f44f1d 2301 /* we are already retrieving those keys, sorry */
dd359a9f
RG
2302 if (qtype == QType::DS) {
2303 /* something is very wrong */
2304 LOG(d_prefix<<"The DS for "<<qname<<" is signed by itself, going Bogus"<<endl);
2305 return Bogus;
2306 }
15f44f1d
RG
2307 return Indeterminate;
2308 }
51b6b728 2309 vState state = getDNSKeys(signer, keys, depth);
4d2be65d
RG
2310 if (state != Secure) {
2311 return state;
2312 }
2313 }
2314 } else {
bcb05770 2315 LOG(d_prefix<<"Bogus!"<<endl);
4d2be65d
RG
2316 return Bogus;
2317 }
2318
2319 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
2320 for (const auto& record : records) {
2321 recordcontents.push_back(record.d_content);
2322 }
2323
bcb05770 2324 LOG(d_prefix<<"Going to validate "<<recordcontents.size()<< " record contents with "<<signatures.size()<<" sigs and "<<keys.size()<<" keys for "<<name<<endl);
4d2be65d 2325 if (validateWithKeySet(d_now.tv_sec, name, recordcontents, signatures, keys, false)) {
bcb05770 2326 LOG(d_prefix<<"Secure!"<<endl);
4d2be65d
RG
2327 return Secure;
2328 }
2329
bcb05770 2330 LOG(d_prefix<<"Bogus!"<<endl);
4d2be65d
RG
2331 return Bogus;
2332}
2333
7155c3e5
RG
2334static bool allowAdditionalEntry(std::unordered_set<DNSName>& allowedAdditionals, const DNSRecord& rec)
2335{
2336 switch(rec.d_type) {
2337 case QType::MX:
2338 {
2339 if (auto mxContent = getRR<MXRecordContent>(rec)) {
2340 allowedAdditionals.insert(mxContent->d_mxname);
2341 }
2342 return true;
2343 }
2344 case QType::NS:
2345 {
2346 if (auto nsContent = getRR<NSRecordContent>(rec)) {
2347 allowedAdditionals.insert(nsContent->getNS());
2348 }
2349 return true;
2350 }
2351 case QType::SRV:
2352 {
2353 if (auto srvContent = getRR<SRVRecordContent>(rec)) {
2354 allowedAdditionals.insert(srvContent->d_target);
2355 }
2356 return true;
2357 }
2358 default:
2359 return false;
2360 }
2361}
2362
2363void SyncRes::sanitizeRecords(const std::string& prefix, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, bool rdQuery)
2364{
2365 const bool wasForwardRecurse = wasForwarded && rdQuery;
2366 /* list of names for which we will allow A and AAAA records in the additional section
2367 to remain */
2368 std::unordered_set<DNSName> allowedAdditionals = { qname };
2369 bool haveAnswers = false;
2370 bool isNXDomain = false;
2371 bool isNXQType = false;
2372
2373 for(auto rec = lwr.d_records.begin(); rec != lwr.d_records.end(); ) {
2374
2375 if (rec->d_type == QType::OPT) {
2376 ++rec;
2377 continue;
2378 }
2379
2380 if (rec->d_class != QClass::IN) {
2381 LOG(prefix<<"Removing non internet-classed data received from "<<auth<<endl);
2382 rec = lwr.d_records.erase(rec);
2383 continue;
2384 }
2385
2386 if (rec->d_type == QType::ANY) {
2387 LOG(prefix<<"Removing 'ANY'-typed data received from "<<auth<<endl);
2388 rec = lwr.d_records.erase(rec);
2389 continue;
2390 }
2391
2392 if (!rec->d_name.isPartOf(auth)) {
2393 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);
2394 rec = lwr.d_records.erase(rec);
2395 continue;
2396 }
2397
2398 /* dealing with the records in answer */
2399 if (!(lwr.d_aabit || wasForwardRecurse) && rec->d_place == DNSResourceRecord::ANSWER) {
9870af40
RG
2400 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2401 are sending such responses */
2402 if (!(rec->d_type == QType::CNAME && qname == rec->d_name)) {
2403 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);
2404 rec = lwr.d_records.erase(rec);
2405 continue;
2406 }
7155c3e5
RG
2407 }
2408
2409 if (rec->d_type == QType::DNAME && (rec->d_place != DNSResourceRecord::ANSWER || !qname.isPartOf(rec->d_name))) {
2410 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);
2411 rec = lwr.d_records.erase(rec);
2412 continue;
2413 }
2414
123da0f8 2415 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
2416 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);
2417 rec = lwr.d_records.erase(rec);
2418 continue;
2419 }
2420
2421 if (rec->d_place == DNSResourceRecord::ANSWER && !haveAnswers) {
2422 haveAnswers = true;
2423 }
2424
2425 if (rec->d_place == DNSResourceRecord::ANSWER) {
2426 allowAdditionalEntry(allowedAdditionals, *rec);
2427 }
2428
2429 /* dealing with the records in authority */
2430 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) {
2431 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);
2432 rec = lwr.d_records.erase(rec);
2433 continue;
2434 }
2435
2436 if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type == QType::SOA) {
2437 if (!qname.isPartOf(rec->d_name)) {
2438 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);
2439 rec = lwr.d_records.erase(rec);
2440 continue;
2441 }
2442
215c16f9
RG
2443 if (!(lwr.d_aabit || wasForwardRecurse)) {
2444 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);
2445 rec = lwr.d_records.erase(rec);
2446 continue;
2447 }
2448
7155c3e5
RG
2449 if (!haveAnswers) {
2450 if (lwr.d_rcode == RCode::NXDomain) {
2451 isNXDomain = true;
2452 }
2453 else if (lwr.d_rcode == RCode::NoError) {
2454 isNXQType = true;
2455 }
2456 }
2457 }
2458
2459 if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type == QType::NS && (isNXDomain || isNXQType)) {
2460 /* we don't want to pick up NS records in AUTHORITY or ADDITIONAL sections of NXDomain answers
2461 because they are somewhat easy to insert into a large, fragmented UDP response
1bb97c02 2462 for an off-path attacker by injecting spoofed UDP fragments.
7155c3e5
RG
2463 */
2464 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);
2465 rec = lwr.d_records.erase(rec);
1bb97c02 2466 continue;
7155c3e5
RG
2467 }
2468
2469 if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type == QType::NS) {
2470 allowAdditionalEntry(allowedAdditionals, *rec);
2471 }
2472
2473 /* dealing with the records in additional */
2474 if (rec->d_place == DNSResourceRecord::ADDITIONAL && rec->d_type != QType::A && rec->d_type != QType::AAAA && rec->d_type != QType::RRSIG) {
2475 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);
2476 rec = lwr.d_records.erase(rec);
2477 continue;
2478 }
2479
2480 if (rec->d_place == DNSResourceRecord::ADDITIONAL && allowedAdditionals.count(rec->d_name) == 0) {
2481 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);
2482 rec = lwr.d_records.erase(rec);
2483 continue;
2484 }
2485
2486 ++rec;
2487 }
2488}
2489
78cdf520 2490RCode::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 2491{
ba40d3d7 2492 bool wasForwardRecurse = wasForwarded && rdQuery;
26ca3513
RG
2493 tcache_t tcache;
2494
4d2be65d
RG
2495 string prefix;
2496 if(doLog()) {
2497 prefix=d_prefix;
2498 prefix.append(depth, ' ');
2499 }
2500
7155c3e5
RG
2501 sanitizeRecords(prefix, lwr, qname, qtype, auth, wasForwarded, rdQuery);
2502
2b984251 2503 std::vector<std::shared_ptr<DNSRecord>> authorityRecs;
142ab370 2504 const unsigned int labelCount = qname.countLabels();
a82d4e27 2505 bool isCNAMEAnswer = false;
8838c88f 2506 bool isDNAMEAnswer = false;
26ca3513 2507 for(const auto& rec : lwr.d_records) {
c5310862
RG
2508 if (rec.d_class != QClass::IN) {
2509 continue;
2510 }
2511
d30b5493 2512 if(!isCNAMEAnswer && rec.d_place == DNSResourceRecord::ANSWER && rec.d_type == QType::CNAME && (!(qtype==QType(QType::CNAME))) && rec.d_name == qname && !isDNAMEAnswer) {
a82d4e27
RG
2513 isCNAMEAnswer = true;
2514 }
d30b5493 2515 if(!isDNAMEAnswer && rec.d_place == DNSResourceRecord::ANSWER && rec.d_type == QType::DNAME && qtype != QType(QType::DNAME) && qname.isPartOf(rec.d_name)) {
8838c88f 2516 isDNAMEAnswer = true;
d30b5493 2517 isCNAMEAnswer = false;
8838c88f 2518 }
a82d4e27 2519
9b061cf5
RG
2520 /* if we have a positive answer synthetized from a wildcard,
2521 we need to store the corresponding NSEC/NSEC3 records proving
2522 that the exact name did not exist in the negative cache */
78cdf520 2523 if(gatherWildcardProof) {
2b984251
RG
2524 if (nsecTypes.count(rec.d_type)) {
2525 authorityRecs.push_back(std::make_shared<DNSRecord>(rec));
2526 }
2527 else if (rec.d_type == QType::RRSIG) {
2528 auto rrsig = getRR<RRSIGRecordContent>(rec);
2529 if (rrsig && nsecTypes.count(rrsig->d_type)) {
2530 authorityRecs.push_back(std::make_shared<DNSRecord>(rec));
2531 }
2532 }
2533 }
26ca3513
RG
2534 if(rec.d_type == QType::RRSIG) {
2535 auto rrsig = getRR<RRSIGRecordContent>(rec);
2536 if (rrsig) {
bb07ad8e
RG
2537 /* As illustrated in rfc4035's Appendix B.6, the RRSIG label
2538 count can be lower than the name's label count if it was
9b061cf5 2539 synthetized from the wildcard. Note that the difference might
bb07ad8e 2540 be > 1. */
78cdf520
RG
2541 if (rec.d_name == qname && isWildcardExpanded(labelCount, rrsig)) {
2542 gatherWildcardProof = true;
2543 if (!isWildcardExpandedOntoItself(rec.d_name, labelCount, rrsig)) {
2544 /* if we have a wildcard expanded onto itself, we don't need to prove
2545 that the exact name doesn't exist because it actually does.
2546 We still want to gather the corresponding NSEC/NSEC3 records
2547 to pass them to our client in case it wants to validate by itself.
2548 */
2549 LOG(prefix<<qname<<": RRSIG indicates the name was synthetized from a wildcard, we need a wildcard proof"<<endl);
2550 needWildcardProof = true;
2551 }
2552 else {
2553 LOG(prefix<<qname<<": RRSIG indicates the name was synthetized from a wildcard expanded onto itself, we need to gather wildcard proof"<<endl);
2554 }
e4894ce0 2555 wildcardLabelsCount = rrsig->d_labels;
2b984251
RG
2556 }
2557
26ca3513
RG
2558 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
2559 tcache[{rec.d_name, rrsig->d_type, rec.d_place}].signatures.push_back(rrsig);
4d2be65d 2560 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
2561 }
2562 }
2563 }
2564
2565 // reap all answers from this packet that are acceptable
2566 for(auto& rec : lwr.d_records) {
2567 if(rec.d_type == QType::OPT) {
2568 LOG(prefix<<qname<<": OPT answer '"<<rec.d_name<<"' from '"<<auth<<"' nameservers" <<endl);
2569 continue;
2570 }
e77f01d1 2571 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 2572 if(rec.d_type == QType::ANY) {
c5310862
RG
2573 LOG("NO! - we don't accept 'ANY'-typed data"<<endl);
2574 continue;
2575 }
2576
2577 if(rec.d_class != QClass::IN) {
2578 LOG("NO! - we don't accept records for any other class than 'IN'"<<endl);
26ca3513
RG
2579 continue;
2580 }
2581
70ea0c65 2582 if (!(lwr.d_aabit || wasForwardRecurse) && rec.d_place == DNSResourceRecord::ANSWER) {
9870af40
RG
2583 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2584 are sending such responses */
2585 if (!(rec.d_type == QType::CNAME && rec.d_name == qname)) {
2586 LOG("NO! - we don't accept records in the answers section without the AA bit set"<<endl);
2587 continue;
2588 }
70ea0c65
RG
2589 }
2590
26ca3513
RG
2591 if(rec.d_name.isPartOf(auth)) {
2592 if(rec.d_type == QType::RRSIG) {
2593 LOG("RRSIG - separate"<<endl);
2594 }
4d2be65d 2595 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
2596 LOG("NO! Is from delegation-only zone"<<endl);
2597 s_nodelegated++;
2598 return RCode::NXDomain;
2599 }
2600 else {
2601 bool haveLogged = false;
d30b5493
PL
2602 if (isDNAMEAnswer && rec.d_type == QType::CNAME) {
2603 LOG("NO - we already have a DNAME answer for this domain");
2604 continue;
2605 }
a712cb56 2606 if (!t_sstorage.domainmap->empty()) {
26ca3513
RG
2607 // Check if we are authoritative for a zone in this answer
2608 DNSName tmp_qname(rec.d_name);
2609 auto auth_domain_iter=getBestAuthZone(&tmp_qname);
a712cb56 2610 if(auth_domain_iter!=t_sstorage.domainmap->end() &&
26ca3513
RG
2611 auth.countLabels() <= auth_domain_iter->first.countLabels()) {
2612 if (auth_domain_iter->first != auth) {
2613 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter->first<<endl);
2614 continue;
2615 } else {
2616 LOG("YES! - This answer was ");
6dfff36f 2617 if (!wasForwarded) {
26ca3513
RG
2618 LOG("retrieved from the local auth store.");
2619 } else {
2620 LOG("received from a server we forward to.");
2621 }
2622 haveLogged = true;
2623 LOG(endl);
2624 }
2625 }
2626 }
2627 if (!haveLogged) {
2628 LOG("YES!"<<endl);
2629 }
2630
2631 rec.d_ttl=min(s_maxcachettl, rec.d_ttl);
2632
2633 DNSRecord dr(rec);
26ca3513 2634 dr.d_ttl += d_now.tv_sec;
2b984251 2635 dr.d_place=DNSResourceRecord::ANSWER;
26ca3513
RG
2636 tcache[{rec.d_name,rec.d_type,rec.d_place}].records.push_back(dr);
2637 }
2638 }
2639 else
2640 LOG("NO!"<<endl);
2641 }
2642
2643 // supplant
4d2be65d
RG
2644 for(tcache_t::iterator i = tcache.begin(); i != tcache.end(); ++i) {
2645 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)
2646 uint32_t lowestTTD=computeLowestTTD(i->second.records, i->second.signatures, i->second.signaturesTTL);
26ca3513
RG
2647
2648 for(auto& record : i->second.records)
4d2be65d 2649 record.d_ttl = lowestTTD; // boom
26ca3513
RG
2650 }
2651
2652// cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
2653// cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
4d2be65d
RG
2654 }
2655
2656 for(tcache_t::iterator i = tcache.begin(); i != tcache.end(); ++i) {
4d2be65d 2657
26ca3513
RG
2658 if(i->second.records.empty()) // this happens when we did store signatures, but passed on the records themselves
2659 continue;
6dfff36f 2660
405a26bd
RG
2661 /* Even if the AA bit is set, additional data cannot be considered
2662 as authoritative. This is especially important during validation
2663 because keeping records in the additional section is allowed even
2664 if the corresponding RRSIGs are not included, without setting the TC
2665 bit, as stated in rfc4035's section 3.1.1. Including RRSIG RRs in a Response:
2666 "When placing a signed RRset in the Additional section, the name
2667 server MUST also place its RRSIG RRs in the Additional section.
2668 If space does not permit inclusion of both the RRset and its
2669 associated RRSIG RRs, the name server MAY retain the RRset while
2670 dropping the RRSIG RRs. If this happens, the name server MUST NOT
2671 set the TC bit solely because these RRSIG RRs didn't fit."
2672 */
2673 bool isAA = lwr.d_aabit && i->first.place != DNSResourceRecord::ADDITIONAL;
dff3ef07
RG
2674 /* if we forwarded the query to a recursor, we can expect the answer to be signed,
2675 even if the answer is not AA. Of course that's not only true inside a Secure
2676 zone, but we check that below. */
70ea0c65 2677 bool expectSignature = i->first.place == DNSResourceRecord::ANSWER || ((lwr.d_aabit || wasForwardRecurse) && i->first.place != DNSResourceRecord::ADDITIONAL);
dff3ef07 2678 if (isCNAMEAnswer && (i->first.place != DNSResourceRecord::ANSWER || i->first.type != QType::CNAME || i->first.name != qname)) {
a82d4e27
RG
2679 /*
2680 rfc2181 states:
2681 Note that the answer section of an authoritative answer normally
2682 contains only authoritative data. However when the name sought is an
2683 alias (see section 10.1.1) only the record describing that alias is
2684 necessarily authoritative. Clients should assume that other records
2685 may have come from the server's cache. Where authoritative answers
2686 are required, the client should query again, using the canonical name
2687 associated with the alias.
2688 */
2689 isAA = false;
dff3ef07 2690 expectSignature = false;
a82d4e27
RG
2691 }
2692
d9c32b52
RG
2693 if (isCNAMEAnswer && i->first.place == DNSResourceRecord::AUTHORITY && i->first.type == QType::NS && auth == i->first.name) {
2694 /* These NS can't be authoritative since we have a CNAME answer for which (see above) only the
2695 record describing that alias is necessarily authoritative.
2696 But if we allow the current auth, which might be serving the child zone, to raise the TTL
2697 of non-authoritative NS in the cache, they might be able to keep a "ghost" zone alive forever,
2698 even after the delegation is gone from the parent.
2699 So let's just do nothing with them, we can fetch them directly if we need them.
2700 */
2701 LOG(d_prefix<<": skipping authority NS from '"<<auth<<"' nameservers in CNAME answer "<<i->first.name<<"|"<<DNSRecordContent::NumberToType(i->first.type)<<endl);
2702 continue;
2703 }
2704
5374b03b 2705 vState recordState = getValidationStatus(i->first.name, false);
1a8d6a9e 2706 LOG(d_prefix<<": got initial zone status "<<vStates[recordState]<<" for record "<<i->first.name<<"|"<<DNSRecordContent::NumberToType(i->first.type)<<endl);
70b3fe7a 2707
e1636f82 2708 if (shouldValidate() && recordState == Secure) {
5374b03b
RG
2709 vState initialState = recordState;
2710
dff3ef07 2711 if (expectSignature) {
4d2be65d
RG
2712 if (i->first.place != DNSResourceRecord::ADDITIONAL) {
2713 /* the additional entries can be insecure,
2714 like glue:
2715 "Glue address RRsets associated with delegations MUST NOT be signed"
2716 */
2717 if (i->first.type == QType::DNSKEY && i->first.place == DNSResourceRecord::ANSWER) {
bcb05770 2718 LOG(d_prefix<<"Validating DNSKEY for "<<i->first.name<<endl);
51b6b728 2719 recordState = validateDNSKeys(i->first.name, i->second.records, i->second.signatures, depth);
4d2be65d
RG
2720 }
2721 else {
8838c88f
PL
2722 /*
2723 * RFC 6672 section 5.3.1
2724 * In any response, a signed DNAME RR indicates a non-terminal
2725 * redirection of the query. There might or might not be a server-
2726 * synthesized CNAME in the answer section; if there is, the CNAME will
2727 * never be signed. For a DNSSEC validator, verification of the DNAME
2728 * RR and then that the CNAME was properly synthesized is sufficient
2729 * proof.
2730 *
2731 * We do the synthesis check in processRecords, here we make sure we
2732 * don't validate the CNAME.
2733 */
2734 if (!(isDNAMEAnswer && i->first.type == QType::CNAME)) {
2735 LOG(d_prefix<<"Validating non-additional record for "<<i->first.name<<endl);
2736 recordState = validateRecordsWithSigs(depth, qname, qtype, i->first.name, i->second.records, i->second.signatures);
2737 /* 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 */
2738 if (qtype == QType::NS && i->second.signatures.empty() && recordState == Bogus && haveExactValidationStatus(i->first.name) && getValidationStatus(i->first.name) == Indeterminate) {
2739 recordState = Indeterminate;
2740 }
0735b60f 2741 }
4d2be65d
RG
2742 }
2743 }
2744 }
2745 else {
933299e8
RG
2746 recordState = Indeterminate;
2747
a82d4e27 2748 /* in a non authoritative answer, we only care about the DS record (or lack of) */
88cb0fe0 2749 if ((i->first.type == QType::DS || i->first.type == QType::NSEC || i->first.type == QType::NSEC3) && i->first.place == DNSResourceRecord::AUTHORITY) {
bcb05770 2750 LOG(d_prefix<<"Validating DS record for "<<i->first.name<<endl);
51b6b728 2751 recordState = validateRecordsWithSigs(depth, qname, qtype, i->first.name, i->second.records, i->second.signatures);
4d2be65d
RG
2752 }
2753 }
0735b60f 2754
dff3ef07 2755 if (initialState == Secure && state != recordState && expectSignature) {
5374b03b
RG
2756 updateValidationState(state, recordState);
2757 }
4d2be65d
RG
2758 }
2759 else {
e1636f82 2760 if (shouldValidate()) {
bcb05770 2761 LOG(d_prefix<<"Skipping validation because the current state is "<<vStates[recordState]<<endl);
4d2be65d
RG
2762 }
2763 }
2764
b9473937
RG
2765 if (recordState == Bogus) {
2766 /* this is a TTD by now, be careful */
2767 for(auto& record : i->second.records) {
2768 record.d_ttl = std::min(record.d_ttl, static_cast<uint32_t>(s_maxbogusttl + d_now.tv_sec));
2769 }
2770 }
2771
005b4b98
RG
2772 /* We don't need to store NSEC3 records in the positive cache because:
2773 - we don't allow direct NSEC3 queries
2774 - denial of existence proofs in wildcard expanded positive responses are stored in authorityRecs
2775 - denial of existence proofs for negative responses are stored in the negative cache
a321baf9
RG
2776 We also don't want to cache non-authoritative data except for:
2777 - records coming from non forward-recurse servers (those will never be AA)
2778 - DS (special case)
2779 - NS, A and AAAA (used for infra queries)
005b4b98 2780 */
a321baf9 2781 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 2782
73d9bf3a
OM
2783 bool doCache = true;
2784 if (i->first.place == DNSResourceRecord::ANSWER && ednsmask) {
2785 // If ednsmask is relevant, we do not want to cache if the scope prefix length is large and TTL is small
2786 if (SyncRes::s_ecscachelimitttl > 0) {
2787 bool manyMaskBits = (ednsmask->isIpv4() && ednsmask->getBits() > SyncRes::s_ecsipv4cachelimit) ||
37e35fbc 2788 (ednsmask->isIPv6() && ednsmask->getBits() > SyncRes::s_ecsipv6cachelimit);
e7861cc4 2789
e7861cc4
OM
2790 if (manyMaskBits) {
2791 uint32_t minttl = UINT32_MAX;
2792 for (const auto &it : i->second.records) {
2793 if (it.d_ttl < minttl)
2794 minttl = it.d_ttl;
2795 }
2796 bool ttlIsSmall = minttl < SyncRes::s_ecscachelimitttl + d_now.tv_sec;
2797 if (ttlIsSmall) {
2798 // Case: many bits and ttlIsSmall
2799 doCache = false;
2800 }
e7861cc4 2801 }
ed9019c9 2802 }
e7861cc4
OM
2803 }
2804 if (doCache) {
2805 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 2806 }
005b4b98 2807 }
6dfff36f 2808
26ca3513
RG
2809 if(i->first.place == DNSResourceRecord::ANSWER && ednsmask)
2810 d_wasVariable=true;
2811 }
2812
2813 return RCode::NoError;
2814}
2815
28364e4b 2816void SyncRes::updateDenialValidationState(vState& neValidationState, const DNSName& neName, vState& state, const dState denialState, const dState expectedState, bool allowOptOut)
4d2be65d 2817{
b25712fd 2818 if (denialState == expectedState) {
28364e4b 2819 neValidationState = Secure;
b25712fd
RG
2820 }
2821 else {
142ab370 2822 if (denialState == OPTOUT && allowOptOut) {
28364e4b
RG
2823 LOG(d_prefix<<"OPT-out denial found for "<<neName<<endl);
2824 neValidationState = Secure;
142ab370 2825 return;
4d2be65d 2826 }
142ab370 2827 else if (denialState == INSECURE) {
28364e4b
RG
2828 LOG(d_prefix<<"Insecure denial found for "<<neName<<", returning Insecure"<<endl);
2829 neValidationState = Insecure;
4d2be65d 2830 }
142ab370 2831 else {
28364e4b
RG
2832 LOG(d_prefix<<"Invalid denial found for "<<neName<<", returning Bogus, res="<<denialState<<", expectedState="<<expectedState<<endl);
2833 neValidationState = Bogus;
142ab370 2834 }
28364e4b 2835 updateValidationState(state, neValidationState);
4d2be65d
RG
2836 }
2837}
2838
28364e4b 2839dState SyncRes::getDenialValidationState(const NegCache::NegCacheEntry& ne, const vState state, const dState expectedState, bool referralToUnsigned)
142ab370
RG
2840{
2841 cspmap_t csp = harvestCSPFromNE(ne);
2842 return getDenial(csp, ne.d_name, ne.d_qtype.getCode(), referralToUnsigned, expectedState == NXQTYPE);
2843}
2844
78cdf520 2845bool 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
2846{
2847 bool done = false;
123da0f8 2848 DNSName dnameTarget, dnameOwner;
ee936074 2849 uint32_t dnameTTL = 0;
26ca3513
RG
2850
2851 for(auto& rec : lwr.d_records) {
2852 if (rec.d_type!=QType::OPT && rec.d_class!=QClass::IN)
2853 continue;
2854
70ea0c65 2855 if (rec.d_place==DNSResourceRecord::ANSWER && !(lwr.d_aabit || sendRDQuery)) {
9870af40
RG
2856 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2857 are sending such responses */
2858 if (!(rec.d_type == QType::CNAME && rec.d_name == qname)) {
2859 continue;
2860 }
70ea0c65
RG
2861 }
2862
26ca3513
RG
2863 if(rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::SOA &&
2864 lwr.d_rcode==RCode::NXDomain && qname.isPartOf(rec.d_name) && rec.d_name.isPartOf(auth)) {
2865 LOG(prefix<<qname<<": got negative caching indication for name '"<<qname<<"' (accept="<<rec.d_name.isPartOf(auth)<<"), newtarget='"<<newtarget<<"'"<<endl);
2866
2867 rec.d_ttl = min(rec.d_ttl, s_maxnegttl);
2868 if(newtarget.empty()) // only add a SOA if we're not going anywhere after this
2869 ret.push_back(rec);
39ce10b2 2870
114829cc
RG
2871 NegCache::NegCacheEntry ne;
2872
dbbef467 2873 uint32_t lowestTTL = rec.d_ttl;
9b061cf5
RG
2874 /* if we get an NXDomain answer with a CNAME, the name
2875 does exist but the target does not */
2876 ne.d_name = newtarget.empty() ? qname : newtarget;
114829cc
RG
2877 ne.d_qtype = QType(0); // this encodes 'whole record'
2878 ne.d_auth = rec.d_name;
dbbef467 2879 harvestNXRecords(lwr.d_records, ne, d_now.tv_sec, &lowestTTL);
dbbef467 2880
142ab370
RG
2881 if (state == Secure) {
2882 dState denialState = getDenialValidationState(ne, state, NXDOMAIN, false);
28364e4b 2883 updateDenialValidationState(ne.d_validationState, ne.d_name, state, denialState, NXDOMAIN, false);
142ab370
RG
2884 }
2885 else {
2886 ne.d_validationState = state;
2887 }
114829cc 2888
b9473937
RG
2889 if (ne.d_validationState == Bogus) {
2890 lowestTTL = min(lowestTTL, s_maxbogusttl);
2891 }
2892
2893 ne.d_ttd = d_now.tv_sec + lowestTTL;
9b061cf5
RG
2894 /* if we get an NXDomain answer with a CNAME, let's not cache the
2895 target, even the server was authoritative for it,
2896 and do an additional query for the CNAME target.
2897 We have a regression test making sure we do exactly that.
2898 */
2899 if(!wasVariable() && newtarget.empty()) {
a712cb56 2900 t_sstorage.negcache.add(ne);
2ef32aec 2901 if(s_rootNXTrust && ne.d_auth.isRoot() && auth.isRoot() && lwr.d_aabit) {
9a1e060b 2902 ne.d_name = ne.d_name.getLastLabel();
a712cb56 2903 t_sstorage.negcache.add(ne);
26ca3513
RG
2904 }
2905 }
2906
2907 negindic=true;
2908 }
123da0f8
PL
2909 else if(rec.d_place==DNSResourceRecord::ANSWER && s_redirectionQTypes.count(rec.d_type) > 0 && // CNAME or DNAME answer
2910 s_redirectionQTypes.count(qtype.getCode()) == 0) { // But not in response to a CNAME or DNAME query
2911 if (rec.d_type == QType::CNAME && rec.d_name == qname) {
ee936074
PL
2912 if (!dnameOwner.empty()) { // We synthesize ourselves
2913 continue;
2914 }
123da0f8
PL
2915 ret.push_back(rec);
2916 if (auto content = getRR<CNAMERecordContent>(rec)) {
2917 newtarget=content->getTarget();
2918 }
2919 } else if (rec.d_type == QType::DNAME && qname.isPartOf(rec.d_name)) { // DNAME
2920 ret.push_back(rec);
2921 if (auto content = getRR<DNAMERecordContent>(rec)) {
2922 dnameOwner = rec.d_name;
2923 dnameTarget = content->getTarget();
ee936074 2924 dnameTTL = rec.d_ttl;
29ec25aa
PL
2925 if (!newtarget.empty()) { // We had a CNAME before, remove it from ret so we don't cache it
2926 ret.erase(std::remove_if(
2927 ret.begin(),
2928 ret.end(),
2929 [&qname](DNSRecord& rr) {
2930 return (rr.d_place == DNSResourceRecord::ANSWER && rr.d_type == QType::CNAME && rr.d_name == qname);
2931 }),
2932 ret.end());
2933 }
ee936074
PL
2934 try {
2935 newtarget = qname.makeRelative(dnameOwner) + dnameTarget;
2936 } catch (const std::exception &e) {
2937 // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
2938 // But there is no way to set the RCODE from this function
2939 throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + dnameOwner.toLogString() +
2940 "', DNAME target: '" + dnameTarget.toLogString() + "', substituted name: '" +
2941 qname.makeRelative(dnameOwner).toLogString() + "." + dnameTarget.toLogString() +
2942 "' : " + e.what());
2943 }
123da0f8 2944 }
26ca3513
RG
2945 }
2946 }
9b061cf5
RG
2947 /* if we have a positive answer synthetized from a wildcard, we need to
2948 return the corresponding NSEC/NSEC3 records from the AUTHORITY section
2949 proving that the exact name did not exist */
78cdf520 2950 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
2951 ret.push_back(rec); // enjoy your DNSSEC
2952 }
26ca3513
RG
2953 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
2954 else if(rec.d_place==DNSResourceRecord::ANSWER && rec.d_name == qname &&
2955 (
331222c4 2956 rec.d_type==qtype.getCode() || ((lwr.d_aabit || sendRDQuery) && qtype == QType(QType::ANY))
26ca3513
RG
2957 )
2958 )
2959 {
2960 LOG(prefix<<qname<<": answer is in: resolved to '"<< rec.d_content->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec.d_type)<<"'"<<endl);
2961
2962 done=true;
9b061cf5
RG
2963
2964 if (state == Secure && needWildcardProof) {
2965 /* We have a positive answer synthetized from a wildcard, we need to check that we have
2966 proof that the exact name doesn't exist so the wildcard can be used,
d0d39496 2967 as described in section 5.3.4 of RFC 4035 and 5.3 of RFC 7129.
9b061cf5
RG
2968 */
2969 NegCache::NegCacheEntry ne;
2970
2971 uint32_t lowestTTL = rec.d_ttl;
2972 ne.d_name = qname;
2973 ne.d_qtype = QType(0); // this encodes 'whole record'
2974 harvestNXRecords(lwr.d_records, ne, d_now.tv_sec, &lowestTTL);
2975
2976 cspmap_t csp = harvestCSPFromNE(ne);
e4894ce0 2977 dState res = getDenial(csp, qname, ne.d_qtype.getCode(), false, false, false, wildcardLabelsCount);
9b061cf5 2978 if (res != NXDOMAIN) {
b7c40613
RG
2979 vState st = Bogus;
2980 if (res == INSECURE) {
2981 /* Some part could not be validated, for example a NSEC3 record with a too large number of iterations,
2982 this is not enough to warrant a Bogus, but go Insecure. */
2983 st = Insecure;
2984 LOG(d_prefix<<"Unable to validate denial in wildcard expanded positive response found for "<<qname<<", returning Insecure, res="<<res<<endl);
2985 }
2986 else {
2987 LOG(d_prefix<<"Invalid denial in wildcard expanded positive response found for "<<qname<<", returning Bogus, res="<<res<<endl);
b9473937 2988 rec.d_ttl = std::min(rec.d_ttl, s_maxbogusttl);
b7c40613
RG
2989 }
2990
2991 updateValidationState(state, st);
2992 /* we already stored the record with a different validation status, let's fix it */
b9473937 2993 updateValidationStatusInCache(qname, qtype, lwr.d_aabit, st);
9b061cf5
RG
2994 }
2995 }
b9473937 2996 ret.push_back(rec);
26ca3513 2997 }
7030a59b 2998 else if((rec.d_type==QType::RRSIG || rec.d_type==QType::NSEC || rec.d_type==QType::NSEC3) && rec.d_place==DNSResourceRecord::ANSWER) {
123da0f8 2999 if(rec.d_type != QType::RRSIG || rec.d_name == qname) {
7030a59b 3000 ret.push_back(rec); // enjoy your DNSSEC
123da0f8
PL
3001 } else if(rec.d_type == QType::RRSIG && qname.isPartOf(rec.d_name)) {
3002 auto rrsig = getRR<RRSIGRecordContent>(rec);
3003 if (rrsig != nullptr && rrsig->d_type == QType::DNAME) {
3004 ret.push_back(rec);
3005 }
3006 }
7030a59b 3007 }
4d2be65d 3008 else if(rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::NS && qname.isPartOf(rec.d_name)) {
26ca3513
RG
3009 if(moreSpecificThan(rec.d_name,auth)) {
3010 newauth=rec.d_name;
3011 LOG(prefix<<qname<<": got NS record '"<<rec.d_name<<"' -> '"<<rec.d_content->getZoneRepresentation()<<"'"<<endl);
3012 realreferral=true;
3013 }
3014 else {
3015 LOG(prefix<<qname<<": got upwards/level NS record '"<<rec.d_name<<"' -> '"<<rec.d_content->getZoneRepresentation()<<"', had '"<<auth<<"'"<<endl);
3016 }
3017 if (auto content = getRR<NSRecordContent>(rec)) {
3018 nsset.insert(content->getNS());
3019 }
3020 }
4d2be65d 3021 else if(rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::DS && qname.isPartOf(rec.d_name)) {
26ca3513 3022 LOG(prefix<<qname<<": got DS record '"<<rec.d_name<<"' -> '"<<rec.d_content->getZoneRepresentation()<<"'"<<endl);
26ca3513 3023 }
860d5e8e 3024 else if(realreferral && rec.d_place==DNSResourceRecord::AUTHORITY && (rec.d_type==QType::NSEC || rec.d_type==QType::NSEC3) && newauth.isPartOf(auth)) {
4d2be65d
RG
3025 /* we might have received a denial of the DS, let's check */
3026 if (state == Secure) {
3027 NegCache::NegCacheEntry ne;
3028 ne.d_auth = auth;
860d5e8e
RG
3029 ne.d_name = newauth;
3030 ne.d_qtype = QType::DS;
dbbef467
RG
3031 rec.d_ttl = min(s_maxnegttl, rec.d_ttl);
3032 uint32_t lowestTTL = rec.d_ttl;
3033 harvestNXRecords(lwr.d_records, ne, d_now.tv_sec, &lowestTTL);
3034
142ab370
RG
3035 dState denialState = getDenialValidationState(ne, state, NXQTYPE, true);
3036
d377bb54 3037 if (denialState == NXQTYPE || denialState == OPTOUT || denialState == INSECURE) {
dbbef467 3038 ne.d_ttd = lowestTTL + d_now.tv_sec;
860d5e8e 3039 ne.d_validationState = Secure;
812c3a69 3040 LOG(prefix<<qname<<": got negative indication of DS record for '"<<newauth<<"'"<<endl);
5374b03b 3041
4d2be65d
RG
3042 if(!wasVariable()) {
3043 t_sstorage.negcache.add(ne);
3044 }
5374b03b
RG
3045
3046 if (qname == newauth && qtype == QType::DS) {
3047 /* we are actually done! */
3048 negindic=true;
3049 nsset.clear();
3050 }
4d2be65d
RG
3051 }
3052 }
3053 }
3054 else if(!done && rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::SOA &&
3055 lwr.d_rcode==RCode::NoError && qname.isPartOf(rec.d_name)) {
26ca3513
RG
3056 LOG(prefix<<qname<<": got negative caching indication for '"<< qname<<"|"<<qtype.getName()<<"'"<<endl);
3057
3058 if(!newtarget.empty()) {
3059 LOG(prefix<<qname<<": Hang on! Got a redirect to '"<<newtarget<<"' already"<<endl);
3060 }
3061 else {
3062 rec.d_ttl = min(s_maxnegttl, rec.d_ttl);
114829cc
RG
3063
3064 NegCache::NegCacheEntry ne;
3065 ne.d_auth = rec.d_name;
dbbef467 3066 uint32_t lowestTTL = rec.d_ttl;
114829cc
RG
3067 ne.d_name = qname;
3068 ne.d_qtype = qtype;
dbbef467 3069 harvestNXRecords(lwr.d_records, ne, d_now.tv_sec, &lowestTTL);
dbbef467 3070
142ab370
RG
3071 if (state == Secure) {
3072 dState denialState = getDenialValidationState(ne, state, NXQTYPE, false);
28364e4b 3073 updateDenialValidationState(ne.d_validationState, ne.d_name, state, denialState, NXQTYPE, qtype == QType::DS);
142ab370
RG
3074 } else {
3075 ne.d_validationState = state;
3076 }
114829cc 3077
b9473937
RG
3078 if (ne.d_validationState == Bogus) {
3079 lowestTTL = min(lowestTTL, s_maxbogusttl);
3080 rec.d_ttl = min(rec.d_ttl, s_maxbogusttl);
3081 }
3082 ne.d_ttd = d_now.tv_sec + lowestTTL;
3083
26ca3513 3084 if(!wasVariable()) {
26ca3513 3085 if(qtype.getCode()) { // prevents us from blacking out a whole domain
a712cb56 3086 t_sstorage.negcache.add(ne);
26ca3513
RG
3087 }
3088 }
b9473937
RG
3089
3090 ret.push_back(rec);
26ca3513
RG
3091 negindic=true;
3092 }
3093 }
3094 }
3095
ee936074
PL
3096 if (!dnameTarget.empty()) {
3097 // Synthesize a CNAME
3098 auto cnamerec = DNSRecord();
3099 cnamerec.d_name = qname;
3100 cnamerec.d_type = QType::CNAME;
3101 cnamerec.d_ttl = dnameTTL;
3102 cnamerec.d_content = std::make_shared<CNAMERecordContent>(CNAMERecordContent(newtarget));
3103 ret.push_back(cnamerec);
123da0f8 3104 }
26ca3513
RG
3105 return done;
3106}
3107
6dfff36f
RG
3108bool 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)
3109{
deca7d8f 3110 bool chained = false;
17cecc84 3111 int resolveret = RCode::NoError;
6dfff36f
RG
3112 s_outqueries++;
3113 d_outqueries++;
3114
3115 if(d_outqueries + d_throttledqueries > s_maxqperq) {
3116 throw ImmediateServFailException("more than "+std::to_string(s_maxqperq)+" (max-qperq) queries sent while resolving "+qname.toLogString());
3117 }
3118
3119 if(s_maxtotusec && d_totUsec > s_maxtotusec) {
3120 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");
3121 }
3122
3123 if(doTCP) {
3124 LOG(prefix<<qname<<": using TCP with "<< remoteIP.toStringWithPort() <<endl);
3125 s_tcpoutqueries++;
3126 d_tcpoutqueries++;
3127 }
3128
3129 if(d_pdl && d_pdl->preoutquery(remoteIP, d_requestor, qname, qtype, doTCP, lwr.d_records, resolveret)) {
3130 LOG(prefix<<qname<<": query handled by Lua"<<endl);
3131 }
3132 else {
2fe3354d 3133 ednsmask=getEDNSSubnetMask(qname, remoteIP);
6dfff36f
RG
3134 if(ednsmask) {
3135 LOG(prefix<<qname<<": Adding EDNS Client Subnet Mask "<<ednsmask->toString()<<" to query"<<endl);
d6923beb 3136 s_ecsqueries++;
6dfff36f 3137 }
6de48f75 3138 resolveret = asyncresolveWrapper(remoteIP, d_doDNSSEC, qname, auth, qtype.getCode(),
deca7d8f 3139 doTCP, sendRDQuery, &d_now, ednsmask, &lwr, &chained); // <- we go out on the wire!
6dfff36f 3140 if(ednsmask) {
d6923beb 3141 s_ecsresponses++;
6dfff36f 3142 LOG(prefix<<qname<<": Received EDNS Client Subnet Mask "<<ednsmask->toString()<<" on response"<<endl);
c9783016
RG
3143 if (ednsmask->getBits() > 0) {
3144 if (ednsmask->isIpv4()) {
3145 ++SyncRes::s_ecsResponsesBySubnetSize4.at(ednsmask->getBits()-1);
3146 }
3147 else {
3148 ++SyncRes::s_ecsResponsesBySubnetSize6.at(ednsmask->getBits()-1);
3149 }
3150 }
6dfff36f
RG
3151 }
3152 }
3153
3154 /* preoutquery killed the query by setting dq.rcode to -3 */
3155 if(resolveret==-3) {
3156 throw ImmediateServFailException("Query killed by policy");
3157 }
3158
3159 d_totUsec += lwr.d_usec;
3160 accountAuthLatency(lwr.d_usec, remoteIP.sin4.sin_family);
3161
5c8c72bf
PL
3162 bool dontThrottle = false;
3163 {
3164 auto dontThrottleNames = g_dontThrottleNames.getLocal();
3165 auto dontThrottleNetmasks = g_dontThrottleNetmasks.getLocal();
3166 dontThrottle = dontThrottleNames->check(nsName) || dontThrottleNetmasks->match(remoteIP);
3167 }
3168
6dfff36f
RG
3169 if(resolveret != 1) {
3170 /* Error while resolving */
3171 if(resolveret == 0) {
3172 /* Time out */
3173
3174 LOG(prefix<<qname<<": timeout resolving after "<<lwr.d_usec/1000.0<<"msec "<< (doTCP ? "over TCP" : "")<<endl);
3175 d_timeouts++;
3176 s_outgoingtimeouts++;
3177
3178 if(remoteIP.sin4.sin_family == AF_INET)
3179 s_outgoing4timeouts++;
3180 else
3181 s_outgoing6timeouts++;
be9078b3 3182
3183 if(t_timeouts)
3184 t_timeouts->push_back(remoteIP);
6dfff36f
RG
3185 }
3186 else if(resolveret == -2) {
3187 /* OS resource limit reached */
3188 LOG(prefix<<qname<<": hit a local resource limit resolving"<< (doTCP ? " over TCP" : "")<<", probable error: "<<stringerror()<<endl);
3189 g_stats.resourceLimits++;
3190 }
3191 else {
3192 /* -1 means server unreachable */
3193 s_unreachables++;
3194 d_unreachables++;
a702a96c
OM
3195 // XXX questionable use of errno
3196 LOG(prefix<<qname<<": error resolving from "<<remoteIP.toString()<< (doTCP ? " over TCP" : "") <<", possible error: "<<stringerror()<< endl);
6dfff36f
RG
3197 }
3198
5c8c72bf 3199 if(resolveret != -2 && !chained && !dontThrottle) {
559b6c93
PL
3200 // don't account for resource limits, they are our own fault
3201 // And don't throttle when the IP address is on the dontThrottleNetmasks list or the name is part of dontThrottleNames
589884b8 3202 t_sstorage.nsSpeeds[nsName.empty()? DNSName(remoteIP.toStringWithPort()) : nsName].submit(remoteIP, 1000000, &d_now); // 1 sec
6dfff36f
RG
3203
3204 // code below makes sure we don't filter COM or the root
60e5208a 3205 if (s_serverdownmaxfails > 0 && (auth != g_rootdnsname) && t_sstorage.fails.incr(remoteIP, d_now) >= s_serverdownmaxfails) {
6dfff36f
RG
3206 LOG(prefix<<qname<<": Max fails reached resolving on "<< remoteIP.toString() <<". Going full throttle for "<< s_serverdownthrottletime <<" seconds" <<endl);
3207 // mark server as down
3208 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, "", 0), s_serverdownthrottletime, 10000);
3209 }
3210 else if (resolveret == -1) {
3211 // unreachable, 1 minute or 100 queries
3212 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 60, 100);
3213 }
3214 else {
559b6c93 3215 // timeout, 10 seconds or 5 queries
6dfff36f
RG
3216 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 10, 5);
3217 }
3218 }
3219
3220 return false;
3221 }
3222
3223 /* we got an answer */
3224 if(lwr.d_rcode==RCode::ServFail || lwr.d_rcode==RCode::Refused) {
3225 LOG(prefix<<qname<<": "<<nsName<<" ("<<remoteIP.toString()<<") returned a "<< (lwr.d_rcode==RCode::ServFail ? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl);
5c8c72bf 3226 if (!chained && !dontThrottle) {
deca7d8f
RG
3227 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 60, 3);
3228 }
6dfff36f
RG
3229 return false;
3230 }
3231
3232 /* this server sent a valid answer, mark it backup up if it was down */
3233 if(s_serverdownmaxfails > 0) {
3234 t_sstorage.fails.clear(remoteIP);
3235 }
3236
3237 if(lwr.d_tcbit) {
3238 *truncated = true;
3239
4ab4187c 3240 if (doTCP) {
6dfff36f 3241 LOG(prefix<<qname<<": truncated bit set, over TCP?"<<endl);
4ab4187c
PD
3242 if (!dontThrottle) {
3243 /* let's treat that as a ServFail answer from this server */
3244 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 60, 3);
3245 }
6dfff36f
RG
3246 return false;
3247 }
b1f2295b 3248 LOG(prefix<<qname<<": truncated bit set, over UDP"<<endl);
6dfff36f
RG
3249
3250 return true;
3251 }
3252
3253 return true;
3254}
3255
51b6b728 3256bool 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
3257{
3258 string prefix;
3259 if(doLog()) {
3260 prefix=d_prefix;
3261 prefix.append(depth, ' ');
3262 }
3263
3264 if(s_minimumTTL) {
3265 for(auto& rec : lwr.d_records) {
3266 rec.d_ttl = max(rec.d_ttl, s_minimumTTL);
3267 }
3268 }
3269
5cf4b2e7
RG
3270 /* if the answer is ECS-specific, a minimum TTL is set for this kind of answers
3271 and it's higher than the global minimum TTL */
3272 if (ednsmask && s_minimumECSTTL > 0 && (s_minimumTTL == 0 || s_minimumECSTTL > s_minimumTTL)) {
3273 for(auto& rec : lwr.d_records) {
3274 if (rec.d_place == DNSResourceRecord::ANSWER) {
3275 rec.d_ttl = max(rec.d_ttl, s_minimumECSTTL);
3276 }
3277 }
3278 }
3279
2b984251 3280 bool needWildcardProof = false;
78cdf520 3281 bool gatherWildcardProof = false;
e4894ce0 3282 unsigned int wildcardLabelsCount;
78cdf520 3283 *rcode = updateCacheFromRecords(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, state, needWildcardProof, gatherWildcardProof, wildcardLabelsCount, sendRDQuery);
6dfff36f
RG
3284 if (*rcode != RCode::NoError) {
3285 return true;
3286 }
3287
3288 LOG(prefix<<qname<<": determining status after receiving this packet"<<endl);
3289
3290 set<DNSName> nsset;
3291 bool realreferral=false, negindic=false;
3292 DNSName newauth;
3293 DNSName newtarget;
3294
78cdf520 3295 bool done = processRecords(prefix, qname, qtype, auth, lwr, sendRDQuery, ret, nsset, newtarget, newauth, realreferral, negindic, state, needWildcardProof, gatherWildcardProof, wildcardLabelsCount);
6dfff36f
RG
3296
3297 if(done){
3298 LOG(prefix<<qname<<": status=got results, this level of recursion done"<<endl);
5374b03b 3299 LOG(prefix<<qname<<": validation status is "<<vStates[state]<<endl);
6dfff36f
RG
3300 *rcode = RCode::NoError;
3301 return true;
3302 }
3303
3304 if(!newtarget.empty()) {
3305 if(newtarget == qname) {
3306 LOG(prefix<<qname<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl);
3307 *rcode = RCode::ServFail;
3308 return true;
3309 }
3310
3311 if(depth > 10) {
3312 LOG(prefix<<qname<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl);
3313 *rcode = RCode::ServFail;
3314 return true;
3315 }
3316
5374b03b
RG
3317 if (qtype == QType::DS) {
3318 LOG(prefix<<qname<<": status=got a CNAME referral, but we are looking for a DS"<<endl);
6dfff36f 3319
1c39e884
RG
3320 if(d_doDNSSEC)
3321 addNXNSECS(ret, lwr.d_records);
3322
3323 *rcode = RCode::NoError;
3324 return true;
5374b03b
RG
3325 }
3326 else {
3327 LOG(prefix<<qname<<": status=got a CNAME referral, starting over with "<<newtarget<<endl);
6dfff36f 3328
5374b03b
RG
3329 set<GetBestNSAnswer> beenthere2;
3330 vState cnameState = Indeterminate;
3331 *rcode = doResolve(newtarget, qtype, ret, depth + 1, beenthere2, cnameState);
3332 LOG(prefix<<qname<<": updating validation state for response to "<<qname<<" from "<<vStates[state]<<" with the state from the CNAME quest: "<<vStates[cnameState]<<endl);
3333 updateValidationState(state, cnameState);
3334 return true;
3335 }
6dfff36f
RG
3336 }
3337
3338 if(lwr.d_rcode == RCode::NXDomain) {
3339 LOG(prefix<<qname<<": status=NXDOMAIN, we are done "<<(negindic ? "(have negative SOA)" : "")<<endl);
3340
3341 if(d_doDNSSEC)
3342 addNXNSECS(ret, lwr.d_records);
3343
3344 *rcode = RCode::NXDomain;
3345 return true;
3346 }
3347
3348 if(nsset.empty() && !lwr.d_rcode && (negindic || lwr.d_aabit || sendRDQuery)) {
3349 LOG(prefix<<qname<<": status=noerror, other types may exist, but we are done "<<(negindic ? "(have negative SOA) " : "")<<(lwr.d_aabit ? "(have aa bit) " : "")<<endl);
3350
6e9d3cae 3351 if(state == Secure && (lwr.d_aabit || sendRDQuery) && !negindic) {
114829cc
RG
3352 updateValidationState(state, Bogus);
3353 }
3354
6dfff36f
RG
3355 if(d_doDNSSEC)
3356 addNXNSECS(ret, lwr.d_records);
3357
3358 *rcode = RCode::NoError;
3359 return true;
3360 }
3361
3362 if(realreferral) {
3363 LOG(prefix<<qname<<": status=did not resolve, got "<<(unsigned int)nsset.size()<<" NS, ");
6dfff36f
RG
3364
3365 nameservers.clear();
3366 for (auto const &nameserver : nsset) {
3367 if (d_wantsRPZ) {
3368 d_appliedPolicy = dfe.getProcessingPolicy(nameserver, d_discardedPolicies);
3369 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
3370 LOG("however "<<nameserver<<" was blocked by RPZ policy '"<<(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")<<"'"<<endl);
3371 *rcode = -2;
3372 return true;
3373 }
3374 }
3375 nameservers.insert({nameserver, {{}, false}});
3376 }
3377 LOG("looping to them"<<endl);
3378 *gotNewServers = true;
812c3a69 3379 auth=newauth;
4d2be65d 3380
6dfff36f
RG
3381 return false;
3382 }
3383
3384 return false;
3385}
3386
b8470add
PL
3387/** returns:
3388 * -1 in case of no results
3389 * -2 when a FilterEngine Policy was hit
3390 * rcode otherwise
3391 */
fa1b87ff 3392int SyncRes::doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype,
e325f20c 3393 vector<DNSRecord>&ret,
116d1288 3394 unsigned int depth, set<GetBestNSAnswer>&beenthere, vState& state, StopAtDelegation* stopAtDelegation)
86c152f2 3395{
69cbdef9 3396 auto luaconfsLocal = g_luaconfs.getLocal();
ded77b10 3397 string prefix;
77499b05 3398 if(doLog()) {
ded77b10
BH
3399 prefix=d_prefix;
3400 prefix.append(depth, ' ');
3401 }
3ddb9247 3402
b8470add
PL
3403 LOG(prefix<<qname<<": Cache consultations done, have "<<(unsigned int)nameservers.size()<<" NS to contact");
3404
69cbdef9 3405 if (nameserversBlockedByRPZ(luaconfsLocal->dfe, nameservers)) {
26ca3513 3406 return -2;
b8470add
PL
3407 }
3408
3409 LOG(endl);
afbe2787
BH
3410
3411 for(;;) { // we may get more specific nameservers
feccaf7f 3412 auto rnameservers = shuffleInSpeedOrder(nameservers, doLog() ? (prefix+qname.toString()+": ") : string() );
3ddb9247 3413
26ca3513
RG
3414 for(auto tns=rnameservers.cbegin();;++tns) {
3415 if(tns==rnameservers.cend()) {
2189085d 3416 LOG(prefix<<qname<<": Failed to resolve via any of the "<<(unsigned int)rnameservers.size()<<" offered NS at level '"<<auth<<"'"<<endl);
03c09afe 3417 if(!auth.isRoot() && flawedNSSet) {
2189085d 3418 LOG(prefix<<qname<<": Ageing nameservers for level '"<<auth<<"', next query might succeed"<<endl);
88490c03 3419
49a699c4 3420 if(t_RC->doAgeCache(d_now.tv_sec, auth, QType::NS, 10))
4957a608
BH
3421 g_stats.nsSetInvalidations++;
3422 }
3423 return -1;
afbe2787 3424 }
6dfff36f 3425
b4c8789a
RG
3426 bool cacheOnly = false;
3427 // this line needs to identify the 'self-resolving' behaviour
feccaf7f 3428 if(qname == tns->first && (qtype.getCode() == QType::A || qtype.getCode() == QType::AAAA)) {
b4c8789a
RG
3429 /* we might have a glue entry in cache so let's try this NS
3430 but only if we have enough in the cache to know how to reach it */
3431 LOG(prefix<<qname<<": Using NS to resolve itself, but only using what we have in cache ("<<(1+tns-rnameservers.cbegin())<<"/"<<rnameservers.size()<<")"<<endl);
3432 cacheOnly = true;
20177d1d 3433 }
5605c067 3434
996c89cc 3435 typedef vector<ComboAddress> remoteIPs_t;
5605c067 3436 remoteIPs_t remoteIPs;
bfea0d0b 3437 remoteIPs_t::const_iterator remoteIP;
1c21f389 3438 bool pierceDontQuery=false;
c1d73d94 3439 bool sendRDQuery=false;
376effcf 3440 boost::optional<Netmask> ednsmask;
263f6a5a 3441 LWResult lwr;
feccaf7f 3442 const bool wasForwarded = tns->first.empty() && (!nameservers[tns->first].first.empty());
6dfff36f
RG
3443 int rcode = RCode::NoError;
3444 bool gotNewServers = false;
3445
feccaf7f 3446 if(tns->first.empty() && !wasForwarded) {
2189085d 3447 LOG(prefix<<qname<<": Domain is out-of-band"<<endl);
e1636f82
RG
3448 /* setting state to indeterminate since validation is disabled for local auth zone,
3449 and Insecure would be misleading. */
3450 state = Indeterminate;
9fc36e90 3451 d_wasOutOfBand = doOOBResolve(qname, qtype, lwr.d_records, depth, lwr.d_rcode);
4957a608
BH
3452 lwr.d_tcbit=false;
3453 lwr.d_aabit=true;
6dfff36f
RG
3454
3455 /* we have received an answer, are we done ? */
51b6b728 3456 bool done = processAnswer(depth, lwr, qname, qtype, auth, false, ednsmask, sendRDQuery, nameservers, ret, luaconfsLocal->dfe, &gotNewServers, &rcode, state);
6dfff36f
RG
3457 if (done) {
3458 return rcode;
3459 }
3460 if (gotNewServers) {
116d1288
OM
3461 if (stopAtDelegation && *stopAtDelegation == Stop) {
3462 *stopAtDelegation = Stopped;
3463 return rcode;
3464 }
6dfff36f
RG
3465 break;
3466 }
5605c067
BH
3467 }
3468 else {
6dfff36f 3469 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
b4c8789a 3470 remoteIPs = retrieveAddressesForNS(prefix, qname, tns, depth, beenthere, rnameservers, nameservers, sendRDQuery, pierceDontQuery, flawedNSSet, cacheOnly);
4957a608
BH
3471
3472 if(remoteIPs.empty()) {
feccaf7f 3473 LOG(prefix<<qname<<": Failed to get IP for NS "<<tns->first<<", trying next if available"<<endl);
4957a608
BH
3474 flawedNSSet=true;
3475 continue;
3476 }
3477 else {
b8470add 3478 bool hitPolicy{false};
feccaf7f 3479 LOG(prefix<<qname<<": Resolved '"<<auth<<"' NS "<<tns->first<<" to: ");
26ca3513
RG
3480 for(remoteIP = remoteIPs.cbegin(); remoteIP != remoteIPs.cend(); ++remoteIP) {
3481 if(remoteIP != remoteIPs.cbegin()) {
77499b05
BH
3482 LOG(", ");
3483 }
3484 LOG(remoteIP->toString());
69cbdef9 3485 if(nameserverIPBlockedByRPZ(luaconfsLocal->dfe, *remoteIP)) {
26ca3513 3486 hitPolicy = true;
b8470add 3487 }
4957a608 3488 }
77499b05 3489 LOG(endl);
b8470add
PL
3490 if (hitPolicy) //implies d_wantsRPZ
3491 return -2;
4957a608
BH
3492 }
3493
26ca3513 3494 for(remoteIP = remoteIPs.cbegin(); remoteIP != remoteIPs.cend(); ++remoteIP) {
2189085d 3495 LOG(prefix<<qname<<": Trying IP "<< remoteIP->toStringWithPort() <<", asking '"<<qname<<"|"<<qtype.getName()<<"'"<<endl);
6dfff36f 3496
26ca3513 3497 if (throttledOrBlocked(prefix, *remoteIP, qname, qtype, pierceDontQuery)) {
4957a608
BH
3498 continue;
3499 }
9de3e034 3500
6dfff36f
RG
3501 bool truncated = false;
3502 bool gotAnswer = doResolveAtThisIP(prefix, qname, qtype, lwr, ednsmask, auth, sendRDQuery,
feccaf7f 3503 tns->first, *remoteIP, false, &truncated);
6dfff36f
RG
3504 if (gotAnswer && truncated ) {
3505 /* retry, over TCP this time */
3506 gotAnswer = doResolveAtThisIP(prefix, qname, qtype, lwr, ednsmask, auth, sendRDQuery,
feccaf7f 3507 tns->first, *remoteIP, true, &truncated);
6dfff36f 3508 }
710af846 3509
6dfff36f
RG
3510 if (!gotAnswer) {
3511 continue;
3512 }
352b4183 3513
feccaf7f 3514 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 3515
6dfff36f
RG
3516 /* // for you IPv6 fanatics :-)
3517 if(remoteIP->sin4.sin_family==AF_INET6)
3518 lwr.d_usec/=3;
3519 */
3520 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
710af846 3521
feccaf7f 3522 t_sstorage.nsSpeeds[tns->first.empty()? DNSName(remoteIP->toStringWithPort()) : tns->first].submit(*remoteIP, lwr.d_usec, &d_now);
628e2c7b 3523
6dfff36f 3524 /* we have received an answer, are we done ? */
51b6b728 3525 bool done = processAnswer(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, sendRDQuery, nameservers, ret, luaconfsLocal->dfe, &gotNewServers, &rcode, state);
6dfff36f
RG
3526 if (done) {
3527 return rcode;
4957a608 3528 }
6dfff36f 3529 if (gotNewServers) {
116d1288
OM
3530 if (stopAtDelegation && *stopAtDelegation == Stop) {
3531 *stopAtDelegation = Stopped;
3532 return rcode;
3533 }
6dfff36f 3534 break;
4957a608 3535 }
6dfff36f
RG
3536 /* was lame */
3537 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100);
4957a608 3538 }
aadceba8 3539
6dfff36f
RG
3540 if (gotNewServers) {
3541 break;
4957a608 3542 }
620db2c8 3543
6dfff36f
RG
3544 if(remoteIP == remoteIPs.cend()) // we tried all IP addresses, none worked
3545 continue;
620db2c8 3546
86c152f2
BH
3547 }
3548 }
86c152f2 3549 }
ac539791 3550 return -1;
86c152f2
BH
3551}
3552
2fe3354d 3553void SyncRes::setQuerySource(const ComboAddress& requestor, boost::optional<const EDNSSubnetOpts&> incomingECS)
8a3a3822 3554{
2fe3354d
CH
3555 d_requestor = requestor;
3556
3557 if (incomingECS && incomingECS->source.getBits() > 0) {
3558 d_cacheRemote = incomingECS->source.getMaskedNetwork();
3559 uint8_t bits = std::min(incomingECS->source.getBits(), (incomingECS->source.isIpv4() ? s_ecsipv4limit : s_ecsipv6limit));
3560 ComboAddress trunc = incomingECS->source.getNetwork();
3561 trunc.truncate(bits);
3562 d_outgoingECSNetwork = boost::optional<Netmask>(Netmask(trunc, bits));
3563 } else {
3564 d_cacheRemote = d_requestor;
3565 if(!incomingECS && s_ednslocalsubnets.match(d_requestor)) {
3566 ComboAddress trunc = d_requestor;
3567 uint8_t bits = d_requestor.isIPv4() ? 32 : 128;
3568 bits = std::min(bits, (trunc.isIPv4() ? s_ecsipv4limit : s_ecsipv6limit));
3569 trunc.truncate(bits);
3570 d_outgoingECSNetwork = boost::optional<Netmask>(Netmask(trunc, bits));
3571 } else if (s_ecsScopeZero.source.getBits() > 0) {
8a3a3822
RG
3572 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0.
3573 But using an empty ECS in that case would mean inserting
3574 a non ECS-specific entry into the cache, preventing any further
3575 ECS-specific query to be sent.
3576 So instead we use the trick described in section 7.1.2:
3577 "The subsequent Recursive Resolver query to the Authoritative Nameserver
3578 will then either not include an ECS option or MAY optionally include
3579 its own address information, which is what the Authoritative
3580 Nameserver will almost certainly use to generate any Tailored
3581 Response in lieu of an option. This allows the answer to be handled
3582 by the same caching mechanism as other queries, with an explicit
3583 indicator of the applicable scope. Subsequent Stub Resolver queries
3584 for /0 can then be answered from this cached response.
3585 */
2fe3354d
CH
3586 d_outgoingECSNetwork = boost::optional<Netmask>(s_ecsScopeZero.source.getMaskedNetwork());
3587 d_cacheRemote = s_ecsScopeZero.source.getNetwork();
3588 } else {
3589 // ECS disabled because no scope-zero address could be derived.
3590 d_outgoingECSNetwork = boost::none;
8a3a3822
RG
3591 }
3592 }
8a3a3822
RG
3593}
3594
2fe3354d 3595boost::optional<Netmask> SyncRes::getEDNSSubnetMask(const DNSName& dn, const ComboAddress& rem)
e9f9b8ec 3596{
2fe3354d
CH
3597 if(d_outgoingECSNetwork && (s_ednsdomains.check(dn) || s_ednsremotesubnets.match(rem))) {
3598 return d_outgoingECSNetwork;
e9f9b8ec 3599 }
2fe3354d 3600 return boost::none;
e9f9b8ec 3601}
bd53ea9d 3602
9065eb05
RG
3603void SyncRes::parseEDNSSubnetWhitelist(const std::string& wlist)
3604{
3605 vector<string> parts;
3606 stringtok(parts, wlist, ",; ");
3607 for(const auto& a : parts) {
3608 try {
2fe3354d 3609 s_ednsremotesubnets.addMask(Netmask(a));
9065eb05
RG
3610 }
3611 catch(...) {
3612 s_ednsdomains.add(DNSName(a));
3613 }
3614 }
3615}
3616
2fe3354d
CH
3617void SyncRes::parseEDNSSubnetAddFor(const std::string& subnetlist)
3618{
3619 vector<string> parts;
3620 stringtok(parts, subnetlist, ",; ");
3621 for(const auto& a : parts) {
3622 s_ednslocalsubnets.addMask(a);
3623 }
3624}
3625
8ce79a22 3626// used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
a3e7b735 3627int directResolve(const DNSName& qname, const QType& qtype, int qclass, vector<DNSRecord>& ret)
bd53ea9d
PD
3628{
3629 struct timeval now;
3630 gettimeofday(&now, 0);
710af846 3631
bd53ea9d 3632 SyncRes sr(now);
13658071
RB
3633 int res = -1;
3634 try {
3635 res = sr.beginResolve(qname, QType(qtype), qclass, ret);
3636 }
3637 catch(const PDNSException& e) {
3638 g_log<<Logger::Error<<"Failed to resolve "<<qname.toLogString()<<", got pdns exception: "<<e.reason<<endl;
3639 ret.clear();
3640 }
3641 catch(const ImmediateServFailException& e) {
3642 g_log<<Logger::Error<<"Failed to resolve "<<qname.toLogString()<<", got ImmediateServFailException: "<<e.reason<<endl;
3643 ret.clear();
3644 }
3645 catch(const std::exception& e) {
3646 g_log<<Logger::Error<<"Failed to resolve "<<qname.toLogString()<<", got STL error: "<<e.what()<<endl;
3647 ret.clear();
3648 }
3649 catch(...) {
3650 g_log<<Logger::Error<<"Failed to resolve "<<qname.toLogString()<<", got an exception"<<endl;
3651 ret.clear();
3652 }
e325f20c 3653
bd53ea9d
PD
3654 return res;
3655}
30ee601a 3656
30ee601a
RG
3657int SyncRes::getRootNS(struct timeval now, asyncresolve_t asyncCallback) {
3658 SyncRes sr(now);
3659 sr.setDoEDNS0(true);
0b29b9c5 3660 sr.setUpdatingRootNS();
30ee601a 3661 sr.setDoDNSSEC(g_dnssecmode != DNSSECMode::Off);
0c43f455 3662 sr.setDNSSECValidationRequested(g_dnssecmode != DNSSECMode::Off && g_dnssecmode != DNSSECMode::ProcessNoValidate);
30ee601a
RG
3663 sr.setAsyncCallback(asyncCallback);
3664
3665 vector<DNSRecord> ret;
3666 int res=-1;
3667 try {
3668 res=sr.beginResolve(g_rootdnsname, QType(QType::NS), 1, ret);
3669 if (g_dnssecmode != DNSSECMode::Off && g_dnssecmode != DNSSECMode::ProcessNoValidate) {
4d2be65d 3670 auto state = sr.getValidationState();
30ee601a
RG
3671 if (state == Bogus)
3672 throw PDNSException("Got Bogus validation result for .|NS");
3673 }
3674 return res;
3675 }
c78ceb39 3676 catch(const PDNSException& e) {
e6a9dde5 3677 g_log<<Logger::Error<<"Failed to update . records, got an exception: "<<e.reason<<endl;
30ee601a 3678 }
c78ceb39 3679 catch(const ImmediateServFailException& e) {
e6a9dde5 3680 g_log<<Logger::Error<<"Failed to update . records, got an exception: "<<e.reason<<endl;
c78ceb39
RG
3681 }
3682 catch(const std::exception& e) {
e6a9dde5 3683 g_log<<Logger::Error<<"Failed to update . records, got an exception: "<<e.what()<<endl;
30ee601a 3684 }
c78ceb39 3685 catch(...) {
e6a9dde5 3686 g_log<<Logger::Error<<"Failed to update . records, got an exception"<<endl;
30ee601a 3687 }
c78ceb39 3688
30ee601a 3689 if(!res) {
e6a9dde5 3690 g_log<<Logger::Notice<<"Refreshed . records"<<endl;
30ee601a
RG
3691 }
3692 else
e6a9dde5 3693 g_log<<Logger::Error<<"Failed to update . records, RCODE="<<res<<endl;
c78ceb39 3694
30ee601a
RG
3695 return res;
3696}