]> granicus.if.org Git - pdns/commitdiff
further interim
authorbert hubert <bert.hubert@netherlabs.nl>
Fri, 23 Oct 2015 10:48:14 +0000 (12:48 +0200)
committerbert hubert <bert.hubert@netherlabs.nl>
Fri, 23 Oct 2015 10:48:14 +0000 (12:48 +0200)
pdns/Makefile.am
pdns/ixplore.cc

index ead56997a278f4340d01a829cf67fb0e5370ba32..b4bd4e31008027bc77a40e5ce702134898dc5742 100644 (file)
@@ -591,7 +591,7 @@ ixplore_SOURCES = \
        sillyrecords.cc \
        sstuff.hh \
        statbag.cc \
-       unix_utility.cc
+       unix_utility.cc zoneparser-tng.cc
 
 ixplore_LDADD = $(MBEDTLS_LIBS)
 
index f4f6cafc72df0a9472b8e88fbfa7c373a6189e0a..c1b6923925f4e7ec57cb236f91add7c7f2468bb9 100644 (file)
 #include <boost/foreach.hpp>
 #include "dns_random.hh"
 #include "gss_context.hh"
-
+#include "zoneparser-tng.hh"
+#include <boost/multi_index_container.hpp>
+#include <fstream>
+using namespace boost::multi_index;
 StatBag S;
 
