]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
interim- too muchwork done to lose
authorBert Hubert <bert.hubert@netherlabs.nl>
Sun, 3 Jul 2005 15:58:11 +0000 (15:58 +0000)
committerBert Hubert <bert.hubert@netherlabs.nl>
Sun, 3 Jul 2005 15:58:11 +0000 (15:58 +0000)
git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@424 d19b8d6e-7fed-0310-83ef-9ca221ded41b

pdns/anadns.hh [new file with mode: 0644]
pdns/dnspacket.hh
pdns/dnsparser.hh
pdns/dnsreplay.cc
pdns/dnsscope.cc
pdns/sstuff.hh

diff --git a/pdns/anadns.hh b/pdns/anadns.hh
new file mode 100644 (file)
index 0000000..af60472
--- /dev/null
@@ -0,0 +1,81 @@
+#ifndef PDNS_ANADNS_HH
+#define PDNS_ANADNS_HH
+#include <boost/tuple/tuple.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+#include <string>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include "dnsparser.hh"
+
+using namespace boost;
+using namespace std;
+
+struct QuestionIdentifier
+{
+  QuestionIdentifier() 
+  {}
+
+  bool operator<(const QuestionIdentifier& rhs) const
+  {
+    return 
+      tie(d_sourceip, d_destip, d_sourceport, d_destport, d_qname, d_qtype, d_id) < 
+      tie(rhs.d_sourceip, rhs.d_destip, rhs.d_sourceport, rhs.d_destport, rhs.d_qname, rhs.d_qtype, rhs.d_id);
+  }
+
+  // the canonical direction is that of the question
+  static QuestionIdentifier create(const struct iphdr* d_ip, const struct udphdr* d_udp, const MOADNSParser& mdp)
+  {
+    QuestionIdentifier ret;
+    if(mdp.d_header.qr) {
+      ret.d_sourceip=htonl(d_ip->daddr);
+      ret.d_destip=htonl(d_ip->saddr);
+      ret.d_sourceport=htons(d_udp->dest);
+      ret.d_destport=htons(d_udp->source);
+    }
+    else {
+      ret.d_sourceip=htonl(d_ip->saddr);
+      ret.d_destip=htonl(d_ip->daddr);
+      ret.d_sourceport=htons(d_udp->source);
+      ret.d_destport=htons(d_udp->dest);
+    }
+    ret.d_qname=mdp.d_qname;
+    ret.d_qtype=mdp.d_qtype;
+    ret.d_id=mdp.d_header.id;
+    return ret;
+  }
+
+
+  uint32_t d_sourceip;
+  uint32_t d_destip;
+  uint16_t d_sourceport;
+  uint16_t d_destport;
+
+  string d_qname;
+  uint16_t d_qtype;
+  uint16_t d_id;
+
+
+};
+
+inline ostream& operator<<(ostream &s, const QuestionIdentifier& qi) 
+{
+  s<< "'"<<qi.d_qname<<"|"<<qi.d_qtype<<"', with id " << qi.d_id <<" from ";
+  u_int32_t rint=qi.d_sourceip;
+
+  s<< (rint>>24 & 0xff)<<".";
+  s<< (rint>>16 & 0xff)<<".";
+  s<< (rint>>8  & 0xff)<<".";
+  s<< (rint     & 0xff);
+  s<<":"<<qi.d_sourceport;
+  
+  s<<" to ";
+  rint=qi.d_destip;
+  s<< (rint>>24 & 0xff)<<".";
+  s<< (rint>>16 & 0xff)<<".";
+  s<< (rint>>8  & 0xff)<<".";
+  s<< (rint     & 0xff);
+  return s<<":"<<qi.d_destport;
+}
+
+
+#endif
index e9ae9eee61672bac5e065224d7f36ca6a3ce8254..539ad59c861b1b1ad6018a0dbfe349fb2c8e39a4 100644 (file)
@@ -297,16 +297,23 @@ int DNSPacket::parse(const char *mesg, int length)
 
   int offset=0;
   d_qlen=0;
