]> granicus.if.org Git - pdns/commitdiff
yolocommit, but it does track a zone. Once.
authorbert hubert <bert.hubert@powerdns.com>
Tue, 31 May 2016 15:02:13 +0000 (17:02 +0200)
committerbert hubert <bert.hubert@powerdns.com>
Tue, 7 Jun 2016 09:25:01 +0000 (11:25 +0200)
pdns/Makefile.am
pdns/communicator.cc
pdns/communicator.hh
pdns/dynhandler.cc
pdns/ixfr.cc
pdns/slavecommunicator.cc
pdns/sstuff.hh
pdns/ws-auth.cc

index 4434692c61fc5423aee7faf12c4739a3d9c050dd..ff5dd7c80e1dd7f33dc02413961a13862444de2b 100644 (file)
@@ -165,6 +165,7 @@ pdns_server_SOURCES = \
        ednssubnet.cc ednssubnet.hh \
        gss_context.cc gss_context.hh \
        iputils.cc iputils.hh \
+       ixfr.cc ixfr.hh \
        json.cc json.hh \
        lock.hh \
        logger.cc logger.hh \
index 28543082c07a4b7bf486d8609df1465a7d621784..cba4180e2f155d9a437ff56e72d59a1aeca559c2 100644 (file)
@@ -52,7 +52,7 @@ void CommunicatorClass::retrievalLoopThread(void)
       sr=d_suckdomains.front();
       d_suckdomains.pop_front();
     }
-    suck(sr.domain,sr.master);
+    suck(sr.domain, sr.master, sr.currentSerial ? &sr.currentSerial : 0);
   }
 }
 