+struct CanonStruct : public std::binary_function<DNSName, DNSName, bool>
+{
+  bool operator()(const DNSName&a, const DNSName& b) const
+  {
+    return a.canonCompare(b);
+  }
+};
+
+struct CIContentCompareStruct
+{
+  bool operator()(const shared_ptr<DNSRecordContent>&a, const shared_ptr<DNSRecordContent>& b) const
+  {
+    return toLower(a->getZoneRepresentation()) < toLower(b->getZoneRepresentation());
+  }
+};
+
+
+typedef multi_index_container<
+  DNSRecord,
+    indexed_by<
+      ordered_non_unique<
+        composite_key<DNSRecord,
+                     member<DNSRecord, DNSName, &DNSRecord::d_name>,
+                     member<DNSRecord, uint16_t, &DNSRecord::d_type>,
+                     member<DNSRecord, uint16_t, &DNSRecord::d_class>,
+                     member<DNSRecord, shared_ptr<DNSRecordContent>, &DNSRecord::d_content> >,
+                     composite_key_compare<CanonStruct, std::less<uint16_t>, std::less<uint16_t>, CIContentCompareStruct >
+                     
+      >
+    >
+  >records_t;
+
+uint32_t getSerial(const ComboAddress& master, const DNSName& zone, shared_ptr<SOARecordContent>& sr)
+{
+  vector<uint8_t> packet;
+  DNSPacketWriter pw(packet, zone, QType::SOA);
+  
+  Socket s(master.sin4.sin_family, SOCK_DGRAM);
+  s.connect(master);
+  string msg((const char*)&packet[0], packet.size());
+  s.writen(msg);
+
+  string reply;
+  s.read(reply);
+  MOADNSParser mdp(reply);
+  for(const auto& r: mdp.d_answers) {
+    if(r.first.d_type == QType::SOA) {
+      sr = std::dynamic_pointer_cast<SOARecordContent>(r.first.d_content);
+      cout<<"Current serial number: "<<sr->d_st.serial<<endl;
+      return sr->d_st.serial;
+    }
+  }
+  return 0;
+}
+
+vector<pair<vector<DNSRecord>, vector<DNSRecord> > >   getIXFRDeltas(const ComboAddress& master, const DNSName& zone, shared_ptr<SOARecordContent> sr)
+{
+  vector<pair<vector<DNSRecord>, vector<DNSRecord> > >  ret;
+  vector<uint8_t> packet;
+  DNSPacketWriter pw(packet, zone, QType::IXFR);
+  pw.getHeader()->qr=0;
+  pw.getHeader()->rd=0;
+  pw.startRecord(zone, QType::SOA, 3600, QClass::IN, DNSPacketWriter::AUTHORITY);
+  sr->toPacket(pw);
+  pw.commit();
+  
+  
+  uint16_t len=htons(packet.size());
+  string msg((const char*)&len, 2);
+  msg.append((const char*)&packet[0], packet.size());
+
+  Socket s(master.sin4.sin_family, SOCK_STREAM);
+  s.connect(master);
+  s.writen(msg);
+
+  // CURRENT MASTER SOA
+  // REPEAT:
+  //   SOA WHERE THIS DELTA STARTS
+  //   RECORDS TO REMOVE
+  //   SOA WHERE THIS DELTA GOES
+  //   RECORDS TO ADD
+  // CURRENT MASTER SOA 
+  shared_ptr<SOARecordContent> masterSOA;
+  vector<DNSRecord> records;
+  for(;;) {
+    if(s.read((char*)&len, 2)!=2)
+      break;
+    len=ntohs(len);
+    //    cout<<"Got chunk of "<<len<<" bytes"<<endl;
+    if(!len)
+      break;
+    char reply[len]; 
+    readn2(s.getHandle(), reply, len);
+    MOADNSParser mdp(string(reply, len));
+    //    cout<<"Got a response, rcode: "<<mdp.d_header.rcode<<", got "<<mdp.d_answers.size()<<" answers"<<endl;
+    for(auto& r: mdp.d_answers) {
+      r.first.d_name = r.first.d_name.makeRelative(zone);
+      records.push_back(r.first);
+      if(r.first.d_type == QType::SOA) {
+       auto sr = std::dynamic_pointer_cast<SOARecordContent>(r.first.d_content);
+       if(!masterSOA) {
+         masterSOA=sr;
+       }
+       else if(sr->d_st.serial == masterSOA->d_st.serial)
+         goto done;
+
+      }
+    }
+  }
+ done:;
+  for(unsigned int pos = 1;pos < records.size();) {
+    auto sr = std::dynamic_pointer_cast<SOARecordContent>(records[pos].d_content);
+    if(sr->d_st.serial == masterSOA->d_st.serial)
+      break;
+    
+    //    cout<<"Got delta going from "<<sr->d_st.serial<<endl;
+    vector<DNSRecord> remove, add;
+    remove.push_back(records[pos]); // this adds the SOA
+    for(pos++; pos < records.size() && records[pos].d_type != QType::SOA; ++pos) {
+      // cout<<"Should remove "<<records[pos].d_name<<" "<<DNSRecordContent::NumberToType(records[pos].d_type)<<" "<<records[pos].d_content->getZoneRepresentation()<<endl;
+      remove.push_back(records[pos]);
+    }
+    sr = std::dynamic_pointer_cast<SOARecordContent>(records[pos].d_content);
+    //    cout<<"This delta goes to "<<sr->d_st.serial<<endl;
+    add.push_back(records[pos]); // this adds the new SOA
+    for(pos++; pos < records.size() && records[pos].d_type != QType::SOA; ++pos)  {
+      //      cout<<"Should ADD "<<records[pos].d_name<<" "<<DNSRecordContent::NumberToType(records[pos].d_type)<<" "<<records[pos].d_content->getZoneRepresentation()<<endl;
+      add.push_back(records[pos]);
+    }
+    ret.push_back(make_pair(remove,add));
+    //    cout<<"End of this delta"<<endl<<endl;
+  }
+  
+  return ret;
+  
+}
+
+uint32_t getHighestSerialFromDir(const std::string& dir)
+{
+  return 1445497587;
+}
+
+bool canonCompare(const DNSRecord& a, const DNSRecord& b)
+{
+  if(a.d_name.canonCompare(b.d_name))
+    return true;
+  if(a.d_name!=b.d_name) {
+    return false;
+  }
+  string lzrp, rzrp;
+  if(a.d_content)
+    lzrp=toLower(a.d_content->getZoneRepresentation());
+  if(b.d_content)
+    rzrp=toLower(b.d_content->getZoneRepresentation());
+  auto atype = a.d_type == QType::SOA ? 0 : a.d_type;
+  auto btype = b.d_type == QType::SOA ? 0 : b.d_type;
+  
+  return tie(atype, a.d_class, lzrp) <
+         tie(btype, b.d_class, rzrp);
+}
 
 int main(int argc, char** argv)
 try
@@ -26,9 +189,8 @@ try
   }
 
   reportAllTypes();
-  dns_random_init("0123456789abcdef");
 
-  /* goal in life:
+    /* goal in life:
      in directory/zone-name we leave files with their name the serial number
      at startup, retrieve current SOA SERIAL for domain from master server
      
@@ -38,26 +200,82 @@ try
      Next up, loop this every REFRESH seconds */
 
   DNSName zone(argv[3]);
