]> granicus.if.org Git - pdns/commitdiff
heaps
authorBert Hubert <bert.hubert@netherlabs.nl>
Wed, 8 Jan 2003 13:45:30 +0000 (13:45 +0000)
committerBert Hubert <bert.hubert@netherlabs.nl>
Wed, 8 Jan 2003 13:45:30 +0000 (13:45 +0000)
git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@121 d19b8d6e-7fed-0310-83ef-9ca221ded41b

pdns/dns.hh
pdns/docs/pdns.sgml
pdns/docs/pdns_server.8
pdns/misc.cc
pdns/misc.hh
pdns/recns.cc
pdns/syncres.cc

index 132a069cd7b22a9fb24a9098138793802b2bfe76..d6e32f079073532099d4a2c66941419975f2c64b 100644 (file)
     along with this program; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
-// $Id: dns.hh,v 1.1 2002/11/27 15:18:31 ahu Exp $ 
+// $Id: dns.hh,v 1.2 2003/01/08 13:45:30 ahu Exp $ 
 /* (C) 2002 POWERDNS.COM BV */
 #ifndef DNS_HH
 #define DNS_HH
-\r
+
 #include "utility.hh"
 #include "qtype.hh"
 #include <time.h>
@@ -78,6 +78,16 @@ public:
   enum Place {QUESTION=0, ANSWER=1, AUTHORITY=2, ADDITIONAL=3}; //!< Type describing the positioning of a DNSResourceRecord within, say, a DNSPacket
   Place d_place; //!< This specifies where a record goes within the packet
 
+  bool operator<(const DNSResourceRecord &b) const
+  {
+    if(qname<b.qname)
+      return true;
+    if(qname==b.qname)
+      return(content<b.content);
+    return false;
+  }
+
+
 private:
   string escape(const string &str) const;
 };
index 5a2a72336297ca2afb0ea23c843325986218a7f9..9f407cbe08f5ace97984fe0f0d800cff0d50b18c 100644 (file)
@@ -11,7 +11,7 @@
       </affiliation>
     </author>
     
-    <PubDate>v2.1 $Date: 2003/01/07 23:31:28 $</PubDate>
+    <PubDate>v2.1 $Date: 2003/01/08 13:45:30 $</PubDate>
     
     <Abstract>
        <para>  
@@ -3551,10 +3551,10 @@ local0.err                        /var/log/pdns.err
            </para>
          </listitem></varlistentry>
        <varlistentry>
-         <term>PDNS does not operate as a 'slave' server with all backends</term>
+         <term>PDNS does not operate as a 'slave' or 'master' server with all backends</term>
          <listitem>
            <para>
-             Only the PostgreSQL backend has, of version 1.99.9, the ability to act as a slave.
+             Only the Generic PostgreSQL, Generic MySQL and BIND backends have the ability to act as master or slave.
            </para>
          </listitem>
        </varlistentry>
index 3e6395d433a1f959a4aa27077c9d57819c0663e1..4f63340689ef169c3f006ffe12e80fd682791e69 100644 (file)
@@ -9,7 +9,7 @@ pdns_control \- The PowerDNS nameserver
 .TP
 .B \-\-daemon=\fIyes|no\fR
 Indicate if the server should run in the background as a real daemon,
-or in the foregroun.
+or in the foreground.
 .TP
 .B \-\-guardion=\fIyes|no\fR
 Run \fBpdns_server\fR inside a guardian. This guardian monitors the performance
index 189f28d5a65d264c8a790e1fefaaeb1ee9cfc49f..c24439c550241daeaf99d322e825b061b4b0dc54 100644 (file)
@@ -67,6 +67,31 @@ bool stripDomainSuffix(string *qname, const string &domain)
   return true;
 }
 
