]> granicus.if.org Git - pdns/commitdiff
recursorrr
authorBert Hubert <bert.hubert@netherlabs.nl>
Sun, 5 Jan 2003 22:09:24 +0000 (22:09 +0000)
committerBert Hubert <bert.hubert@netherlabs.nl>
Sun, 5 Jan 2003 22:09:24 +0000 (22:09 +0000)
git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@117 d19b8d6e-7fed-0310-83ef-9ca221ded41b

pdns/communicator.cc
pdns/docs/pdns.sgml
pdns/dynhandler.cc
pdns/recns.cc
pdns/syncres.cc

index 518fa8643ed512525e20338425152f2e2c3b0509..4ee1caf70c0fe5b1ef5d33eb26a51dd2cd79fea6 100644 (file)
@@ -258,7 +258,7 @@ void CommunicatorClass::slaveRefresh(PacketHandler *P)
       }
     }
     catch(ResolverException &re) {
-      L<<Logger::Error<<"Trying to retrieve/refresh '"+i->zone+"': "+re.reason<<endl;
+      L<<Logger::Error<<"Error trying to retrieve/refresh '"+i->zone+"': "+re.reason<<endl;
     }
   }
 }  
index 07d67aa901a9de34fec8b1367a941ba943fb1e27..4c5d8dbf611be3abc1eeea00fa277a3089915309 100644 (file)
@@ -1,9 +1,6 @@
 <!DOCTYPE Book PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
-
 <Book>
-  
   <BookInfo>
-    
     <Title>PowerDNS manual</Title>
     <AUTHOR>
       <affiliation>
         <address>
           <email>pdns@powerdns.com</email>
         </address>
-       
       </affiliation>
     </author>
     
-    <PubDate>v2.1 $Date: 2003/01/03 18:00:12 $</PubDate>
+    <PubDate>v2.1 $Date: 2003/01/05 22:09:24 $</PubDate>
     
     <Abstract>
        <para>  
@@ -3793,13 +3789,10 @@ local0.err                        /var/log/pdns.err
              Can only answer queries for types and classes it knows about - it is not transparent as it should be.
            </para></listitem>
          <listitem><para>
-             Has a broken algorithm.
-           </para></listitem>
-         <listitem><para>
-             Can get into a loop when resolving.
+             Does not expire entries from its cache
            </para></listitem>
          <listitem><para>
-             Does not cache enough due to blatantly paranoid 'trust-rules', or more exactly 'no-trust' rules.
+             Fakes the TTL of NS records in the additional section
            </para></listitem>
          <listitem><para>
              Only compiles on Linux and possibly Solaris. FreeBSD decided not to support the POSIX get/set/swapcontext functions.
index cafa51ae8b099f1f214c8dfd540546dcd53417b8..71f1e11ff200a4c33289ef5923be3964d4a48502 100644 (file)
@@ -173,10 +173,8 @@ string DLSettingsHandler(const vector<string>&parts, Utility::pid_t ppid)
 
 }
 
-
 string DLVersionHandler(const vector<string>&parts, Utility::pid_t ppid)
 {
-
   return VERSION;
 }
 
index 7e35a5d9acd13c597b00753d3a15d5e008d971d9..a25a25587fbc1f50469ecb41ef9a23c8c246ee50 100644 (file)
@@ -99,28 +99,26 @@ int arecvfrom(char *data, int len, int flags, struct sockaddr *toaddr, socklen_t
 
 
 extern void init(void);
-string doResolve(const string &qname, int depth=0);
-string doResolve(vector<string> nameservers, const string &qname, int depth=0);
 
+bool beginResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret);
 
 void startDoResolve(void *p)
 {
   try {
-    cout<<"Passed: "<<p<<endl;
     DNSPacket P=*(DNSPacket *)p;
     delete (DNSPacket *)p;
     
-    string ip=doResolve(P.qdomain);
-    cout<<"done: "<<ip<<endl;
+    vector<DNSResourceRecord>ret;
     DNSPacket *R=P.replyPacket();
-    DNSResourceRecord rr;
-    rr.qname=P.qdomain;
-    rr.qtype=QType::A;
-    rr.content=ip;
-    rr.ttl=3600;
-    R->addRecord(rr);
+    if(!beginResolve(P.qdomain, P.qtype, ret))
+      R->setRcode(RCode::ServFail);
+    else
+      for(vector<DNSResourceRecord>::const_iterator i=ret.begin();i!=ret.end();++i)
+       R->addRecord(*i);
+
     const char *buffer=R->getData();
     sendto(d_sock,buffer,R->len,0,(struct sockaddr *)(R->remote),R->d_socklen);
+    delete R;
   }
   catch(AhuException &ae) {
     cerr<<"startDoResolve timeout: "<<ae.reason<<endl;
@@ -201,7 +199,7 @@ int main(int argc, char **argv)
        MT.sendEvent(pident,packet);
       }
       else {
-       cout<<"new question for '"<<P.qdomain<<"'"<<endl;
+       cout<<"new question arrived for '"<<P.qdomain<<"|"<<P.qtype.getName()<<"'"<<endl;
        MT.makeThread(startDoResolve,(void*)new DNSPacket(P));
       }
     }
