]> granicus.if.org Git - pdns/commitdiff
heaps of work again
authorBert Hubert <bert.hubert@netherlabs.nl>
Fri, 20 Dec 2002 14:25:29 +0000 (14:25 +0000)
committerBert Hubert <bert.hubert@netherlabs.nl>
Fri, 20 Dec 2002 14:25:29 +0000 (14:25 +0000)
git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@91 d19b8d6e-7fed-0310-83ef-9ca221ded41b

ChangeLog
TODO
pdns/backends/bind/bindbackend.cc
pdns/backends/bind/bindbackend.hh
pdns/communicator.cc
pdns/dnsbackend.hh
pdns/dynhandler.cc
pdns/misc.cc
pdns/misc.hh

index 1ed88029c7efd6c419a8482009d6be300a20a39f..45fc08a82ce2366625d9d475cb9380937f97bca8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -13,6 +13,8 @@ Changes since 2.9.2:
        - lots of bind backend work
                - we now ignore 'hint' 'forward' whatever zones
        - added 'bind-domain-status', 'bind-reload-now'
+       - added 'retrieve'
+       - bind zones are now way smaller on disk
        - 'notify' no longer prints out garbage to pdns_control
        - more verbose logging of AXFRs - is a heavy operation already,
          logging won't add much to that
diff --git a/TODO b/TODO
index ca31cea8eb1f40f6be10e505539cb91f70fe801c..06b5b4c299ec50a7feb7027fc56ff8d320b3af86 100644 (file)
--- a/TODO
+++ b/TODO
@@ -20,11 +20,8 @@ Medium size things:
          non-resolving bind. We're 90% there.
                - improve atomic zone swapping
                        right now we are SOL if we try to reload a broken zone
-               - write out $ORIGIN statements on file that came in over AXFR
-               - make sure its name can be changed and that everything
-                       changes with it
-               - right now, bindbackend accepts out of zone records!
                - bind backend does not do proper notifications!
+               - writes tmp file to /tmp/wuh!
 
        - get PDNS into Red Hat 8.x 
                needs very good RPMS    
index 5b8439fc8bdda18aa05b7d3b806788ab6abe0834..492eef2da86664636b2642dcfbecabe81c01ed17 100644 (file)
@@ -3,9 +3,8 @@
     Copyright (C) 2002  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 as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
+    it under the terms of the GNU General Public License version 2 as 
+    published by the Free Software Foundation; 
 
     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -16,7 +15,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: bindbackend.cc,v 1.7 2002/12/19 20:15:55 ahu Exp $ 
+// $Id: bindbackend.cc,v 1.8 2002/12/20 14:25:29 ahu Exp $ 
 #include <errno.h>
 #include <string>
 #include <map>
@@ -40,6 +39,7 @@ using namespace std;
 #include "qtype.hh"
 #include "misc.hh"
 #include "dynlistener.hh"
+#include "lock.hh"
 using namespace std;
 
 
@@ -51,6 +51,7 @@ HuffmanCodec BindBackend::s_hc;
 map<unsigned int,BBDomainInfo> BindBackend::d_bbds;
 
 int BindBackend::s_first=1;
+pthread_mutex_t BindBackend::s_startup_lock=PTHREAD_MUTEX_INITIALIZER;
 
 BBDomainInfo::BBDomainInfo()
 {
@@ -98,6 +99,10 @@ void BBDomainInfo::setCtime()
   d_ctime=buf.st_ctime;
 }
 
