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