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