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