-  if(ntohs(d.qdcount)) {
-    offset = getq(); // also sets this->qdomain!
-    if(offset < 0) {
-      //    L << Logger::Warning << "Ignoring packet: invalid label in question from "
-      //  << inet_ntoa(remote.sin_addr) << endl;
-      return -1;
-    }
-    d_qlen=offset+4; // this points to the start of any answers
+  if(!ntohs(d.qdcount)) {
+    L << Logger::Warning << "No question section in packet from " << getRemote() <<", rcode="<<(int)d.rcode<<endl;
+    return -1;
   }
 
+  offset = getq(); // also sets this->qdomain!
+  if(offset < 0) {
+    //    L << Logger::Warning << "Ignoring packet: invalid label in question from "
+    //  << inet_ntoa(remote.sin_addr) << endl;
+    return -1;
+  }
+  if(qdomain.length() > 255) { // this prevents crap from the rootservers
+    return -1;
+  }
+
+  d_qlen=offset+4; // this points to the start of any answers
+  
   if((unsigned int)(15+offset)>=stringbuffer.length()) {
     L << Logger::Warning << "Ignoring packet: question too short from "<< getRemote()<<", offset "<<
       15+offset<<">="<<stringbuffer.length()<<endl;
index eaa392089452307998f81315be5c209c973c0064..1857165053d0add5883f4ca0b0066fbee6282dae 100644 (file)
@@ -12,7 +12,8 @@
 #include <arpa/nameser.h>
 #include <boost/shared_ptr.hpp>
 #include <boost/lexical_cast.hpp>
-
+#include <boost/tuple/tuple.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
 namespace {
   typedef HEADER dnsheader;
 }
@@ -112,6 +113,32 @@ struct DNSRecord
   u_int16_t d_clen;
   enum {Answer, Nameserver, Additional} d_place;
   boost::shared_ptr<DNSRecordContent> d_content;
+
+  bool operator<(const DNSRecord& rhs) const
+  {
+    string lzrp, rzrp;
+    if(d_content)
+      lzrp=    d_content->getZoneRepresentation();
+    if(rhs.d_content)
+      rzrp=rhs.d_content->getZoneRepresentation();
+    
+    return 
+      tie(d_label,         d_type,     d_class,     d_ttl,     d_clen, lzrp) <
+      tie(rhs.d_label, rhs.d_type, rhs.d_class, rhs.d_ttl, rhs.d_clen, rzrp);
+  }
+
+  bool operator==(const DNSRecord& rhs) const
+  {
+    string lzrp, rzrp;
+    if(d_content)
+      lzrp=    d_content->getZoneRepresentation();
+    if(rhs.d_content)
+      rzrp=rhs.d_content->getZoneRepresentation();
+    
+    return 
+      tie(d_label,         d_type,     d_class,     d_ttl,     d_clen, lzrp) ==
+      tie(rhs.d_label, rhs.d_type, rhs.d_class, rhs.d_ttl, rhs.d_clen, rzrp);
+  }
 };
 
 
index c3237df52996b7bf955e4e68e7ca7aa27ec0c42e..2424c1cecccf907ca372a825ab60853b1193b047 100644 (file)
 /** two modes:
 
-Replay all recursion-desired DNS questions to a specified IP address
+Replay all recursion-desired DNS questions to a specified IP address.
 
+Track all outgoing questions, remap id to one of ours.
+Also track all recorded answers, and map them to that same id, the 'expectation'.
+
+When we see a question, parse it, give it a QuestionIdentifyer, and and an id from the free-id list.
+
+When we see an answer in the tcpdump, parse it, make QI, and add it to the original QI
+   and check
+
+When we see an answer from the socket, use the id to match it up to the original QI
+   and check
+
+
+There is one central object, which has (when complete)
+
+   our assigned id
+   QI
+   Original answer
+   Socket answer
 */
 
 #include <pcap.h>
-
+#include <bitset>
 #include "statbag.hh"
 #include "dnspcap.hh"
 #include "sstuff.hh"
-
+#include "anadns.hh"
 #include <arpa/nameser.h>
+#include <set>
 
 using namespace boost;
 using namespace std;
 
 StatBag S;
 
+class DNSIDManager
+{
+public:
+  
+  int getID()
+  {
+
+    for(unsigned int n=0; n < d_freeids.size() ; ++n)
+      if(!d_freeids[n]) {
+       d_freeids[n]=1;
+       return n;
+      }
+
+    throw runtime_error("Out of free IDs");
+  }
+
+  void releaseID(int id)
+  {
+    if(!d_freeids[id])
+      throw runtime_error("Trying to release unused id: "+lexical_cast<string>(id));
+    d_freeids[id]=0;
+  }
+
+private:
+  bitset<65536> d_freeids;
+} s_idmanager;
+
+struct QuestionData
+{
+  QuestionData() : d_assignedID(-1), d_origRcode(-1), d_newRcode(-1) 
+  {}
+  int d_assignedID;
+  MOADNSParser::answers_t d_origAnswers, d_newAnswers;
+  int d_origRcode, d_newRcode;
+};
+
+typedef map<QuestionIdentifier, QuestionData> qids_t;
+qids_t qids;
+
+void compactAnswerSet(MOADNSParser::answers_t orig, set<DNSRecord>& compacted)
+{
+  for(MOADNSParser::answers_t::const_iterator i=orig.begin(); i != orig.end(); ++i)
+    if(i->first.d_place==DNSRecord::Answer)
+      compacted.insert(i->first);
+}
+
+void measureResultAndClean(const QuestionIdentifier& qi)
+{
+  QuestionData qd=qids[qi];
+  cerr<<"Orig rcode: "<<qd.d_origRcode<<", ours: "<<qd.d_newRcode;
+
+  set<DNSRecord> canonicOrig, canonicNew;
+  compactAnswerSet(qd.d_origAnswers, canonicOrig);
+  compactAnswerSet(qd.d_newAnswers, canonicNew);
+  
+  cerr<<", "<<canonicOrig.size()<< " vs " << canonicNew.size()<<", perfect: ";
+
+  if(canonicOrig==canonicNew)
+    cerr<<"yes";
+  else
+    cerr<<"no";
+  cerr<<endl;
+
+  qids.erase(qi);
+}
+
+
+void processIncoming(Socket& s)
+{
+  string packet;
+  IPEndpoint remote;
+  while(s.recvFromAsync(packet, remote)) {
+    MOADNSParser mdp(packet.c_str(), packet.length());
+    if(!mdp.d_header.qr) {
+      cerr<<"Received a question from our reference nameserver!"<<endl;
+      continue;
+    }
+
+    qids_t::iterator i=qids.begin();
+    for(; i!=qids.end(); ++i)
+      if(i->second.d_assignedID == ntohs(mdp.d_header.id))
+       break;
+    
+    if(i==qids.end()) {
+      cerr<<"Received an answer from reference nameserver with id "<<mdp.d_header.id<<" which we can't match to a question!"<<endl;
+      continue;
+    }
+    
+    cerr<<"Matched answer from reference to a question we asked"<<endl;
+
+    QuestionData& qd=i->second;
+    
+    qd.d_newAnswers=mdp.d_answers;
+    qd.d_newRcode=mdp.d_header.rcode;
+    if(qd.d_origRcode!=-1) {
+      cerr<<"Removing entry "<<i->first<<", is done [in socket]"<<endl;
+      measureResultAndClean(i->first);
+    }
+  }
+    
+}
 
 int main(int argc, char** argv)
 try
@@ -27,36 +147,64 @@ try
 
   PcapPacketReader pr(argv[1]);
   Socket s(InterNetwork, Datagram);
-
+  s.setNonBlocking();
   IPEndpoint remote("127.0.0.1", 5300);
 
+  /*
   struct timespec tosleep;
-
   struct timeval lastsent={0,0};
   double seconds, useconds;
   double factor=20;
+  */
+
   while(pr.getUDPPacket()) {
-    if(ntohs(pr.d_udp->dest)==53 || ntohs(pr.d_udp->source)==53 && pr.d_len > sizeof(HEADER)) {
-      HEADER* dh=(HEADER*)pr.d_payload;
-
-      if(dh->rd && !dh->qr) {
-       if(lastsent.tv_sec) {
-         seconds=pr.d_pheader.ts.tv_sec - lastsent.tv_sec;
-         useconds=(pr.d_pheader.ts.tv_usec - lastsent.tv_usec);
-         
-         seconds/=factor;
-         useconds/=factor;
-         
-         long long nanoseconds=1000000000ULL*seconds + useconds * 1000;
-         
-         tosleep.tv_sec=nanoseconds/1000000000UL;
-         tosleep.tv_nsec=nanoseconds%1000000000UL;
-         
-         nanosleep(&tosleep, 0);
+    processIncoming(s);
+
+
+    HEADER* dh=(HEADER*)pr.d_payload;
+    if(ntohs(pr.d_udp->dest)!=53 && ntohs(pr.d_udp->source)!=53 ||  !dh->rd || pr.d_len <= sizeof(HEADER)) 
+      continue;
+    
+    try {
+      MOADNSParser mdp((const char*)pr.d_payload, pr.d_len);
+      QuestionIdentifier qi=QuestionIdentifier::create(pr.d_ip, pr.d_udp, mdp);
+      
+      if(!mdp.d_header.qr) {
+       if(qids.count(qi)) {
+         cerr<<"Saw an exact duplicate question, "<<qi<< endl;
+         continue;
        }
-       lastsent=pr.d_pheader.ts;
+       else 
+         cerr<<"New question "<<qi<<endl;
+       QuestionData& qd=qids[qi];
+       
+       qd.d_assignedID = s_idmanager.getID();
+       dh->id=htons(qd.d_assignedID);
        s.sendTo(string(pr.d_payload, pr.d_payload + pr.d_len), remote);
       }
+      else {
+       if(qids.count(qi)) {
+         QuestionData& qd=qids[qi];
+         cerr<<"Matched answer "<<qi<<endl;
+         qd.d_origAnswers=mdp.d_answers;
+         qd.d_origRcode=mdp.d_header.rcode;
+         if(qd.d_newRcode!=-1) {
+           cerr<<"Removing entry "<<qi<<", is done [in main loop]"<<endl;
+           measureResultAndClean(qi);
+         }
+         continue;
+       }
+       else 
+         cerr<<"Unmatched answer "<<qi<<endl;
+       //      QuestionData& qd=qids[qi];
+       
+      }
+    }
+    catch(MOADNSException &e)
+    {
+    }
+    catch(out_of_range &e)
+    {
     }
     
   }
@@ -66,3 +214,21 @@ catch(exception& e)
 {
   cerr<<"Fatal: "<<e.what()<<endl;
 }
+
+
+#if 0
+      if(lastsent.tv_sec) {
+       seconds=pr.d_pheader.ts.tv_sec - lastsent.tv_sec;
+       useconds=(pr.d_pheader.ts.tv_usec - lastsent.tv_usec);
+       
+       seconds/=factor;
+       useconds/=factor;
+       
+       long long nanoseconds=1000000000ULL*seconds + useconds * 1000;
+       
+       tosleep.tv_sec=nanoseconds/1000000000UL;
+       tosleep.tv_nsec=nanoseconds%1000000000UL;
+       
+       nanosleep(&tosleep, 0);
+      }
+#endif
index dbbd3ea056d07bc8cd2502fbd71d72fb80a1481a..47d075c285f5575383bc1291618d6ebb408ea0b0 100644 (file)
@@ -8,55 +8,13 @@
 #include <map>
 #include <set>
 #include <fstream>
+#include "anadns.hh"
 
 using namespace boost;
 using namespace std;
 
 StatBag S;
 
-struct QuestionIdentifyer
-{
-  QuestionIdentifyer() 
-  {}
-
-  bool operator<(const QuestionIdentifyer& rhs) const
-  {
-    return 
-      tie(d_sourceip, d_destip, d_sourceport, d_destport, d_qname, d_qtype, d_id) < 
-      tie(rhs.d_sourceip, rhs.d_destip, rhs.d_sourceport, rhs.d_destport, rhs.d_qname, rhs.d_qtype, rhs.d_id);
-  }
-
-  // the canonical direction is that of the question
-  static QuestionIdentifyer create(const struct iphdr* d_ip, const struct udphdr* d_udp, const MOADNSParser& mdp)
-  {
-    QuestionIdentifyer ret;
-    if(mdp.d_header.qr) {
-      ret.d_sourceip=htonl(d_ip->daddr);
-      ret.d_destip=htonl(d_ip->saddr);
-      ret.d_sourceport=htons(d_udp->dest);
-      ret.d_destport=htons(d_udp->source);
-    }
-    else {
-      ret.d_sourceip=htonl(d_ip->saddr);
-      ret.d_destip=htonl(d_ip->daddr);
-      ret.d_sourceport=htons(d_udp->source);
-      ret.d_destport=htons(d_udp->dest);
-    }
-    ret.d_qname=mdp.d_qname;
-    ret.d_qtype=mdp.d_qtype;
-    ret.d_id=mdp.d_header.id;
-    return ret;
-  }
-
-  uint32_t d_sourceip;
-  uint32_t d_destip;
-  uint16_t d_sourceport;
-  uint16_t d_destport;
-
-  string d_qname;
-  uint16_t d_qtype;
-  uint16_t d_id;
-};
 
 struct QuestionData
 {
@@ -71,7 +29,7 @@ struct QuestionData
   struct timeval d_firstquestiontime;
 };
 
-typedef map<QuestionIdentifyer, QuestionData> statmap_t;
+typedef map<QuestionIdentifier, QuestionData> statmap_t;
 statmap_t statmap;
 
 int main(int argc, char** argv)
@@ -106,7 +64,7 @@ try
 
        string name=mdp.d_qname+"|"+DNSRecordContent::NumberToType(mdp.d_qtype);
        
-       QuestionIdentifyer qi=QuestionIdentifyer::create(pr.d_ip, pr.d_udp, mdp);
+       QuestionIdentifier qi=QuestionIdentifier::create(pr.d_ip, pr.d_udp, mdp);
 
        if(!mdp.d_header.qr) {
          //      cout<<"Question for '"<< name <<"'\n";
index 913f9fde44390154b5f13e7c0f94e363bcf5bf61..ee7436a07e037a2aa85231f7dfe6428886d49eb2 100755 (executable)
@@ -184,6 +184,24 @@ public:
     ep.port=ntohs(remote.sin_port);
   }
 
+  bool recvFromAsync(string &dgram, IPEndpoint &ep)
+  {
+    struct sockaddr_in remote;
+    socklen_t remlen=sizeof(remote);
+    int bytes;
+    if((bytes=recvfrom(d_socket, d_buffer, d_buflen, 0, (sockaddr *)&remote, &remlen))<0)
+      if(errno!=EAGAIN)
+       throw NetworkError(strerror(errno));
+      else
+       return false;
+    
+    dgram.assign(d_buffer,bytes);
+    ep.address.byte=remote.sin_addr.s_addr;
+    ep.port=ntohs(remote.sin_port);
+    return true;
+  }
+
+
   //! For datagram sockets, send a datagram to a destination
   /** For datagram sockets, send a datagram to a destination
       \param dgram The datagram