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

Revision 1628, 42.4 KB (checked in by ahu, 3 years ago)

fix up SOA misunderstanding around CNAME referrals from UltraDNS. Thanks to 'marwood' for reporting this.

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