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