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