+/** Chops off the start of a domain, so goes from 'www.ds9a.nl' to 'ds9a.nl' to ''. Return zero on the empty string */
+bool chopOff(string &domain)
+{
+  if(domain.empty())
+    return false;
+
+  string::size_type fdot=domain.find('.');
+
+  if(fdot==string::npos) 
+    domain="";
+  else 
+    domain=domain.substr(fdot+1);
+  return true;
+}
+
+/** does domain end on suffix? Is smart about "wwwds9a.nl" "ds9a.nl" not matching */
+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);
+}
+
 
 int sendData(const char *buffer, int replen, int outsock)
 {
index 249be7fe3ce6923bef210a1c40f4f36b44e8558b..9eb0526baf432a8650b3fa37b61df1215ae42e26 100644 (file)
@@ -42,6 +42,8 @@
 #include <string>
 #include <ctype.h>
 using namespace std;
+bool chopOff(string &domain);
+bool endsOn(const string &domain, const string &suffix);
 string nowTime();
 const string unquotify(const string &item);
 int matchNetmask(const char *address, const char *omask);
index 9ac94b76dc17f8ee47dd517a97f1164ff9731d07..e59bd4df75d3255e7d4b11436a78bca66b9b4091 100644 (file)
@@ -86,8 +86,7 @@ int arecvfrom(char *data, int len, int flags, struct sockaddr *toaddr, socklen_t
   memcpy(&pident.remote,toaddr,sizeof(pident.remote));
   
   string packet;
-  if(!MT.waitEvent(pident,&packet,5)) {
-    cerr<<"TIMEOUT!!!"<<endl;
+  if(!MT.waitEvent(pident,&packet,1)) { // timeout
     return 0; 
   }
 
@@ -135,8 +134,6 @@ void startDoResolve(void *p)
 
 void makeClientSocket()
 {
-  static u_int16_t port_counter=5000;
-  
   d_clientsock=socket(AF_INET, SOCK_DGRAM,0);
   if(d_clientsock<0) 
     throw AhuException("Making a socket for resolver: "+stringerror());
@@ -149,10 +146,11 @@ void makeClientSocket()
   
   int tries=10;
   while(--tries) {
-    sin.sin_port = htons(10000+(port_counter++)%10000); // should be random!
+    u_int16_t port=10000+random()%10000;
+    sin.sin_port = htons(port); 
     
     if (bind(d_clientsock, (struct sockaddr *)&sin, sizeof(sin)) >= 0) {
-      cout<<"Bound to port "<<10000+port_counter-1<<endl;
+      cout<<"Outging query source port: "<<port<<endl;
       break;
     }
     
@@ -176,6 +174,7 @@ void makeServerSocket()
     
   if (bind(d_serversock, (struct sockaddr *)&sin, sizeof(sin))<0) 
     throw AhuException("Resolver binding to server socket: "+stringerror());
+  cout<<"Incoming query source port: "<<arg().asNum("local-port")<<endl;
 }
 
 
@@ -186,12 +185,13 @@ int main(int argc, char **argv)
 #endif
 
   try {
+    srandom(time(0));
     arg().set("soa-minimum-ttl","0")="0";
     arg().set("soa-serial-offset","0")="0";
     arg().set("local-port","port to listen on")="5300";
     arg().parse(argc, argv);
     init();
-    cerr<<"Done priming"<<endl;
+    cerr<<"Done priming cache with root hints"<<endl;
 
     makeClientSocket();
     makeServerSocket();
@@ -209,8 +209,8 @@ int main(int argc, char **argv)
       DNSPacket P;
       
       struct timeval tv;
-      tv.tv_sec=1;
-      tv.tv_usec= 0;
+      tv.tv_sec=0;
+      tv.tv_usec=500000;
       
       fd_set readfds;
       FD_ZERO( &readfds );
index 7a5506091359173d756fbb8cf082cc0c5ab9d4f9..589ddfe19af8830521f2cb9a38d9ac7d1f96fa8e 100644 (file)
 #include "arguments.hh"
 #include "lwres.hh"
 
-/** Issues:
-    - we need a cache pruning thing
-    - case issues
-    - transparency 
-      everything should be record=unknown except for A, MX, NS, AAAA
-    - negative caching
-    - compressions sucks [ortho]
-*/
 
 typedef map<string,set<DNSResourceRecord> > cache_t;
 cache_t cache;
 
-bool operator<(const DNSResourceRecord &a, const DNSResourceRecord &b)
-{
-  if(a.qname<b.qname)
-    return true;
-  if(a.qname==b.qname)
-    return(a.content<b.content);
-  return false;
-}
-
+/** dramatis personae */
 int doResolveAt(set<string> nameservers, string auth, const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret,int depth=0);
 int doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth=0);
+bool doCNAMECacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res);
+bool doCacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res);
+void getBestNSFromCache(const string &qname, set<DNSResourceRecord>&bestns, int depth);
+void addCruft(const string &qname, vector<DNSResourceRecord>& ret);
+string getBestNSNamesFromCache(const string &qname,set<string>& nsset, int depth);
+void addAuthorityRecords(const string& qname, vector<DNSResourceRecord>& ret, int depth);
+
+/** everything begins here - this is the entry point just after receiving a packet */
+int beginResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret)
+{
+  int res=doResolve(qname, qtype, ret,0);
+  if(!res)
+    addCruft(qname, ret);
+  cout<<endl;
+  return res;
+}
 
-string getA(const string &qname, int depth=0)
+int doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth)
 {
-  vector<DNSResourceRecord> res;
-  string ret;
+  string prefix;
+  prefix.assign(3*depth, ' ');
+  
+  int res;
+  if(doCNAMECacheCheck(qname,qtype,ret,depth,res)) // will reroute us if needed
+    return res;
 
-  if(!doResolve(qname,QType(QType::A), res,depth+1)) 
-    ret=res[0].content;
+  if(doCacheCheck(qname,qtype,ret,depth,res)) // we done
+    return res;
 
-  return ret;
+  cout<<prefix<<qname<<": No cache hit for '"<<qname<<"|"<<qtype.getName()<<"', trying to find an appropriate NS record"<<endl;
+
+  string subdomain(qname);
+
+  set<string> nsset;
+  subdomain=getBestNSNamesFromCache(subdomain,nsset,depth);
+  if(!doResolveAt(nsset,subdomain,qname,qtype,ret,depth))
+    return 0;
+  
+  cout<<prefix<<qname<<": failed"<<endl;
+  return RCode::ServFail;
 }
 