index 9b69b36ce7ed60a4e69f0c32728b998aefd7d458..f777887c5f6a7bfc0bd434cf7f7c6da2368daefb 100644 (file)
@@ -19,6 +19,7 @@
 #include <iostream>
 #include <map>
 #include <algorithm>
+#include <set>
 
 #include <cerrno>
 #include <cstdio>
 #include "arguments.hh"
 #include "lwres.hh"
 
-typedef pair<vector<string>,vector<DNSResourceRecord> > CacheVal;
-typedef multimap<string,CacheVal> cache_t;
+typedef map<string, set<string> > nscache_t;
+nscache_t nscache;
+
+typedef map<string,vector<DNSResourceRecord> > cache_t;
 cache_t cache;
 
 vector<string>rootservers;
-map<string,string> hints;
 
-string doResolve(vector<string> nameservers, const string &qname, int depth=0);
 
-string doResolve(const string &qname, int depth=0)
+bool doResolve(set<string> nameservers, string auth, const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret,int depth=0);
+bool doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth=0);
+
+string getA(const string &qname, int depth=0)
+{
+  vector<DNSResourceRecord> res;
+  string ret;
+
+  if(doResolve(qname,QType(QType::A), res,depth+1)) 
+    ret=res[0].content;
+
+  return ret;
+}
+
+void getBestNSFromCache(const string &qname, vector<DNSResourceRecord>&ret, int depth=0)
 {
-  if(hints.find(toLower(qname))!=hints.end()) {
-    string prefix;
-    prefix.assign(3*depth, ' ');
+  string prefix;
+  prefix.assign(3*depth, ' ');
 
-    cerr<<prefix<<qname<<": resolved via hint cache to "<<hints[toLower(qname)]<<endl;
-    return hints[toLower(qname)];
+  vector<string>parts;
+  stringtok(parts,qname,".");  // www.us.powerdns.com -> 'www' 'us' 'powerdns' 'com'
+  
+  unsigned int spos=0;
+  string subdomain;
+
+  while(spos<=parts.size()) {
+    if(spos<parts.size()) { // www.us.powerdns.com -> us.powerdns.com -> powerdns.com -> com ->
+      subdomain=parts[spos++];
+      for(unsigned int i=spos;i<parts.size();++i) {
+       subdomain+=".";
+       subdomain+=parts[i];
+      }
+    }
+    else {
+      subdomain=""; // ROOT!
+      spos++;
+    }
+    cout<<prefix<<qname<<": Checking if we have NS for '"<<subdomain<<"'"<<endl;
+    nscache_t::const_iterator j=nscache.find(toLower(subdomain));
+    if(j!=nscache.end() && j->first==toLower(subdomain)) {
+      cout<<prefix<<qname<<": Adding authority records for '"<<subdomain<<"'"<<endl;
+      for(set<string>::const_iterator k=j->second.begin();k!=j->second.end();++k) {
+       DNSResourceRecord rr;
+       rr.qname=subdomain;
+       rr.content=*k;
+       rr.ttl=1234;
+       rr.qtype=QType(QType::NS);
+       rr.d_place=DNSResourceRecord::AUTHORITY;
+       ret.push_back(rr);
+      }
+      return;
+    }
   }
+}
+
+
+
+void addCruft(const string &qname, vector<DNSResourceRecord>& ret)
+{
+  getBestNSFromCache(qname,ret);
+  
+  cout<<qname<<": Additional processing"<<endl;
+  vector<DNSResourceRecord> addit;
+  for(vector<DNSResourceRecord>::const_iterator k=ret.begin();k!=ret.end();++k) 
+    if((k->d_place==DNSResourceRecord::ANSWER && k->qtype==QType(QType::MX)) || 
+       (k->d_place==DNSResourceRecord::AUTHORITY && k->qtype==QType(QType::NS))) {
+      cout<<qname<<": record '"<<k->content<<"|"<<k->qtype.getCode()<<"' needs an IP address"<<endl;
+      doResolve(k->content,QType(QType::A),addit,1);
+    }
+
   
-  return doResolve(rootservers, qname,depth);
+  for(vector<DNSResourceRecord>::iterator k=addit.begin();k!=addit.end();++k) {
+    k->d_place=DNSResourceRecord::ADDITIONAL;
+    ret.push_back(*k);
+  }
+}
+
+bool beginResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret)
+{
+  bool res=doResolve(qname, qtype, ret,0);
+  if(res)
+    addCruft(qname, ret);
+  return res;
 }
 
