]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/syncres.cc
doCNAMECacheCheck: Remove one level of indent
[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
adbd867b 1086 LOG(prefix<<qname<<": Looking for DNAME cache hit of '"<<qname<<"|DNAME' or its ancestors"<<endl);
d30b5493
PL
1087 do {
1088 dnameName.prependRawLabel(labels.back());
1089 labels.pop_back();
71e9cc53
PL
1090 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
1091 break;
1092 }
d30b5493 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
8d11c508
PL
1101 if (foundName.empty()) {
1102 LOG(prefix<<qname<<": No CNAME or DNAME cache hit of '"<< qname <<"' found"<<endl);
1103 return false;
1104 }
1105
1106 for(auto j=cset.cbegin() ; j != cset.cend() ; ++j) {
1107 if (j->d_class != QClass::IN) {
1108 continue;
1109 }
c5310862 1110
8d11c508
PL
1111 if(j->d_ttl>(unsigned int) d_now.tv_sec) {
1112
1113 if (!wasAuthZone && shouldValidate() && (wasAuth || wasForwardRecurse) && state == Indeterminate && d_requireAuthData) {
1114 /* This means we couldn't figure out the state when this entry was cached,
1115 most likely because we hadn't computed the zone cuts yet. */
1116 /* make sure they are computed before validating */
1117 DNSName subdomain(foundName);
1118 /* if we are retrieving a DS, we only care about the state of the parent zone */
1119 if(qtype == QType::DS)
1120 subdomain.chopOff();
1121
1122 computeZoneCuts(subdomain, g_rootdnsname, depth);
1123
1124 vState recordState = getValidationStatus(foundName, false);
1125 if (recordState == Secure) {
1126 LOG(prefix<<qname<<": got Indeterminate state from the "<<foundQT.getName()<<" cache, validating.."<<endl);
1127 state = SyncRes::validateRecordsWithSigs(depth, foundName, foundQT, foundName, cset, signatures);
1128 if (state != Indeterminate) {
1129 LOG(prefix<<qname<<": got Indeterminate state from the CNAME cache, new validation result is "<<vStates[state]<<endl);
1130 if (state == Bogus) {
1131 capTTL = s_maxbogusttl;
787737ae 1132 }
8d11c508 1133 updateValidationStatusInCache(foundName, foundQT, wasAuth, state);
787737ae 1134 }
428f41b7 1135 }
8d11c508 1136 }
428f41b7 1137
8d11c508 1138 LOG(prefix<<qname<<": Found cache "<<foundQT.getName()<<" hit for '"<< foundName << "|"<<foundQT.getName()<<"' to '"<<j->d_content->getZoneRepresentation()<<"', validation state is "<<vStates[state]<<endl);
1f77f479 1139
8d11c508
PL
1140 DNSRecord dr=*j;
1141 dr.d_ttl -= d_now.tv_sec;
1142 dr.d_ttl = std::min(dr.d_ttl, capTTL);
1143 const uint32_t ttl = dr.d_ttl;
1144 ret.reserve(ret.size() + 2 + signatures.size() + authorityRecs.size());
1145 ret.push_back(dr);
2b984251 1146
8d11c508
PL
1147 for(const auto& signature : signatures) {
1148 DNSRecord sigdr;
1149 sigdr.d_type=QType::RRSIG;
1150 sigdr.d_name=foundName;
1151 sigdr.d_ttl=ttl;
1152 sigdr.d_content=signature;
1153 sigdr.d_place=DNSResourceRecord::ANSWER;
1154 sigdr.d_class=QClass::IN;
1155 ret.push_back(sigdr);
1156 }
4d2be65d 1157
8d11c508
PL
1158 for(const auto& rec : authorityRecs) {
1159 DNSRecord authDR(*rec);
1160 authDR.d_ttl=ttl;
1161 ret.push_back(authDR);
1162 }
d30b5493 1163
8d11c508
PL
1164 DNSName newTarget;
1165 if (foundQT == QType::DNAME) {
1166 if (qtype == QType::DNAME && qname == foundName) { // client wanted the DNAME, no need to synthesize a CNAME
d30b5493
PL
1167 res = 0;
1168 return true;
1169 }
8d11c508
PL
1170 // Synthesize a CNAME
1171 auto dnameRR = getRR<DNAMERecordContent>(*j);
1172 if (dnameRR == nullptr) {
1173 throw ImmediateServFailException("Unable to get record content for "+foundName.toLogString()+"|DNAME cache entry");
1174 }
1175 const auto& dnameSuffix = dnameRR->getTarget();
1176 DNSName targetPrefix = qname.makeRelative(foundName);
1177 try {
1178 dr.d_type = QType::CNAME;
1179 dr.d_name = targetPrefix + foundName;
1180 newTarget = targetPrefix + dnameSuffix;
1181 dr.d_content = std::make_shared<CNAMERecordContent>(CNAMERecordContent(newTarget));
1182 ret.push_back(dr);
1183 } catch (const std::exception &e) {
1184 // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
1185 // But this is consistent with processRecords
1186 throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + foundName.toLogString() +
1187 "', DNAME target: '" + dnameSuffix.toLogString() + "', substituted name: '" +
1188 targetPrefix.toLogString() + "." + dnameSuffix.toLogString() +
1189 "' : " + e.what());
4957a608 1190 }
d30b5493 1191
8d11c508
PL
1192 LOG(prefix<<qname<<": Synthesized "<<dr.d_name<<"|CNAME "<<newTarget<<endl);
1193 }
4d2be65d 1194
8d11c508
PL
1195 if(qtype == QType::CNAME) { // perhaps they really wanted a CNAME!
1196 res = 0;
4957a608 1197 return true;
ac539791 1198 }
8d11c508
PL
1199
1200 // We have a DNAME _or_ CNAME cache hit and the client wants something else than those two.
1201 // Let's find the answer!
1202 if (foundQT == QType::CNAME) {
1203 const auto cnameContent = getRR<CNAMERecordContent>(*j);
1204 if (cnameContent == nullptr) {
1205 throw ImmediateServFailException("Unable to get record content for "+foundName.toLogString()+"|CNAME cache entry");
1206 }
1207 newTarget = cnameContent->getTarget();
1208 }
1209
1210 set<GetBestNSAnswer>beenthere;
1211 vState cnameState = Indeterminate;
1212 res = doResolve(newTarget, qtype, ret, depth+1, beenthere, cnameState);
1213 LOG(prefix<<qname<<": updating validation state for response to "<<qname<<" from "<<vStates[state]<<" with the state from the DNAME/CNAME quest: "<<vStates[cnameState]<<endl);
1214 updateValidationState(state, cnameState);
1215
1216 return true;
ac539791 1217 }
afbe2787 1218 }
8d11c508 1219 throw ImmediateServFailException("Could not determine whether or not there was a CNAME or DNAME in cache for '" + qname.toLogString() + "'");
75b49099
BH
1220}
1221
f984e703 1222namespace {
142ab370
RG
1223struct CacheEntry
1224{
1225 vector<DNSRecord> records;
1226 vector<shared_ptr<RRSIGRecordContent>> signatures;
1227 uint32_t signaturesTTL{std::numeric_limits<uint32_t>::max()};
1228};
1229struct CacheKey
1230{
1231 DNSName name;
1232 uint16_t type;
1233 DNSResourceRecord::Place place;
1234 bool operator<(const CacheKey& rhs) const {
186e99c9 1235 return tie(type, place, name) < tie(rhs.type, rhs.place, rhs.name);
142ab370
RG
1236 }
1237};
1238typedef map<CacheKey, CacheEntry> tcache_t;
f984e703 1239}
142ab370
RG
1240
1241static void reapRecordsFromNegCacheEntryForValidation(tcache_t& tcache, const vector<DNSRecord>& records)
1242{
1243 for (const auto& rec : records) {
1244 if (rec.d_type == QType::RRSIG) {
1245 auto rrsig = getRR<RRSIGRecordContent>(rec);
1246 if (rrsig) {
1247 tcache[{rec.d_name, rrsig->d_type, rec.d_place}].signatures.push_back(rrsig);
1248 }
1249 } else {
1250 tcache[{rec.d_name,rec.d_type,rec.d_place}].records.push_back(rec);
1251 }
1252 }
1253}
1254
6909b8c5
PL
1255/*!
1256 * Convience function to push the records from records into ret with a new TTL
1257 *
1258 * \param records DNSRecords that need to go into ret
1259 * \param ttl The new TTL for these records
1260 * \param ret The vector of DNSRecords that should contian the records with the modified TTL
1261 */
1262static void addTTLModifiedRecords(const vector<DNSRecord>& records, const uint32_t ttl, vector<DNSRecord>& ret) {
39ce10b2
PL
1263 for (const auto& rec : records) {
1264 DNSRecord r(rec);
1265 r.d_ttl = ttl;
1266 ret.push_back(r);
1267 }
1268}
1269
28364e4b 1270void SyncRes::computeNegCacheValidationStatus(const NegCache::NegCacheEntry* ne, const DNSName& qname, const QType& qtype, const int res, vState& state, unsigned int depth)
142ab370 1271{
f4de85a3
RG
1272 DNSName subdomain(qname);
1273 /* if we are retrieving a DS, we only care about the state of the parent zone */
1274 if(qtype == QType::DS)
1275 subdomain.chopOff();
1276
1277 computeZoneCuts(subdomain, g_rootdnsname, depth);
142ab370
RG
1278
1279 tcache_t tcache;
28364e4b
RG
1280 reapRecordsFromNegCacheEntryForValidation(tcache, ne->authoritySOA.records);
1281 reapRecordsFromNegCacheEntryForValidation(tcache, ne->authoritySOA.signatures);
1282 reapRecordsFromNegCacheEntryForValidation(tcache, ne->DNSSECRecords.records);
1283 reapRecordsFromNegCacheEntryForValidation(tcache, ne->DNSSECRecords.signatures);
142ab370
RG
1284
1285 for (const auto& entry : tcache) {
1286 // this happens when we did store signatures, but passed on the records themselves
1287 if (entry.second.records.empty()) {
1288 continue;
1289 }
1290
1291 const DNSName& owner = entry.first.name;
1292
1293 vState recordState = getValidationStatus(owner, false);
1294 if (state == Indeterminate) {
1295 state = recordState;
1296 }
1297
1298 if (recordState == Secure) {
f4de85a3
RG
1299 recordState = SyncRes::validateRecordsWithSigs(depth, qname, qtype, owner, entry.second.records, entry.second.signatures);
1300 }
142ab370 1301
f4de85a3
RG
1302 if (recordState != Indeterminate && recordState != state) {
1303 updateValidationState(state, recordState);
1304 if (state != Secure) {
1305 break;
142ab370
RG
1306 }
1307 }
1308 }
1309
1310 if (state == Secure) {
28364e4b 1311 vState neValidationState = ne->d_validationState;
142ab370 1312 dState expectedState = res == RCode::NXDomain ? NXDOMAIN : NXQTYPE;
28364e4b
RG
1313 dState denialState = getDenialValidationState(*ne, state, expectedState, false);
1314 updateDenialValidationState(neValidationState, ne->d_name, state, denialState, expectedState, qtype == QType::DS);
142ab370
RG
1315 }
1316 if (state != Indeterminate) {
1317 /* validation succeeded, let's update the cache entry so we don't have to validate again */
b9473937
RG
1318 boost::optional<uint32_t> capTTD = boost::none;
1319 if (state == Bogus) {
1320 capTTD = d_now.tv_sec + s_maxbogusttl;
1321 }
1322 t_sstorage.negcache.updateValidationStatus(ne->d_name, ne->d_qtype, state, capTTD);
142ab370
RG
1323 }
1324}
e325f20c 1325
ad797d94 1326bool 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 1327{
fd8bc993 1328 bool giveNegative=false;
710af846 1329
be718669 1330 string prefix;
77499b05 1331 if(doLog()) {
ded77b10
BH
1332 prefix=d_prefix;
1333 prefix.append(depth, ' ');
1334 }
afbe2787 1335
30e9bd93 1336 // 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 1337 DNSName sqname(qname);
288f4aa9 1338 QType sqt(qtype);
092f210a 1339 uint32_t sttl=0;
2189085d 1340 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
4d2be65d 1341 vState cachedState;
28364e4b 1342 const NegCache::NegCacheEntry* ne = nullptr;
64a8b6a1 1343
710af846 1344 if(s_rootNXTrust &&
28364e4b
RG
1345 t_sstorage.negcache.getRootNXTrust(qname, d_now, &ne) &&
1346 ne->d_auth.isRoot() &&
e1636f82 1347 !(wasForwardedOrAuthZone && !authname.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
28364e4b
RG
1348 sttl = ne->d_ttd - d_now.tv_sec;
1349 LOG(prefix<<qname<<": Entire name '"<<qname<<"', is negatively cached via '"<<ne->d_auth<<"' & '"<<ne->d_name<<"' for another "<<sttl<<" seconds"<<endl);
3ddb9247 1350 res = RCode::NXDomain;
39ce10b2 1351 giveNegative = true;
28364e4b 1352 cachedState = ne->d_validationState;
01402d56 1353 }
ba40d3d7 1354 else if (t_sstorage.negcache.get(qname, qtype, d_now, &ne)) {
b0c164a2
RG
1355 /* If we are looking for a DS, discard NXD if auth == qname
1356 and ask for a specific denial instead */
28364e4b
RG
1357 if (qtype != QType::DS || ne->d_qtype.getCode() || ne->d_auth != qname ||
1358 t_sstorage.negcache.get(qname, qtype, d_now, &ne, true))
b0c164a2
RG
1359 {
1360 res = 0;
28364e4b 1361 sttl = ne->d_ttd - d_now.tv_sec;
b0c164a2 1362 giveNegative = true;
28364e4b
RG
1363 cachedState = ne->d_validationState;
1364 if(ne->d_qtype.getCode()) {
1365 LOG(prefix<<qname<<": "<<qtype.getName()<<" is negatively cached via '"<<ne->d_auth<<"' for another "<<sttl<<" seconds"<<endl);
b0c164a2
RG
1366 res = RCode::NoError;
1367 }
1368 else {
28364e4b 1369 LOG(prefix<<qname<<": Entire name '"<<qname<<"', is negatively cached via '"<<ne->d_auth<<"' for another "<<sttl<<" seconds"<<endl);
b0c164a2
RG
1370 res = RCode::NXDomain;
1371 }
39ce10b2 1372 }
39ce10b2
PL
1373 }
1374
1375 if (giveNegative) {
142ab370
RG
1376
1377 state = cachedState;
1378
e1636f82 1379 if (!wasAuthZone && shouldValidate() && state == Indeterminate) {
142ab370
RG
1380 LOG(prefix<<qname<<": got Indeterminate state for records retrieved from the negative cache, validating.."<<endl);
1381 computeNegCacheValidationStatus(ne, qname, qtype, res, state, depth);
b9473937
RG
1382
1383 if (state != cachedState && state == Bogus) {
1384 sttl = std::min(sttl, s_maxbogusttl);
1385 }
142ab370
RG
1386 }
1387
39ce10b2 1388 // Transplant SOA to the returned packet
28364e4b 1389 addTTLModifiedRecords(ne->authoritySOA.records, sttl, ret);
4d00b38b 1390 if(d_doDNSSEC) {
28364e4b
RG
1391 addTTLModifiedRecords(ne->authoritySOA.signatures, sttl, ret);
1392 addTTLModifiedRecords(ne->DNSSECRecords.records, sttl, ret);
1393 addTTLModifiedRecords(ne->DNSSECRecords.signatures, sttl, ret);
4d00b38b 1394 }
4d2be65d 1395
142ab370 1396 LOG(prefix<<qname<<": updating validation state with negative cache content for "<<qname<<" to "<<vStates[state]<<endl);
39ce10b2 1397 return true;
fd8bc993 1398 }
39ce10b2 1399
e325f20c 1400 vector<DNSRecord> cset;
75b49099 1401 bool found=false, expired=false;
57769f13 1402 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
2b984251 1403 vector<std::shared_ptr<DNSRecord>> authorityRecs;
57769f13 1404 uint32_t ttl=0;
b9473937 1405 uint32_t capTTL = std::numeric_limits<uint32_t>::max();
428f41b7 1406 bool wasCachedAuth;
ad797d94 1407 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 1408
2189085d 1409 LOG(prefix<<sqname<<": Found cache hit for "<<sqt.getName()<<": ");
428f41b7 1410
dff3ef07 1411 if (!wasAuthZone && shouldValidate() && (wasCachedAuth || wasForwardRecurse) && cachedState == Indeterminate && d_requireAuthData) {
428f41b7
RG
1412
1413 /* This means we couldn't figure out the state when this entry was cached,
1414 most likely because we hadn't computed the zone cuts yet. */
aa30ad7e 1415 /* make sure they are computed before validating */
f4de85a3
RG
1416 DNSName subdomain(sqname);
1417 /* if we are retrieving a DS, we only care about the state of the parent zone */
1418 if(qtype == QType::DS)
1419 subdomain.chopOff();
1420
1421 computeZoneCuts(subdomain, g_rootdnsname, depth);
aa30ad7e 1422
142ab370 1423 vState recordState = getValidationStatus(qname, false);
787737ae
RG
1424 if (recordState == Secure) {
1425 LOG(prefix<<sqname<<": got Indeterminate state from the cache, validating.."<<endl);
1426 cachedState = SyncRes::validateRecordsWithSigs(depth, sqname, sqt, sqname, cset, signatures);
f4de85a3
RG
1427 }
1428 else {
1429 cachedState = recordState;
1430 }
787737ae 1431
f4de85a3
RG
1432 if (cachedState != Indeterminate) {
1433 LOG(prefix<<qname<<": got Indeterminate state from the cache, validation result is "<<vStates[cachedState]<<endl);
b9473937
RG
1434 if (cachedState == Bogus) {
1435 capTTL = s_maxbogusttl;
1436 }
1437 updateValidationStatusInCache(sqname, sqt, wasCachedAuth, cachedState);
787737ae 1438 }
428f41b7
RG
1439 }
1440
e325f20c 1441 for(auto j=cset.cbegin() ; j != cset.cend() ; ++j) {
c5310862 1442
e325f20c 1443 LOG(j->d_content->getZoneRepresentation());
c5310862
RG
1444
1445 if (j->d_class != QClass::IN) {
1446 continue;
1447 }
1448
e325f20c 1449 if(j->d_ttl>(unsigned int) d_now.tv_sec) {
1450 DNSRecord dr=*j;
b9473937
RG
1451 dr.d_ttl -= d_now.tv_sec;
1452 dr.d_ttl = std::min(dr.d_ttl, capTTL);
1453 ttl = dr.d_ttl;
e325f20c 1454 ret.push_back(dr);
1455 LOG("[ttl="<<dr.d_ttl<<"] ");
4957a608 1456 found=true;
ac539791 1457 }
75b49099 1458 else {
77499b05 1459 LOG("[expired] ");
4957a608 1460 expired=true;
75b49099 1461 }
afbe2787 1462 }
57769f13 1463
f128d20d
RG
1464 ret.reserve(ret.size() + signatures.size() + authorityRecs.size());
1465
57769f13 1466 for(const auto& signature : signatures) {
e325f20c 1467 DNSRecord dr;
1468 dr.d_type=QType::RRSIG;
1469 dr.d_name=sqname;
1470 dr.d_ttl=ttl;
1471 dr.d_content=signature;
39ce10b2 1472 dr.d_place = DNSResourceRecord::ANSWER;
4d2be65d 1473 dr.d_class=QClass::IN;
e325f20c 1474 ret.push_back(dr);
57769f13 1475 }
2b984251
RG
1476
1477 for(const auto& rec : authorityRecs) {
1478 DNSRecord dr(*rec);
1479 dr.d_ttl=ttl;
1480 ret.push_back(dr);
1481 }
1482
77499b05 1483 LOG(endl);
f4df5e89 1484 if(found && !expired) {
4d2be65d 1485 if (!giveNegative)
4957a608 1486 res=0;
bcb05770 1487 LOG(prefix<<qname<<": updating validation state with cache content for "<<qname<<" to "<<vStates[cachedState]<<endl);
4d2be65d 1488 state = cachedState;
75b49099 1489 return true;
f4df5e89 1490 }
75b49099 1491 else
2189085d 1492 LOG(prefix<<qname<<": cache had only stale entries"<<endl);
afbe2787 1493 }
f4df5e89 1494
75b49099
BH
1495 return false;
1496}
afbe2787 1497
69cbdef9 1498bool SyncRes::moreSpecificThan(const DNSName& a, const DNSName &b) const
75b49099 1499{
6a1010f7 1500 return (a.isPartOf(b) && a.countLabels() > b.countLabels());
afbe2787
BH
1501}
1502
d8d0bb8f 1503struct speedOrder
eefd15f9 1504{
feccaf7f 1505 bool operator()(const std::pair<DNSName, double> &a, const std::pair<DNSName, double> &b) const
c3d9d009 1506 {
feccaf7f 1507 return a.second < b.second;
c3d9d009 1508 }
c3d9d009
BH
1509};
1510
feccaf7f 1511inline std::vector<std::pair<DNSName, double>> SyncRes::shuffleInSpeedOrder(NsSet &tnameservers, const string &prefix)
afbe2787 1512{
feccaf7f 1513 std::vector<std::pair<DNSName, double>> rnameservers;
5ea6f7de 1514 rnameservers.reserve(tnameservers.size());
a2d65f83 1515 for(const auto& tns: tnameservers) {
feccaf7f
RG
1516 double speed = t_sstorage.nsSpeeds[tns.first].get(&d_now);
1517 rnameservers.push_back({tns.first, speed});
a2d65f83 1518 if(tns.first.empty()) // this was an authoritative OOB zone, don't pollute the nsSpeeds with that
1519 return rnameservers;
21f0f88b 1520 }
461df9d2 1521
feccaf7f
RG
1522 random_shuffle(rnameservers.begin(),rnameservers.end());
1523 speedOrder so;
996c89cc 1524 stable_sort(rnameservers.begin(),rnameservers.end(), so);
710af846 1525
77499b05
BH
1526 if(doLog()) {
1527 LOG(prefix<<"Nameservers: ");
feccaf7f
RG
1528 for(auto i=rnameservers.begin();i!=rnameservers.end();++i) {
1529 if(i!=rnameservers.begin()) {
77499b05
BH
1530 LOG(", ");
1531 if(!((i-rnameservers.begin())%3)) {
1532 LOG(endl<<prefix<<" ");
1533 }
d8d0bb8f 1534 }
feccaf7f 1535 LOG(i->first.toLogString()<<"(" << (boost::format("%0.2f") % (i->second/1000.0)).str() <<"ms)");
d8d0bb8f 1536 }
77499b05 1537 LOG(endl);
d8d0bb8f 1538 }
728485ca 1539 return rnameservers;
afbe2787
BH
1540}
1541
cc11d7f4 1542inline vector<ComboAddress> SyncRes::shuffleForwardSpeed(const vector<ComboAddress> &rnameservers, const string &prefix, const bool wasRd)
589884b8 1543{
cc11d7f4 1544 vector<ComboAddress> nameservers = rnameservers;
6ed0c28a 1545 map<ComboAddress, double> speeds;
589884b8 1546
cc11d7f4 1547 for(const auto& val: nameservers) {
589884b8 1548 double speed;
6ed0c28a 1549 DNSName nsName = DNSName(val.toStringWithPort());
1550 speed=t_sstorage.nsSpeeds[nsName].get(&d_now);
589884b8 1551 speeds[val]=speed;
1552 }
feccaf7f 1553 random_shuffle(nameservers.begin(),nameservers.end());
6ed0c28a 1554 speedOrderCA so(speeds);
cc11d7f4 1555 stable_sort(nameservers.begin(),nameservers.end(), so);
589884b8 1556
589884b8 1557 if(doLog()) {
1558 LOG(prefix<<"Nameservers: ");
cc11d7f4 1559 for(vector<ComboAddress>::const_iterator i=nameservers.cbegin();i!=nameservers.cend();++i) {
1560 if(i!=nameservers.cbegin()) {
589884b8 1561 LOG(", ");
cc11d7f4 1562 if(!((i-nameservers.cbegin())%3)) {
589884b8 1563 LOG(endl<<prefix<<" ");
1564 }
1565 }
6ed0c28a 1566 LOG((wasRd ? string("+") : string("-")) << i->toStringWithPort() <<"(" << (boost::format("%0.2f") % (speeds[*i]/1000.0)).str() <<"ms)");
589884b8 1567 }
1568 LOG(endl);
1569 }
cc11d7f4 1570 return nameservers;
589884b8 1571}
1572
dbbef467
RG
1573static uint32_t getRRSIGTTL(const time_t now, const std::shared_ptr<RRSIGRecordContent>& rrsig)
1574{
1575 uint32_t res = 0;
1576 if (now < rrsig->d_sigexpire) {
1577 res = static_cast<uint32_t>(rrsig->d_sigexpire) - now;
1578 }
1579 return res;
1580}
1581
2b984251
RG
1582static const set<uint16_t> nsecTypes = {QType::NSEC, QType::NSEC3};
1583
39ce10b2
PL
1584/* Fills the authoritySOA and DNSSECRecords fields from ne with those found in the records
1585 *
1586 * \param records The records to parse for the authority SOA and NSEC(3) records
1587 * \param ne The NegCacheEntry to be filled out (will not be cleared, only appended to
1588 */
dbbef467 1589static void harvestNXRecords(const vector<DNSRecord>& records, NegCache::NegCacheEntry& ne, const time_t now, uint32_t* lowestTTL) {
620db2c8 1590 for(const auto& rec : records) {
39ce10b2
PL
1591 if(rec.d_place != DNSResourceRecord::AUTHORITY)
1592 // RFC 4035 section 3.1.3. indicates that NSEC records MUST be placed in
1593 // the AUTHORITY section. Section 3.1.1 indicates that that RRSIGs for
1594 // records MUST be in the same section as the records they cover.
1595 // Hence, we ignore all records outside of the AUTHORITY section.
1596 continue;
1597
620db2c8 1598 if(rec.d_type == QType::RRSIG) {
39ce10b2
PL
1599 auto rrsig = getRR<RRSIGRecordContent>(rec);
1600 if(rrsig) {
1601 if(rrsig->d_type == QType::SOA) {
1602 ne.authoritySOA.signatures.push_back(rec);
dbbef467
RG
1603 if (lowestTTL && isRRSIGNotExpired(now, rrsig)) {
1604 *lowestTTL = min(*lowestTTL, rec.d_ttl);
1605 *lowestTTL = min(*lowestTTL, getRRSIGTTL(now, rrsig));
1606 }
39ce10b2
PL
1607 }
1608 if(nsecTypes.count(rrsig->d_type)) {
1609 ne.DNSSECRecords.signatures.push_back(rec);
dbbef467
RG
1610 if (lowestTTL && isRRSIGNotExpired(now, rrsig)) {
1611 *lowestTTL = min(*lowestTTL, rec.d_ttl);
1612 *lowestTTL = min(*lowestTTL, getRRSIGTTL(now, rrsig));
1613 }
39ce10b2
PL
1614 }
1615 }
1616 continue;
1617 }
1618 if(rec.d_type == QType::SOA) {
1619 ne.authoritySOA.records.push_back(rec);
dbbef467
RG
1620 if (lowestTTL) {
1621 *lowestTTL = min(*lowestTTL, rec.d_ttl);
1622 }
39ce10b2
PL
1623 continue;
1624 }
1625 if(nsecTypes.count(rec.d_type)) {
1626 ne.DNSSECRecords.records.push_back(rec);
dbbef467
RG
1627 if (lowestTTL) {
1628 *lowestTTL = min(*lowestTTL, rec.d_ttl);
1629 }
39ce10b2 1630 continue;
620db2c8 1631 }
620db2c8 1632 }
620db2c8 1633}
1634
4d2be65d
RG
1635static cspmap_t harvestCSPFromNE(const NegCache::NegCacheEntry& ne)
1636{
1637 cspmap_t cspmap;
1638 for(const auto& rec : ne.DNSSECRecords.signatures) {
1639 if(rec.d_type == QType::RRSIG) {
1640 auto rrc = getRR<RRSIGRecordContent>(rec);
1641 if (rrc) {
1642 cspmap[{rec.d_name,rrc->d_type}].signatures.push_back(rrc);
1643 }
1644 }
1645 }
1646 for(const auto& rec : ne.DNSSECRecords.records) {
1647 cspmap[{rec.d_name, rec.d_type}].records.push_back(rec.d_content);
1648 }
1649 return cspmap;
1650}
1651
39ce10b2
PL
1652// TODO remove after processRecords is fixed!
1653// Adds the RRSIG for the SOA and the NSEC(3) + RRSIGs to ret
620db2c8 1654static void addNXNSECS(vector<DNSRecord>&ret, const vector<DNSRecord>& records)
1655{
39ce10b2 1656 NegCache::NegCacheEntry ne;
dbbef467 1657 harvestNXRecords(records, ne, 0, nullptr);
39ce10b2
PL
1658 ret.insert(ret.end(), ne.authoritySOA.signatures.begin(), ne.authoritySOA.signatures.end());
1659 ret.insert(ret.end(), ne.DNSSECRecords.records.begin(), ne.DNSSECRecords.records.end());
1660 ret.insert(ret.end(), ne.DNSSECRecords.signatures.begin(), ne.DNSSECRecords.signatures.end());
620db2c8 1661}
1662
69cbdef9 1663bool SyncRes::nameserversBlockedByRPZ(const DNSFilterEngine& dfe, const NsSet& nameservers)
26ca3513
RG
1664{
1665 if(d_wantsRPZ) {
1666 for (auto const &ns : nameservers) {
69cbdef9 1667 d_appliedPolicy = dfe.getProcessingPolicy(ns.first, d_discardedPolicies);
26ca3513
RG
1668 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
1669 LOG(", however nameserver "<<ns.first<<" was blocked by RPZ policy '"<<(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")<<"'"<<endl);
1670 return true;
1671 }
1672
1673 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
1674 for (auto const &address : ns.second.first) {
69cbdef9 1675 d_appliedPolicy = dfe.getProcessingPolicy(address, d_discardedPolicies);
26ca3513
RG
1676 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
1677 LOG(", however nameserver "<<ns.first<<" IP address "<<address.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")<<"'"<<endl);
1678 return true;
1679 }
1680 }
1681 }
1682 }
1683 return false;
1684}
1685
69cbdef9 1686bool SyncRes::nameserverIPBlockedByRPZ(const DNSFilterEngine& dfe, const ComboAddress& remoteIP)
26ca3513
RG
1687{
1688 if (d_wantsRPZ) {
69cbdef9 1689 d_appliedPolicy = dfe.getProcessingPolicy(remoteIP, d_discardedPolicies);
26ca3513
RG
1690 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) {
1691 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")+"')");
1692 return true;
1693 }
1694 }
1695 return false;
1696}
1697
feccaf7f 1698vector<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
1699{
1700 vector<ComboAddress> result;
1701
feccaf7f
RG
1702 if(!tns->first.empty()) {
1703 LOG(prefix<<qname<<": Trying to resolve NS '"<<tns->first<< "' ("<<1+tns-rnameservers.begin()<<"/"<<(unsigned int)rnameservers.size()<<")"<<endl);
1704 result = getAddrs(tns->first, depth+2, beenthere, cacheOnly);
26ca3513
RG
1705 pierceDontQuery=false;
1706 }
1707 else {
1708 LOG(prefix<<qname<<": Domain has hardcoded nameserver");
1709
feccaf7f 1710 if(nameservers[tns->first].first.size() > 1) {
26ca3513
RG
1711 LOG("s");
1712 }
1713 LOG(endl);
1714
feccaf7f
RG
1715 sendRDQuery = nameservers[tns->first].second;
1716 result = shuffleForwardSpeed(nameservers[tns->first].first, doLog() ? (prefix+qname.toString()+": ") : string(), sendRDQuery);
26ca3513
RG
1717 pierceDontQuery=true;
1718 }
1719 return result;
1720}
1721
1722bool SyncRes::throttledOrBlocked(const std::string& prefix, const ComboAddress& remoteIP, const DNSName& qname, const QType& qtype, bool pierceDontQuery)
1723{
a712cb56 1724 if(t_sstorage.throttle.shouldThrottle(d_now.tv_sec, boost::make_tuple(remoteIP, "", 0))) {
26ca3513
RG
1725 LOG(prefix<<qname<<": server throttled "<<endl);
1726 s_throttledqueries++; d_throttledqueries++;
1727 return true;
1728 }
a712cb56 1729 else if(t_sstorage.throttle.shouldThrottle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()))) {
6dfff36f 1730 LOG(prefix<<qname<<": query throttled "<<remoteIP.toString()<<", "<<qname<<"; "<<qtype.getName()<<endl);
26ca3513
RG
1731 s_throttledqueries++; d_throttledqueries++;
1732 return true;
1733 }
9065eb05 1734 else if(!pierceDontQuery && s_dontQuery && s_dontQuery->match(&remoteIP)) {
26ca3513
RG
1735 LOG(prefix<<qname<<": not sending query to " << remoteIP.toString() << ", blocked by 'dont-query' setting" << endl);
1736 s_dontqueries++;
1737 return true;
1738 }
1739 return false;
1740}
1741
4d2be65d
RG
1742bool SyncRes::validationEnabled() const
1743{
8455425c 1744 return g_dnssecmode != DNSSECMode::Off && g_dnssecmode != DNSSECMode::ProcessNoValidate;
4d2be65d
RG
1745}
1746
1747uint32_t SyncRes::computeLowestTTD(const std::vector<DNSRecord>& records, const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures, uint32_t signaturesTTL) const
26ca3513 1748{
4d2be65d
RG
1749 uint32_t lowestTTD = std::numeric_limits<uint32_t>::max();
1750 for(const auto& record : records)
1751 lowestTTD = min(lowestTTD, record.d_ttl);
1752
0c43f455
RG
1753 /* even if it was not requested for that request (Process, and neither AD nor DO set),
1754 it might be requested at a later time so we need to be careful with the TTL. */
4d2be65d 1755 if (validationEnabled() && !signatures.empty()) {
3cef03e9 1756 /* if we are validating, we don't want to cache records after their signatures expire. */
4d2be65d
RG
1757 /* records TTL are now TTD, let's add 'now' to the signatures lowest TTL */
1758 lowestTTD = min(lowestTTD, static_cast<uint32_t>(signaturesTTL + d_now.tv_sec));
1759
1760 for(const auto& sig : signatures) {
dbbef467
RG
1761 if (isRRSIGNotExpired(d_now.tv_sec, sig)) {
1762 // we don't decerement d_sigexpire by 'now' because we actually want a TTD, not a TTL */
4d2be65d
RG
1763 lowestTTD = min(lowestTTD, static_cast<uint32_t>(sig->d_sigexpire));
1764 }
1765 }
1766 }
1767
1768 return lowestTTD;
1769}
1770
1771void SyncRes::updateValidationState(vState& state, const vState stateUpdate)
1772{
f715542c 1773 LOG(d_prefix<<"validation state was "<<std::string(vStates[state])<<", state update is "<<std::string(vStates[stateUpdate]));
4d2be65d 1774
895449a5
RG
1775 if (stateUpdate == TA) {
1776 state = Secure;
4d2be65d
RG
1777 }
1778 else if (stateUpdate == NTA) {
1779 state = Insecure;
1780 }
895449a5
RG
1781 else if (stateUpdate == Bogus) {
1782 state = Bogus;
1783 }
1784 else if (state == Indeterminate) {
1785 state = stateUpdate;
1786 }
4d2be65d
RG
1787 else if (stateUpdate == Insecure) {
1788 if (state != Bogus) {
1789 state = Insecure;
1790 }
1791 }
f715542c 1792 LOG(", validation state is now "<<std::string(vStates[state])<<endl);
4d2be65d
RG
1793}
1794
1795vState SyncRes::getTA(const DNSName& zone, dsmap_t& ds)
1796{
1797 auto luaLocal = g_luaconfs.getLocal();
1798
1799 if (luaLocal->dsAnchors.empty()) {
e77f01d1 1800 LOG(d_prefix<<": No trust anchors configured, everything is Insecure"<<endl);
4d2be65d
RG
1801 /* We have no TA, everything is insecure */
1802 return Insecure;
1803 }
1804
1805 std::string reason;
1806 if (haveNegativeTrustAnchor(luaLocal->negAnchors, zone, reason)) {
e77f01d1 1807 LOG(d_prefix<<": got NTA for '"<<zone<<"'"<<endl);
4d2be65d
RG
1808 return NTA;
1809 }
1810
1811 if (getTrustAnchor(luaLocal->dsAnchors, zone, ds)) {
e77f01d1 1812 LOG(d_prefix<<": got TA for '"<<zone<<"'"<<endl);
895449a5 1813 return TA;
4d2be65d 1814 }
e77f01d1 1815 else {
1816 LOG(d_prefix<<": no TA found for '"<<zone<<"' among "<< luaLocal->dsAnchors.size()<<endl);
1817 }
4d2be65d
RG
1818
1819 if (zone.isRoot()) {
1820 /* No TA for the root */
1821 return Insecure;
1822 }
1823
1824 return Indeterminate;
1825}
1826
8455425c
RG
1827static size_t countSupportedDS(const dsmap_t& dsmap)
1828{
1829 size_t count = 0;
1830
1831 for (const auto& ds : dsmap) {
1832 if (isSupportedDS(ds)) {
1833 count++;
1834 }
1835 }
1836
1837 return count;
1838}
1839
5374b03b 1840vState SyncRes::getDSRecords(const DNSName& zone, dsmap_t& ds, bool taOnly, unsigned int depth, bool bogusOnNXD, bool* foundCut)
4d2be65d
RG
1841{
1842 vState result = getTA(zone, ds);
1843
1844 if (result != Indeterminate || taOnly) {
5374b03b
RG
1845 if (foundCut) {
1846 *foundCut = (result != Indeterminate);
1847 }
1848
18159e92
RG
1849 if (result == TA) {
1850 if (countSupportedDS(ds) == 0) {
1851 ds.clear();
1852 result = Insecure;
1853 }
1854 else {
1855 result = Secure;
1856 }
1857 }
1858 else if (result == NTA) {
8455425c
RG
1859 result = Insecure;
1860 }
1861
4d2be65d
RG
1862 return result;
1863 }
1864
1865 bool oldSkipCNAME = d_skipCNAMECheck;
4d2be65d 1866 d_skipCNAMECheck = true;
4d2be65d
RG
1867
1868 std::set<GetBestNSAnswer> beenthere;
1869 std::vector<DNSRecord> dsrecords;
1870
1871 vState state = Indeterminate;
51b6b728 1872 int rcode = doResolve(zone, QType(QType::DS), dsrecords, depth + 1, beenthere, state);
4d2be65d 1873 d_skipCNAMECheck = oldSkipCNAME;
4d2be65d 1874
3ca6d908 1875 if (rcode == RCode::NoError || (rcode == RCode::NXDomain && !bogusOnNXD)) {
1e332f68
PL
1876 uint8_t bestDigestType = 0;
1877
dd359a9f
RG
1878 bool gotCNAME = false;
1879 for (const auto& record : dsrecords) {
1880 if (record.d_type == QType::DS) {
1881 const auto dscontent = getRR<DSRecordContent>(record);
1882 if (dscontent && isSupportedDS(*dscontent)) {
1883 // Make GOST a lower prio than SHA256
1884 if (dscontent->d_digesttype == DNSSECKeeper::GOST && bestDigestType == DNSSECKeeper::SHA256) {
1885 continue;
4d2be65d 1886 }
dd359a9f
RG
1887 if (dscontent->d_digesttype > bestDigestType || (bestDigestType == DNSSECKeeper::GOST && dscontent->d_digesttype == DNSSECKeeper::SHA256)) {
1888 bestDigestType = dscontent->d_digesttype;
1889 }
1890 ds.insert(*dscontent);
1c39e884 1891 }
4d2be65d 1892 }
dd359a9f
RG
1893 else if (record.d_type == QType::CNAME && record.d_name == zone) {
1894 gotCNAME = true;
1895 }
1896 }
4d2be65d 1897
dd359a9f
RG
1898 /* RFC 4509 section 3: "Validator implementations SHOULD ignore DS RRs containing SHA-1
1899 * digests if DS RRs with SHA-256 digests are present in the DS RRset."
1900 * As SHA348 is specified as well, the spirit of the this line is "use the best algorithm".
1901 */
1902 for (auto dsrec = ds.begin(); dsrec != ds.end(); ) {
1903 if (dsrec->d_digesttype != bestDigestType) {
1904 dsrec = ds.erase(dsrec);
1e332f68 1905 }
dd359a9f
RG
1906 else {
1907 ++dsrec;
1908 }
1909 }
1e332f68 1910
dd359a9f
RG
1911 if (rcode == RCode::NoError) {
1912 if (ds.empty()) {
46df9251
RG
1913 /* we have no DS, it's either:
1914 - a delegation to a non-DNSSEC signed zone
1915 - no delegation, we stay in the same zone
1916 */
dd359a9f
RG
1917 if (gotCNAME || denialProvesNoDelegation(zone, dsrecords)) {
1918 /* we are still inside the same zone */
5374b03b 1919
dd359a9f 1920 if (foundCut) {
5374b03b 1921 *foundCut = false;
5374b03b 1922 }
dd359a9f
RG
1923 return state;
1924 }
5374b03b 1925
dd359a9f
RG
1926 /* delegation with no DS, might be Secure -> Insecure */
1927 if (foundCut) {
5374b03b
RG
1928 *foundCut = true;
1929 }
1930
46df9251
RG
1931 /* a delegation with no DS is either:
1932 - a signed zone (Secure) to an unsigned one (Insecure)
1933 - an unsigned zone to another unsigned one (Insecure stays Insecure, Bogus stays Bogus)
1934 */
dd359a9f
RG
1935 return state == Secure ? Insecure : state;
1936 } else {
1937 /* we have a DS */
1938 if (foundCut) {
1939 *foundCut = true;
1940 }
b7f378d1 1941 }
4d2be65d 1942 }
b7f378d1 1943
4d2be65d
RG
1944 return state;
1945 }
1946
bcb05770 1947 LOG(d_prefix<<": returning Bogus state from "<<__func__<<"("<<zone<<")"<<endl);
4d2be65d
RG
1948 return Bogus;
1949}
1950
0735b60f
RG
1951bool SyncRes::haveExactValidationStatus(const DNSName& domain)
1952{
e1636f82 1953 if (!shouldValidate()) {
0735b60f
RG
1954 return false;
1955 }
1956 const auto& it = d_cutStates.find(domain);
1957 if (it != d_cutStates.cend()) {
1958 return true;
1959 }
1960 return false;
1961}
1962
5374b03b 1963vState SyncRes::getValidationStatus(const DNSName& subdomain, bool allowIndeterminate)
70b3fe7a
RG
1964{
1965 vState result = Indeterminate;
1966
e1636f82 1967 if (!shouldValidate()) {
70b3fe7a
RG
1968 return result;
1969 }
1970 DNSName name(subdomain);
1971 do {
51b6b728
RG
1972 const auto& it = d_cutStates.find(name);
1973 if (it != d_cutStates.cend()) {
5374b03b
RG
1974 if (allowIndeterminate || it->second != Indeterminate) {
1975 LOG(d_prefix<<": got status "<<vStates[it->second]<<" for name "<<subdomain<<" (from "<<name<<")"<<endl);
1976 return it->second;
1977 }
70b3fe7a
RG
1978 }
1979 }
1980 while (name.chopOff());
1981
1982 return result;
1983}
1984
c405e222
RG
1985bool SyncRes::lookForCut(const DNSName& qname, unsigned int depth, const vState existingState, vState& newState)
1986{
1987 bool foundCut = false;
5374b03b
RG
1988 dsmap_t ds;
1989 vState dsState = getDSRecords(qname, ds, newState == Bogus || existingState == Insecure || existingState == Bogus, depth, false, &foundCut);
c405e222 1990
5374b03b
RG
1991 if (dsState != Indeterminate) {
1992 newState = dsState;
1993 }
c405e222 1994
c405e222
RG
1995 return foundCut;
1996}
1997
51b6b728 1998void SyncRes::computeZoneCuts(const DNSName& begin, const DNSName& end, unsigned int depth)
4d2be65d 1999{
428f41b7 2000 if(!begin.isPartOf(end)) {
86f1af1c
KM
2001 LOG(d_prefix<<" "<<begin.toLogString()<<" is not part of "<<end.toLogString()<<endl);
2002 throw PDNSException(begin.toLogString() + " is not part of " + end.toLogString());
428f41b7
RG
2003 }
2004
51b6b728 2005 if (d_cutStates.count(begin) != 0) {
ad75fdbd 2006 return;
4d2be65d
RG
2007 }
2008
2009 dsmap_t ds;
51b6b728 2010 vState cutState = getDSRecords(end, ds, false, depth);
bcb05770 2011 LOG(d_prefix<<": setting cut state for "<<end<<" to "<<vStates[cutState]<<endl);
51b6b728 2012 d_cutStates[end] = cutState;
70b3fe7a 2013
e1636f82 2014 if (!shouldValidate()) {
ad75fdbd 2015 return;
70b3fe7a
RG
2016 }
2017
70b3fe7a
RG
2018 DNSName qname(end);
2019 std::vector<string> labelsToAdd = begin.makeRelative(end).getRawLabels();
2020
ad75fdbd 2021 bool oldSkipCNAME = d_skipCNAMECheck;
ad75fdbd 2022 d_skipCNAMECheck = true;
ad75fdbd 2023
70b3fe7a 2024 while(qname != begin) {
70b3fe7a
RG
2025 if (labelsToAdd.empty())
2026 break;
2027
2028 qname.prependRawLabel(labelsToAdd.back());
2029 labelsToAdd.pop_back();
bcb05770
RG
2030 LOG(d_prefix<<": - Looking for a cut at "<<qname<<endl);
2031
2032 const auto cutIt = d_cutStates.find(qname);
2033 if (cutIt != d_cutStates.cend()) {
2034 if (cutIt->second != Indeterminate) {
2035 LOG(d_prefix<<": - Cut already known at "<<qname<<endl);
3d4e836e 2036 cutState = cutIt->second;
bcb05770
RG
2037 continue;
2038 }
2039 }
70b3fe7a 2040
3d4e836e
RG
2041 /* no need to look for NS and DS if we are already insecure or bogus,
2042 just look for (N)TA
2043 */
2044 if (cutState == Insecure || cutState == Bogus) {
2010ac95
RG
2045 dsmap_t cutDS;
2046 vState newState = getDSRecords(qname, cutDS, true, depth);
3d4e836e
RG
2047 if (newState == Indeterminate) {
2048 continue;
2049 }
2050
2051 LOG(d_prefix<<": New state for "<<qname<<" is "<<vStates[newState]<<endl);
3d4e836e
RG
2052 cutState = newState;
2053
2054 d_cutStates[qname] = cutState;
2055
2056 continue;
2057 }
70b3fe7a 2058
c405e222 2059 vState newState = Indeterminate;
428f41b7
RG
2060 /* temporarily mark as Indeterminate, so that we won't enter an endless loop
2061 trying to determine that zone cut again. */
c405e222
RG
2062 d_cutStates[qname] = newState;
2063 bool foundCut = lookForCut(qname, depth + 1, cutState, newState);
2064 if (foundCut) {
2065 LOG(d_prefix<<": - Found cut at "<<qname<<endl);
2066 if (newState != Indeterminate) {
2067 cutState = newState;
70b3fe7a 2068 }
c405e222
RG
2069 LOG(d_prefix<<": New state for "<<qname<<" is "<<vStates[cutState]<<endl);
2070 d_cutStates[qname] = cutState;
70b3fe7a 2071 }
c405e222 2072 else {
428f41b7 2073 /* remove the temporary cut */
b25712fd 2074 LOG(d_prefix<<qname<<": removing cut state for "<<qname<<endl);
51b6b728 2075 d_cutStates.erase(qname);
428f41b7 2076 }
70b3fe7a
RG
2077 }
2078
ad75fdbd 2079 d_skipCNAMECheck = oldSkipCNAME;
ad75fdbd 2080
bcb05770 2081 LOG(d_prefix<<": list of cuts from "<<begin<<" to "<<end<<endl);
51b6b728 2082 for (const auto& cut : d_cutStates) {
bcb05770 2083 if (cut.first.isRoot() || (begin.isPartOf(cut.first) && cut.first.isPartOf(end))) {
51b6b728
RG
2084 LOG(" - "<<cut.first<<": "<<vStates[cut.second]<<endl);
2085 }
70b3fe7a 2086 }
4d2be65d
RG
2087}
2088
51b6b728 2089vState SyncRes::validateDNSKeys(const DNSName& zone, const std::vector<DNSRecord>& dnskeys, const std::vector<std::shared_ptr<RRSIGRecordContent> >& signatures, unsigned int depth)
4d2be65d
RG
2090{
2091 dsmap_t ds;
2092 if (!signatures.empty()) {
2093 DNSName signer = getSigner(signatures);
2094
8d2e7fa1 2095 if (!signer.empty() && zone.isPartOf(signer)) {
51b6b728 2096 vState state = getDSRecords(signer, ds, false, depth);
b7f378d1 2097
4d2be65d
RG
2098 if (state != Secure) {
2099 return state;
2100 }
2101 }
2102 }
2103
2104 skeyset_t tentativeKeys;
2105 std::vector<shared_ptr<DNSRecordContent> > toSign;
2106
2107 for (const auto& dnskey : dnskeys) {
2108 if (dnskey.d_type == QType::DNSKEY) {
2109 auto content = getRR<DNSKEYRecordContent>(dnskey);
2110 if (content) {
2111 tentativeKeys.insert(content);
2112 toSign.push_back(content);
2113 }
2114 }
2115 }
2116
bcb05770 2117 LOG(d_prefix<<": trying to validate "<<std::to_string(tentativeKeys.size())<<" DNSKEYs with "<<std::to_string(ds.size())<<" DS"<<endl);
4d2be65d
RG
2118 skeyset_t validatedKeys;
2119 validateDNSKeysAgainstDS(d_now.tv_sec, zone, ds, tentativeKeys, toSign, signatures, validatedKeys);
2120
bcb05770 2121 LOG(d_prefix<<": we now have "<<std::to_string(validatedKeys.size())<<" DNSKEYs"<<endl);
4d2be65d 2122
82fbd934
RG
2123 /* if we found at least one valid RRSIG covering the set,
2124 all tentative keys are validated keys. Otherwise it means
2125 we haven't found at least one DNSKEY and a matching RRSIG
2126 covering this set, this looks Bogus. */
4d2be65d 2127 if (validatedKeys.size() != tentativeKeys.size()) {
bcb05770 2128 LOG(d_prefix<<": returning Bogus state from "<<__func__<<"("<<zone<<")"<<endl);
4d2be65d
RG
2129 return Bogus;
2130 }
2131
2132 return Secure;
2133}
2134
51b6b728 2135vState SyncRes::getDNSKeys(const DNSName& signer, skeyset_t& keys, unsigned int depth)
4d2be65d
RG
2136{
2137 std::vector<DNSRecord> records;
2138 std::set<GetBestNSAnswer> beenthere;
bcb05770 2139 LOG(d_prefix<<"Retrieving DNSKeys for "<<signer<<endl);
4d2be65d
RG
2140
2141 vState state = Indeterminate;
c7385ddb
RG
2142 /* following CNAME might lead to us to the wrong DNSKEY */
2143 bool oldSkipCNAME = d_skipCNAMECheck;
2144 d_skipCNAMECheck = true;
51b6b728 2145 int rcode = doResolve(signer, QType(QType::DNSKEY), records, depth + 1, beenthere, state);
c7385ddb 2146 d_skipCNAMECheck = oldSkipCNAME;
4d2be65d
RG
2147
2148 if (rcode == RCode::NoError) {
2149 if (state == Secure) {
2150 for (const auto& key : records) {
2151 if (key.d_type == QType::DNSKEY) {
2152 auto content = getRR<DNSKEYRecordContent>(key);
2153 if (content) {
2154 keys.insert(content);
2155 }
2156 }
2157 }
2158 }
bcb05770 2159 LOG(d_prefix<<"Retrieved "<<keys.size()<<" DNSKeys for "<<signer<<", state is "<<vStates[state]<<endl);
4d2be65d
RG
2160 return state;
2161 }
2162
bcb05770 2163 LOG(d_prefix<<"Returning Bogus state from "<<__func__<<"("<<signer<<")"<<endl);
4d2be65d
RG
2164 return Bogus;
2165}
2166
51b6b728 2167vState 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
2168{
2169 skeyset_t keys;
2170 if (!signatures.empty()) {
2171 const DNSName signer = getSigner(signatures);
2172 if (!signer.empty() && name.isPartOf(signer)) {
f715542c 2173 if ((qtype == QType::DNSKEY || qtype == QType::DS) && signer == qname) {
15f44f1d 2174 /* we are already retrieving those keys, sorry */
dd359a9f
RG
2175 if (qtype == QType::DS) {
2176 /* something is very wrong */
2177 LOG(d_prefix<<"The DS for "<<qname<<" is signed by itself, going Bogus"<<endl);
2178 return Bogus;
2179 }
15f44f1d
RG
2180 return Indeterminate;
2181 }
51b6b728 2182 vState state = getDNSKeys(signer, keys, depth);
4d2be65d
RG
2183 if (state != Secure) {
2184 return state;
2185 }
2186 }
2187 } else {
bcb05770 2188 LOG(d_prefix<<"Bogus!"<<endl);
4d2be65d
RG
2189 return Bogus;
2190 }
2191
2192 std::vector<std::shared_ptr<DNSRecordContent> > recordcontents;
2193 for (const auto& record : records) {
2194 recordcontents.push_back(record.d_content);
2195 }
2196
bcb05770 2197 LOG(d_prefix<<"Going to validate "<<recordcontents.size()<< " record contents with "<<signatures.size()<<" sigs and "<<keys.size()<<" keys for "<<name<<endl);
4d2be65d 2198 if (validateWithKeySet(d_now.tv_sec, name, recordcontents, signatures, keys, false)) {
bcb05770 2199 LOG(d_prefix<<"Secure!"<<endl);
4d2be65d
RG
2200 return Secure;
2201 }
2202
bcb05770 2203 LOG(d_prefix<<"Bogus!"<<endl);
4d2be65d
RG
2204 return Bogus;
2205}
2206
7155c3e5
RG
2207static bool allowAdditionalEntry(std::unordered_set<DNSName>& allowedAdditionals, const DNSRecord& rec)
2208{
2209 switch(rec.d_type) {
2210 case QType::MX:
2211 {
2212 if (auto mxContent = getRR<MXRecordContent>(rec)) {
2213 allowedAdditionals.insert(mxContent->d_mxname);
2214 }
2215 return true;
2216 }
2217 case QType::NS:
2218 {
2219 if (auto nsContent = getRR<NSRecordContent>(rec)) {
2220 allowedAdditionals.insert(nsContent->getNS());
2221 }
2222 return true;
2223 }
2224 case QType::SRV:
2225 {
2226 if (auto srvContent = getRR<SRVRecordContent>(rec)) {
2227 allowedAdditionals.insert(srvContent->d_target);
2228 }
2229 return true;
2230 }
2231 default:
2232 return false;
2233 }
2234}
2235
2236void SyncRes::sanitizeRecords(const std::string& prefix, LWResult& lwr, const DNSName& qname, const QType& qtype, const DNSName& auth, bool wasForwarded, bool rdQuery)
2237{
2238 const bool wasForwardRecurse = wasForwarded && rdQuery;
2239 /* list of names for which we will allow A and AAAA records in the additional section
2240 to remain */
2241 std::unordered_set<DNSName> allowedAdditionals = { qname };
2242 bool haveAnswers = false;
2243 bool isNXDomain = false;
2244 bool isNXQType = false;
2245
2246 for(auto rec = lwr.d_records.begin(); rec != lwr.d_records.end(); ) {
2247
2248 if (rec->d_type == QType::OPT) {
2249 ++rec;
2250 continue;
2251 }
2252
2253 if (rec->d_class != QClass::IN) {
2254 LOG(prefix<<"Removing non internet-classed data received from "<<auth<<endl);
2255 rec = lwr.d_records.erase(rec);
2256 continue;
2257 }
2258
2259 if (rec->d_type == QType::ANY) {
2260 LOG(prefix<<"Removing 'ANY'-typed data received from "<<auth<<endl);
2261 rec = lwr.d_records.erase(rec);
2262 continue;
2263 }
2264
2265 if (!rec->d_name.isPartOf(auth)) {
2266 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);
2267 rec = lwr.d_records.erase(rec);
2268 continue;
2269 }
2270
2271 /* dealing with the records in answer */
2272 if (!(lwr.d_aabit || wasForwardRecurse) && rec->d_place == DNSResourceRecord::ANSWER) {
9870af40
RG
2273 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2274 are sending such responses */
2275 if (!(rec->d_type == QType::CNAME && qname == rec->d_name)) {
2276 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);
2277 rec = lwr.d_records.erase(rec);
2278 continue;
2279 }
7155c3e5
RG
2280 }
2281
2282 if (rec->d_type == QType::DNAME && (rec->d_place != DNSResourceRecord::ANSWER || !qname.isPartOf(rec->d_name))) {
2283 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);
2284 rec = lwr.d_records.erase(rec);
2285 continue;
2286 }
2287
123da0f8 2288 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
2289 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);
2290 rec = lwr.d_records.erase(rec);
2291 continue;
2292 }
2293
2294 if (rec->d_place == DNSResourceRecord::ANSWER && !haveAnswers) {
2295 haveAnswers = true;
2296 }
2297
2298 if (rec->d_place == DNSResourceRecord::ANSWER) {
2299 allowAdditionalEntry(allowedAdditionals, *rec);
2300 }
2301
2302 /* dealing with the records in authority */
2303 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) {
2304 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);
2305 rec = lwr.d_records.erase(rec);
2306 continue;
2307 }
2308
2309 if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type == QType::SOA) {
2310 if (!qname.isPartOf(rec->d_name)) {
2311 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);
2312 rec = lwr.d_records.erase(rec);
2313 continue;
2314 }
2315
215c16f9
RG
2316 if (!(lwr.d_aabit || wasForwardRecurse)) {
2317 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);
2318 rec = lwr.d_records.erase(rec);
2319 continue;
2320 }
2321
7155c3e5
RG
2322 if (!haveAnswers) {
2323 if (lwr.d_rcode == RCode::NXDomain) {
2324 isNXDomain = true;
2325 }
2326 else if (lwr.d_rcode == RCode::NoError) {
2327 isNXQType = true;
2328 }
2329 }
2330 }
2331
2332 if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type == QType::NS && (isNXDomain || isNXQType)) {
2333 /* we don't want to pick up NS records in AUTHORITY or ADDITIONAL sections of NXDomain answers
2334 because they are somewhat easy to insert into a large, fragmented UDP response
1bb97c02 2335 for an off-path attacker by injecting spoofed UDP fragments.
7155c3e5
RG
2336 */
2337 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);
2338 rec = lwr.d_records.erase(rec);
1bb97c02 2339 continue;
7155c3e5
RG
2340 }
2341
2342 if (rec->d_place == DNSResourceRecord::AUTHORITY && rec->d_type == QType::NS) {
2343 allowAdditionalEntry(allowedAdditionals, *rec);
2344 }
2345
2346 /* dealing with the records in additional */
2347 if (rec->d_place == DNSResourceRecord::ADDITIONAL && rec->d_type != QType::A && rec->d_type != QType::AAAA && rec->d_type != QType::RRSIG) {
2348 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);
2349 rec = lwr.d_records.erase(rec);
2350 continue;
2351 }
2352
2353 if (rec->d_place == DNSResourceRecord::ADDITIONAL && allowedAdditionals.count(rec->d_name) == 0) {
2354 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);
2355 rec = lwr.d_records.erase(rec);
2356 continue;
2357 }
2358
2359 ++rec;
2360 }
2361}
2362
78cdf520 2363RCode::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 2364{
ba40d3d7 2365 bool wasForwardRecurse = wasForwarded && rdQuery;
26ca3513
RG
2366 tcache_t tcache;
2367
4d2be65d
RG
2368 string prefix;
2369 if(doLog()) {
2370 prefix=d_prefix;
2371 prefix.append(depth, ' ');
2372 }
2373
7155c3e5
RG
2374 sanitizeRecords(prefix, lwr, qname, qtype, auth, wasForwarded, rdQuery);
2375
2b984251 2376 std::vector<std::shared_ptr<DNSRecord>> authorityRecs;
142ab370 2377 const unsigned int labelCount = qname.countLabels();
a82d4e27 2378 bool isCNAMEAnswer = false;
8838c88f 2379 bool isDNAMEAnswer = false;
26ca3513 2380 for(const auto& rec : lwr.d_records) {
c5310862
RG
2381 if (rec.d_class != QClass::IN) {
2382 continue;
2383 }
2384
d30b5493 2385 if(!isCNAMEAnswer && rec.d_place == DNSResourceRecord::ANSWER && rec.d_type == QType::CNAME && (!(qtype==QType(QType::CNAME))) && rec.d_name == qname && !isDNAMEAnswer) {
a82d4e27
RG
2386 isCNAMEAnswer = true;
2387 }
d30b5493 2388 if(!isDNAMEAnswer && rec.d_place == DNSResourceRecord::ANSWER && rec.d_type == QType::DNAME && qtype != QType(QType::DNAME) && qname.isPartOf(rec.d_name)) {
8838c88f 2389 isDNAMEAnswer = true;
d30b5493 2390 isCNAMEAnswer = false;
8838c88f 2391 }
a82d4e27 2392
9b061cf5
RG
2393 /* if we have a positive answer synthetized from a wildcard,
2394 we need to store the corresponding NSEC/NSEC3 records proving
2395 that the exact name did not exist in the negative cache */
78cdf520 2396 if(gatherWildcardProof) {
2b984251
RG
2397 if (nsecTypes.count(rec.d_type)) {
2398 authorityRecs.push_back(std::make_shared<DNSRecord>(rec));
2399 }
2400 else if (rec.d_type == QType::RRSIG) {
2401 auto rrsig = getRR<RRSIGRecordContent>(rec);
2402 if (rrsig && nsecTypes.count(rrsig->d_type)) {
2403 authorityRecs.push_back(std::make_shared<DNSRecord>(rec));
2404 }
2405 }
2406 }
26ca3513
RG
2407 if(rec.d_type == QType::RRSIG) {
2408 auto rrsig = getRR<RRSIGRecordContent>(rec);
2409 if (rrsig) {
bb07ad8e
RG
2410 /* As illustrated in rfc4035's Appendix B.6, the RRSIG label
2411 count can be lower than the name's label count if it was
9b061cf5 2412 synthetized from the wildcard. Note that the difference might
bb07ad8e 2413 be > 1. */
78cdf520
RG
2414 if (rec.d_name == qname && isWildcardExpanded(labelCount, rrsig)) {
2415 gatherWildcardProof = true;
2416 if (!isWildcardExpandedOntoItself(rec.d_name, labelCount, rrsig)) {
2417 /* if we have a wildcard expanded onto itself, we don't need to prove
2418 that the exact name doesn't exist because it actually does.
2419 We still want to gather the corresponding NSEC/NSEC3 records
2420 to pass them to our client in case it wants to validate by itself.
2421 */
2422 LOG(prefix<<qname<<": RRSIG indicates the name was synthetized from a wildcard, we need a wildcard proof"<<endl);
2423 needWildcardProof = true;
2424 }
2425 else {
2426 LOG(prefix<<qname<<": RRSIG indicates the name was synthetized from a wildcard expanded onto itself, we need to gather wildcard proof"<<endl);
2427 }
e4894ce0 2428 wildcardLabelsCount = rrsig->d_labels;
2b984251
RG
2429 }
2430
26ca3513
RG
2431 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
2432 tcache[{rec.d_name, rrsig->d_type, rec.d_place}].signatures.push_back(rrsig);
4d2be65d 2433 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
2434 }
2435 }
2436 }
2437
2438 // reap all answers from this packet that are acceptable
2439 for(auto& rec : lwr.d_records) {
2440 if(rec.d_type == QType::OPT) {
2441 LOG(prefix<<qname<<": OPT answer '"<<rec.d_name<<"' from '"<<auth<<"' nameservers" <<endl);
2442 continue;
2443 }
e77f01d1 2444 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 2445 if(rec.d_type == QType::ANY) {
c5310862
RG
2446 LOG("NO! - we don't accept 'ANY'-typed data"<<endl);
2447 continue;
2448 }
2449
2450 if(rec.d_class != QClass::IN) {
2451 LOG("NO! - we don't accept records for any other class than 'IN'"<<endl);
26ca3513
RG
2452 continue;
2453 }
2454
70ea0c65 2455 if (!(lwr.d_aabit || wasForwardRecurse) && rec.d_place == DNSResourceRecord::ANSWER) {
9870af40
RG
2456 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2457 are sending such responses */
2458 if (!(rec.d_type == QType::CNAME && rec.d_name == qname)) {
2459 LOG("NO! - we don't accept records in the answers section without the AA bit set"<<endl);
2460 continue;
2461 }
70ea0c65
RG
2462 }
2463
26ca3513
RG
2464 if(rec.d_name.isPartOf(auth)) {
2465 if(rec.d_type == QType::RRSIG) {
2466 LOG("RRSIG - separate"<<endl);
2467 }
4d2be65d 2468 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
2469 LOG("NO! Is from delegation-only zone"<<endl);
2470 s_nodelegated++;
2471 return RCode::NXDomain;
2472 }
2473 else {
2474 bool haveLogged = false;
d30b5493
PL
2475 if (isDNAMEAnswer && rec.d_type == QType::CNAME) {
2476 LOG("NO - we already have a DNAME answer for this domain");
2477 continue;
2478 }
a712cb56 2479 if (!t_sstorage.domainmap->empty()) {
26ca3513
RG
2480 // Check if we are authoritative for a zone in this answer
2481 DNSName tmp_qname(rec.d_name);
2482 auto auth_domain_iter=getBestAuthZone(&tmp_qname);
a712cb56 2483 if(auth_domain_iter!=t_sstorage.domainmap->end() &&
26ca3513
RG
2484 auth.countLabels() <= auth_domain_iter->first.countLabels()) {
2485 if (auth_domain_iter->first != auth) {
2486 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter->first<<endl);
2487 continue;
2488 } else {
2489 LOG("YES! - This answer was ");
6dfff36f 2490 if (!wasForwarded) {
26ca3513
RG
2491 LOG("retrieved from the local auth store.");
2492 } else {
2493 LOG("received from a server we forward to.");
2494 }
2495 haveLogged = true;
2496 LOG(endl);
2497 }
2498 }
2499 }
2500 if (!haveLogged) {
2501 LOG("YES!"<<endl);
2502 }
2503
2504 rec.d_ttl=min(s_maxcachettl, rec.d_ttl);
2505
2506 DNSRecord dr(rec);
26ca3513 2507 dr.d_ttl += d_now.tv_sec;
2b984251 2508 dr.d_place=DNSResourceRecord::ANSWER;
26ca3513
RG
2509 tcache[{rec.d_name,rec.d_type,rec.d_place}].records.push_back(dr);
2510 }
2511 }
2512 else
2513 LOG("NO!"<<endl);
2514 }
2515
2516 // supplant
4d2be65d
RG
2517 for(tcache_t::iterator i = tcache.begin(); i != tcache.end(); ++i) {
2518 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)
2519 uint32_t lowestTTD=computeLowestTTD(i->second.records, i->second.signatures, i->second.signaturesTTL);
26ca3513
RG
2520
2521 for(auto& record : i->second.records)
4d2be65d 2522 record.d_ttl = lowestTTD; // boom
26ca3513
RG
2523 }
2524
2525// cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
2526// cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
4d2be65d
RG
2527 }
2528
2529 for(tcache_t::iterator i = tcache.begin(); i != tcache.end(); ++i) {
4d2be65d 2530
26ca3513
RG
2531 if(i->second.records.empty()) // this happens when we did store signatures, but passed on the records themselves
2532 continue;
6dfff36f 2533
405a26bd
RG
2534 /* Even if the AA bit is set, additional data cannot be considered
2535 as authoritative. This is especially important during validation
2536 because keeping records in the additional section is allowed even
2537 if the corresponding RRSIGs are not included, without setting the TC
2538 bit, as stated in rfc4035's section 3.1.1. Including RRSIG RRs in a Response:
2539 "When placing a signed RRset in the Additional section, the name
2540 server MUST also place its RRSIG RRs in the Additional section.
2541 If space does not permit inclusion of both the RRset and its
2542 associated RRSIG RRs, the name server MAY retain the RRset while
2543 dropping the RRSIG RRs. If this happens, the name server MUST NOT
2544 set the TC bit solely because these RRSIG RRs didn't fit."
2545 */
2546 bool isAA = lwr.d_aabit && i->first.place != DNSResourceRecord::ADDITIONAL;
dff3ef07
RG
2547 /* if we forwarded the query to a recursor, we can expect the answer to be signed,
2548 even if the answer is not AA. Of course that's not only true inside a Secure
2549 zone, but we check that below. */
70ea0c65 2550 bool expectSignature = i->first.place == DNSResourceRecord::ANSWER || ((lwr.d_aabit || wasForwardRecurse) && i->first.place != DNSResourceRecord::ADDITIONAL);
dff3ef07 2551 if (isCNAMEAnswer && (i->first.place != DNSResourceRecord::ANSWER || i->first.type != QType::CNAME || i->first.name != qname)) {
a82d4e27
RG
2552 /*
2553 rfc2181 states:
2554 Note that the answer section of an authoritative answer normally
2555 contains only authoritative data. However when the name sought is an
2556 alias (see section 10.1.1) only the record describing that alias is
2557 necessarily authoritative. Clients should assume that other records
2558 may have come from the server's cache. Where authoritative answers
2559 are required, the client should query again, using the canonical name
2560 associated with the alias.
2561 */
2562 isAA = false;
dff3ef07 2563 expectSignature = false;
a82d4e27
RG
2564 }
2565
d9c32b52
RG
2566 if (isCNAMEAnswer && i->first.place == DNSResourceRecord::AUTHORITY && i->first.type == QType::NS && auth == i->first.name) {
2567 /* These NS can't be authoritative since we have a CNAME answer for which (see above) only the
2568 record describing that alias is necessarily authoritative.
2569 But if we allow the current auth, which might be serving the child zone, to raise the TTL
2570 of non-authoritative NS in the cache, they might be able to keep a "ghost" zone alive forever,
2571 even after the delegation is gone from the parent.
2572 So let's just do nothing with them, we can fetch them directly if we need them.
2573 */
2574 LOG(d_prefix<<": skipping authority NS from '"<<auth<<"' nameservers in CNAME answer "<<i->first.name<<"|"<<DNSRecordContent::NumberToType(i->first.type)<<endl);
2575 continue;
2576 }
2577
5374b03b 2578 vState recordState = getValidationStatus(i->first.name, false);
1a8d6a9e 2579 LOG(d_prefix<<": got initial zone status "<<vStates[recordState]<<" for record "<<i->first.name<<"|"<<DNSRecordContent::NumberToType(i->first.type)<<endl);
70b3fe7a 2580
e1636f82 2581 if (shouldValidate() && recordState == Secure) {
5374b03b
RG
2582 vState initialState = recordState;
2583
dff3ef07 2584 if (expectSignature) {
4d2be65d
RG
2585 if (i->first.place != DNSResourceRecord::ADDITIONAL) {
2586 /* the additional entries can be insecure,
2587 like glue:
2588 "Glue address RRsets associated with delegations MUST NOT be signed"
2589 */
2590 if (i->first.type == QType::DNSKEY && i->first.place == DNSResourceRecord::ANSWER) {
bcb05770 2591 LOG(d_prefix<<"Validating DNSKEY for "<<i->first.name<<endl);
51b6b728 2592 recordState = validateDNSKeys(i->first.name, i->second.records, i->second.signatures, depth);
4d2be65d
RG
2593 }
2594 else {
8838c88f
PL
2595 /*
2596 * RFC 6672 section 5.3.1
2597 * In any response, a signed DNAME RR indicates a non-terminal
2598 * redirection of the query. There might or might not be a server-
2599 * synthesized CNAME in the answer section; if there is, the CNAME will
2600 * never be signed. For a DNSSEC validator, verification of the DNAME
2601 * RR and then that the CNAME was properly synthesized is sufficient
2602 * proof.
2603 *
2604 * We do the synthesis check in processRecords, here we make sure we
2605 * don't validate the CNAME.
2606 */
2607 if (!(isDNAMEAnswer && i->first.type == QType::CNAME)) {
2608 LOG(d_prefix<<"Validating non-additional record for "<<i->first.name<<endl);
2609 recordState = validateRecordsWithSigs(depth, qname, qtype, i->first.name, i->second.records, i->second.signatures);
2610 /* 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 */
2611 if (qtype == QType::NS && i->second.signatures.empty() && recordState == Bogus && haveExactValidationStatus(i->first.name) && getValidationStatus(i->first.name) == Indeterminate) {
2612 recordState = Indeterminate;
2613 }
0735b60f 2614 }
4d2be65d
RG
2615 }
2616 }
2617 }
2618 else {
933299e8
RG
2619 recordState = Indeterminate;
2620
a82d4e27 2621 /* in a non authoritative answer, we only care about the DS record (or lack of) */
88cb0fe0 2622 if ((i->first.type == QType::DS || i->first.type == QType::NSEC || i->first.type == QType::NSEC3) && i->first.place == DNSResourceRecord::AUTHORITY) {
bcb05770 2623 LOG(d_prefix<<"Validating DS record for "<<i->first.name<<endl);
51b6b728 2624 recordState = validateRecordsWithSigs(depth, qname, qtype, i->first.name, i->second.records, i->second.signatures);
4d2be65d
RG
2625 }
2626 }
0735b60f 2627
dff3ef07 2628 if (initialState == Secure && state != recordState && expectSignature) {
5374b03b
RG
2629 updateValidationState(state, recordState);
2630 }
4d2be65d
RG
2631 }
2632 else {
e1636f82 2633 if (shouldValidate()) {
bcb05770 2634 LOG(d_prefix<<"Skipping validation because the current state is "<<vStates[recordState]<<endl);
4d2be65d
RG
2635 }
2636 }
2637
b9473937
RG
2638 if (recordState == Bogus) {
2639 /* this is a TTD by now, be careful */
2640 for(auto& record : i->second.records) {
2641 record.d_ttl = std::min(record.d_ttl, static_cast<uint32_t>(s_maxbogusttl + d_now.tv_sec));
2642 }
2643 }
2644
005b4b98
RG
2645 /* We don't need to store NSEC3 records in the positive cache because:
2646 - we don't allow direct NSEC3 queries
2647 - denial of existence proofs in wildcard expanded positive responses are stored in authorityRecs
2648 - denial of existence proofs for negative responses are stored in the negative cache
a321baf9
RG
2649 We also don't want to cache non-authoritative data except for:
2650 - records coming from non forward-recurse servers (those will never be AA)
2651 - DS (special case)
2652 - NS, A and AAAA (used for infra queries)
005b4b98 2653 */
a321baf9 2654 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 2655
73d9bf3a
OM
2656 bool doCache = true;
2657 if (i->first.place == DNSResourceRecord::ANSWER && ednsmask) {
2658 // If ednsmask is relevant, we do not want to cache if the scope prefix length is large and TTL is small
2659 if (SyncRes::s_ecscachelimitttl > 0) {
2660 bool manyMaskBits = (ednsmask->isIpv4() && ednsmask->getBits() > SyncRes::s_ecsipv4cachelimit) ||
e7861cc4
OM
2661 (ednsmask->isIpv6() && ednsmask->getBits() > SyncRes::s_ecsipv6cachelimit);
2662
e7861cc4
OM
2663 if (manyMaskBits) {
2664 uint32_t minttl = UINT32_MAX;
2665 for (const auto &it : i->second.records) {
2666 if (it.d_ttl < minttl)
2667 minttl = it.d_ttl;
2668 }
2669 bool ttlIsSmall = minttl < SyncRes::s_ecscachelimitttl + d_now.tv_sec;
2670 if (ttlIsSmall) {
2671 // Case: many bits and ttlIsSmall
2672 doCache = false;
2673 }
e7861cc4 2674 }
ed9019c9 2675 }
e7861cc4
OM
2676 }
2677 if (doCache) {
2678 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 2679 }
005b4b98 2680 }
6dfff36f 2681
26ca3513
RG
2682 if(i->first.place == DNSResourceRecord::ANSWER && ednsmask)
2683 d_wasVariable=true;
2684 }
2685
2686 return RCode::NoError;
2687}
2688
28364e4b 2689void SyncRes::updateDenialValidationState(vState& neValidationState, const DNSName& neName, vState& state, const dState denialState, const dState expectedState, bool allowOptOut)
4d2be65d 2690{
b25712fd 2691 if (denialState == expectedState) {
28364e4b 2692 neValidationState = Secure;
b25712fd
RG
2693 }
2694 else {
142ab370 2695 if (denialState == OPTOUT && allowOptOut) {
28364e4b
RG
2696 LOG(d_prefix<<"OPT-out denial found for "<<neName<<endl);
2697 neValidationState = Secure;
142ab370 2698 return;
4d2be65d 2699 }
142ab370 2700 else if (denialState == INSECURE) {
28364e4b
RG
2701 LOG(d_prefix<<"Insecure denial found for "<<neName<<", returning Insecure"<<endl);
2702 neValidationState = Insecure;
4d2be65d 2703 }
142ab370 2704 else {
28364e4b
RG
2705 LOG(d_prefix<<"Invalid denial found for "<<neName<<", returning Bogus, res="<<denialState<<", expectedState="<<expectedState<<endl);
2706 neValidationState = Bogus;
142ab370 2707 }
28364e4b 2708 updateValidationState(state, neValidationState);
4d2be65d
RG
2709 }
2710}
2711
28364e4b 2712dState SyncRes::getDenialValidationState(const NegCache::NegCacheEntry& ne, const vState state, const dState expectedState, bool referralToUnsigned)
142ab370
RG
2713{
2714 cspmap_t csp = harvestCSPFromNE(ne);
2715 return getDenial(csp, ne.d_name, ne.d_qtype.getCode(), referralToUnsigned, expectedState == NXQTYPE);
2716}
2717
78cdf520 2718bool 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
2719{
2720 bool done = false;
123da0f8 2721 DNSName dnameTarget, dnameOwner;
ee936074 2722 uint32_t dnameTTL = 0;
26ca3513
RG
2723
2724 for(auto& rec : lwr.d_records) {
2725 if (rec.d_type!=QType::OPT && rec.d_class!=QClass::IN)
2726 continue;
2727
70ea0c65 2728 if (rec.d_place==DNSResourceRecord::ANSWER && !(lwr.d_aabit || sendRDQuery)) {
9870af40
RG
2729 /* for now we allow a CNAME for the exact qname in ANSWER with AA=0, because Amazon DNS servers
2730 are sending such responses */
2731 if (!(rec.d_type == QType::CNAME && rec.d_name == qname)) {
2732 continue;
2733 }
70ea0c65
RG
2734 }
2735
26ca3513
RG
2736 if(rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::SOA &&
2737 lwr.d_rcode==RCode::NXDomain && qname.isPartOf(rec.d_name) && rec.d_name.isPartOf(auth)) {
2738 LOG(prefix<<qname<<": got negative caching indication for name '"<<qname<<"' (accept="<<rec.d_name.isPartOf(auth)<<"), newtarget='"<<newtarget<<"'"<<endl);
2739
2740 rec.d_ttl = min(rec.d_ttl, s_maxnegttl);
2741 if(newtarget.empty()) // only add a SOA if we're not going anywhere after this
2742 ret.push_back(rec);
39ce10b2 2743
114829cc
RG
2744 NegCache::NegCacheEntry ne;
2745
dbbef467 2746 uint32_t lowestTTL = rec.d_ttl;
9b061cf5
RG
2747 /* if we get an NXDomain answer with a CNAME, the name
2748 does exist but the target does not */
2749 ne.d_name = newtarget.empty() ? qname : newtarget;
114829cc
RG
2750 ne.d_qtype = QType(0); // this encodes 'whole record'
2751 ne.d_auth = rec.d_name;
dbbef467 2752 harvestNXRecords(lwr.d_records, ne, d_now.tv_sec, &lowestTTL);
dbbef467 2753
142ab370
RG
2754 if (state == Secure) {
2755 dState denialState = getDenialValidationState(ne, state, NXDOMAIN, false);
28364e4b 2756 updateDenialValidationState(ne.d_validationState, ne.d_name, state, denialState, NXDOMAIN, false);
142ab370
RG
2757 }
2758 else {
2759 ne.d_validationState = state;
2760 }
114829cc 2761
b9473937
RG
2762 if (ne.d_validationState == Bogus) {
2763 lowestTTL = min(lowestTTL, s_maxbogusttl);
2764 }
2765
2766 ne.d_ttd = d_now.tv_sec + lowestTTL;
9b061cf5
RG
2767 /* if we get an NXDomain answer with a CNAME, let's not cache the
2768 target, even the server was authoritative for it,
2769 and do an additional query for the CNAME target.
2770 We have a regression test making sure we do exactly that.
2771 */
2772 if(!wasVariable() && newtarget.empty()) {
a712cb56 2773 t_sstorage.negcache.add(ne);
2ef32aec 2774 if(s_rootNXTrust && ne.d_auth.isRoot() && auth.isRoot() && lwr.d_aabit) {
9a1e060b 2775 ne.d_name = ne.d_name.getLastLabel();
a712cb56 2776 t_sstorage.negcache.add(ne);
26ca3513
RG
2777 }
2778 }
2779
2780 negindic=true;
2781 }
123da0f8
PL
2782 else if(rec.d_place==DNSResourceRecord::ANSWER && s_redirectionQTypes.count(rec.d_type) > 0 && // CNAME or DNAME answer
2783 s_redirectionQTypes.count(qtype.getCode()) == 0) { // But not in response to a CNAME or DNAME query
2784 if (rec.d_type == QType::CNAME && rec.d_name == qname) {
ee936074
PL
2785 if (!dnameOwner.empty()) { // We synthesize ourselves
2786 continue;
2787 }
123da0f8
PL
2788 ret.push_back(rec);
2789 if (auto content = getRR<CNAMERecordContent>(rec)) {
2790 newtarget=content->getTarget();
2791 }
2792 } else if (rec.d_type == QType::DNAME && qname.isPartOf(rec.d_name)) { // DNAME
2793 ret.push_back(rec);
2794 if (auto content = getRR<DNAMERecordContent>(rec)) {
2795 dnameOwner = rec.d_name;
2796 dnameTarget = content->getTarget();
ee936074 2797 dnameTTL = rec.d_ttl;
29ec25aa
PL
2798 if (!newtarget.empty()) { // We had a CNAME before, remove it from ret so we don't cache it
2799 ret.erase(std::remove_if(
2800 ret.begin(),
2801 ret.end(),
2802 [&qname](DNSRecord& rr) {
2803 return (rr.d_place == DNSResourceRecord::ANSWER && rr.d_type == QType::CNAME && rr.d_name == qname);
2804 }),
2805 ret.end());
2806 }
ee936074
PL
2807 try {
2808 newtarget = qname.makeRelative(dnameOwner) + dnameTarget;
2809 } catch (const std::exception &e) {
2810 // We should probably catch an std::range_error here and set the rcode to YXDOMAIN (RFC 6672, section 2.2)
2811 // But there is no way to set the RCODE from this function
2812 throw ImmediateServFailException("Unable to perform DNAME substitution(DNAME owner: '" + dnameOwner.toLogString() +
2813 "', DNAME target: '" + dnameTarget.toLogString() + "', substituted name: '" +
2814 qname.makeRelative(dnameOwner).toLogString() + "." + dnameTarget.toLogString() +
2815 "' : " + e.what());
2816 }
123da0f8 2817 }
26ca3513
RG
2818 }
2819 }
9b061cf5
RG
2820 /* if we have a positive answer synthetized from a wildcard, we need to
2821 return the corresponding NSEC/NSEC3 records from the AUTHORITY section
2822 proving that the exact name did not exist */
78cdf520 2823 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
2824 ret.push_back(rec); // enjoy your DNSSEC
2825 }
26ca3513
RG
2826 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
2827 else if(rec.d_place==DNSResourceRecord::ANSWER && rec.d_name == qname &&
2828 (
331222c4 2829 rec.d_type==qtype.getCode() || ((lwr.d_aabit || sendRDQuery) && qtype == QType(QType::ANY))
26ca3513
RG
2830 )
2831 )
2832 {
2833 LOG(prefix<<qname<<": answer is in: resolved to '"<< rec.d_content->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec.d_type)<<"'"<<endl);
2834
2835 done=true;
9b061cf5
RG
2836
2837 if (state == Secure && needWildcardProof) {
2838 /* We have a positive answer synthetized from a wildcard, we need to check that we have
2839 proof that the exact name doesn't exist so the wildcard can be used,
2840 as described in section 5.3.4 of RFC 4035 and 5.3 of FRC 7129.
2841 */
2842 NegCache::NegCacheEntry ne;
2843
2844 uint32_t lowestTTL = rec.d_ttl;
2845 ne.d_name = qname;
2846 ne.d_qtype = QType(0); // this encodes 'whole record'
2847 harvestNXRecords(lwr.d_records, ne, d_now.tv_sec, &lowestTTL);
2848
2849 cspmap_t csp = harvestCSPFromNE(ne);
e4894ce0 2850 dState res = getDenial(csp, qname, ne.d_qtype.getCode(), false, false, false, wildcardLabelsCount);
9b061cf5 2851 if (res != NXDOMAIN) {
b7c40613
RG
2852 vState st = Bogus;
2853 if (res == INSECURE) {
2854 /* Some part could not be validated, for example a NSEC3 record with a too large number of iterations,
2855 this is not enough to warrant a Bogus, but go Insecure. */
2856 st = Insecure;
2857 LOG(d_prefix<<"Unable to validate denial in wildcard expanded positive response found for "<<qname<<", returning Insecure, res="<<res<<endl);
2858 }
2859 else {
2860 LOG(d_prefix<<"Invalid denial in wildcard expanded positive response found for "<<qname<<", returning Bogus, res="<<res<<endl);
b9473937 2861 rec.d_ttl = std::min(rec.d_ttl, s_maxbogusttl);
b7c40613
RG
2862 }
2863
2864 updateValidationState(state, st);
2865 /* we already stored the record with a different validation status, let's fix it */
b9473937 2866 updateValidationStatusInCache(qname, qtype, lwr.d_aabit, st);
9b061cf5
RG
2867 }
2868 }
b9473937 2869 ret.push_back(rec);
26ca3513 2870 }
7030a59b 2871 else if((rec.d_type==QType::RRSIG || rec.d_type==QType::NSEC || rec.d_type==QType::NSEC3) && rec.d_place==DNSResourceRecord::ANSWER) {
123da0f8 2872 if(rec.d_type != QType::RRSIG || rec.d_name == qname) {
7030a59b 2873 ret.push_back(rec); // enjoy your DNSSEC
123da0f8
PL
2874 } else if(rec.d_type == QType::RRSIG && qname.isPartOf(rec.d_name)) {
2875 auto rrsig = getRR<RRSIGRecordContent>(rec);
2876 if (rrsig != nullptr && rrsig->d_type == QType::DNAME) {
2877 ret.push_back(rec);
2878 }
2879 }
7030a59b 2880 }
4d2be65d 2881 else if(rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::NS && qname.isPartOf(rec.d_name)) {
26ca3513
RG
2882 if(moreSpecificThan(rec.d_name,auth)) {
2883 newauth=rec.d_name;
2884 LOG(prefix<<qname<<": got NS record '"<<rec.d_name<<"' -> '"<<rec.d_content->getZoneRepresentation()<<"'"<<endl);
2885 realreferral=true;
2886 }
2887 else {
2888 LOG(prefix<<qname<<": got upwards/level NS record '"<<rec.d_name<<"' -> '"<<rec.d_content->getZoneRepresentation()<<"', had '"<<auth<<"'"<<endl);
2889 }
2890 if (auto content = getRR<NSRecordContent>(rec)) {
2891 nsset.insert(content->getNS());
2892 }
2893 }
4d2be65d 2894 else if(rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::DS && qname.isPartOf(rec.d_name)) {
26ca3513 2895 LOG(prefix<<qname<<": got DS record '"<<rec.d_name<<"' -> '"<<rec.d_content->getZoneRepresentation()<<"'"<<endl);
26ca3513 2896 }
860d5e8e 2897 else if(realreferral && rec.d_place==DNSResourceRecord::AUTHORITY && (rec.d_type==QType::NSEC || rec.d_type==QType::NSEC3) && newauth.isPartOf(auth)) {
4d2be65d
RG
2898 /* we might have received a denial of the DS, let's check */
2899 if (state == Secure) {
2900 NegCache::NegCacheEntry ne;
2901 ne.d_auth = auth;
860d5e8e
RG
2902 ne.d_name = newauth;
2903 ne.d_qtype = QType::DS;
dbbef467
RG
2904 rec.d_ttl = min(s_maxnegttl, rec.d_ttl);
2905 uint32_t lowestTTL = rec.d_ttl;
2906 harvestNXRecords(lwr.d_records, ne, d_now.tv_sec, &lowestTTL);
2907
142ab370
RG
2908 dState denialState = getDenialValidationState(ne, state, NXQTYPE, true);
2909
d377bb54 2910 if (denialState == NXQTYPE || denialState == OPTOUT || denialState == INSECURE) {
dbbef467 2911 ne.d_ttd = lowestTTL + d_now.tv_sec;
860d5e8e 2912 ne.d_validationState = Secure;
812c3a69 2913 LOG(prefix<<qname<<": got negative indication of DS record for '"<<newauth<<"'"<<endl);
5374b03b 2914
4d2be65d
RG
2915 if(!wasVariable()) {
2916 t_sstorage.negcache.add(ne);
2917 }
5374b03b
RG
2918
2919 if (qname == newauth && qtype == QType::DS) {
2920 /* we are actually done! */
2921 negindic=true;
2922 nsset.clear();
2923 }
4d2be65d
RG
2924 }
2925 }
2926 }
2927 else if(!done && rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::SOA &&
2928 lwr.d_rcode==RCode::NoError && qname.isPartOf(rec.d_name)) {
26ca3513
RG
2929 LOG(prefix<<qname<<": got negative caching indication for '"<< qname<<"|"<<qtype.getName()<<"'"<<endl);
2930
2931 if(!newtarget.empty()) {
2932 LOG(prefix<<qname<<": Hang on! Got a redirect to '"<<newtarget<<"' already"<<endl);
2933 }
2934 else {
2935 rec.d_ttl = min(s_maxnegttl, rec.d_ttl);
114829cc
RG
2936
2937 NegCache::NegCacheEntry ne;
2938 ne.d_auth = rec.d_name;
dbbef467 2939 uint32_t lowestTTL = rec.d_ttl;
114829cc
RG
2940 ne.d_name = qname;
2941 ne.d_qtype = qtype;
dbbef467 2942 harvestNXRecords(lwr.d_records, ne, d_now.tv_sec, &lowestTTL);
dbbef467 2943
142ab370
RG
2944 if (state == Secure) {
2945 dState denialState = getDenialValidationState(ne, state, NXQTYPE, false);
28364e4b 2946 updateDenialValidationState(ne.d_validationState, ne.d_name, state, denialState, NXQTYPE, qtype == QType::DS);
142ab370
RG
2947 } else {
2948 ne.d_validationState = state;
2949 }
114829cc 2950
b9473937
RG
2951 if (ne.d_validationState == Bogus) {
2952 lowestTTL = min(lowestTTL, s_maxbogusttl);
2953 rec.d_ttl = min(rec.d_ttl, s_maxbogusttl);
2954 }
2955 ne.d_ttd = d_now.tv_sec + lowestTTL;
2956
26ca3513 2957 if(!wasVariable()) {
26ca3513 2958 if(qtype.getCode()) { // prevents us from blacking out a whole domain
a712cb56 2959 t_sstorage.negcache.add(ne);
26ca3513
RG
2960 }
2961 }
b9473937
RG
2962
2963 ret.push_back(rec);
26ca3513
RG
2964 negindic=true;
2965 }
2966 }
2967 }
2968
ee936074
PL
2969 if (!dnameTarget.empty()) {
2970 // Synthesize a CNAME
2971 auto cnamerec = DNSRecord();
2972 cnamerec.d_name = qname;
2973 cnamerec.d_type = QType::CNAME;
2974 cnamerec.d_ttl = dnameTTL;
2975 cnamerec.d_content = std::make_shared<CNAMERecordContent>(CNAMERecordContent(newtarget));
2976 ret.push_back(cnamerec);
123da0f8 2977 }
26ca3513
RG
2978 return done;
2979}
2980
6dfff36f
RG
2981bool 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)
2982{
deca7d8f 2983 bool chained = false;
17cecc84 2984 int resolveret = RCode::NoError;
6dfff36f
RG
2985 s_outqueries++;
2986 d_outqueries++;
2987
2988 if(d_outqueries + d_throttledqueries > s_maxqperq) {
2989 throw ImmediateServFailException("more than "+std::to_string(s_maxqperq)+" (max-qperq) queries sent while resolving "+qname.toLogString());
2990 }
2991
2992 if(s_maxtotusec && d_totUsec > s_maxtotusec) {
2993 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");
2994 }
2995
2996 if(doTCP) {
2997 LOG(prefix<<qname<<": using TCP with "<< remoteIP.toStringWithPort() <<endl);
2998 s_tcpoutqueries++;
2999 d_tcpoutqueries++;
3000 }
3001
3002 if(d_pdl && d_pdl->preoutquery(remoteIP, d_requestor, qname, qtype, doTCP, lwr.d_records, resolveret)) {
3003 LOG(prefix<<qname<<": query handled by Lua"<<endl);
3004 }
3005 else {
2fe3354d 3006 ednsmask=getEDNSSubnetMask(qname, remoteIP);
6dfff36f
RG
3007 if(ednsmask) {
3008 LOG(prefix<<qname<<": Adding EDNS Client Subnet Mask "<<ednsmask->toString()<<" to query"<<endl);
d6923beb 3009 s_ecsqueries++;
6dfff36f 3010 }
6de48f75 3011 resolveret = asyncresolveWrapper(remoteIP, d_doDNSSEC, qname, auth, qtype.getCode(),
deca7d8f 3012 doTCP, sendRDQuery, &d_now, ednsmask, &lwr, &chained); // <- we go out on the wire!
6dfff36f 3013 if(ednsmask) {
d6923beb 3014 s_ecsresponses++;
6dfff36f 3015 LOG(prefix<<qname<<": Received EDNS Client Subnet Mask "<<ednsmask->toString()<<" on response"<<endl);
c9783016
RG
3016 if (ednsmask->getBits() > 0) {
3017 if (ednsmask->isIpv4()) {
3018 ++SyncRes::s_ecsResponsesBySubnetSize4.at(ednsmask->getBits()-1);
3019 }
3020 else {
3021 ++SyncRes::s_ecsResponsesBySubnetSize6.at(ednsmask->getBits()-1);
3022 }
3023 }
6dfff36f
RG
3024 }
3025 }
3026
3027 /* preoutquery killed the query by setting dq.rcode to -3 */
3028 if(resolveret==-3) {
3029 throw ImmediateServFailException("Query killed by policy");
3030 }
3031
3032 d_totUsec += lwr.d_usec;
3033 accountAuthLatency(lwr.d_usec, remoteIP.sin4.sin_family);
3034
5c8c72bf
PL
3035 bool dontThrottle = false;
3036 {
3037 auto dontThrottleNames = g_dontThrottleNames.getLocal();
3038 auto dontThrottleNetmasks = g_dontThrottleNetmasks.getLocal();
3039 dontThrottle = dontThrottleNames->check(nsName) || dontThrottleNetmasks->match(remoteIP);
3040 }
3041
6dfff36f
RG
3042 if(resolveret != 1) {
3043 /* Error while resolving */
3044 if(resolveret == 0) {
3045 /* Time out */
3046
3047 LOG(prefix<<qname<<": timeout resolving after "<<lwr.d_usec/1000.0<<"msec "<< (doTCP ? "over TCP" : "")<<endl);
3048 d_timeouts++;
3049 s_outgoingtimeouts++;
3050
3051 if(remoteIP.sin4.sin_family == AF_INET)
3052 s_outgoing4timeouts++;
3053 else
3054 s_outgoing6timeouts++;
be9078b3 3055
3056 if(t_timeouts)
3057 t_timeouts->push_back(remoteIP);
6dfff36f
RG
3058 }
3059 else if(resolveret == -2) {
3060 /* OS resource limit reached */
3061 LOG(prefix<<qname<<": hit a local resource limit resolving"<< (doTCP ? " over TCP" : "")<<", probable error: "<<stringerror()<<endl);
3062 g_stats.resourceLimits++;
3063 }
3064 else {
3065 /* -1 means server unreachable */
3066 s_unreachables++;
3067 d_unreachables++;
3068 LOG(prefix<<qname<<": error resolving from "<<remoteIP.toString()<< (doTCP ? " over TCP" : "") <<", possible error: "<<strerror(errno)<< endl);
3069 }
3070
5c8c72bf 3071 if(resolveret != -2 && !chained && !dontThrottle) {
559b6c93
PL
3072 // don't account for resource limits, they are our own fault
3073 // And don't throttle when the IP address is on the dontThrottleNetmasks list or the name is part of dontThrottleNames
589884b8 3074 t_sstorage.nsSpeeds[nsName.empty()? DNSName(remoteIP.toStringWithPort()) : nsName].submit(remoteIP, 1000000, &d_now); // 1 sec
6dfff36f
RG
3075
3076 // code below makes sure we don't filter COM or the root
3077 if (s_serverdownmaxfails > 0 && (auth != g_rootdnsname) && t_sstorage.fails.incr(remoteIP) >= s_serverdownmaxfails) {
3078 LOG(prefix<<qname<<": Max fails reached resolving on "<< remoteIP.toString() <<". Going full throttle for "<< s_serverdownthrottletime <<" seconds" <<endl);
3079 // mark server as down
3080 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, "", 0), s_serverdownthrottletime, 10000);
3081 }
3082 else if (resolveret == -1) {
3083 // unreachable, 1 minute or 100 queries
3084 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 60, 100);
3085 }
3086 else {
559b6c93 3087 // timeout, 10 seconds or 5 queries
6dfff36f
RG
3088 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 10, 5);
3089 }
3090 }
3091
3092 return false;
3093 }
3094
3095 /* we got an answer */
3096 if(lwr.d_rcode==RCode::ServFail || lwr.d_rcode==RCode::Refused) {
3097 LOG(prefix<<qname<<": "<<nsName<<" ("<<remoteIP.toString()<<") returned a "<< (lwr.d_rcode==RCode::ServFail ? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl);
5c8c72bf 3098 if (!chained && !dontThrottle) {
deca7d8f
RG
3099 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 60, 3);
3100 }
6dfff36f
RG
3101 return false;
3102 }
3103
3104 /* this server sent a valid answer, mark it backup up if it was down */
3105 if(s_serverdownmaxfails > 0) {
3106 t_sstorage.fails.clear(remoteIP);
3107 }
3108
3109 if(lwr.d_tcbit) {
3110 *truncated = true;
3111
4ab4187c 3112 if (doTCP) {
6dfff36f 3113 LOG(prefix<<qname<<": truncated bit set, over TCP?"<<endl);
4ab4187c
PD
3114 if (!dontThrottle) {
3115 /* let's treat that as a ServFail answer from this server */
3116 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(remoteIP, qname, qtype.getCode()), 60, 3);
3117 }
6dfff36f
RG
3118 return false;
3119 }
b1f2295b 3120 LOG(prefix<<qname<<": truncated bit set, over UDP"<<endl);
6dfff36f
RG
3121
3122 return true;
3123 }
3124
3125 return true;
3126}
3127
51b6b728 3128bool 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
3129{
3130 string prefix;
3131 if(doLog()) {
3132 prefix=d_prefix;
3133 prefix.append(depth, ' ');
3134 }
3135
3136 if(s_minimumTTL) {
3137 for(auto& rec : lwr.d_records) {
3138 rec.d_ttl = max(rec.d_ttl, s_minimumTTL);
3139 }
3140 }
3141
5cf4b2e7
RG
3142 /* if the answer is ECS-specific, a minimum TTL is set for this kind of answers
3143 and it's higher than the global minimum TTL */
3144 if (ednsmask && s_minimumECSTTL > 0 && (s_minimumTTL == 0 || s_minimumECSTTL > s_minimumTTL)) {
3145 for(auto& rec : lwr.d_records) {
3146 if (rec.d_place == DNSResourceRecord::ANSWER) {
3147 rec.d_ttl = max(rec.d_ttl, s_minimumECSTTL);
3148 }
3149 }
3150 }
3151
2b984251 3152 bool needWildcardProof = false;
78cdf520 3153 bool gatherWildcardProof = false;
e4894ce0 3154 unsigned int wildcardLabelsCount;
78cdf520 3155 *rcode = updateCacheFromRecords(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, state, needWildcardProof, gatherWildcardProof, wildcardLabelsCount, sendRDQuery);
6dfff36f
RG
3156 if (*rcode != RCode::NoError) {
3157 return true;
3158 }
3159
3160 LOG(prefix<<qname<<": determining status after receiving this packet"<<endl);
3161
3162 set<DNSName> nsset;
3163 bool realreferral=false, negindic=false;
3164 DNSName newauth;
3165 DNSName newtarget;
3166
78cdf520 3167 bool done = processRecords(prefix, qname, qtype, auth, lwr, sendRDQuery, ret, nsset, newtarget, newauth, realreferral, negindic, state, needWildcardProof, gatherWildcardProof, wildcardLabelsCount);
6dfff36f
RG
3168
3169 if(done){
3170 LOG(prefix<<qname<<": status=got results, this level of recursion done"<<endl);
5374b03b 3171 LOG(prefix<<qname<<": validation status is "<<vStates[state]<<endl);
6dfff36f
RG
3172 *rcode = RCode::NoError;
3173 return true;
3174 }
3175
3176 if(!newtarget.empty()) {
3177 if(newtarget == qname) {
3178 LOG(prefix<<qname<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl);
3179 *rcode = RCode::ServFail;
3180 return true;
3181 }
3182
3183 if(depth > 10) {
3184 LOG(prefix<<qname<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl);
3185 *rcode = RCode::ServFail;
3186 return true;
3187 }
3188
5374b03b
RG
3189 if (qtype == QType::DS) {
3190 LOG(prefix<<qname<<": status=got a CNAME referral, but we are looking for a DS"<<endl);
6dfff36f 3191
1c39e884
RG
3192 if(d_doDNSSEC)
3193 addNXNSECS(ret, lwr.d_records);
3194
3195 *rcode = RCode::NoError;
3196 return true;
5374b03b
RG
3197 }
3198 else {
3199 LOG(prefix<<qname<<": status=got a CNAME referral, starting over with "<<newtarget<<endl);
6dfff36f 3200
5374b03b
RG
3201 set<GetBestNSAnswer> beenthere2;
3202 vState cnameState = Indeterminate;
3203 *rcode = doResolve(newtarget, qtype, ret, depth + 1, beenthere2, cnameState);
3204 LOG(prefix<<qname<<": updating validation state for response to "<<qname<<" from "<<vStates[state]<<" with the state from the CNAME quest: "<<vStates[cnameState]<<endl);
3205 updateValidationState(state, cnameState);
3206 return true;
3207 }
6dfff36f
RG
3208 }
3209
3210 if(lwr.d_rcode == RCode::NXDomain) {
3211 LOG(prefix<<qname<<": status=NXDOMAIN, we are done "<<(negindic ? "(have negative SOA)" : "")<<endl);
3212
3213 if(d_doDNSSEC)
3214 addNXNSECS(ret, lwr.d_records);
3215
3216 *rcode = RCode::NXDomain;
3217 return true;
3218 }
3219
3220 if(nsset.empty() && !lwr.d_rcode && (negindic || lwr.d_aabit || sendRDQuery)) {
3221 LOG(prefix<<qname<<": status=noerror, other types may exist, but we are done "<<(negindic ? "(have negative SOA) " : "")<<(lwr.d_aabit ? "(have aa bit) " : "")<<endl);
3222
6e9d3cae 3223 if(state == Secure && (lwr.d_aabit || sendRDQuery) && !negindic) {
114829cc
RG
3224 updateValidationState(state, Bogus);
3225 }
3226
6dfff36f
RG
3227 if(d_doDNSSEC)
3228 addNXNSECS(ret, lwr.d_records);
3229
3230 *rcode = RCode::NoError;
3231 return true;
3232 }
3233
3234 if(realreferral) {
3235 LOG(prefix<<qname<<": status=did not resolve, got "<<(unsigned int)nsset.size()<<" NS, ");
6dfff36f
RG
3236
3237 nameservers.clear();
3238 for (auto const &nameserver : nsset) {
3239 if (d_wantsRPZ) {
3240 d_appliedPolicy = dfe.getProcessingPolicy(nameserver, d_discardedPolicies);
3241 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
3242 LOG("however "<<nameserver<<" was blocked by RPZ policy '"<<(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")<<"'"<<endl);
3243 *rcode = -2;
3244 return true;
3245 }
3246 }
3247 nameservers.insert({nameserver, {{}, false}});
3248 }
3249 LOG("looping to them"<<endl);
3250 *gotNewServers = true;
812c3a69 3251 auth=newauth;
4d2be65d 3252
6dfff36f
RG
3253 return false;
3254 }
3255
3256 return false;
3257}
3258
b8470add
PL
3259/** returns:
3260 * -1 in case of no results
3261 * -2 when a FilterEngine Policy was hit
3262 * rcode otherwise
3263 */
fa1b87ff 3264int SyncRes::doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype,
e325f20c 3265 vector<DNSRecord>&ret,
116d1288 3266 unsigned int depth, set<GetBestNSAnswer>&beenthere, vState& state, StopAtDelegation* stopAtDelegation)
86c152f2 3267{
69cbdef9 3268 auto luaconfsLocal = g_luaconfs.getLocal();
ded77b10 3269 string prefix;
77499b05 3270 if(doLog()) {
ded77b10
BH
3271 prefix=d_prefix;
3272 prefix.append(depth, ' ');
3273 }
3ddb9247 3274
b8470add
PL
3275 LOG(prefix<<qname<<": Cache consultations done, have "<<(unsigned int)nameservers.size()<<" NS to contact");
3276
69cbdef9 3277 if (nameserversBlockedByRPZ(luaconfsLocal->dfe, nameservers)) {
26ca3513 3278 return -2;
b8470add
PL
3279 }
3280
3281 LOG(endl);
afbe2787
BH
3282
3283 for(;;) { // we may get more specific nameservers
feccaf7f 3284 auto rnameservers = shuffleInSpeedOrder(nameservers, doLog() ? (prefix+qname.toString()+": ") : string() );
3ddb9247 3285
26ca3513
RG
3286 for(auto tns=rnameservers.cbegin();;++tns) {
3287 if(tns==rnameservers.cend()) {
2189085d 3288 LOG(prefix<<qname<<": Failed to resolve via any of the "<<(unsigned int)rnameservers.size()<<" offered NS at level '"<<auth<<"'"<<endl);
03c09afe 3289 if(!auth.isRoot() && flawedNSSet) {
2189085d 3290 LOG(prefix<<qname<<": Ageing nameservers for level '"<<auth<<"', next query might succeed"<<endl);
88490c03 3291
49a699c4 3292 if(t_RC->doAgeCache(d_now.tv_sec, auth, QType::NS, 10))
4957a608
BH
3293 g_stats.nsSetInvalidations++;
3294 }
3295 return -1;
afbe2787 3296 }
6dfff36f 3297
b4c8789a
RG
3298 bool cacheOnly = false;
3299 // this line needs to identify the 'self-resolving' behaviour
feccaf7f 3300 if(qname == tns->first && (qtype.getCode() == QType::A || qtype.getCode() == QType::AAAA)) {
b4c8789a
RG
3301 /* we might have a glue entry in cache so let's try this NS
3302 but only if we have enough in the cache to know how to reach it */
3303 LOG(prefix<<qname<<": Using NS to resolve itself, but only using what we have in cache ("<<(1+tns-rnameservers.cbegin())<<"/"<<rnameservers.size()<<")"<<endl);
3304 cacheOnly = true;
20177d1d 3305 }
5605c067 3306
996c89cc 3307 typedef vector<ComboAddress> remoteIPs_t;
5605c067 3308 remoteIPs_t remoteIPs;
bfea0d0b 3309 remoteIPs_t::const_iterator remoteIP;
1c21f389 3310 bool pierceDontQuery=false;
c1d73d94 3311 bool sendRDQuery=false;
376effcf 3312 boost::optional<Netmask> ednsmask;
263f6a5a 3313 LWResult lwr;
feccaf7f 3314 const bool wasForwarded = tns->first.empty() && (!nameservers[tns->first].first.empty());
6dfff36f
RG
3315 int rcode = RCode::NoError;
3316 bool gotNewServers = false;
3317
feccaf7f 3318 if(tns->first.empty() && !wasForwarded) {
2189085d 3319 LOG(prefix<<qname<<": Domain is out-of-band"<<endl);
e1636f82
RG
3320 /* setting state to indeterminate since validation is disabled for local auth zone,
3321 and Insecure would be misleading. */
3322 state = Indeterminate;
9fc36e90 3323 d_wasOutOfBand = doOOBResolve(qname, qtype, lwr.d_records, depth, lwr.d_rcode);
4957a608
BH
3324 lwr.d_tcbit=false;
3325 lwr.d_aabit=true;
6dfff36f
RG
3326
3327 /* we have received an answer, are we done ? */
51b6b728 3328 bool done = processAnswer(depth, lwr, qname, qtype, auth, false, ednsmask, sendRDQuery, nameservers, ret, luaconfsLocal->dfe, &gotNewServers, &rcode, state);
6dfff36f
RG
3329 if (done) {
3330 return rcode;
3331 }
3332 if (gotNewServers) {
116d1288
OM
3333 if (stopAtDelegation && *stopAtDelegation == Stop) {
3334 *stopAtDelegation = Stopped;
3335 return rcode;
3336 }
6dfff36f
RG
3337 break;
3338 }
5605c067
BH
3339 }
3340 else {
6dfff36f 3341 /* if tns is empty, retrieveAddressesForNS() knows we have hardcoded servers (i.e. "forwards") */
b4c8789a 3342 remoteIPs = retrieveAddressesForNS(prefix, qname, tns, depth, beenthere, rnameservers, nameservers, sendRDQuery, pierceDontQuery, flawedNSSet, cacheOnly);
4957a608
BH
3343
3344 if(remoteIPs.empty()) {
feccaf7f 3345 LOG(prefix<<qname<<": Failed to get IP for NS "<<tns->first<<", trying next if available"<<endl);
4957a608
BH
3346 flawedNSSet=true;
3347 continue;
3348 }
3349 else {
b8470add 3350 bool hitPolicy{false};
feccaf7f 3351 LOG(prefix<<qname<<": Resolved '"<<auth<<"' NS "<<tns->first<<" to: ");
26ca3513
RG
3352 for(remoteIP = remoteIPs.cbegin(); remoteIP != remoteIPs.cend(); ++remoteIP) {
3353 if(remoteIP != remoteIPs.cbegin()) {
77499b05
BH
3354 LOG(", ");
3355 }
3356 LOG(remoteIP->toString());
69cbdef9 3357 if(nameserverIPBlockedByRPZ(luaconfsLocal->dfe, *remoteIP)) {
26ca3513 3358 hitPolicy = true;
b8470add 3359 }
4957a608 3360 }
77499b05 3361 LOG(endl);
b8470add
PL
3362 if (hitPolicy) //implies d_wantsRPZ
3363 return -2;
4957a608
BH
3364 }
3365
26ca3513 3366 for(remoteIP = remoteIPs.cbegin(); remoteIP != remoteIPs.cend(); ++remoteIP) {
2189085d 3367 LOG(prefix<<qname<<": Trying IP "<< remoteIP->toStringWithPort() <<", asking '"<<qname<<"|"<<qtype.getName()<<"'"<<endl);
6dfff36f 3368
26ca3513 3369 if (throttledOrBlocked(prefix, *remoteIP, qname, qtype, pierceDontQuery)) {
4957a608
BH
3370 continue;
3371 }
9de3e034 3372
6dfff36f
RG
3373 bool truncated = false;
3374 bool gotAnswer = doResolveAtThisIP(prefix, qname, qtype, lwr, ednsmask, auth, sendRDQuery,
feccaf7f 3375 tns->first, *remoteIP, false, &truncated);
6dfff36f
RG
3376 if (gotAnswer && truncated ) {
3377 /* retry, over TCP this time */
3378 gotAnswer = doResolveAtThisIP(prefix, qname, qtype, lwr, ednsmask, auth, sendRDQuery,
feccaf7f 3379 tns->first, *remoteIP, true, &truncated);
6dfff36f 3380 }
710af846 3381
6dfff36f
RG
3382 if (!gotAnswer) {
3383 continue;
3384 }
352b4183 3385
feccaf7f 3386 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 3387
6dfff36f
RG
3388 /* // for you IPv6 fanatics :-)
3389 if(remoteIP->sin4.sin_family==AF_INET6)
3390 lwr.d_usec/=3;
3391 */
3392 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
710af846 3393
feccaf7f 3394 t_sstorage.nsSpeeds[tns->first.empty()? DNSName(remoteIP->toStringWithPort()) : tns->first].submit(*remoteIP, lwr.d_usec, &d_now);
628e2c7b 3395
6dfff36f 3396 /* we have received an answer, are we done ? */
51b6b728 3397 bool done = processAnswer(depth, lwr, qname, qtype, auth, wasForwarded, ednsmask, sendRDQuery, nameservers, ret, luaconfsLocal->dfe, &gotNewServers, &rcode, state);
6dfff36f
RG
3398 if (done) {
3399 return rcode;
4957a608 3400 }
6dfff36f 3401 if (gotNewServers) {
116d1288
OM
3402 if (stopAtDelegation && *stopAtDelegation == Stop) {
3403 *stopAtDelegation = Stopped;
3404 return rcode;
3405 }
6dfff36f 3406 break;
4957a608 3407 }
6dfff36f
RG
3408 /* was lame */
3409 t_sstorage.throttle.throttle(d_now.tv_sec, boost::make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100);
4957a608 3410 }
aadceba8 3411
6dfff36f
RG
3412 if (gotNewServers) {
3413 break;
4957a608 3414 }
620db2c8 3415
6dfff36f
RG
3416 if(remoteIP == remoteIPs.cend()) // we tried all IP addresses, none worked
3417 continue;
620db2c8 3418
86c152f2
BH
3419 }
3420 }
86c152f2 3421 }
ac539791 3422 return -1;
86c152f2
BH
3423}
3424
2fe3354d 3425void SyncRes::setQuerySource(const ComboAddress& requestor, boost::optional<const EDNSSubnetOpts&> incomingECS)
8a3a3822 3426{
2fe3354d
CH
3427 d_requestor = requestor;
3428
3429 if (incomingECS && incomingECS->source.getBits() > 0) {
3430 d_cacheRemote = incomingECS->source.getMaskedNetwork();
3431 uint8_t bits = std::min(incomingECS->source.getBits(), (incomingECS->source.isIpv4() ? s_ecsipv4limit : s_ecsipv6limit));
3432 ComboAddress trunc = incomingECS->source.getNetwork();
3433 trunc.truncate(bits);
3434 d_outgoingECSNetwork = boost::optional<Netmask>(Netmask(trunc, bits));
3435 } else {
3436 d_cacheRemote = d_requestor;
3437 if(!incomingECS && s_ednslocalsubnets.match(d_requestor)) {
3438 ComboAddress trunc = d_requestor;
3439 uint8_t bits = d_requestor.isIPv4() ? 32 : 128;
3440 bits = std::min(bits, (trunc.isIPv4() ? s_ecsipv4limit : s_ecsipv6limit));
3441 trunc.truncate(bits);
3442 d_outgoingECSNetwork = boost::optional<Netmask>(Netmask(trunc, bits));
3443 } else if (s_ecsScopeZero.source.getBits() > 0) {
8a3a3822
RG
3444 /* RFC7871 says we MUST NOT send any ECS if the source scope is 0.
3445 But using an empty ECS in that case would mean inserting
3446 a non ECS-specific entry into the cache, preventing any further
3447 ECS-specific query to be sent.
3448 So instead we use the trick described in section 7.1.2:
3449 "The subsequent Recursive Resolver query to the Authoritative Nameserver
3450 will then either not include an ECS option or MAY optionally include
3451 its own address information, which is what the Authoritative
3452 Nameserver will almost certainly use to generate any Tailored
3453 Response in lieu of an option. This allows the answer to be handled
3454 by the same caching mechanism as other queries, with an explicit
3455 indicator of the applicable scope. Subsequent Stub Resolver queries
3456 for /0 can then be answered from this cached response.
3457 */
2fe3354d
CH
3458 d_outgoingECSNetwork = boost::optional<Netmask>(s_ecsScopeZero.source.getMaskedNetwork());
3459 d_cacheRemote = s_ecsScopeZero.source.getNetwork();
3460 } else {
3461 // ECS disabled because no scope-zero address could be derived.
3462 d_outgoingECSNetwork = boost::none;
8a3a3822
RG
3463 }
3464 }
8a3a3822
RG
3465}
3466
2fe3354d 3467boost::optional<Netmask> SyncRes::getEDNSSubnetMask(const DNSName& dn, const ComboAddress& rem)
e9f9b8ec 3468{
2fe3354d
CH
3469 if(d_outgoingECSNetwork && (s_ednsdomains.check(dn) || s_ednsremotesubnets.match(rem))) {
3470 return d_outgoingECSNetwork;
e9f9b8ec 3471 }
2fe3354d 3472 return boost::none;
e9f9b8ec 3473}
bd53ea9d 3474
9065eb05
RG
3475void SyncRes::parseEDNSSubnetWhitelist(const std::string& wlist)
3476{
3477 vector<string> parts;
3478 stringtok(parts, wlist, ",; ");
3479 for(const auto& a : parts) {
3480 try {
2fe3354d 3481 s_ednsremotesubnets.addMask(Netmask(a));
9065eb05
RG
3482 }
3483 catch(...) {
3484 s_ednsdomains.add(DNSName(a));
3485 }
3486 }
3487}
3488
2fe3354d
CH
3489void SyncRes::parseEDNSSubnetAddFor(const std::string& subnetlist)
3490{
3491 vector<string> parts;
3492 stringtok(parts, subnetlist, ",; ");
3493 for(const auto& a : parts) {
3494 s_ednslocalsubnets.addMask(a);
3495 }
3496}
3497
8ce79a22 3498// used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
a3e7b735 3499int directResolve(const DNSName& qname, const QType& qtype, int qclass, vector<DNSRecord>& ret)
bd53ea9d
PD
3500{
3501 struct timeval now;
3502 gettimeofday(&now, 0);
710af846 3503
bd53ea9d 3504 SyncRes sr(now);
13658071
RB
3505 int res = -1;
3506 try {
3507 res = sr.beginResolve(qname, QType(qtype), qclass, ret);
3508 }
3509 catch(const PDNSException& e) {
3510 g_log<<Logger::Error<<"Failed to resolve "<<qname.toLogString()<<", got pdns exception: "<<e.reason<<endl;
3511 ret.clear();
3512 }
3513 catch(const ImmediateServFailException& e) {
3514 g_log<<Logger::Error<<"Failed to resolve "<<qname.toLogString()<<", got ImmediateServFailException: "<<e.reason<<endl;
3515 ret.clear();
3516 }
3517 catch(const std::exception& e) {
3518 g_log<<Logger::Error<<"Failed to resolve "<<qname.toLogString()<<", got STL error: "<<e.what()<<endl;
3519 ret.clear();
3520 }
3521 catch(...) {
3522 g_log<<Logger::Error<<"Failed to resolve "<<qname.toLogString()<<", got an exception"<<endl;
3523 ret.clear();
3524 }
e325f20c 3525
bd53ea9d
PD
3526 return res;
3527}
30ee601a 3528
30ee601a
RG
3529int SyncRes::getRootNS(struct timeval now, asyncresolve_t asyncCallback) {
3530 SyncRes sr(now);
3531 sr.setDoEDNS0(true);
0b29b9c5 3532 sr.setUpdatingRootNS();
30ee601a 3533 sr.setDoDNSSEC(g_dnssecmode != DNSSECMode::Off);
0c43f455 3534 sr.setDNSSECValidationRequested(g_dnssecmode != DNSSECMode::Off && g_dnssecmode != DNSSECMode::ProcessNoValidate);
30ee601a
RG
3535 sr.setAsyncCallback(asyncCallback);
3536
3537 vector<DNSRecord> ret;
3538 int res=-1;
3539 try {
3540 res=sr.beginResolve(g_rootdnsname, QType(QType::NS), 1, ret);
3541 if (g_dnssecmode != DNSSECMode::Off && g_dnssecmode != DNSSECMode::ProcessNoValidate) {
4d2be65d 3542 auto state = sr.getValidationState();
30ee601a
RG
3543 if (state == Bogus)
3544 throw PDNSException("Got Bogus validation result for .|NS");
3545 }
3546 return res;
3547 }
c78ceb39 3548 catch(const PDNSException& e) {
e6a9dde5 3549 g_log<<Logger::Error<<"Failed to update . records, got an exception: "<<e.reason<<endl;
30ee601a 3550 }
c78ceb39 3551 catch(const ImmediateServFailException& e) {
e6a9dde5 3552 g_log<<Logger::Error<<"Failed to update . records, got an exception: "<<e.reason<<endl;
c78ceb39
RG
3553 }
3554 catch(const std::exception& e) {
e6a9dde5 3555 g_log<<Logger::Error<<"Failed to update . records, got an exception: "<<e.what()<<endl;
30ee601a 3556 }
c78ceb39 3557 catch(...) {
e6a9dde5 3558 g_log<<Logger::Error<<"Failed to update . records, got an exception"<<endl;
30ee601a 3559 }
c78ceb39 3560
30ee601a 3561 if(!res) {
e6a9dde5 3562 g_log<<Logger::Notice<<"Refreshed . records"<<endl;
30ee601a
RG
3563 }
3564 else
e6a9dde5 3565 g_log<<Logger::Error<<"Failed to update . records, RCODE="<<res<<endl;
c78ceb39 3566
30ee601a
RG
3567 return res;
3568}