root/trunk/pdns/pdns/syncres.cc @ 721

Revision 721, 21.8 KB (checked in by ahu, 7 years ago)

fix 'removing unlisted fd from multiplexer'
remove --single-socket support (and --query-local-port with it)
make powerdns deal with resource limit errors (specifically EMFILE)
make reporting ICMP errors faster by passing around PacketID

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