39
40
SyncRes::negcache_t SyncRes::s_negcache;
40
41
SyncRes::nsspeeds_t SyncRes::s_nsSpeeds;
42
unsigned int SyncRes::s_maxnegttl;
42
43
unsigned int SyncRes::s_queries;
43
44
unsigned int SyncRes::s_outgoingtimeouts;
44
45
unsigned int SyncRes::s_outqueries;
45
46
unsigned int SyncRes::s_tcpoutqueries;
46
47
unsigned int SyncRes::s_throttledqueries;
47
48
unsigned int SyncRes::s_nodelegated;
49
unsigned int SyncRes::s_unreachables;
50
bool SyncRes::s_doIPv6;
52
SyncRes::domainmap_t SyncRes::s_domainmap;
53
string SyncRes::s_serverID;
48
54
bool SyncRes::s_log;
50
56
#define LOG if(s_log) L<<Logger::Warning
52
Throttle<string> SyncRes::s_throttle;
58
SyncRes::throttle_t SyncRes::s_throttle;
54
60
/** everything begins here - this is the entry point just after receiving a packet */
55
int SyncRes::beginResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret)
61
int SyncRes::beginResolve(const string &qname, const QType &qtype, uint16_t qclass, vector<DNSResourceRecord>&ret)
57
set<GetBestNSAnswer> beenthere;
59
int res=doResolve(qname, qtype, ret,0,beenthere);
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."))) {
72
if(qtype.getCode()==QType::PTR)
73
rr.content="localhost.";
75
rr.content="127.0.0.1";
80
if(qclass==3 && qtype.getCode()==QType::TXT &&
81
(!Utility::strcasecmp(qname.c_str(), "version.bind.") || !Utility::strcasecmp(qname.c_str(), "id.server.") || !Utility::strcasecmp(qname.c_str(), "version.pdns.") )
89
if(!Utility::strcasecmp(qname.c_str(),"version.bind.") || !Utility::strcasecmp(qname.c_str(),"version.pdns."))
90
rr.content="\""+::arg()["version-string"]+"\"";
92
rr.content="\""+s_serverID+"\"";
102
set<GetBestNSAnswer> beenthere;
103
int res=doResolve(qname, qtype, ret, 0, beenthere);
61
105
addCruft(qname, ret);
109
//! This is the 'out of band resolver', in other words, the authoritative server
110
bool SyncRes::doOOBResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int& res)
115
prefix.append(depth, ' ');
118
LOG<<prefix<<qname<<": checking auth storage for '"<<qname<<"|"<<qtype.getName()<<"'"<<endl;
119
string authdomain(qname);
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;
126
LOG<<prefix<<qname<<": auth storage has data, zone='"<<authdomain<<"'"<<endl;
127
pair<AuthDomain::records_t::const_iterator, AuthDomain::records_t::const_iterator> range;
129
range=iter->second.d_records.equal_range(tie(qname)); // partial lookup
132
AuthDomain::records_t::const_iterator ziter;
134
for(ziter=range.first; ziter!=range.second; ++ziter) {
136
if(qtype.getCode()==QType::ANY || ziter->qtype==qtype || ziter->qtype.getCode()==QType::CNAME) // let rest of nameserver do the legwork on this one
137
ret.push_back(*ziter);
140
LOG<<prefix<<qname<<": exact match in zone '"<<authdomain<<"'"<<endl;
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;
153
LOG<<prefix<<qname<<": can't find SOA record '"<<authdomain<<"' in our zone!"<<endl;
158
string nsdomain(qname);
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)
165
for(ziter=range.first; ziter!=range.second; ++ziter) {
166
DNSResourceRecord rr=*ziter;
167
rr.d_place=DNSResourceRecord::AUTHORITY;
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;
180
LOG<<prefix<<qname<<": can't find SOA record '"<<authdomain<<"' in our zone!"<<endl;
65
189
int SyncRes::doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, set<GetBestNSAnswer>& beenthere)
67
string prefix(d_prefix);
68
prefix.append(depth, ' ');
194
prefix.append(depth, ' ');
71
if(!(d_nocache && qtype.getCode()==QType::NS && qname.empty())) {
198
if(!(d_nocache && qtype.getCode()==QType::NS && qname==".")) {
199
if(d_cacheonly) { // very limited OOB support
200
LOG<<prefix<<qname<<": Recursion not requested for '"<<qname<<"|"<<qtype.getName()<<"', peeking at auth/forward zones"<<endl;
201
string authname(qname);
202
domainmap_t::const_iterator iter=getBestAuthZone(&authname);
203
if(iter != s_domainmap.end()) {
204
string server=iter->second.d_server;
208
doOOBResolve(qname, qtype, ret, depth, res);
212
LOG<<prefix<<qname<<": forwarding query to hardcoded nameserver '"<<server<<"' for zone '"<<authname<<"'"<<endl;
213
ComboAddress remoteIP(server, 53);
214
res=d_lwr.asyncresolve(remoteIP, qname, qtype.getCode(), false, &d_now);
215
// filter out the good stuff from d_lwr.result()
216
LWRes::res_t result=d_lwr.result();
218
for(LWRes::res_t::const_iterator i=result.begin();i!=result.end();++i) {
219
if(i->d_place == DNSResourceRecord::ANSWER)
72
227
if(doCNAMECacheCheck(qname,qtype,ret,depth,res)) // will reroute us if needed
96
if(!(res=doResolveAt(nsset,subdomain,qname,qtype,ret,depth, beenthere)))
252
if(!(res=doResolveAt(nsset, subdomain, flawedNSSet, qname, qtype, ret, depth, beenthere)))
99
LOG<<prefix<<qname<<": failed"<<endl;
255
LOG<<prefix<<qname<<": failed (res="<<res<<")"<<endl;
100
256
return res<0 ? RCode::ServFail : res;
103
vector<string> SyncRes::getAs(const string &qname, int depth, set<GetBestNSAnswer>& beenthere)
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
262
vector<ComboAddress> SyncRes::getAs(const string &qname, int depth, set<GetBestNSAnswer>& beenthere)
105
264
typedef vector<DNSResourceRecord> res_t;
267
typedef vector<ComboAddress> ret_t;
110
270
if(!doResolve(qname,QType(QType::A), res,depth+1,beenthere) && !res.empty()) {
111
for(res_t::const_iterator i=res.begin(); i!= res.end(); ++i)
112
if(i->qtype.getCode()==QType::A)
113
ret.push_back(i->content);
271
for(res_t::const_iterator i=res.begin(); i!= res.end(); ++i) {
272
if(i->qtype.getCode()==QType::A) {
273
ret.push_back(ComboAddress(i->content, 53));
279
typedef set<DNSResourceRecord> ipv6_t;
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));
116
288
random_shuffle(ret.begin(), ret.end());
290
// move 'best' address up front
291
nsspeeds_t::iterator best=s_nsSpeeds.find(qname);
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) {
298
// cerr<<"Moving "<<best->second.d_best.toString()<<" up front!\n";
300
*ret.begin()=best->second.d_best;
120
void SyncRes::getBestNSFromCache(const string &qname, set<DNSResourceRecord>&bestns, int depth, set<GetBestNSAnswer>& beenthere)
310
void SyncRes::getBestNSFromCache(const string &qname, set<DNSResourceRecord>&bestns, bool* flawedNSSet, int depth, set<GetBestNSAnswer>& beenthere)
122
string prefix(d_prefix), subdomain(qname);
123
prefix.append(depth, ' ');
312
string prefix, subdomain(qname);
315
prefix.append(depth, ' ');
127
320
LOG<<prefix<<qname<<": Checking if we have NS in cache for '"<<subdomain<<"'"<<endl;
128
set<DNSResourceRecord>ns;
129
if(RC.get(d_now.tv_sec, subdomain, QType(QType::NS), &ns)>0) {
321
set<DNSResourceRecord> ns;
322
*flawedNSSet = false;
323
if(RC.get(d_now.tv_sec, subdomain, QType(QType::NS), &ns) > 0) {
131
324
for(set<DNSResourceRecord>::const_iterator k=ns.begin();k!=ns.end();++k) {
132
325
if(k->ttl > (unsigned int)d_now.tv_sec ) {
133
326
set<DNSResourceRecord>aset;
135
328
DNSResourceRecord rr=*k;
136
rr.content=toLowerCanonic(k->content);
137
if(!endsOn(rr.content,subdomain) || RC.get(d_now.tv_sec, rr.content ,QType(QType::A),&aset) > 5) {
329
rr.content=k->content;
330
if(!dottedEndsOn(rr.content, subdomain) || RC.get(d_now.tv_sec, rr.content, QType(QType::A), s_log ? &aset : 0) > 5) {
138
331
bestns.insert(rr);
140
333
LOG<<prefix<<qname<<": NS (with ip, or non-glue) in cache for '"<<subdomain<<"' -> '"<<rr.content<<"'"<<endl;
141
LOG<<prefix<<qname<<": within bailiwick: "<<endsOn(rr.content,subdomain);
334
LOG<<prefix<<qname<<": within bailiwick: "<<dottedEndsOn(rr.content, subdomain);
142
335
if(!aset.empty()) {
143
336
LOG<<", in cache, ttl="<<(unsigned int)(((time_t)aset.begin()->ttl- d_now.tv_sec ))<<endl;
146
LOG<<", not in cache"<<endl;
339
LOG<<", not in cache / did not look at cache"<<endl;
150
LOG<<prefix<<qname<<": NS in cache for '"<<subdomain<<"', but needs glue ("<<toLowerCanonic(k->content)<<") which we miss or is expired"<<endl;
344
LOG<<prefix<<qname<<": NS in cache for '"<<subdomain<<"', but needs glue ("<<k->content<<") which we miss or is expired"<<endl;
153
348
if(!bestns.empty()) {
154
349
GetBestNSAnswer answer;
155
answer.qname=toLower(qname); answer.bestns=bestns;
350
answer.qname=qname; answer.bestns=bestns;
156
351
if(beenthere.count(answer)) {
157
352
LOG<<prefix<<qname<<": We have NS in cache for '"<<subdomain<<"' but part of LOOP! Trying less specific NS"<<endl;
158
for( set<GetBestNSAnswer>::const_iterator j=beenthere.begin();j!=beenthere.end();++j)
159
LOG<<prefix<<qname<<": beenthere: "<<j->qname<<" ("<<j->bestns.size()<<")"<<endl;
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;
163
359
beenthere.insert(answer);
164
LOG<<prefix<<qname<<": We have NS in cache for '"<<subdomain<<"'"<<endl;
360
LOG<<prefix<<qname<<": We have NS in cache for '"<<subdomain<<"' (flawedNSSet="<<*flawedNSSet<<")"<<endl;
169
}while(chopOff(subdomain));
365
LOG<<prefix<<qname<<": no valid/useful NS in cache for '"<<subdomain<<"'"<<endl;
366
}while(chopOffDotted(subdomain));
369
SyncRes::domainmap_t::const_iterator SyncRes::getBestAuthZone(string* qname)
371
SyncRes::domainmap_t::const_iterator ret;
373
ret=s_domainmap.find(*qname);
374
if(ret!=s_domainmap.end())
376
}while(chopOffDotted(*qname));
173
380
/** doesn't actually do the work, leaves that to getBestNSFromCache */
174
string SyncRes::getBestNSNamesFromCache(const string &qname,set<string>& nsset, int depth, set<GetBestNSAnswer>&beenthere)
381
string SyncRes::getBestNSNamesFromCache(const string &qname, set<string, CIStringCompare>& nsset, bool* flawedNSSet, int depth, set<GetBestNSAnswer>&beenthere)
176
383
string subdomain(qname);
385
string authdomain(qname);
387
domainmap_t::const_iterator iter=getBestAuthZone(&authdomain);
388
if(iter!=s_domainmap.end()) {
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
178
393
set<DNSResourceRecord> bestns;
179
getBestNSFromCache(subdomain, bestns, depth, beenthere);
394
getBestNSFromCache(subdomain, bestns, flawedNSSet, depth, beenthere);
181
396
for(set<DNSResourceRecord>::const_iterator k=bestns.begin();k!=bestns.end();++k) {
182
397
nsset.insert(k->content);
398
if(k==bestns.begin())
185
401
return subdomain;
188
404
bool SyncRes::doCNAMECacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res)
190
string prefix(d_prefix), tuple=toLowerCanonic(qname)+"|CNAME";
191
prefix.append(depth, ' ');
409
prefix.append(depth, ' ');
194
413
LOG<<prefix<<qname<<": CNAME loop too deep, depth="<<depth<<endl;
219
LOG<<prefix<<qname<<": No CNAME cache hit of '"<<tuple<<"' found"<<endl;
438
LOG<<prefix<<qname<<": No CNAME cache hit of '"<< (qname+"|CNAME") <<"' found"<<endl;
223
442
bool SyncRes::doCacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res)
225
444
bool giveNegative=false;
226
string prefix(d_prefix), tuple;
227
prefix.append(depth, ' ');
449
prefix.append(depth, ' ');
229
452
string sqname(qname);
230
453
QType sqt(qtype);
233
if(s_negcache.count(toLower(qname))) {
235
negcache_t::const_iterator ni=s_negcache.find(toLower(qname));
236
if(d_now.tv_sec < ni->second.ttd) {
237
sttl=ni->second.ttd - d_now.tv_sec;
238
LOG<<prefix<<qname<<": Entire record '"<<toLower(qname)<<"', is negatively cached for another "<<sttl<<" seconds"<<endl;
241
sqname=ni->second.name;
245
LOG<<prefix<<qname<<": Entire record '"<<toLower(qname)<<"' was negatively cached, but entry expired"<<endl;
246
s_negcache.erase(toLower(qname));
250
if(!giveNegative) { // let's try some more
251
tuple=toLower(qname); tuple.append(1,'|'); tuple+=qtype.getName();
252
LOG<<prefix<<qname<<": Looking for direct cache hit of '"<<tuple<<"', negative cached: "<<s_negcache.count(tuple)<<endl;
255
negcache_t::const_iterator ni=s_negcache.find(tuple);
256
if(ni!=s_negcache.end()) {
257
if(d_now.tv_sec < ni->second.ttd) {
258
sttl=ni->second.ttd - d_now.tv_sec;
259
LOG<<prefix<<qname<<": "<<qtype.getName()<<" is negatively cached for another "<<sttl<<" seconds"<<endl;
260
res=RCode::NoError; // only this record doesn't exist
455
// cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"'\n";
457
pair<negcache_t::const_iterator, negcache_t::const_iterator> range=s_negcache.equal_range(tie(qname));
458
negcache_t::iterator ni;
459
for(ni=range.first; ni != range.second; ni++) {
461
if(ni->d_qtype.getCode() == 0 || ni->d_qtype == qtype) {
463
if((uint32_t)d_now.tv_sec < ni->d_ttd) {
464
sttl=ni->d_ttd - d_now.tv_sec;
465
if(ni->d_qtype.getCode()) {
466
LOG<<prefix<<qname<<": "<<qtype.getName()<<" is negatively cached via '"<<ni->d_qname<<"' for another "<<sttl<<" seconds"<<endl;
467
res = RCode::NoError;
470
LOG<<prefix<<qname<<": Entire record '"<<qname<<"', is negatively cached via '"<<ni->d_qname<<"' for another "<<sttl<<" seconds"<<endl;
471
res= RCode::NXDomain;
261
473
giveNegative=true;
262
sqname=ni->second.name;
266
LOG<<prefix<<qname<<": "<<qtype.getName()<<" was negatively cached, but entry expired"<<endl;
267
s_negcache.erase(toLower(tuple));
479
LOG<<prefix<<qname<<": Entire record '"<<qname<<"' was negatively cached, but entry expired"<<endl;
272
484
set<DNSResourceRecord> cset;
273
485
bool found=false, expired=false;
274
if(RC.get(d_now.tv_sec, sqname,sqt,&cset)>0) {
275
LOG<<prefix<<qname<<": Found cache hit for "<<sqt.getName()<<": ";
487
if(RC.get(d_now.tv_sec, sqname, sqt, &cset) > 0) {
488
LOG<<prefix<<sqname<<": Found cache hit for "<<sqt.getName()<<": ";
276
489
for(set<DNSResourceRecord>::const_iterator j=cset.begin();j!=cset.end();++j) {
278
491
if(j->ttl>(unsigned int) d_now.tv_sec) {
355
571
return rnameservers;
576
bool operator()(const pair<string, QType>& a, const pair<string, QType>& b) const
578
int cmp=Utility::strcasecmp(a.first.c_str(), b.first.c_str());
584
return a.second < b.second;
358
590
/** returns -1 in case of no results, rcode otherwise */
359
int SyncRes::doResolveAt(set<string> nameservers, string auth, const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret,
360
int depth, set<GetBestNSAnswer>&beenthere)
591
int SyncRes::doResolveAt(set<string, CIStringCompare> nameservers, string auth, bool flawedNSSet, const string &qname, const QType &qtype,
592
vector<DNSResourceRecord>&ret,
593
int depth, set<GetBestNSAnswer>&beenthere)
362
string prefix(d_prefix);
363
prefix.append(depth, ' ');
598
prefix.append(depth, ' ');
365
601
LWRes::res_t result;
367
LOG<<prefix<<qname<<": Cache consultations done, have "<<nameservers.size()<<" NS to contact"<<endl;
603
LOG<<prefix<<qname<<": Cache consultations done, have "<<(unsigned int)nameservers.size()<<" NS to contact"<<endl;
369
605
for(;;) { // we may get more specific nameservers
372
vector<string> rnameservers=shuffle(nameservers, prefix+qname+": ");
608
vector<string> rnameservers=shuffleInSpeedOrder(nameservers, s_log ? (prefix+qname+": ") : string() );
374
610
for(vector<string>::const_iterator tns=rnameservers.begin();;++tns) {
375
611
if(tns==rnameservers.end()) {
376
LOG<<prefix<<qname<<": Failed to resolve via any of the "<<rnameservers.size()<<" offered NS"<<endl;
612
LOG<<prefix<<qname<<": Failed to resolve via any of the "<<(unsigned int)rnameservers.size()<<" offered NS at level '"<<auth<<"'"<<endl;
613
if(auth!="." && flawedNSSet) {
614
g_stats.nsSetInvalidations++;
615
LOG<<prefix<<qname<<": Invalidating nameservers for level '"<<auth<<"', next query might succeed"<<endl;
616
RC.doWipeCache(auth, QType::NS);
379
620
if(qname==*tns && qtype.getCode()==QType::A) {
380
621
LOG<<prefix<<qname<<": Not using NS to resolve itself!"<<endl;
383
LOG<<prefix<<qname<<": Trying to resolve NS "<<*tns<<" ("<<1+tns-rnameservers.begin()<<"/"<<rnameservers.size()<<")"<<endl;
384
typedef vector<string> remoteIPs_t;
385
remoteIPs_t remoteIPs=getAs(*tns, depth+1, beenthere);
386
if(remoteIPs.empty()) {
387
LOG<<prefix<<qname<<": Failed to get IP for NS "<<*tns<<", trying next if available"<<endl;
625
typedef vector<ComboAddress> remoteIPs_t;
626
remoteIPs_t remoteIPs;
390
627
remoteIPs_t::const_iterator remoteIP;
391
628
bool doTCP=false;
392
for(remoteIP = remoteIPs.begin(); remoteIP != remoteIPs.end(); ++remoteIP) {
393
LOG<<prefix<<qname<<": Resolved '"+auth+"' NS "<<*tns<<" to "<<*remoteIP<<", asking '"<<qname<<"|"<<qtype.getName()<<"'"<<endl;
395
if(s_throttle.shouldThrottle(d_now.tv_sec, *remoteIP+"|"+qname+"|"+qtype.getName())) {
396
LOG<<prefix<<qname<<": query throttled "<<endl;
397
s_throttledqueries++;
398
d_throttledqueries++;
632
LOG<<prefix<<qname<<": Domain is out-of-band"<<endl;
633
doOOBResolve(qname, qtype, result, depth, d_lwr.d_rcode);
638
LOG<<prefix<<qname<<": Trying to resolve NS '"<<*tns<<"' ("<<1+tns-rnameservers.begin()<<"/"<<(unsigned int)rnameservers.size()<<")"<<endl;
639
if(!isCanonical(*tns)) {
640
LOG<<prefix<<qname<<": Domain has hardcoded nameserver"<<endl;
641
remoteIPs.push_back(ComboAddress(*tns, 53));
644
remoteIPs=getAs(*tns, depth+1, beenthere);
646
if(remoteIPs.empty()) {
647
LOG<<prefix<<qname<<": Failed to get IP for NS "<<*tns<<", trying next if available"<<endl;
410
int ret=d_lwr.asyncresolve(*remoteIP, qname.c_str(), qtype.getCode(), doTCP); // <- we go out on the wire!
413
LOG<<prefix<<qname<<": timeout resolving"<<endl;
415
s_outgoingtimeouts++;
418
LOG<<prefix<<qname<<": error resolving"<<endl;
420
s_nsSpeeds[toLower(*tns)].submit(1000000, &d_now); // 1 sec
422
s_throttle.throttle(d_now.tv_sec, *remoteIP+"|"+qname+"|"+qtype.getName(),20,5);
425
gettimeofday(&d_now, 0);
426
break; // it did work!
430
if(remoteIP == remoteIPs.end()) // we tried all IP addresses, none worked
433
result=d_lwr.result();
652
LOG<<prefix<<qname<<": Resolved '"+auth+"' NS "<<*tns<<" to: ";
653
for(remoteIP = remoteIPs.begin(); remoteIP != remoteIPs.end(); ++remoteIP) {
654
if(remoteIP != remoteIPs.begin())
656
LOG<<remoteIP->toString();
661
for(remoteIP = remoteIPs.begin(); remoteIP != remoteIPs.end(); ++remoteIP) {
662
LOG<<prefix<<qname<<": Trying IP "<< remoteIP->toString() <<", asking '"<<qname<<"|"<<qtype.getName()<<"'"<<endl;
663
extern NetmaskGroup* g_dontQuery;
665
if(s_throttle.shouldThrottle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()))) {
666
LOG<<prefix<<qname<<": query throttled "<<endl;
667
s_throttledqueries++; d_throttledqueries++;
670
else if(g_dontQuery && g_dontQuery->match(&*remoteIP)) {
671
LOG<<prefix<<qname<<": not sending query to " << remoteIP->toString() << ", blocked by 'dont-query' setting" << endl;
675
s_outqueries++; d_outqueries++;
678
s_tcpoutqueries++; d_tcpoutqueries++;
681
resolveret=d_lwr.asyncresolve(*remoteIP, qname, qtype.getCode(), doTCP, &d_now); // <- we go out on the wire!
682
if(resolveret != 1) {
684
LOG<<prefix<<qname<<": timeout resolving "<< (doTCP ? "over TCP" : "")<<endl;
686
s_outgoingtimeouts++;
688
else if(resolveret==-2) {
689
LOG<<prefix<<qname<<": hit a local resource limit resolving "<< (doTCP ? "over TCP" : "")<<endl;
690
g_stats.resourceLimits++;
693
s_unreachables++; d_unreachables++;
694
LOG<<prefix<<qname<<": error resolving "<< (doTCP ? "over TCP" : "") << endl;
697
if(resolveret!=-2) { // don't account for resource limits, they are our own fault
698
s_nsSpeeds[*tns].submit(*remoteIP, 1000000, &d_now); // 1 sec
700
s_throttle.throttle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100); // unreachable
702
s_throttle.throttle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()), 20, 5); // timeout
707
break; // this IP address worked!
708
wasLame:; // well, it didn't
709
LOG<<prefix<<qname<<": status=NS "<<*tns<<" ("<< remoteIP->toString() <<") is lame for '"<<auth<<"', trying sibling IP or NS"<<endl;
710
s_throttle.throttle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100);
714
if(remoteIP == remoteIPs.end()) // we tried all IP addresses, none worked
717
result=d_lwr.result();
438
LOG<<prefix<<qname<<": truncated bit set, retrying via TCP"<<endl;
441
LOG<<prefix<<qname<<": truncated bit set, over TCP?"<<endl;
442
return RCode::ServFail;
445
if(d_lwr.d_rcode==RCode::ServFail) {
446
LOG<<prefix<<qname<<": "<<*tns<<" returned a ServFail, trying sibling NS"<<endl;
447
s_throttle.throttle(d_now.tv_sec,*remoteIP+"|"+qname+"|"+qtype.getName(),60,3);
450
LOG<<prefix<<qname<<": Got "<<result.size()<<" answers from "<<*tns<<" ("<<*remoteIP<<"), rcode="<<d_lwr.d_rcode<<", in "<<d_lwr.d_usec/1000<<"ms"<<endl;
451
s_nsSpeeds[toLower(*tns)].submit(d_lwr.d_usec, &d_now);
453
map<string,set<DNSResourceRecord> > tcache;
722
LOG<<prefix<<qname<<": truncated bit set, retrying via TCP"<<endl;
725
LOG<<prefix<<qname<<": truncated bit set, over TCP?"<<endl;
726
return RCode::ServFail;
729
if(d_lwr.d_rcode==RCode::ServFail) {
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);
734
LOG<<prefix<<qname<<": Got "<<(unsigned int)result.size()<<" answers from "<<*tns<<" ("<< remoteIP->toString() <<"), rcode="<<d_lwr.d_rcode<<", in "<<d_lwr.d_usec/1000<<"ms"<<endl;
736
/* // for you IPv6 fanatics :-)
737
if(remoteIP->sin4.sin_family==AF_INET6)
741
s_nsSpeeds[*tns].submit(*remoteIP, d_lwr.d_usec, &d_now);
744
typedef map<pair<string, QType>, set<DNSResourceRecord>, TCacheComp > tcache_t;
454
747
// reap all answers from this packet that are acceptable
455
748
for(LWRes::res_t::const_iterator i=result.begin();i!=result.end();++i) {
456
if(i->qtype.getCode() < 1024) {
457
LOG<<prefix<<qname<<": accept answer '"<<i->qname<<"|"<<i->qtype.getName()<<"|"<<i->content<<"' from '"<<auth<<"' nameservers? ";
460
LOG<<prefix<<qname<<": accept opaque answer '"<<i->qname<<"|"<<QType(i->qtype.getCode()-1024).getName()<<" from '"<<auth<<"' nameservers? ";
463
if(endsOn(i->qname, auth)) {
749
LOG<<prefix<<qname<<": accept answer '"<<i->qname<<"|"<<i->qtype.getName()<<"|"<<i->content<<"' from '"<<auth<<"' nameservers? ";
750
if(i->qtype.getCode()==QType::ANY) {
751
LOG<<"NO! - we don't accept 'ANY' data"<<endl;
755
if(dottedEndsOn(i->qname, auth)) {
464
756
if(d_lwr.d_aabit && d_lwr.d_rcode==RCode::NoError && i->d_place==DNSResourceRecord::ANSWER && ::arg().contains("delegation-only",auth)) {
465
757
LOG<<"NO! Is from delegation-only zone"<<endl;
484
for(map<string,set<DNSResourceRecord> >::const_iterator i=tcache.begin();i!=tcache.end();++i) {
486
stringtok(parts,i->first,"|");
488
if(parts.size()==2) {
490
RC.replace(parts[0],qt,i->second);
494
RC.replace("",qt,i->second);
780
for(tcache_t::iterator i=tcache.begin();i!=tcache.end();++i) {
781
if(i->second.size() > 1) { // need to group the ttl to be the minimum of the RRSET (RFC 2181, 5.2)
782
uint32_t lowestTTL=numeric_limits<uint32_t>::max();
783
for(tcache_t::value_type::second_type::iterator j=i->second.begin(); j != i->second.end(); ++j)
784
lowestTTL=min(lowestTTL, j->ttl);
786
for(tcache_t::value_type::second_type::iterator j=i->second.begin(); j != i->second.end(); ++j)
787
((tcache_t::value_type::second_type::value_type*)&(*j))->ttl=lowestTTL;
790
RC.replace(d_now.tv_sec, i->first.first, i->first.second, i->second, d_lwr.d_aabit);
792
set<string, CIStringCompare> nsset;
498
793
LOG<<prefix<<qname<<": determining status after receiving this packet"<<endl;
500
795
bool done=false, realreferral=false, negindic=false;
501
796
string newauth, soaname, newtarget;
503
798
for(LWRes::res_t::const_iterator i=result.begin();i!=result.end();++i) {
504
if(i->d_place==DNSResourceRecord::AUTHORITY && endsOn(qname,i->qname) && i->qtype.getCode()==QType::SOA &&
799
if(i->d_place==DNSResourceRecord::AUTHORITY && dottedEndsOn(qname,i->qname) && i->qtype.getCode()==QType::SOA &&
505
800
d_lwr.d_rcode==RCode::NXDomain) {
506
LOG<<prefix<<qname<<": got negative caching indication for RECORD '"<<toLower(qname)+"'"<<endl;
801
LOG<<prefix<<qname<<": got negative caching indication for RECORD '"<<qname+"'"<<endl;
507
802
ret.push_back(*i);
509
804
NegCacheEntry ne;
511
ne.ttd=d_now.tv_sec + i->ttl;
512
s_negcache[toLower(qname)]=ne;
807
ne.d_ttd=d_now.tv_sec + min(i->ttl, s_maxnegttl); // controversial
809
ne.d_qtype=QType(0); // this encodes 'whole record'
811
replacing_insert(s_negcache, ne);
515
814
else if(i->d_place==DNSResourceRecord::ANSWER && i->qname==qname && i->qtype.getCode()==QType::CNAME && (!(qtype==QType(QType::CNAME)))) {
516
815
ret.push_back(*i);
517
newtarget=toLowerCanonic(i->content);
816
newtarget=i->content;
519
818
// for ANY answers we *must* have an authoritive answer
520
else if(i->d_place==DNSResourceRecord::ANSWER && toLower(i->qname)==toLower(qname) &&
521
(((i->qtype==qtype) || (i->qtype.getCode()>1024 && i->qtype.getCode()-1024==qtype.getCode())) || ( qtype==QType(QType::ANY) &&
523
if(i->qtype.getCode() < 1024) {
524
LOG<<prefix<<qname<<": answer is in: resolved to '"<< i->content<<"|"<<i->qtype.getName()<<"'"<<endl;
527
LOG<<prefix<<qname<<": answer is in: resolved to opaque record of type '"<<QType(i->qtype.getCode()-1024).getName()<<"'"<<endl;
819
else if(i->d_place==DNSResourceRecord::ANSWER && !Utility::strcasecmp(i->qname.c_str(),qname.c_str()) &&
820
( (i->qtype==qtype) ||
821
( qtype==QType(QType::ANY) && d_lwr.d_aabit))) {
823
LOG<<prefix<<qname<<": answer is in: resolved to '"<< i->content<<"|"<<i->qtype.getName()<<"'"<<endl;
531
826
ret.push_back(*i);
533
else if(i->d_place==DNSResourceRecord::AUTHORITY && endsOn(qname,i->qname) && i->qtype.getCode()==QType::NS) {
828
else if(i->d_place==DNSResourceRecord::AUTHORITY && dottedEndsOn(qname,i->qname) && i->qtype.getCode()==QType::NS) {
534
829
if(moreSpecificThan(i->qname,auth)) {
535
830
newauth=i->qname;
536
831
LOG<<prefix<<qname<<": got NS record '"<<i->qname<<"' -> '"<<i->content<<"'"<<endl;
562
861
return RCode::NXDomain;
564
863
if(!newtarget.empty()) {
864
if(iequals(newtarget,qname)) {
865
LOG<<prefix<<qname<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl;
866
return RCode::ServFail;
869
LOG<<prefix<<qname<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl;
870
return RCode::ServFail;
565
872
LOG<<prefix<<qname<<": status=got a CNAME referral, starting over with "<<newtarget<<endl;
566
874
set<GetBestNSAnswer>beenthere2;
567
return doResolve(newtarget, qtype, ret,0,beenthere2);
875
return doResolve(newtarget, qtype, ret, depth + 1, beenthere2);
569
877
if(nsset.empty() && !d_lwr.d_rcode) {
570
878
LOG<<prefix<<qname<<": status=noerror, other types may exist, but we are done "<<(negindic ? "(have negative SOA)" : "")<<endl;
573
881
else if(realreferral) {
574
LOG<<prefix<<qname<<": status=did not resolve, got "<<nsset.size()<<" NS, looping to them"<<endl;
882
LOG<<prefix<<qname<<": status=did not resolve, got "<<(unsigned int)nsset.size()<<" NS, looping to them"<<endl;
576
884
nameservers=nsset;
580
LOG<<prefix<<qname<<": status=NS "<<*tns<<" is lame for '"<<auth<<"', trying sibling NS"<<endl;
581
s_throttle.throttle(d_now.tv_sec, *remoteIP+"|"+qname+"|"+qtype.getName(),60,0);
887
else if(isCanonical(*tns)) {
895
static bool uniqueComp(const DNSResourceRecord& a, const DNSResourceRecord& b)
897
return(a.qtype==b.qtype && a.qname==b.qname && a.content==b.content);
588
900
void SyncRes::addCruft(const string &qname, vector<DNSResourceRecord>& ret)
590
902
for(vector<DNSResourceRecord>::const_iterator k=ret.begin();k!=ret.end();++k) // don't add stuff to an NXDOMAIN!
598
910
LOG<<d_prefix<<qname<<": Starting additional processing"<<endl;
599
911
vector<DNSResourceRecord> addit;
600
bool doIPv6AP=::arg().mustDo("aaaa-additional-processing");
912
static optional<bool> l_doIPv6AP;
914
l_doIPv6AP=::arg().mustDo("aaaa-additional-processing");
601
916
for(vector<DNSResourceRecord>::const_iterator k=ret.begin();k!=ret.end();++k)
602
if((k->d_place==DNSResourceRecord::ANSWER && k->qtype==QType(QType::MX)) ||
917
if( (k->d_place==DNSResourceRecord::ANSWER && (k->qtype==QType(QType::MX) || k->qtype==QType(QType::SRV))) ||
603
918
((k->d_place==DNSResourceRecord::AUTHORITY || k->d_place==DNSResourceRecord::ANSWER) && k->qtype==QType(QType::NS))) {
604
919
LOG<<d_prefix<<qname<<": record '"<<k->content<<"|"<<k->qtype.getName()<<"' needs IP for additional processing"<<endl;
605
set<GetBestNSAnswer>beenthere;
606
if(k->qtype==QType(QType::MX)) {
607
string::size_type pos=k->content.find_first_not_of(" \t0123456789"); // chop off the priority
608
if(pos!=string::npos) {
609
doResolve(toLowerCanonic(k->content.substr(pos)), QType(QType::A),addit,1,beenthere);
611
doResolve(toLowerCanonic(k->content.substr(pos)), QType(QType::AAAA),addit,1,beenthere);
614
doResolve(toLowerCanonic(k->content), QType(QType::A),addit,1,beenthere);
616
doResolve(toLowerCanonic(k->content.substr(pos)), QType(QType::AAAA),addit,1,beenthere);
620
doResolve(k->content,QType(QType::A),addit,1,beenthere);
622
doResolve(k->content,QType(QType::AAAA),addit,1,beenthere);
920
set<GetBestNSAnswer> beenthere;
921
vector<pair<string::size_type, string::size_type> > fields;
922
vstringtok(fields, k->content, " ");
924
if(k->qtype==QType(QType::MX) && fields.size()==2)
925
host=string(k->content.c_str() + fields[1].first, fields[1].second - fields[1].first);
926
else if(k->qtype==QType(QType::NS))
928
else if(k->qtype==QType(QType::SRV) && fields.size()==4)
929
host=string(k->content.c_str() + fields[3].first, fields[3].second - fields[3].first);
932
doResolve(host, QType(QType::A), addit, 1, beenthere);
934
doResolve(host, QType(QType::AAAA), addit, 1, beenthere);
937
sort(addit.begin(), addit.end());
938
addit.erase(unique(addit.begin(), addit.end(), uniqueComp), addit.end());
626
939
for(vector<DNSResourceRecord>::iterator k=addit.begin();k!=addit.end();++k) {
627
940
if(k->qtype.getCode()==QType::A || k->qtype.getCode()==QType::AAAA) {
628
941
k->d_place=DNSResourceRecord::ADDITIONAL;