]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
I horked the recursor code for now but it WILL get better!
authorBert Hubert <bert.hubert@netherlabs.nl>
Sat, 11 Jan 2003 21:09:57 +0000 (21:09 +0000)
committerBert Hubert <bert.hubert@netherlabs.nl>
Sat, 11 Jan 2003 21:09:57 +0000 (21:09 +0000)
git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@126 d19b8d6e-7fed-0310-83ef-9ca221ded41b

pdns/Makefile.am
pdns/common_startup.cc
pdns/dnspacket.cc
pdns/dnspacket.hh
pdns/docs/pdns.sgml
pdns/misc.hh
pdns/qtype.cc
pdns/recns.cc
pdns/syncres.cc

index 57435c1fdc7324c4931351a804de04c36ec3a167..4759dfdc58e27392c6383686be168dae89418448 100644 (file)
@@ -35,7 +35,7 @@ backends/bind/bindbackend.cc backends/bind/zoneparser2.cc \
 backends/bind/bindparser.cc backends/bind/bindlexer.c \
 backends/bind/huffman.cc backends/gsql/gsqlbackend.cc \
 backends/gsql/gsqlbackend.hh backends/gsql/ssql.hh \
-sillyrecords.cc
+sillyrecords.cc recbcomm.hh recbcomm.cc
 
 #
 pdns_server_LDFLAGS= @moduleobjects@ @modulelibs@ @DYNLINKFLAGS@ @LIBDL@ @THREADFLAGS@
index 8a5fe2475d13643ace33d42e3f1fab538608e636..553c7284817b5462d270b62026406661975a82c7 100644 (file)
@@ -17,6 +17,7 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 #include "common_startup.hh"
+#include "recbcomm.hh"
 
 typedef Distributor<DNSPacket,DNSPacket,PacketHandler> DNSDistributor;
 
@@ -30,6 +31,7 @@ CommunicatorClass Communicator;
 UDPNameserver *N;
 int avg_latency;
 TCPNameserver *TN;