+void BindBackend::setNotified(u_int32_t id, u_int32_t serial)
+{
+  d_bbds[id].d_lastnotified=serial;
+}
 
 void BindBackend::setFresh(u_int32_t domain_id)
 {
@@ -106,48 +111,69 @@ void BindBackend::setFresh(u_int32_t domain_id)
 
 bool BindBackend::startTransaction(const string &qname, int id)
 {
-  d_of=new ofstream("/tmp/juh");
-  if(!d_of)
-    throw AhuException("Unable to open temporary zonefile!");
+  BBDomainInfo &bbd=d_bbds[d_transaction_id=id];
+  d_transaction_tmpname=bbd.d_filename+"."+itoa(random());
+  d_of=new ofstream(d_transaction_tmpname.c_str());
+  if(!*d_of) {
+    throw DBException("Unable to open temporary zonefile '"+d_transaction_tmpname+"': "+stringerror());
+    unlink(d_transaction_tmpname.c_str());
+    delete d_of;
+    d_of=0;
+  }
   
   *d_of<<"; Written by PowerDNS, don't edit!"<<endl;
-  d_bbds[d_transaction_id=id].lock();
+  *d_of<<"; Zone '"+bbd.d_name+"' retrieved from master "<<bbd.d_master<<endl<<"; at "<<nowTime()<<endl;
+  bbd.lock();
   return true;
 }
 
 bool BindBackend::commitTransaction()
 {
   delete d_of;
-  if(rename("/tmp/juh",d_bbds[d_transaction_id].d_filename.c_str())<0)
-    throw AhuException("Unable to commit (rename to: '"+d_bbds[d_transaction_id].d_filename+"') AXFRed zone: "+stringerror());
+  d_of=0;
+  if(rename(d_transaction_tmpname.c_str(),d_bbds[d_transaction_id].d_filename.c_str())<0)
+    throw DBException("Unable to commit (rename to: '"+d_bbds[d_transaction_id].d_filename+"') AXFRed zone: "+stringerror());
 
   queueReload(&d_bbds[d_transaction_id]);
   d_bbds[d_transaction_id].unlock();
   return true;
 }
 
+bool BindBackend::abortTransaction()
+{
+  delete d_of;
+  d_of=0;
+  unlink(d_transaction_tmpname.c_str());
+  return true;
+}
+
+
 
 bool BindBackend::feedRecord(const DNSResourceRecord &r)
 {
   string qname=r.qname;
   string domain=d_bbds[d_transaction_id].d_name;
-  if((r.qname.size()-toLower(r.qname).rfind(toLower(domain)))!=domain.size()) {   // XXX THIS CHECK IS WRONG! ds9a.nl != wuhds9a.nl!
-    throw DBException("out-of-zone data '"+r.qname+"' during AXFR of zone '"+domain+"'");
-  }
-  if(qname==domain)
-    qname="@";
-  else
-    qname.resize(qname.size()-domain.size()-1);
+
+  if(!stripDomainSuffix(&qname,domain)) 
+    throw DBException("out-of-zone data '"+qname+"' during AXFR of zone '"+domain+"'");
+
+  string content=r.content;
+
+  // SOA needs stripping too! XXX FIXME
   switch(r.qtype.getCode()) {
   case QType::TXT:
     *d_of<<qname<<"\t"<<r.ttl<<"\t"<<r.qtype.getName()<<"\t\""<<r.content<<"\""<<endl;
     break;
   case QType::MX:
-    *d_of<<qname<<"\t"<<r.ttl<<"\t"<<r.qtype.getName()<<"\t"<<r.priority<<"\t"<<r.content<<"."<<endl;
+    if(!stripDomainSuffix(&content,domain))
+      content+=".";
+    *d_of<<qname<<"\t"<<r.ttl<<"\t"<<r.qtype.getName()<<"\t"<<r.priority<<"\t"<<content<<endl;
     break;
   case QType::CNAME:
   case QType::NS:
-    *d_of<<qname<<"\t"<<r.ttl<<"\t"<<r.qtype.getName()<<"\t"<<r.content<<"."<<endl;
+    if(!stripDomainSuffix(&content,domain))
+      content+=".";
+    *d_of<<qname<<"\t"<<r.ttl<<"\t"<<r.qtype.getName()<<"\t"<<content<<endl;
     break;
   default:
     *d_of<<qname<<"\t"<<r.ttl<<"\t"<<r.qtype.getName()<<"\t"<<r.content<<endl;
@@ -159,6 +185,29 @@ bool BindBackend::feedRecord(const DNSResourceRecord &r)
 
 void BindBackend::getUpdatedMasters(vector<DomainInfo> *changedDomains)
 {
+  SOAData soadata;
+  for(map<u_int32_t,BBDomainInfo>::iterator i=d_bbds.begin();i!=d_bbds.end();++i) {
+    if(!i->second.d_master.empty())
+      continue;
+    soadata.serial=0;
+    try {
+      getSOA(i->second.d_name,soadata); // we might not *have* a SOA yet
+    }
+    catch(...){}
+    DomainInfo di;
+    di.id=i->first;
+    di.serial=soadata.serial;
+    di.zone=i->second.d_name;
+    di.last_check=i->second.d_last_check;
+    di.backend=this;
+    di.kind=DomainInfo::Master;
+    if(!i->second.d_lastnotified)            // don't do notification storm on startup 
+      i->second.d_lastnotified=soadata.serial;
+    else
+      if(soadata.serial!=i->second.d_lastnotified)
+       changedDomains->push_back(di);
+    
+  }
 }
 
 void BindBackend::getUnfreshSlaveInfos(vector<DomainInfo> *unfreshDomains)
@@ -177,6 +226,7 @@ void BindBackend::getUnfreshSlaveInfos(vector<DomainInfo> *unfreshDomains)
     soadata.serial=0;
     soadata.refresh=0;
     soadata.serial=0;
+
     try {
       getSOA(i->second.d_name,soadata); // we might not *have* a SOA yet
     }
@@ -197,6 +247,13 @@ bool BindBackend::getDomainInfo(const string &domain, DomainInfo &di)
       di.last_check=i->second.d_last_check;
       di.backend=this;
       di.kind=i->second.d_master.empty() ? DomainInfo::Master : DomainInfo::Slave;
+      di.serial=0;
+      try {
+       SOAData sd;
+       getSOA(i->second.d_name,sd); // we might not *have* a SOA yet
+       di.serial=sd.serial;
+      }
+      catch(...){}
 
       return true;
     }
@@ -371,8 +428,11 @@ BindBackend::BindBackend(const string &suffix)
 {
   d_logprefix="[bind"+suffix+"backend]";
   setArgPrefix("bind"+suffix);
-  if(!s_first)
+  Lock l(&s_startup_lock);
+
+  if(!s_first) {
     return;
+  }
    
   s_first=0;
   if(!mustDo("enable-huffman"))
@@ -465,9 +525,10 @@ void BindBackend::loadConfig(string* status)
          }
        if(j==d_bbds.end()) { // entirely new
          bbd.d_id=domain_id++;
-         bbd.setCtime();
+
          bbd.setCheckInterval(getArgAsNum("check-interval"));
-         nbbds[bbd.d_id].d_loaded=false;
+         bbd.d_lastnotified=0;
+         bbd.d_loaded=false;
        }
 
        bbd.d_name=i->name;
@@ -480,8 +541,10 @@ void BindBackend::loadConfig(string* status)
          
          try {
            ZP.parse(i->filename,i->name,bbd.d_id); // calls callback for us
+           nbbds[bbd.d_id].setCtime();
            nbbds[bbd.d_id].d_loaded=true;          // does this perform locking for us?
            nbbds[bbd.d_id].d_status="parsed into memory at "+nowTime();
+           
          }
          catch(AhuException &ae) {
            ostringstream msg;
index 28c501181a1efedc6ef1e5fec3efbefb2532b378..4f2d15a9977038e84c920294fe59ca34e22c20ec 100644 (file)
@@ -54,6 +54,7 @@ public:
   time_t d_last_check;
   string d_master;
   int d_confcount;
+  u_int32_t d_lastnotified;
 
   bool tryRLock()
   {
@@ -181,13 +182,15 @@ public:
 
   static DNSBackend *maker();
   static set<string> s_contents;
+  static pthread_mutex_t s_startup_lock;
 
   void setFresh(u_int32_t domain_id);
-
+  void setNotified(u_int32_t id, u_int32_t serial);
   bool startTransaction(const string &qname, int id);
   //  bool BindBackend::stopTransaction(const string &qname, int id);
   bool feedRecord(const DNSResourceRecord &r);
   bool commitTransaction();
+  bool abortTransaction();
   void insert(int id, const string &qname, const string &qtype, const string &content, int ttl, int prio);  
   void rediscover(string *status=0);
   static HuffmanCodec s_hc;
@@ -236,6 +239,7 @@ private:
 
   string d_logprefix;
   int d_transaction_id;
+  string d_transaction_tmpname;
   ofstream *d_of;
   handle *d_handle;
   void queueReload(BBDomainInfo *bbd);
index 0231a5fa41f8a88e5e7b5de8cc2971feec587889..81466b133e4ee08f7dfcc3fef6697a369f29e5b5 100644 (file)
@@ -150,14 +150,18 @@ void CommunicatorClass::queueNotifyDomain(const string &domain, DNSBackend *B)
   }
   
   // make calls to d_nq.add(domain, ip);
-  for(set<string>::const_iterator j=ips.begin();j!=ips.end();++j)
+  for(set<string>::const_iterator j=ips.begin();j!=ips.end();++j) {
+    L<<Logger::Warning<<"Queued notification of domain '"<<domain<<"' to "<<*j<<endl;
     d_nq.add(domain,*j);
+  }
   
   set<string>alsoNotify;
   B->alsoNotifies(domain, &alsoNotify);
   
-  for(set<string>::const_iterator j=alsoNotify.begin();j!=alsoNotify.end();++j)
+  for(set<string>::const_iterator j=alsoNotify.begin();j!=alsoNotify.end();++j) {
+    L<<Logger::Warning<<"Queued also-notification of domain '"<<domain<<"' to "<<*j<<endl;
     d_nq.add(domain,*j);
+  }
 }
 
 bool CommunicatorClass::notifyDomain(const string &domain)
@@ -170,7 +174,7 @@ bool CommunicatorClass::notifyDomain(const string &domain)
   }
   queueNotifyDomain(domain, P.getBackend());
   // call backend and tell them we sent out the notification - even though that is premature    
-  di.backend->setNotified(di.id,di.serial);   
+  di.backend->setNotified(di.id, di.serial);
 
   return true; 
 }
