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