+SyncresCommunicator* SRC;
 
 ArgvMap &arg()
 {
@@ -254,9 +256,6 @@ void mainthread()
   // NOW SAFE TO CREATE THREADS!
   dl->go();
 
-
-
-
   pthread_t qtid;
   StatWebServer sws;
 
@@ -266,6 +265,8 @@ void mainthread()
   if(arg().mustDo("slave") || arg().mustDo("master"))
     Communicator.go(); 
 
+  SRC=new SyncresCommunicator();
+
   if(TN)
     TN->go(); // tcp nameserver launch
     
index 5978321f1967fa3be610be65564d722412978258..3eb54a651fe23a198eeec0ec9a0c0df36e5ef88c 100644 (file)
@@ -16,7 +16,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
-// $Id: dnspacket.cc,v 1.9 2003/01/10 18:43:01 ahu Exp $
+// $Id: dnspacket.cc,v 1.10 2003/01/11 21:09:57 ahu Exp $
 #include "utility.hh"
 #include <cstdio>
 
@@ -247,18 +247,11 @@ void DNSPacket::addARecord(const string &name, u_int32_t ip, u_int32_t ttl, DNSR
   p[2]=0;
   p[3]=1; // IN
 
-  u_int32_t *ttlp=(u_int32_t *)(p+4);
-
-  *ttlp=htonl(ttl); // 4, 5, 6, 7
-
+  putLong(p+4, ttl);
   p[8]=0;
   p[9]=4; // length of data
 
-  p[10]=(ip>>24)&0xff;
-  p[11]=(ip>>16)&0xff;
-  p[12]=(ip>>8)&0xff;
-  p[13]=ip&0xff;
-  
+  putLong(p+10,ip);
   stringbuffer.append(piece1);
   stringbuffer.append(p,14);
 
@@ -296,10 +289,7 @@ void DNSPacket::addAAAARecord(const string &name, unsigned char addr[16], u_int3
   p[2]=0;
   p[3]=1; // IN
 
-  u_int32_t *ttlp=(u_int32_t *)(p+4);
-
-  *ttlp=htonl(ttl); // 4, 5, 6, 7
-
+  putLong(p+4,ttl);
   p[8]=0;
   p[9]=16; // length of data
 
@@ -332,9 +322,7 @@ void DNSPacket::addMXRecord(const string &domain, const string &mx, int priority
   piece2[2]=0;
   piece2[3]=1; // IN
 
-  u_int32_t *ttlp=(u_int32_t *)(piece2+4);
-  *ttlp=htonl(ttl); // 4, 5, 6, 7
-
+  putLong(piece2+4,ttl);
   piece2[8]=0;
   piece2[9]=0;  // need to fill this in
 
@@ -421,13 +409,10 @@ void DNSPacket::fillSOAData(const string &content, SOAData &data)
 string DNSPacket::serializeSOAData(const SOAData &d)
 {
   ostringstream o;
-
   //  nameservername hostmaster serial-number [refresh [retry [expire [ minimum] ] ] ]
-
   o<<d.nameserver<<" "<< d.hostmaster <<" "<< d.serial <<" "<< d.refresh << " "<< d.retry << " "<< d.expire << " "<< d.default_ttl;
 
   return o.str();
-
 }
 
   /* the hostmaster is encoded as two parts - the bit UNTIL the first unescaped '.'
@@ -491,10 +476,7 @@ void DNSPacket::addSOARecord(const string &domain, const string & content, u_int
   p[2]=0;
   p[3]=1; // IN
   
-  
-  u_int32_t *ttlp=(u_int32_t *)(p+4);
-  *ttlp=htonl(ttl); // 4, 5, 6, 7
-  
+  putLong(p+4,ttl);
   p[8]=0;
   p[9]=0;  // need to fill this in (length)
   
@@ -518,7 +500,6 @@ void DNSPacket::addSOARecord(const string &domain, const string & content, u_int
   *i_p++=htonl(soadata.expire);
   *i_p++=htonl(soadata.default_ttl);
   
-  
   p[9]=piece3.length()+piece4.length()+20; 
 
   stringbuffer+=piece1;
@@ -532,9 +513,6 @@ void DNSPacket::addSOARecord(const string &domain, const string & content, u_int
     d.nscount++;
 }
 
-
-
 void DNSPacket::addCNAMERecord(const DNSResourceRecord &rr)
 {
   addCNAMERecord(rr.qname, rr.content, rr.ttl);
@@ -544,7 +522,6 @@ void DNSPacket::addCNAMERecord(const string &domain, const string &alias, u_int3
 {
  string piece1;
 
- //xtoqname(domain.c_str(),&piece1); 
  toqname(domain.c_str(),&piece1);
  char p[10];
  
@@ -553,10 +530,7 @@ void DNSPacket::addCNAMERecord(const string &domain, const string &alias, u_int3
  p[2]=0;
  p[3]=1; // IN
  
- u_int32_t *ttlp=(u_int32_t *)(p+4);
- *ttlp=htonl(ttl); // 4, 5, 6, 7
+ putLong(p+4,ttl);
  p[8]=0;
  p[9]=0;  // need to fill this in
  
@@ -591,10 +565,8 @@ void DNSPacket::addRPRecord(const string &domain, const string &content, u_int32
  p[2]=0;
  p[3]=1; // IN
  
- u_int32_t *ttlp=(u_int32_t *)(p+4);
- *ttlp=htonl(ttl); // 4, 5, 6, 7
+ putLong(p+4,ttl);
+
  p[8]=0;
  p[9]=0;  // need to fill this in
  
@@ -635,6 +607,16 @@ void DNSPacket::addNAPTRRecord(const DNSResourceRecord &rr)
 }
 
 
+void DNSPacket::makeHeader(char *p,u_int16_t qtype, u_int32_t ttl)
+{
+  p[0]=0;
+  p[1]=qtype; 
+  p[2]=0;
+  p[3]=1; // IN
+  putLong(p+4,ttl);
+  p[8]=0;
+  p[9]=0;  // need to fill this in
+}
 
 void DNSPacket::addNAPTRRecord(const string &domain, const string &content, u_int32_t ttl)
 {
@@ -643,18 +625,7 @@ void DNSPacket::addNAPTRRecord(const string &domain, const string &content, u_in
   //xtoqname(domain.c_str(),&piece1);
   toqname(domain.c_str(),&piece1);
   char p[10];
-  
-  p[0]=0;
-  p[1]=QType::NAPTR; 
-  p[2]=0;
-  p[3]=1; // IN
-  u_int32_t *ttlp=(u_int32_t *)(p+4);
-  *ttlp=htonl(ttl); // 4, 5, 6, 7
-  
-  p[8]=0;
-  p[9]=0;  // need to fill this in
+  makeHeader(p,QType::NAPTR,ttl);
  
   // content contains: 100  100  "s"   "http+I2R"   ""    _http._tcp.foo.com.
 
@@ -751,25 +722,11 @@ void DNSPacket::addPTRRecord(const string &domain, const string &alias, u_int32_
 {
  string piece1;
 
- //xtoqname(domain,&piece1);
  toqname(domain,&piece1);
  char p[10];
- p[0]=0;
- p[1]=12; // PTR
- p[2]=0;
- p[3]=1; // IN
- u_int32_t *ttlp=(u_int32_t *)(p+4);
- *ttlp=htonl(ttl); // 4, 5, 6, 7
- p[8]=0;
- p[9]=0;  // need to fill this in
+ makeHeader(p,QType::PTR,ttl);
 
  string piece3;
- //xtoqname(alias,&piece3);
  toqname(alias,&piece3);
  
  p[9]=piece3.length();
@@ -794,19 +751,7 @@ void DNSPacket::addTXTRecord(string domain, string txt, u_int32_t ttl)
  //xtoqname(domain, &piece1);
  toqname(domain, &piece1);
  char p[10];
- p[0]=0;
- p[1]=16; // TXT
- p[2]=0;
- p[3]=1; // IN
-
- u_int32_t *ttlp=(u_int32_t *)(p+4);
- *ttlp=htonl(ttl); // 4, 5, 6, 7
-
- p[8]=0;
- p[9]=0; // need to fill this in
-
+ makeHeader(p,QType::TXT,ttl);
  string piece3;
  piece3.reserve(txt.length()+1);
  piece3.append(1,txt.length());
@@ -821,7 +766,6 @@ void DNSPacket::addTXTRecord(string domain, string txt, u_int32_t ttl)
 
  d.ancount++;
 }
-
 void DNSPacket::addHINFORecord(const DNSResourceRecord& rr)
 {
   addHINFORecord(rr.qname, rr.content, rr.ttl);
@@ -838,10 +782,7 @@ void DNSPacket::addHINFORecord(string domain, string content, u_int32_t ttl)
  p[1]=13; // HINFO
  p[2]=0;
  p[3]=1; // IN
-
- u_int32_t *ttlp=(u_int32_t *)(p+4);
- *ttlp=htonl(ttl); // 4, 5, 6, 7
+ putLong(p+4,ttl);
 
  p[8]=0;
  p[9]=0; // need to fill this in
@@ -896,10 +837,7 @@ void DNSPacket::addNSRecord(string domain, string server, u_int32_t ttl, DNSReso
   p[1]=2; // NS
   p[2]=0;
   p[3]=1; // IN
-
-  u_int32_t *ttlp=(u_int32_t *)(p+4);
-
-  *ttlp=htonl(ttl); // 4, 5, 6, 7
+  putLong(p+4,ttl);
 
   p[8]=0;
   p[9]=0;  // need to fill this in
@@ -1094,7 +1032,10 @@ void DNSPacket::wrapup(void)
       break;
 
     default:
-      L<<Logger::Warning<<"Unable to insert a record of type "<<rr.qtype.getName()<<" for '"<<rr.qname<<"'"<<endl;
+      if(rr.qtype.getCode()>1024)
+       addGenericRecord(rr);
+      else
+       L<<Logger::Warning<<"Unable to insert a record of type "<<rr.qtype.getName()<<" for '"<<rr.qname<<"'"<<endl;
     }
   }
   d.ancount=htons(d.ancount);
@@ -1108,6 +1049,31 @@ void DNSPacket::wrapup(void)
   len=stringbuffer.length();
 }
 
+void DNSPacket::addGenericRecord(const DNSResourceRecord& rr)
+{
+  string piece1;
+ //xtoqname(domain, &piece1);
+ toqname(rr.qname, &piece1);
+ char p[10];
+ p[0]=0;
+ p[1]=rr.qtype.getCode()-1024; // TXT
+ p[2]=0;
+ p[3]=1; // IN
+
+ putLong(p+4,rr.ttl);
+
+ p[8]=rr.content.length()/256;
+ p[9]=rr.content.length()%256; // need to fill this in
+
+ stringbuffer+=piece1;
+ stringbuffer.append(p,10);
+ stringbuffer+=rr.content;
+ if(rr.d_place==DNSResourceRecord::ADDITIONAL)
+   d.arcount++;
+ else
+   d.ancount++;
+}
 
 /** Truncates a packet that has already been wrapup()-ed, possibly via a call to getData(). Do not call this function
     before having done this - it will possibly break your packet, or crash your program. 
@@ -1290,9 +1256,10 @@ vector<DNSResourceRecord> DNSPacket::getAnswers()
 
       rr.content=tmp;
       break;
-
     default:
-      throw AhuException("Unknown type number "+itoa(rr.qtype.getCode())+" for: '"+rr.qname+"'");
+      rr.qtype=rr.qtype.getCode()+1024;
+      rr.content.assign((const char *)datapos,length);
+      //      throw AhuException("Unknown type number "+itoa(rr.qtype.getCode())+" for: '"+rr.qname+"'");
     }
     if(pos<ntohs(d.ancount))
       rr.d_place=DNSResourceRecord::ANSWER;
index 9574be8df95e01b043bd6602e73976851378b133..8f24e9e7b6e0cf148735d484311c106df92b863e 100644 (file)
@@ -16,7 +16,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
-// $Id: dnspacket.hh,v 1.10 2003/01/08 21:31:06 ahu Exp $
+// $Id: dnspacket.hh,v 1.11 2003/01/11 21:09:57 ahu Exp $
 #ifndef DNSPACKET_HH
 #define DNSPACKET_HH
 
@@ -191,7 +191,7 @@ private:
 
   void addNSRecord(string domain, string server, u_int32_t ttl, DNSResourceRecord::Place place); //!< add an NS record to the packet
   void addNSRecord(const DNSResourceRecord &); //!< add an NS record to the packet
-
+  void addGenericRecord(const DNSResourceRecord& rr);
   static string &attodot(string &str);  //!< for when you need to insert an email address in the SOA
 
 public:
@@ -248,7 +248,7 @@ private:
   int toqname(const string &name, string *qname, bool compress = true); 
   const string makeSoaHostmasterPiece(const string &hostmaster);
   static string parseLOC(const unsigned char *p, unsigned int length);
-
+  void makeHeader(char *p,u_int16_t qtype, u_int32_t ttl);
   int domprint();
   int getq();
 
index 193dd71f621646bd6eb1c2a80c21c8231301b23a..e84e8f8350b921b1422b36eeb93a9bcf577ae621 100644 (file)
@@ -11,7 +11,7 @@
       </affiliation>
     </author>
     
-    <PubDate>v2.1 $Date: 2003/01/10 18:43:01 $</PubDate>
+    <PubDate>v2.1 $Date: 2003/01/11 21:09:57 $</PubDate>
     
     <Abstract>
        <para>  
@@ -3954,20 +3954,20 @@ local0.err                        /var/log/pdns.err
          <listitem><para>
              Only operates on the foreground, it does not fork.
            </para></listitem>
-         <listitem><para>
-             Can only answer queries for types and classes it knows about - it is not transparent as it should be.
-           </para></listitem>
          <listitem><para>
              Only ignores stale cache entries, does not actually clean them up. May replace them with newer data, however.
            </para></listitem>
          <listitem><para>
-             Not very IPv6 aware - does no AAAA additional processing.
+             Not very IPv6 aware - does no AAAA additional processing. Should not actually break anything.
            </para></listitem>
          <listitem><para>
              Only compiles on Linux and possibly Solaris. FreeBSD 4.x decided not to support the 
              POSIX get/set/swapcontext functions. Bug your favorite FreeBSD kernel or libc maintainer for a fix,
              or ask him to port MTasker (see below) to your operating system.
            </para></listitem>
+         <listitem<para>
+             It does not do TCP yet, and may have big problems with truncated packets.
+           </para></listitem>
        </itemizedlist>
       </para>
       <para>
@@ -3980,7 +3980,7 @@ local0.err                        /var/log/pdns.err
        <note>
          <para>
            PowerDNS author bert hubert has the pdns recursor in production and browsing with it works for him. Furthermore, the LARTC
-           mailinglist (2000 subscribers) is using the pdns recursing nameserver.
+           mailinglist (2000 subscribers) is using the pdns recursing nameserver. 
          </para>
        </note>
       </para>
index c449699e08cf96fbd58c42fe544d344e5ac227b0..8651631a3bb81b49abe3fa983c03e5a36d2ba97e 100644 (file)
@@ -56,6 +56,18 @@ string urlEncode(const string &text);
 int waitForData(int fd, int seconds);
 u_int16_t getShort(const unsigned char *p);
 u_int16_t getShort(const char *p);
+inline void putLong(unsigned char* p, u_int32_t val)
+{
+  *p++=(val>>24)&0xff;
+  *p++=(val>>16)&0xff;
+  *p++=(val>>8)&0xff;
+  *p++=(val   )&0xff;
+
+}
+inline void putLong(char* p, u_int32_t val)
+{
+  putLong((unsigned char *)p,val);
+}
 
 void upperCase(string& s);
 
index f0b7a1dfb517eac07223b5a71c300922874e924b..922fb4a3ea177d3890a0d98e89dd345f856af371 100644 (file)
@@ -48,10 +48,10 @@ QType::QType()
       insert("MX",15);
       insert("TXT",16);
       insert("RP",17);
+      insert("AAAA",28);
       insert("LOC",29);
       insert("SRV",33);
       insert("A6",38);
-      insert("AAAA",28);
       insert("NAPTR",35);
       insert("AXFR",252);
       insert("ANY",255);
index fe1304a293ced6be553c14628b31219d8271c311..fcfdcb850c2e4f908bebad3dd19e0321d6007c5d 100644 (file)
@@ -124,7 +124,7 @@ void startDoResolve(void *p)
     delete R;
   }
   catch(AhuException &ae) {
-    cerr<<"startDoResolve timeout: "<<ae.reason<<endl;
+    cerr<<"startDoResolve problem: "<<ae.reason<<endl;
   }
   catch(...) {
     cerr<<"Any other exception"<<endl;
@@ -206,8 +206,14 @@ int main(int argc, char **argv)
     init();
     cerr<<"Done priming cache with root hints"<<endl;
 
+    
     makeClientSocket();
-    makeServerSocket();
+    if(argc==1)
+      makeServerSocket();
+    else {
+      cout<<"Launched within pdns! Socket="<<atoi(argv[1])<<endl;
+      d_serversock=atoi(argv[1]);
+    }
     
     char data[1500];
     struct sockaddr_in fromaddr;
@@ -262,23 +268,36 @@ int main(int argc, char **argv)
       }
       
       if(FD_ISSET(d_serversock,&readfds)) { // do we have a new question?
-       d_len=recvfrom(d_serversock, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen);    
-       if(d_len<0) {
-         cerr<<"Recvfrom returned error, retrying: "<<strerror(errno)<<endl;
-         continue;
-       }
-       
-       P.setRemote((struct sockaddr *)&fromaddr, addrlen);
-       if(P.parse(data,d_len)<0) {
-         cerr<<"Unparseable packet from "<<P.getRemote()<<endl;
+       if(argc==1) {
+         d_len=recvfrom(d_serversock, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen);    
+         if(d_len<0) {
+           cerr<<"Recvfrom returned error, retrying: "<<strerror(errno)<<endl;
+           continue;
+         }
+         cout<<"Read "<<d_len<<" bytes?!"<<endl;
+         P.setRemote((struct sockaddr *)&fromaddr, addrlen);
+         if(P.parse(data,d_len)<0) {
+           cerr<<"Unparseable packet from "<<P.getRemote()<<endl;
+         }
+         else { 
+           if(P.d.qr)
+             cout<<"Ignoring answer on server socket!"<<endl;
+           else {
+             cout<<"new question arrived for '"<<P.qdomain<<"|"<<P.qtype.getName()<<"' from "<<P.getRemote()<<endl;
+             MT.makeThread(startDoResolve,(void*)new DNSPacket(P));
+           }
+         }
        }
-       else { 
-         if(P.d.qr)
-           cout<<"Ignoring answer on server socket!"<<endl;
-         else {
-           cout<<"new question arrived for '"<<P.qdomain<<"|"<<P.qtype.getName()<<"' from "<<P.getRemote()<<endl;
-           MT.makeThread(startDoResolve,(void*)new DNSPacket(P));
+       else {
+         string line;
+         int len=read(d_serversock,data,sizeof(data));
+         if(len<=0) {
+           cout<<"shit on the pdns socket"<<endl;
+           exit(1);
          }
+         line.assign(data,d_len);
+         strip(line);
+         cout<<"pdns gave us a question: '"<<line<<"'"<<endl;
        }
       }
     }
index c442e04f1ae7b99f0adc5cfdbc851436797c6128..b6d4a821f10988f9bf9c92c8a674eb59ace5cf53 100644 (file)
@@ -32,27 +32,43 @@ typedef map<string,set<DNSResourceRecord> > cache_t;
 cache_t cache;
 map<string,string> negcache;
 
+struct GetBestNSAnswer
+{
+  string qname;
+  set<DNSResourceRecord> bestns;
+  bool operator<(const GetBestNSAnswer &b) const
+  {
+    if(qname<b.qname)
+      return true;
+    if(qname==b.qname)
+      return bestns<b.bestns;
+    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);
+int doResolveAt(set<string> nameservers, string auth, const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret,
+               int depth, set<GetBestNSAnswer>&beenthere);
+int doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, set<GetBestNSAnswer>& beenthere);
 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 getBestNSFromCache(const string &qname, set<DNSResourceRecord>&bestns, int depth, set<GetBestNSAnswer>& beenthere);
 void addCruft(const string &qname, vector<DNSResourceRecord>& ret);
-string getBestNSNamesFromCache(const string &qname,set<string>& nsset, int depth);
+string getBestNSNamesFromCache(const string &qname,set<string>& nsset, int depth, set<GetBestNSAnswer>&beenthere);
 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);
+  set<GetBestNSAnswer> beenthere;
+  int res=doResolve(qname, qtype, ret,0,beenthere);
   if(!res)
     addCruft(qname, ret);
   cout<<endl;
   return res;
 }
 
-int doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth)
+int doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, set<GetBestNSAnswer>& beenthere)
 {
   string prefix;
   prefix.assign(3*depth, ' ');
@@ -69,26 +85,43 @@ int doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>
   string subdomain(qname);
 
   set<string> nsset;
-  subdomain=getBestNSNamesFromCache(subdomain,nsset,depth);
-  if(!(res=doResolveAt(nsset,subdomain,qname,qtype,ret,depth)))
+  subdomain=getBestNSNamesFromCache(subdomain,nsset,depth, beenthere); //  pass beenthere to both occasions/
+  if(!(res=doResolveAt(nsset,subdomain,qname,qtype,ret,depth, beenthere)))
     return 0;
   
   cout<<prefix<<qname<<": failed"<<endl;
   return res<0 ? RCode::ServFail : res;
 }
 
-string getA(const string &qname, int depth=0)
+string getA(const string &qname, int depth, set<GetBestNSAnswer>& beenthere)
 {
   vector<DNSResourceRecord> res;
   string ret;
 
-  if(!doResolve(qname,QType(QType::A), res,depth+1) && !res.empty()) 
+  if(!doResolve(qname,QType(QType::A), res,depth+1,beenthere) && !res.empty()) 
     ret=res[res.size()-1].content; // last entry, in case of CNAME in between
 
   return ret;
 }
 
-void getBestNSFromCache(const string &qname, set<DNSResourceRecord>&bestns, int depth)
+int getCache(const string &qname, const QType& qt, set<DNSResourceRecord>* res=0)
+{
+  cache_t::const_iterator j=cache.find(toLower(qname)+"|"+qt.getName());
+  if(j!=cache.end() && j->first==toLower(qname)+"|"+qt.getName() && j->second.begin()->ttl>(unsigned int)time(0)) {
+    if(res)
+      *res=j->second;
+    return (unsigned int)j->second.begin()->ttl-time(0);
+  }
+  return -1;
+}
+
+void replaceCache(const string &tuple, const set<DNSResourceRecord>& content)
+{
+  cache[tuple]=content;
+}
+
+
+void getBestNSFromCache(const string &qname, set<DNSResourceRecord>&bestns, int depth, set<GetBestNSAnswer>& beenthere)
 {
   string prefix, subdomain(qname);
   prefix.assign(3*depth, ' ');
@@ -96,28 +129,38 @@ void getBestNSFromCache(const string &qname, set<DNSResourceRecord>&bestns, int
 
   do {
     cout<<prefix<<qname<<": Checking if we have NS in cache for '"<<subdomain<<"'"<<endl;
-
-    cache_t::const_iterator j=cache.find(toLower(subdomain)+"|NS");
-    if(j!=cache.end() && j->first==toLower(subdomain)+"|NS") {
-      for(set<DNSResourceRecord>::const_iterator k=j->second.begin();k!=j->second.end();++k) {
-       if(k->ttl>(unsigned int)time(0)) { // the below is fugly
-         if(!endsOn(k->content,subdomain) || // glue risk
-            (cache.find(toLower(k->content)+"|A")!=cache.end() && ((time_t)cache[toLower(k->content)+"|A"].begin()->ttl-time(0))>5)) {
+    set<DNSResourceRecord>ns;
+    if(getCache(subdomain,QType(QType::NS),&ns)>0) {
+      for(set<DNSResourceRecord>::const_iterator k=ns.begin();k!=ns.end();++k) {
+       if(k->ttl>(unsigned int)time(0)) { 
+         set<DNSResourceRecord>aset;
+         if(!endsOn(k->content,subdomain) || getCache(k->content,QType(QType::A),&aset) > 5) {
            bestns.insert(*k);
            cout<<prefix<<qname<<": NS (with ip, or non-glue) in cache for '"<<subdomain<<"' -> '"<<k->content<<"'"<<endl;
            cout<<prefix<<qname<<": endson: "<<endsOn(k->content,subdomain);
-           if(cache.find(toLower(k->content)+"|A")!=cache.end())
-             cout<<", in cache, ttl="<<((time_t)cache[toLower(k->content)+"|A"].begin()->ttl-time(0))<<endl;
+           if(!aset.empty())
+             cout<<", in cache, ttl="<<((time_t)aset.begin()->ttl-time(0))<<endl;
            else
              cout<<", not in cache"<<endl;
          }
          else
-           cout<<prefix<<qname<<": NS in cache for '"<<subdomain<<"' , but needs glue ("<<k->content<<") which we miss or is expired"<<endl;
+           cout<<prefix<<qname<<": NS in cache for '"<<subdomain<<"', but needs glue ("<<k->content<<") which we miss or is expired"<<endl;
        }
       }
       if(!bestns.empty()) {
-       cout<<prefix<<qname<<": We have NS in cache for '"<<subdomain<<"'"<<endl;
-       return;
+       GetBestNSAnswer answer;
+       answer.qname=toLower(qname); answer.bestns=bestns;
+       if(beenthere.count(answer)) {
+         cout<<prefix<<qname<<": We have NS in cache for '"<<subdomain<<"' but part of LOOP! Trying less specific NS"<<endl;
+         for(set<GetBestNSAnswer>::const_iterator j=beenthere.begin();j!=beenthere.end();++j)
+           cout<<prefix<<qname<<": beenthere: "<<j->qname<<" ("<<j->bestns.size()<<")"<<endl;
+         bestns.clear();
+       }
+       else {
+         beenthere.insert(answer);
+         cout<<prefix<<qname<<": We have NS in cache for '"<<subdomain<<"'"<<endl;
+         return;
+       }
       }
     }
   }while(chopOff(subdomain));
@@ -126,7 +169,8 @@ void getBestNSFromCache(const string &qname, set<DNSResourceRecord>&bestns, int
 void addAuthorityRecords(const string& qname, vector<DNSResourceRecord>& ret, int depth)
 {
   set<DNSResourceRecord> bestns;
-  getBestNSFromCache(qname, bestns, depth);
+  set<GetBestNSAnswer>beenthere;
+  getBestNSFromCache(qname, bestns, depth,beenthere);
   for(set<DNSResourceRecord>::const_iterator k=bestns.begin();k!=bestns.end();++k) {
     DNSResourceRecord ns=*k;
     ns.d_place=DNSResourceRecord::AUTHORITY;
@@ -134,13 +178,13 @@ void addAuthorityRecords(const string& qname, vector<DNSResourceRecord>& ret, in
     ret.push_back(ns);
   }
 }
-
-string getBestNSNamesFromCache(const string &qname,set<string>& nsset, int depth)
+/** doesn't actually do the work, leaves that to getBestNSFromCache */
+string getBestNSNamesFromCache(const string &qname,set<string>& nsset, int depth, set<GetBestNSAnswer>&beenthere)
 {
   string subdomain(qname);
 
   set<DNSResourceRecord> bestns;
-  getBestNSFromCache(subdomain, bestns, depth);
+  getBestNSFromCache(subdomain, bestns, depth, beenthere);
 
   for(set<DNSResourceRecord>::const_iterator k=bestns.begin();k!=bestns.end();++k) {
     nsset.insert(k->content);
@@ -155,16 +199,18 @@ bool doCNAMECacheCheck(const string &qname, const QType &qtype, vector<DNSResour
   prefix.assign(3*depth, ' ');
 
   cout<<prefix<<qname<<": 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
-    for(set<DNSResourceRecord>::const_iterator j=i->second.begin();j!=i->second.end();++j) {
+  set<DNSResourceRecord> cset;
+  if(getCache(qname,QType(QType::CNAME),&cset) > 0) {
+    for(set<DNSResourceRecord>::const_iterator j=cset.begin();j!=cset.end();++j) {
       if(j->ttl>(unsigned int)time(0)) {
-       cout<<prefix<<qname<<": Found cache CNAME hit for '"<<tuple<<"' to '"<<i->second.begin()->content<<"'"<<endl;    
+       cout<<prefix<<qname<<": Found cache CNAME hit for '"<<tuple<<"' to '"<<j->content<<"'"<<endl;    
        DNSResourceRecord rr=*j;
        rr.ttl-=time(0);
        ret.push_back(rr);
-       if(!(qtype==QType(QType::CNAME))) // perhaps they really wanted a CNAME!
-         res=doResolve(i->second.begin()->content, qtype, ret, depth);
+       if(!(qtype==QType(QType::CNAME))) {// perhaps they really wanted a CNAME!
+         set<GetBestNSAnswer>beenthere;
+         res=doResolve(j->content, qtype, ret, depth, beenthere);
+       }
        return true;
       }
     }
@@ -189,11 +235,11 @@ bool doCacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRec
     tuple=ni->second+"|SOA";
   }
 
-  cache_t::const_iterator i=cache.find(tuple);
+  set<DNSResourceRecord> cset;
   bool found=false, expired=false;
-  if(i!=cache.end() && i->first==tuple) { // found it
+  if(getCache(qname,qtype,&cset)>0) {
     cout<<prefix<<qname<<": Found cache hit for "<<qtype.getName()<<": ";
-    for(set<DNSResourceRecord>::const_iterator j=i->second.begin();j!=i->second.end();++j) {
+    for(set<DNSResourceRecord>::const_iterator j=cset.begin();j!=cset.end();++j) {
       cout<<j->content;
       if(j->ttl>(unsigned int)time(0)) {
        DNSResourceRecord rr=*j;
@@ -243,7 +289,8 @@ inline vector<string>shuffle(set<string> &nameservers)
 }
 
 /** returns -1 in case of no results, rcode otherwise */
-int doResolveAt(set<string> nameservers, string auth, const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth)
+int doResolveAt(set<string> nameservers, string auth, const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, 
+               int depth, set<GetBestNSAnswer>&beenthere)
 {
   string prefix;
   prefix.assign(3*depth, ' ');
@@ -251,7 +298,7 @@ int doResolveAt(set<string> nameservers, string auth, const string &qname, const
   LWRes r;
   LWRes::res_t result;
 
-  cout<<prefix<<qname<<": Cache consultations done, going on the wire!"<<endl;
+  cout<<prefix<<qname<<": Cache consultations done, have "<<nameservers.size()<<" NS to contact"<<endl;
 
   for(;;) { // we may get more specific nameservers
     bool aabit=false;
@@ -270,8 +317,8 @@ int doResolveAt(set<string> nameservers, string auth, const string &qname, const
        cout<<prefix<<qname<<": Not using NS to resolve itself!"<<endl;
        continue;
       }
-      cout<<prefix<<qname<<": Trying to resolve NS "<<*tns<<endl;
-      string remoteIP=getA(*tns, depth+1);
+      cout<<prefix<<qname<<": Trying to resolve NS "<<*tns<<" ("<<1+tns-rnameservers.begin()<<"/"<<rnameservers.size()<<")"<<endl;
+      string remoteIP=getA(*tns, depth+1,beenthere);
       if(remoteIP.empty()) {
        cout<<prefix<<qname<<": Failed to get IP for NS "<<*tns<<", trying next if available"<<endl;
        continue;
@@ -290,7 +337,6 @@ int doResolveAt(set<string> nameservers, string auth, const string &qname, const
       result=r.result(aabit);
       cout<<prefix<<qname<<": Got "<<result.size()<<" answers from "<<*tns<<" ("<<remoteIP<<"), rcode="<<r.d_rcode<<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) {
@@ -302,6 +348,7 @@ int doResolveAt(set<string> nameservers, string auth, const string &qname, const
          DNSResourceRecord rr=*i;
          rr.d_place=DNSResourceRecord::ANSWER;
          rr.ttl+=time(0);
+         //      rr.ttl=time(0)+10+10*rr.qtype.getCode();
          tcache[toLower(i->qname)+"|"+i->qtype.getName()].insert(rr);
        }
        else
@@ -310,7 +357,7 @@ int doResolveAt(set<string> nameservers, string auth, const string &qname, const
     
       // supplant
       for(cache_t::const_iterator i=tcache.begin();i!=tcache.end();++i)
-       cache[i->first]=i->second;
+       replaceCache(i->first,i->second);
       
       set<string> nsset;  
       cout<<prefix<<qname<<": determining status after receiving this packet"<<endl;
@@ -328,7 +375,8 @@ int doResolveAt(set<string> nameservers, string auth, const string &qname, const
        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);
+         set<GetBestNSAnswer>beenthere2;
+         return doResolve(i->content, qtype, ret,0,beenthere2);
        }
        // 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)))  {
@@ -342,9 +390,8 @@ int doResolveAt(set<string> nameservers, string auth, const string &qname, const
            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;
-         }
+         else 
+           cout<<prefix<<qname<<": got upwards/level NS record '"<<i->qname<<"' -> '"<<i->content<<"', had '"<<auth<<"'"<<endl;
          nsset.insert(toLower(i->content));
        }
       }
@@ -368,7 +415,7 @@ int doResolveAt(set<string> nameservers, string auth, const string &qname, const
        break; 
       }
       else {
-       cout<<prefix<<qname<<": status=NS "<<*tns<<" is lame for '"<<auth<<"', trying sibbling NS"<<endl;
+       cout<<prefix<<qname<<": status=NS "<<*tns<<" is lame for '"<<auth<<"', trying sibling NS"<<endl;
       }
     }
   }
@@ -391,7 +438,8 @@ void addCruft(const string &qname, vector<DNSResourceRecord>& ret)
     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);
+      set<GetBestNSAnswer>beenthere;
+      doResolve(k->content,QType(QType::A),addit,1,beenthere);
     }
   
   for(vector<DNSResourceRecord>::iterator k=addit.begin();k!=addit.end();++k) {