index b4356d9add54735e8180d9e309460178f8c27cd7..a1e84319f158b7aba354d0fd769d44b91d9096d2 100644 (file)
@@ -46,6 +46,7 @@ struct SuckRequest
 {
   DNSName domain;
   string master;
+  uint32_t currentSerial;
   bool operator<(const SuckRequest& b) const
   {
     return tie(domain, master) < tie(b.domain, b.master);
@@ -164,7 +165,7 @@ public:
   
   void drillHole(const DNSName &domain, const string &ip);
   bool justNotified(const DNSName &domain, const string &ip);
-  void addSuckRequest(const DNSName &domain, const string &master);
+  void addSuckRequest(const DNSName &domain, const string &master, uint32_t curser);
   void addSlaveCheckRequest(const DomainInfo& di, const ComboAddress& remote);
   void addTrySuperMasterRequest(DNSPacket *p);
   void notify(const DNSName &domain, const string &ip);
@@ -190,7 +191,9 @@ private:
   map<pair<DNSName,string>,time_t>d_holes;
   pthread_mutex_t d_holelock;
   void launchRetrievalThreads();
-  void suck(const DNSName &domain, const string &remote);
+  void suck(const DNSName &domain, const string &remote, uint32_t* curser);
+  void ixfrSuck(const DNSName &domain, const string &remote, uint32_t curser);
+
   void slaveRefresh(PacketHandler *P);
   void masterUpdateCheck(PacketHandler *P);
   pthread_mutex_t d_lock;
index 3e2d5fbd410a686abcfd41bddde2ce73c6b29779..f1e6833ee3f272bb8ea089c83cfab27ac745058b 100644 (file)
@@ -251,7 +251,7 @@ string DLNotifyRetrieveHandler(const vector<string>&parts, Utility::pid_t ppid)
     return "Domain '"+domain.toString()+"' is not a slave domain (or has no master defined)";
 
   random_shuffle(di.masters.begin(), di.masters.end());
-  Communicator.addSuckRequest(domain, di.masters.front());
+  Communicator.addSuckRequest(domain, di.masters.front(), 0); // we don't know serial
   return "Added retrieval request for '"+domain.toString()+"' from master "+di.masters.front();
 }
 
index 7e53f938b0d292846b526e88cc03994facd15f87..b30b84f06fbc8944d4dbd95ba7708fdee9dc5ddb 100644 (file)
@@ -39,6 +39,8 @@ vector<pair<vector<DNSRecord>, vector<DNSRecord> > > getIXFRDeltas(const ComboAd
 
   Socket s(master.sin4.sin_family, SOCK_STREAM);
   //  cout<<"going to connect"<<endl;
+  ComboAddress local("2001:470:1f15:86f:4413:6149:48d1:16a3", 0);
+  s.bind(local);
   s.connect(master);
   //  cout<<"Connected"<<endl;
   s.writen(msg);
index 0c26c1649be9ff182dc3689ed317564391487336..86e0de91559fcc5e2280430a838a796a380a2502 100644 (file)
@@ -1,6 +1,6 @@
 /*
     PowerDNS Versatile Database Driven Nameserver
-    Copyright (C) 2002-2012  PowerDNS.COM BV
+    Copyright (C) 2002-2016  PowerDNS.COM BV
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License version 2 as
 #include "namespaces.hh"
 #include "common_startup.hh"
 #include <boost/scoped_ptr.hpp>
+#include "ixfr.hh"
 using boost::scoped_ptr;
 
 
-void CommunicatorClass::addSuckRequest(const DNSName &domain, const string &master)
+void CommunicatorClass::addSuckRequest(const DNSName &domain, const string &master, uint32_t curser)
 {
   Lock l(&d_lock);
   SuckRequest sr;
   sr.domain = domain;
   sr.master = master;
+  sr.currentSerial = curser;
   pair<UniQueue::iterator, bool>  res;
 
   res=d_suckdomains.push_back(sr);
@@ -64,8 +66,106 @@ void CommunicatorClass::addSuckRequest(const DNSName &domain, const string &mast
   }
 }
 
-void CommunicatorClass::suck(const DNSName &domain,const string &remote)
+void CommunicatorClass::ixfrSuck(const DNSName &domain, const string &remote, uint32_t curser)
 {
+  UeberBackend B; // fresh UeberBackend
+
+  DomainInfo di;
+  di.backend=0;
+  //  bool transaction=false;
+  try {
+    DNSSECKeeper dk (&B); // reuse our UeberBackend copy for DNSSECKeeper
+
+    if(!B.getDomainInfo(domain, di) || !di.backend) { // di.backend and B are mostly identical
+      L<<Logger::Error<<"Can't determine backend for domain '"<<domain<<"'"<<endl;
+      return;
+    }
+    //    uint32_t domain_id=di.id;
+
+    TSIGTriplet tt;
+    if(dk.getTSIGForAccess(domain, remote, &tt.name)) {
+      string tsigsecret64;
+      if(B.getTSIGKey(tt.name, &tt.algo, &tsigsecret64)) {
+        if(B64Decode(tsigsecret64, tt.secret)) {
+          L<<Logger::Error<<"Unable to Base-64 decode TSIG key '"<<tt.name<<"' for domain '"<<domain<<"' not found"<<endl;
+          return;
+        }
+      } else {
+        L<<Logger::Error<<"TSIG key '"<<tt.name<<"' for domain '"<<domain<<"' not found"<<endl;
+        return;
+      }
+    }
+
+    soatimes st;
+    memset(&st, 0, sizeof(st));
+    st.serial=curser;
+
+    DNSRecord dr;
+    dr.d_content = std::make_shared<SOARecordContent>(DNSName("."), DNSName("."), st);
+    auto deltas = getIXFRDeltas(ComboAddress(remote, 53), domain, dr, tt);
+    cout<<"Got "<<deltas.size()<<" deltas from serial "<<curser<<", applying.."<<endl;
+    cout<<"ID: "<<di.id<<endl;
+    
+    for(const auto& d : deltas) {
+      const auto& before= d.first;
+      const auto& after = d.second;
+      
+      // our hammer is 'replaceRRSet(domain_id, qname, qt, vector<DNSResourceRecord>& rrset)
+      // first thing we need to do is delete every {qname/qt} present in before and not in after
+      
+      typedef set<pair<DNSName,uint16_t>> present_t;
+      present_t pbefore, pafter;
+      for(const auto& b: before)
+        pbefore.insert({b.d_name, b.d_type});
+      for(const auto& a: after)
+        pafter.insert({a.d_name, a.d_type});
+
+      vector<pair<DNSName,uint16_t>> diff;
+    
+      set_difference(pbefore.cbegin(), pbefore.cend(), pafter.cbegin(), pafter.cend(), back_inserter(diff));
+
+      di.backend->startTransaction(domain, -1);
+      for(const auto& gone : diff) {
+        cerr<<"Removing "<<gone.first<<"/"<<QType(gone.second).getName()<<endl;
+        di.backend->replaceRRSet(di.id, gone.first+domain, QType(gone.second), vector<DNSResourceRecord>());
+      }
+
+      map<pair<DNSName,uint16_t>, vector<DNSResourceRecord>> replacement;
+      
+      for(const auto& add : after) {
+        DNSResourceRecord dr(add);
+        dr.qname += domain;
+        dr.domain_id=di.id;
+        replacement[{add.d_name, add.d_type}].push_back(dr);
+      }
+      for(const auto& rep : replacement) {
+        cerr<<"Adding back in "<<rep.first.first<<"/"<<QType(rep.first.second).getName()<<": "<<rep.second.begin()->content<<endl;
+        di.backend->replaceRRSet(di.id, rep.first.first+domain, QType(rep.first.second), rep.second);
+      }
+      cerr<<"And commit!"<<endl;
+      di.backend->commitTransaction();
+    }
+
+    exit(1);
+
+  }
+  catch(std::exception& p) {
+    cerr<<"Got exception: "<<p.what()<<endl;
+    exit(1);
+  }
+  catch(PDNSException& p) {
+    cerr<<"Got exception: "<<p.reason<<endl;
+    exit(1);
+  }
+
+  
+}
+
+
+void CommunicatorClass::suck(const DNSName &domain, const string &remote, uint32_t* curser)
+{
+  if(curser)
+    return ixfrSuck(domain, remote, *curser);
   L<<Logger::Error<<"Initiating transfer of '"<<domain<<"' from remote '"<<remote<<"'"<<endl;
   UeberBackend B; // fresh UeberBackend
 
@@ -573,6 +673,7 @@ void CommunicatorClass::slaveRefresh(PacketHandler *P)
       std::vector<std::string> localaddr;
       SuckRequest sr;
       sr.domain=di.zone;
+      sr.currentSerial = di.serial;
       if(di.masters.empty()) // slave domains w/o masters are ignored
         continue;
       // remove unfresh domains already queued for AXFR, no sense polling them again
@@ -684,13 +785,13 @@ void CommunicatorClass::slaveRefresh(PacketHandler *P)
         }
         else {
           L<<Logger::Warning<<"Domain '"<< di.zone<<"' is fresh, but RRSIGS differ, so DNSSEC stale"<<endl;
-          addSuckRequest(di.zone, *di.masters.begin());
+          addSuckRequest(di.zone, *di.masters.begin(), ourserial);
         }
       }
     }
     else {
       L<<Logger::Warning<<"Domain '"<< di.zone<<"' is stale, master serial "<<theirserial<<", our serial "<< ourserial <<endl;
-      addSuckRequest(di.zone, *di.masters.begin());
+      addSuckRequest(di.zone, *di.masters.begin(), ourserial);
     }
   }
 }
index 2630237b2234421989b79b405e57ab20fb055947..274577c92ea1bfe43d1a447090e7119f508f551c 100644 (file)
@@ -140,7 +140,7 @@ public:
   void connect(const ComboAddress &ep)
   {
     if(::connect(d_socket,(struct sockaddr *)&ep, ep.getSocklen()) < 0 && errno != EINPROGRESS)
-      throw NetworkError("While connecting: "+string(strerror(errno)));
+      throw NetworkError("While connecting to "+ep.toStringWithPort()+": "+string(strerror(errno)));
   }
 
 
index 61f4e92d2be3c49c50e08c7e0ac6ad3edceca2d8..72ef44cbc1a6eba4d41a337224ed8e62f2cdd010 100644 (file)
@@ -870,7 +870,7 @@ static void apiServerZoneAxfrRetrieve(HttpRequest* req, HttpResponse* resp) {
     throw ApiException("Domain '"+zonename.toString()+"' is not a slave domain (or has no master defined)");
 
   random_shuffle(di.masters.begin(), di.masters.end());
-  Communicator.addSuckRequest(zonename, di.masters.front());
+  Communicator.addSuckRequest(zonename, di.masters.front(), 0);
   resp->setSuccessResult("Added retrieval request for '"+zonename.toString()+"' from master "+di.masters.front());
 }