@@ -200,17 +204,11 @@ void CommunicatorClass::masterUpdateCheck(PacketHandler *P)
   // figure out A records of everybody needing notification
   // do this via the FindNS class, d_fns
   
-
   for(vector<DomainInfo>::const_iterator i=cmdomains.begin();i!=cmdomains.end();++i) {
+
     queueNotifyDomain(i->zone,P->getBackend());
     i->backend->setNotified(i->id,i->serial); 
   }
-
-
-
-  // call it a day
-  // day()
-
 }
 
 void CommunicatorClass::slaveRefresh(PacketHandler *P)
@@ -233,7 +231,8 @@ void CommunicatorClass::slaveRefresh(PacketHandler *P)
   
   for(vector<DomainInfo>::const_iterator i=sdomains.begin();i!=sdomains.end();++i) {
     d_slaveschanged=true;
-    u_int32_t theirserial=0;
+    u_int32_t ourserial=i->serial,theirserial=0;
+
     try {
       Resolver resolver;
       int res=resolver.getSoaSerial(i->master,i->zone, &theirserial);
@@ -243,7 +242,7 @@ void CommunicatorClass::slaveRefresh(PacketHandler *P)
       }
       
       if(theirserial<i->serial) {
-       L<<Logger::Error<<"Domain "<<i->zone<<" more recent than master, our serial "<<i->serial<<" > their serial "<<theirserial<<endl;
+       L<<Logger::Error<<"Domain "<<i->zone<<" more recent than master, our serial "<<ourserial<<" > their serial "<<theirserial<<endl;
        i->backend->setFresh(i->id);
       }
       else if(theirserial==i->serial) {
@@ -291,8 +290,9 @@ int CommunicatorClass::doNotifications()
 
     if(p.d.rcode)
       L<<Logger::Warning<<"Received unsuccesful notification report for '"<<p.qdomain<<"' from "<<p.getRemote()<<", rcode: "<<p.d.rcode<<endl;      
-    else if(d_nq.removeIf(p.getRemote(), p.d.id, p.qdomain))
-      L<<Logger::Warning<<"Received valid notify answer for '"<<p.qdomain<<"' from "<<p.getRemote()<<endl;      
+    
+    if(d_nq.removeIf(p.getRemote(), p.d.id, p.qdomain))
+      L<<Logger::Warning<<"Removed from notification list: '"<<p.qdomain<<"' to "<<p.getRemote()<< (p.d.rcode ? "" : " (was acknowledged)")<<endl;      
     else
       L<<Logger::Warning<<"Received spurious notify answer for '"<<p.qdomain<<"' from "<<p.getRemote()<<endl;      
   }
index 8faa44853df5feff3590c8c10d87096be3b57c5b..8483a222cda306bf29f7a8ba1208a746dc75316f 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: dnsbackend.hh,v 1.3 2002/12/19 16:20:14 ahu Exp $
+// $Id: dnsbackend.hh,v 1.4 2002/12/20 14:25:29 ahu Exp $
 /* (C) 2002 POWERDNS.COM BV  */
    
 #ifndef DNSBACKEND_HH
@@ -51,8 +51,8 @@ struct DomainInfo
   u_int32_t id;
   string zone;
   string master;
-  u_int32_t serial;
   u_int32_t notified_serial;
+  u_int32_t serial;
   time_t last_check;
   enum {Master,Slave,Native} kind;
   DNSBackend *backend;
index 52505e93efa8bb7fc3ed7f041c06cef740c2d9d4..c925f39d48357560c8286fe7ad32f78be4b05d7b 100644 (file)
@@ -193,6 +193,9 @@ string DLNotifyRetrieveHandler(const vector<string>&parts, Utility::pid_t ppid)
   if(!P.getBackend()->getDomainInfo(domain, di))
     return "Domain '"+domain+"' unknown";
   
+  if(di.master.empty())
+    return "Domain '"+domain+"' is not a slave domain (or has no master defined)";
+
   Communicator.addSuckRequest(domain,di.master);
   return "Added retrieval request for '"+domain+"' from master "+di.master;
 }
