- 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
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
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
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>
#include "qtype.hh"
#include "misc.hh"
#include "dynlistener.hh"
+#include "lock.hh"
using namespace std;
map<unsigned int,BBDomainInfo> BindBackend::d_bbds;
int BindBackend::s_first=1;
+pthread_mutex_t BindBackend::s_startup_lock=PTHREAD_MUTEX_INITIALIZER;
BBDomainInfo::BBDomainInfo()
{
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)
{
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;
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)
soadata.serial=0;
soadata.refresh=0;
soadata.serial=0;
+
try {
getSOA(i->second.d_name,soadata); // we might not *have* a SOA yet
}
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;
}
{
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"))
}
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;
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;
time_t d_last_check;
string d_master;
int d_confcount;
+ u_int32_t d_lastnotified;
bool tryRLock()
{
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;
string d_logprefix;
int d_transaction_id;
+ string d_transaction_tmpname;
ofstream *d_of;
handle *d_handle;
void queueReload(BBDomainInfo *bbd);
}
// 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)
}
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;
}
// 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)
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);
}
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) {
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;
}
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
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;
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;
}
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);
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);