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