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