]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/syncres.cc
reprime root hints using EDNS0, thanks to dns-operations AT mail.oarc.isc.org
[thirdparty/pdns.git] / pdns / syncres.cc
CommitLineData
86c152f2
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
263f6a5a 3 Copyright (C) 2003 - 2007 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
06bd9ccf 16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
86c152f2 17*/
caa6eefa 18
c9f52071 19#include <boost/algorithm/string.hpp>
caa6eefa 20#include "utility.hh"
288f4aa9 21#include "syncres.hh"
86c152f2
BH
22#include <iostream>
23#include <map>
24#include <algorithm>
afbe2787 25#include <set>
86c152f2
BH
26#include <cerrno>
27#include <cstdio>
28#include <cstdlib>
86c152f2 29#include <utility>
3de83124 30#include <deque>
c836dc19 31#include "logger.hh"
20177d1d 32#include "misc.hh"
86c152f2
BH
33#include "arguments.hh"
34#include "lwres.hh"
eefd15f9 35#include "recursor_cache.hh"
ea634573 36#include "dnsparser.hh"
eefd15f9
BH
37
38extern MemRecursorCache RC;
86c152f2 39
9fdf67d5
BH
40SyncRes::negcache_t SyncRes::s_negcache;
41SyncRes::nsspeeds_t SyncRes::s_nsSpeeds;
a9af3782 42unsigned int SyncRes::s_maxnegttl;
7b35aa49 43unsigned int SyncRes::s_queries;
7becf07f 44unsigned int SyncRes::s_outgoingtimeouts;
7b35aa49 45unsigned int SyncRes::s_outqueries;
5c633640 46unsigned int SyncRes::s_tcpoutqueries;
3de83124 47unsigned int SyncRes::s_throttledqueries;
525b8a7c 48unsigned int SyncRes::s_nodelegated;
c571588b 49unsigned int SyncRes::s_unreachables;
996c89cc 50bool SyncRes::s_doIPv6;
c571588b 51
5605c067 52SyncRes::domainmap_t SyncRes::s_domainmap;
a9af3782 53string SyncRes::s_serverID;
7b35aa49 54bool SyncRes::s_log;
c836dc19 55
ea634573 56#define LOG if(s_log) L<<Logger::Warning
728485ca 57
996c89cc 58SyncRes::throttle_t SyncRes::s_throttle;
3de83124 59
728485ca 60/** everything begins here - this is the entry point just after receiving a packet */
a9af3782 61int SyncRes::beginResolve(const string &qname, const QType &qtype, uint16_t qclass, vector<DNSResourceRecord>&ret)
728485ca 62{
c836dc19 63 s_queries++;
705f31ae
BH
64 if( (qtype.getCode()==QType::PTR && !Utility::strcasecmp(qname.c_str(), "1.0.0.127.in-addr.arpa.")) ||
65 (qtype.getCode()==QType::A && qname.length()==10 && !Utility::strcasecmp(qname.c_str(), "localhost."))) {
31ad43ab
BH
66 ret.clear();
67 DNSResourceRecord rr;
68 rr.qname=qname;
69 rr.qtype=qtype;
a9af3782 70 rr.qclass=1;
31ad43ab
BH
71 rr.ttl=86400;
72 if(qtype.getCode()==QType::PTR)
73 rr.content="localhost.";
74 else
75 rr.content="127.0.0.1";
76 ret.push_back(rr);
77 return 0;
78 }
79
a9af3782 80 if(qclass==3 && qtype.getCode()==QType::TXT &&
705f31ae 81 (!Utility::strcasecmp(qname.c_str(), "version.bind.") || !Utility::strcasecmp(qname.c_str(), "id.server.") || !Utility::strcasecmp(qname.c_str(), "version.pdns.") )
a9af3782
BH
82 ) {
83 ret.clear();
84 DNSResourceRecord rr;
85 rr.qname=qname;
86 rr.qtype=qtype;
87 rr.qclass=qclass;
88 rr.ttl=86400;
705f31ae 89 if(!Utility::strcasecmp(qname.c_str(),"version.bind.") || !Utility::strcasecmp(qname.c_str(),"version.pdns."))
a9af3782
BH
90 rr.content="\""+::arg()["version-string"]+"\"";
91 else
92 rr.content="\""+s_serverID+"\"";
93 ret.push_back(rr);
94 return 0;
95 }
9a97cc5c 96
a114f49e
BH
97 if(qclass==0xff)
98 qclass=1;
99 else if(qclass!=1)
9a97cc5c
BH
100 return -1;
101
31ad43ab 102 set<GetBestNSAnswer> beenthere;
809fe23f 103 int res=doResolve(qname, qtype, ret, 0, beenthere);
728485ca
BH
104 if(!res)
105 addCruft(qname, ret);
728485ca
BH
106 return res;
107}
afbe2787 108
ab5c053d 109//! This is the 'out of band resolver', in other words, the authoritative server
e93c956b
BH
110bool SyncRes::doOOBResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int& res)
111{
5605c067
BH
112 string prefix;
113 if(s_log) {
114 prefix=d_prefix;
115 prefix.append(depth, ' ');
116 }
117
118 LOG<<prefix<<qname<<": checking auth storage for '"<<qname<<"|"<<qtype.getName()<<"'"<<endl;
119 string authdomain(qname);
120
121 domainmap_t::const_iterator iter=getBestAuthZone(&authdomain);
122 if(iter==s_domainmap.end()) {
123 LOG<<prefix<<qname<<": auth storage has no zone for this query!"<<endl;
124 return false;
125 }
126 LOG<<prefix<<qname<<": auth storage has data, zone='"<<authdomain<<"'"<<endl;
127 pair<AuthDomain::records_t::const_iterator, AuthDomain::records_t::const_iterator> range;
128
129 range=iter->second.d_records.equal_range(tie(qname)); // partial lookup
130
131 ret.clear();
132 AuthDomain::records_t::const_iterator ziter;
9e9844e2 133 bool somedata=false;
5605c067 134 for(ziter=range.first; ziter!=range.second; ++ziter) {
9e9844e2 135 somedata=true;
9bc8c14c 136 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
137 ret.push_back(*ziter);
138 }
9bc8c14c
BH
139 if(!ret.empty()) {
140 LOG<<prefix<<qname<<": exact match in zone '"<<authdomain<<"'"<<endl;
141 res=0;
142 return true;
5605c067 143 }
9e9844e2
BH
144 if(somedata) {
145 LOG<<prefix<<qname<<": found record in '"<<authdomain<<"', but nothing of the right type, sending SOA"<<endl;
146 ziter=iter->second.d_records.find(make_tuple(authdomain, QType(QType::SOA)));
147 if(ziter!=iter->second.d_records.end()) {
148 DNSResourceRecord rr=*ziter;
149 rr.d_place=DNSResourceRecord::AUTHORITY;
150 ret.push_back(rr);
151 }
152 else
153 LOG<<prefix<<qname<<": can't find SOA record '"<<authdomain<<"' in our zone!"<<endl;
154 res=RCode::NoError;
155 return true;
156 }
5605c067
BH
157
158 string nsdomain(qname);
159
160 while(chopOffDotted(nsdomain) && nsdomain!=iter->first) {
161 range=iter->second.d_records.equal_range(make_tuple(nsdomain,QType(QType::NS)));
162 if(range.first==range.second)
163 continue;
164
165 for(ziter=range.first; ziter!=range.second; ++ziter) {
166 DNSResourceRecord rr=*ziter;
167 rr.d_place=DNSResourceRecord::AUTHORITY;
168 ret.push_back(rr);
169 }
170 }
171 if(ret.empty()) {
172 LOG<<prefix<<qname<<": no NS match in zone '"<<authdomain<<"' either, handing out SOA"<<endl;
173 ziter=iter->second.d_records.find(make_tuple(authdomain, QType(QType::SOA)));
174 if(ziter!=iter->second.d_records.end()) {
175 DNSResourceRecord rr=*ziter;
176 rr.d_place=DNSResourceRecord::AUTHORITY;
177 ret.push_back(rr);
178 }
179 else
180 LOG<<prefix<<qname<<": can't find SOA record '"<<authdomain<<"' in our zone!"<<endl;
181 res=RCode::NXDomain;
182 }
183 else
184 res=0;
185
9e9844e2 186 return true;
e93c956b
BH
187}
188
7b35aa49 189int SyncRes::doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, set<GetBestNSAnswer>& beenthere)
afbe2787 190{
ded77b10
BH
191 string prefix;
192 if(s_log) {
193 prefix=d_prefix;
194 prefix.append(depth, ' ');
195 }
728485ca 196
f4df5e89 197 int res=0;
5605c067 198 if(!(d_nocache && qtype.getCode()==QType::NS && qname==".")) {
115d07ad 199 if(d_cacheonly) { // very limited OOB support
263f6a5a 200 LWResult lwr;
115d07ad
BH
201 LOG<<prefix<<qname<<": Recursion not requested for '"<<qname<<"|"<<qtype.getName()<<"', peeking at auth/forward zones"<<endl;
202 string authname(qname);
203 domainmap_t::const_iterator iter=getBestAuthZone(&authname);
204 if(iter != s_domainmap.end()) {
205 string server=iter->second.d_server;
206 if(server.empty()) {
115d07ad
BH
207 ret.clear();
208 doOOBResolve(qname, qtype, ret, depth, res);
209 return res;
210 }
211 else {
212 LOG<<prefix<<qname<<": forwarding query to hardcoded nameserver '"<<server<<"' for zone '"<<authname<<"'"<<endl;
213 ComboAddress remoteIP(server, 53);
115d07ad 214
2188dcc3 215 res=asyncresolve(remoteIP, qname, qtype.getCode(), false, false, &d_now, &lwr);
263f6a5a
BH
216 // filter out the good stuff from lwr.result()
217
218 for(LWResult::res_t::const_iterator i=lwr.d_result.begin();i!=lwr.d_result.end();++i) {
115d07ad
BH
219 if(i->d_place == DNSResourceRecord::ANSWER)
220 ret.push_back(*i);
221 }
222 return res;
223 }
224 }
225 }
226
c836dc19
BH
227 if(doCNAMECacheCheck(qname,qtype,ret,depth,res)) // will reroute us if needed
228 return res;
229
230 if(doCacheCheck(qname,qtype,ret,depth,res)) // we done
231 return res;
232 }
afbe2787 233
115d07ad 234 if(d_cacheonly)
c836dc19 235 return 0;
115d07ad 236
c836dc19 237 LOG<<prefix<<qname<<": No cache hit for '"<<qname<<"|"<<qtype.getName()<<"', trying to find an appropriate NS record"<<endl;
728485ca
BH
238
239 string subdomain(qname);
240
7738a23f 241 set<string, CIStringCompare> nsset;
7305df82 242 bool flawedNSSet=false;
bdf40704 243 for(int tries=0;tries<2 && nsset.empty();++tries) {
7305df82 244 subdomain=getBestNSNamesFromCache(subdomain, nsset, &flawedNSSet, depth, beenthere); // pass beenthere to both occasions
bdf40704
BH
245
246 if(nsset.empty()) { // must've lost root records
247 LOG<<prefix<<qname<<": our root expired, repriming from hints and retrying"<<endl;
248 primeHints();
249 }
250 }
251
7305df82 252 if(!(res=doResolveAt(nsset, subdomain, flawedNSSet, qname, qtype, ret, depth, beenthere)))
728485ca
BH
253 return 0;
254
5605c067 255 LOG<<prefix<<qname<<": failed (res="<<res<<")"<<endl;
20177d1d 256 return res<0 ? RCode::ServFail : res;
afbe2787
BH
257}
258
996c89cc
BH
259/** This function explicitly goes out for A addresses, but if configured to use IPv6 as well, will also return any IPv6 addresses in the cache
260 Additionally, it will return the 'best' address up front, and the rest shufled
261*/
262vector<ComboAddress> SyncRes::getAs(const string &qname, int depth, set<GetBestNSAnswer>& beenthere)
75b49099 263{
bfea0d0b
BH
264 typedef vector<DNSResourceRecord> res_t;
265 res_t res;
75b49099 266
996c89cc
BH
267 typedef vector<ComboAddress> ret_t;
268 ret_t ret;
75b49099 269
bfea0d0b 270 if(!doResolve(qname,QType(QType::A), res,depth+1,beenthere) && !res.empty()) {
f4df5e89 271 for(res_t::const_iterator i=res.begin(); i!= res.end(); ++i) {
42724edf 272 if(i->qtype.getCode()==QType::A) {
996c89cc 273 ret.push_back(ComboAddress(i->content, 53));
42724edf 274 }
f4df5e89 275 }
bfea0d0b 276 }
996c89cc
BH
277
278 if(s_doIPv6) {
279 typedef set<DNSResourceRecord> ipv6_t;
280 ipv6_t ipv6;
281 if(RC.get(d_now.tv_sec, qname, QType(QType::AAAA), &ipv6) > 0) {
282 for(ipv6_t::const_iterator i=ipv6.begin(); i != ipv6.end(); ++i)
283 ret.push_back(ComboAddress(i->content, 53));
284 }
285 }
286
287 if(ret.size() > 1) {
bfea0d0b 288 random_shuffle(ret.begin(), ret.end());
996c89cc
BH
289
290 // move 'best' address up front
291 nsspeeds_t::iterator best=s_nsSpeeds.find(qname);
292
293 if(best != s_nsSpeeds.end())
294 for(ret_t::iterator i=ret.begin(); i != ret.end(); ++i) {
295 // cerr<<"Is "<<i->toString()<<" equal to "<<best->second.d_best.toString()<<"?\n";
296 if(*i==best->second.d_best) {
297 if(i!=ret.begin()) {
298 // cerr<<"Moving "<<best->second.d_best.toString()<<" up front!\n";
299 *i=*ret.begin();
300 *ret.begin()=best->second.d_best;
301 }
302 break;
303 }
304 }
305 }
306
728485ca 307 return ret;
75b49099
BH
308}
309
7305df82 310void SyncRes::getBestNSFromCache(const string &qname, set<DNSResourceRecord>&bestns, bool* flawedNSSet, int depth, set<GetBestNSAnswer>& beenthere)
86c152f2 311{
ded77b10
BH
312 string prefix, subdomain(qname);
313 if(s_log) {
314 prefix=d_prefix;
315 prefix.append(depth, ' ');
316 }
75b49099
BH
317 bestns.clear();
318
75b49099 319 do {
c836dc19 320 LOG<<prefix<<qname<<": Checking if we have NS in cache for '"<<subdomain<<"'"<<endl;
7738a23f 321 set<DNSResourceRecord> ns;
7305df82 322 *flawedNSSet = false;
7738a23f 323 if(RC.get(d_now.tv_sec, subdomain, QType(QType::NS), &ns) > 0) {
7bf26383 324 for(set<DNSResourceRecord>::const_iterator k=ns.begin();k!=ns.end();++k) {
d6d5dea7 325 if(k->ttl > (unsigned int)d_now.tv_sec ) {
7bf26383 326 set<DNSResourceRecord>aset;
b0d4fb45 327
eab7dbda 328 DNSResourceRecord rr=*k;
7738a23f 329 rr.content=k->content;
e93c956b 330 if(!dottedEndsOn(rr.content, subdomain) || RC.get(d_now.tv_sec, rr.content, QType(QType::A), s_log ? &aset : 0) > 5) {
b0d4fb45 331 bestns.insert(rr);
9fdf67d5 332
b0d4fb45 333 LOG<<prefix<<qname<<": NS (with ip, or non-glue) in cache for '"<<subdomain<<"' -> '"<<rr.content<<"'"<<endl;
7738a23f 334 LOG<<prefix<<qname<<": within bailiwick: "<<dottedEndsOn(rr.content, subdomain);
9fdf67d5
BH
335 if(!aset.empty()) {
336 LOG<<", in cache, ttl="<<(unsigned int)(((time_t)aset.begin()->ttl- d_now.tv_sec ))<<endl;
337 }
338 else {
61973281 339 LOG<<", not in cache / did not look at cache"<<endl;
9fdf67d5 340 }
0d8612f2 341 }
7305df82
BH
342 else {
343 *flawedNSSet=true;
7738a23f 344 LOG<<prefix<<qname<<": NS in cache for '"<<subdomain<<"', but needs glue ("<<k->content<<") which we miss or is expired"<<endl;
7305df82 345 }
ac539791 346 }
afbe2787 347 }
75b49099 348 if(!bestns.empty()) {
7bf26383 349 GetBestNSAnswer answer;
7738a23f 350 answer.qname=qname; answer.bestns=bestns;
7bf26383 351 if(beenthere.count(answer)) {
c836dc19 352 LOG<<prefix<<qname<<": We have NS in cache for '"<<subdomain<<"' but part of LOOP! Trying less specific NS"<<endl;
7305df82
BH
353 if(s_log)
354 for( set<GetBestNSAnswer>::const_iterator j=beenthere.begin();j!=beenthere.end();++j)
355 LOG<<prefix<<qname<<": beenthere: "<<j->qname<<" ("<<(unsigned int)j->bestns.size()<<")"<<endl;
7bf26383
BH
356 bestns.clear();
357 }
358 else {
359 beenthere.insert(answer);
7305df82 360 LOG<<prefix<<qname<<": We have NS in cache for '"<<subdomain<<"' (flawedNSSet="<<*flawedNSSet<<")"<<endl;
7bf26383
BH
361 return;
362 }
75b49099 363 }
afbe2787 364 }
e93c956b 365 LOG<<prefix<<qname<<": no valid/useful NS in cache for '"<<subdomain<<"'"<<endl;
7738a23f 366 }while(chopOffDotted(subdomain));
75b49099
BH
367}
368
5605c067
BH
369SyncRes::domainmap_t::const_iterator SyncRes::getBestAuthZone(string* qname)
370{
371 SyncRes::domainmap_t::const_iterator ret;
372 do {
373 ret=s_domainmap.find(*qname);
374 if(ret!=s_domainmap.end())
375 break;
376 }while(chopOffDotted(*qname));
377 return ret;
378}
288f4aa9 379
7bf26383 380/** doesn't actually do the work, leaves that to getBestNSFromCache */
7305df82 381string SyncRes::getBestNSNamesFromCache(const string &qname, set<string, CIStringCompare>& nsset, bool* flawedNSSet, int depth, set<GetBestNSAnswer>&beenthere)
75b49099
BH
382{
383 string subdomain(qname);
384
5605c067
BH
385 string authdomain(qname);
386
387 domainmap_t::const_iterator iter=getBestAuthZone(&authdomain);
388 if(iter!=s_domainmap.end()) {
67828389 389 nsset.insert(iter->second.d_server); // this gets picked up in doResolveAt, if empty it means "we are auth", otherwise it denotes a forward
5605c067
BH
390 return authdomain;
391 }
392
75b49099 393 set<DNSResourceRecord> bestns;
7305df82 394 getBestNSFromCache(subdomain, bestns, flawedNSSet, depth, beenthere);
75b49099
BH
395
396 for(set<DNSResourceRecord>::const_iterator k=bestns.begin();k!=bestns.end();++k) {
397 nsset.insert(k->content);
e93c956b
BH
398 if(k==bestns.begin())
399 subdomain=k->qname;
86c152f2 400 }
75b49099 401 return subdomain;
afbe2787
BH
402}
403
7b35aa49 404bool SyncRes::doCNAMECacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res)
afbe2787 405{
ded77b10
BH
406 string prefix;
407 if(s_log) {
408 prefix=d_prefix;
409 prefix.append(depth, ' ');
410 }
36f5e3db 411
c6644fc5 412 if(depth>10) {
c836dc19 413 LOG<<prefix<<qname<<": CNAME loop too deep, depth="<<depth<<endl;
c6644fc5
BH
414 res=RCode::ServFail;
415 return true;
416 }
36f5e3db 417
7738a23f 418 LOG<<prefix<<qname<<": Looking for CNAME cache hit of '"<<(qname+"|CNAME")<<"'"<<endl;
7bf26383 419 set<DNSResourceRecord> cset;
d6d5dea7 420 if(RC.get(d_now.tv_sec, qname,QType(QType::CNAME),&cset) > 0) {
36c5ee42 421
7bf26383 422 for(set<DNSResourceRecord>::const_iterator j=cset.begin();j!=cset.end();++j) {
d6d5dea7 423 if(j->ttl>(unsigned int) d_now.tv_sec) {
7738a23f 424 LOG<<prefix<<qname<<": Found cache CNAME hit for '"<< (qname+"|CNAME") <<"' to '"<<j->content<<"'"<<endl;
ac539791 425 DNSResourceRecord rr=*j;
d6d5dea7 426 rr.ttl-=d_now.tv_sec;
ac539791 427 ret.push_back(rr);
b0d4fb45 428 if(!(qtype==QType(QType::CNAME))) { // perhaps they really wanted a CNAME!
7bf26383 429 set<GetBestNSAnswer>beenthere;
7738a23f 430 res=doResolve(j->content, qtype, ret, depth+1, beenthere);
7bf26383 431 }
b0d4fb45
BH
432 else
433 res=0;
75b49099 434 return true;
ac539791
BH
435 }
436 }
afbe2787 437 }
7738a23f 438 LOG<<prefix<<qname<<": No CNAME cache hit of '"<< (qname+"|CNAME") <<"' found"<<endl;
75b49099
BH
439 return false;
440}
441
7b35aa49 442bool SyncRes::doCacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res)
75b49099 443{
fd8bc993 444 bool giveNegative=false;
ded77b10 445
be718669 446 string prefix;
ded77b10
BH
447 if(s_log) {
448 prefix=d_prefix;
449 prefix.append(depth, ' ');
450 }
afbe2787 451
288f4aa9
BH
452 string sqname(qname);
453 QType sqt(qtype);
092f210a 454 uint32_t sttl=0;
f4df5e89
BH
455 // cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"'\n";
456
7738a23f 457 pair<negcache_t::const_iterator, negcache_t::const_iterator> range=s_negcache.equal_range(tie(qname));
f4df5e89
BH
458 negcache_t::iterator ni;
459 for(ni=range.first; ni != range.second; ni++) {
460 // we have something
461 if(ni->d_qtype.getCode() == 0 || ni->d_qtype == qtype) {
462 res=0;
33988bfb
BH
463 if((uint32_t)d_now.tv_sec < ni->d_ttd) {
464 sttl=ni->d_ttd - d_now.tv_sec;
f4df5e89 465 if(ni->d_qtype.getCode()) {
f15a5b2a 466 LOG<<prefix<<qname<<": "<<qtype.getName()<<" is negatively cached via '"<<ni->d_qname<<"' for another "<<sttl<<" seconds"<<endl;
f4df5e89
BH
467 res = RCode::NoError;
468 }
469 else {
f15a5b2a 470 LOG<<prefix<<qname<<": Entire record '"<<qname<<"', is negatively cached via '"<<ni->d_qname<<"' for another "<<sttl<<" seconds"<<endl;
f4df5e89
BH
471 res= RCode::NXDomain;
472 }
38e22b5a 473 giveNegative=true;
33988bfb 474 sqname=ni->d_qname;
f4df5e89
BH
475 sqt=QType::SOA;
476 break;
38e22b5a
BH
477 }
478 else {
7738a23f 479 LOG<<prefix<<qname<<": Entire record '"<<qname<<"' was negatively cached, but entry expired"<<endl;
38e22b5a 480 }
fd8bc993
BH
481 }
482 }
20177d1d 483
7bf26383 484 set<DNSResourceRecord> cset;
75b49099 485 bool found=false, expired=false;
be718669 486
9bc8c14c 487 if(RC.get(d_now.tv_sec, sqname, sqt, &cset) > 0) {
f15a5b2a 488 LOG<<prefix<<sqname<<": Found cache hit for "<<sqt.getName()<<": ";
7bf26383 489 for(set<DNSResourceRecord>::const_iterator j=cset.begin();j!=cset.end();++j) {
c836dc19 490 LOG<<j->content;
d6d5dea7 491 if(j->ttl>(unsigned int) d_now.tv_sec) {
ac539791 492 DNSResourceRecord rr=*j;
d6d5dea7 493 rr.ttl-=d_now.tv_sec;
38e22b5a 494 if(giveNegative) {
20177d1d 495 rr.d_place=DNSResourceRecord::AUTHORITY;
38e22b5a
BH
496 rr.ttl=sttl;
497 }
ac539791 498 ret.push_back(rr);
c836dc19 499 LOG<<"[ttl="<<rr.ttl<<"] ";
75b49099 500 found=true;
ac539791 501 }
75b49099 502 else {
c836dc19 503 LOG<<"[expired] ";
75b49099
BH
504 expired=true;
505 }
afbe2787 506 }
ac539791 507
c836dc19 508 LOG<<endl;
f4df5e89 509 if(found && !expired) {
f15a5b2a
BH
510 if(!giveNegative)
511 res=0;
75b49099 512 return true;
f4df5e89 513 }
75b49099 514 else
c836dc19 515 LOG<<prefix<<qname<<": cache had only stale entries"<<endl;
afbe2787 516 }
f4df5e89 517
75b49099
BH
518 return false;
519}
afbe2787 520
7b35aa49 521bool SyncRes::moreSpecificThan(const string& a, const string &b)
75b49099 522{
7738a23f
BH
523 static string dot(".");
524 int counta=(a!=dot), countb=(b!=dot);
afbe2787 525
728485ca
BH
526 for(string::size_type n=0;n<a.size();++n)
527 if(a[n]=='.')
528 counta++;
529 for(string::size_type n=0;n<b.size();++n)
530 if(b[n]=='.')
531 countb++;
532 return counta>countb;
afbe2787
BH
533}
534
d8d0bb8f 535struct speedOrder
eefd15f9 536{
d8d0bb8f 537 speedOrder(map<string,double> &speeds) : d_speeds(speeds) {}
c3d9d009
BH
538 bool operator()(const string &a, const string &b) const
539 {
540 return d_speeds[a] < d_speeds[b];
c3d9d009
BH
541 }
542 map<string,double>& d_speeds;
543};
544
996c89cc 545inline vector<string> SyncRes::shuffleInSpeedOrder(set<string, CIStringCompare> &nameservers, const string &prefix)
afbe2787 546{
728485ca 547 vector<string> rnameservers;
c3d9d009
BH
548 rnameservers.reserve(nameservers.size());
549 map<string,double> speeds;
eefd15f9 550
7738a23f 551 for(set<string, CIStringCompare>::const_iterator i=nameservers.begin();i!=nameservers.end();++i) {
728485ca 552 rnameservers.push_back(*i);
996c89cc 553 speeds[*i]=s_nsSpeeds[*i].get(&d_now);
eefd15f9 554 }
728485ca 555 random_shuffle(rnameservers.begin(),rnameservers.end());
996c89cc
BH
556 speedOrder so(speeds);
557 stable_sort(rnameservers.begin(),rnameservers.end(), so);
eefd15f9 558
d8d0bb8f
BH
559 if(s_log) {
560 L<<Logger::Warning<<prefix<<"Nameservers: ";
561 for(vector<string>::const_iterator i=rnameservers.begin();i!=rnameservers.end();++i) {
562 if(i!=rnameservers.begin()) {
563 L<<", ";
996c89cc 564 if(!((i-rnameservers.begin())%3))
d8d0bb8f
BH
565 L<<endl<<Logger::Warning<<prefix<<" ";
566 }
49f076e8 567 L<<*i<<"(" << (int)(speeds[*i]/1000.0) <<"ms)";
d8d0bb8f
BH
568 }
569 L<<endl;
570 }
728485ca 571 return rnameservers;
afbe2787
BH
572}
573
7738a23f
BH
574struct TCacheComp
575{
576 bool operator()(const pair<string, QType>& a, const pair<string, QType>& b) const
577 {
705f31ae 578 int cmp=Utility::strcasecmp(a.first.c_str(), b.first.c_str());
7738a23f
BH
579 if(cmp < 0)
580 return true;
581 if(cmp > 0)
582 return false;
583
584 return a.second < b.second;
585 }
586};
587
588
589
ac539791 590/** returns -1 in case of no results, rcode otherwise */
7305df82 591int SyncRes::doResolveAt(set<string, CIStringCompare> nameservers, string auth, bool flawedNSSet, const string &qname, const QType &qtype,
5605c067
BH
592 vector<DNSResourceRecord>&ret,
593 int depth, set<GetBestNSAnswer>&beenthere)
86c152f2 594{
ded77b10
BH
595 string prefix;
596 if(s_log) {
597 prefix=d_prefix;
598 prefix.append(depth, ' ');
599 }
86c152f2 600
263f6a5a 601 LWResult::res_t result;
86c152f2 602
705f31ae 603 LOG<<prefix<<qname<<": Cache consultations done, have "<<(unsigned int)nameservers.size()<<" NS to contact"<<endl;
afbe2787
BH
604
605 for(;;) { // we may get more specific nameservers
86c152f2
BH
606 result.clear();
607
996c89cc 608 vector<string> rnameservers=shuffleInSpeedOrder(nameservers, s_log ? (prefix+qname+": ") : string() );
20177d1d 609
728485ca
BH
610 for(vector<string>::const_iterator tns=rnameservers.begin();;++tns) {
611 if(tns==rnameservers.end()) {
1ef00ba1 612 LOG<<prefix<<qname<<": Failed to resolve via any of the "<<(unsigned int)rnameservers.size()<<" offered NS at level '"<<auth<<"'"<<endl;
7305df82 613 if(auth!="." && flawedNSSet) {
1ef00ba1
BH
614 g_stats.nsSetInvalidations++;
615 LOG<<prefix<<qname<<": Invalidating nameservers for level '"<<auth<<"', next query might succeed"<<endl;
616 RC.doWipeCache(auth, QType::NS);
617 }
ac539791 618 return -1;
afbe2787 619 }
288f4aa9 620 if(qname==*tns && qtype.getCode()==QType::A) {
c836dc19 621 LOG<<prefix<<qname<<": Not using NS to resolve itself!"<<endl;
20177d1d
BH
622 continue;
623 }
5605c067 624
996c89cc 625 typedef vector<ComboAddress> remoteIPs_t;
5605c067 626 remoteIPs_t remoteIPs;
bfea0d0b 627 remoteIPs_t::const_iterator remoteIP;
5c633640 628 bool doTCP=false;
5605c067
BH
629 int resolveret;
630
263f6a5a 631 LWResult lwr;
5605c067
BH
632 if(tns->empty()) {
633 LOG<<prefix<<qname<<": Domain is out-of-band"<<endl;
263f6a5a
BH
634 doOOBResolve(qname, qtype, result, depth, lwr.d_rcode);
635 lwr.d_tcbit=false;
636 lwr.d_aabit=true;
5605c067
BH
637 }
638 else {
705f31ae 639 LOG<<prefix<<qname<<": Trying to resolve NS '"<<*tns<<"' ("<<1+tns-rnameservers.begin()<<"/"<<(unsigned int)rnameservers.size()<<")"<<endl;
5605c067
BH
640 if(!isCanonical(*tns)) {
641 LOG<<prefix<<qname<<": Domain has hardcoded nameserver"<<endl;
996c89cc 642 remoteIPs.push_back(ComboAddress(*tns, 53));
5605c067
BH
643 }
644 else
645 remoteIPs=getAs(*tns, depth+1, beenthere);
646
647 if(remoteIPs.empty()) {
648 LOG<<prefix<<qname<<": Failed to get IP for NS "<<*tns<<", trying next if available"<<endl;
7305df82 649 flawedNSSet=true;
bfea0d0b 650 continue;
5c633640 651 }
996c89cc
BH
652 else {
653 LOG<<prefix<<qname<<": Resolved '"+auth+"' NS "<<*tns<<" to: ";
654 for(remoteIP = remoteIPs.begin(); remoteIP != remoteIPs.end(); ++remoteIP) {
655 if(remoteIP != remoteIPs.begin())
656 LOG<<", ";
657 LOG<<remoteIP->toString();
658 }
659 LOG<<endl;
5605c067 660
996c89cc 661 }
263f6a5a 662
5605c067 663 for(remoteIP = remoteIPs.begin(); remoteIP != remoteIPs.end(); ++remoteIP) {
996c89cc 664 LOG<<prefix<<qname<<": Trying IP "<< remoteIP->toString() <<", asking '"<<qname<<"|"<<qtype.getName()<<"'"<<endl;
eb5bae86 665 extern NetmaskGroup* g_dontQuery;
7becf07f 666
5605c067
BH
667 if(s_throttle.shouldThrottle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()))) {
668 LOG<<prefix<<qname<<": query throttled "<<endl;
669 s_throttledqueries++; d_throttledqueries++;
670 continue;
eb5bae86
BH
671 }
672 else if(g_dontQuery && g_dontQuery->match(&*remoteIP)) {
673 LOG<<prefix<<qname<<": not sending query to " << remoteIP->toString() << ", blocked by 'dont-query' setting" << endl;
674 continue;
5605c067
BH
675 }
676 else {
677 s_outqueries++; d_outqueries++;
678 TryTCP:
679 if(doTCP) {
680 s_tcpoutqueries++; d_tcpoutqueries++;
998a4334 681 }
bfea0d0b 682
2188dcc3 683 resolveret=asyncresolve(*remoteIP, qname, qtype.getCode(), doTCP, d_doEDNS0, &d_now, &lwr); // <- we go out on the wire!
5605c067
BH
684 if(resolveret != 1) {
685 if(resolveret==0) {
686 LOG<<prefix<<qname<<": timeout resolving "<< (doTCP ? "over TCP" : "")<<endl;
687 d_timeouts++;
688 s_outgoingtimeouts++;
689 }
690 else if(resolveret==-2) {
23bfe484 691 LOG<<prefix<<qname<<": hit a local resource limit resolving "<< (doTCP ? "over TCP" : "")<<", probable error: "<<stringerror()<<endl;
5605c067
BH
692 g_stats.resourceLimits++;
693 }
c571588b
BH
694 else {
695 s_unreachables++; d_unreachables++;
263f6a5a 696 LOG<<prefix<<qname<<": error resolving"<< (doTCP ? " over TCP" : "") <<", possible error: "<<strerror(errno)<< endl;
c571588b 697 }
5605c067
BH
698
699 if(resolveret!=-2) { // don't account for resource limits, they are our own fault
996c89cc 700 s_nsSpeeds[*tns].submit(*remoteIP, 1000000, &d_now); // 1 sec
c571588b
BH
701 if(resolveret==-1)
702 s_throttle.throttle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100); // unreachable
703 else
704 s_throttle.throttle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()), 20, 5); // timeout
5605c067
BH
705 }
706 continue;
998a4334 707 }
5605c067
BH
708
709 break; // this IP address worked!
710 wasLame:; // well, it didn't
996c89cc 711 LOG<<prefix<<qname<<": status=NS "<<*tns<<" ("<< remoteIP->toString() <<") is lame for '"<<auth<<"', trying sibling IP or NS"<<endl;
c571588b 712 s_throttle.throttle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100);
bfea0d0b 713 }
3de83124 714 }
5605c067
BH
715
716 if(remoteIP == remoteIPs.end()) // we tried all IP addresses, none worked
717 continue;
718
263f6a5a 719 if(lwr.d_tcbit) {
5605c067
BH
720 if(!doTCP) {
721 doTCP=true;
722 LOG<<prefix<<qname<<": truncated bit set, retrying via TCP"<<endl;
723 goto TryTCP;
724 }
725 LOG<<prefix<<qname<<": truncated bit set, over TCP?"<<endl;
726 return RCode::ServFail;
d0166f4a 727 }
5605c067 728
263f6a5a 729 if(lwr.d_rcode==RCode::ServFail) {
5605c067
BH
730 LOG<<prefix<<qname<<": "<<*tns<<" returned a ServFail, trying sibling IP or NS"<<endl;
731 s_throttle.throttle(d_now.tv_sec,make_tuple(*remoteIP, qname, qtype.getCode()),60,3);
732 continue;
733 }
263f6a5a 734 LOG<<prefix<<qname<<": Got "<<(unsigned int)lwr.d_result.size()<<" answers from "<<*tns<<" ("<< remoteIP->toString() <<"), rcode="<<lwr.d_rcode<<", in "<<lwr.d_usec/1000<<"ms"<<endl;
996c89cc
BH
735
736 /* // for you IPv6 fanatics :-)
737 if(remoteIP->sin4.sin_family==AF_INET6)
263f6a5a 738 lwr.d_usec/=3;
996c89cc
BH
739 */
740
263f6a5a 741 s_nsSpeeds[*tns].submit(*remoteIP, lwr.d_usec, &d_now);
20177d1d 742 }
20177d1d 743
7738a23f 744 typedef map<pair<string, QType>, set<DNSResourceRecord>, TCacheComp > tcache_t;
1ac4e536
BH
745 tcache_t tcache;
746
728485ca 747 // reap all answers from this packet that are acceptable
263f6a5a 748 for(LWResult::res_t::const_iterator i=lwr.d_result.begin();i != lwr.d_result.end();++i) {
2188dcc3
BH
749 if(i->qtype.getCode() == QType::OPT) {
750 LOG<<prefix<<qname<<": skipping OPT answer '"<<i->qname<<"' from '"<<auth<<"' nameservers" <<endl;
751 continue;
752 }
5456e605 753 LOG<<prefix<<qname<<": accept answer '"<<i->qname<<"|"<<i->qtype.getName()<<"|"<<i->content<<"' from '"<<auth<<"' nameservers? ";
9bc8c14c
BH
754 if(i->qtype.getCode()==QType::ANY) {
755 LOG<<"NO! - we don't accept 'ANY' data"<<endl;
756 continue;
757 }
758
7738a23f 759 if(dottedEndsOn(i->qname, auth)) {
263f6a5a 760 if(lwr.d_aabit && lwr.d_rcode==RCode::NoError && i->d_place==DNSResourceRecord::ANSWER && ::arg().contains("delegation-only",auth)) {
562588a3 761 LOG<<"NO! Is from delegation-only zone"<<endl;
525b8a7c 762 s_nodelegated++;
562588a3
BH
763 return RCode::NXDomain;
764 }
765 else {
766 LOG<<"YES!"<<endl;
767
768 DNSResourceRecord rr=*i;
769 rr.d_place=DNSResourceRecord::ANSWER;
61973281 770
ab5c053d 771 rr.ttl=min(86400*14U, rr.ttl); // limit TTL to two weeks
40170d23 772 rr.ttl += d_now.tv_sec;
61973281 773
5456e605 774 if(rr.qtype.getCode() == QType::NS) // people fiddle with the case
61973281 775 rr.content=toLower(rr.content); // this must stay! (the cache can't be case-insensitive on the RHS of records)
7738a23f 776 tcache[make_pair(i->qname,i->qtype)].insert(rr);
562588a3
BH
777 }
778 }
728485ca 779 else
c836dc19 780 LOG<<"NO!"<<endl;
86c152f2 781 }
728485ca
BH
782
783 // supplant
60b859b9 784 for(tcache_t::iterator i=tcache.begin();i!=tcache.end();++i) {
ab5c053d 785 if(i->second.size() > 1) { // need to group the ttl to be the minimum of the RRSET (RFC 2181, 5.2)
40170d23
BH
786 uint32_t lowestTTL=numeric_limits<uint32_t>::max();
787 for(tcache_t::value_type::second_type::iterator j=i->second.begin(); j != i->second.end(); ++j)
788 lowestTTL=min(lowestTTL, j->ttl);
789
790 for(tcache_t::value_type::second_type::iterator j=i->second.begin(); j != i->second.end(); ++j)
791 ((tcache_t::value_type::second_type::value_type*)&(*j))->ttl=lowestTTL;
792 }
793
263f6a5a 794 RC.replace(d_now.tv_sec, i->first.first, i->first.second, i->second, lwr.d_aabit);
288f4aa9 795 }
7738a23f 796 set<string, CIStringCompare> nsset;
c836dc19 797 LOG<<prefix<<qname<<": determining status after receiving this packet"<<endl;
728485ca 798
20177d1d 799 bool done=false, realreferral=false, negindic=false;
c6644fc5 800 string newauth, soaname, newtarget;
728485ca 801
263f6a5a 802 for(LWResult::res_t::const_iterator i=lwr.d_result.begin();i!=lwr.d_result.end();++i) {
7738a23f 803 if(i->d_place==DNSResourceRecord::AUTHORITY && dottedEndsOn(qname,i->qname) && i->qtype.getCode()==QType::SOA &&
263f6a5a 804 lwr.d_rcode==RCode::NXDomain) {
7738a23f 805 LOG<<prefix<<qname<<": got negative caching indication for RECORD '"<<qname+"'"<<endl;
728485ca 806 ret.push_back(*i);
fd8bc993 807
38e22b5a 808 NegCacheEntry ne;
33988bfb
BH
809
810 ne.d_qname=i->qname;
a9af3782 811 ne.d_ttd=d_now.tv_sec + min(i->ttl, s_maxnegttl); // controversial
7738a23f 812 ne.d_name=qname;
ab5c053d 813 ne.d_qtype=QType(0); // this encodes 'whole record'
f40c8545 814
739f6278 815 replacing_insert(s_negcache, ne);
20177d1d 816 negindic=true;
728485ca
BH
817 }
818 else if(i->d_place==DNSResourceRecord::ANSWER && i->qname==qname && i->qtype.getCode()==QType::CNAME && (!(qtype==QType(QType::CNAME)))) {
728485ca 819 ret.push_back(*i);
7738a23f 820 newtarget=i->content;
728485ca
BH
821 }
822 // for ANY answers we *must* have an authoritive answer
705f31ae 823 else if(i->d_place==DNSResourceRecord::ANSWER && !Utility::strcasecmp(i->qname.c_str(),qname.c_str()) &&
5456e605 824 ( (i->qtype==qtype) ||
263f6a5a 825 ( qtype==QType(QType::ANY) && lwr.d_aabit))) {
5456e605
BH
826
827 LOG<<prefix<<qname<<": answer is in: resolved to '"<< i->content<<"|"<<i->qtype.getName()<<"'"<<endl;
828
728485ca
BH
829 done=true;
830 ret.push_back(*i);
831 }
7738a23f 832 else if(i->d_place==DNSResourceRecord::AUTHORITY && dottedEndsOn(qname,i->qname) && i->qtype.getCode()==QType::NS) {
728485ca
BH
833 if(moreSpecificThan(i->qname,auth)) {
834 newauth=i->qname;
c836dc19 835 LOG<<prefix<<qname<<": got NS record '"<<i->qname<<"' -> '"<<i->content<<"'"<<endl;
728485ca
BH
836 realreferral=true;
837 }
7bf26383 838 else
c836dc19 839 LOG<<prefix<<qname<<": got upwards/level NS record '"<<i->qname<<"' -> '"<<i->content<<"', had '"<<auth<<"'"<<endl;
7738a23f 840 nsset.insert(i->content);
728485ca 841 }
d3178e4b 842 else if(!done && i->d_place==DNSResourceRecord::AUTHORITY && dottedEndsOn(qname,i->qname) && i->qtype.getCode()==QType::SOA &&
263f6a5a 843 lwr.d_rcode==RCode::NoError) {
7738a23f 844 LOG<<prefix<<qname<<": got negative caching indication for '"<< (qname+"|"+i->qtype.getName()+"'") <<endl;
fd8bc993 845 ret.push_back(*i);
38e22b5a
BH
846
847 NegCacheEntry ne;
33988bfb 848 ne.d_qname=i->qname;
f40c8545 849 ne.d_ttd=d_now.tv_sec + min(s_maxnegttl, i->ttl);
7738a23f 850 ne.d_name=qname;
f4df5e89 851 ne.d_qtype=qtype;
f40c8545 852 if(qtype.getCode()) { // prevents us from blacking out a whole domain
739f6278 853 replacing_insert(s_negcache, ne);
f40c8545 854 }
fd8bc993
BH
855 negindic=true;
856 }
86c152f2 857 }
86c152f2 858
728485ca 859 if(done){
c836dc19 860 LOG<<prefix<<qname<<": status=got results, this level of recursion done"<<endl;
728485ca 861 return 0;
ac539791 862 }
263f6a5a 863 if(lwr.d_rcode==RCode::NXDomain) {
c836dc19 864 LOG<<prefix<<qname<<": status=NXDOMAIN, we are done "<<(negindic ? "(have negative SOA)" : "")<<endl;
728485ca 865 return RCode::NXDomain;
86c152f2 866 }
c6644fc5 867 if(!newtarget.empty()) {
c9f52071
BH
868 if(iequals(newtarget,qname)) {
869 LOG<<prefix<<qname<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl;
870 return RCode::ServFail;
871 }
872 if(depth > 10) {
873 LOG<<prefix<<qname<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl;
874 return RCode::ServFail;
875 }
c836dc19 876 LOG<<prefix<<qname<<": status=got a CNAME referral, starting over with "<<newtarget<<endl;
c9f52071 877
c6644fc5 878 set<GetBestNSAnswer>beenthere2;
c9f52071 879 return doResolve(newtarget, qtype, ret, depth + 1, beenthere2);
c6644fc5 880 }
263f6a5a 881 if(nsset.empty() && !lwr.d_rcode) {
caa6eefa
BH
882 LOG<<prefix<<qname<<": status=noerror, other types may exist, but we are done "<<(negindic ? "(have negative SOA)" : "")<<endl;
883 return 0;
884 }
728485ca 885 else if(realreferral) {
705f31ae 886 LOG<<prefix<<qname<<": status=did not resolve, got "<<(unsigned int)nsset.size()<<" NS, looping to them"<<endl;
728485ca
BH
887 auth=newauth;
888 nameservers=nsset;
889 break;
890 }
5605c067 891 else if(isCanonical(*tns)) {
263f6a5a 892 goto wasLame;
86c152f2
BH
893 }
894 }
86c152f2 895 }
ac539791 896 return -1;
86c152f2
BH
897}
898
9bc8c14c
BH
899static bool uniqueComp(const DNSResourceRecord& a, const DNSResourceRecord& b)
900{
901 return(a.qtype==b.qtype && a.qname==b.qname && a.content==b.content);
902}
903
7b35aa49 904void SyncRes::addCruft(const string &qname, vector<DNSResourceRecord>& ret)
728485ca
BH
905{
906 for(vector<DNSResourceRecord>::const_iterator k=ret.begin();k!=ret.end();++k) // don't add stuff to an NXDOMAIN!
907 if(k->d_place==DNSResourceRecord::AUTHORITY && k->qtype==QType(QType::SOA))
908 return;
909
c836dc19 910 // LOG<<qname<<": Adding best authority records from cache"<<endl;
288f4aa9 911 // addAuthorityRecords(qname,ret,0);
c836dc19 912 // LOG<<qname<<": Done adding best authority records."<<endl;
728485ca 913
c836dc19 914 LOG<<d_prefix<<qname<<": Starting additional processing"<<endl;
728485ca 915 vector<DNSResourceRecord> addit;
1ac4e536
BH
916 static optional<bool> l_doIPv6AP;
917 if(!l_doIPv6AP)
918 l_doIPv6AP=::arg().mustDo("aaaa-additional-processing");
919
728485ca 920 for(vector<DNSResourceRecord>::const_iterator k=ret.begin();k!=ret.end();++k)
e4d89ee9 921 if( (k->d_place==DNSResourceRecord::ANSWER && (k->qtype==QType(QType::MX) || k->qtype==QType(QType::SRV))) ||
288f4aa9 922 ((k->d_place==DNSResourceRecord::AUTHORITY || k->d_place==DNSResourceRecord::ANSWER) && k->qtype==QType(QType::NS))) {
d8d0bb8f 923 LOG<<d_prefix<<qname<<": record '"<<k->content<<"|"<<k->qtype.getName()<<"' needs IP for additional processing"<<endl;
e4d89ee9
BH
924 set<GetBestNSAnswer> beenthere;
925 vector<pair<string::size_type, string::size_type> > fields;
926 vstringtok(fields, k->content, " ");
927 string host;
928 if(k->qtype==QType(QType::MX) && fields.size()==2)
929 host=string(k->content.c_str() + fields[1].first, fields[1].second - fields[1].first);
930 else if(k->qtype==QType(QType::NS))
931 host=k->content;
932 else if(k->qtype==QType(QType::SRV) && fields.size()==4)
933 host=string(k->content.c_str() + fields[3].first, fields[3].second - fields[3].first);
934 else
935 continue;
936 doResolve(host, QType(QType::A), addit, 1, beenthere);
937 if(*l_doIPv6AP)
938 doResolve(host, QType(QType::AAAA), addit, 1, beenthere);
728485ca
BH
939 }
940
9bc8c14c
BH
941 sort(addit.begin(), addit.end());
942 addit.erase(unique(addit.begin(), addit.end(), uniqueComp), addit.end());
728485ca 943 for(vector<DNSResourceRecord>::iterator k=addit.begin();k!=addit.end();++k) {
288f4aa9
BH
944 if(k->qtype.getCode()==QType::A || k->qtype.getCode()==QType::AAAA) {
945 k->d_place=DNSResourceRecord::ADDITIONAL;
946 ret.push_back(*k);
947 }
728485ca 948 }
c836dc19 949 LOG<<d_prefix<<qname<<": Done with additional processing"<<endl;
728485ca
BH
950}
951
7b35aa49 952void SyncRes::addAuthorityRecords(const string& qname, vector<DNSResourceRecord>& ret, int depth)
86c152f2 953{
288f4aa9 954 set<DNSResourceRecord> bestns;
7305df82
BH
955 set<GetBestNSAnswer> beenthere;
956 bool dontcare;
957 getBestNSFromCache(qname, bestns, &dontcare, depth, beenthere);
36c5ee42 958
288f4aa9
BH
959 for(set<DNSResourceRecord>::const_iterator k=bestns.begin();k!=bestns.end();++k) {
960 DNSResourceRecord ns=*k;
961 ns.d_place=DNSResourceRecord::AUTHORITY;
d6d5dea7 962 ns.ttl-=d_now.tv_sec;
288f4aa9 963 ret.push_back(ns);
86c152f2
BH
964 }
965}