-  vector<uint8_t> packet;
-  DNSPacketWriter pw(packet, zone, QType::SOA);
+  
   ComboAddress master(argv[1], atoi(argv[2]));
 
-  Socket s(master.sin4.sin_family, SOCK_DGRAM);
-  s.connect(master);
-  string msg((const char*)&packet[0], packet.size());
-  s.writen(msg);
+  shared_ptr<SOARecordContent> sr;
+  uint32_t serial = getSerial(master, zone, sr);
+  uint32_t ourSerial = getHighestSerialFromDir(argv[4]);
 
-  string reply;
-  s.read(reply);
-  MOADNSParser mdp(reply);
-  for(const auto& r: mdp.d_answers) {
-    if(r.first.d_type == QType::SOA) {
-      auto sr = std::dynamic_pointer_cast<SOARecordContent>(r.first.d_content);
-      cout<<"Current serial number: "<<sr->d_st.serial<<endl;
-    }
+  cout<<"Our serial: "<<ourSerial<<", their serial: "<<serial<<endl;
+
+  ZoneParserTNG zpt(argv[4]+string("/")+std::to_string(ourSerial), zone);
+  DNSResourceRecord rr;
+  unsigned int nrecords=0;
+  records_t records;
+
+  while(zpt.get(rr)) {
+    ++nrecords;
+    if(rr.qtype.getCode() == QType::CNAME && rr.content.empty())
+      rr.content=".";
+    rr.qname = rr.qname.makeRelative(zone);
+    records.insert(DNSRecord(rr));
   }
-  
 
+  cout<<"Parsed "<<nrecords<<" records"<<endl;
+  sr->d_st.serial= ourSerial;
+
+  auto deltas = getIXFRDeltas(master, zone, sr);
+  cout<<"Got "<<deltas.size()<<" deltas, applying.."<<endl;
+  int oldserial;
+  for(const auto& delta : deltas) {
+    for(const auto& r : records) {
+      if(r.d_type == QType::SOA) {
+       oldserial=std::dynamic_pointer_cast<SOARecordContent>(r.d_content)->d_st.serial;
+       cout<<"Serial before application: "<< oldserial  <<endl;
+       break;
+      }
+    }
+
+    const auto& remove = delta.first;
+    const auto& add = delta.second;
+    set<DNSRecord> toremove;
+    ofstream report(string(argv[4]) +"/delta."+std::to_string(oldserial));
+    for(const auto& rr : remove) {
+      auto range = records.equal_range(tie(rr.d_name, rr.d_type, rr.d_class, rr.d_content));
+      if(range.first == range.second) {
+       cerr<<"Could not find record "<<rr.d_name<<" to remove!!"<<endl;
+       exit(1);
+      }
+      if(rr.d_type == QType::SOA) {
+       cout<<"Serial to remove:  "<< std::dynamic_pointer_cast<SOARecordContent>(rr.d_content)->d_st.serial <<endl;
+      }
+      records.erase(range.first, range.second);
+      report<<'-'<< (rr.d_name+zone) <<" IN "<<DNSRecordContent::NumberToType(rr.d_type)<<" "<<rr.d_content->getZoneRepresentation()<<endl;
+    }
+    cout<<"Adding "<<add.size()<<" records now"<<endl;
+
+    uint32_t newserial=0;
+    for(const auto& rr : add) {
+      if(rr.d_type == QType::SOA) {
+       newserial=std::dynamic_pointer_cast<SOARecordContent>(rr.d_content)->d_st.serial;
+       cout<<"Serial to ADD:  "<< newserial <<endl;
+      }
+      report<<'+'<< (rr.d_name+zone) <<" IN "<<DNSRecordContent::NumberToType(rr.d_type)<<" "<<rr.d_content->getZoneRepresentation()<<endl;
+      records.insert(rr);
+    }
+    if(newserial == serial) {
+      FILE* fp=fopen((string(argv[4]) +"/"+std::to_string(newserial)).c_str(), "w");
+      for(const auto& r: records) {
+       fprintf(fp, "%s\t%d\tIN\t%s\t%s\n", (r.d_name+zone).toString().c_str(),
+               r.d_ttl,
+               DNSRecordContent::NumberToType(r.d_type).c_str(),
+               r.d_content->getZoneRepresentation().c_str());
+      }
+      fclose(fp);
+      
+    }
+  }
 }
 catch(PDNSException &e2) {
   cerr<<"Fatal: "<<e2.reason<<endl;