index da4a0382c21a1708bdcf0a3ea70914592718048e..be27c9e007482fc4367e9f6b231a5fd28bcfbaa5 100644 (file)
@@ -47,6 +47,25 @@ string nowTime()
   return t;
 }
 
+/** strips a domain suffix from a domain, returns true if it stripped */
+bool stripDomainSuffix(string *qname, const string &domain)
+{
+  if((qname->size()-toLower(*qname).rfind(toLower(domain)))!=domain.size()) {   
+    return false;
+
+  }
+  if(*qname==domain)
+    *qname="@";
+  else {
+    if((*qname)[qname->size()-domain.size()-1]!='.')
+      return false;
+
+    qname->resize(qname->size()-domain.size()-1);
+  }
+  return true;
+}
+
+
 int sendData(const char *buffer, int replen, int outsock)
 {
   u_int16_t nlen=htons(replen);
index 35a896c5fc6394e6227f71e9a8f51bf101faef61..d7041273f3f6820e7010814c854130bc7b721644 100644 (file)
@@ -46,6 +46,7 @@ string nowTime();
 int matchNetmask(const char *address, const char *omask);
 string humanDuration(time_t passed);
 void chomp(string &line, const string &delim);
+bool stripDomainSuffix(string *qname, const string &domain);
 void stripLine(string &line);
 string getHostname();
 string urlEncode(const string &text);