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