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