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

Revision 1996, 42.7 KB (checked in by ahu, 2 years ago)

fix up 'wingsuitnews.com' - they don't deserve to resolve though..

  • 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 - 2010  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#include <boost/algorithm/string.hpp>
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#include "dns_random.hh"
38#include "lock.hh"
39#include "cachecleaner.hh"
40
41__thread SyncRes::StaticStorage* t_sstorage;
42
43unsigned int SyncRes::s_maxnegttl;
44unsigned int SyncRes::s_maxcachettl;
45unsigned int SyncRes::s_packetcachettl;
46unsigned int SyncRes::s_packetcacheservfailttl;
47unsigned int SyncRes::s_queries;
48unsigned int SyncRes::s_outgoingtimeouts;
49unsigned int SyncRes::s_outqueries;
50unsigned int SyncRes::s_tcpoutqueries;
51unsigned int SyncRes::s_throttledqueries;
52unsigned int SyncRes::s_dontqueries;
53unsigned int SyncRes::s_nodelegated;
54unsigned int SyncRes::s_unreachables;
55bool SyncRes::s_doIPv6;
56bool SyncRes::s_nopacketcache;
57
58string SyncRes::s_serverID;
59bool SyncRes::s_log;
60
61#define LOG if(s_log) L<<Logger::Warning
62
63bool SyncRes::s_noEDNSPing;
64bool SyncRes::s_noEDNS;
65
66SyncRes::SyncRes(const struct timeval& now) :  d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0),
67                                                 d_now(now),
68                                                 d_cacheonly(false), d_nocache(false), d_doEDNS0(false) 
69{ 
70  if(!t_sstorage) {
71    t_sstorage = new StaticStorage();
72  }
73}
74
75/** everything begins here - this is the entry point just after receiving a packet */
76int SyncRes::beginResolve(const string &qname, const QType &qtype, uint16_t qclass, vector<DNSResourceRecord>&ret)
77{
78  s_queries++;
79 
80  if( (qtype.getCode() == QType::AXFR)) 
81    return -1;
82 
83  if( (qtype.getCode()==QType::PTR && pdns_iequals(qname, "1.0.0.127.in-addr.arpa.")) ||
84      (qtype.getCode()==QType::A && qname.length()==10 && pdns_iequals(qname, "localhost."))) {
85    ret.clear();
86    DNSResourceRecord rr;
87    rr.qname=qname;
88    rr.qtype=qtype;
89    rr.qclass=1;
90    rr.ttl=86400;
91    if(qtype.getCode()==QType::PTR)
92      rr.content="localhost.";
93    else
94      rr.content="127.0.0.1";
95    ret.push_back(rr);
96    return 0;
97  }
98
99  if(qclass==3 && qtype.getCode()==QType::TXT && 
100        (pdns_iequals(qname, "version.bind.") || pdns_iequals(qname, "id.server.") || pdns_iequals(qname, "version.pdns.") ) 
101     ) {
102    ret.clear();
103    DNSResourceRecord rr;
104    rr.qname=qname;
105    rr.qtype=qtype;
106    rr.qclass=qclass;
107    rr.ttl=86400;
108    if(pdns_iequals(qname,"version.bind.")  || pdns_iequals(qname,"version.pdns."))
109      rr.content="\""+::arg()["version-string"]+"\"";
110    else
111      rr.content="\""+s_serverID+"\"";
112    ret.push_back(rr);
113    return 0;
114  }
115 
116  if(qclass==0xff)
117    qclass=1;
118  else if(qclass!=1)
119    return -1;
120 
121  set<GetBestNSAnswer> beenthere;
122  int res=doResolve(qname, qtype, ret, 0, beenthere);
123  if(!res)
124    addCruft(qname, ret);
125  return res;
126}
127
128//! This is the 'out of band resolver', in other words, the authoritative server
129bool SyncRes::doOOBResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int& res)
130{
131  string prefix;
132  if(s_log) {
133    prefix=d_prefix;
134    prefix.append(depth, ' ');
135  }
136
137  LOG<<prefix<<qname<<": checking auth storage for '"<<qname<<"|"<<qtype.getName()<<"'"<<endl;
138  string authdomain(qname);
139
140  domainmap_t::const_iterator iter=getBestAuthZone(&authdomain);
141  if(iter==t_sstorage->domainmap->end()) {
142    LOG<<prefix<<qname<<": auth storage has no zone for this query!"<<endl;
143    return false;
144  }
145  LOG<<prefix<<qname<<": auth storage has data, zone='"<<authdomain<<"'"<<endl;
146  pair<AuthDomain::records_t::const_iterator, AuthDomain::records_t::const_iterator> range;
147
148  range=iter->second.d_records.equal_range(tie(qname)); // partial lookup
149
150  ret.clear();
151  AuthDomain::records_t::const_iterator ziter;
152  bool somedata=false;
153  for(ziter=range.first; ziter!=range.second; ++ziter) {
154    somedata=true;
155    if(qtype.getCode()==QType::ANY || ziter->qtype==qtype || ziter->qtype.getCode()==QType::CNAME)  // let rest of nameserver do the legwork on this one
156      ret.push_back(*ziter);
157  }
158  if(!ret.empty()) {
159    LOG<<prefix<<qname<<": exact match in zone '"<<authdomain<<"'"<<endl;
160    res=0;
161    return true;
162  }
163  if(somedata) {
164    LOG<<prefix<<qname<<": found record in '"<<authdomain<<"', but nothing of the right type, sending SOA"<<endl;
165    ziter=iter->second.d_records.find(make_tuple(authdomain, QType(QType::SOA)));
166    if(ziter!=iter->second.d_records.end()) {
167      DNSResourceRecord rr=*ziter;
168      rr.d_place=DNSResourceRecord::AUTHORITY;
169      ret.push_back(rr);
170    }
171    else
172      LOG<<prefix<<qname<<": can't find SOA record '"<<authdomain<<"' in our zone!"<<endl;
173    res=RCode::NoError;
174    return true;
175  }
176
177  string nsdomain(qname);
178
179  while(chopOffDotted(nsdomain) && !pdns_iequals(nsdomain, iter->first)) {
180    range=iter->second.d_records.equal_range(make_tuple(nsdomain,QType(QType::NS))); 
181    if(range.first==range.second)
182      continue;
183
184    for(ziter=range.first; ziter!=range.second; ++ziter) {
185      DNSResourceRecord rr=*ziter;
186      rr.d_place=DNSResourceRecord::AUTHORITY;
187      ret.push_back(rr);
188    }
189  }
190  if(ret.empty()) { 
191    LOG<<prefix<<qname<<": no NS match in zone '"<<authdomain<<"' either, handing out SOA"<<endl;
192    ziter=iter->second.d_records.find(make_tuple(authdomain, QType(QType::SOA)));
193    if(ziter!=iter->second.d_records.end()) {
194      DNSResourceRecord rr=*ziter;
195      rr.d_place=DNSResourceRecord::AUTHORITY;
196      ret.push_back(rr);
197    }
198    else
199      LOG<<prefix<<qname<<": can't find SOA record '"<<authdomain<<"' in our zone!"<<endl;
200    res=RCode::NXDomain;
201  }
202  else 
203    res=0;
204
205  return true;
206}
207
208
209
210void SyncRes::doEDNSDumpAndClose(int fd)
211{
212  FILE* fp=fdopen(fd, "w");
213  fprintf(fp,"IP Address\tMode\tMode last updated at\n");
214
215  for(ednsstatus_t::const_iterator iter = t_sstorage->ednsstatus.begin(); iter != t_sstorage->ednsstatus.end(); ++iter) {
216    fprintf(fp, "%s\t%d\t%s", iter->first.toString().c_str(), (int)iter->second.mode, ctime(&iter->second.modeSetAt));
217  }
218
219  fclose(fp);
220}
221
222int SyncRes::asyncresolveWrapper(const ComboAddress& ip, const string& domain, int type, bool doTCP, bool sendRDQuery, struct timeval* now, LWResult* res) 
223{
224  /* what is your QUEST?
225     the goal is to get as many remotes as possible on the highest level of hipness: EDNS PING responders.
226     The levels are:
227
228     -1) CONFIRMEDPINGER: Confirmed pinger!
229     0) UNKNOWN Unknown state
230     1) EDNSNOPING: Honors EDNS0 if no PING is included
231     2) EDNSPINGOK: Ignores EDNS0+PING, but does generate EDNS0 response
232     3) EDNSIGNORANT: Ignores EDNS0+PING, gives replies without EDNS0 nor PING
233     4) NOEDNS: Generates FORMERR on EDNS queries
234
235     Everybody starts out assumed to be '0'.
236     If '-1', send out EDNS0+Ping
237        If we get a FormErr, ignore
238        If we get a incorrect PING, ignore
239        If we get no PING, ignore
240     If '0', send out EDNS0+Ping
241        If we get a pure EDNS response, you are downgraded to '2'.
242        If you FORMERR us, go to '1',
243        If no EDNS in response, go to '3' - 3 and 0 are really identical, except confirmed
244        If with correct PING, upgrade to -1
245     If '1', send out EDNS0, no PING
246        If FORMERR, downgrade to 4
247     If '2', keep on including EDNS0+PING, just don't expect PING to be correct
248        If PING correct, move to '0', and cheer in the log file!
249     If '3', keep on including EDNS0+PING, see what happens
250        Same behaviour as 0
251     If '4', send bare queries
252  */
253
254  if(s_noEDNS) {
255    g_stats.noEdnsOutQueries++;
256    return asyncresolve(ip, domain, type, doTCP, sendRDQuery, 0, now, res);
257  }
258
259  SyncRes::EDNSStatus* ednsstatus;
260  ednsstatus = &t_sstorage->ednsstatus[ip];
261
262  if(ednsstatus->modeSetAt && ednsstatus->modeSetAt + 3600 < d_now.tv_sec) {
263    *ednsstatus=SyncRes::EDNSStatus();
264    //    cerr<<"Resetting EDNS Status for "<<ip.toString()<<endl;
265  }
266
267  if(s_noEDNSPing && ednsstatus->mode == EDNSStatus::UNKNOWN)
268    ednsstatus->mode = EDNSStatus::EDNSNOPING;
269
270  SyncRes::EDNSStatus::EDNSMode& mode=ednsstatus->mode;
271  SyncRes::EDNSStatus::EDNSMode oldmode = mode;
272  int EDNSLevel=0;
273
274  int ret;
275  for(int tries = 0; tries < 3; ++tries) {
276    //    cerr<<"Remote '"<<ip.toString()<<"' currently in mode "<<mode<<endl;
277
278    if(mode==EDNSStatus::CONFIRMEDPINGER || mode==EDNSStatus::UNKNOWN || mode==EDNSStatus::EDNSPINGOK || mode==EDNSStatus::EDNSIGNORANT)
279      EDNSLevel = 2;
280    else if(mode==EDNSStatus::EDNSNOPING) {
281      EDNSLevel = 1;
282      g_stats.noPingOutQueries++;
283    }
284    else if(mode==EDNSStatus::NOEDNS) {
285      g_stats.noEdnsOutQueries++;
286      EDNSLevel = 0;
287    }
288
289    ret=asyncresolve(ip, domain, type, doTCP, sendRDQuery, EDNSLevel, now, res);
290    if(ret == 0 || ret < 0) {
291      //      cerr<<"Transport error or timeout (ret="<<ret<<"), no change in mode"<<endl;
292      return ret;
293    }
294
295    if(mode== EDNSStatus::CONFIRMEDPINGER) {  // confirmed pinger!
296      if(!res->d_pingCorrect) {
297        L<<Logger::Error<<"Confirmed EDNS-PING enabled host "<<ip.toString()<<" did not send back correct ping"<<endl;
298        //      perhaps lower some kind of count here, don't want to punnish a downgrader too long!
299        ret = 0;
300        res->d_rcode = RCode::ServFail;
301        g_stats.ednsPingMismatches++;
302      }
303      else {
304        g_stats.ednsPingMatches++;
305        ednsstatus->modeSetAt=d_now.tv_sec; // only the very best mode self-perpetuates
306      }
307    }
308    else if(mode==EDNSStatus::UNKNOWN || mode==EDNSStatus::EDNSPINGOK || mode == EDNSStatus::EDNSIGNORANT ) {
309      if(res->d_rcode == RCode::FormErr)  {
310        //      cerr<<"Downgrading to EDNSNOPING because of FORMERR!"<<endl;
311        mode = EDNSStatus::EDNSNOPING;
312        continue;
313      }
314      else if(mode==EDNSStatus::UNKNOWN && (res->d_rcode == RCode::Refused || res->d_rcode == RCode::NotImp) ) { // this "fixes" F5
315        //      cerr<<"Downgrading an unknown status to EDNSNOPING because of RCODE="<<res->d_rcode<<endl;
316        mode = EDNSStatus::EDNSNOPING;
317        continue;
318      }
319      else if(!res->d_pingCorrect && res->d_haveEDNS) 
320        mode = EDNSStatus::EDNSPINGOK;
321      else if(res->d_pingCorrect) {
322        L<<Logger::Warning<<"We welcome "<<ip.toString()<<" to the land of EDNS-PING!"<<endl;
323        mode = EDNSStatus::CONFIRMEDPINGER;
324        g_stats.ednsPingMatches++;
325      }
326      else if(!res->d_haveEDNS) {
327        if(mode != EDNSStatus::EDNSIGNORANT) {
328          mode = EDNSStatus::EDNSIGNORANT;
329          //      cerr<<"We find that "<<ip.toString()<<" is an EDNS-ignorer, moving to mode 3"<<endl;
330        }
331      }
332    }
333    else if(mode==EDNSStatus::EDNSNOPING) {
334      if(res->d_rcode == RCode::FormErr) {
335        //              cerr<<"Downgrading to mode 4, FORMERR!"<<endl;
336        mode = EDNSStatus::NOEDNS;
337        continue;
338      }
339    }
340    else if(mode==EDNSStatus::EDNSPINGOK) {
341      if(res->d_pingCorrect) {
342        // an upgrade!
343        L<<Logger::Warning<<"We welcome "<<ip.toString()<<" to the land of EDNS-PING!"<<endl;
344        mode = EDNSStatus::CONFIRMEDPINGER;
345      }
346    }
347    if(oldmode != mode)
348      ednsstatus->modeSetAt=d_now.tv_sec;
349    //        cerr<<"Result: ret="<<ret<<", EDNS-level: "<<EDNSLevel<<", haveEDNS: "<<res->d_haveEDNS<<", EDNS-PING correct: "<<res->d_pingCorrect<<", new mode: "<<mode<<endl; 
350   
351    return ret;
352  }
353  return ret;
354}
355
356int SyncRes::doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, set<GetBestNSAnswer>& beenthere)
357{
358  string prefix;
359  if(s_log) {
360    prefix=d_prefix;
361    prefix.append(depth, ' ');
362  }
363 
364  int res=0;
365  if(!(d_nocache && qtype.getCode()==QType::NS && qname==".")) {
366    if(d_cacheonly) { // very limited OOB support
367      LWResult lwr;
368      LOG<<prefix<<qname<<": Recursion not requested for '"<<qname<<"|"<<qtype.getName()<<"', peeking at auth/forward zones"<<endl;
369      string authname(qname);
370      domainmap_t::const_iterator iter=getBestAuthZone(&authname);
371      if(iter != t_sstorage->domainmap->end()) {
372        const vector<ComboAddress>& servers = iter->second.d_servers;
373        if(servers.empty()) {
374          ret.clear();
375          doOOBResolve(qname, qtype, ret, depth, res);
376          return res;
377        }
378        else {
379          const ComboAddress remoteIP = servers.front();
380          LOG<<prefix<<qname<<": forwarding query to hardcoded nameserver '"<< remoteIP.toStringWithPort()<<"' for zone '"<<authname<<"'"<<endl;
381
382          res=asyncresolveWrapper(remoteIP, qname, qtype.getCode(), false, false, &d_now, &lwr);   
383          // filter out the good stuff from lwr.result()
384
385          for(LWResult::res_t::const_iterator i=lwr.d_result.begin();i!=lwr.d_result.end();++i) {
386            if(i->d_place == DNSResourceRecord::ANSWER)
387              ret.push_back(*i);
388          }
389          return res;
390        }
391      }
392    }
393
394    if(doCNAMECacheCheck(qname,qtype,ret,depth,res)) // will reroute us if needed
395      return res;
396   
397    if(doCacheCheck(qname,qtype,ret,depth,res)) // we done
398      return res;
399  }
400
401  if(d_cacheonly)
402    return 0;
403   
404  LOG<<prefix<<qname<<": No cache hit for '"<<qname<<"|"<<qtype.getName()<<"', trying to find an appropriate NS record"<<endl;
405
406  string subdomain(qname);
407
408  set<string, CIStringCompare> nsset;
409  bool flawedNSSet=false;
410  for(int tries=0;tries<2 && nsset.empty();++tries) {
411    subdomain=getBestNSNamesFromCache(subdomain, nsset, &flawedNSSet, depth, beenthere); //  pass beenthere to both occasions
412
413    if(nsset.empty()) { // must've lost root records
414      set<DNSResourceRecord> rootset;
415      /* this additional test is needed since getBestNSNamesFromCache sometimes returns that no
416         useful NS records were found, even without the root being expired. This might for example
417         be the case when the . records are not acceptable because they are part of a loop, a loop
418         caused by the invalidation of an nsset during the resolution algorithm */
419      if(t_RC->get(d_now.tv_sec, ".", QType(QType::NS), &rootset) <= 0) {
420        L<<Logger::Warning<<prefix<<qname<<": our root expired, repriming from hints and retrying"<<endl;
421        primeHints();
422      }
423    }
424  }
425
426  if(!(res=doResolveAt(nsset, subdomain, flawedNSSet, qname, qtype, ret, depth, beenthere)))
427    return 0;
428 
429  LOG<<prefix<<qname<<": failed (res="<<res<<")"<<endl;
430  return res<0 ? RCode::ServFail : res;
431}
432
433#if 0
434// for testing purpoises
435static bool ipv6First(const ComboAddress& a, const ComboAddress& b)
436{
437  return !(a.sin4.sin_family < a.sin4.sin_family);
438}
439#endif
440
441/** 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
442    Additionally, it will return the 'best' address up front, and the rest shufled
443*/
444vector<ComboAddress> SyncRes::getAs(const string &qname, int depth, set<GetBestNSAnswer>& beenthere)
445{
446  typedef vector<DNSResourceRecord> res_t;
447  res_t res;
448
449  typedef vector<ComboAddress> ret_t;
450  ret_t ret;
451
452  if(!doResolve(qname, s_doIPv6 ? QType(QType::ADDR) : QType(QType::A), res,depth+1,beenthere) && !res.empty()) {  // this consults cache, OR goes out
453    for(res_t::const_iterator i=res.begin(); i!= res.end(); ++i) {
454      if(i->qtype.getCode()==QType::A || i->qtype.getCode()==QType::AAAA) {
455        ret.push_back(ComboAddress(i->content, 53));
456      }
457    }
458  }
459 
460  if(ret.size() > 1) {
461    random_shuffle(ret.begin(), ret.end(), dns_random);
462
463    // move 'best' address for this nameserver name up front
464    nsspeeds_t::iterator best = t_sstorage->nsSpeeds.find(qname); 
465
466    if(best != t_sstorage->nsSpeeds.end())
467      for(ret_t::iterator i=ret.begin(); i != ret.end(); ++i) { 
468        if(*i==best->second.d_best) {  // got the fastest one
469          if(i!=ret.begin()) {
470            *i=*ret.begin();
471            *ret.begin()=best->second.d_best;
472          }
473          break;
474        }
475      }
476  }
477
478  return ret;
479}
480
481void SyncRes::getBestNSFromCache(const string &qname, set<DNSResourceRecord>&bestns, bool* flawedNSSet, int depth, set<GetBestNSAnswer>& beenthere)
482{
483  string prefix, subdomain(qname);
484  if(s_log) {
485    prefix=d_prefix;
486    prefix.append(depth, ' ');
487  }
488  bestns.clear();
489
490  do {
491    LOG<<prefix<<qname<<": Checking if we have NS in cache for '"<<subdomain<<"'"<<endl;
492    set<DNSResourceRecord> ns;
493    *flawedNSSet = false;
494    if(t_RC->get(d_now.tv_sec, subdomain, QType(QType::NS), &ns) > 0) {
495      for(set<DNSResourceRecord>::const_iterator k=ns.begin();k!=ns.end();++k) {
496        if(k->ttl > (unsigned int)d_now.tv_sec ) { 
497          set<DNSResourceRecord> aset;
498
499          DNSResourceRecord rr=*k;
500          rr.content=k->content;
501          if(!dottedEndsOn(rr.content, subdomain) || t_RC->get(d_now.tv_sec, rr.content, s_doIPv6 ? QType(QType::ADDR) : QType(QType::A),
502                                                            s_log ? &aset : 0) > 5) {
503            bestns.insert(rr);
504            LOG<<prefix<<qname<<": NS (with ip, or non-glue) in cache for '"<<subdomain<<"' -> '"<<rr.content<<"'"<<endl;
505            LOG<<prefix<<qname<<": within bailiwick: "<<dottedEndsOn(rr.content, subdomain);
506            if(!aset.empty()) {
507              LOG<<",  in cache, ttl="<<(unsigned int)(((time_t)aset.begin()->ttl- d_now.tv_sec ))<<endl;
508            }
509            else {
510              LOG<<", not in cache / did not look at cache"<<endl;
511            }
512          }
513          else {
514            *flawedNSSet=true;
515            LOG<<prefix<<qname<<": NS in cache for '"<<subdomain<<"', but needs glue ("<<k->content<<") which we miss or is expired"<<endl;
516          }
517        }
518      }
519      if(!bestns.empty()) {
520        GetBestNSAnswer answer;
521        answer.qname=qname; answer.bestns=bestns;
522        if(beenthere.count(answer)) {
523          LOG<<prefix<<qname<<": We have NS in cache for '"<<subdomain<<"' but part of LOOP! Trying less specific NS"<<endl;
524          if(s_log)
525            for( set<GetBestNSAnswer>::const_iterator j=beenthere.begin();j!=beenthere.end();++j)
526              LOG<<prefix<<qname<<": beenthere: "<<j->qname<<" ("<<(unsigned int)j->bestns.size()<<")"<<endl;
527          bestns.clear();
528        }
529        else {
530          beenthere.insert(answer);
531          LOG<<prefix<<qname<<": We have NS in cache for '"<<subdomain<<"' (flawedNSSet="<<*flawedNSSet<<")"<<endl;
532          return;
533        }
534      }
535    }
536    LOG<<prefix<<qname<<": no valid/useful NS in cache for '"<<subdomain<<"'"<<endl;
537  }while(chopOffDotted(subdomain));
538}
539
540SyncRes::domainmap_t::const_iterator SyncRes::getBestAuthZone(string* qname)
541{
542  SyncRes::domainmap_t::const_iterator ret;
543  do {
544    ret=t_sstorage->domainmap->find(*qname);
545    if(ret!=t_sstorage->domainmap->end()) 
546      break;
547  }while(chopOffDotted(*qname));
548  return ret;
549}
550
551/** doesn't actually do the work, leaves that to getBestNSFromCache */
552string SyncRes::getBestNSNamesFromCache(const string &qname, set<string, CIStringCompare>& nsset, bool* flawedNSSet, int depth, set<GetBestNSAnswer>&beenthere)
553{
554  string subdomain(qname);
555  string authdomain(qname);
556 
557  domainmap_t::const_iterator iter=getBestAuthZone(&authdomain);
558  if(iter!=t_sstorage->domainmap->end()) {
559    if( iter->second.d_servers.empty() )
560      nsset.insert(string()); // this gets picked up in doResolveAt, if empty it means "we are auth", otherwise it denotes a forward
561    else {
562      for(vector<ComboAddress>::const_iterator server=iter->second.d_servers.begin(); server != iter->second.d_servers.end(); ++server)
563        nsset.insert((iter->second.d_rdForward ? "+" : "-") + server->toStringWithPort()); // add a '+' if the rd bit should be set
564    }
565
566    return authdomain;
567  }
568
569  set<DNSResourceRecord> bestns;
570  getBestNSFromCache(subdomain, bestns, flawedNSSet, depth, beenthere);
571
572  for(set<DNSResourceRecord>::const_iterator k=bestns.begin();k!=bestns.end();++k) {
573    nsset.insert(k->content);
574    if(k==bestns.begin())
575      subdomain=k->qname;
576  }
577  return subdomain;
578}
579
580bool SyncRes::doCNAMECacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res)
581{
582  string prefix;
583  if(s_log) {
584    prefix=d_prefix; 
585    prefix.append(depth, ' ');
586  }
587
588  if(depth>10) {
589    LOG<<prefix<<qname<<": CNAME loop too deep, depth="<<depth<<endl;
590    res=RCode::ServFail;
591    return true;
592  }
593 
594  LOG<<prefix<<qname<<": Looking for CNAME cache hit of '"<<(qname+"|CNAME")<<"'"<<endl;
595  set<DNSResourceRecord> cset;
596  if(t_RC->get(d_now.tv_sec, qname,QType(QType::CNAME),&cset) > 0) {
597
598    for(set<DNSResourceRecord>::const_iterator j=cset.begin();j!=cset.end();++j) {
599      if(j->ttl>(unsigned int) d_now.tv_sec) {
600        LOG<<prefix<<qname<<": Found cache CNAME hit for '"<< (qname+"|CNAME") <<"' to '"<<j->content<<"'"<<endl;   
601        DNSResourceRecord rr=*j;
602        rr.ttl-=d_now.tv_sec;
603        ret.push_back(rr);
604        if(!(qtype==QType(QType::CNAME))) { // perhaps they really wanted a CNAME!
605          set<GetBestNSAnswer>beenthere;
606          res=doResolve(j->content, qtype, ret, depth+1, beenthere);
607        }
608        else
609          res=0;
610        return true;
611      }
612    }
613  }
614  LOG<<prefix<<qname<<": No CNAME cache hit of '"<< (qname+"|CNAME") <<"' found"<<endl;
615  return false;
616}
617
618
619
620
621bool SyncRes::doCacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res)
622{
623  bool giveNegative=false;
624 
625  string prefix;
626  if(s_log) {
627    prefix=d_prefix;
628    prefix.append(depth, ' ');
629  }
630
631  string sqname(qname);
632  QType sqt(qtype);
633  uint32_t sttl=0;
634  //  cout<<"Lookup for '"<<qname<<"|"<<qtype.getName()<<"'\n";
635 
636  pair<negcache_t::const_iterator, negcache_t::const_iterator> range=t_sstorage->negcache.equal_range(tie(qname));
637  negcache_t::iterator ni;
638  for(ni=range.first; ni != range.second; ni++) {
639    // we have something
640    if(ni->d_qtype.getCode() == 0 || ni->d_qtype == qtype) {
641      res=0;
642      if((uint32_t)d_now.tv_sec < ni->d_ttd) {
643        sttl=ni->d_ttd - d_now.tv_sec;
644        if(ni->d_qtype.getCode()) {
645          LOG<<prefix<<qname<<": "<<qtype.getName()<<" is negatively cached via '"<<ni->d_qname<<"' for another "<<sttl<<" seconds"<<endl;
646          res = RCode::NoError;
647        }
648        else {
649          LOG<<prefix<<qname<<": Entire record '"<<qname<<"', is negatively cached via '"<<ni->d_qname<<"' for another "<<sttl<<" seconds"<<endl;
650          res= RCode::NXDomain; 
651        }
652        giveNegative=true;
653        sqname=ni->d_qname;
654        sqt=QType::SOA;
655        moveCacheItemToBack(t_sstorage->negcache, ni);
656        break;
657      }
658      else {
659        LOG<<prefix<<qname<<": Entire record '"<<qname<<"' or type was negatively cached, but entry expired"<<endl;
660        moveCacheItemToFront(t_sstorage->negcache, ni);
661      }
662    }
663  }
664
665  set<DNSResourceRecord> cset;
666  bool found=false, expired=false;
667
668  if(t_RC->get(d_now.tv_sec, sqname, sqt, &cset) > 0) {
669    LOG<<prefix<<sqname<<": Found cache hit for "<<sqt.getName()<<": ";
670    for(set<DNSResourceRecord>::const_iterator j=cset.begin();j!=cset.end();++j) {
671      LOG<<j->content;
672      if(j->ttl>(unsigned int) d_now.tv_sec) {
673        DNSResourceRecord rr=*j;
674        rr.ttl-=d_now.tv_sec;
675        if(giveNegative) {
676          rr.d_place=DNSResourceRecord::AUTHORITY;
677          rr.ttl=sttl;
678        }
679        ret.push_back(rr);
680        LOG<<"[ttl="<<rr.ttl<<"] ";
681        found=true;
682      }
683      else {
684        LOG<<"[expired] ";
685        expired=true;
686      }
687    }
688 
689    LOG<<endl;
690    if(found && !expired) {
691      if(!giveNegative)
692        res=0;
693      return true;
694    }
695    else
696      LOG<<prefix<<qname<<": cache had only stale entries"<<endl;
697  }
698
699  return false;
700}
701
702bool SyncRes::moreSpecificThan(const string& a, const string &b)
703{
704  static string dot(".");
705  int counta=(a!=dot), countb=(b!=dot);
706 
707  for(string::size_type n=0;n<a.size();++n)
708    if(a[n]=='.')
709      counta++;
710  for(string::size_type n=0;n<b.size();++n)
711    if(b[n]=='.')
712      countb++;
713  return counta>countb;
714}
715
716struct speedOrder
717{
718  speedOrder(map<string,double> &speeds) : d_speeds(speeds) {}
719  bool operator()(const string &a, const string &b) const
720  {
721    return d_speeds[a] < d_speeds[b];
722  }
723  map<string,double>& d_speeds;
724};
725
726inline vector<string> SyncRes::shuffleInSpeedOrder(set<string, CIStringCompare> &nameservers, const string &prefix)
727{
728  vector<string> rnameservers;
729  rnameservers.reserve(nameservers.size());
730  map<string,double> speeds;
731
732  for(set<string, CIStringCompare>::const_iterator i=nameservers.begin();i!=nameservers.end();++i) {
733    rnameservers.push_back(*i);
734    double speed;
735    speed=t_sstorage->nsSpeeds[*i].get(&d_now);
736    speeds[*i]=speed;
737  }
738  random_shuffle(rnameservers.begin(),rnameservers.end(), dns_random);
739  speedOrder so(speeds);
740  stable_sort(rnameservers.begin(),rnameservers.end(), so);
741 
742  if(s_log) {
743    L<<Logger::Warning<<prefix<<"Nameservers: ";
744    for(vector<string>::const_iterator i=rnameservers.begin();i!=rnameservers.end();++i) {
745      if(i!=rnameservers.begin()) {
746        L<<", ";
747        if(!((i-rnameservers.begin())%3))
748          L<<endl<<Logger::Warning<<prefix<<"             ";
749      }
750      L<<*i<<"(" << (int)(speeds[*i]/1000.0) <<"ms)";
751    }
752    L<<endl;
753  }
754  return rnameservers;
755}
756
757struct TCacheComp
758{
759  bool operator()(const pair<string, QType>& a, const pair<string, QType>& b) const
760  {
761    if(pdns_ilexicographical_compare(a.first, b.first))
762      return true;
763    if(pdns_ilexicographical_compare(b.first, a.first))   
764      return false;
765     
766    return a.second < b.second;
767  }
768};
769
770static bool magicAddrMatch(const QType& query, const QType& answer)
771{
772  if(query.getCode() != QType::ADDR)
773    return false;
774  return answer.getCode() == QType::A || answer.getCode() == QType::AAAA;
775}
776
777double g_avgLatency;
778
779/** returns -1 in case of no results, rcode otherwise */
780int SyncRes::doResolveAt(set<string, CIStringCompare> nameservers, string auth, bool flawedNSSet, const string &qname, const QType &qtype, 
781                         vector<DNSResourceRecord>&ret, 
782                         int depth, set<GetBestNSAnswer>&beenthere)
783{
784  string prefix;
785  if(s_log) {
786    prefix=d_prefix;
787    prefix.append(depth, ' ');
788  }
789 
790  LOG<<prefix<<qname<<": Cache consultations done, have "<<(unsigned int)nameservers.size()<<" NS to contact"<<endl;
791
792  for(;;) { // we may get more specific nameservers
793    vector<string> rnameservers=shuffleInSpeedOrder(nameservers, s_log ? (prefix+qname+": ") : string() );
794
795    for(vector<string>::const_iterator tns=rnameservers.begin();;++tns) { 
796      if(tns==rnameservers.end()) {
797        LOG<<prefix<<qname<<": Failed to resolve via any of the "<<(unsigned int)rnameservers.size()<<" offered NS at level '"<<auth<<"'"<<endl;
798        if(auth!="." && flawedNSSet) {
799          LOG<<prefix<<qname<<": Ageing nameservers for level '"<<auth<<"', next query might succeed"<<endl;
800          if(t_RC->doAgeCache(d_now.tv_sec, auth, QType::NS, 10))
801            g_stats.nsSetInvalidations++;
802        }
803        return -1;
804      }
805      if(qname==*tns && qtype.getCode()==QType::A) {
806        LOG<<prefix<<qname<<": Not using NS to resolve itself!"<<endl;
807        continue;
808      }
809
810      typedef vector<ComboAddress> remoteIPs_t;
811      remoteIPs_t remoteIPs;
812      remoteIPs_t::const_iterator remoteIP;
813      bool doTCP=false;
814      int resolveret;
815      bool pierceDontQuery=false;
816      bool sendRDQuery=false;
817      LWResult lwr;
818      if(tns->empty()) {
819        LOG<<prefix<<qname<<": Domain is out-of-band"<<endl;
820        doOOBResolve(qname, qtype, lwr.d_result, depth, lwr.d_rcode);
821        lwr.d_tcbit=false;
822        lwr.d_aabit=true;
823      }
824      else {
825        LOG<<prefix<<qname<<": Trying to resolve NS '"<<*tns<<"' ("<<1+tns-rnameservers.begin()<<"/"<<(unsigned int)rnameservers.size()<<")"<<endl;
826
827        if(!isCanonical(*tns)) {
828          LOG<<prefix<<qname<<": Domain has hardcoded nameserver(s)"<<endl;
829
830          string txtAddr = *tns;
831          if(!tns->empty()) {
832            sendRDQuery = txtAddr[0] == '+';
833            txtAddr=txtAddr.c_str()+1;
834          }
835          ComboAddress addr=parseIPAndPort(txtAddr, 53);
836         
837          remoteIPs.push_back(addr);
838          pierceDontQuery=true;
839        }
840        else {
841          remoteIPs=getAs(*tns, depth+1, beenthere);
842          pierceDontQuery=false;
843        }
844
845        if(remoteIPs.empty()) {
846          LOG<<prefix<<qname<<": Failed to get IP for NS "<<*tns<<", trying next if available"<<endl;
847          flawedNSSet=true;
848          continue;
849        }
850        else {
851          LOG<<prefix<<qname<<": Resolved '"+auth+"' NS "<<*tns<<" to: ";
852          for(remoteIP = remoteIPs.begin(); remoteIP != remoteIPs.end(); ++remoteIP) {
853            if(remoteIP != remoteIPs.begin())
854              LOG<<", ";
855            LOG<<remoteIP->toString();
856          }
857          LOG<<endl;
858
859        }
860
861        for(remoteIP = remoteIPs.begin(); remoteIP != remoteIPs.end(); ++remoteIP) {
862          LOG<<prefix<<qname<<": Trying IP "<< remoteIP->toStringWithPort() <<", asking '"<<qname<<"|"<<qtype.getName()<<"'"<<endl;
863          extern NetmaskGroup* g_dontQuery;
864         
865          if(t_sstorage->throttle.shouldThrottle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()))) {
866            LOG<<prefix<<qname<<": query throttled "<<endl;
867            s_throttledqueries++; d_throttledqueries++;
868            continue;
869          } 
870          else if(!pierceDontQuery && g_dontQuery && g_dontQuery->match(&*remoteIP)) {
871            LOG<<prefix<<qname<<": not sending query to " << remoteIP->toString() << ", blocked by 'dont-query' setting" << endl;
872            s_dontqueries++;
873            continue;
874          }
875          else {
876            s_outqueries++; d_outqueries++;
877          TryTCP:
878            if(doTCP) {
879              LOG<<prefix<<qname<<": using TCP with "<< remoteIP->toStringWithPort() <<endl;
880              s_tcpoutqueries++; d_tcpoutqueries++;
881            }
882           
883            resolveret=asyncresolveWrapper(*remoteIP, qname, 
884                                    (qtype.getCode() == QType::ADDR ? QType::ANY : qtype.getCode()), 
885                                           doTCP, sendRDQuery, &d_now, &lwr);    // <- we go out on the wire!
886            if(resolveret != 1) {
887              if(resolveret==0) {
888                LOG<<prefix<<qname<<": timeout resolving "<< (doTCP ? "over TCP" : "")<<endl;
889                d_timeouts++;
890                s_outgoingtimeouts++;
891              }
892              else if(resolveret==-2) {
893                LOG<<prefix<<qname<<": hit a local resource limit resolving"<< (doTCP ? " over TCP" : "")<<", probable error: "<<stringerror()<<endl;
894                g_stats.resourceLimits++;
895              }
896              else {
897                s_unreachables++; d_unreachables++;
898                LOG<<prefix<<qname<<": error resolving"<< (doTCP ? " over TCP" : "") <<", possible error: "<<strerror(errno)<< endl;
899              }
900             
901              if(resolveret!=-2) { // don't account for resource limits, they are our own fault
902                {
903                 
904                  t_sstorage->nsSpeeds[*tns].submit(*remoteIP, 1000000, &d_now); // 1 sec
905                }
906                if(resolveret==-1)
907                  t_sstorage->throttle.throttle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100); // unreachable, 1 minute or 100 queries
908                else
909                  t_sstorage->throttle.throttle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()), 10, 5);  // timeout
910              }
911              continue;
912            }
913           
914            break;  // this IP address worked!
915          wasLame:; // well, it didn't
916            LOG<<prefix<<qname<<": status=NS "<<*tns<<" ("<< remoteIP->toString() <<") is lame for '"<<auth<<"', trying sibling IP or NS"<<endl;
917            t_sstorage->throttle.throttle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100); // lame
918          }
919        }
920       
921        if(remoteIP == remoteIPs.end())  // we tried all IP addresses, none worked
922          continue; 
923       
924        if(lwr.d_tcbit) {
925          if(!doTCP) {
926            doTCP=true;
927            LOG<<prefix<<qname<<": truncated bit set, retrying via TCP"<<endl;
928            goto TryTCP;
929          }
930          LOG<<prefix<<qname<<": truncated bit set, over TCP?"<<endl;
931          return RCode::ServFail;
932        }
933       
934        if(lwr.d_rcode==RCode::ServFail) {
935          LOG<<prefix<<qname<<": "<<*tns<<" returned a ServFail, trying sibling IP or NS"<<endl;
936          t_sstorage->throttle.throttle(d_now.tv_sec,make_tuple(*remoteIP, qname, qtype.getCode()),60,3); // servfail
937          continue;
938        }
939        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;
940
941        /*  // for you IPv6 fanatics :-)
942        if(remoteIP->sin4.sin_family==AF_INET6)
943          lwr.d_usec/=3;
944        */
945        //      cout<<"msec: "<<lwr.d_usec/1000.0<<", "<<g_avgLatency/1000.0<<'\n';
946        double fract = 0.001;
947        g_avgLatency = (1-fract) * g_avgLatency + fract * lwr.d_usec;
948
949        t_sstorage->nsSpeeds[*tns].submit(*remoteIP, lwr.d_usec, &d_now);
950      }
951
952      typedef map<pair<string, QType>, set<DNSResourceRecord>, TCacheComp > tcache_t;
953      tcache_t tcache;
954
955      // reap all answers from this packet that are acceptable
956      for(LWResult::res_t::iterator i=lwr.d_result.begin();i != lwr.d_result.end();++i) {
957        if(i->qtype.getCode() == QType::OPT) {
958          LOG<<prefix<<qname<<": skipping OPT answer '"<<i->qname<<"' from '"<<auth<<"' nameservers" <<endl;
959          continue;
960        }
961        LOG<<prefix<<qname<<": accept answer '"<<i->qname<<"|"<<i->qtype.getName()<<"|"<<i->content<<"' from '"<<auth<<"' nameservers? ";
962        if(i->qtype.getCode()==QType::ANY) {
963          LOG<<"NO! - we don't accept 'ANY' data"<<endl;
964          continue;
965        }
966         
967        if(dottedEndsOn(i->qname, auth)) {
968          if(lwr.d_aabit && lwr.d_rcode==RCode::NoError && i->d_place==DNSResourceRecord::ANSWER && ::arg().contains("delegation-only",auth)) {
969            LOG<<"NO! Is from delegation-only zone"<<endl;
970            s_nodelegated++;
971            return RCode::NXDomain;
972          }
973          else {
974            LOG<<"YES!"<<endl;
975
976            i->ttl=min(s_maxcachettl, i->ttl);
977           
978            DNSResourceRecord rr=*i;
979            rr.d_place=DNSResourceRecord::ANSWER;
980
981            rr.ttl += d_now.tv_sec;
982
983            if(rr.qtype.getCode() == QType::NS) // people fiddle with the case
984              rr.content=toLower(rr.content); // this must stay! (the cache can't be case-insensitive on the RHS of records)
985           
986            tcache[make_pair(i->qname,i->qtype)].insert(rr);
987          }
988        }         
989        else
990          LOG<<"NO!"<<endl;
991      }
992   
993      // supplant
994      for(tcache_t::iterator i=tcache.begin();i!=tcache.end();++i) {
995        if(i->second.size() > 1) {  // need to group the ttl to be the minimum of the RRSET (RFC 2181, 5.2)
996          uint32_t lowestTTL=std::numeric_limits<uint32_t>::max();
997          for(tcache_t::value_type::second_type::iterator j=i->second.begin(); j != i->second.end(); ++j)
998            lowestTTL=min(lowestTTL, j->ttl);
999         
1000          for(tcache_t::value_type::second_type::iterator j=i->second.begin(); j != i->second.end(); ++j)
1001            ((tcache_t::value_type::second_type::value_type*)&(*j))->ttl=lowestTTL;
1002        }
1003
1004        t_RC->replace(d_now.tv_sec, i->first.first, i->first.second, i->second, lwr.d_aabit);
1005      }
1006      set<string, CIStringCompare> nsset; 
1007      LOG<<prefix<<qname<<": determining status after receiving this packet"<<endl;
1008
1009      bool done=false, realreferral=false, negindic=false;
1010      string newauth, soaname, newtarget;
1011
1012      for(LWResult::res_t::iterator i=lwr.d_result.begin();i!=lwr.d_result.end();++i) {
1013        if(i->d_place==DNSResourceRecord::AUTHORITY && dottedEndsOn(qname,i->qname) && i->qtype.getCode()==QType::SOA && 
1014           lwr.d_rcode==RCode::NXDomain) {
1015          LOG<<prefix<<qname<<": got negative caching indication for RECORD '"<<qname+"'"<<endl;
1016          i->ttl = min(i->ttl, s_maxnegttl);
1017          ret.push_back(*i);
1018
1019          NegCacheEntry ne;
1020
1021          ne.d_qname=i->qname;
1022         
1023          ne.d_ttd=d_now.tv_sec + i->ttl;
1024         
1025          ne.d_name=qname;
1026          ne.d_qtype=QType(0); // this encodes 'whole record'
1027         
1028          replacing_insert(t_sstorage->negcache, ne);
1029         
1030          negindic=true;
1031        }
1032        else if(i->d_place==DNSResourceRecord::ANSWER && pdns_iequals(i->qname, qname) && i->qtype.getCode()==QType::CNAME && (!(qtype==QType(QType::CNAME)))) {
1033          ret.push_back(*i);
1034          newtarget=i->content;
1035        }
1036        // for ANY answers we *must* have an authoritive answer
1037        else if(i->d_place==DNSResourceRecord::ANSWER && pdns_iequals(i->qname, qname) && 
1038                (
1039                 i->qtype==qtype || (lwr.d_aabit && (qtype==QType(QType::ANY) || magicAddrMatch(qtype, i->qtype) ) )
1040                ) 
1041               )   
1042          {
1043         
1044          LOG<<prefix<<qname<<": answer is in: resolved to '"<< i->content<<"|"<<i->qtype.getName()<<"'"<<endl;
1045
1046          done=true;
1047          ret.push_back(*i);
1048        }
1049        else if(i->d_place==DNSResourceRecord::AUTHORITY && dottedEndsOn(qname,i->qname) && i->qtype.getCode()==QType::NS) { 
1050          if(moreSpecificThan(i->qname,auth)) {
1051            newauth=i->qname;
1052            LOG<<prefix<<qname<<": got NS record '"<<i->qname<<"' -> '"<<i->content<<"'"<<endl;
1053            realreferral=true;
1054          }
1055          else 
1056            LOG<<prefix<<qname<<": got upwards/level NS record '"<<i->qname<<"' -> '"<<i->content<<"', had '"<<auth<<"'"<<endl;
1057          nsset.insert(i->content);
1058        }
1059        else if(!done && i->d_place==DNSResourceRecord::AUTHORITY && dottedEndsOn(qname,i->qname) && i->qtype.getCode()==QType::SOA && 
1060           lwr.d_rcode==RCode::NoError) {
1061          LOG<<prefix<<qname<<": got negative caching indication for '"<< (qname+"|"+i->qtype.getName()+"'") <<endl;
1062         
1063          if(!newtarget.empty()) {
1064            LOG<<prefix<<qname<<": Hang on! Got a redirect to '"<<newtarget<<"' already"<<endl;
1065          }
1066          else {
1067            i-> ttl = min(s_maxnegttl, i->ttl);
1068            ret.push_back(*i);
1069            NegCacheEntry ne;
1070            ne.d_qname=i->qname;
1071            ne.d_ttd=d_now.tv_sec + i->ttl;
1072            ne.d_name=qname;
1073            ne.d_qtype=qtype;
1074            if(qtype.getCode()) {  // prevents us from blacking out a whole domain
1075              replacing_insert(t_sstorage->negcache, ne);
1076            }
1077            negindic=true;
1078          }
1079        }
1080      }
1081
1082      if(done){ 
1083        LOG<<prefix<<qname<<": status=got results, this level of recursion done"<<endl;
1084        return 0;
1085      }
1086      if(!newtarget.empty()) {
1087        if(pdns_iequals(newtarget,qname)) {
1088          LOG<<prefix<<qname<<": status=got a CNAME referral to self, returning SERVFAIL"<<endl;
1089          return RCode::ServFail;
1090        }
1091        if(depth > 10) {
1092          LOG<<prefix<<qname<<": status=got a CNAME referral, but recursing too deep, returning SERVFAIL"<<endl;
1093          return RCode::ServFail;
1094        }
1095        LOG<<prefix<<qname<<": status=got a CNAME referral, starting over with "<<newtarget<<endl;
1096
1097        set<GetBestNSAnswer> beenthere2;
1098        return doResolve(newtarget, qtype, ret, depth + 1, beenthere2);
1099      }
1100      if(lwr.d_rcode==RCode::NXDomain) {
1101        LOG<<prefix<<qname<<": status=NXDOMAIN, we are done "<<(negindic ? "(have negative SOA)" : "")<<endl;
1102        return RCode::NXDomain;
1103      }
1104      if(nsset.empty() && !lwr.d_rcode) {
1105        LOG<<prefix<<qname<<": status=noerror, other types may exist, but we are done "<<(negindic ? "(have negative SOA)" : "")<<endl;
1106        return 0;
1107      }
1108      else if(realreferral) {
1109        LOG<<prefix<<qname<<": status=did not resolve, got "<<(unsigned int)nsset.size()<<" NS, looping to them"<<endl;
1110        auth=newauth;
1111        nameservers=nsset;
1112        break; 
1113      }
1114      else if(isCanonical(*tns)) {
1115        goto wasLame;
1116      }
1117    }
1118  }
1119  return -1;
1120}
1121
1122static bool uniqueComp(const DNSResourceRecord& a, const DNSResourceRecord& b)
1123{
1124  return(a.qtype==b.qtype && a.qname==b.qname && a.content==b.content);
1125}
1126
1127void SyncRes::addCruft(const string &qname, vector<DNSResourceRecord>& ret)
1128{
1129  for(vector<DNSResourceRecord>::const_iterator k=ret.begin();k!=ret.end();++k)  // don't add stuff to an NXDOMAIN!
1130    if(k->d_place==DNSResourceRecord::AUTHORITY && k->qtype==QType(QType::SOA))
1131      return;
1132
1133  //  LOG<<qname<<": Adding best authority records from cache"<<endl;
1134  // addAuthorityRecords(qname,ret,0);
1135  // LOG<<qname<<": Done adding best authority records."<<endl;
1136
1137  LOG<<d_prefix<<qname<<": Starting additional processing"<<endl;
1138  vector<DNSResourceRecord> addit;
1139  static optional<bool> l_doIPv6AP;
1140  if(!l_doIPv6AP)
1141    l_doIPv6AP=::arg().mustDo("aaaa-additional-processing");
1142
1143  for(vector<DNSResourceRecord>::const_iterator k=ret.begin();k!=ret.end();++k) 
1144    if( (k->d_place==DNSResourceRecord::ANSWER && (k->qtype==QType(QType::MX) || k->qtype==QType(QType::SRV)))  || 
1145       ((k->d_place==DNSResourceRecord::AUTHORITY || k->d_place==DNSResourceRecord::ANSWER) && k->qtype==QType(QType::NS))) {
1146      LOG<<d_prefix<<qname<<": record '"<<k->content<<"|"<<k->qtype.getName()<<"' needs IP for additional processing"<<endl;
1147      set<GetBestNSAnswer> beenthere;
1148      vector<pair<string::size_type, string::size_type> > fields;
1149      vstringtok(fields, k->content, " ");
1150      string host;
1151      if(k->qtype==QType(QType::MX) && fields.size()==2)
1152        host=string(k->content.c_str() + fields[1].first, fields[1].second - fields[1].first);
1153      else if(k->qtype==QType(QType::NS))
1154        host=k->content;
1155      else if(k->qtype==QType(QType::SRV) && fields.size()==4)
1156        host=string(k->content.c_str() + fields[3].first, fields[3].second - fields[3].first);
1157      else 
1158        continue;
1159      doResolve(host, *l_doIPv6AP ? QType(QType::ADDR) : QType(QType::A), addit, 1, beenthere);
1160    }
1161 
1162  if(!addit.empty()) {
1163    sort(addit.begin(), addit.end());
1164    addit.erase(unique(addit.begin(), addit.end(), uniqueComp), addit.end());
1165    for(vector<DNSResourceRecord>::iterator k=addit.begin();k!=addit.end();++k) {
1166      if(k->qtype.getCode()==QType::A || k->qtype.getCode()==QType::AAAA) {
1167        k->d_place=DNSResourceRecord::ADDITIONAL;
1168        ret.push_back(*k);
1169      }
1170    }
1171  }
1172  LOG<<d_prefix<<qname<<": Done with additional processing"<<endl;
1173}
1174
1175void SyncRes::addAuthorityRecords(const string& qname, vector<DNSResourceRecord>& ret, int depth)
1176{
1177  set<DNSResourceRecord> bestns;
1178  set<GetBestNSAnswer> beenthere;
1179  bool dontcare;
1180  getBestNSFromCache(qname, bestns, &dontcare, depth, beenthere);
1181
1182  for(set<DNSResourceRecord>::const_iterator k=bestns.begin();k!=bestns.end();++k) {
1183    DNSResourceRecord ns=*k;
1184    ns.d_place=DNSResourceRecord::AUTHORITY;
1185    ns.ttl-=d_now.tv_sec;
1186    ret.push_back(ns);
1187  }
1188}
Note: See TracBrowser for help on using the browser.