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