-bool chopOff(string &domain)
+string getA(const string &qname, int depth=0)
 {
-  if(domain.empty())
-    return false;
+  vector<DNSResourceRecord> res;
+  string ret;
 
-  string::size_type fdot=domain.find('.');
+  if(!doResolve(qname,QType(QType::A), res,depth+1) && !res.empty()) 
+    ret=res[res.size()-1].content; // last entry, in case of CNAME in between
 
-  if(fdot==string::npos) 
-    domain="";
-  else 
-    domain=domain.substr(fdot+1);
-  return true;
+  return ret;
 }
 
-
 void getBestNSFromCache(const string &qname, set<DNSResourceRecord>&bestns, int depth)
 {
   string prefix;
@@ -134,43 +144,7 @@ string getBestNSNamesFromCache(const string &qname,set<string>& nsset, int depth
   return subdomain;
 }
 
-
-void addCruft(const string &qname, vector<DNSResourceRecord>& ret)
-{
-  for(vector<DNSResourceRecord>::const_iterator k=ret.begin();k!=ret.end();++k)  // don't add stuff to an NXDOMAIN!
-    if(k->d_place==DNSResourceRecord::AUTHORITY && k->qtype==QType(QType::SOA))
-      return;
-
-  cout<<qname<<": Adding best authority records from cache"<<endl;
-  addAuthorityRecords(qname,ret,0);
-  cout<<qname<<": Done adding best authority records."<<endl;
-
-  cout<<qname<<": Starting 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.getName()<<"' needs an IP address"<<endl;
-      doResolve(k->content,QType(QType::A),addit,1);
-    }
-
-  
-  for(vector<DNSResourceRecord>::iterator k=addit.begin();k!=addit.end();++k) {
-    k->d_place=DNSResourceRecord::ADDITIONAL;
-    ret.push_back(*k);
-  }
-  cout<<qname<<": Done with additional processing"<<endl;
-}
-
-int beginResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret)
-{
-  int res=doResolve(qname, qtype, ret,0);
-  if(!res)
-    addCruft(qname, ret);
-  return res;
-}
-
-bool doCNAMECheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res)
+bool doCNAMECacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res)
 {
   string prefix, tuple=toLower(qname)+"|CNAME";
   prefix.assign(3*depth, ' ');
@@ -184,7 +158,8 @@ bool doCNAMECheck(const string &qname, const QType &qtype, vector<DNSResourceRec
        DNSResourceRecord rr=*j;
        rr.ttl-=time(0);
        ret.push_back(rr);
-       res=doResolve(i->second.begin()->content, qtype, ret, depth);
+       if(!(qtype==QType(QType::CNAME))) // perhaps they really wanted a CNAME!
+         res=doResolve(i->second.begin()->content, qtype, ret, depth);
        return true;
       }
     }
