]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/syncres.cc
rec: Fix shadowed variables
[thirdparty/pdns.git] / pdns / syncres.cc
CommitLineData
86c152f2
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
7e2e4419 3 Copyright (C) 2003 - 2015 PowerDNS.COM BV
86c152f2
BH
4
5 This program is free software; you can redistribute it and/or modify
710af846 6 it under the terms of the GNU General Public License version 2 as published
36c5ee42 7 by the Free Software Foundation
86c152f2 8
f782fe38
MH
9 Additionally, the license of this program contains a special
10 exception which allows to distribute the program in binary form when
11 it is linked against OpenSSL.
12
86c152f2
BH
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
06bd9ccf 20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
86c152f2 21*/
caa6eefa 22
870a0fe4
AT
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
c9f52071 26#include <boost/algorithm/string.hpp>
fa8fd4d2 27
a3e7b735 28#include "lua-recursor4.hh"
caa6eefa 29#include "utility.hh"
288f4aa9 30#include "syncres.hh"
86c152f2
BH
31#include <iostream>
32#include <map>
57769f13 33#include "dnsrecords.hh"
86c152f2 34#include <algorithm>
afbe2787 35#include <set>
86c152f2
BH
36#include <cerrno>
37#include <cstdio>
38#include <cstdlib>
86c152f2 39#include <utility>
3de83124 40#include <deque>
c836dc19 41#include "logger.hh"
620db2c8 42#include "validate.hh"
20177d1d 43#include "misc.hh"
86c152f2
BH
44#include "arguments.hh"
45#include "lwres.hh"
eefd15f9 46#include "recursor_cache.hh"
ea634573 47#include "dnsparser.hh"
51e2144e 48#include "dns_random.hh"
bb4bdbaf 49#include "lock.hh"
376effcf 50#include "ednssubnet.hh"
c2567ad1 51#include "cachecleaner.hh"
ad42489c 52#include "rec-lua-conf.hh"
ac0e821b 53__thread SyncRes::StaticStorage* t_sstorage;
bb4bdbaf 54
a9af3782 55unsigned int SyncRes::s_maxnegttl;
c3e753c7 56unsigned int SyncRes::s_maxcachettl;
1051f8a9
BH
57unsigned int SyncRes::s_packetcachettl;
58unsigned int SyncRes::s_packetcacheservfailttl;
628e2c7b
PA
59unsigned int SyncRes::s_serverdownmaxfails;
60unsigned int SyncRes::s_serverdownthrottletime;
aebb81e4 61std::atomic<uint64_t> SyncRes::s_queries;
62std::atomic<uint64_t> SyncRes::s_outgoingtimeouts;
63std::atomic<uint64_t> SyncRes::s_outgoing4timeouts;
64std::atomic<uint64_t> SyncRes::s_outgoing6timeouts;
65std::atomic<uint64_t> SyncRes::s_outqueries;
66std::atomic<uint64_t> SyncRes::s_tcpoutqueries;
67std::atomic<uint64_t> SyncRes::s_throttledqueries;
68std::atomic<uint64_t> SyncRes::s_dontqueries;
69std::atomic<uint64_t> SyncRes::s_nodelegated;
70std::atomic<uint64_t> SyncRes::s_unreachables;
aadceba8 71unsigned int SyncRes::s_minimumTTL;
996c89cc 72bool SyncRes::s_doIPv6;
1051f8a9 73bool SyncRes::s_nopacketcache;
01402d56 74bool SyncRes::s_rootNXTrust;
173d790e 75unsigned int SyncRes::s_maxqperq;
9de3e034 76unsigned int SyncRes::s_maxtotusec;
7c3398aa 77unsigned int SyncRes::s_maxdepth;
a9af3782 78string SyncRes::s_serverID;
77499b05 79SyncRes::LogMode SyncRes::s_lm;
c836dc19 80
77499b05 81#define LOG(x) if(d_lm == Log) { L <<Logger::Warning << x; } else if(d_lm == Store) { d_trace << x; }
728485ca 82
4bfae16d 83bool SyncRes::s_noEDNS;
3de83124 84
7b75810e 85void accountAuthLatency(int usec, int family)
11adfdd3 86{
7b75810e 87 if(family == AF_INET) {
88 if(usec < 1000)
89 g_stats.auth4Answers0_1++;
90 else if(usec < 10000)
91 g_stats.auth4Answers1_10++;
92 else if(usec < 100000)
93 g_stats.auth4Answers10_100++;
94 else if(usec < 1000000)
95 g_stats.auth4Answers100_1000++;
96 else
97 g_stats.auth4AnswersSlow++;
98 } else {
99 if(usec < 1000)
100 g_stats.auth6Answers0_1++;
101 else if(usec < 10000)
102 g_stats.auth6Answers1_10++;
103 else if(usec < 100000)
104 g_stats.auth6Answers10_100++;
105 else if(usec < 1000000)
106 g_stats.auth6Answers100_1000++;
107 else
108 g_stats.auth6AnswersSlow++;
109 }
110
11adfdd3 111}
112
4465e941 113
ac0e821b 114SyncRes::SyncRes(const struct timeval& now) : d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
57769f13 115 d_totUsec(0), d_doDNSSEC(false), d_now(now),
116 d_cacheonly(false), d_nocache(false), d_doEDNS0(false), d_lm(s_lm)
232f0877 117
ac0e821b
BH
118{
119 if(!t_sstorage) {
120 t_sstorage = new StaticStorage();
121 }
122}
123
728485ca 124/** everything begins here - this is the entry point just after receiving a packet */
e325f20c 125int SyncRes::beginResolve(const DNSName &qname, const QType &qtype, uint16_t qclass, vector<DNSRecord>&ret)
728485ca 126{
c836dc19 127 s_queries++;
3762e821 128 d_wasVariable=false;
9fc36e90 129 d_wasOutOfBand=false;
710af846
PL
130
131 if( (qtype.getCode() == QType::AXFR))
693dbe65 132 return -1;
710af846 133
8171ab83 134 static const DNSName arpa("1.0.0.127.in-addr.arpa."), localhost("localhost."),
135 versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns.");
136
137 if( (qtype.getCode()==QType::PTR && qname==arpa) ||
138 (qtype.getCode()==QType::A && qname==localhost)) {
31ad43ab 139 ret.clear();
e325f20c 140 DNSRecord dr;
141 dr.d_name=qname;
e693ff5a 142 dr.d_place = DNSResourceRecord::ANSWER;
e325f20c 143 dr.d_type=qtype.getCode();
144 dr.d_class=QClass::IN;
145 dr.d_ttl=86400;
31ad43ab 146 if(qtype.getCode()==QType::PTR)
e325f20c 147 dr.d_content=shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(QType::PTR, 1, "localhost."));
31ad43ab 148 else
e325f20c 149 dr.d_content=shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(QType::A, 1, "127.0.0.1"));
150 ret.push_back(dr);
9fc36e90 151 d_wasOutOfBand=true;
31ad43ab
BH
152 return 0;
153 }
154
703761cc 155 if(qclass==QClass::CHAOS && qtype.getCode()==QType::TXT &&
8171ab83 156 (qname==versionbind || qname==idserver || qname==versionpdns )
a9af3782
BH
157 ) {
158 ret.clear();
e325f20c 159 DNSRecord dr;
160 dr.d_name=qname;
161 dr.d_type=qtype.getCode();
162 dr.d_class=qclass;
163 dr.d_ttl=86400;
e693ff5a 164 dr.d_place = DNSResourceRecord::ANSWER;
8171ab83 165 if(qname==versionbind || qname==versionpdns)
e325f20c 166 dr.d_content=shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(QType::TXT, 3, "\""+::arg()["version-string"]+"\""));
a9af3782 167 else
e325f20c 168 dr.d_content=shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(QType::TXT, 3, "\""+s_serverID+"\""));
169
170 ret.push_back(dr);
9fc36e90 171 d_wasOutOfBand=true;
a9af3782
BH
172 return 0;
173 }
710af846 174
703761cc
KM
175 if(qclass==QClass::ANY)
176 qclass=QClass::IN;
177 else if(qclass!=QClass::IN)
9a97cc5c 178 return -1;
710af846 179
31ad43ab 180 set<GetBestNSAnswer> beenthere;
809fe23f 181 int res=doResolve(qname, qtype, ret, 0, beenthere);
728485ca
BH
182 return res;
183}
afbe2787 184
ab5c053d 185//! This is the 'out of band resolver', in other words, the authoritative server
7c3398aa 186bool SyncRes::doOOBResolve(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int& res)
e93c956b 187{
5605c067 188 string prefix;
77499b05 189 if(doLog()) {
5605c067
BH
190 prefix=d_prefix;
191 prefix.append(depth, ' ');
192 }
193
2189085d 194 LOG(prefix<<qname<<": checking auth storage for '"<<qname<<"|"<<qtype.getName()<<"'"<<endl);
c5c066bf 195 DNSName authdomain(qname);
5605c067
BH
196
197 domainmap_t::const_iterator iter=getBestAuthZone(&authdomain);
49a699c4 198 if(iter==t_sstorage->domainmap->end()) {
2189085d 199 LOG(prefix<<qname<<": auth storage has no zone for this query!"<<endl);
5605c067
BH
200 return false;
201 }
2189085d 202 LOG(prefix<<qname<<": auth storage has data, zone='"<<authdomain<<"'"<<endl);
5605c067
BH
203 pair<AuthDomain::records_t::const_iterator, AuthDomain::records_t::const_iterator> range;
204
205 range=iter->second.d_records.equal_range(tie(qname)); // partial lookup
7bddb139 206
5605c067
BH
207 ret.clear();
208 AuthDomain::records_t::const_iterator ziter;
9e9844e2 209 bool somedata=false;
5605c067 210 for(ziter=range.first; ziter!=range.second; ++ziter) {
9e9844e2 211 somedata=true;
e325f20c 212 if(qtype.getCode()==QType::ANY || ziter->d_type==qtype.getCode() || ziter->d_type==QType::CNAME) // let rest of nameserver do the legwork on this one
5605c067 213 ret.push_back(*ziter);
221a3f72 214 else if(ziter->d_type == QType::NS && ziter->d_name.countLabels() > authdomain.countLabels()) { // we hit a delegation point!
39eb8051 215 DNSRecord dr=*ziter;
216 dr.d_place=DNSResourceRecord::AUTHORITY;
217 ret.push_back(dr);
218 }
5605c067 219 }
9bc8c14c 220 if(!ret.empty()) {
2189085d 221 LOG(prefix<<qname<<": exact match in zone '"<<authdomain<<"'"<<endl);
9bc8c14c
BH
222 res=0;
223 return true;
5605c067 224 }
9e9844e2 225 if(somedata) {
2189085d 226 LOG(prefix<<qname<<": found record in '"<<authdomain<<"', but nothing of the right type, sending SOA"<<endl);
e325f20c 227 ziter=iter->second.d_records.find(boost::make_tuple(authdomain, QType::SOA));
9e9844e2 228 if(ziter!=iter->second.d_records.end()) {
e325f20c 229 DNSRecord dr=*ziter;
e693ff5a 230 dr.d_place=DNSResourceRecord::AUTHORITY;
e325f20c 231 ret.push_back(dr);
9e9844e2
BH
232 }
233 else
2189085d 234 LOG(prefix<<qname<<": can't find SOA record '"<<authdomain<<"' in our zone!"<<endl);
9e9844e2
BH
235 res=RCode::NoError;
236 return true;
237 }
5605c067 238
2189085d 239 LOG(prefix<<qname<<": nothing found so far in '"<<authdomain<<"', trying wildcards"<<endl);
c5c066bf 240 DNSName wcarddomain(qname);
e325f20c 241 while(wcarddomain != iter->first && wcarddomain.chopOff()) {
2189085d 242 LOG(prefix<<qname<<": trying '*."<<wcarddomain<<"' in "<<authdomain<<endl);
12c06211 243 range=iter->second.d_records.equal_range(boost::make_tuple(g_wildcarddnsname+wcarddomain));
0d1e259a
BH
244 if(range.first==range.second)
245 continue;
246
247 for(ziter=range.first; ziter!=range.second; ++ziter) {
e325f20c 248 DNSRecord dr=*ziter;
249 if(dr.d_type == qtype.getCode() || qtype.getCode() == QType::ANY) {
250 dr.d_name = qname;
e693ff5a 251 dr.d_place=DNSResourceRecord::ANSWER;
e325f20c 252 ret.push_back(dr);
0d1e259a
BH
253 }
254 }
2189085d 255 LOG(prefix<<qname<<": in '"<<authdomain<<"', had wildcard match on '*."<<wcarddomain<<"'"<<endl);
0d1e259a
BH
256 res=RCode::NoError;
257 return true;
258 }
259
c5c066bf 260 DNSName nsdomain(qname);
5605c067 261
e325f20c 262 while(nsdomain.chopOff() && nsdomain != iter->first) {
263 range=iter->second.d_records.equal_range(boost::make_tuple(nsdomain,QType::NS));
5605c067
BH
264 if(range.first==range.second)
265 continue;
266
267 for(ziter=range.first; ziter!=range.second; ++ziter) {
e325f20c 268 DNSRecord dr=*ziter;
e693ff5a 269 dr.d_place=DNSResourceRecord::AUTHORITY;
e325f20c 270 ret.push_back(dr);
5605c067
BH
271 }
272 }
3ddb9247 273 if(ret.empty()) {
2189085d 274 LOG(prefix<<qname<<": no NS match in zone '"<<authdomain<<"' either, handing out SOA"<<endl);
e325f20c 275 ziter=iter->second.d_records.find(boost::make_tuple(authdomain, QType::SOA));
5605c067 276 if(ziter!=iter->second.d_records.end()) {
e325f20c 277 DNSRecord dr=*ziter;
e693ff5a 278 dr.d_place=DNSResourceRecord::AUTHORITY;
e325f20c 279 ret.push_back(dr);
5605c067 280 }
e325f20c 281 else {
2189085d 282 LOG(prefix<<qname<<": can't find SOA record '"<<authdomain<<"' in our zone!"<<endl);
e325f20c 283 }
5605c067
BH
284 res=RCode::NXDomain;
285 }
710af846 286 else
5605c067
BH
287 res=0;
288
9e9844e2 289 return true;
e93c956b
BH
290}
291
ff1872cf
BH
292void SyncRes::doEDNSDumpAndClose(int fd)
293{
294 FILE* fp=fdopen(fd, "w");
a82f68f0
RG
295 if (!fp) {
296 return;
297 }
ff1872cf 298 fprintf(fp,"IP Address\tMode\tMode last updated at\n");
57769f13 299 for(const auto& eds : t_sstorage->ednsstatus) {
300 fprintf(fp, "%s\t%d\t%s", eds.first.toString().c_str(), (int)eds.second.mode, ctime(&eds.second.modeSetAt));
ff1872cf 301 }
bb4bdbaf 302
ff1872cf
BH
303 fclose(fp);
304}
305
9d534f2a 306/* so here is the story. First we complete the full resolution process for a domain name. And only THEN do we decide
307 to also do DNSSEC validation, which leads to new queries. To make this simple, we *always* ask for DNSSEC records
308 so that if there are RRSIGs for a name, we'll have them.
309
310 However, some hosts simply can't answer questions which ask for DNSSEC. This can manifest itself as:
311 * No answer
312 * FormErr
313 * Nonsense answer
314
315 The cause of "No answer" may be fragmentation, and it is tempting to probe if smaller answers would get through.
316 Another cause of "No answer" may simply be a network condition.
317 Nonsense answers are a clearer indication this host won't be able to do DNSSEC evah.
318
319 Previous implementations have suffered from turning off DNSSEC questions for an authoritative server based on timeouts.
320 A clever idea is to only turn off DNSSEC if we know a domain isn't signed anyhow. The problem with that really
321 clever idea however is that at this point in PowerDNS, we may simply not know that yet. All the DNSSEC thinking happens
322 elsewhere. It may not have happened yet.
323
324 For now this means we can't be clever, but will turn off DNSSEC if you reply with FormError or gibberish.
325*/
326
12ce523e 327int 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)
81883dcc
BH
328{
329 /* what is your QUEST?
57769f13 330 the goal is to get as many remotes as possible on the highest level of EDNS support
81883dcc
BH
331 The levels are:
332
81883dcc 333 0) UNKNOWN Unknown state
57769f13 334 1) EDNS: Honors EDNS0
335 2) EDNSIGNORANT: Ignores EDNS0, gives replies without EDNS0
9d534f2a 336 3) NOEDNS: Generates FORMERR/NOTIMP on EDNS queries
81883dcc
BH
337
338 Everybody starts out assumed to be '0'.
57769f13 339 If '0', send out EDNS0
340 If you FORMERR us, go to '3',
341 If no EDNS in response, go to '2'
342 If '1', send out EDNS0
343 If FORMERR, downgrade to 3
344 If '2', keep on including EDNS0, see what happens
81883dcc 345 Same behaviour as 0
57769f13 346 If '3', send bare queries
81883dcc
BH
347 */
348
bb4bdbaf 349 SyncRes::EDNSStatus* ednsstatus;
57769f13 350 ednsstatus = &t_sstorage->ednsstatus[ip]; // does this include port?
81883dcc 351
bb4bdbaf
BH
352 if(ednsstatus->modeSetAt && ednsstatus->modeSetAt + 3600 < d_now.tv_sec) {
353 *ednsstatus=SyncRes::EDNSStatus();
77499b05 354 // cerr<<"Resetting EDNS Status for "<<ip.toString()<<endl);
81883dcc
BH
355 }
356
bb4bdbaf 357 SyncRes::EDNSStatus::EDNSMode& mode=ednsstatus->mode;
81883dcc
BH
358 SyncRes::EDNSStatus::EDNSMode oldmode = mode;
359 int EDNSLevel=0;
4898a348
RG
360 auto luaconfsLocal = g_luaconfs.getLocal();
361 ResolveContext ctx;
362#ifdef HAVE_PROTOBUF
363 ctx.d_initialRequestId = d_initialRequestId;
364#endif
81883dcc
BH
365
366 int ret;
ff1872cf 367 for(int tries = 0; tries < 3; ++tries) {
e325f20c 368 // cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl;
57769f13 369
9d534f2a 370 if(mode==EDNSStatus::NOEDNS) {
81883dcc 371 g_stats.noEdnsOutQueries++;
9d534f2a 372 EDNSLevel = 0; // level != mode
81883dcc 373 }
9d534f2a 374 else if(ednsMANDATORY || mode==EDNSStatus::UNKNOWN || mode==EDNSStatus::EDNSOK || mode==EDNSStatus::EDNSIGNORANT)
375 EDNSLevel = 1;
57769f13 376
4898a348 377 ret=asyncresolve(ip, domain, type, doTCP, sendRDQuery, EDNSLevel, now, srcmask, ctx, luaconfsLocal->outgoingProtobufServer, res);
9d534f2a 378 if(ret < 0) {
379 return ret; // transport error, nothing to learn here
380 }
57769f13 381
9d534f2a 382 if(ret == 0) { // timeout, not doing anything with it now
81883dcc
BH
383 return ret;
384 }
57769f13 385 else if(mode==EDNSStatus::UNKNOWN || mode==EDNSStatus::EDNSOK || mode == EDNSStatus::EDNSIGNORANT ) {
386 if(res->d_rcode == RCode::FormErr || res->d_rcode == RCode::NotImp) {
2189085d 387 // cerr<<"Downgrading to NOEDNS because of "<<RCode::to_s(res->d_rcode)<<" for query to "<<ip.toString()<<" for '"<<domain<<"'"<<endl;
57769f13 388 mode = EDNSStatus::NOEDNS;
4957a608 389 continue;
81883dcc 390 }
81883dcc 391 else if(!res->d_haveEDNS) {
4957a608
BH
392 if(mode != EDNSStatus::EDNSIGNORANT) {
393 mode = EDNSStatus::EDNSIGNORANT;
2189085d 394 // cerr<<"We find that "<<ip.toString()<<" is an EDNS-ignorer for '"<<domain<<"', moving to mode 3"<<endl;
57769f13 395 }
81883dcc 396 }
57769f13 397 else {
398 mode = EDNSStatus::EDNSOK;
e325f20c 399 // cerr<<"We find that "<<ip.toString()<<" is EDNS OK!"<<endl;
81883dcc 400 }
57769f13 401
81883dcc 402 }
12ce523e 403 if(oldmode != mode || !ednsstatus->modeSetAt)
bb4bdbaf 404 ednsstatus->modeSetAt=d_now.tv_sec;
e325f20c 405 // cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", new mode: "<<mode<<endl;
81883dcc
BH
406 return ret;
407 }
408 return ret;
409}
410
7c3398aa 411int SyncRes::doResolve(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, set<GetBestNSAnswer>& beenthere)
afbe2787 412{
ded77b10 413 string prefix;
77499b05 414 if(doLog()) {
ded77b10
BH
415 prefix=d_prefix;
416 prefix.append(depth, ' ');
417 }
b8470add 418
2189085d 419 LOG(prefix<<qname<<": Wants "<< (d_doDNSSEC ? "" : "NO ") << "DNSSEC processing in query for "<<qtype.getName()<<endl);
710af846 420
7c3398aa
RG
421 if(s_maxdepth && depth > s_maxdepth)
422 throw ImmediateServFailException("More than "+std::to_string(s_maxdepth)+" (max-recursion-depth) levels of recursion needed while resolving "+qname.toLogString());
423
f4df5e89 424 int res=0;
52683ca3 425 if(!(d_nocache && qtype.getCode()==QType::NS && qname.isRoot())) {
115d07ad 426 if(d_cacheonly) { // very limited OOB support
263f6a5a 427 LWResult lwr;
2189085d 428 LOG(prefix<<qname<<": Recursion not requested for '"<<qname<<"|"<<qtype.getName()<<"', peeking at auth/forward zones"<<endl);
c5c066bf 429 DNSName authname(qname);
115d07ad 430 domainmap_t::const_iterator iter=getBestAuthZone(&authname);
49a699c4 431 if(iter != t_sstorage->domainmap->end()) {
4957a608
BH
432 const vector<ComboAddress>& servers = iter->second.d_servers;
433 if(servers.empty()) {
434 ret.clear();
9fc36e90 435 d_wasOutOfBand = doOOBResolve(qname, qtype, ret, depth, res);
4957a608
BH
436 return res;
437 }
438 else {
439 const ComboAddress remoteIP = servers.front();
2189085d 440 LOG(prefix<<qname<<": forwarding query to hardcoded nameserver '"<< remoteIP.toStringWithPort()<<"' for zone '"<<authname<<"'"<<endl);
4957a608 441
376effcf 442 boost::optional<Netmask> nm;
12ce523e 443 res=asyncresolveWrapper(remoteIP, d_doDNSSEC, qname, qtype.getCode(), false, false, &d_now, nm, &lwr);
4957a608
BH
444 // filter out the good stuff from lwr.result()
445
48b560ea 446 for(const auto& rec : lwr.d_records) {
e693ff5a 447 if(rec.d_place == DNSResourceRecord::ANSWER)
e325f20c 448 ret.push_back(rec);
4957a608
BH
449 }
450 return res;
451 }
115d07ad
BH
452 }
453 }
454
a672e9de 455 if(!d_skipCNAMECheck && doCNAMECacheCheck(qname,qtype,ret,depth,res)) // will reroute us if needed
c836dc19 456 return res;
710af846 457
c836dc19
BH
458 if(doCacheCheck(qname,qtype,ret,depth,res)) // we done
459 return res;
460 }
afbe2787 461
115d07ad 462 if(d_cacheonly)
c836dc19 463 return 0;
728485ca 464
2189085d 465 LOG(prefix<<qname<<": No cache hit for '"<<qname<<"|"<<qtype.getName()<<"', trying to find an appropriate NS record"<<endl);
710af846 466
c5c066bf 467 DNSName subdomain(qname);
d8049162 468 if(qtype == QType::DS) subdomain.chopOff();
728485ca 469
fa1b87ff 470 NsSet nsset;
7305df82 471 bool flawedNSSet=false;
97df07f8
PD
472
473 // the two retries allow getBestNSNamesFromCache&co to reprime the root
474 // hints, in case they ever go missing
bdf40704 475 for(int tries=0;tries<2 && nsset.empty();++tries) {
891fbf88 476 subdomain=getBestNSNamesFromCache(subdomain, qtype, nsset, &flawedNSSet, depth, beenthere); // pass beenthere to both occasions
bdf40704
BH
477 }
478
7305df82 479 if(!(res=doResolveAt(nsset, subdomain, flawedNSSet, qname, qtype, ret, depth, beenthere)))
728485ca 480 return 0;
3ddb9247 481
2189085d 482 LOG(prefix<<qname<<": failed (res="<<res<<")"<<endl);
e325f20c 483 ;
b8470add
PL
484
485 if (res == -2)
486 return res;
487
20177d1d 488 return res<0 ? RCode::ServFail : res;
afbe2787
BH
489}
490
c2567ad1 491#if 0
a67dd0cf 492// for testing purposes
fdf05fd4
BH
493static bool ipv6First(const ComboAddress& a, const ComboAddress& b)
494{
495 return !(a.sin4.sin_family < a.sin4.sin_family);
496}
c2567ad1 497#endif
fdf05fd4 498
21f0f88b 499/** This function explicitly goes out for A or AAAA addresses
996c89cc 500*/
7c3398aa 501vector<ComboAddress> SyncRes::getAddrs(const DNSName &qname, unsigned int depth, set<GetBestNSAnswer>& beenthere)
75b49099 502{
e325f20c 503 typedef vector<DNSRecord> res_t;
bfea0d0b 504 res_t res;
75b49099 505
996c89cc
BH
506 typedef vector<ComboAddress> ret_t;
507 ret_t ret;
75b49099 508
d96e88da 509 QType type;
92011b8f 510
511 for(int j=1; j<2+s_doIPv6; j++)
d96e88da 512 {
76c01aec 513 bool done=false;
76c01aec
PD
514 switch(j) {
515 case 0:
516 type = QType::ANY;
517 break;
518 case 1:
519 type = QType::A;
520 break;
521 case 2:
522 type = QType::AAAA;
523 break;
524 }
d96e88da 525
891fbf88 526 if(!doResolve(qname, type, res,depth+1, beenthere) && !res.empty()) { // this consults cache, OR goes out
d96e88da 527 for(res_t::const_iterator i=res.begin(); i!= res.end(); ++i) {
e325f20c 528 if(i->d_type == QType::A || i->d_type == QType::AAAA) {
529 if(auto rec = std::dynamic_pointer_cast<ARecordContent>(i->d_content))
530 ret.push_back(rec->getCA(53));
dd079764
RG
531 else if(auto aaaarec = std::dynamic_pointer_cast<AAAARecordContent>(i->d_content))
532 ret.push_back(aaaarec->getCA(53));
92011b8f 533 done=true;
d96e88da 534 }
42724edf 535 }
f4df5e89 536 }
710af846 537 if(done) {
60c9a54f 538 if(j==1 && s_doIPv6) { // we got an A record, see if we have some AAAA lying around
e325f20c 539 vector<DNSRecord> cset;
376effcf 540 if(t_RC->get(d_now.tv_sec, qname, QType(QType::AAAA), &cset, d_requestor) > 0) {
e325f20c 541 for(auto k=cset.cbegin();k!=cset.cend();++k) {
542 if(k->d_ttl > (unsigned int)d_now.tv_sec ) {
ba3c54cb
RG
543 if (auto drc = std::dynamic_pointer_cast<AAAARecordContent>(k->d_content)) {
544 ComboAddress ca=drc->getCA(53);
545 ret.push_back(ca);
546 }
60c9a54f 547 }
548 }
549 }
550 }
551 break;
552 }
bfea0d0b 553 }
710af846 554
996c89cc 555 if(ret.size() > 1) {
51e2144e 556 random_shuffle(ret.begin(), ret.end(), dns_random);
996c89cc 557
ae4d8cf1 558 // move 'best' address for this nameserver name up front
5ea6f7de 559 nsspeeds_t::iterator best = t_sstorage->nsSpeeds.find(qname);
996c89cc 560
49a699c4 561 if(best != t_sstorage->nsSpeeds.end())
710af846 562 for(ret_t::iterator i=ret.begin(); i != ret.end(); ++i) {
4957a608
BH
563 if(*i==best->second.d_best) { // got the fastest one
564 if(i!=ret.begin()) {
565 *i=*ret.begin();
566 *ret.begin()=best->second.d_best;
567 }
568 break;
569 }
996c89cc
BH
570 }
571 }
fdf05fd4 572
728485ca 573 return ret;
75b49099
BH
574}
575
7c3398aa 576void SyncRes::getBestNSFromCache(const DNSName &qname, const QType& qtype, vector<DNSRecord>& bestns, bool* flawedNSSet, unsigned int depth, set<GetBestNSAnswer>& beenthere)
86c152f2 577{
c5c066bf
PD
578 string prefix;
579 DNSName subdomain(qname);
77499b05 580 if(doLog()) {
ded77b10
BH
581 prefix=d_prefix;
582 prefix.append(depth, ' ');
583 }
75b49099 584 bestns.clear();
2b1b4054 585 bool brokeloop;
75b49099 586 do {
2b1b4054 587 brokeloop=false;
2189085d 588 LOG(prefix<<qname<<": Checking if we have NS in cache for '"<<subdomain<<"'"<<endl);
e325f20c 589 vector<DNSRecord> ns;
7305df82 590 *flawedNSSet = false;
376effcf 591 if(t_RC->get(d_now.tv_sec, subdomain, QType(QType::NS), &ns, d_requestor) > 0) {
e325f20c 592 for(auto k=ns.cbegin();k!=ns.cend(); ++k) {
593 if(k->d_ttl > (unsigned int)d_now.tv_sec ) {
594 vector<DNSRecord> aset;
4957a608 595
e325f20c 596 const DNSRecord& dr=*k;
ba3c54cb
RG
597 auto nrr = getRR<NSRecordContent>(dr);
598 if(nrr && (!nrr->getNS().isPartOf(subdomain) || t_RC->get(d_now.tv_sec, nrr->getNS(), s_doIPv6 ? QType(QType::ADDR) : QType(QType::A),
599 doLog() ? &aset : 0, d_requestor) > 5)) {
e325f20c 600 bestns.push_back(dr);
2189085d
PL
601 LOG(prefix<<qname<<": NS (with ip, or non-glue) in cache for '"<<subdomain<<"' -> '"<<nrr->getNS()<<"'"<<endl);
602 LOG(prefix<<qname<<": within bailiwick: "<< nrr->getNS().isPartOf(subdomain));
4957a608 603 if(!aset.empty()) {
e325f20c 604 LOG(", in cache, ttl="<<(unsigned int)(((time_t)aset.begin()->d_ttl- d_now.tv_sec ))<<endl);
4957a608
BH
605 }
606 else {
77499b05 607 LOG(", not in cache / did not look at cache"<<endl);
4957a608
BH
608 }
609 }
610 else {
611 *flawedNSSet=true;
e325f20c 612 LOG(prefix<<qname<<": NS in cache for '"<<subdomain<<"', but needs glue ("<<nrr->getNS()<<") which we miss or is expired"<<endl);
4957a608
BH
613 }
614 }
afbe2787 615 }
75b49099 616 if(!bestns.empty()) {
4957a608 617 GetBestNSAnswer answer;
891fbf88 618 answer.qname=qname;
619 answer.qtype=qtype.getCode();
e325f20c 620 for(const auto& dr : bestns)
ba3c54cb 621 answer.bestns.insert(make_pair(dr.d_name, getRR<NSRecordContent>(dr)->getNS()));
891fbf88 622
4957a608 623 if(beenthere.count(answer)) {
2b1b4054 624 brokeloop=true;
2189085d 625 LOG(prefix<<qname<<": We have NS in cache for '"<<subdomain<<"' but part of LOOP (already seen "<<answer.qname<<")! Trying less specific NS"<<endl);
e325f20c 626 ;
77499b05
BH
627 if(doLog())
628 for( set<GetBestNSAnswer>::const_iterator j=beenthere.begin();j!=beenthere.end();++j) {
2b1b4054 629 bool neo = !(*j< answer || answer<*j);
2189085d 630 LOG(prefix<<qname<<": beenthere"<<(neo?"*":"")<<": "<<j->qname<<"|"<<DNSRecordContent::NumberToType(j->qtype)<<" ("<<(unsigned int)j->bestns.size()<<")"<<endl);
77499b05 631 }
4957a608
BH
632 bestns.clear();
633 }
634 else {
6576051d 635 beenthere.insert(answer);
2189085d 636 LOG(prefix<<qname<<": We have NS in cache for '"<<subdomain<<"' (flawedNSSet="<<*flawedNSSet<<")"<<endl);
4957a608
BH
637 return;
638 }
75b49099 639 }
afbe2787 640 }
2189085d 641 LOG(prefix<<qname<<": no valid/useful NS in cache for '"<<subdomain<<"'"<<endl);
e325f20c 642 ;
52683ca3 643 if(subdomain.isRoot() && !brokeloop) {
7836f7b4 644 // We lost the root NS records
3ddb9247 645 primeHints();
2189085d 646 LOG(prefix<<qname<<": reprimed the root"<<endl);
7836f7b4 647 getRootNS();
6576051d 648 }
c5c066bf 649 }while(subdomain.chopOff());
75b49099
BH
650}
651
c5c066bf 652SyncRes::domainmap_t::const_iterator SyncRes::getBestAuthZone(DNSName* qname)
5605c067
BH
653{
654 SyncRes::domainmap_t::const_iterator ret;
655 do {
49a699c4 656 ret=t_sstorage->domainmap->find(*qname);
710af846 657 if(ret!=t_sstorage->domainmap->end())
5605c067 658 break;
c5c066bf 659 }while(qname->chopOff());
5605c067
BH
660 return ret;
661}
288f4aa9 662
7bf26383 663/** doesn't actually do the work, leaves that to getBestNSFromCache */
7c3398aa 664DNSName SyncRes::getBestNSNamesFromCache(const DNSName &qname, const QType& qtype, NsSet& nsset, bool* flawedNSSet, unsigned int depth, set<GetBestNSAnswer>&beenthere)
75b49099 665{
c5c066bf
PD
666 DNSName subdomain(qname);
667 DNSName authdomain(qname);
3ddb9247 668
5605c067 669 domainmap_t::const_iterator iter=getBestAuthZone(&authdomain);
49a699c4 670 if(iter!=t_sstorage->domainmap->end()) {
2e5ae2b2 671 if( iter->second.d_servers.empty() )
fa1b87ff
PL
672 // this gets picked up in doResolveAt, the empty DNSName, combined with the
673 // empty vector means 'we are auth for this zone'
674 nsset.insert({DNSName(), {{}, false}});
2e5ae2b2 675 else {
fa1b87ff
PL
676 // Again, picked up in doResolveAt. An empty DNSName, combined with a
677 // non-empty vector of ComboAddresses means 'this is a forwarded domain'
678 nsset.insert({DNSName(), {iter->second.d_servers, iter->second.d_rdForward}});
2e5ae2b2 679 }
5605c067
BH
680 return authdomain;
681 }
682
e325f20c 683 vector<DNSRecord> bestns;
891fbf88 684 getBestNSFromCache(subdomain, qtype, bestns, flawedNSSet, depth, beenthere);
75b49099 685
e325f20c 686 for(auto k=bestns.cbegin() ; k != bestns.cend(); ++k) {
fa1b87ff
PL
687 // The actual resolver code will not even look at the ComboAddress or bool
688 nsset.insert({std::dynamic_pointer_cast<NSRecordContent>(k->d_content)->getNS(), {{}, false}});
e325f20c 689 if(k==bestns.cbegin())
690 subdomain=k->d_name;
86c152f2 691 }
75b49099 692 return subdomain;
afbe2787
BH
693}
694
7c3398aa 695bool SyncRes::doCNAMECacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>& ret, unsigned int depth, int &res)
afbe2787 696{
ded77b10 697 string prefix;
77499b05 698 if(doLog()) {
710af846 699 prefix=d_prefix;
ded77b10
BH
700 prefix.append(depth, ' ');
701 }
36f5e3db 702
40de2910 703 if((depth>9 && d_outqueries>10 && d_throttledqueries>5) || depth > 15) {
2189085d 704 LOG(prefix<<qname<<": recursing (CNAME or other indirection) too deep, depth="<<depth<<endl);
c6644fc5
BH
705 res=RCode::ServFail;
706 return true;
707 }
3ddb9247 708
2189085d 709 LOG(prefix<<qname<<": Looking for CNAME cache hit of '"<<qname<<"|CNAME"<<"'"<<endl);
e325f20c 710 vector<DNSRecord> cset;
1f77f479 711 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
376effcf 712 if(t_RC->get(d_now.tv_sec, qname,QType(QType::CNAME), &cset, d_requestor, &signatures) > 0) {
36c5ee42 713
e325f20c 714 for(auto j=cset.cbegin() ; j != cset.cend() ; ++j) {
715 if(j->d_ttl>(unsigned int) d_now.tv_sec) {
2189085d 716 LOG(prefix<<qname<<": Found cache CNAME hit for '"<< qname << "|CNAME" <<"' to '"<<j->d_content->getZoneRepresentation()<<"'"<<endl);
e325f20c 717 DNSRecord dr=*j;
718 dr.d_ttl-=d_now.tv_sec;
719 ret.push_back(dr);
1f77f479 720
721 for(const auto& signature : signatures) {
dd079764
RG
722 DNSRecord sigdr;
723 sigdr.d_type=QType::RRSIG;
724 sigdr.d_name=qname;
725 sigdr.d_ttl=j->d_ttl - d_now.tv_sec;
726 sigdr.d_content=signature;
727 sigdr.d_place=DNSResourceRecord::ANSWER;
728 sigdr.d_class=1;
729 ret.push_back(sigdr);
1f77f479 730 }
731
4957a608
BH
732 if(!(qtype==QType(QType::CNAME))) { // perhaps they really wanted a CNAME!
733 set<GetBestNSAnswer>beenthere;
e325f20c 734 res=doResolve(std::dynamic_pointer_cast<CNAMERecordContent>(j->d_content)->getTarget(), qtype, ret, depth+1, beenthere);
4957a608
BH
735 }
736 else
737 res=0;
738 return true;
ac539791
BH
739 }
740 }
afbe2787 741 }
2189085d 742 LOG(prefix<<qname<<": No CNAME cache hit of '"<< qname << "|CNAME" <<"' found"<<endl);
75b49099
BH
743 return false;
744}
745
8171ab83 746static const DNSName getLastLabel(const DNSName& qname)
01402d56 747{
8171ab83 748 DNSName ret(qname);
749 ret.trimToLabels(1);
750 return ret;
01402d56 751}
bb4bdbaf 752
e325f20c 753
7c3398aa 754bool SyncRes::doCacheCheck(const DNSName &qname, const QType &qtype, vector<DNSRecord>&ret, unsigned int depth, int &res)
75b49099 755{
fd8bc993 756 bool giveNegative=false;
710af846 757
be718669 758 string prefix;
77499b05 759 if(doLog()) {
ded77b10
BH
760 prefix=d_prefix;
761 prefix.append(depth, ' ');
762 }
afbe2787 763
c5c066bf 764 DNSName sqname(qname);
288f4aa9 765 QType sqt(qtype);
092f210a 766 uint32_t sttl=0;
2189085d 767 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"' -> "<<getLastLabel(qname)<<endl;
3ddb9247 768
01402d56 769 pair<negcache_t::const_iterator, negcache_t::const_iterator> range;
770 QType qtnull(0);
710af846 771
64a8b6a1
PL
772 DNSName authname(qname);
773 bool wasForwardedOrAuth = (getBestAuthZone(&authname) != t_sstorage->domainmap->end());
774
710af846
PL
775 if(s_rootNXTrust &&
776 (range.first=t_sstorage->negcache.find(tie(getLastLabel(qname), qtnull))) != t_sstorage->negcache.end() &&
64a8b6a1
PL
777 !(wasForwardedOrAuth && !authname.isRoot()) && // when forwarding, the root may only neg-cache if it was forwarded to.
778 range.first->d_qname.isRoot() && (uint32_t)d_now.tv_sec < range.first->d_ttd) {
01402d56 779 sttl=range.first->d_ttd - d_now.tv_sec;
3ddb9247 780
2189085d 781 LOG(prefix<<qname<<": Entire name '"<<qname<<"', is negatively cached via '"<<range.first->d_name<<"' & '"<<range.first->d_qname<<"' for another "<<sttl<<" seconds"<<endl);
3ddb9247 782 res = RCode::NXDomain;
01402d56 783 sqname=range.first->d_qname;
784 sqt=QType::SOA;
785 moveCacheItemToBack(t_sstorage->negcache, range.first);
710af846 786
01402d56 787 giveNegative=true;
788 }
789 else {
790 range=t_sstorage->negcache.equal_range(tie(qname));
791 negcache_t::iterator ni;
792 for(ni=range.first; ni != range.second; ni++) {
793 // we have something
64a8b6a1
PL
794 if(!(wasForwardedOrAuth && ni->d_qname != authname) && // Only the authname nameserver can neg cache entries
795 (ni->d_qtype.getCode() == 0 || ni->d_qtype == qtype)) {
01402d56 796 res=0;
797 if((uint32_t)d_now.tv_sec < ni->d_ttd) {
798 sttl=ni->d_ttd - d_now.tv_sec;
799 if(ni->d_qtype.getCode()) {
2189085d 800 LOG(prefix<<qname<<": "<<qtype.getName()<<" is negatively cached via '"<<ni->d_qname<<"' for another "<<sttl<<" seconds"<<endl);
01402d56 801 res = RCode::NoError;
802 }
803 else {
2189085d 804 LOG(prefix<<qname<<": Entire name '"<<qname<<"', is negatively cached via '"<<ni->d_qname<<"' for another "<<sttl<<" seconds"<<endl);
3ddb9247 805 res= RCode::NXDomain;
01402d56 806 }
807 giveNegative=true;
808 sqname=ni->d_qname;
809 sqt=QType::SOA;
2e921ec6 810 if(d_doDNSSEC) {
811 for(const auto& p : ni->d_dnssecProof) {
812 for(const auto& rec: p.second.records)
813 ret.push_back(rec);
814 for(const auto& rec: p.second.signatures)
815 ret.push_back(rec);
816 }
817 }
01402d56 818 moveCacheItemToBack(t_sstorage->negcache, ni);
819 break;
820 }
821 else {
2189085d 822 LOG(prefix<<qname<<": Entire name '"<<qname<<"' or type was negatively cached, but entry expired"<<endl);
01402d56 823 moveCacheItemToFront(t_sstorage->negcache, ni);
824 }
38e22b5a 825 }
fd8bc993
BH
826 }
827 }
e325f20c 828 vector<DNSRecord> cset;
75b49099 829 bool found=false, expired=false;
57769f13 830 vector<std::shared_ptr<RRSIGRecordContent>> signatures;
831 uint32_t ttl=0;
376effcf 832 if(t_RC->get(d_now.tv_sec, sqname, sqt, &cset, d_requestor, d_doDNSSEC ? &signatures : 0) > 0) {
2189085d 833 LOG(prefix<<sqname<<": Found cache hit for "<<sqt.getName()<<": ");
e325f20c 834 for(auto j=cset.cbegin() ; j != cset.cend() ; ++j) {
835 LOG(j->d_content->getZoneRepresentation());
836 if(j->d_ttl>(unsigned int) d_now.tv_sec) {
837 DNSRecord dr=*j;
838 ttl = (dr.d_ttl-=d_now.tv_sec);
4957a608 839 if(giveNegative) {
e693ff5a 840 dr.d_place=DNSResourceRecord::AUTHORITY;
e325f20c 841 dr.d_ttl=sttl;
4957a608 842 }
e325f20c 843 ret.push_back(dr);
844 LOG("[ttl="<<dr.d_ttl<<"] ");
4957a608 845 found=true;
ac539791 846 }
75b49099 847 else {
77499b05 848 LOG("[expired] ");
4957a608 849 expired=true;
75b49099 850 }
afbe2787 851 }
57769f13 852
853 for(const auto& signature : signatures) {
e325f20c 854 DNSRecord dr;
855 dr.d_type=QType::RRSIG;
856 dr.d_name=sqname;
857 dr.d_ttl=ttl;
858 dr.d_content=signature;
620db2c8 859 dr.d_place= giveNegative ? DNSResourceRecord::AUTHORITY : DNSResourceRecord::ANSWER;
e325f20c 860 dr.d_class=1;
861 ret.push_back(dr);
57769f13 862 }
ac539791 863
77499b05 864 LOG(endl);
f4df5e89 865 if(found && !expired) {
f15a5b2a 866 if(!giveNegative)
4957a608 867 res=0;
75b49099 868 return true;
f4df5e89 869 }
75b49099 870 else
2189085d 871 LOG(prefix<<qname<<": cache had only stale entries"<<endl);
afbe2787 872 }
f4df5e89 873
75b49099
BH
874 return false;
875}
afbe2787 876
e8b23f3b 877bool SyncRes::moreSpecificThan(const DNSName& a, const DNSName &b)
75b49099 878{
6a1010f7 879 return (a.isPartOf(b) && a.countLabels() > b.countLabels());
afbe2787
BH
880}
881
d8d0bb8f 882struct speedOrder
eefd15f9 883{
3ddb9247
PD
884 speedOrder(map<DNSName,double> &speeds) : d_speeds(speeds) {}
885 bool operator()(const DNSName &a, const DNSName &b) const
c3d9d009
BH
886 {
887 return d_speeds[a] < d_speeds[b];
c3d9d009 888 }
3ddb9247 889 map<DNSName, double>& d_speeds;
c3d9d009
BH
890};
891
fa1b87ff 892inline vector<DNSName> SyncRes::shuffleInSpeedOrder(NsSet &tnameservers, const string &prefix)
afbe2787 893{
e8b23f3b 894 vector<DNSName> rnameservers;
5ea6f7de 895 rnameservers.reserve(tnameservers.size());
e8b23f3b 896 for(const auto& tns:tnameservers) {
88490c03 897 rnameservers.push_back(tns.first);
21f0f88b 898 }
e8b23f3b 899 map<DNSName, double> speeds;
461df9d2 900
e8b23f3b 901 for(const auto& val: rnameservers) {
79b8cdcc 902 double speed;
21f0f88b
BH
903 speed=t_sstorage->nsSpeeds[val].get(&d_now);
904 speeds[val]=speed;
eefd15f9 905 }
51e2144e 906 random_shuffle(rnameservers.begin(),rnameservers.end(), dns_random);
996c89cc
BH
907 speedOrder so(speeds);
908 stable_sort(rnameservers.begin(),rnameservers.end(), so);
710af846 909
77499b05
BH
910 if(doLog()) {
911 LOG(prefix<<"Nameservers: ");
e325f20c 912 for(vector<DNSName>::const_iterator i=rnameservers.begin();i!=rnameservers.end();++i) {
3ddb9247 913 if(i!=rnameservers.begin()) {
77499b05
BH
914 LOG(", ");
915 if(!((i-rnameservers.begin())%3)) {
916 LOG(endl<<prefix<<" ");
917 }
d8d0bb8f 918 }
34dcd30c 919 LOG((i->empty() ? string("<empty>") : i->toString())<<"(" << (boost::format("%0.2f") % (speeds[*i]/1000.0)).str() <<"ms)");
d8d0bb8f 920 }
77499b05 921 LOG(endl);
d8d0bb8f 922 }
728485ca 923 return rnameservers;
afbe2787
BH
924}
925
bf7e4a70
BH
926static bool magicAddrMatch(const QType& query, const QType& answer)
927{
928 if(query.getCode() != QType::ADDR)
929 return false;
930 return answer.getCode() == QType::A || answer.getCode() == QType::AAAA;
931}
7738a23f 932
620db2c8 933
934recsig_t harvestRecords(const vector<DNSRecord>& records, const set<uint16_t>& types)
935{
936 recsig_t ret;
937 for(const auto& rec : records) {
938 if(rec.d_type == QType::RRSIG) {
939 auto rrs=getRR<RRSIGRecordContent>(rec);
ba3c54cb 940 if(rrs && types.count(rrs->d_type))
620db2c8 941 ret[make_pair(rec.d_name, rrs->d_type)].signatures.push_back(rec);
942 }
943 else if(types.count(rec.d_type))
944 ret[make_pair(rec.d_name, rec.d_type)].records.push_back(rec);
945 }
946 return ret;
947}
948
949static void addNXNSECS(vector<DNSRecord>&ret, const vector<DNSRecord>& records)
950{
951 auto csp = harvestRecords(records, {QType::NSEC, QType::NSEC3, QType::SOA});
952 for(const auto& c : csp) {
953 if(c.first.second == QType::NSEC || c.first.second == QType::NSEC3 || c.first.second == QType::SOA) {
954 if(c.first.second !=QType::SOA) {
955 for(const auto& rec : c.second.records)
956 ret.push_back(rec);
957 }
958 for(const auto& rec : c.second.signatures)
959 ret.push_back(rec);
960 }
961 }
962}
963
b8470add
PL
964/** returns:
965 * -1 in case of no results
966 * -2 when a FilterEngine Policy was hit
967 * rcode otherwise
968 */
fa1b87ff 969int SyncRes::doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, const QType &qtype,
e325f20c 970 vector<DNSRecord>&ret,
7c3398aa 971 unsigned int depth, set<GetBestNSAnswer>&beenthere)
86c152f2 972{
ded77b10 973 string prefix;
77499b05 974 if(doLog()) {
ded77b10
BH
975 prefix=d_prefix;
976 prefix.append(depth, ' ');
977 }
3ddb9247 978
b8470add
PL
979 LOG(prefix<<qname<<": Cache consultations done, have "<<(unsigned int)nameservers.size()<<" NS to contact");
980
981 if(d_wantsRPZ) {
982 for (auto const &ns : nameservers) {
0a273054 983 d_appliedPolicy = g_luaconfs.getLocal()->dfe.getProcessingPolicy(ns.first, d_discardedPolicies);
b8470add 984 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
0a273054 985 LOG(", however nameserver "<<ns.first<<" was blocked by RPZ policy '"<<(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")<<"'"<<endl);
b8470add
PL
986 return -2;
987 }
988
989 // Traverse all IP addresses for this NS to see if they have an RPN NSIP policy
990 for (auto const &address : ns.second.first) {
0a273054 991 d_appliedPolicy = g_luaconfs.getLocal()->dfe.getProcessingPolicy(address, d_discardedPolicies);
b8470add 992 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
0a273054 993 LOG(", however nameserver "<<ns.first<<" IP address "<<address.toString()<<" was blocked by RPZ policy '"<<(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")<<"'"<<endl);
b8470add
PL
994 return -2;
995 }
996 }
997 }
998 }
999
1000 LOG(endl);
afbe2787
BH
1001
1002 for(;;) { // we may get more specific nameservers
e8b23f3b 1003 vector<DNSName > rnameservers = shuffleInSpeedOrder(nameservers, doLog() ? (prefix+qname.toString()+": ") : string() );
3ddb9247 1004
88490c03 1005 for(vector<DNSName >::const_iterator tns=rnameservers.begin();;++tns) {
728485ca 1006 if(tns==rnameservers.end()) {
2189085d 1007 LOG(prefix<<qname<<": Failed to resolve via any of the "<<(unsigned int)rnameservers.size()<<" offered NS at level '"<<auth<<"'"<<endl);
8171ab83 1008 if(auth!=DNSName() && flawedNSSet) {
2189085d 1009 LOG(prefix<<qname<<": Ageing nameservers for level '"<<auth<<"', next query might succeed"<<endl);
88490c03 1010
49a699c4 1011 if(t_RC->doAgeCache(d_now.tv_sec, auth, QType::NS, 10))
4957a608
BH
1012 g_stats.nsSetInvalidations++;
1013 }
1014 return -1;
afbe2787 1015 }
21f0f88b 1016 // this line needs to identify the 'self-resolving' behaviour, but we get it wrong now
e325f20c 1017 if(qname == *tns && qtype.getCode()==QType::A && rnameservers.size() > (unsigned)(1+1*s_doIPv6)) {
2189085d 1018 LOG(prefix<<qname<<": Not using NS to resolve itself! ("<<(1+tns-rnameservers.begin())<<"/"<<rnameservers.size()<<")"<<endl);
4957a608 1019 continue;
20177d1d 1020 }
5605c067 1021
996c89cc 1022 typedef vector<ComboAddress> remoteIPs_t;
5605c067 1023 remoteIPs_t remoteIPs;
bfea0d0b 1024 remoteIPs_t::const_iterator remoteIP;
5c633640 1025 bool doTCP=false;
5605c067 1026 int resolveret;
1c21f389 1027 bool pierceDontQuery=false;
c1d73d94 1028 bool sendRDQuery=false;
376effcf 1029 boost::optional<Netmask> ednsmask;
263f6a5a 1030 LWResult lwr;
fa1b87ff 1031 if(tns->empty() && nameservers[*tns].first.empty() ) {
2189085d 1032 LOG(prefix<<qname<<": Domain is out-of-band"<<endl);
9fc36e90 1033 d_wasOutOfBand = doOOBResolve(qname, qtype, lwr.d_records, depth, lwr.d_rcode);
4957a608
BH
1034 lwr.d_tcbit=false;
1035 lwr.d_aabit=true;
5605c067
BH
1036 }
1037 else {
fa1b87ff 1038 if(!tns->empty()) {
2189085d 1039 LOG(prefix<<qname<<": Trying to resolve NS '"<<*tns<< "' ("<<1+tns-rnameservers.begin()<<"/"<<(unsigned int)rnameservers.size()<<")"<<endl);
fa1b87ff 1040 }
644dd1da 1041
d7d7a91a 1042 if(tns->empty()) {
2189085d 1043 LOG(prefix<<qname<<": Domain has hardcoded nameserver");
fa1b87ff
PL
1044
1045 remoteIPs = nameservers[*tns].first;
1046 if(remoteIPs.size() > 1) {
1047 LOG("s");
1048 }
1049 LOG(endl);
4957a608 1050
88490c03 1051 sendRDQuery = nameservers[*tns].second;
4957a608
BH
1052 pierceDontQuery=true;
1053 }
1054 else {
76f190f2 1055 remoteIPs=getAddrs(*tns, depth+2, beenthere);
4957a608
BH
1056 pierceDontQuery=false;
1057 }
1058
1059 if(remoteIPs.empty()) {
2189085d 1060 LOG(prefix<<qname<<": Failed to get IP for NS "<<*tns<<", trying next if available"<<endl);
4957a608
BH
1061 flawedNSSet=true;
1062 continue;
1063 }
1064 else {
b8470add 1065 bool hitPolicy{false};
2189085d 1066 LOG(prefix<<qname<<": Resolved '"<<auth<<"' NS "<<*tns<<" to: ");
4957a608 1067 for(remoteIP = remoteIPs.begin(); remoteIP != remoteIPs.end(); ++remoteIP) {
77499b05
BH
1068 if(remoteIP != remoteIPs.begin()) {
1069 LOG(", ");
1070 }
1071 LOG(remoteIP->toString());
b8470add 1072 if (d_wantsRPZ) {
0a273054 1073 d_appliedPolicy = g_luaconfs.getLocal()->dfe.getProcessingPolicy(*remoteIP, d_discardedPolicies);
b8470add
PL
1074 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) {
1075 hitPolicy = true;
0a273054 1076 LOG(" (blocked by RPZ policy '"+(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")+"')");
b8470add
PL
1077 }
1078 }
4957a608 1079 }
77499b05 1080 LOG(endl);
b8470add
PL
1081 if (hitPolicy) //implies d_wantsRPZ
1082 return -2;
4957a608
BH
1083 }
1084
1085 for(remoteIP = remoteIPs.begin(); remoteIP != remoteIPs.end(); ++remoteIP) {
2189085d 1086 LOG(prefix<<qname<<": Trying IP "<< remoteIP->toStringWithPort() <<", asking '"<<qname<<"|"<<qtype.getName()<<"'"<<endl);
4957a608 1087 extern NetmaskGroup* g_dontQuery;
710af846 1088
41ea0e50 1089 if(t_sstorage->throttle.shouldThrottle(d_now.tv_sec, boost::make_tuple(*remoteIP, "", 0))) {
2189085d 1090 LOG(prefix<<qname<<": server throttled "<<endl);
628e2c7b
PA
1091 s_throttledqueries++; d_throttledqueries++;
1092 continue;
1093 }
41ea0e50 1094 else if(t_sstorage->throttle.shouldThrottle(d_now.tv_sec, boost::make_tuple(*remoteIP, qname, qtype.getCode()))) {
2189085d 1095 LOG(prefix<<qname<<": query throttled "<<endl);
4957a608
BH
1096 s_throttledqueries++; d_throttledqueries++;
1097 continue;
710af846 1098 }
4957a608 1099 else if(!pierceDontQuery && g_dontQuery && g_dontQuery->match(&*remoteIP)) {
2189085d 1100 LOG(prefix<<qname<<": not sending query to " << remoteIP->toString() << ", blocked by 'dont-query' setting" << endl);
66e0b6ea 1101 s_dontqueries++;
4957a608
BH
1102 continue;
1103 }
1104 else {
1105 s_outqueries++; d_outqueries++;
2189085d 1106 if(d_outqueries + d_throttledqueries > s_maxqperq) throw ImmediateServFailException("more than "+std::to_string(s_maxqperq)+" (max-qperq) queries sent while resolving "+qname.toLogString());
4957a608
BH
1107 TryTCP:
1108 if(doTCP) {
2189085d 1109 LOG(prefix<<qname<<": using TCP with "<< remoteIP->toStringWithPort() <<endl);
4957a608
BH
1110 s_tcpoutqueries++; d_tcpoutqueries++;
1111 }
9de3e034 1112
3ddb9247 1113 if(s_maxtotusec && d_totUsec > s_maxtotusec)
2189085d 1114 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");
9de3e034 1115
c672b54a 1116 if(d_pdl && d_pdl->preoutquery(*remoteIP, d_requestor, qname, qtype, doTCP, lwr.d_records, resolveret)) {
2189085d 1117 LOG(prefix<<qname<<": query handled by Lua"<<endl);
3457a2a0 1118 }
376effcf 1119 else {
1120 ednsmask=getEDNSSubnetMask(d_requestor, qname, *remoteIP);
12ce523e 1121 resolveret=asyncresolveWrapper(*remoteIP, d_doDNSSEC, qname, qtype.getCode(),
376effcf 1122 doTCP, sendRDQuery, &d_now, ednsmask, &lwr); // <- we go out on the wire!
376effcf 1123 }
3457a2a0 1124 if(resolveret==-3)
1125 throw ImmediateServFailException("Query killed by policy");
1126
9de3e034 1127 d_totUsec += lwr.d_usec;
7b75810e 1128 accountAuthLatency(lwr.d_usec, remoteIP->sin4.sin_family);
30b13ef7 1129 if(resolveret != 1) {
4957a608 1130 if(resolveret==0) {
2189085d 1131 LOG(prefix<<qname<<": timeout resolving after "<<lwr.d_usec/1000.0<<"msec "<< (doTCP ? "over TCP" : "")<<endl);
232f0877
CH
1132 d_timeouts++;
1133 s_outgoingtimeouts++;
7b75810e 1134 if(remoteIP->sin4.sin_family == AF_INET)
1135 s_outgoing4timeouts++;
1136 else
1137 s_outgoing6timeouts++;
4957a608
BH
1138 }
1139 else if(resolveret==-2) {
2189085d 1140 LOG(prefix<<qname<<": hit a local resource limit resolving"<< (doTCP ? " over TCP" : "")<<", probable error: "<<stringerror()<<endl);
232f0877 1141 g_stats.resourceLimits++;
4957a608
BH
1142 }
1143 else {
232f0877 1144 s_unreachables++; d_unreachables++;
2189085d 1145 LOG(prefix<<qname<<": error resolving from "<<remoteIP->toString()<< (doTCP ? " over TCP" : "") <<", possible error: "<<strerror(errno)<< endl);
4957a608 1146 }
710af846 1147
4957a608 1148 if(resolveret!=-2) { // don't account for resource limits, they are our own fault
30b13ef7 1149 t_sstorage->nsSpeeds[*tns].submit(*remoteIP, 1000000, &d_now); // 1 sec
710af846 1150
30b13ef7 1151 // code below makes sure we don't filter COM or the root
12c06211 1152 if (s_serverdownmaxfails > 0 && (auth != g_rootdnsname) && t_sstorage->fails.incr(*remoteIP) >= s_serverdownmaxfails) {
2189085d 1153 LOG(prefix<<qname<<": Max fails reached resolving on "<< remoteIP->toString() <<". Going full throttle for "<< s_serverdownthrottletime <<" seconds" <<endl);
41ea0e50 1154 t_sstorage->throttle.throttle(d_now.tv_sec, boost::make_tuple(*remoteIP, "", 0), s_serverdownthrottletime, 10000); // mark server as down
628e2c7b 1155 } else if(resolveret==-1)
41ea0e50 1156 t_sstorage->throttle.throttle(d_now.tv_sec, boost::make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100); // unreachable, 1 minute or 100 queries
232f0877 1157 else
41ea0e50 1158 t_sstorage->throttle.throttle(d_now.tv_sec, boost::make_tuple(*remoteIP, qname, qtype.getCode()), 10, 5); // timeout
4957a608
BH
1159 }
1160 continue;
1161 }
352b4183 1162
335da0ba 1163// if(d_timeouts + 0.5*d_throttledqueries > 6.0 && d_timeouts > 2) throw ImmediateServFailException("Too much work resolving "+qname+"|"+qtype.getName()+", timeouts: "+std::to_string(d_timeouts) +", throttles: "+std::to_string(d_throttledqueries));
92011b8f 1164
352b4183 1165 if(lwr.d_rcode==RCode::ServFail || lwr.d_rcode==RCode::Refused) {
2189085d 1166 LOG(prefix<<qname<<": "<<*tns<<" ("<<remoteIP->toString()<<") returned a "<< (lwr.d_rcode==RCode::ServFail ? "ServFail" : "Refused") << ", trying sibling IP or NS"<<endl);
41ea0e50 1167 t_sstorage->throttle.throttle(d_now.tv_sec,boost::make_tuple(*remoteIP, qname, qtype.getCode()),60,3); // servfail or refused
352b4183
PD
1168 continue;
1169 }
710af846 1170
628e2c7b
PA
1171 if(s_serverdownmaxfails > 0)
1172 t_sstorage->fails.clear(*remoteIP);
1173
4957a608
BH
1174 break; // this IP address worked!
1175 wasLame:; // well, it didn't
2189085d 1176 LOG(prefix<<qname<<": status=NS "<<*tns<<" ("<< remoteIP->toString() <<") is lame for '"<<auth<<"', trying sibling IP or NS"<<endl);
41ea0e50 1177 t_sstorage->throttle.throttle(d_now.tv_sec, boost::make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100); // lame
4957a608
BH
1178 }
1179 }
710af846 1180
4957a608 1181 if(remoteIP == remoteIPs.end()) // we tried all IP addresses, none worked
710af846
PL
1182 continue;
1183
4957a608
BH
1184 if(lwr.d_tcbit) {
1185 if(!doTCP) {
1186 doTCP=true;
2189085d 1187 LOG(prefix<<qname<<": truncated bit set, retrying via TCP"<<endl);
4957a608
BH
1188 goto TryTCP;
1189 }
2189085d 1190 LOG(prefix<<qname<<": truncated bit set, over TCP?"<<endl);
4957a608
BH
1191 return RCode::ServFail;
1192 }
2189085d 1193 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);
4957a608
BH
1194
1195 /* // for you IPv6 fanatics :-)
1196 if(remoteIP->sin4.sin_family==AF_INET6)
1197 lwr.d_usec/=3;
1198 */
232f0877 1199 // cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
4957a608 1200
49a699c4 1201 t_sstorage->nsSpeeds[*tns].submit(*remoteIP, lwr.d_usec, &d_now);
20177d1d 1202 }
20177d1d 1203
aadceba8 1204 if(s_minimumTTL) {
48b560ea 1205 for(auto& rec : lwr.d_records) {
e325f20c 1206 rec.d_ttl = max(rec.d_ttl, s_minimumTTL);
aadceba8 1207 }
1208 }
1209
57769f13 1210 struct CachePair
1211 {
e325f20c 1212 vector<DNSRecord> records;
57769f13 1213 vector<shared_ptr<RRSIGRecordContent>> signatures;
1214 };
6c674e9a 1215 struct CacheKey
1216 {
1217 DNSName name;
1218 uint16_t type;
1219 DNSResourceRecord::Place place;
1220 bool operator<(const CacheKey& rhs) const {
1221 return tie(name, type) < tie(rhs.name, rhs.type);
1222 }
1223 };
1224 typedef map<CacheKey, CachePair> tcache_t;
1ac4e536
BH
1225 tcache_t tcache;
1226
12ce523e 1227 for(const auto& rec : lwr.d_records) {
1228 if(rec.d_type == QType::RRSIG) {
ba3c54cb
RG
1229 auto rrsig = getRR<RRSIGRecordContent>(rec);
1230 if (rrsig) {
1231 // cerr<<"Got an RRSIG for "<<DNSRecordContent::NumberToType(rrsig->d_type)<<" with name '"<<rec.d_name<<"'"<<endl;
1232 tcache[{rec.d_name, rrsig->d_type, rec.d_place}].signatures.push_back(rrsig);
1233 }
12ce523e 1234 }
57769f13 1235 }
1236
728485ca 1237 // reap all answers from this packet that are acceptable
e325f20c 1238 for(auto& rec : lwr.d_records) {
1239 if(rec.d_type == QType::OPT) {
2189085d 1240 LOG(prefix<<qname<<": OPT answer '"<<rec.d_name<<"' from '"<<auth<<"' nameservers" <<endl);
4957a608
BH
1241 continue;
1242 }
2189085d 1243 LOG(prefix<<qname<<": accept answer '"<<rec.d_name<<"|"<<DNSRecordContent::NumberToType(rec.d_type)<<"|"<<rec.d_content->getZoneRepresentation()<<"' from '"<<auth<<"' nameservers? "<<(int)rec.d_place<<" ");
e325f20c 1244 if(rec.d_type == QType::ANY) {
77499b05 1245 LOG("NO! - we don't accept 'ANY' data"<<endl);
4957a608
BH
1246 continue;
1247 }
3ddb9247 1248
e325f20c 1249 if(rec.d_name.isPartOf(auth)) {
9ea28e46
RG
1250 if(rec.d_type == QType::RRSIG) {
1251 LOG("RRSIG - separate"<<endl);
1252 }
1253 else if(lwr.d_aabit && lwr.d_rcode==RCode::NoError && rec.d_place==DNSResourceRecord::ANSWER && (rec.d_type != QType::DNSKEY || rec.d_name != auth) && g_delegationOnly.count(auth)) {
77499b05 1254 LOG("NO! Is from delegation-only zone"<<endl);
4957a608
BH
1255 s_nodelegated++;
1256 return RCode::NXDomain;
1257 }
1258 else {
3ad03d75
PL
1259 bool haveLogged = false;
1260 if (!t_sstorage->domainmap->empty()) {
1261 // Check if we are authoritative for a zone in this answer
1262 DNSName tmp_qname(rec.d_name);
1263 auto auth_domain_iter=getBestAuthZone(&tmp_qname);
0af9c73d
PL
1264 if(auth_domain_iter!=t_sstorage->domainmap->end() &&
1265 auth.countLabels() <= auth_domain_iter->first.countLabels()) {
3ad03d75 1266 if (auth_domain_iter->first != auth) {
2189085d 1267 LOG("NO! - we are authoritative for the zone "<<auth_domain_iter->first<<endl);
3ad03d75
PL
1268 continue;
1269 } else {
1270 LOG("YES! - This answer was ");
1271 if (nameservers[*tns].first.empty()) {
1272 LOG("retrieved from the local auth store.");
1273 } else {
1274 LOG("received from a server we forward to.");
1275 }
1276 haveLogged = true;
1277 LOG(endl);
1278 }
1279 }
1280 }
1281 if (!haveLogged) {
1282 LOG("YES!"<<endl);
1283 }
4957a608 1284
e325f20c 1285 rec.d_ttl=min(s_maxcachettl, rec.d_ttl);
710af846 1286
e325f20c 1287 DNSRecord dr(rec);
e693ff5a 1288 dr.d_place=DNSResourceRecord::ANSWER;
4957a608 1289
e325f20c 1290 dr.d_ttl += d_now.tv_sec;
6c674e9a 1291 tcache[{rec.d_name,rec.d_type,rec.d_place}].records.push_back(dr);
4957a608 1292 }
710af846 1293 }
4957a608 1294 else
77499b05 1295 LOG("NO!"<<endl);
86c152f2 1296 }
710af846 1297
728485ca 1298 // supplant
60b859b9 1299 for(tcache_t::iterator i=tcache.begin();i!=tcache.end();++i) {
57769f13 1300 if(i->second.records.size() > 1) { // need to group the ttl to be the minimum of the RRSET (RFC 2181, 5.2)
331c187c 1301 uint32_t lowestTTL=std::numeric_limits<uint32_t>::max();
57769f13 1302 for(auto& record : i->second.records)
e325f20c 1303 lowestTTL=min(lowestTTL, record.d_ttl);
4957a608 1304
57769f13 1305 for(auto& record : i->second.records)
e325f20c 1306 *const_cast<uint32_t*>(&record.d_ttl)=lowestTTL; // boom
4957a608
BH
1307 }
1308
a0750204
PL
1309// cout<<"Have "<<i->second.records.size()<<" records and "<<i->second.signatures.size()<<" signatures for "<<i->first.name;
1310// cout<<'|'<<DNSRecordContent::NumberToType(i->first.type)<<endl;
7b20ee0d 1311 if(i->second.records.empty()) // this happens when we did store signatures, but passed on the records themselves
1312 continue;
6c674e9a 1313 t_RC->replace(d_now.tv_sec, i->first.name, QType(i->first.type), i->second.records, i->second.signatures, lwr.d_aabit, i->first.place == DNSResourceRecord::ANSWER ? ednsmask : boost::optional<Netmask>());
3762e821 1314 if(i->first.place == DNSResourceRecord::ANSWER && ednsmask)
1315 d_wasVariable=true;
288f4aa9 1316 }
3ddb9247 1317 set<DNSName> nsset;
2189085d 1318 LOG(prefix<<qname<<": determining status after receiving this packet"<<endl);
728485ca 1319
57769f13 1320 bool done=false, realreferral=false, negindic=false, sawDS=false;
7e2e4419 1321 DNSName newauth, soaname;
1322 DNSName newtarget;
57769f13 1323
e325f20c 1324 for(auto& rec : lwr.d_records) {
ba3c54cb
RG
1325 if (rec.d_type!=QType::OPT && rec.d_class!=QClass::IN)
1326 continue;
1327
e693ff5a 1328 if(rec.d_place==DNSResourceRecord::AUTHORITY && rec.d_type==QType::SOA &&
c32f9f94 1329 lwr.d_rcode==RCode::NXDomain && qname.isPartOf(rec.d_name) && rec.d_name.isPartOf(auth)) {
2189085d 1330 LOG(prefix<<qname<<": got negative caching indication for name '"<<qname<<"' (accept="<<rec.d_name.isPartOf(auth)<<"), newtarget='"<<newtarget<<"'"<<endl);
3ddb9247 1331
e325f20c 1332 rec.d_ttl = min(rec.d_ttl, s_maxnegttl);
ae14c1f3 1333 if(newtarget.empty()) // only add a SOA if we're not going anywhere after this
e325f20c 1334 ret.push_back(rec);
061d67cb 1335 if(!wasVariable()) {
1336 NegCacheEntry ne;
1337
1338 ne.d_qname=rec.d_name;
1339 ne.d_ttd=d_now.tv_sec + rec.d_ttl;
1340 ne.d_name=qname;
1341 ne.d_qtype=QType(0); // this encodes 'whole record'
620db2c8 1342 ne.d_dnssecProof = harvestRecords(lwr.d_records, {QType::NSEC, QType::NSEC3});
01402d56 1343 replacing_insert(t_sstorage->negcache, ne);
061d67cb 1344 if(s_rootNXTrust && auth.isRoot()) {
1345 ne.d_name = getLastLabel(ne.d_name);
1346 replacing_insert(t_sstorage->negcache, ne);
1347 }
01402d56 1348 }
710af846 1349
4957a608
BH
1350 negindic=true;
1351 }
e693ff5a 1352 else if(rec.d_place==DNSResourceRecord::ANSWER && rec.d_name == qname && rec.d_type==QType::CNAME && (!(qtype==QType(QType::CNAME)))) {
e325f20c 1353 ret.push_back(rec);
ba3c54cb
RG
1354 if (auto content = getRR<CNAMERecordContent>(rec)) {
1355 newtarget=content->getTarget();
1356 }
4957a608 1357 }
2e921ec6 1358 else if((rec.d_type==QType::RRSIG || rec.d_type==QType::NSEC || rec.d_type==QType::NSEC3) && rec.d_place==DNSResourceRecord::ANSWER){
8ed7b45e 1359 if(rec.d_type != QType::RRSIG || rec.d_name == qname)
1360 ret.push_back(rec); // enjoy your DNSSEC
57769f13 1361 }
7c696097 1362 // for ANY answers we *must* have an authoritative answer, unless we are forwarding recursively
e693ff5a 1363 else if(rec.d_place==DNSResourceRecord::ANSWER && rec.d_name == qname &&
232f0877 1364 (
e325f20c 1365 rec.d_type==qtype.getCode() || (lwr.d_aabit && (qtype==QType(QType::ANY) || magicAddrMatch(qtype, QType(rec.d_type)) ) ) || sendRDQuery
710af846
PL
1366 )
1367 )
4957a608 1368 {
3ddb9247 1369
2189085d 1370 LOG(prefix<<qname<<": answer is in: resolved to '"<< rec.d_content->getZoneRepresentation()<<"|"<<DNSRecordContent::NumberToType(rec.d_type)<<"'"<<endl);
4957a608
BH
1371
1372 done=true;
e325f20c 1373 ret.push_back(rec);
4957a608 1374 }
e693ff5a 1375 else if(rec.d_place==DNSResourceRecord::AUTHORITY && qname.isPartOf(rec.d_name) && rec.d_type==QType::NS) {
e325f20c 1376 if(moreSpecificThan(rec.d_name,auth)) {
1377 newauth=rec.d_name;
2189085d 1378 LOG(prefix<<qname<<": got NS record '"<<rec.d_name<<"' -> '"<<rec.d_content->getZoneRepresentation()<<"'"<<endl);
4957a608
BH
1379 realreferral=true;
1380 }
e325f20c 1381 else {
2189085d 1382 LOG(prefix<<qname<<": got upwards/level NS record '"<<rec.d_name<<"' -> '"<<rec.d_content->getZoneRepresentation()<<"', had '"<<auth<<"'"<<endl);
e325f20c 1383 }
ba3c54cb
RG
1384 if (auto content = getRR<NSRecordContent>(rec)) {
1385 nsset.insert(content->getNS());
1386 }
4957a608 1387 }
c32f9f94 1388 else if(rec.d_place==DNSResourceRecord::AUTHORITY && qname.isPartOf(rec.d_name) && rec.d_type==QType::DS) {
2189085d 1389 LOG(prefix<<qname<<": got DS record '"<<rec.d_name<<"' -> '"<<rec.d_content->getZoneRepresentation()<<"'"<<endl);
57769f13 1390 sawDS=true;
1391 }
c32f9f94 1392 else if(!done && rec.d_place==DNSResourceRecord::AUTHORITY && qname.isPartOf(rec.d_name) && rec.d_type==QType::SOA &&
4957a608 1393 lwr.d_rcode==RCode::NoError) {
2189085d 1394 LOG(prefix<<qname<<": got negative caching indication for '"<< qname<<"|"<<qtype.getName()<<"'"<<endl);
3ddb9247 1395
bac969f0 1396 if(!newtarget.empty()) {
2189085d 1397 LOG(prefix<<qname<<": Hang on! Got a redirect to '"<<newtarget<<"' already"<<endl);
bac969f0
BH
1398 }
1399 else {
e325f20c 1400 rec.d_ttl = min(s_maxnegttl, rec.d_ttl);
1401 ret.push_back(rec);
061d67cb 1402 if(!wasVariable()) {
1403 NegCacheEntry ne;
1404 ne.d_qname=rec.d_name;
1405 ne.d_ttd=d_now.tv_sec + rec.d_ttl;
1406 ne.d_name=qname;
1407 ne.d_qtype=qtype;
620db2c8 1408 ne.d_dnssecProof = harvestRecords(lwr.d_records, {QType::NSEC, QType::NSEC3});
061d67cb 1409 if(qtype.getCode()) { // prevents us from blacking out a whole domain
1410 replacing_insert(t_sstorage->negcache, ne);
1411 }
1412 }
bac969f0 1413 negindic=true;
4957a608 1414 }
4957a608 1415 }
86c152f2 1416 }
86c152f2 1417
3ddb9247 1418 if(done){
2189085d 1419 LOG(prefix<<qname<<": status=got results, this level of recursion done"<<endl);
4957a608 1420 return 0;
ac539791 1421 }
c6644fc5 1422 if(!newtarget.empty()) {
e325f20c 1423 if(newtarget == qname) {
2189085d 1424 LOG(prefix<<qname<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl);
4957a608
BH
1425 return RCode::ServFail;
1426 }
1427 if(depth > 10) {
2189085d 1428 LOG(prefix<<qname<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl);
4957a608
BH
1429 return RCode::ServFail;
1430 }
2189085d 1431 LOG(prefix<<qname<<": status=got a CNAME referral, starting over with "<<newtarget<<endl);
4957a608
BH
1432
1433 set<GetBestNSAnswer> beenthere2;
1434 return doResolve(newtarget, qtype, ret, depth + 1, beenthere2);
c6644fc5 1435 }
331c187c 1436 if(lwr.d_rcode==RCode::NXDomain) {
2189085d 1437 LOG(prefix<<qname<<": status=NXDOMAIN, we are done "<<(negindic ? "(have negative SOA)" : "")<<endl);
620db2c8 1438
51e1e6dd 1439 if(d_doDNSSEC)
1440 addNXNSECS(ret, lwr.d_records);
620db2c8 1441
331c187c
BH
1442 return RCode::NXDomain;
1443 }
73c32d1b 1444 if(nsset.empty() && !lwr.d_rcode && (negindic || lwr.d_aabit || sendRDQuery)) {
2189085d 1445 LOG(prefix<<qname<<": status=noerror, other types may exist, but we are done "<<(negindic ? "(have negative SOA) " : "")<<(lwr.d_aabit ? "(have aa bit) " : "")<<endl);
2e921ec6 1446
51e1e6dd 1447 if(d_doDNSSEC)
1448 addNXNSECS(ret, lwr.d_records);
4957a608 1449 return 0;
caa6eefa 1450 }
728485ca 1451 else if(realreferral) {
b8470add 1452 LOG(prefix<<qname<<": status=did not resolve, got "<<(unsigned int)nsset.size()<<" NS, ");
57769f13 1453 if(sawDS) {
1454 t_sstorage->dnssecmap[newauth]=true;
e325f20c 1455 /* for(const auto& e : t_sstorage->dnssecmap)
2189085d 1456 cout<<e.first<<' ';
e325f20c 1457 cout<<endl;*/
57769f13 1458 }
4957a608 1459 auth=newauth;
88490c03
PL
1460
1461 nameservers.clear();
b8470add
PL
1462 for (auto const &nameserver : nsset) {
1463 if (d_wantsRPZ) {
0a273054 1464 d_appliedPolicy = g_luaconfs.getLocal()->dfe.getProcessingPolicy(nameserver, d_discardedPolicies);
b8470add 1465 if (d_appliedPolicy.d_kind != DNSFilterEngine::PolicyKind::NoAction) { // client query needs an RPZ response
0a273054 1466 LOG("however "<<nameserver<<" was blocked by RPZ policy '"<<(d_appliedPolicy.d_name ? *d_appliedPolicy.d_name : "")<<"'"<<endl);
b8470add
PL
1467 return -2;
1468 }
1469 }
fa1b87ff 1470 nameservers.insert({nameserver, {{}, false}});
b8470add
PL
1471 }
1472 LOG("looping to them"<<endl);
710af846 1473 break;
728485ca 1474 }
d7d7a91a 1475 else if(!tns->empty()) { // means: not OOB, OOB == empty
4957a608 1476 goto wasLame;
86c152f2
BH
1477 }
1478 }
86c152f2 1479 }
ac539791 1480 return -1;
86c152f2
BH
1481}
1482
bd53ea9d 1483
8ce79a22 1484// used by PowerDNSLua - note that this neglects to add the packet count & statistics back to pdns_ercursor.cc
a3e7b735 1485int directResolve(const DNSName& qname, const QType& qtype, int qclass, vector<DNSRecord>& ret)
bd53ea9d
PD
1486{
1487 struct timeval now;
1488 gettimeofday(&now, 0);
710af846 1489
bd53ea9d 1490 SyncRes sr(now);
a3e7b735 1491 int res = sr.beginResolve(qname, QType(qtype), qclass, ret);
e325f20c 1492
bd53ea9d
PD
1493 return res;
1494}