]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/syncres.cc
remote a lot of silly string processing used for --trace output, even w/o a trace..
[thirdparty/pdns.git] / pdns / syncres.cc
CommitLineData
86c152f2
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
1d5b3ce6 3 Copyright (C) 2003 - 2006 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
BH
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17*/
caa6eefa
BH
18
19#include "utility.hh"
288f4aa9 20#include "syncres.hh"
86c152f2
BH
21#include <iostream>
22#include <map>
23#include <algorithm>
afbe2787 24#include <set>
86c152f2
BH
25#include <cerrno>
26#include <cstdio>
27#include <cstdlib>
86c152f2 28#include <utility>
3de83124 29#include <deque>
c836dc19 30#include "logger.hh"
20177d1d 31#include "misc.hh"
86c152f2
BH
32#include "arguments.hh"
33#include "lwres.hh"
eefd15f9 34#include "recursor_cache.hh"
ea634573 35#include "dnsparser.hh"
eefd15f9
BH
36
37extern MemRecursorCache RC;
86c152f2 38
9fdf67d5
BH
39SyncRes::negcache_t SyncRes::s_negcache;
40SyncRes::nsspeeds_t SyncRes::s_nsSpeeds;
41
7b35aa49 42unsigned int SyncRes::s_queries;
7becf07f 43unsigned int SyncRes::s_outgoingtimeouts;
7b35aa49 44unsigned int SyncRes::s_outqueries;
5c633640 45unsigned int SyncRes::s_tcpoutqueries;
3de83124 46unsigned int SyncRes::s_throttledqueries;
525b8a7c 47unsigned int SyncRes::s_nodelegated;
7b35aa49 48bool SyncRes::s_log;
c836dc19 49
ea634573 50#define LOG if(s_log) L<<Logger::Warning
728485ca 51
cd7bf56b 52Throttle<tuple<string,string,uint16_t> > SyncRes::s_throttle;
3de83124 53
728485ca 54/** everything begins here - this is the entry point just after receiving a packet */
7b35aa49 55int SyncRes::beginResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret)
728485ca 56{
7bf26383 57 set<GetBestNSAnswer> beenthere;
c836dc19 58 s_queries++;
7bf26383 59 int res=doResolve(qname, qtype, ret,0,beenthere);
728485ca
BH
60 if(!res)
61 addCruft(qname, ret);
728485ca
BH
62 return res;
63}
afbe2787 64
7b35aa49 65int SyncRes::doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, set<GetBestNSAnswer>& beenthere)
afbe2787 66{
ded77b10
BH
67
68 string prefix;
69 if(s_log) {
70 prefix=d_prefix;
71 prefix.append(depth, ' ');
72 }
728485ca
BH
73
74 int res;
c836dc19
BH
75 if(!(d_nocache && qtype.getCode()==QType::NS && qname.empty())) {
76 if(doCNAMECacheCheck(qname,qtype,ret,depth,res)) // will reroute us if needed
77 return res;
78
79 if(doCacheCheck(qname,qtype,ret,depth,res)) // we done
80 return res;
81 }
afbe2787 82
c836dc19
BH
83 if(d_cacheonly)
84 return 0;
afbe2787 85
c836dc19 86 LOG<<prefix<<qname<<": No cache hit for '"<<qname<<"|"<<qtype.getName()<<"', trying to find an appropriate NS record"<<endl;
728485ca
BH
87
88 string subdomain(qname);
89
90 set<string> nsset;
bdf40704
BH
91 for(int tries=0;tries<2 && nsset.empty();++tries) {
92 subdomain=getBestNSNamesFromCache(subdomain,nsset,depth, beenthere); // pass beenthere to both occasions
93
94 if(nsset.empty()) { // must've lost root records
95 LOG<<prefix<<qname<<": our root expired, repriming from hints and retrying"<<endl;
96 primeHints();
97 }
98 }
99
7bf26383 100 if(!(res=doResolveAt(nsset,subdomain,qname,qtype,ret,depth, beenthere)))
728485ca
BH
101 return 0;
102
c836dc19 103 LOG<<prefix<<qname<<": failed"<<endl;
20177d1d 104 return res<0 ? RCode::ServFail : res;
afbe2787
BH
105}
106
bfea0d0b 107vector<string> SyncRes::getAs(const string &qname, int depth, set<GetBestNSAnswer>& beenthere)
75b49099 108{
bfea0d0b
BH
109 typedef vector<DNSResourceRecord> res_t;
110 res_t res;
75b49099 111
bfea0d0b 112 vector<string> ret;
75b49099 113
bfea0d0b
BH
114 if(!doResolve(qname,QType(QType::A), res,depth+1,beenthere) && !res.empty()) {
115 for(res_t::const_iterator i=res.begin(); i!= res.end(); ++i)
116 if(i->qtype.getCode()==QType::A)
117 ret.push_back(i->content);
118 }
119 if(ret.size() > 1)
120 random_shuffle(ret.begin(), ret.end());
728485ca 121 return ret;
75b49099
BH
122}
123
7b35aa49 124void SyncRes::getBestNSFromCache(const string &qname, set<DNSResourceRecord>&bestns, int depth, set<GetBestNSAnswer>& beenthere)
86c152f2 125{
ded77b10
BH
126 string prefix, subdomain(qname);
127 if(s_log) {
128 prefix=d_prefix;
129 prefix.append(depth, ' ');
130 }
75b49099
BH
131 bestns.clear();
132
75b49099 133 do {
c836dc19 134 LOG<<prefix<<qname<<": Checking if we have NS in cache for '"<<subdomain<<"'"<<endl;
7bf26383 135 set<DNSResourceRecord>ns;
b0d4fb45 136 if(RC.get(d_now.tv_sec, subdomain, QType(QType::NS), &ns)>0) {
36c5ee42 137
7bf26383 138 for(set<DNSResourceRecord>::const_iterator k=ns.begin();k!=ns.end();++k) {
d6d5dea7 139 if(k->ttl > (unsigned int)d_now.tv_sec ) {
7bf26383 140 set<DNSResourceRecord>aset;
b0d4fb45 141
eab7dbda
BH
142 DNSResourceRecord rr=*k;
143 rr.content=toLowerCanonic(k->content);
144 if(!endsOn(rr.content,subdomain) || RC.get(d_now.tv_sec, rr.content ,QType(QType::A),&aset) > 5) {
b0d4fb45 145 bestns.insert(rr);
9fdf67d5 146
b0d4fb45
BH
147 LOG<<prefix<<qname<<": NS (with ip, or non-glue) in cache for '"<<subdomain<<"' -> '"<<rr.content<<"'"<<endl;
148 LOG<<prefix<<qname<<": within bailiwick: "<<endsOn(rr.content,subdomain);
9fdf67d5
BH
149 if(!aset.empty()) {
150 LOG<<", in cache, ttl="<<(unsigned int)(((time_t)aset.begin()->ttl- d_now.tv_sec ))<<endl;
151 }
152 else {
153 LOG<<", not in cache"<<endl;
154 }
0d8612f2 155 }
20177d1d 156 else
b0d4fb45 157 LOG<<prefix<<qname<<": NS in cache for '"<<subdomain<<"', but needs glue ("<<toLowerCanonic(k->content)<<") which we miss or is expired"<<endl;
ac539791 158 }
afbe2787 159 }
75b49099 160 if(!bestns.empty()) {
7bf26383
BH
161 GetBestNSAnswer answer;
162 answer.qname=toLower(qname); answer.bestns=bestns;
163 if(beenthere.count(answer)) {
c836dc19 164 LOG<<prefix<<qname<<": We have NS in cache for '"<<subdomain<<"' but part of LOOP! Trying less specific NS"<<endl;
7b35aa49 165 for( set<GetBestNSAnswer>::const_iterator j=beenthere.begin();j!=beenthere.end();++j)
c836dc19 166 LOG<<prefix<<qname<<": beenthere: "<<j->qname<<" ("<<j->bestns.size()<<")"<<endl;
7bf26383
BH
167 bestns.clear();
168 }
169 else {
170 beenthere.insert(answer);
c836dc19 171 LOG<<prefix<<qname<<": We have NS in cache for '"<<subdomain<<"'"<<endl;
7bf26383
BH
172 return;
173 }
75b49099 174 }
afbe2787 175 }
75b49099
BH
176 }while(chopOff(subdomain));
177}
178
288f4aa9 179
7bf26383 180/** doesn't actually do the work, leaves that to getBestNSFromCache */
7b35aa49 181string SyncRes::getBestNSNamesFromCache(const string &qname,set<string>& nsset, int depth, set<GetBestNSAnswer>&beenthere)
75b49099
BH
182{
183 string subdomain(qname);
184
185 set<DNSResourceRecord> bestns;
7bf26383 186 getBestNSFromCache(subdomain, bestns, depth, beenthere);
75b49099
BH
187
188 for(set<DNSResourceRecord>::const_iterator k=bestns.begin();k!=bestns.end();++k) {
189 nsset.insert(k->content);
190 subdomain=k->qname;
86c152f2 191 }
75b49099 192 return subdomain;
afbe2787
BH
193}
194
7b35aa49 195bool SyncRes::doCNAMECacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res)
afbe2787 196{
ded77b10
BH
197 string prefix;
198 if(s_log) {
199 prefix=d_prefix;
200 prefix.append(depth, ' ');
201 }
36f5e3db 202
c6644fc5 203 if(depth>10) {
c836dc19 204 LOG<<prefix<<qname<<": CNAME loop too deep, depth="<<depth<<endl;
c6644fc5
BH
205 res=RCode::ServFail;
206 return true;
207 }
36f5e3db 208
ded77b10 209 LOG<<prefix<<qname<<": Looking for CNAME cache hit of '"<<(toLowerCanonic(qname)+"|CNAME")<<"'"<<endl;
7bf26383 210 set<DNSResourceRecord> cset;
d6d5dea7 211 if(RC.get(d_now.tv_sec, qname,QType(QType::CNAME),&cset) > 0) {
36c5ee42 212
7bf26383 213 for(set<DNSResourceRecord>::const_iterator j=cset.begin();j!=cset.end();++j) {
d6d5dea7 214 if(j->ttl>(unsigned int) d_now.tv_sec) {
ded77b10 215 LOG<<prefix<<qname<<": Found cache CNAME hit for '"<< (toLowerCanonic(qname)+"|CNAME") <<"' to '"<<j->content<<"'"<<endl;
ac539791 216 DNSResourceRecord rr=*j;
d6d5dea7 217 rr.ttl-=d_now.tv_sec;
ac539791 218 ret.push_back(rr);
b0d4fb45 219 if(!(qtype==QType(QType::CNAME))) { // perhaps they really wanted a CNAME!
7bf26383 220 set<GetBestNSAnswer>beenthere;
b0d4fb45 221 res=doResolve(toLowerCanonic(j->content), qtype, ret, depth+1, beenthere);
7bf26383 222 }
b0d4fb45
BH
223 else
224 res=0;
75b49099 225 return true;
ac539791
BH
226 }
227 }
afbe2787 228 }
ded77b10 229 LOG<<prefix<<qname<<": No CNAME cache hit of '"<< (toLowerCanonic(qname)+"|CNAME") <<"' found"<<endl;
75b49099
BH
230 return false;
231}
232
7b35aa49 233bool SyncRes::doCacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res)
75b49099 234{
fd8bc993 235 bool giveNegative=false;
ded77b10
BH
236
237 string prefix, tuple;
238 if(s_log) {
239 prefix=d_prefix;
240 prefix.append(depth, ' ');
241 }
afbe2787 242
288f4aa9
BH
243 string sqname(qname);
244 QType sqt(qtype);
092f210a 245 uint32_t sttl=0;
afbe2787 246
fd8bc993
BH
247 if(s_negcache.count(toLower(qname))) {
248 res=0;
9fdf67d5 249 negcache_t::const_iterator ni=s_negcache.find(toLower(qname));
d6d5dea7
BH
250 if(d_now.tv_sec < ni->second.ttd) {
251 sttl=ni->second.ttd - d_now.tv_sec;
38e22b5a
BH
252 LOG<<prefix<<qname<<": Entire record '"<<toLower(qname)<<"', is negatively cached for another "<<sttl<<" seconds"<<endl;
253 res=RCode::NXDomain;
254 giveNegative=true;
255 sqname=ni->second.name;
256 sqt="SOA";
38e22b5a
BH
257 }
258 else {
259 LOG<<prefix<<qname<<": Entire record '"<<toLower(qname)<<"' was negatively cached, but entry expired"<<endl;
260 s_negcache.erase(toLower(qname));
261 }
20177d1d 262 }
38e22b5a
BH
263
264 if(!giveNegative) { // let's try some more
9fdf67d5 265 tuple=toLower(qname); tuple.append(1,'|'); tuple+=qtype.getName();
bdf40704 266 LOG<<prefix<<qname<<": Looking for direct cache hit of '"<<tuple<<"', negative cached: "<<s_negcache.count(tuple)<<endl;
fd8bc993
BH
267
268 res=0;
9fdf67d5 269 negcache_t::const_iterator ni=s_negcache.find(tuple);
fd8bc993 270 if(ni!=s_negcache.end()) {
d6d5dea7
BH
271 if(d_now.tv_sec < ni->second.ttd) {
272 sttl=ni->second.ttd - d_now.tv_sec;
38e22b5a
BH
273 LOG<<prefix<<qname<<": "<<qtype.getName()<<" is negatively cached for another "<<sttl<<" seconds"<<endl;
274 res=RCode::NoError; // only this record doesn't exist
275 giveNegative=true;
276 sqname=ni->second.name;
277 sqt="SOA";
278 }
279 else {
280 LOG<<prefix<<qname<<": "<<qtype.getName()<<" was negatively cached, but entry expired"<<endl;
281 s_negcache.erase(toLower(tuple));
282 }
fd8bc993
BH
283 }
284 }
20177d1d 285
7bf26383 286 set<DNSResourceRecord> cset;
75b49099 287 bool found=false, expired=false;
d6d5dea7 288 if(RC.get(d_now.tv_sec, sqname,sqt,&cset)>0) {
c836dc19 289 LOG<<prefix<<qname<<": Found cache hit for "<<sqt.getName()<<": ";
7bf26383 290 for(set<DNSResourceRecord>::const_iterator j=cset.begin();j!=cset.end();++j) {
c836dc19 291 LOG<<j->content;
d6d5dea7 292 if(j->ttl>(unsigned int) d_now.tv_sec) {
ac539791 293 DNSResourceRecord rr=*j;
d6d5dea7 294 rr.ttl-=d_now.tv_sec;
38e22b5a 295 if(giveNegative) {
20177d1d 296 rr.d_place=DNSResourceRecord::AUTHORITY;
38e22b5a
BH
297 rr.ttl=sttl;
298 }
ac539791 299 ret.push_back(rr);
c836dc19 300 LOG<<"[ttl="<<rr.ttl<<"] ";
75b49099 301 found=true;
ac539791 302 }
75b49099 303 else {
c836dc19 304 LOG<<"[expired] ";
75b49099
BH
305 expired=true;
306 }
afbe2787 307 }
ac539791 308
c836dc19 309 LOG<<endl;
20177d1d 310 if(found && !expired)
75b49099 311 return true;
75b49099 312 else
c836dc19 313 LOG<<prefix<<qname<<": cache had only stale entries"<<endl;
afbe2787 314 }
75b49099
BH
315 return false;
316}
afbe2787 317
7b35aa49 318bool SyncRes::moreSpecificThan(const string& a, const string &b)
75b49099 319{
728485ca 320 int counta=!a.empty(), countb=!b.empty();
afbe2787 321
728485ca
BH
322 for(string::size_type n=0;n<a.size();++n)
323 if(a[n]=='.')
324 counta++;
325 for(string::size_type n=0;n<b.size();++n)
326 if(b[n]=='.')
327 countb++;
328 return counta>countb;
afbe2787
BH
329}
330
8a5602d4 331
eefd15f9 332
d8d0bb8f 333struct speedOrder
eefd15f9 334{
d8d0bb8f 335 speedOrder(map<string,double> &speeds) : d_speeds(speeds) {}
c3d9d009
BH
336 bool operator()(const string &a, const string &b) const
337 {
338 return d_speeds[a] < d_speeds[b];
c3d9d009
BH
339 }
340 map<string,double>& d_speeds;
341};
342
d8d0bb8f 343inline vector<string> SyncRes::shuffle(set<string> &nameservers, const string &prefix)
afbe2787 344{
728485ca 345 vector<string> rnameservers;
c3d9d009
BH
346 rnameservers.reserve(nameservers.size());
347 map<string,double> speeds;
eefd15f9
BH
348
349 for(set<string>::const_iterator i=nameservers.begin();i!=nameservers.end();++i) {
728485ca 350 rnameservers.push_back(*i);
8a5602d4 351 DecayingEwma& temp=s_nsSpeeds[toLower(*i)];
d6d5dea7 352 speeds[*i]=temp.get(&d_now);
eefd15f9 353 }
728485ca 354 random_shuffle(rnameservers.begin(),rnameservers.end());
ded77b10 355 stable_sort(rnameservers.begin(),rnameservers.end(), speedOrder(speeds));
eefd15f9 356
d8d0bb8f
BH
357 if(s_log) {
358 L<<Logger::Warning<<prefix<<"Nameservers: ";
359 for(vector<string>::const_iterator i=rnameservers.begin();i!=rnameservers.end();++i) {
360 if(i!=rnameservers.begin()) {
361 L<<", ";
362 if(!((i-rnameservers.begin())%4))
363 L<<endl<<Logger::Warning<<prefix<<" ";
364 }
49f076e8 365 L<<*i<<"(" << (int)(speeds[*i]/1000.0) <<"ms)";
d8d0bb8f
BH
366 }
367 L<<endl;
368 }
728485ca 369 return rnameservers;
afbe2787
BH
370}
371
ac539791 372/** returns -1 in case of no results, rcode otherwise */
7b35aa49 373int SyncRes::doResolveAt(set<string> nameservers, string auth, const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret,
7bf26383 374 int depth, set<GetBestNSAnswer>&beenthere)
86c152f2 375{
ded77b10
BH
376 string prefix;
377 if(s_log) {
378 prefix=d_prefix;
379 prefix.append(depth, ' ');
380 }
86c152f2 381
86c152f2 382 LWRes::res_t result;
86c152f2 383
c836dc19 384 LOG<<prefix<<qname<<": Cache consultations done, have "<<nameservers.size()<<" NS to contact"<<endl;
afbe2787
BH
385
386 for(;;) { // we may get more specific nameservers
86c152f2
BH
387 result.clear();
388
ded77b10 389 vector<string> rnameservers=shuffle(nameservers, s_log ? (prefix+qname+": ") : string() );
20177d1d 390
728485ca
BH
391 for(vector<string>::const_iterator tns=rnameservers.begin();;++tns) {
392 if(tns==rnameservers.end()) {
c836dc19 393 LOG<<prefix<<qname<<": Failed to resolve via any of the "<<rnameservers.size()<<" offered NS"<<endl;
ac539791 394 return -1;
afbe2787 395 }
288f4aa9 396 if(qname==*tns && qtype.getCode()==QType::A) {
c836dc19 397 LOG<<prefix<<qname<<": Not using NS to resolve itself!"<<endl;
20177d1d
BH
398 continue;
399 }
c836dc19 400 LOG<<prefix<<qname<<": Trying to resolve NS "<<*tns<<" ("<<1+tns-rnameservers.begin()<<"/"<<rnameservers.size()<<")"<<endl;
bfea0d0b
BH
401 typedef vector<string> remoteIPs_t;
402 remoteIPs_t remoteIPs=getAs(*tns, depth+1, beenthere);
403 if(remoteIPs.empty()) {
c836dc19 404 LOG<<prefix<<qname<<": Failed to get IP for NS "<<*tns<<", trying next if available"<<endl;
afbe2787
BH
405 continue;
406 }
bfea0d0b 407 remoteIPs_t::const_iterator remoteIP;
5c633640 408 bool doTCP=false;
bfea0d0b
BH
409 for(remoteIP = remoteIPs.begin(); remoteIP != remoteIPs.end(); ++remoteIP) {
410 LOG<<prefix<<qname<<": Resolved '"+auth+"' NS "<<*tns<<" to "<<*remoteIP<<", asking '"<<qname<<"|"<<qtype.getName()<<"'"<<endl;
411
cd7bf56b 412 if(s_throttle.shouldThrottle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()))) {
bfea0d0b
BH
413 LOG<<prefix<<qname<<": query throttled "<<endl;
414 s_throttledqueries++;
415 d_throttledqueries++;
416 continue;
5c633640 417 }
bfea0d0b
BH
418 else {
419 s_outqueries++;
420 d_outqueries++;
421 TryTCP:
422 if(doTCP) {
423 s_tcpoutqueries++;
424 d_tcpoutqueries++;
7becf07f 425 }
7becf07f 426
5e3da48d 427 int ret=d_lwr.asyncresolve(*remoteIP, qname.c_str(), qtype.getCode(), doTCP, &d_now); // <- we go out on the wire!
bfea0d0b
BH
428 if(ret != 1) {
429 if(ret==0) {
430 LOG<<prefix<<qname<<": timeout resolving"<<endl;
431 d_timeouts++;
432 s_outgoingtimeouts++;
433 }
434 else
435 LOG<<prefix<<qname<<": error resolving"<<endl;
436
437 s_nsSpeeds[toLower(*tns)].submit(1000000, &d_now); // 1 sec
438
cd7bf56b 439 s_throttle.throttle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()),20,5);
bfea0d0b
BH
440 continue;
441 }
5e3da48d 442
bfea0d0b 443 break; // it did work!
3de83124
BH
444 }
445 }
20177d1d 446
bfea0d0b
BH
447 if(remoteIP == remoteIPs.end()) // we tried all IP addresses, none worked
448 continue;
449
eefd15f9 450 result=d_lwr.result();
66ab6a63 451
d0166f4a
BH
452 if(d_lwr.d_tcbit) {
453 if(!doTCP) {
454 doTCP=true;
455 LOG<<prefix<<qname<<": truncated bit set, retrying via TCP"<<endl;
456 goto TryTCP;
457 }
458 LOG<<prefix<<qname<<": truncated bit set, over TCP?"<<endl;
459 return RCode::ServFail;
460 }
461
288f4aa9 462 if(d_lwr.d_rcode==RCode::ServFail) {
c836dc19 463 LOG<<prefix<<qname<<": "<<*tns<<" returned a ServFail, trying sibling NS"<<endl;
cd7bf56b 464 s_throttle.throttle(d_now.tv_sec,make_tuple(*remoteIP, qname, qtype.getCode()),60,3);
20177d1d
BH
465 continue;
466 }
bfea0d0b 467 LOG<<prefix<<qname<<": Got "<<result.size()<<" answers from "<<*tns<<" ("<<*remoteIP<<"), rcode="<<d_lwr.d_rcode<<", in "<<d_lwr.d_usec/1000<<"ms"<<endl;
8a5602d4 468 s_nsSpeeds[toLower(*tns)].submit(d_lwr.d_usec, &d_now);
20177d1d 469
288f4aa9 470 map<string,set<DNSResourceRecord> > tcache;
728485ca
BH
471 // reap all answers from this packet that are acceptable
472 for(LWRes::res_t::const_iterator i=result.begin();i!=result.end();++i) {
6cf876a2
BH
473 if(i->qtype.getCode() < 1024) {
474 LOG<<prefix<<qname<<": accept answer '"<<i->qname<<"|"<<i->qtype.getName()<<"|"<<i->content<<"' from '"<<auth<<"' nameservers? ";
475 }
476 else {
477 LOG<<prefix<<qname<<": accept opaque answer '"<<i->qname<<"|"<<QType(i->qtype.getCode()-1024).getName()<<" from '"<<auth<<"' nameservers? ";
478 }
479
562588a3 480 if(endsOn(i->qname, auth)) {
84de7c8a 481 if(d_lwr.d_aabit && d_lwr.d_rcode==RCode::NoError && i->d_place==DNSResourceRecord::ANSWER && ::arg().contains("delegation-only",auth)) {
562588a3 482 LOG<<"NO! Is from delegation-only zone"<<endl;
525b8a7c 483 s_nodelegated++;
562588a3
BH
484 return RCode::NXDomain;
485 }
486 else {
487 LOG<<"YES!"<<endl;
488
489 DNSResourceRecord rr=*i;
490 rr.d_place=DNSResourceRecord::ANSWER;
d6d5dea7 491 rr.ttl+=d_now.tv_sec;
562588a3
BH
492 // rr.ttl=time(0)+10+10*rr.qtype.getCode();
493 tcache[toLower(i->qname)+"|"+i->qtype.getName()].insert(rr);
494 }
495 }
728485ca 496 else
c836dc19 497 LOG<<"NO!"<<endl;
86c152f2 498 }
728485ca
BH
499
500 // supplant
288f4aa9
BH
501 for(map<string,set<DNSResourceRecord> >::const_iterator i=tcache.begin();i!=tcache.end();++i) {
502 vector<string>parts;
503 stringtok(parts,i->first,"|");
504 QType qt;
505 if(parts.size()==2) {
506 qt=parts[1];
eefd15f9 507 RC.replace(parts[0],qt,i->second);
288f4aa9
BH
508 }
509 else {
510 qt=parts[0];
eefd15f9 511 RC.replace("",qt,i->second);
288f4aa9
BH
512 }
513 }
728485ca 514 set<string> nsset;
c836dc19 515 LOG<<prefix<<qname<<": determining status after receiving this packet"<<endl;
728485ca 516
20177d1d 517 bool done=false, realreferral=false, negindic=false;
c6644fc5 518 string newauth, soaname, newtarget;
728485ca
BH
519
520 for(LWRes::res_t::const_iterator i=result.begin();i!=result.end();++i) {
fd8bc993
BH
521 if(i->d_place==DNSResourceRecord::AUTHORITY && endsOn(qname,i->qname) && i->qtype.getCode()==QType::SOA &&
522 d_lwr.d_rcode==RCode::NXDomain) {
523 LOG<<prefix<<qname<<": got negative caching indication for RECORD '"<<toLower(qname)+"'"<<endl;
728485ca 524 ret.push_back(*i);
fd8bc993 525
38e22b5a
BH
526 NegCacheEntry ne;
527 ne.name=i->qname;
d6d5dea7 528 ne.ttd=d_now.tv_sec + i->ttl;
38e22b5a 529 s_negcache[toLower(qname)]=ne;
20177d1d 530 negindic=true;
728485ca
BH
531 }
532 else if(i->d_place==DNSResourceRecord::ANSWER && i->qname==qname && i->qtype.getCode()==QType::CNAME && (!(qtype==QType(QType::CNAME)))) {
728485ca 533 ret.push_back(*i);
b0d4fb45 534 newtarget=toLowerCanonic(i->content);
728485ca
BH
535 }
536 // for ANY answers we *must* have an authoritive answer
6cf876a2
BH
537 else if(i->d_place==DNSResourceRecord::ANSWER && toLower(i->qname)==toLower(qname) &&
538 (((i->qtype==qtype) || (i->qtype.getCode()>1024 && i->qtype.getCode()-1024==qtype.getCode())) || ( qtype==QType(QType::ANY) &&
6cf876a2
BH
539 d_lwr.d_aabit))) {
540 if(i->qtype.getCode() < 1024) {
541 LOG<<prefix<<qname<<": answer is in: resolved to '"<< i->content<<"|"<<i->qtype.getName()<<"'"<<endl;
542 }
543 else {
544 LOG<<prefix<<qname<<": answer is in: resolved to opaque record of type '"<<QType(i->qtype.getCode()-1024).getName()<<"'"<<endl;
545 }
546
728485ca
BH
547 done=true;
548 ret.push_back(*i);
549 }
550 else if(i->d_place==DNSResourceRecord::AUTHORITY && endsOn(qname,i->qname) && i->qtype.getCode()==QType::NS) {
551 if(moreSpecificThan(i->qname,auth)) {
552 newauth=i->qname;
c836dc19 553 LOG<<prefix<<qname<<": got NS record '"<<i->qname<<"' -> '"<<i->content<<"'"<<endl;
728485ca
BH
554 realreferral=true;
555 }
7bf26383 556 else
c836dc19 557 LOG<<prefix<<qname<<": got upwards/level NS record '"<<i->qname<<"' -> '"<<i->content<<"', had '"<<auth<<"'"<<endl;
b0d4fb45 558 nsset.insert(toLowerCanonic(i->content));
728485ca 559 }
fd8bc993
BH
560 else if(i->d_place==DNSResourceRecord::AUTHORITY && endsOn(qname,i->qname) && i->qtype.getCode()==QType::SOA &&
561 d_lwr.d_rcode==RCode::NoError) {
562 LOG<<prefix<<qname<<": got negative caching indication for '"<<toLower(qname)+"|"+i->qtype.getName()+"'"<<endl;
563 ret.push_back(*i);
38e22b5a
BH
564
565 NegCacheEntry ne;
566 ne.name=i->qname;
d6d5dea7 567 ne.ttd=d_now.tv_sec + i->ttl;
38e22b5a 568 s_negcache[toLower(qname)+"|"+qtype.getName()]=ne;
fd8bc993
BH
569 negindic=true;
570 }
86c152f2 571 }
86c152f2 572
728485ca 573 if(done){
c836dc19 574 LOG<<prefix<<qname<<": status=got results, this level of recursion done"<<endl;
728485ca 575 return 0;
ac539791 576 }
288f4aa9 577 if(d_lwr.d_rcode==RCode::NXDomain) {
c836dc19 578 LOG<<prefix<<qname<<": status=NXDOMAIN, we are done "<<(negindic ? "(have negative SOA)" : "")<<endl;
728485ca 579 return RCode::NXDomain;
86c152f2 580 }
c6644fc5 581 if(!newtarget.empty()) {
c836dc19 582 LOG<<prefix<<qname<<": status=got a CNAME referral, starting over with "<<newtarget<<endl;
c6644fc5
BH
583 set<GetBestNSAnswer>beenthere2;
584 return doResolve(newtarget, qtype, ret,0,beenthere2);
585 }
caa6eefa
BH
586 if(nsset.empty() && !d_lwr.d_rcode) {
587 LOG<<prefix<<qname<<": status=noerror, other types may exist, but we are done "<<(negindic ? "(have negative SOA)" : "")<<endl;
588 return 0;
589 }
728485ca 590 else if(realreferral) {
c836dc19 591 LOG<<prefix<<qname<<": status=did not resolve, got "<<nsset.size()<<" NS, looping to them"<<endl;
728485ca
BH
592 auth=newauth;
593 nameservers=nsset;
594 break;
595 }
596 else {
c836dc19 597 LOG<<prefix<<qname<<": status=NS "<<*tns<<" is lame for '"<<auth<<"', trying sibling NS"<<endl;
cd7bf56b 598 s_throttle.throttle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()),60,0);
86c152f2
BH
599 }
600 }
86c152f2 601 }
ac539791 602 return -1;
86c152f2
BH
603}
604
7b35aa49 605void SyncRes::addCruft(const string &qname, vector<DNSResourceRecord>& ret)
728485ca
BH
606{
607 for(vector<DNSResourceRecord>::const_iterator k=ret.begin();k!=ret.end();++k) // don't add stuff to an NXDOMAIN!
608 if(k->d_place==DNSResourceRecord::AUTHORITY && k->qtype==QType(QType::SOA))
609 return;
610
c836dc19 611 // LOG<<qname<<": Adding best authority records from cache"<<endl;
288f4aa9 612 // addAuthorityRecords(qname,ret,0);
c836dc19 613 // LOG<<qname<<": Done adding best authority records."<<endl;
728485ca 614
c836dc19 615 LOG<<d_prefix<<qname<<": Starting additional processing"<<endl;
728485ca 616 vector<DNSResourceRecord> addit;
84de7c8a 617 bool doIPv6AP=::arg().mustDo("aaaa-additional-processing");
728485ca
BH
618 for(vector<DNSResourceRecord>::const_iterator k=ret.begin();k!=ret.end();++k)
619 if((k->d_place==DNSResourceRecord::ANSWER && k->qtype==QType(QType::MX)) ||
288f4aa9 620 ((k->d_place==DNSResourceRecord::AUTHORITY || k->d_place==DNSResourceRecord::ANSWER) && k->qtype==QType(QType::NS))) {
d8d0bb8f 621 LOG<<d_prefix<<qname<<": record '"<<k->content<<"|"<<k->qtype.getName()<<"' needs IP for additional processing"<<endl;
7bf26383 622 set<GetBestNSAnswer>beenthere;
ea634573 623 if(k->qtype==QType(QType::MX)) {
a1754c6a 624 string::size_type pos=k->content.find_first_not_of(" \t0123456789"); // chop off the priority
e29f6ed0 625 if(pos!=string::npos) {
f814d7c8 626 doResolve(toLowerCanonic(k->content.substr(pos)), QType(QType::A),addit,1,beenthere);
e29f6ed0
BH
627 if(doIPv6AP)
628 doResolve(toLowerCanonic(k->content.substr(pos)), QType(QType::AAAA),addit,1,beenthere);
629 }
630 else {
f814d7c8 631 doResolve(toLowerCanonic(k->content), QType(QType::A),addit,1,beenthere);
e29f6ed0
BH
632 if(doIPv6AP)
633 doResolve(toLowerCanonic(k->content.substr(pos)), QType(QType::AAAA),addit,1,beenthere);
634 }
ea634573 635 }
e29f6ed0 636 else {
ea634573 637 doResolve(k->content,QType(QType::A),addit,1,beenthere);
e29f6ed0
BH
638 if(doIPv6AP)
639 doResolve(k->content,QType(QType::AAAA),addit,1,beenthere);
640 }
728485ca
BH
641 }
642
643 for(vector<DNSResourceRecord>::iterator k=addit.begin();k!=addit.end();++k) {
288f4aa9
BH
644 if(k->qtype.getCode()==QType::A || k->qtype.getCode()==QType::AAAA) {
645 k->d_place=DNSResourceRecord::ADDITIONAL;
646 ret.push_back(*k);
647 }
728485ca 648 }
c836dc19 649 LOG<<d_prefix<<qname<<": Done with additional processing"<<endl;
728485ca
BH
650}
651
7b35aa49 652void SyncRes::addAuthorityRecords(const string& qname, vector<DNSResourceRecord>& ret, int depth)
86c152f2 653{
288f4aa9
BH
654 set<DNSResourceRecord> bestns;
655 set<GetBestNSAnswer>beenthere;
656 getBestNSFromCache(qname, bestns, depth,beenthere);
36c5ee42 657
288f4aa9
BH
658 for(set<DNSResourceRecord>::const_iterator k=bestns.begin();k!=bestns.end();++k) {
659 DNSResourceRecord ns=*k;
660 ns.d_place=DNSResourceRecord::AUTHORITY;
d6d5dea7 661 ns.ttl-=d_now.tv_sec;
288f4aa9 662 ret.push_back(ns);
86c152f2
BH
663 }
664}