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