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