@@ -231,42 +206,27 @@ bool doCacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRec
   return false;
 }
 
-
-int doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth)
+inline bool moreSpecificThan(const string& a, const string &b)
 {
-  string prefix;
-  prefix.assign(3*depth, ' ');
+  int counta=!a.empty(), countb=!b.empty();
   
-  int res;
-  if(doCNAMECheck(qname,qtype,ret,depth,res))
-    return res;
-
-  if(doCacheCheck(qname,qtype,ret,depth,res)) // we done
-    return res;
-
-  cout<<prefix<<qname<<": No cache hit for '"<<qname<<"|"<<qtype.getName()<<"', trying to find an appropriate NS record"<<endl;
-
-  string subdomain(qname);
-
-  do {
-    set<string> nsset;
-    subdomain=getBestNSNamesFromCache(subdomain,nsset,depth);
-    if(!doResolveAt(nsset,subdomain,qname,qtype,ret,depth))
-      return 0;
-    // failed, restart at a lower level of NS
-  }while(chopOff(subdomain));
-
-  cout<<prefix<<qname<<": FOUND NO NS FOR '"<<subdomain<<"'"<<endl;
-  return RCode::ServFail;
+  for(string::size_type n=0;n<a.size();++n)
+    if(a[n]=='.')
+      counta++;
+  for(string::size_type n=0;n<b.size();++n)
+    if(b[n]=='.')
+      countb++;
+  return counta>countb;
 }
 
-bool endsOn(const string &domain, const string &suffix) 
+inline vector<string>shuffle(set<string> &nameservers)
 {
-  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);
+  vector<string> rnameservers;
+  for(set<string>::const_iterator i=nameservers.begin();i!=nameservers.end();++i)
+    rnameservers.push_back(*i);
+  
+  random_shuffle(rnameservers.begin(),rnameservers.end());
+  return rnameservers;
 }
 
 /** returns -1 in case of no results, rcode otherwise */
