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