-string doResolve(vector<string> nameservers, const string &qname, int depth)
+
+bool doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth)
+{
+  string prefix;
+  prefix.assign(3*depth, ' ');
+  
+  // see if we have a CNAME hit
+  string tuple=toLower(qname)+"|CNAME";
+  cout<<prefix<<"Looking for CNAME cache hit of '"<<tuple<<"'"<<endl;
+
+  cache_t::const_iterator i=cache.find(tuple);
+  if(i!=cache.end() && i->first==tuple) { // found it
+    cout<<prefix<<"Found cache CNAME hit for '"<<tuple<<"' to '"<<i->second.begin()->content<<"'"<<endl;    
+    for(vector<DNSResourceRecord>::const_iterator j=i->second.begin();j!=i->second.end();++j)
+      ret.push_back(*j);
+    return doResolve(i->second.begin()->content, qtype, ret, depth);
+  }
+
+  tuple=toLower(qname)+"|"+qtype.getName();
+  cout<<prefix<<"Looking for direct cache hit of '"<<tuple<<"'"<<endl;
+
+  i=cache.find(tuple);
+  if(i!=cache.end() && i->first==tuple) { // found it
+    cout<<prefix<<"Found cache hit for '"<<tuple<<"': ";
+    for(vector<DNSResourceRecord>::const_iterator j=i->second.begin();j!=i->second.end();++j) {
+      cout<<j->content<<" ";
+      ret.push_back(*j);
+    }
+    cout<<endl;
+    return true;
+  }
+
+  
+  cout<<prefix<<"No cache hit for '"<<tuple<<"', trying to find an appropriate NS record"<<endl;
+  // bummer, get the best NS record then
+
+  vector<string>parts;
+  stringtok(parts,qname,".");  // www.us.powerdns.com -> 'www' 'us' 'powerdns' 'com'
+  
+  unsigned int spos=0;
+  string subdomain;
+
+  while(spos<=parts.size()) {
+    if(spos<parts.size()) { // www.us.powerdns.com -> us.powerdns.com -> powerdns.com -> com ->
+      subdomain=parts[spos++];
+      for(unsigned int i=spos;i<parts.size();++i) {
+       subdomain+=".";
+       subdomain+=parts[i];
+      }
+    }
+    else {
+      subdomain=""; // ROOT!
+      spos++;
+    }
+    cout<<prefix<<qname<<": Checking if we have NS for '"<<subdomain<<"'"<<endl;
+    nscache_t::const_iterator j=nscache.find(toLower(subdomain));
+    if(j!=nscache.end() && j->first==toLower(subdomain)) {
+      cout<<prefix<<"Found NS for '"<<subdomain<<"', heading there for further questions"<<endl;
+      bool hasResults=doResolve(j->second,subdomain,qname,qtype,ret,depth);
+      if(!hasResults)
+       continue; // perhaps less specific nameservers can help us
+
+      return true;
+    }
+  }
+  return false;
+}
+
+bool endsOn(const string &domain, const string &suffix) 
+{
+  if(domain==suffix || suffix.empty())
+    return true;
+  if(domain.size()<suffix.size())
+    return false;
+  return (domain.substr(domain.size()-suffix.size()-1,suffix.size()+1)=="."+suffix);
+}
+
+bool doResolve(set<string> nameservers, string auth, const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth)
 {
   string prefix;
   prefix.assign(3*depth, ' ');
@@ -59,89 +209,96 @@ string doResolve(vector<string> nameservers, const string &qname, int depth)
   LWRes r;
   LWRes::res_t result;
   vector<DNSResourceRecord>usefulrrs;
-  vector<string> nsset;  
-  cerr<<prefix<<qname<<": start of recursion!"<<endl;
+  set<string> nsset;  
+  cout<<prefix<<qname<<": start of recursion!"<<endl;
 
-  for(;;) {
+
+  for(;;) { // we may get more specific nameservers
     result.clear();
 
-    for(cache_t::const_iterator i=cache.find(qname);i!=cache.end() && i->first==qname;++i) {
-      cerr<<prefix<<qname<<": potential cache hit!"<<endl;
+    vector<string>rnameservers;
+    for(set<string>::const_iterator i=nameservers.begin();i!=nameservers.end();++i)
+      rnameservers.push_back(*i);
 
-      sort(nameservers.begin(),nameservers.end());
-      if(nameservers==i->second.first) {
-       cerr<<prefix<<qname<<": REAL cache hit, "<<i->second.second.size()<<" records"<<endl;
-       result=i->second.second;
+    random_shuffle(rnameservers.begin(),rnameservers.end());
+    for(vector<string>::const_iterator i=rnameservers.begin();;++i){ 
+      if(i==rnameservers.end()) {
+       cout<<prefix<<qname<<": failed to resolve via any of the "<<rnameservers.size()<<" offered nameservers"<<endl;
+       return false;
+      }
+      cout<<prefix<<qname<<": trying to resolve nameserver "<<*i<<endl;
+      string remoteIP=getA(*i, depth+1);
+      if(remoteIP.empty()) {
+       cout<<prefix<<qname<<": failed to resolve nameserver "<<*i<<", trying next if available"<<endl;
+       continue;
+      }
+      cout<<prefix<<qname<<": resolved nameserver "<<*i<<" to "<<remoteIP<<endl;
 
+      if(r.asyncresolve(remoteIP,qname.c_str(),qtype.getCode())!=1) { // <- shouldn't this be internal?
+       cout<<prefix<<qname<<": error resolving"<<endl;
+      }
+      else {
+       result=r.result();
+       
+       cout<<prefix<<qname<<": got "<<result.size()<<" answers from "<<*i<<" ("<<remoteIP<<")"<<endl;
        break;
       }
     }
-    if(result.empty()) {
 
-      cerr<<prefix<<qname<<": no cache hit"<<endl;
-  
-      random_shuffle(nameservers.begin(),nameservers.end());
-      for(vector<string>::const_iterator i=nameservers.begin();;++i){ 
-       if(i==nameservers.end()) {
-         cerr<<prefix<<qname<<": failed to resolve via any of the "<<nameservers.size()<<" offered nameservers"<<endl;
-         return "";
-       }
-       cerr<<prefix<<qname<<": trying to resolve nameserver "<<*i<<endl;
-       string remoteIP=doResolve(*i,depth+1);
-       if(remoteIP.empty()) {
-         cerr<<prefix<<qname<<": failed to resolve nameserver "<<*i<<", trying next if available"<<endl;
-         continue;
-       }
-       cerr<<prefix<<qname<<": resolved nameserver "<<*i<<" to "<<remoteIP<<endl;
-
-       if(r.asyncresolve(remoteIP,qname.c_str(),QType::A)!=1) {
-         cerr<<prefix<<qname<<": error resolving"<<endl;
-       }
-       else {
-         result=r.result();
-         
-         cerr<<prefix<<qname<<": got "<<result.size()<<" answers from "<<*i<<" ("<<remoteIP<<")"<<endl;
-         break;
-       }
-      }
-      usefulrrs.clear();
-      for(LWRes::res_t::const_iterator i=result.begin();i!=result.end();++i) 
-       if(i->d_place==DNSResourceRecord::ANSWER || (i->d_place==DNSResourceRecord::AUTHORITY && i->qtype.getCode()==QType::NS))
-         usefulrrs.push_back(*i);
-      
-      if(!usefulrrs.empty()) {
-       CacheVal cv;
-       sort(nameservers.begin(),nameservers.end());
-       cv.first=nameservers;
-       cv.second=usefulrrs;
-       cache.insert(make_pair(qname,cv));
+
+    cache_t tcache;
+    // reap all answers from this packet that are acceptable
+    for(LWRes::res_t::const_iterator i=result.begin();i!=result.end();++i) {
+      cout<<prefix<<qname<<": accept answer '"<<i->qname<<"|"<<i->qtype.getName()<<"|"<<i->content<<"' from '"<<auth<<"' nameservers? ";
+      if(endsOn(i->qname, auth)) {
+       cout<<"YES!"<<endl;
+
+       if(i->qtype.getCode()==QType::NS)
+         nscache[toLower(i->qname)].insert(toLower(i->content));
+       DNSResourceRecord rr=*i;
+       rr.d_place=DNSResourceRecord::ANSWER;
+       tcache[toLower(i->qname)+"|"+i->qtype.getName()].push_back(rr);
       }
-    }
+      else
+       cout<<"NO!"<<endl;
 
+    }
+  
+    for(cache_t::const_iterator i=tcache.begin();i!=tcache.end();++i)
+      cache[i->first]=i->second;
+    
     nsset.clear();
+
     for(LWRes::res_t::const_iterator i=result.begin();i!=result.end();++i) {
-      //    cerr<<prefix<<(int)i->d_place<<" "<<i->qname<<" "<<i->qtype.getName()<<" "<<i->content<<endl;
+      
       if(i->d_place==DNSResourceRecord::ANSWER && i->qname==qname && i->qtype.getCode()==QType::CNAME) {
-       cerr<<prefix<<qname<<": got a CNAME referral, starting over with "<<i->content<<endl<<endl;
-       return doResolve(i->content, 0);
+       cout<<prefix<<qname<<": got a CNAME referral, starting over with "<<i->content<<endl<<endl;
+       ret.push_back(*i);
+       return doResolve(i->content, qtype, ret,0);
       }
-      if(i->d_place==DNSResourceRecord::ANSWER && i->qname==qname && i->qtype.getCode()==QType::A) {
-       cerr<<prefix<<qname<<": resolved to "<<i->content<<endl;
-       return i->content;
+      if(i->d_place==DNSResourceRecord::ANSWER && i->qname==qname && i->qtype==qtype) {
+       cout<<prefix<<qname<<": resolved to "<<i->content<<endl;
+       ret.push_back(*i);
       }
-      if(i->d_place==DNSResourceRecord::AUTHORITY && i->qtype.getCode()==QType::NS) {
-       cerr<<prefix<<qname<<": got NS record "<<i->content<<endl;
-       nsset.push_back(i->content);
+      if(i->d_place==DNSResourceRecord::AUTHORITY && i->qtype.getCode()==QType::NS) { // XXX FIXME check if suffix!
+       auth=i->qname;
+       cout<<prefix<<qname<<": got NS record "<<i->content<<endl;
+       nsset.insert(toLower(i->content));
       }
     }
+    if(!ret.empty()){ 
+      cout<<prefix<<qname<<": got results, returning"<<endl;
+      return true;
+    }
     if(nsset.empty()) {
-      cerr<<prefix<<qname<<": did not resolve "<<qname<<", did not get referral"<<endl;
-      return "";
+      cout<<prefix<<qname<<": did not resolve "<<qname<<", did not get referral"<<endl;
+      return false;
     }
-
-    cerr<<prefix<<qname<<": did not resolve "<<qname<<", did get "<<nsset.size()<<" nameservers, looping to them"<<endl;
+    
+    cout<<prefix<<qname<<": did not resolve "<<qname<<", did get "<<nsset.size()<<" nameservers, looping to them"<<endl;
     nameservers=nsset;
   }
+  return false;
 }
 
 void init(void)
@@ -150,12 +307,16 @@ void init(void)
   static char*ips[]={"198.41.0.4", "128.9.0.107", "192.33.4.12", "128.8.10.90", "192.203.230.10",
                     "192.5.5.241", "192.112.36.4", "128.63.2.53", "192.36.148.17",
                     "198.41.0.10", "193.0.14.129", "198.32.64.12", "202.12.27.33"};
-
+  DNSResourceRecord rr;
+  rr.qtype=QType::A;
+  rr.ttl=86400;
   for(char c='a';c<='m';++c) {
     static char templ[40];
     strncpy(templ,"a.root-servers.net", sizeof(templ) - 1);
     *templ=c;
-    rootservers.push_back(templ);
-    hints[templ]=ips[c-'a'];
+    nscache[""].insert(string(templ));
+    rr.qname=templ;
+    rr.content=ips[c-'a'];
+    cache[string(templ)+"|A"].push_back(rr);
   }
 }