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