@@ -277,130 +237,162 @@ int doResolveAt(set<string> nameservers, string auth, const string &qname, const
   
   LWRes r;
   LWRes::res_t result;
-  vector<DNSResourceRecord>usefulrrs;
-  set<string> nsset;  
-  cout<<prefix<<qname<<": Cache consultations done, going on the wire!"<<endl;
 
+  cout<<prefix<<qname<<": Cache consultations done, going on the wire!"<<endl;
 
   for(;;) { // we may get more specific nameservers
     bool aabit=false;
     result.clear();
 
-    vector<string>rnameservers;
-    for(set<string>::const_iterator i=nameservers.begin();i!=nameservers.end();++i)
-      rnameservers.push_back(*i);
+    vector<string>rnameservers=shuffle(nameservers);
 
-    random_shuffle(rnameservers.begin(),rnameservers.end());
-    for(vector<string>::const_iterator i=rnameservers.begin();;++i){ 
-      if(i==rnameservers.end()) {
+    for(vector<string>::const_iterator tns=rnameservers.begin();;++tns) { 
+      if(tns==rnameservers.end()) {
        cout<<prefix<<qname<<": Failed to resolve via any of the "<<rnameservers.size()<<" offered NS"<<endl;
        return -1;
       }
-      cout<<prefix<<qname<<": Trying to resolve NS "<<*i<<endl;
-      string remoteIP=getA(*i, depth+1);
+      cout<<prefix<<qname<<": Trying to resolve NS "<<*tns<<endl;
+      string remoteIP=getA(*tns, depth+1);
       if(remoteIP.empty()) {
-       cout<<prefix<<qname<<": Failed to resolve NS "<<*i<<", trying next if available"<<endl;
+       cout<<prefix<<qname<<": Failed to get IP for NS "<<*tns<<", trying next if available"<<endl;
        continue;
       }
-      cout<<prefix<<qname<<": Resolved NS "<<*i<<" to "<<remoteIP<<", asking '"<<qname<<"|"<<qtype.getName()<<"'"<<endl;
+      cout<<prefix<<qname<<": Resolved NS "<<*tns<<" to "<<remoteIP<<", asking '"<<qname<<"|"<<qtype.getName()<<"'"<<endl;
 
       if(r.asyncresolve(remoteIP,qname.c_str(),qtype.getCode())!=1) { // <- we go out on the wire!
-       cout<<prefix<<qname<<": error resolving"<<endl;
+       cout<<prefix<<qname<<": error resolving (perhaps timeout?)"<<endl;
+       continue;
       }
-      else {
-       result=r.result(aabit);
-       
-       cout<<prefix<<qname<<": Got "<<result.size()<<" answers from "<<*i<<" ("<<remoteIP<<")"<<endl;
-       break;
+      result=r.result(aabit);
+      cout<<prefix<<qname<<": Got "<<result.size()<<" answers from "<<*tns<<" ("<<remoteIP<<")"<<endl;
+
+      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? ";
+       cout.flush();
+       if(endsOn(i->qname, auth)) {
+         cout<<"YES!"<<endl;
+
+         DNSResourceRecord rr=*i;
+         rr.d_place=DNSResourceRecord::ANSWER;
+         rr.ttl+=time(0);
+         tcache[toLower(i->qname)+"|"+i->qtype.getName()].insert(rr);
+       }
+       else
+         cout<<"NO!"<<endl;
       }
-    }
-
-
-    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? ";
-      cout.flush();
-      if(endsOn(i->qname, auth)) {
-       cout<<"YES!"<<endl;
-
-       DNSResourceRecord rr=*i;
-       rr.d_place=DNSResourceRecord::ANSWER;
-       rr.ttl+=time(0);
-       tcache[toLower(i->qname)+"|"+i->qtype.getName()].insert(rr);
+    
+      // supplant
+      for(cache_t::const_iterator i=tcache.begin();i!=tcache.end();++i)
+       cache[i->first]=i->second;
+      
+      set<string> nsset;  
+      cout<<prefix<<qname<<": determining status after receiving this packet"<<endl;
+
+      bool done=false, realreferral=false, negcache=false;
+      string newauth;
+
+      for(LWRes::res_t::const_iterator i=result.begin();i!=result.end();++i) {
+       if(i->d_place==DNSResourceRecord::AUTHORITY && endsOn(qname,i->qname) && i->qtype.getCode()==QType::SOA) {
+         cout<<prefix<<qname<<": got negative caching indication"<<endl;
+         ret.push_back(*i);
+         negcache=true;
+       }
+       else if(i->d_place==DNSResourceRecord::ANSWER && i->qname==qname && i->qtype.getCode()==QType::CNAME && (!(qtype==QType(QType::CNAME)))) {
+         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);
+       }
+       // for ANY answers we *must* have an authoritive answer
+       else if(i->d_place==DNSResourceRecord::ANSWER && i->qname==qname && (i->qtype==qtype || ( qtype==QType(QType::ANY) && aabit)))  {
+         cout<<prefix<<qname<<": answer is in: resolved to '"<<i->content<<"|"<<i->qtype.getName()<<"'"<<endl;
+         done=true;
+         ret.push_back(*i);
+       }
+       else if(i->d_place==DNSResourceRecord::AUTHORITY && endsOn(qname,i->qname) && i->qtype.getCode()==QType::NS) { 
+         if(moreSpecificThan(i->qname,auth)) {
+           newauth=i->qname;
+           cout<<prefix<<qname<<": got NS record '"<<i->qname<<"' -> '"<<i->content<<"'"<<endl;
+           realreferral=true;
+         }
+         else {
+           cout<<prefix<<qname<<": got upwards NS record '"<<i->qname<<"' -> '"<<i->content<<"', already had '"<<auth<<"'"<<endl;
+         }
+         nsset.insert(toLower(i->content));
+       }
       }
-      else
-       cout<<"NO!"<<endl;
 
-    }
-    
-    // supplant
-    for(cache_t::const_iterator i=tcache.begin();i!=tcache.end();++i)
-      cache[i->first]=i->second;
-    
-    nsset.clear();
-    cout<<prefix<<qname<<": determining status after receiving this packet"<<endl;
-    bool done=false;
-    for(LWRes::res_t::const_iterator i=result.begin();i!=result.end();++i) {
-      if(i->d_place==DNSResourceRecord::AUTHORITY && endsOn(qname,i->qname) && i->qtype.getCode()==QType::SOA) {
-       cout<<prefix<<qname<<": got a NXDOMAIN"<<endl;
-       ret.push_back(*i);
-       return RCode::NXDomain; // NXDOMAIN
+      if(done){ 
+       cout<<prefix<<qname<<": status=got results, this level of recursion done"<<endl;
+       return 0;
       }
-      if(i->d_place==DNSResourceRecord::ANSWER && i->qname==qname && i->qtype.getCode()==QType::CNAME) {
-       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(r.d_rcode==RCode::NXDomain) {
+       cout<<prefix<<qname<<": status=NXDOMAIN, we are done "<<(negcache ? "(have negative SOA)" : "")<<endl;
+       return RCode::NXDomain;
       }
-      if(aabit && i->d_place==DNSResourceRecord::ANSWER && i->qname==qname && (i->qtype==qtype || qtype==QType(QType::ANY)) ) {
-       cout<<prefix<<qname<<": answer is in: resolved to '"<<i->content<<"|"<<i->qtype.getName()<<"'"<<endl;
-       done=true;
-       ret.push_back(*i);
+      if(nsset.empty() && !r.d_rcode) {
+       cout<<prefix<<qname<<": status=noerror, other types may exist, but we are done "<<(negcache ? "(have negative SOA)" : "")<<endl;
+       return 0;
       }
-      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));
+      else if(realreferral) {
+       cout<<prefix<<qname<<": status=did not resolve, got "<<nsset.size()<<" NS, looping to them"<<endl;
+       auth=newauth;
+       nameservers=nsset;
+       break; 
+      }
+      else {
+       cout<<prefix<<qname<<": status=NS "<<*tns<<" is lame for '"<<auth<<"', trying sibbling NS"<<endl;
       }
     }
-    if(done){ 
-      cout<<prefix<<qname<<": status=got results, this level of recursion done"<<endl;
-      return 0;
-    }
-    if(nsset.empty()) {
-      cout<<prefix<<qname<<": status=not resolved, did not get referral"<<endl;
-      return -1;
-    }
-    
-    cout<<prefix<<qname<<": status=did not resolve, got "<<nsset.size()<<" NS, looping to them"<<endl;
-    nameservers=nsset;
   }
   return -1;
 }
 
+void addCruft(const string &qname, vector<DNSResourceRecord>& ret)
+{
+  for(vector<DNSResourceRecord>::const_iterator k=ret.begin();k!=ret.end();++k)  // don't add stuff to an NXDOMAIN!
+    if(k->d_place==DNSResourceRecord::AUTHORITY && k->qtype==QType(QType::SOA))
+      return;
+
+  cout<<qname<<": Adding best authority records from cache"<<endl;
+  addAuthorityRecords(qname,ret,0);
+  cout<<qname<<": Done adding best authority records."<<endl;
+
+  cout<<qname<<": Starting 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.getName()<<"' needs an IP address"<<endl;
+      doResolve(k->content,QType(QType::A),addit,1);
+    }
+  
+  for(vector<DNSResourceRecord>::iterator k=addit.begin();k!=addit.end();++k) {
+    k->d_place=DNSResourceRecord::ADDITIONAL;
+    ret.push_back(*k);
+  }
+  cout<<qname<<": Done with additional processing"<<endl;
+}
+
 void init(void)
 {
   // prime root cache
-  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"};
+  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 arr, nsrr;
   arr.qtype=QType::A;
   arr.ttl=time(0)+86400;
-
   nsrr.qtype=QType::NS;
   nsrr.ttl=time(0)+86400;
-  nsrr.qname="";
   
   for(char c='a';c<='m';++c) {
     static char templ[40];
     strncpy(templ,"a.root-servers.net", sizeof(templ) - 1);
     *templ=c;
-    arr.qname=templ;
+    arr.qname=nsrr.content=templ;
     arr.content=ips[c-'a'];
     cache[string(templ)+"|A"].insert(arr);
-
-    nsrr.content=templ;
     cache["|NS"].insert(nsrr);
   }
 }