INCLUDES=-I../..
-noinst_LTLIBRARIES = libbindbackend.la libbind2backend.la
-
-libbindbackend_la_SOURCES=bindbackend.cc bindbackend.hh bindparser.yy \
-bindlexer.l zoneparser2.cc ../../misc.cc huffman.cc huffman.hh zoneparser.hh \
-bindparser.hh ../../unix_utility.cc
-
-libbindbackend_la_CXXFLAGS=$(AM_CXXFLAGS)
-libbindbackend_la_CFLAGS=$(AM_CFLAGS)
+noinst_LTLIBRARIES = libbind2backend.la
libbind2backend_la_SOURCES=bindbackend2.cc bindbackend2.hh bindparser.yy \
-bindlexer.l zoneparser2.cc ../../misc.cc huffman.cc huffman.hh zoneparser.hh \
+bindlexer.l ../../zoneparser-tng.cc ../../misc.cc huffman.cc huffman.hh \
bindparser.hh ../../unix_utility.cc
libbind2backend_la_CXXFLAGS=$(AM_CXXFLAGS)
bin_PROGRAMS = zone2sql zone2ldap
-zone2sql_SOURCES=bindparser.yy bindlexer.l zoneparser2.cc \
+zone2sql_SOURCES=bindparser.yy bindlexer.l \
../../arguments.cc ../../logger.cc zone2sql.cc ../../statbag.cc ../../misc.cc \
../../unix_utility.cc ../../qtype.cc ../../dnspacket.cc \
-../../sillyrecords.cc
+../../sillyrecords.cc ../../zoneparser-tng.cc ../../dnsrecords.cc \
+../../dnswriter.cc ../../rcpgenerator.cc ../../dnsparser.cc ../../base64.cc
-zone2ldap_SOURCES=bindparser.yy bindlexer.l zoneparser2.cc \
+
+zone2ldap_SOURCES=bindparser.yy bindlexer.l \
../../arguments.cc ../../logger.cc zone2ldap.cc ../../statbag.cc ../../misc.cc \
-../../unix_utility.cc ../../qtype.cc
+../../unix_utility.cc ../../qtype.cc ../../zoneparser-tng.cc ../../dnsrecords.cc \
+../../dnswriter.cc ../../rcpgenerator.cc ../../dnsparser.cc ../../base64.cc
+
zone2ldap_LDFLAGS=@THREADFLAGS@
+++ /dev/null
-/*
- PowerDNS Versatile Database Driven Nameserver
- 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 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
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-*/
-#include <errno.h>
-#include <string>
-#include <map>
-#include <set>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-using namespace std;
-
-#include "dns.hh"
-#include "dnsbackend.hh"
-#include "bindbackend.hh"
-#include "dnspacket.hh"
-
-#include "zoneparser.hh"
-#include "bindparser.hh"
-#include "logger.hh"
-#include "arguments.hh"
-#include "huffman.hh"
-#include "qtype.hh"
-#include "misc.hh"
-#include "dynlistener.hh"
-#include "lock.hh"
-using namespace std;
-
-
-cmap_t BindBackend::d_qnames;
-map<int,vector<vector<BBResourceRecord>* > > BindBackend::d_zone_id_map;
-set<string> BindBackend::s_contents;
-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()
-{
- d_loaded=false;
- d_last_check=0;
- d_checknow=false;
- d_rwlock=new pthread_rwlock_t;
- d_status="Seen in bind configuration";
- d_confcount=0;
- //cout<<"Generated a new bbdomaininfo: "<<(void*)d_rwlock<<"/"<<getpid()<<endl;
- pthread_rwlock_init(d_rwlock,0);
-}
-
-void BBDomainInfo::setCheckInterval(time_t seconds)
-{
- d_checkinterval=seconds;
-}
-
-bool BBDomainInfo::current()
-{
- if(d_checknow)
- return false;
-
- if(!d_checknow && !d_checkinterval || (time(0)-d_lastcheck<d_checkinterval) || d_filename.empty())
- return true;
-
- return (getCtime()==d_ctime);
-}
-
-time_t BBDomainInfo::getCtime()
-{
- struct stat buf;
-
- if(d_filename.empty() || stat(d_filename.c_str(),&buf)<0)
- return 0;
- d_lastcheck=time(0);
- return buf.st_ctime;
-}
-
-void BBDomainInfo::setCtime()
-{
- struct stat buf;
- if(stat(d_filename.c_str(),&buf)<0)
- return;
- d_ctime=buf.st_ctime;
-}
-
-void BindBackend::setNotified(uint32_t id, uint32_t serial)
-{
- d_bbds[id].d_lastnotified=serial;
-}
-
-void BindBackend::setFresh(uint32_t domain_id)
-{
- d_bbds[domain_id].d_last_check=time(0);
-}
-
-bool BindBackend::startTransaction(const string &qname, int id)
-{
- 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_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;
- 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();
- d_transaction_id=0;
- return true;
-}
-
-bool BindBackend::abortTransaction()
-{
- if(d_transaction_id) {
- d_bbds[d_transaction_id].unlock();
- delete d_of;
- d_of=0;
- unlink(d_transaction_tmpname.c_str());
- d_transaction_id=0;
- }
- return true;
-}
-
-
-
-bool BindBackend::feedRecord(const DNSResourceRecord &r)
-{
- string qname=r.qname;
- string domain=d_bbds[d_transaction_id].d_name;
-
- 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:
- 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:
- 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;
- break;
- }
-
- return true;
-}
-
-void BindBackend::getUpdatedMasters(vector<DomainInfo> *changedDomains)
-{
- SOAData soadata;
- for(map<uint32_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)
-{
- for(map<uint32_t,BBDomainInfo>::const_iterator i=d_bbds.begin();i!=d_bbds.end();++i) {
- if(i->second.d_master.empty())
- continue;
- DomainInfo sd;
- sd.id=i->first;
- sd.zone=i->second.d_name;
- sd.master=i->second.d_master;
- sd.last_check=i->second.d_last_check;
- sd.backend=this;
- sd.kind=DomainInfo::Slave;
- SOAData soadata;
- soadata.serial=0;
- soadata.refresh=0;
- soadata.serial=0;
- soadata.db=(DNSBackend *)-1; // not sure if this is useful, inhibits any caches that might be around
- try {
- getSOA(i->second.d_name,soadata); // we might not *have* a SOA yet
- }
- catch(...){}
- sd.serial=soadata.serial;
- if(sd.last_check+soadata.refresh<(unsigned int)time(0))
- unfreshDomains->push_back(sd);
- }
-}
-
-bool BindBackend::getDomainInfo(const string &domain, DomainInfo &di)
-{
- for(map<uint32_t,BBDomainInfo>::const_iterator i=d_bbds.begin();i!=d_bbds.end();++i) {
- if(i->second.d_name==domain) {
- di.id=i->first;
- di.zone=domain;
- di.master=i->second.d_master;
- 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;
- sd.serial=0;
-
- getSOA(i->second.d_name,sd); // we might not *have* a SOA yet
- di.serial=sd.serial;
- }
- catch(...){}
-
- return true;
- }
- }
- return false;
-}
-
-
-static string canonic(string ret)
-{
- string::iterator i;
-
- for(i=ret.begin();
- i!=ret.end();
- ++i)
- *i=*i; //tolower(*i);
-
-
- if(*(i-1)=='.')
- ret.resize(i-ret.begin()-1);
- return ret;
-}
-
-/** This function adds a record to a domain with a certain id. */
-void BindBackend::insert(int id, const string &qnameu, const string &qtype, const string &content, int ttl=300, int prio=25)
-{
- static int s_count;
- static unsigned int len;
- static unsigned int ulen;
- DLOG(
- if(!((s_count++)%10000))
- cerr<<"\r"<<s_count-1<<", "<<s_contents.size()<<" different contents, "<<d_qnames.size()<<" different qnames, "<<len/1000000<<"MB, saved: "<<
- (ulen-len)/1000;
- );
- string compressed;
- s_hc.encode(toLower(canonic(qnameu)),compressed);
- // string(compressed).swap(compressed);
- // cout<<"saved: "<<qnameu.size()-compressed.size()<<endl;
-
- vector<BBResourceRecord>::const_iterator i;
-
- if(d_qnames[compressed].empty()) { // NEW! NEW! NEW! in de top 40!
- d_zone_id_map[id].push_back(&d_qnames[compressed]);
- i=d_qnames[compressed].end();
- }
- else
- for(i=d_qnames[compressed].begin();i!=d_qnames[compressed].end();++i)
- if(((i)->qtype==QType::chartocode(qtype.c_str())))
- if((*(i)->content==canonic(content)))
- break;
-
- // never saw this specific name/type/content triple before
- if(i==d_qnames[compressed].end()) {
- BBResourceRecord v=resourceMaker(id,qtype,canonic(content),ttl,prio);
- v.qnameptr=&d_qnames.find(compressed)->first;
- len+=compressed.size();
- ulen+=qnameu.size();
- d_qnames[compressed].push_back(v);
-
- d_qnames[compressed].reserve(0);
- // vector<BBResourceRecord>&tmp=d_qnames[compressed];
- // vector<BBResourceRecord>(tmp).swap(tmp);
- }
- else {
- s_count--;
- }
-}
-
-
-/** Helper function that creates a BBResourceRecord and does s_content housekeeping */
-BBResourceRecord BindBackend::resourceMaker(int id, const string &qtype, const string &content, int ttl, int prio)
-{
- BBResourceRecord make;
-
- make.domain_id=id;
-
- make.qtype=QType::chartocode(qtype.c_str());
- if(!make.qtype)
- throw AhuException("Unknown qtype '"+qtype+"'"); // never leaves the BindBackend
-
- set<string>::const_iterator i=s_contents.find(content);
- if(i==s_contents.end()) {
- s_contents.insert(content);
- i=s_contents.find(content);
- }
- make.content=&*i;
- make.ttl=ttl;
- make.priority=prio;
- return make;
-}
-
-static BindBackend *us;
-
-void BindBackend::reload()
-{
- for(map<uint32_t,BBDomainInfo>::iterator i=us->d_bbds.begin();i!=us->d_bbds.end();++i)
- i->second.d_checknow=true;
-}
-
-string BindBackend::DLReloadNowHandler(const vector<string>&parts, Utility::pid_t ppid)
-{
- ostringstream ret;
- bool doReload=false;
- for(map<uint32_t,BBDomainInfo>::iterator j=us->d_bbds.begin();j!=us->d_bbds.end();++j) {
- doReload=false;
- if(parts.size()==1)
- doReload=true;
- else
- for(vector<string>::const_iterator i=parts.begin()+1;i<parts.end();++i) // O(N) badness XXX FIXME
- if(*i==j->second.d_name) {
- doReload=true;
- break;
- }
-
- if(doReload) {
- j->second.lock();
-
- us->queueReload(&j->second);
- j->second.unlock();
- ret<<j->second.d_name<< (j->second.d_loaded ? "": "[rejected]") <<"\t"<<j->second.d_status<<"\n";
- }
- doReload=false;
- }
-
- return ret.str();
-}
-
-
-string BindBackend::DLDomStatusHandler(const vector<string>&parts, Utility::pid_t ppid)
-{
- string ret;
- bool doPrint=false;
- for(map<uint32_t,BBDomainInfo>::iterator j=us->d_bbds.begin();j!=us->d_bbds.end();++j) {
- ostringstream line;
- doPrint=false;
- if(parts.size()==1)
- doPrint=true;
- else
- for(vector<string>::const_iterator i=parts.begin()+1;i<parts.end();++i) // O(N) badness XXX FIXME
- if(*i==j->second.d_name) {
- doPrint=true;
- break;
- }
-
- if(doPrint)
- line<<j->second.d_name<< (j->second.d_loaded ? "": "[rejected]") <<"\t"<<j->second.d_status<<"\n";
- doPrint=false;
- ret+=line.str();
- }
-
- return ret;
-}
-
-
-string BindBackend::DLListRejectsHandler(const vector<string>&parts, Utility::pid_t ppid)
-{
- ostringstream ret;
- for(map<uint32_t,BBDomainInfo>::iterator j=us->d_bbds.begin();j!=us->d_bbds.end();++j)
- if(!j->second.d_loaded)
- ret<<j->second.d_name<<"\t"<<j->second.d_status<<endl;
-
- return ret.str();
-}
-
-static void callback(unsigned int domain_id, const string &domain, const string &qtype, const string &content, int ttl, int prio)
-{
- us->insert(domain_id,domain,qtype,content,ttl,prio);
-}
-
-BindBackend::BindBackend(const string &suffix)
-{
- d_logprefix="[bind1"+suffix+"backend]";
- setArgPrefix("bind1"+suffix);
- Lock l(&s_startup_lock);
-
- d_transaction_id=0;
- if(!s_first) {
- return;
- }
-
- s_first=0;
- if(!mustDo("enable-huffman"))
- s_hc.passthrough(true);
-
- if(mustDo("example-zones")) {
- insert(0,"www.example.com","A","1.2.3.4");
- insert(0,"example.com","SOA","ns1.example.com hostmaster.example.com");
- insert(0,"example.com","NS","ns1.example.com",86400);
- insert(0,"example.com","NS","ns2.example.com",86400);
- insert(0,"example.com","MX","mail.example.com",3600,25);
- insert(0,"example.com","MX","mail1.example.com",3600,25);
- insert(0,"mail.example.com","A","4.3.2.1");
- insert(0,"mail1.example.com","A","5.4.3.2");
- insert(0,"ns1.example.com","A","4.3.2.1");
- insert(0,"ns2.example.com","A","5.4.3.2");
-
- for(int i=0;i<1000;i++)
- insert(0,"host-"+itoa(i)+".example.com","A","2.3.4.5");
-
- BBDomainInfo bbd;
- bbd.d_name="example.com";
- bbd.d_filename="";
- bbd.d_id=0;
- d_bbds[0]=bbd;
- d_bbds[0].d_loaded=true;
- d_bbds[0].d_status="parsed into memory at "+nowTime();
- }
-
- loadConfig();
-
-
- extern DynListener *dl;
- us=this;
- dl->registerFunc("BIND1-RELOAD-NOW", &DLReloadNowHandler);
- dl->registerFunc("BIND1-DOMAIN-STATUS", &DLDomStatusHandler);
- dl->registerFunc("BIND1-LIST-REJECTS", &DLListRejectsHandler);
-}
-
-
-void BindBackend::rediscover(string *status)
-{
- loadConfig(status);
-}
-
-void BindBackend::loadConfig(string* status)
-{
- static int domain_id=1;
-
- if(!getArg("config").empty()) {
- BindParser BP;
- try {
- BP.parse(getArg("config"));
- }
- catch(AhuException &ae) {
- L<<Logger::Error<<"Error parsing bind configuration: "<<ae.reason<<endl;
- throw;
- }
-
- ZoneParser ZP;
-
- vector<BindDomainInfo> domains=BP.getDomains();
-
- us=this;
-
- ZP.setDirectory(BP.getDirectory());
- ZP.setCallback(&callback);
- L<<Logger::Warning<<d_logprefix<<" Parsing "<<domains.size()<<" domain(s), will report when done"<<endl;
-
- int rejected=0;
- int newdomains=0;
-
- map<unsigned int, BBDomainInfo> nbbds;
-
- for(vector<BindDomainInfo>::const_iterator i=domains.begin();
- i!=domains.end();
- ++i)
- {
- BBDomainInfo bbd;
- if(i->type!="master" && i->type!="slave") {
- L<<Logger::Warning<<d_logprefix<<" Warning! Skipping '"<<i->type<<"' zone '"<<i->name<<"'"<<endl;
- continue;
- }
- map<unsigned int, BBDomainInfo>::const_iterator j=d_bbds.begin();
- for(;j!=d_bbds.end();++j)
- if(j->second.d_name==i->name) {
- bbd=j->second;
- break;
- }
- if(j==d_bbds.end()) { // entirely new
- bbd.d_id=domain_id++;
-
- bbd.setCheckInterval(getArgAsNum("check-interval"));
- bbd.d_lastnotified=0;
- bbd.d_loaded=false;
- }
-
- bbd.d_name=i->name;
- bbd.d_filename=i->filename;
- bbd.d_master=i->master;
-
- nbbds[bbd.d_id]=bbd;
- if(!bbd.d_loaded) {
- L<<Logger::Info<<d_logprefix<<" parsing '"<<i->name<<"' from file '"<<i->filename<<"'"<<endl;
-
- 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;
- msg<<" error at "+nowTime()+" parsing '"<<i->name<<"' from file '"<<i->filename<<"': "<<ae.reason;
- if(status)
- *status+=msg.str();
- nbbds[bbd.d_id].d_status=msg.str();
- L<<Logger::Warning<<d_logprefix<<msg.str()<<endl;
- rejected++;
- }
- }
-
- vector<vector<BBResourceRecord> *>&tmp=d_zone_id_map[bbd.d_id]; // shrink trick
- vector<vector<BBResourceRecord> *>(tmp).swap(tmp);
- }
-
-
- int remdomains=0;
- set<string> oldnames, newnames;
- for(map<unsigned int, BBDomainInfo>::const_iterator j=d_bbds.begin();j!=d_bbds.end();++j) {
- oldnames.insert(j->second.d_name);
- }
- for(map<unsigned int, BBDomainInfo>::const_iterator j=nbbds.begin();j!=nbbds.end();++j) {
- newnames.insert(j->second.d_name);
- }
-
- vector<string> diff;
- set_difference(oldnames.begin(), oldnames.end(), newnames.begin(), newnames.end(), back_inserter(diff));
- remdomains=diff.size();
- for(vector<string>::const_iterator k=diff.begin();k!=diff.end();++k)
- L<<Logger::Error<<"Removed: "<<*k<<endl;
-
- for(map<unsigned int, BBDomainInfo>::iterator j=d_bbds.begin();j!=d_bbds.end();++j) { // O(N*M)
- for(vector<string>::const_iterator k=diff.begin();k!=diff.end();++k)
- if(j->second.d_name==*k) {
- L<<Logger::Error<<"Removing records from zone '"<<j->second.d_name<<"' from memory"<<endl;
- j->second.lock();
- j->second.d_loaded=false;
- nukeZoneRecords(&j->second);
- j->second.unlock();
- break;
- }
- }
-
- vector<string> diff2;
- set_difference(newnames.begin(), newnames.end(), oldnames.begin(), oldnames.end(), back_inserter(diff2));
- newdomains=diff2.size();
-
- d_bbds.swap(nbbds); // commit
- ostringstream msg;
- msg<<" Done parsing domains, "<<rejected<<" rejected, "<<newdomains<<" new, "<<remdomains<<" removed";
- if(status)
- *status=msg.str();
-
- L<<Logger::Error<<d_logprefix<<msg.str()<<endl;
- L<<Logger::Info<<d_logprefix<<" Number of hash buckets: "<<d_qnames.bucket_count()<<", number of entries: "<<d_qnames.size()<< endl;
- }
-}
-
-/** nuke all records from memory, keep bbd intact though. Must be called with bbd lock held already! */
-void BindBackend::nukeZoneRecords(BBDomainInfo *bbd)
-{
- bbd->d_loaded=0; // block further access
-
- // this emtpies all d_qnames vectors belonging to this domain. We find these vectors via d_zone_id_map
- for(vector<vector<BBResourceRecord> *>::iterator i=d_zone_id_map[bbd->d_id].begin();
- i!=d_zone_id_map[bbd->d_id].end();++i) {
- (*i)->clear();
- }
-
- // empty our d_zone_id_map of the references to the now empty vectors (which are not gone from d_qnames, btw)
- d_zone_id_map[bbd->d_id].clear();
-}
-
-/** Must be called with bbd locked already. Will not be unlocked on return, is your own problem.
- Does not throw errors or anything, may update d_status however */
-
-
-void BindBackend::queueReload(BBDomainInfo *bbd)
-{
- // we reload *now* for the time being
- //cout<<"unlock domain"<<endl;
- bbd->unlock();
- //cout<<"lock it again"<<endl;
-
- bbd->lock();
- try {
- nukeZoneRecords(bbd);
-
- ZoneParser ZP;
- us=this;
- ZP.setCallback(&callback);
- ZP.parse(bbd->d_filename,bbd->d_name,bbd->d_id);
- bbd->setCtime();
- // and raise d_loaded again!
- bbd->d_loaded=1;
- bbd->d_checknow=0;
- bbd->d_status="parsed into memory at "+nowTime();
- L<<Logger::Warning<<"Zone '"<<bbd->d_name<<"' ("<<bbd->d_filename<<") reloaded"<<endl;
- }
- catch(AhuException &ae) {
- ostringstream msg;
- msg<<" error at "+nowTime()+" parsing '"<<bbd->d_name<<"' from file '"<<bbd->d_filename<<"': "<<ae.reason;
- bbd->d_status=msg.str();
- }
-}
-
-void BindBackend::lookup(const QType &qtype,const string &qname, DNSPacket *pkt_p, int zoneId )
-{
- d_handle=new BindBackend::handle;
- DLOG(L<<"BindBackend constructing handle for search for "<<qtype.getName()<<" for "<<
- qname<<endl);
-
- d_handle->qname=qname;
- d_handle->parent=this;
- d_handle->qtype=qtype;
- string compressed;
- s_hc.encode(toLower(qname),compressed);
- d_handle->d_records=d_qnames[compressed];
- d_handle->d_bbd=0;
- if(!d_handle->d_records.empty()) {
- BBDomainInfo& bbd=d_bbds[d_handle->d_records.begin()->domain_id];
- if(!bbd.d_loaded) {
- delete d_handle;
- throw DBException("Zone temporarily not available (file missing, or master dead)"); // fuck
- }
-
- if(!bbd.tryRLock()) {
- L<<Logger::Warning<<"Can't get read lock on zone '"<<bbd.d_name<<"'"<<endl;
- delete d_handle;
- throw DBException("Temporarily unavailable due to a zone lock"); // fuck
- }
-
-
- if(!bbd.current()) {
- L<<Logger::Warning<<"Zone '"<<bbd.d_name<<"' ("<<bbd.d_filename<<") needs reloading"<<endl;
- queueReload(&bbd);
- }
- d_handle->d_bbd=&bbd;
- }
- else {
- DLOG(L<<"Query with no results"<<endl);
- }
- d_handle->d_iter=d_handle->d_records.begin();
- d_handle->d_list=false;
-}
-
-BindBackend::handle::handle()
-{
- d_bbd=0;
- count=0;
-}
-
-bool BindBackend::get(DNSResourceRecord &r)
-{
- if(!d_handle->get(r)) {
- delete d_handle;
- d_handle=0;
- return false;
- }
- return true;
-}
-
-bool BindBackend::handle::get(DNSResourceRecord &r)
-{
- if(d_list)
- return get_list(r);
- else
- return get_normal(r);
-}
-
-bool BindBackend::handle::get_normal(DNSResourceRecord &r)
-{
- DLOG(L << "BindBackend get() was called for "<<qtype.getName() << " record for "<<
- qname<<"- "<<d_records.size()<<" available!"<<endl);
-
-
- while(d_iter!=d_records.end() && !(qtype=="ANY" || (d_iter)->qtype==QType(qtype).getCode())) {
- DLOG(L<<"Skipped "<<qname<<"/"<<QType(d_iter->qtype).getName()<<": '"<<*d_iter->content<<"'"<<endl);
- d_iter++;
- }
- if(d_iter==d_records.end()) { // we've reached the end
- if(d_bbd) {
- d_bbd->unlock();
- d_bbd=0;
- }
- return false;
- }
-
- DLOG(L << "BindBackend get() returning a rr with a "<<QType(d_iter->qtype).getCode()<<endl);
-
- r.qname=qname; // fill this in
-
- r.content=*(d_iter)->content;
- r.domain_id=(d_iter)->domain_id;
- r.qtype=(d_iter)->qtype;
- r.ttl=(d_iter)->ttl;
- r.priority=(d_iter)->priority;
- d_iter++;
-
- return true;
-}
-
-bool BindBackend::list(const string &target, int id)
-{
- if(!d_zone_id_map.count(id))
- return false;
-
- d_handle=new BindBackend::handle;
- DLOG(L<<"BindBackend constructing handle for list of "<<id<<endl);
-
- d_handle->d_qname_iter=d_zone_id_map[id].begin();
- d_handle->d_qname_end=d_zone_id_map[id].end(); // iter now points to a vector of pointers to vector<BBResourceRecords>
- d_handle->d_riter=(*(d_handle->d_qname_iter))->begin();
- d_handle->d_rend=(*(d_handle->d_qname_iter))->end();
- // rend?
- d_handle->parent=this;
- d_handle->id=id;
- d_handle->d_list=true;
- return true;
-}
-
-// naam -> naamnummer
-// naamnummer -> vector<BBResourceRecords>, BBResourceRecord bevat ook een pointer naar
-
-bool BindBackend::handle::get_list(DNSResourceRecord &r)
-{
- DLOG(L << "BindBackend get_list()"<<endl);
-
- while(d_riter==d_rend) {
- DLOG(L<<"Starting new record"<<endl);
- d_qname_iter++;
- if(d_qname_iter==d_qname_end) { // we've reached the end of recordsets for this id
- DLOG(L<<"Really stop!"<<endl);
- return false;
- }
- d_riter=(*(d_qname_iter))->begin();
- d_rend=(*(d_qname_iter))->end();
- }
- // d_riter points to a pointer to BBResourceRecord
-
- // r.qname=qname; // fill this in HOW?!
-
- r.qname=parent->s_hc.decode(*d_riter->qnameptr);
-
- r.content=*(d_riter)->content;
- r.domain_id=(d_riter)->domain_id;
- r.qtype=(d_riter)->qtype;
- r.ttl=(d_riter)->ttl;
- r.priority=(d_riter)->priority;
- d_riter++;
- return true;
-}
-
-bool BindBackend::isMaster(const string &name, const string &ip)
-{
- for(map<uint32_t,BBDomainInfo>::iterator j=us->d_bbds.begin();j!=us->d_bbds.end();++j)
- if(j->second.d_name==name)
- return j->second.d_master==ip;
- return false;
-}
-
-class BindFactory : public BackendFactory
-{
- public:
- BindFactory() : BackendFactory("bind1") {}
-
- void declareArguments(const string &suffix="")
- {
- declare(suffix,"config","Location of named.conf","");
- declare(suffix,"example-zones","Install example zones","no");
- declare(suffix,"enable-huffman","Enable huffman compression","no");
- declare(suffix,"check-interval","Interval for zonefile changes","0");
- }
-
- DNSBackend *make(const string &suffix="")
- {
- return new BindBackend(suffix);
- }
-};
-
-
-
-
-//! Magic class that is activated when the dynamic library is loaded
-class BindLoader
-{
-public:
- BindLoader()
- {
- BackendMakers().report(new BindFactory);
- L<<Logger::Notice<<"[BindBackend] This is the bind backend version "VERSION" ("__DATE__", "__TIME__") reporting"<<endl;
- }
-};
-static BindLoader bindloader;
+++ /dev/null
-/*
- PowerDNS Versatile Database Driven Nameserver
- 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 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
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-*/
-#include <string>
-#include <map>
-#include <set>
-#include <pthread.h>
-#include <time.h>
-#include <fstream>
-
-#include "huffman.hh"
-
-#if __GNUC__ >= 3
-# include <ext/hash_map>
-using namespace __gnu_cxx;
-#else
-# include <hash_map>
-#endif
-
-
-using namespace std;
-
-class BBDomainInfo
-{
-public:
- BBDomainInfo();
-
- void setCtime();
-
- bool current();
-
- bool d_loaded;
- string d_status;
- bool d_checknow;
- time_t d_ctime;
- string d_name;
- string d_filename;
- unsigned int d_id;
- time_t d_last_check;
- string d_master;
- int d_confcount;
- uint32_t d_lastnotified;
-
- bool tryRLock()
- {
- // cout<<"[trylock!] "<<(void*)d_rwlock<<"/"<<getpid()<<endl;
- return pthread_rwlock_tryrdlock(d_rwlock)!=EBUSY;
- }
-
- void unlock()
- {
- // cout<<"[unlock] "<<(void*)d_rwlock<<"/"<<getpid()<<endl;
- pthread_rwlock_unlock(d_rwlock);
- }
-
- void lock()
- {
- //cout<<"[writelock!] "<<(void*)d_rwlock<<"/"<<getpid()<<endl;
-
- pthread_rwlock_wrlock(d_rwlock);
- }
-
- void setCheckInterval(time_t seconds);
-private:
- time_t getCtime();
- time_t d_checkinterval;
- time_t d_lastcheck;
- pthread_rwlock_t *d_rwlock;
-};
-
-
-
-class BBResourceRecord
-{
-public:
- bool operator==(const BBResourceRecord &o) const
- {
- return (o.domain_id==domain_id && o.qtype==qtype && o.content==content &&
- o.ttl==ttl && o.priority==priority);
- }
-
- const string *qnameptr; // 4
- unsigned int domain_id; // 4
- unsigned short int qtype; // 2
- unsigned short int priority; // 2
- const string *content; // 4
- unsigned int ttl; // 4
-
-};
-
-struct compare_string
-{
- bool operator()(const string& s1, const string& s2) const
- {
- return s1 == s2;
- }
-};
-
-struct hash_string
-{
- size_t operator()(const string& s) const
- {
- return __stl_hash_string(s.c_str());
- }
-};
-
-typedef hash_map<string,vector<BBResourceRecord>, hash_string, compare_string> cmap_t;
-
-
-
-/** The BindBackend is a DNSBackend that can answer DNS related questions. It looks up data
- in a Bind-style zone file
-
- How this all works is quite complex and prone to change. There are a number of containers involved which,
- together, contain everything we need to know about a domain or a record.
-
- A domain consists of records. So, 'example.com' has 'www.example.com' as a record.
-
- All record names are stored in the hash_map d_qnames, with their name as index. Attached to that index
- is a vector of BBResourceRecords ('BindBackend') belonging to that qname. Each record contains a d_domainid,
- which is the ID of the domain it belongs to.
-
- Then there is the map called d_bbds which has as its key the Domain ID, and attached a BBDomainInfo object, which
- tells us domain metadata (place on disk, if it is a master or a slave etc).
-
- To allow for AXFRs, there is yet another container, the d_zone_id_map, which contains per domain_id a vector
- of pointers to vectors of BBResourceRecords. When read in sequence, these deliver all records of a domain_id.
-
- As there is huge repitition in the right hand side of records, many records point to the same thing (IP address, nameserver),
- a list of these is kept in s_contents, and each BBResourceRecord only contains a pointer to a record in s_contents.
-
- So, summarizing:
-
- class BBResourceRecord:
- Everything you need to know about a record. In this context we call the name of a BBResourceRecord 'qname'
-
- class BBDomainInfo:
- Domain metadata, like location on disk, last time zone was checked
-
- d_qnames<qname,vector<BBResourceRecord> >:
- If you know the qname of a record, this gives you all records under that name.
-
- set<string>s_contents:
- Set of all 'contents' of records, the right hand sides.
-
- map<int,vector<vector<BBResourceRecord>* > > d_zone_id_map:
- If you know the zone_id, this has a vector of pointers to vectors in d_qnames, for AXFR
-
- map<unsigned int, BBDomainInfo>d_bbds:
- Map of all domains we know about and metadata about them.
-
-
-*/
-class BindBackend : public DNSBackend
-{
-public:
- BindBackend(const string &suffix=""); //!< Makes our connection to the database. Calls exit(1) if it fails.
- void getUnfreshSlaveInfos(vector<DomainInfo> *unfreshDomains);
- void getUpdatedMasters(vector<DomainInfo> *changedDomains);
- bool getDomainInfo(const string &domain, DomainInfo &di);
- time_t getCtime(const string &fname);
-
-
- void lookup(const QType &, const string &qdomain, DNSPacket *p=0, int zoneId=-1);
- bool list(const string &target, int id);
- bool get(DNSResourceRecord &);
-
- static DNSBackend *maker();
- static set<string> s_contents;
- static pthread_mutex_t s_startup_lock;
-
- void setFresh(uint32_t domain_id);
- void setNotified(uint32_t id, uint32_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;
-
- bool isMaster(const string &name, const string &ip);
-private:
- class handle
- {
- public:
- bool get(DNSResourceRecord &);
- ~handle() {
- if(d_bbd)
- d_bbd->unlock();
- }
- handle();
-
- BindBackend *parent;
-
- vector<BBResourceRecord>d_records;
- vector<BBResourceRecord>::const_iterator d_iter;
-
- vector<BBResourceRecord>::const_iterator d_riter;
- vector<BBResourceRecord>::const_iterator d_rend;
- vector<vector<BBResourceRecord> *>::const_iterator d_qname_iter;
- vector<vector<BBResourceRecord> *>::const_iterator d_qname_end;
-
- // static map<int,vector<vector<BBResourceRecord>* > > d_zone_id_map;
- // vector<vector<BBResourceRecord>* > d_zone_id_map[id]
- // iterator NAAR vector<BBResourceRecord>* d_zone_id_map[id].begin()
-
- bool d_list;
- int id;
- BBDomainInfo* d_bbd;
- string qname;
- QType qtype;
- private:
- int count;
-
- bool get_normal(DNSResourceRecord &);
- bool get_list(DNSResourceRecord &);
- };
-
- static cmap_t d_qnames;
- static map<int,vector<vector<BBResourceRecord>* > > d_zone_id_map;
-
- static map<unsigned int, BBDomainInfo>d_bbds;
- static int s_first;
-
- string d_logprefix;
- int d_transaction_id;
- string d_transaction_tmpname;
- ofstream *d_of;
- handle *d_handle;
- void queueReload(BBDomainInfo *bbd);
- BBResourceRecord resourceMaker(int id, const string &qtype, const string &content, int ttl, int prio);
- void reload();
- static string DLDomStatusHandler(const vector<string>&parts, Utility::pid_t ppid);
- static string DLListRejectsHandler(const vector<string>&parts, Utility::pid_t ppid);
- static string DLReloadNowHandler(const vector<string>&parts, Utility::pid_t ppid);
- void loadConfig(string *status=0);
- void nukeZoneRecords(BBDomainInfo *bbd);
-};
/*
PowerDNS Versatile Database Driven Nameserver
- Copyright (C) 2002-2006 PowerDNS.COM BV
+ Copyright (C) 2002-2007 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 "dnsbackend.hh"
#include "bindbackend2.hh"
#include "dnspacket.hh"
-
-#include "zoneparser.hh"
+#include "zoneparser-tng.hh"
#include "bindparser.hh"
#include "logger.hh"
#include "arguments.hh"
return ret;
}
-static void InsertionCallback(shared_ptr<Bind2Backend::State> stage, unsigned int domain_id, const string &domain, const string &qtype, const string &content, int ttl, int prio)
-{
- us->insert(stage, domain_id, domain, qtype, content, ttl, prio);
-}
-
set<string> contents;
/** This function adds a record to a domain with a certain id.
Much of the complication is due to the efforts to benefit from std::string reference counting copy on write semantics */
-void Bind2Backend::insert(shared_ptr<State> stage, int id, const string &qnameu, const string &qtype, const string &content, int ttl=300, int prio=25)
+void Bind2Backend::insert(shared_ptr<State> stage, int id, const string &qnameu, const QType &qtype, const string &content, int ttl=300, int prio=25)
{
// XXXX WRONG WRONG WRONG REWRITE
if(!records.empty() && bdr.qname==(records.end()-1)->qname)
bdr.qname=(records.end()-1)->qname;
- bdr.qtype=QType(qtype.c_str()).getCode();
+ bdr.qtype=qtype.getCode();
bdr.content=canonic(content); // I think this is wrong, the zoneparser should not come up with . terminated stuff XXX FIXME
set<string>::const_iterator i=contents.find(bdr.content);
if(i!=contents.end())
throw;
}
- ZoneParser ZP;
+
vector<BindDomainInfo> domains=BP.getDomains();
us=this;
d_binddirectory=BP.getDirectory();
- ZP.setDirectory(d_binddirectory);
- ZoneParser::callback_t func=boost::bind(&InsertionCallback, staging, _1, _2, _3, _4, _5, _6);
- ZP.setCallback(func);
+ // ZP.setDirectory(d_binddirectory);
+ // ZoneParser::callback_t func=boost::bind(&InsertionCallback, staging, _1, _2, _3, _4, _5, _6);
+
L<<Logger::Warning<<d_logprefix<<" Parsing "<<domains.size()<<" domain(s), will report when done"<<endl;
// we need to allocate a new vector so we don't kill the original, which is still in use!
bbd->d_records=shared_ptr<vector<Bind2DNSRecord> > (new vector<Bind2DNSRecord>);
- ZP.parse(i->filename, i->name, bbd->d_id); // calls callback for us
+ ZoneParserTNG zpt(i->filename, i->name, BP.getDirectory());
+ DNSResourceRecord rr;
+ while(zpt.get(rr)) {
+ insert(staging, bbd->d_id, rr.qname, rr.qtype, rr.content, rr.ttl, rr.priority);
+ }
+
+ // ZP.parse(i->filename, i->name, bbd->d_id); // calls callback for us
L<<Logger::Info<<d_logprefix<<" sorting '"<<i->name<<"'"<<endl;
sort(staging->id_zone_map[bbd->d_id].d_records->begin(), staging->id_zone_map[bbd->d_id].d_records->end());
try {
nukeZoneRecords(bbd); // ? do we need this?
- ZoneParser ZP;
us=this;
- ZP.setDirectory(d_binddirectory);
- ZoneParser::callback_t func=boost::bind(&InsertionCallback, staging, _1, _2, _3, _4, _5, _6);
- ZP.setCallback(func);
-
staging->id_zone_map[bbd->d_id]=s_state->id_zone_map[bbd->d_id];
staging->id_zone_map[bbd->d_id].d_records=shared_ptr<vector<Bind2DNSRecord> > (new vector<Bind2DNSRecord>); // nuke it
- ZP.parse(bbd->d_filename, bbd->d_name, bbd->d_id);
-
+ ZoneParserTNG zpt(bbd->d_filename, bbd->d_name, d_binddirectory);
+ DNSResourceRecord rr;
+ while(zpt.get(rr)) {
+ insert(staging, bbd->d_id, rr.qname, rr.qtype, rr.content, rr.ttl, rr.priority);
+ }
+
sort(staging->id_zone_map[bbd->d_id].d_records->begin(), staging->id_zone_map[bbd->d_id].d_records->end());
staging->id_zone_map[bbd->d_id].setCtime();
id_zone_map_t id_zone_map;
};
- void insert(shared_ptr<State> stage, int id, const string &qname, const string &qtype, const string &content, int ttl, int prio);
+ void insert(shared_ptr<State> stage, int id, const string &qname, const QType &qtype, const string &content, int ttl, int prio);
void rediscover(string *status=0);
bool isMaster(const string &name, const string &ip);
#include <utility>
#include <errno.h>
#include "misc.hh"
-#include "zoneparser.hh"
#include "ahuexception.hh"
using namespace std;
#define YYDEBUG 1
zone_command:
ZONETOK quotedname zone_block
{
- s_di.name=ZoneParser::canonic($2);
+ s_di.name=stripDot($2);
parent->commit(s_di);
s_di.clear();
/*
* PowerDNS BIND Zone to LDAP converter
* Copyright (C) 2003 Norbert Sendetzky
+ * Copyright (C) 2007 bert hubert
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
#include <iostream>
#include <stdio.h>
#include "arguments.hh"
-#include "zoneparser.hh"
#include "bindparser.hh"
#include "statbag.hh"
+#include <boost/function.hpp>
#include "misc.hh"
#include "dns.hh"
-
+#include "zoneparser-tng.hh"
using std::map;
using std::string;
using std::vector;
-
-
StatBag S;
ArgvMap args;
bool g_dnsttl;
string g_zonename;
map<string,bool> g_objects;
-
-
static void callback_simple( unsigned int domain_id, const string &domain, const string &qtype, const string &content, int ttl, int prio )
{
string host;
string::size_type pos;
vector<string> parts;
- string domain2 = ZoneParser::canonic( domain );
+ string domain2 = stripDot( domain );
if( ( pos = domain2.rfind( g_zonename ) ) == string::npos )
return;
}
- host = ZoneParser::canonic( domain2.substr( 0, pos ) );
+ host = stripDot( domain2.substr( 0, pos ) );
cout << "dn: dc=";
if( !host.empty() ) { cout << host << ",dc="; }
cout << qtype << "Record: ";
if( prio != 0 ) { cout << prio << " "; }
- cout << ZoneParser::canonic( content ) << endl << endl;
+ cout << stripDot( content ) << endl << endl;
}
unsigned int i;
string dn, net;
vector<string> parts;
- string domain2 = ZoneParser::canonic( domain );
+ string domain2 = stripDot( domain );
stringtok( parts, domain2, "." );
if( parts.empty() ) { return; }
cout << qtype << "Record: ";
if( prio != 0 ) { cout << prio << " "; }
- cout << ZoneParser::canonic( content ) << endl << endl;
+ cout << stripDot( content ) << endl << endl;
}
int main( int argc, char* argv[] )
{
BindParser BP;
- ZoneParser ZP;
vector<string> parts;
g_basedn = args["basedn"];
g_dnsttl = args.mustDo( "dnsttl" );
-
- ZP.setCallback( &callback_simple );
+ typedef boost::function<void(unsigned int, const string &, const string &, const string &, int, int)> callback_t;
+ callback_t callback = callback_simple;
if( args["layout"] == "tree" )
{
- ZP.setCallback( &callback_tree );
+ callback=callback_tree;
}
if( !args["named-conf"].empty() )
{
BP.setVerbose( args.mustDo( "verbose" ) );
BP.parse( args["named-conf"] );
- ZP.setDirectory( BP.getDirectory() );
+// ZP.setDirectory( BP.getDirectory() );
const vector<BindDomainInfo> &domains = BP.getDomains();
for( vector<BindDomainInfo>::const_iterator i = domains.begin(); i != domains.end(); i++ )
{
cerr << "Parsing file: " << i->filename << ", domain: " << i->name << endl;
g_zonename = i->name;
- ZP.parse( i->filename, i->name, 0 );
+ ZoneParserTNG zpt(i->filename, i->name, BP.getDirectory());
+ DNSResourceRecord rr;
+ while(zpt.get(rr))
+ callback(0, rr.qname, rr.qtype.getName(), rr.content, rr.ttl, rr.priority);
}
}
catch( AhuException &ae )
}
g_zonename = args["zone-name"];
- ZP.setDirectory( "." );
- ZP.parse( args["zone-file"], args["zone-name"], 0 );
+ ZoneParserTNG zpt(args["zone-file"], args["zone-name"]);
+ DNSResourceRecord rr;
+ while(zpt.get(rr))
+ callback(0, rr.qname, rr.qtype.getName(), rr.content, rr.ttl, rr.priority);
}
}
catch( AhuException &ae )
/*
PowerDNS Versatile Database Driven Nameserver
- Copyright (C) 2002 PowerDNS.COM BV
+ Copyright (C) 2002 - 2007 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
#include "dns.hh"
#include "arguments.hh"
-#include "zoneparser.hh"
#include "bindparser.hh"
#include "statbag.hh"
#include "misc.hh"
#include "dnspacket.hh"
+#include "zoneparser-tng.hh"
StatBag S;
if(qtype=="SOA") {
// cerr<<"Juh: "<<dirty_hack_num<<", "<<lastsoa_domain_id<<", "<<lastsoa_qname<<", "<<domain<<endl;
- if(dirty_hack_num==lastsoa_domain_id && lastsoa_qname!=ZoneParser::canonic(domain)) {
+ if(dirty_hack_num==lastsoa_domain_id && lastsoa_qname!=stripDot(domain)) {
dirty_hack_num++;
cerr<<"Second SOA in zone, raised domain_id"<<endl;
if(mode==POSTGRES || mode==ORACLE) {
}
if(mode==POSTGRES) {
- cout<<"insert into domains (name,type) values ("<<toLower(sqlstr(ZoneParser::canonic(domain)))<<",'NATIVE');"<<endl;
+ cout<<"insert into domains (name,type) values ("<<toLower(sqlstr(stripDot(domain)))<<",'NATIVE');"<<endl;
}
else if(mode==ORACLE) {
cout<<"insert into domains (id,name,type) values (domains_id_sequence.nextval,"<<toLower(sqlstr(domain))<<",'NATIVE');"<<endl;
}
SOAData soadata;
DNSPacket::fillSOAData(content, soadata);
- soadata.hostmaster=ZoneParser::canonic(soadata.hostmaster);
- soadata.nameserver=ZoneParser::canonic(soadata.nameserver);
+ soadata.hostmaster=stripDot(soadata.hostmaster);
+ soadata.nameserver=stripDot(soadata.nameserver);
content=DNSPacket::serializeSOAData(soadata);
- lastsoa_qname=ZoneParser::canonic(domain);
+ lastsoa_qname=stripDot(domain);
}
lastsoa_domain_id=dirty_hack_num;
if(mode==MYSQL) {
cout<<"insert into records (domain_id, name,type,content,ttl,prio) values ("<< dirty_hack_num<<", "<<
- sqlstr(ZoneParser::canonic(domain))<<", "<<
+ sqlstr(stripDot(domain))<<", "<<
sqlstr(qtype)<<", "<<
- sqlstr(ZoneParser::canonic(content))<<", "<<ttl<<", "<<prio<<");\n";
+ sqlstr(stripDot(content))<<", "<<ttl<<", "<<prio<<");\n";
}
if(mode==POSTGRES) {
cout<<"insert into records (domain_id, name,type,content,ttl,prio) select id ,"<<
- sqlstr(toLower(ZoneParser::canonic(domain)))<<", "<<
+ sqlstr(toLower(stripDot(domain)))<<", "<<
sqlstr(qtype)<<", "<<
- sqlstr(ZoneParser::canonic(content))<<", "<<ttl<<", "<<prio<<
+ sqlstr(stripDot(content))<<", "<<ttl<<", "<<prio<<
" from domains where name="<<toLower(sqlstr(lastsoa_qname))<<";\n";
}
else if(mode==ORACLE) {
cout<<"insert into Records (id,ZoneId, name,type,content,TimeToLive,Priority) select RECORDS_ID_SEQUENCE.nextval,id ,"<<
- sqlstr(toLower(ZoneParser::canonic(domain)))<<", "<<
+ sqlstr(toLower(stripDot(domain)))<<", "<<
sqlstr(qtype)<<", "<<
- sqlstr(ZoneParser::canonic(content))<<", "<<ttl<<", "<<prio<<
+ sqlstr(stripDot(content))<<", "<<ttl<<", "<<prio<<
" from Domains where name="<<toLower(sqlstr(lastsoa_qname))<<";\n";
}
else if(mode==BARE) {
cout<< dirty_hack_num<<"\t"<<
- sqlstr(ZoneParser::canonic(domain))<<"\t"<<
- sqlstr(qtype)<<"\t"<<sqlstr(ZoneParser::canonic(content))<<"\t"<<prio<<"\t"<<ttl<<"\n";
+ sqlstr(stripDot(domain))<<"\t"<<
+ sqlstr(qtype)<<"\t"<<sqlstr(stripDot(content))<<"\t"<<prio<<"\t"<<ttl<<"\n";
}
}
BP.setVerbose(arg().mustDo("verbose"));
BP.parse(namedfile.empty() ? "./named.conf" : namedfile);
- ZoneParser ZP;
-
const vector<BindDomainInfo> &domains=BP.getDomains();
int numdomains=domains.size();
int tick=numdomains/100;
- ZP.setDirectory(BP.getDirectory());
- ZP.setCallback(&callback);
+ // ZP.setDirectory(BP.getDirectory());
for(vector<BindDomainInfo>::const_iterator i=domains.begin();
i!=domains.end();
}
lastsoa_qname=i->name;
}
- ZP.parse(i->filename,i->name,0);
+ ZoneParserTNG zpt(i->filename, i->name, BP.getDirectory());
+ DNSResourceRecord rr;
+ while(zpt.get(rr))
+ callback(0, rr.qname, rr.qtype.getName(), rr.content, rr.ttl, rr.priority);
}
catch(AhuException &ae) {
if(!arg().mustDo("on-error-resume-next"))
cerr<<"\r100% done\033\133\113"<<endl;
}
else {
+ ZoneParserTNG zpt(zonefile, arg()["zone-name"]);
+ DNSResourceRecord rr;
dirty_hack_num=-1; // trigger first SOA output
- ZoneParser ZP;
- ZP.setDirectory(".");
- ZP.setCallback(&callback);
- ZP.parse(zonefile,arg()["zone-name"],0);
+ while(zpt.get(rr))
+ callback(0, rr.qname, rr.qtype.getName(), rr.content, rr.ttl, rr.priority);
+
}
cerr<<"Parsed "<<num_records<<" records"<<endl;
+++ /dev/null
-/*
- PowerDNS Versatile Database Driven Nameserver
- Copyright (C) 2002-2006 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 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
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-*/
-#ifndef ZONEPARSER_HH
-#define ZONEPARSER_HH
-#include <string>
-#include <map>
-#include <vector>
-#include <time.h>
-#include <boost/function.hpp>
-
-using namespace std;
-
-class ZoneParser
-{
- public:
- struct Record
- {
- string name;
- string qtype;
- string content;
- int ttl;
- int prio;
- };
- ZoneParser() : d_ttl(3600) {}
- ~ZoneParser();
- void parse(const string &fname,const string &origin, unsigned int domain_id);
- void parse(const string &fname,const string &origin, vector<Record>&records);
-
- // typedef void callback_t(unsigned int domain_id, const string &domain, const string &qtype, const string &content, int ttl, int prio);
- typedef boost::function<void(unsigned int, const string &, const string &, const string &, int, int)> callback_t;
- void setCallback(callback_t callback);
- callback_t d_callback;
- bool parseLine(const vector<string>&words, vector<Record> &);
- bool eatLine(const string& line, vector<Record>&);
- void setDirectory(const string &dir);
- static string canonic(const string& dom);
-
-private:
- unsigned int zoneNumber(const string &str);
- string d_filename;
- string d_dir;
- unsigned int d_lineno;
- void soaCanonic(string &content);
- bool isNumber(const string &);
- bool isType(const string &);
- bool isClass(const string &);
- string d_origin;
- time_t d_ttl;
- void cutOff(string &line, const string &delim);
- void fillRec(const string &qname, const string &qtype, const string &content, int ttl, int prio, vector<Record>&rec);
- string expandWord(const string &line, int value);
-};
-
-
-#endif /* BINDPARSER_HH */
+++ /dev/null
-/*
- PowerDNS Versatile Database Driven Nameserver
- Copyright (C) 2002 - 2005 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
- 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
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-*/
-
-#ifdef WIN32
-# pragma warning ( disable: 4786 )
-#endif // WIN32
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <string>
-#include <vector>
-#include <iostream>
-#include <utility>
-#include <ctype.h>
-#include <zlib.h>
-#include <errno.h>
-#include <stack>
-#include "utility.hh"
-#include "misc.hh"
-#include "ahuexception.hh"
-#include "qtype.hh"
-#include <algorithm>
-using namespace std;
-
-#include "zoneparser.hh"
-
-extern const char *bind_directory;
-void ZoneParser::setDirectory(const string &dir)
-{
- d_dir=dir;
-
-}
-
-void ZoneParser::parse(const string &fname, const string &origin, unsigned int domain_id)
-{
- d_filename=fname.c_str();
-
- gzFile zonein;
- if(fname!="-")
- zonein=gzopen(fname.c_str(),"r");
- else
- zonein=gzdopen(STDIN_FILENO,"r");
-
- if(!zonein)
- throw AhuException("Unable to open zonefile '"+fname+"': "+stringerror());
-
- d_origin=origin;
-
- char cline[2048];
- string line;
- d_lineno=0;
- vector<Record> rec;
- stack<gzFile> fds;
- fds.push(zonein);
-
-
- while(!fds.empty()) {
- while(gzgets(fds.top(), cline,sizeof(cline)-1)) {
- line=cline;
- chomp(line," \x1a\r\n");
- cutOff(line,";");
-
- d_lineno++;
- if(line.empty())
- continue;
-
- if(line[0]=='$' && (!line.find("$INCLUDE ") || !line.find("$include "))) {
- vector<string> parts;
- stringtok(parts,line," \t\n");
- if(parts.size()!=2)
- throw AhuException("Invalid $INCLUDE statement in zonefile '"+fname+"'");
-
- string filename=unquotify(parts[1]);
- if(filename[0]!='/')
- filename=d_dir+"/"+filename;
-
-
- gzFile fp=gzopen(filename.c_str(),"r");
- if(!fp)
- throw AhuException("Unable to open zonefile '"+filename+"' included from '"+fname+"': "+stringerror());
- fds.push(fp);
- continue;
- }
- if(eatLine(line,rec))
- for(vector<Record>::const_iterator i=rec.begin();i!=rec.end();++i)
- d_callback(domain_id, i->name, i->qtype, i->content, i->ttl, i->prio);
- }
-
- // if(ferror(fds.top())) {
- // fclose(fds.top());
- // fds.pop();
- // throw AhuException("Error reading from file '"+fname+"': "+stringerror());
- // }
- gzclose(fds.top());
- fds.pop();
- }
-}
-
-void ZoneParser::parse(const string &fname, const string &origin, vector<Record>&records)
-{
- d_filename=fname.c_str();
-
- gzFile zonein=gzopen(fname.c_str(),"r");
-
- if(!zonein)
- throw AhuException("Unable to open zonefile '"+fname+"': "+stringerror());
-
- d_origin=origin;
-
- char cline[2048];
- string line;
- d_lineno=0;
- vector<Record> rec;
- stack<gzFile>fds;
- fds.push(zonein);
-
- while(!fds.empty()) {
- while(gzgets(fds.top(),cline, sizeof(cline)-1)) {
- line=cline;
- chomp(line," \x1a\r\n");
- cutOff(line,";");
-
- d_lineno++;
- if(line.empty())
- continue;
-
- if(line[0]=='$' && (!line.find("$INCLUDE ") || !line.find("$include "))) {
- vector<string> parts;
- stringtok(parts,line," \t\r\n");
- if(parts.size()!=2)
- throw AhuException("Invalid $INCLUDE statement in zonefile '"+fname+"'");
-
- string filename=unquotify(parts[1]);
- gzFile fp=gzopen(filename.c_str(),"r");
- if(!fp)
- throw AhuException("Unable to open zonefile '"+filename+"' included from '"+fname+"': "+stringerror());
- fds.push(fp);
- continue;
- }
- if(eatLine(line,rec))
- for(vector<Record>::const_iterator i=rec.begin();i!=rec.end();++i)
- records.push_back(*i);
- }
-
- // if(ferror(fds.top())) {
- // fclose(fds.top());
- // fds.pop();
- // throw AhuException("Error reading from file '"+fname+"': "+stringerror());
- // }
- gzclose(fds.top());
- fds.pop();
- }
-}
-
-
-void ZoneParser::fillRec(const string &qname, const string &qtype, const string &content, int ttl, int prio, vector<Record>&recs)
-{
- Record rec;
- rec.name=qname;
- rec.qtype=qtype;
-
- if(!QType::chartocode(qtype.c_str()))
- throw AhuException("Unknown qtype '"+qtype+"' on line "+itoa(d_lineno)+" of file '"+d_filename+"'");
- rec.content=content;
- rec.ttl=ttl;
- rec.prio=prio;
-
- // cerr<<"filled with type: "<<rec.qtype<<", "<<QType::chartocode(qtype.c_str())<<": "<<content<<endl;
- recs.push_back(rec);
-}
-
-
-void ZoneParser::cutOff(string &line, const string &delim)
-{
- string::size_type pos=line.find_first_of(delim);
- if(pos==string::npos)
- return;
- line.resize(pos);
-}
-
-bool ZoneParser::eatLine(const string& line, vector<Record> &rec)
-{
- rec.clear();
- static string tline;
- static string lastfirstword;
- string::size_type pos=string::npos;
-
- if(tline.empty()) {
- pos=line.find_first_of("(");
- if(pos!=string::npos) { // this is a line that continues
- tline=line.substr(0,pos);
- return false;
- }
- else
- tline=line; // complete & boring line
- }
- else { // continuation
- pos=line.find(")");
- if(pos==string::npos) { // middle part
- tline.append(line);
- return false;
- }
- else {
- tline.append(line.substr(0,pos)); // end part, we have a complete line!
- }
- }
-
- // full & unparenthesised line now in tline!
- // cout<<"line: '"<<tline<<"'"<<endl;
- if(tline.empty() || tline.find_first_not_of(" \t\n")==string::npos) {
-
- tline="";
- return false;
- }
-
- if(isspace(tline[0]))
- tline=lastfirstword+"\t"+tline;
-
- vector<string> parts;
- stringtok(parts,tline," \t"); // we used to strip " here
- if(parts[0][0]!='$' && !isspace(parts[0][0]))
- lastfirstword=parts[0];
-
- // for_each(parts.begin(),parts.end(),print);
- tline="";
- return parseLine(parts,rec);
-}
-
-ZoneParser::~ZoneParser()
-{
-
-}
-
-void ZoneParser::setCallback(callback_t callback)
-{
- d_callback=callback;
-}
-
-bool ZoneParser::isNumber(const string &s)
-{
- for(string::const_iterator i=s.begin();
- i!=s.end();
- ++i) {
- if(i+1==s.end())
- if(*i=='M' || *i=='D' || *i=='H' || *i=='W' || *i=='m' || *i=='d' || *i=='h' || *i=='w') // last character
- continue;
- if(!isdigit(*i))
- return false;
- }
- return true;
-}
-
-bool ZoneParser::isType(const string &s)
-{
- if(isNumber(s))
- return false;
-
- if(isClass(s))
- return false;
-
- return true;
-}
-
-bool ZoneParser::isClass(const string &s)
-{
- return (s.size()==2 && (s=="IN" || s=="CH" || s=="HS" || s=="in" || s=="ch" || s=="hs"));
-}
-
-unsigned int ZoneParser::zoneNumber(const string &str)
-{
- unsigned int val=atoi(str.c_str());
- char lc=toupper(str[str.length()-1]);
- if(!isdigit(lc))
- switch(lc) {
- case 'H':
- val*=3600;
- break;
- case 'D':
- val*=3600*24;
- break;
- case 'W':
- val*=3600*24*7;
- break;
- case 'M':
- val*=3600*24*7*4;
- break;
- case 'Y': // ? :-)
- val*=3600*24*365;
- break;
- default:
- throw AhuException("Unable to parse "+d_origin+" time specification '"+str+"' at line "+itoa(d_lineno));
- }
- return val;
-
-}
-
-/** this parser handles 10 cases (sigh)
- 1) qname TTL CLASS QTYPE *
- 2) qname CLASS TTL QTYPE *
- 3) qname CLASS QTYPE *
- 4) qname TTL QTYPE *
- 5) qname QTYPE *
-
- And then everything again with a space first character, which implies 'same as last name'
-*/
-
-void ZoneParser::soaCanonic(string &content)
-{
- vector<string>parts;
- stringtok(parts,content," \t");
- int pos=0;
-
- // 'ns.naamserver.net. hostmaster.naamserver.net 2001102501 8H 2H 1W 1D'
- // FIXME: what about 'ns hostmaster.naamserver.net 2001102501 8H 2H 1W 1D'?
-
- string newcontent;
- for(vector<string>::const_iterator i=parts.begin();i!=parts.end();++i,++pos) {
- if(pos<3) {
- if(pos)
- newcontent.append(1,' ');
- newcontent.append( canonic( *i ) );
- }
- else {
- unsigned int val=zoneNumber(*i);
-
- newcontent.append(1,' ');
- newcontent.append(itoa(val));
- }
- }
- content=newcontent;
-}
-
-string ZoneParser::expandWord(const string &line, int value)
-{
- string newline;
- bool escape=false;
- for(string::const_iterator i=line.begin();i!=line.end();++i) {
- if(*i=='\\')
- escape=true;
- else{
- if(!escape && *i=='$') {
- if(i+2<line.end() && *(i+1)=='{') { // shit
- string::const_iterator k=(i+=2);
- while(k++!=line.end() && *k!='}')
- ;
- if(k==line.end())
- throw AhuException("Malformed $GENERATE statement");
-
- string spec;
-
- //copy(i,k,back_inserter(spec));
- for ( string::const_iterator a = i; a != k; ++a )
- spec += *a;
-
- vector<string> partjes;
- stringtok(partjes,spec,",");
- if(partjes.empty())
- throw AhuException("Malformed $GENERATE statement: '"+spec+"'");
-
- value+=atoi(partjes[0].c_str());
- int width=0;
- char radix='d';
- if(partjes.size()>=2)
- width=atoi(partjes[1].c_str());
- if(partjes.size()>=3)
- radix=partjes[2][0];
-
- char tmp[20];
- string format;
- format="%0";
- format+=itoa(width);
- format.append(1,radix);
-
- snprintf(tmp,19,format.c_str(),value);
-
- newline.append(tmp);
- i=k;
- }
- else
- newline.append(itoa(value));
- }
- else
- newline.append(1,*i);
- escape=false;
- }
- }
- return newline;
-}
-
-string ZoneParser::canonic(const string& dom)
-{
- if(dom[dom.size()-1]!='.')
- return dom;
-
- return dom.substr(0,dom.size()-1);
-
-}
-
-
-bool ZoneParser::parseLine(const vector<string>&words, vector<Record>&rec)
-{
- int cpos=0;
- if(!words.size())
- return false;
-
- if(words[0][0]=='$')
- {
- if(!Utility::strcasecmp(words[0].c_str(),"$ORIGIN") && words.size()>1) {
- d_origin=canonic(words[1]);
- }
- else if(!Utility::strcasecmp(words[0].c_str(),"$TTL") && words.size()>1) {
- d_ttl=zoneNumber(words[1]);
- }
- else if(!Utility::strcasecmp(words[0].c_str(),"$GENERATE") && words.size()>1) {
- // $GENERATE 1-127 $ CNAME $.0
- string range=words[1]; // 1-127 means 1...127 (including 127). 1-127/2 is 1..3..5..
- vector<string>parts;
- stringtok(parts,range,"-/");
- if(parts.size()<2 || parts.size()>3)
- throw AhuException("Malformed $GENERATE on line "+itoa(d_lineno)+" of "+d_filename);
-
- int start, stop, step=1;
- start=atoi(parts[0].c_str());
- stop=atoi(parts[1].c_str());
- if(parts.size()==3)
- step=atoi(parts[2].c_str());
- vector<string>newwords;
-
- for(int i=start;i<=stop;++i) {
- newwords.clear();
- for(unsigned int j=2;j<words.size();++j) {
- newwords.push_back(expandWord(words[j],i));
- }
- parseLine(newwords, rec);
- }
- return true;
- }
- else {
- throw AhuException("Unhandled command '"+words[0]+"' on line "+itoa(d_lineno)+" of '"+d_filename+"'");
- }
-
- return false;
-
- }
- if(words.size()<3) {
- if(words.size()==1 && words[0]==";")
- return false;
- throw AhuException("Short line "+itoa(d_lineno)+" in '"+d_filename+"': "+itoa(words.size())+ " words. Probably due to repeated record without domainname");
- }
-
- string qname=words[0];
- string qclass="IN";
- int ttl=d_ttl;
- string qtype="NONE";
- if(isNumber(words[1])) // 1 || 4
- {
- ttl=zoneNumber(words[1]);
- if(isClass(words[2]))
- {
-// cout<<1<<endl;
- qclass=words[2];
- qtype=words[3];
- cpos=4;
- // 1
- }
- else
- {
-// cout<<4<<endl;
-
- qtype=words[2];
- cpos=3;
- // 4
- }
- }
- else /* 2 || 3 || 5 */
- {
- if(!isClass(words[1]))
- {
-
- qtype=words[1];
- cpos=2;
-// cout<<5<<endl;
- // 5
- }
- else // 2 || 3
- {
- qclass=words[1];
- if(isNumber(words[2]))
- {
- ttl=zoneNumber(words[2]);
- qtype=words[3];
-// cout<<2<<endl;
- cpos=4;
- // 2
- }
- else if(isType(words[2]))
- {
- qtype=words[2];
-// cout<<4<<endl;
- cpos=3;
- // 4
- }
- }
-
- }
- if(!cpos) {
- throw AhuException("Funky parse case on line "+itoa(d_lineno));
- }
-
- if(qname=="@")
- qname=d_origin;
- else
- if(qname[qname.size()-1]!='.')
- qname+="."+d_origin;
-
-
- // cerr<<qname<<", "<<qclass<<", "<<qtype<<", "<<ttl<<", rest from field "<<cpos<<endl;
-
- int left=words.size()-cpos;
- string content;
-
- if((qtype=="MX" && left==2) || (qtype=="SRV" && left==4)){
- int prio=atoi(words[cpos++].c_str());left--;
- content=words[cpos++];left--;
-
- while(left--)
- content+=" "+words[cpos++];
-
- if(content=="@")
- content=d_origin;
- else
- if(content[content.size()-1]!='.')
- content+="."+d_origin;
-
- fillRec(qname, qtype, content, ttl, prio,rec);
- return true;
- }
- else if(left) {
- content=words[cpos++];left--;
-
- while(left--)
- content+=" "+words[cpos++];
-
- if(qtype=="MX" || qtype=="CNAME" || qtype=="NS") {
- if(content=="@")
- content=d_origin;
- else
- if(content[content.size()-1]!='.')
- content+="."+d_origin;
- }
- if(qtype=="SOA")
- soaCanonic(content);
- if(qtype=="TXT" && content.size() > 2) { // strip quotes from TXT
- if(content[0]=='"')
- content=content.substr(1);
- if(content[content.size()-1]=='"')
- content.resize(content.size()-1);
- }
-
- fillRec(qname, qtype, content,ttl, 0, rec);
- return true;
- }
- else {
- throw AhuException("No content on line "+itoa(d_lineno));
- }
- return false;
-}
-
-