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

Revision 658, 21.5 KB (checked in by ahu, 7 years ago)

fix interesting bug whereby powerdns would sometimes claim to be unable to resolve its rootservers. Found by valgrind. Halve number of s_negcache lookups.

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