]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
add opendbx
authorBert Hubert <bert.hubert@netherlabs.nl>
Sun, 15 Jan 2006 21:26:03 +0000 (21:26 +0000)
committerBert Hubert <bert.hubert@netherlabs.nl>
Sun, 15 Jan 2006 21:26:03 +0000 (21:26 +0000)
speedup in dnswriter (CHECK!)
add publish to auto-build

git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@559 d19b8d6e-7fed-0310-83ef-9ca221ded41b

14 files changed:
build-scripts/auto-build
configure.in
debian-pdns/control
debian-pdns/rules
modules/opendbxbackend/Makefile.am [new file with mode: 0644]
modules/opendbxbackend/OBJECTFILES [new file with mode: 0644]
modules/opendbxbackend/OBJECTLIBS [new file with mode: 0644]
modules/opendbxbackend/odbxbackend.cc [new file with mode: 0644]
modules/opendbxbackend/odbxbackend.hh [new file with mode: 0644]
modules/opendbxbackend/odbxprivate.cc [new file with mode: 0644]
modules/opendbxbackend/tables-mysql.sql [new file with mode: 0644]
modules/opendbxbackend/tables-pgsql.sql [new file with mode: 0644]
modules/opendbxbackend/tables-sqlite.sql [new file with mode: 0644]
pdns/dnswriter.cc

index fce76ba4462dd8102bc45929137b95a9e80d5d31..1aac1c04f2b26a5ffe1ca1cb8937aaabdbab4401 100755 (executable)
@@ -23,6 +23,7 @@ fi
 rm -rf pdns
 svn co svn://svn.powerdns.com/pdns/trunk/pdns
 cd pdns
+LATEST=$(svn info . | awk  '/^Revision/ { print $2 }'  )
 DATE=$(date +%Y%m%d).$LATEST
 ssed -r "s/Version: (.*)/Version: \\1.$DATE/" -i *.spec
 ssed -r "s/AM_INIT_AUTOMAKE\\(pdns, (.*)\\)/AM_INIT_AUTOMAKE\(pdns, \\1.$DATE\)/" -i configure.in
@@ -35,5 +36,7 @@ fakeroot ./build-scripts/rpm-build-instruction
 build-scripts/tar-gz-build-instruction
 cd ..
 mv pdns/*.tar.gz .
+ssh adsl-xs4all.ds9a.nl mkdir /var/www/svn.powerdns.com/snapshots/$LATEST
+scp pdns*$LATEST*{rpm,deb,tar.gz} adsl-xs4all.ds9a.nl:/var/www/svn.powerdns.com/snapshots/$LATEST
 
 
index 445ac1f71fd9e8feda97a060ac528bb3a48c4714..93c79c0eaeb0f6f274a8ca9c4dc4f3f9fd5c98ff 100644 (file)
@@ -412,7 +412,7 @@ AC_OUTPUT(Makefile modules/Makefile pdns/Makefile codedocs/Makefile \
 pdns/backends/Makefile pdns/backends/bind/Makefile pdns/pdns pdns/precursor \
 modules/mysqlbackend/Makefile modules/pdnsbackend/Makefile \
 modules/gmysqlbackend/Makefile modules/db2backend/Makefile \
-modules/geobackend/Makefile \
+modules/geobackend/Makefile modules/opendbxbackend/Makefile \
 modules/pipebackend/Makefile modules/oraclebackend/Makefile \
 modules/xdbbackend/Makefile modules/odbcbackend/Makefile \
 modules/gpgsqlbackend/Makefile modules/ldapbackend/Makefile 
index 7ecdf0123d10308502a181cfcff1e184ecf54521..341a0bf9a9f5c5d7904db10258dcc9741c259a14 100644 (file)
@@ -51,6 +51,13 @@ Provides: pdns-backend
 Description: LDAP backend for pDNS
  This package contains a LDAP backend for the PowerDNS nameserver.
 
+Package: pdns-backend-opendbx
+Architecture: any
+Depends: pdns (= ${dpkg:Version}), ${shlibs:Depends}
+Provides: pdns-backend
+Description: OpenDBX backend for pDNS
+ This package contains a OpenDBX backend for the PowerDNS nameserver.
+
 Package: pdns-backend-mysql
 Architecture: any
 Depends: pdns (= ${dpkg:Version}), ${shlibs:Depends}
index f274c2bf488786d18acebd9cc711661e1af78ca9..d960aa00e1c576212547e343edde438122de8427 100755 (executable)
@@ -2,8 +2,8 @@
 
 tmpdir         := $(shell pwd)/debian-pdns/tmp
 be_tmpdir      := $(shell pwd)/debian-pdns/tmp-backend
-backends       := ldap mysql pipe xdb gmysql gpgsql gsqlite 
-debs           := ldap mysql pipe xdb pgsql sqlite 
+backends       := opendbx ldap mysql pipe xdb gmysql gpgsql gsqlite
+debs           := opendbx ldap mysql pipe xdb pgsql sqlite
 
 binary-doc:
        -make -C pdns/docs html/index.html
diff --git a/modules/opendbxbackend/Makefile.am b/modules/opendbxbackend/Makefile.am
new file mode 100644 (file)
index 0000000..66d48d2
--- /dev/null
@@ -0,0 +1,5 @@
+lib_LTLIBRARIES = libopendbxbackend.la
+libopendbxbackend_la_SOURCES = odbxbackend.hh odbxbackend.cc odbxprivate.cc
+libopendbxbackend_la_LIBADD = -lopendbx
+
+EXTRA_DIST = OBJECTFILES OBJECTLIBS
diff --git a/modules/opendbxbackend/OBJECTFILES b/modules/opendbxbackend/OBJECTFILES
new file mode 100644 (file)
index 0000000..cf716f8
--- /dev/null
@@ -0,0 +1 @@
+odbxbackend.o odbxprivate.o
diff --git a/modules/opendbxbackend/OBJECTLIBS b/modules/opendbxbackend/OBJECTLIBS
new file mode 100644 (file)
index 0000000..d9fd8a6
--- /dev/null
@@ -0,0 +1 @@
+-lopendbx
\ No newline at end of file
diff --git a/modules/opendbxbackend/odbxbackend.cc b/modules/opendbxbackend/odbxbackend.cc
new file mode 100644 (file)
index 0000000..c03008c
--- /dev/null
@@ -0,0 +1,614 @@
+#include "odbxbackend.hh"
+
+
+
+unsigned int odbx_host_index = 0;
+
+
+
+OdbxBackend::OdbxBackend( const string& suffix )
+{
+       int err = -1;
+       unsigned int  idx, i, h;
+       vector<string> hosts;
+
+
+       try
+       {
+               m_result = NULL;
+               m_myname = "[OpendbxBackend]";
+               m_default_ttl = arg().asNum( "default-ttl" );
+               m_qlog = arg().mustDo( "query-logging" );
+
+               setArgPrefix( "opendbx" + suffix );
+               stringtok( hosts, getArg( "host" ), ", " );
+
+               idx = odbx_host_index++ % hosts.size();
+
+               for( i = 0; i < hosts.size(); i++ )
+               {
+                       h = ( idx + i ) % hosts.size();
+                       if( !( err = odbx_init( &m_handle, getArg( "backend" ).c_str(), hosts[h].c_str(), getArg( "port" ).c_str() ) ) ) { break; }
+               }
+
+               if( err < 0 )
+               {
+                       L.log( m_myname + " OdbxBackend: Unable to connect to server - " + string( odbx_error( m_handle, err ) ),  Logger::Error );
+                       throw( AhuException( "Fatal: odbx_init() failed" ) );
+               }
+
+               if( ( err = odbx_bind_simple( m_handle, getArg( "database" ).c_str(), getArg( "username" ).c_str(), getArg( "password" ).c_str() ) ) < 0 )
+               {
+                       L.log( m_myname + " OdbxBackend: Unable to bind to database - " + string( odbx_error( m_handle, err ) ),  Logger::Error );
+                       throw( AhuException( "Fatal: odbx_bind_simple() failed" ) );
+               }
+       }
+       catch( exception& e )
+       {
+               L.log( m_myname + " OdbxBackend: Caught STL exception - " + e.what(),  Logger::Error );
+               throw( DBException( "Fatal: STL exception" ) );
+       }
+
+       L.log( m_myname + " Connection succeeded", Logger::Notice );
+}
+
+
+
+OdbxBackend::~OdbxBackend()
+{
+       odbx_unbind( m_handle );
+       odbx_finish( m_handle );
+}
+
+
+
+bool OdbxBackend::getDomainInfo( const string& domain, DomainInfo& di )
+{
+       const char* tmp;
+       string stmt, type;
+
+
+       try
+       {
+               DLOG( L.log( m_myname + " getDomainInfo()", Logger::Debug ) );
+
+               stmt = strbind( ":name", escape( toLower( domain ) ), getArg( "sql-zoneinfo" ) );
+               execStmt( stmt.c_str(), stmt.size(), true );
+
+               if( !getRecord() ) { return false; }
+
+               do
+               {
+                       di.id = 0;
+                       di.zone = "";
+                       di.master = "";
+                       di.last_check = 0;
+                       di.backend = this;
+                       type = "";
+
+                       if( ( tmp = odbx_field_value( m_result, 0 ) ) != NULL )
+                       {
+                               di.id = strtol( tmp, NULL, 10 );
+                       }
+
+                       if( ( tmp = odbx_field_value( m_result, 1 ) ) != NULL )
+                       {
+                               di.zone = string( tmp );
+                       }
+
+                       if( ( tmp = odbx_field_value( m_result, 2 ) ) != NULL )
+                       {
+                               di.master = string( tmp );
+                       }
+
+                       if( ( tmp = odbx_field_value( m_result, 3 ) ) != NULL )
+                       {
+                               di.last_check = strtol( tmp, NULL, 10 );
+                       }
+
+                       if( ( tmp = odbx_field_value( m_result, 5 ) ) != NULL )
+                       {
+                               type = string( tmp );
+                       }
+
+                       di.kind = DomainInfo::Native;
+
+                       if( type == "SLAVE" )
+                       {
+                               SOAData sd;
+
+                               sd.serial = 0;
+
+                               if( ( tmp = odbx_field_value( m_result, 6 ) ) != NULL )
+                               {
+                                       DNSPacket::fillSOAData( string( tmp ), sd );
+                               }
+                               else
+                               {
+                                       L.log( m_myname + " getDomainInfo: No serial for '" + domain + "' found", Logger::Notice );
+                               }
+
+                               di.serial = sd.serial;
+                               di.kind = DomainInfo::Slave;
+                       }
+                       else if( type == "MASTER" )
+                       {
+                               di.kind = DomainInfo::Master;
+                       }
+               }
+               while( getRecord() );
+       }
+       catch( exception& e )
+       {
+               L.log( m_myname + " getDomainInfo: Caught STL exception - " + e.what(),  Logger::Error );
+               throw( DBException( "Error: STL exception" ) );
+       }
+
+       return true;
+}
+
+
+
+bool OdbxBackend::list( const string& target, int zoneid )
+{
+       string stmt;
+       size_t len;
+
+
+
+       try
+       {
+               DLOG( L.log( m_myname + " list()", Logger::Debug ) );
+
+               m_qname = "";
+               m_result = NULL;
+
+               len = snprintf( m_buffer, sizeof( m_buffer ) - 1, "%d", zoneid );
+
+               if( len < 0 || len > sizeof( m_buffer ) - 1 )
+               {
+                       L.log( m_myname + " list: Unable to convert zone id to string",  Logger::Error );
+                       throw( DBException( "Error: Libc error" ) );
+               }
+
+               stmt = strbind( ":id", string( m_buffer, len ), getArg( "sql-list" ) );
+
+               execStmt( stmt.c_str(), stmt.size(), true );
+       }
+       catch( exception& e )
+       {
+               L.log( m_myname + " list: Caught STL exception - " + e.what(),  Logger::Error );
+               throw( DBException( "Error: STL exception" ) );
+       }
+
+       return true;
+}
+
+
+
+void OdbxBackend::lookup( const QType& qtype, const string& qname, DNSPacket* dnspkt, int zoneid )
+{
+       string stmt;
+
+
+       try
+       {
+               DLOG( L.log( m_myname + " lookup()", Logger::Debug ) );
+
+               m_result = NULL;
+               m_qname = qname;
+               
+               if( zoneid < 0 )
+               {
+                       if( qtype.getCode() == QType::ANY )
+                       {
+                               stmt = getArg( "sql-lookup" );
+                       } else {
+                               stmt = strbind( ":type", qtype.getName(), getArg( "sql-lookuptype" ) );
+                       }
+               }
+               else
+               {
+                       if( qtype.getCode() == QType::ANY )
+                       {
+                               stmt = getArg( "sql-lookupid" );
+                       } else {
+                               stmt = strbind( ":type", qtype.getName(), getArg( "sql-lookuptypeid" ) );
+                       }
+                       
+                       size_t len = snprintf( m_buffer, sizeof( m_buffer ) - 1, "%d", zoneid );
+
+                       if( len < 0 || len > sizeof( m_buffer ) - 1 )
+                       {
+                               L.log( m_myname + " lookup: Unable to convert zone id to string",  Logger::Error );
+                               throw( DBException( "Error: Libc error" ) );
+                       }
+
+                       stmt = strbind( ":id", string( m_buffer, len ), stmt );
+               }
+
+               stmt = strbind( ":name", escape( toLower( qname ) ), stmt );
+               execStmt( stmt.c_str(), stmt.size(), true );
+       }
+       catch( exception& e )
+       {
+               L.log( m_myname + " lookup: Caught STL exception - " + e.what(),  Logger::Error );
+               throw( DBException( "Error: STL exception" ) );
+       }
+}
+
+
+
+bool OdbxBackend::get( DNSResourceRecord& rr )
+{
+       const char* tmp;
+
+
+       try
+       {
+               DLOG( L.log( m_myname + " get()", Logger::Debug ) );
+
+               if( getRecord() )
+               {
+                       rr.content = "";
+                       rr.priority = 0;
+                       rr.domain_id = 0;
+                       rr.last_modified = 0;
+                       rr.ttl = m_default_ttl;
+                       rr.qname = m_qname;
+
+                       if( ( tmp = odbx_field_value( m_result, 0 ) ) != NULL )
+                       {
+                               rr.content = string( tmp );
+                       }
+
+                       if( ( tmp = odbx_field_value( m_result, 1 ) ) != NULL )
+                       {
+                               rr.ttl = strtoul( tmp, NULL, 10 );
+                       }
+
+                       if( ( tmp = odbx_field_value( m_result, 2 ) ) != NULL )
+                       {
+                               rr.priority = (u_int16_t) strtoul( tmp, NULL, 10 );
+                       }
+
+                       if( ( tmp = odbx_field_value( m_result, 3 ) ) != NULL )
+                       {
+                               rr.qtype = QType( tmp );
+                       }
+
+                       if( ( tmp = odbx_field_value( m_result, 4 ) ) != NULL )
+                       {
+                               rr.domain_id = strtol( tmp, NULL, 10 );
+                       }
+
+                       if( m_qname.empty() && ( tmp = odbx_field_value( m_result, 5 ) ) != NULL )
+                       {
+                               rr.qname = string( tmp );
+                       }
+
+                       return true;
+               }
+       }
+       catch( exception& e )
+       {
+               L.log( m_myname + " get: Caught STL exception - " + e.what(),  Logger::Error );
+               throw( DBException( "Error: STL exception" ) );
+       }
+
+       return false;
+}
+
+
+void OdbxBackend::setFresh( u_int32_t domain_id )
+{
+       size_t len;
+
+
+       try
+       {
+               DLOG( L.log( m_myname + " setFresh()", Logger::Debug ) );
+
+               len = snprintf( m_buffer, sizeof( m_buffer ) - 1, getArg( "sql-update-lastcheck" ).c_str(), time( 0 ), domain_id );
+
+               if( len < 0 || len > sizeof( m_buffer ) - 1 )
+               {
+                       L.log( m_myname + " setFresh: Unable to insert values into statement '" + getArg( "sql-update-lastcheck" ) + "'",  Logger::Error );
+                       throw( DBException( "Error: Libc error" ) );
+               }
+
+               execStmt( m_buffer, len, false );
+       }
+       catch ( exception& e )
+       {
+               L.log( m_myname + " setFresh: Caught STL exception - " + e.what(),  Logger::Error );
+               throw( DBException( "Error: STL exception" ) );
+       }
+}
+
+
+
+void OdbxBackend::setNotified( u_int32_t domain_id, u_int32_t serial )
+{
+       size_t len;
+
+
+       try
+       {
+               DLOG( L.log( m_myname + " setNotified()", Logger::Debug ) );
+
+               len = snprintf( m_buffer, sizeof( m_buffer ) - 1, getArg( "sql-update-serial" ).c_str(), serial, domain_id );
+
+               if( len < 0 || len > sizeof( m_buffer ) - 1 )
+               {
+                       L.log( m_myname + " setNotified: Unable to insert values into statement '" + getArg( "sql-update-serial" ) + "'",  Logger::Error );
+                       throw( DBException( "Error: Libc error" ) );
+               }
+
+               execStmt( m_buffer, len, false );
+       }
+       catch ( exception& e )
+       {
+               L.log( m_myname + " setNotified: Caught STL exception - " + e.what(),  Logger::Error );
+               throw( DBException( "Error: STL exception" ) );
+       }
+}
+
+
+
+bool OdbxBackend::isMaster( const string& domain, const string& ip )
+{
+       string stmt;
+
+
+       try
+       {
+               DLOG( L.log( m_myname + " isMaster()", Logger::Debug ) );
+
+               stmt = strbind( ":name", escape( toLower( domain ) ), getArg( "sql-master" ) );
+               execStmt( stmt.c_str(), stmt.size(), true );
+
+               if( !getRecord() ) { return false; }
+
+               do
+               {
+                       if( odbx_field_value( m_result, 0 ) != NULL )
+                       {
+                               if( !strcmp( odbx_field_value( m_result, 0 ), ip.c_str() ) )
+                               {
+                                       return true;
+                               }
+                       }
+               }
+               while( getRecord() );
+       }
+       catch ( exception& e )
+       {
+               L.log( m_myname + " isMaster: Caught STL exception - " + e.what(),  Logger::Error );
+               throw( DBException( "Error: STL exception" ) );
+       }
+
+       return false;
+}
+
+
+
+void OdbxBackend::getUnfreshSlaveInfos( vector<DomainInfo>* unfresh )
+{
+       try
+       {
+               DLOG( L.log( m_myname + " getUnfreshSlaveInfos()", Logger::Debug ) );
+
+               if( unfresh != NULL )
+               {
+                       getDomainList( getArg( "sql-infoslaves" ), unfresh, &checkSlave );
+               }
+       }
+       catch ( exception& e )
+       {
+               L.log( m_myname + " getUnfreshSlaveInfo: Caught STL exception - " + e.what(),  Logger::Error );
+               throw( DBException( "Error: STL exception" ) );
+       }
+}
+
+
+
+void OdbxBackend::getUpdatedMasters( vector<DomainInfo>* updated )
+{
+       try
+       {
+               DLOG( L.log( m_myname + " getUpdatedMasters()", Logger::Debug ) );
+
+               if( updated != NULL )
+               {
+                       getDomainList( getArg( "sql-infomasters" ), updated, &checkMaster );
+               }
+       }
+       catch ( exception& e )
+       {
+               L.log( m_myname + " getUpdatedMasters: Caught STL exception - " + e.what(),  Logger::Error );
+               throw( DBException( "Error: STL exception" ) );
+       }
+}
+
+
+
+bool OdbxBackend::superMasterBackend( const string& ip, const string& domain, const vector<DNSResourceRecord>& set, string* account, DNSBackend** ddb )
+{
+       string stmt;
+       vector<DNSResourceRecord>::const_iterator i;
+
+
+       try
+       {
+               DLOG( L.log( m_myname + " superMasterBackend()", Logger::Debug ) );
+
+               if( account != NULL && ddb != NULL )
+               {
+                       for( i = set.begin(); i != set.end(); i++ )
+                       {
+                               stmt = strbind( ":ip", escape( ip ), getArg( "sql-supermaster" ) );
+                               stmt = strbind( ":ns", escape( i->content ), stmt );
+
+                               execStmt( stmt.c_str(), stmt.size(), true );
+
+                               if( !getRecord() ) { return false; }
+
+                               do
+                               {
+                                       if( odbx_field_value( m_result, 0 ) != NULL )
+                                       {
+                                               *account = string( odbx_field_value( m_result, 0 ), odbx_field_length( m_result, 0 ) );
+                                       }
+                               }
+                               while( getRecord() );
+
+                               *ddb=this;
+                               return true;
+                       }
+               }
+       }
+       catch ( exception& e )
+       {
+               L.log( m_myname + " superMasterBackend: Caught STL exception - " + e.what(),  Logger::Error );
+               throw( DBException( "Error: STL exception" ) );
+       }
+
+       return false;
+}
+
+
+
+bool OdbxBackend::createSlaveDomain( const string& ip, const string& domain, const string& account )
+{
+       size_t len;
+
+
+       try
+       {
+               DLOG( L.log( m_myname + " createSlaveDomain()", Logger::Debug ) );
+
+               len = snprintf( m_buffer, sizeof( m_buffer ) - 1, getArg( "sql-insert-slave" ).c_str(), escape( toLower( domain ) ).c_str(),
+                       escape( ip ).c_str(), escape( account ).c_str() );
+
+               if( len < 0 || len > sizeof( m_buffer ) - 1 )
+               {
+                       L.log( m_myname + " createSlaveDomain: Unable to insert values in statement '" + getArg( "sql-insert-slave" ) + "'",  Logger::Error );
+                       throw( DBException( "Error: Libc error" ) );
+               }
+
+               execStmt( m_buffer, len, false );
+       }
+       catch ( exception& e )
+       {
+               L.log( m_myname + " createSlaveDomain: Caught STL exception - " + e.what(),  Logger::Error );
+               throw( DBException( "Error: STL exception" ) );
+       }
+
+       return true;
+}
+
+
+
+bool OdbxBackend::feedRecord( const DNSResourceRecord& rr )
+{
+       size_t len;
+
+
+       try
+       {
+               DLOG( L.log( m_myname + " feedRecord()", Logger::Debug ) );
+
+               len = snprintf( m_buffer, sizeof( m_buffer ) - 1, getArg( "sql-insert-record" ).c_str(), rr.domain_id,
+                       escape( toLower( rr.qname ) ).c_str(), rr.qtype.getName().c_str(), rr.ttl, rr.priority, escape( rr.content ).c_str() );
+
+               if( len < 0 || len > sizeof( m_buffer ) - 1 )
+               {
+                       L.log( m_myname + " feedRecord: Unable to insert values in statement '" + getArg( "sql-insert-record" ) + "'",  Logger::Error );
+                       throw( DBException( "Error: Libc error" ) );
+               }
+
+               execStmt( m_buffer, len, false );
+       }
+       catch ( exception& e )
+       {
+               L.log( m_myname + " feedRecord: Caught STL exception - " + e.what(),  Logger::Error );
+               throw( DBException( "Error: STL exception" ) );
+       }
+
+       return true;
+}
+
+
+
+bool OdbxBackend::startTransaction( const string& domain, int zoneid )
+{
+       size_t len;
+       string stmt;
+
+
+       try
+       {
+               DLOG( L.log( m_myname + " startTransaction()", Logger::Debug ) );
+
+               stmt = getArg( "sql-transactbegin" );
+               execStmt( stmt.c_str(), stmt.size(), false );
+
+               len = snprintf( m_buffer, sizeof( m_buffer ) - 1, "%d", zoneid );
+
+               if( len < 0 || len > sizeof( m_buffer ) - 1 )
+               {
+                       L.log( m_myname + " lookup: Unable to convert zone id to string",  Logger::Error );
+                       throw( DBException( "Error: Libc error" ) );
+               }
+
+               stmt = strbind( ":id", string( m_buffer, len ), getArg( "sql-zonedelete" ) );
+
+               execStmt( stmt.c_str(), stmt.size(), false );
+       }
+       catch ( exception& e )
+       {
+               L.log( m_myname + " startTransaction: Caught STL exception - " + e.what(),  Logger::Error );
+               throw( DBException( "Error: STL exception" ) );
+       }
+
+       return true;
+}
+
+
+
+bool OdbxBackend::commitTransaction()
+{
+       try
+       {
+               DLOG( L.log( m_myname + " commitTransaction()", Logger::Debug ) );
+
+               execStmt( getArg( "sql-transactend" ).c_str(), getArg( "sql-transactend" ).size(), false );
+       }
+       catch ( exception& e )
+       {
+               L.log( m_myname + " commitTransaction: Caught STL exception - " + e.what(),  Logger::Error );
+               throw( DBException( "Error: STL exception" ) );
+       }
+
+       return true;
+}
+
+
+
+bool OdbxBackend::abortTransaction()
+{
+       try
+       {
+               DLOG( L.log( m_myname + " abortTransaction()", Logger::Debug ) );
+
+               execStmt( getArg( "sql-transactabort" ).c_str(), getArg( "sql-transabort" ).size(), false );
+       }
+       catch ( exception& e )
+       {
+               L.log( m_myname + " abortTransaction: Caught STL exception - " + e.what(),  Logger::Error );
+               throw( DBException( "Error: STL exception" ) );
+       }
+
+       return true;
+}
diff --git a/modules/opendbxbackend/odbxbackend.hh b/modules/opendbxbackend/odbxbackend.hh
new file mode 100644 (file)
index 0000000..798b515
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ *  PowerDNS OpenDBX Backend
+ *  Copyright (C) 2005 Norbert Sendetzky <norbert@linuxnetworks.de>
+ *
+ *  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
+ *  any later version.
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+
+#include <string>
+#include <cstdlib>
+#include <sstream>
+#include <sys/time.h>
+#include <pdns/dns.hh>
+#include <pdns/utility.hh>
+#include <pdns/dnspacket.hh>
+#include <pdns/dnsbackend.hh>
+#include <pdns/ueberbackend.hh>
+#include <pdns/ahuexception.hh>
+#include <pdns/arguments.hh>
+#include <pdns/logger.hh>
+#include <odbx.h>
+#include "modules/ldapbackend/utils.hh"
+
+
+#ifndef ODBXBACKEND_HH
+#define ODBXBACKEND_HH
+
+
+#define BUFLEN 512
+
+
+using std::string;
+using std::vector;
+
+
+
+bool checkSlave( u_int32_t last, u_int32_t notified, SOAData* sd, DomainInfo* di );
+bool checkMaster( u_int32_t last, u_int32_t notified, SOAData* sd, DomainInfo* di );
+
+
+class OdbxBackend : public DNSBackend
+{
+       string m_myname;
+       string m_qname;
+       int m_default_ttl;
+       bool m_qlog;
+       odbx_t* m_handle;
+       odbx_result_t* m_result;
+       char m_escbuf[BUFLEN];
+       char m_buffer[2*BUFLEN];
+
+       bool getRecord();
+       void execStmt( const char* stmt, unsigned long length, bool select );
+       void getDomainList( const string& query, vector<DomainInfo>* list, bool (*check_fcn)(u_int32_t,u_int32_t,SOAData*,DomainInfo*) );
+       string escape( const string& str );
+
+
+public:
+
+       OdbxBackend( const string& suffix="" );
+       ~OdbxBackend();
+
+       void lookup( const QType& qtype, const string& qdomain, DNSPacket* p = 0, int zoneid = -1 );
+       bool list( const string& target, int domain_id );
+       bool get( DNSResourceRecord& rr );
+
+       bool startTransaction( const string& domain, int domain_id );
+       bool commitTransaction();
+       bool abortTransaction();
+
+       bool isMaster( const string& domain, const string& ip );
+       bool getDomainInfo( const string& domain, DomainInfo& di );
+       bool feedRecord( const DNSResourceRecord& rr );
+       bool createSlaveDomain( const string& ip, const string& domain, const string& account );
+       bool superMasterBackend( const string& ip, const string& domain, const vector<DNSResourceRecord>& nsset, string* account, DNSBackend** ddb );
+
+       void getUpdatedMasters( vector<DomainInfo>* updated );
+       void getUnfreshSlaveInfos( vector<DomainInfo>* unfresh );
+
+       void setFresh( u_int32_t domain_id );
+       void setNotified( u_int32_t domain_id, u_int32_t serial );
+};
+
+
+
+class OdbxFactory : public BackendFactory
+{
+
+public:
+
+       OdbxFactory() : BackendFactory( "opendbx" ) {}
+
+
+       void declareArguments( const string &suffix="" )
+       {
+               declare( suffix, "backend", "OpenDBX backend","mysql" );
+               declare( suffix, "host", "Name or address of one or more DBMS server","127.0.0.1" );
+               declare( suffix, "port", "Port the DBMS server is listening to","" );
+               declare( suffix, "database", "Database name containing the DNS records","powerdns" );
+               declare( suffix, "username","User for connecting to the DBMS","powerdns");
+               declare( suffix, "password","Password for connecting to the DBMS","");
+
+               declare( suffix, "sql-list", "AXFR query", "SELECT content, ttl, prio, type, domain_id, name FROM records WHERE domain_id=':id'" );
+
+               declare( suffix, "sql-lookup", "Lookup query","SELECT content, ttl, prio, type, domain_id, name FROM records WHERE name=':name'" );
+               declare( suffix, "sql-lookupid", "Lookup query with id","SELECT content, ttl, prio, type, domain_id, name FROM records WHERE name=':name' AND domain_id=':id'" );
+               declare( suffix, "sql-lookuptype", "Lookup query with type","SELECT content, ttl, prio, type, domain_id, name FROM records WHERE type=':type' AND name=':name'" );
+               declare( suffix, "sql-lookuptypeid", "Lookup query with type and id","SELECT content, ttl, prio, type, domain_id, name FROM records WHERE type=':type' AND name=':name' AND domain_id=':id'" );
+
+               declare( suffix, "sql-zonedelete","Delete all records for this zone","DELETE FROM records WHERE domain_id=':id'" );
+               declare( suffix, "sql-zoneinfo","Get domain info","SELECT d.id, d.name, d.master, d.last_check, d.notified_serial, d.type, r.content FROM domains AS d LEFT JOIN records AS r ON d.id=r.domain_id WHERE ( d.name=':name' AND r.type='SOA' ) OR ( d.name=':name' AND r.domain_id IS NULL )" );
+
+               declare( suffix, "sql-transactbegin", "Start transaction", "BEGIN" );
+               declare( suffix, "sql-transactend", "Finish transaction", "COMMIT" );
+               declare( suffix, "sql-transactabort", "Abort transaction", "ROLLBACK" );
+
+               declare( suffix, "sql-insert-slave","Add slave domain", "INSERT INTO domains ( type, name, master, account ) VALUES ( 'SLAVE', '%s', '%s', '%s' )" );
+               declare( suffix, "sql-insert-record","Feed record into table", "INSERT INTO records ( domain_id, name, type, ttl, prio, content ) VALUES ( '%d', '%s', '%s', '%d', '%d', '%s' )" );
+
+               declare( suffix, "sql-update-serial", "Set zone to notified", "UPDATE domains SET notified_serial='%d' WHERE id='%d'" );
+               declare( suffix, "sql-update-lastcheck", "Set time of last check", "UPDATE domains SET last_check='%d' WHERE id='%d'" );
+
+               declare( suffix, "sql-master", "Get master record for zone", "SELECT master FROM domains WHERE type='SLAVE' AND name=':name'" );
+               declare( suffix, "sql-supermaster","Get supermaster info", "SELECT account FROM supermasters WHERE ip=':ip' AND nameserver=':ns'" );
+
+               declare( suffix, "sql-infoslaves", "Get all unfresh slaves", "SELECT d.id, d.name, d.master, d.last_check, d.notified_serial, r.change_date, r.content FROM domains AS d LEFT JOIN records AS r ON d.id=r.domain_id WHERE ( d.type='SLAVE' AND r.type='SOA' ) OR ( d.type='SLAVE' AND r.domain_id IS NULL )" );
+               declare( suffix, "sql-infomasters", "Get all updated masters", "SELECT d.id, d.name, d.master, d.last_check, d.notified_serial, r.change_date, r.content FROM domains AS d, records AS r WHERE d.type='MASTER' AND d.id=r.domain_id AND r.type='SOA'" );
+       }
+
+
+       DNSBackend* make( const string &suffix="" )
+       {
+               return new OdbxBackend( suffix );
+       }
+};
+
+
+class OdbxLoader
+{
+       OdbxFactory factory;
+
+public:
+
+       OdbxLoader()
+       {
+               BackendMakers().report( &factory );
+               L.log( " [OpendbxBackend] This is the opendbx module version "VERSION" ("__DATE__", "__TIME__") reporting", Logger::Info );
+       }
+};
+
+
+static OdbxLoader odbxloader;
+
+
+
+#endif /* ODBXBACKEND_HH */
diff --git a/modules/opendbxbackend/odbxprivate.cc b/modules/opendbxbackend/odbxprivate.cc
new file mode 100644 (file)
index 0000000..58a9d4b
--- /dev/null
@@ -0,0 +1,201 @@
+#include "odbxbackend.hh"
+
+
+
+void OdbxBackend::execStmt( const char* stmt, unsigned long length, bool select )
+{
+       int err;
+
+
+       DLOG( L.log( m_myname + " execStmt()", Logger::Debug ) );
+
+       if( m_qlog ) { L.log( m_myname + " Query: " + stmt, Logger::Info ); }
+
+       if( ( err = odbx_query( m_handle, stmt, length ) ) < 0 )
+       {
+               L.log( m_myname + " execStmt: Unable to execute query - " + string( odbx_error( m_handle, err ) ),  Logger::Error );
+               throw( AhuException( "Error: odbx_query() failed" ) );
+       }
+
+       if( !select ) { while( getRecord() ); }
+}
+
+
+
+bool OdbxBackend::getRecord()
+{
+       int err = 3;
+
+
+       DLOG( L.log( m_myname + " getRecord()", Logger::Debug ) );
+
+       do
+       {
+               if( m_result != NULL )
+               {
+                       if( err == 3 )
+                       {
+                               if( ( err = odbx_row_fetch( m_result ) ) < 0 )
+                               {
+                                       L.log( m_myname + " getRecord: Unable to get next row - " + string( odbx_error( m_handle, err ) ),  Logger::Error );
+                                       throw( AhuException( "Error: odbx_row_fetch() failed" ) );
+                               }
+
+                               if( err > 0 )
+                               {
+#ifdef VERBOSELOG
+                                       unsigned int i;
+                                       string fields;
+
+                                       for( i = 0; i < odbx_column_count( m_result ); i++ )
+                                       {
+                                               fields += string( odbx_column_name( m_result, i ) );
+
+                                               if( odbx_field_value( m_result, i ) != NULL )
+                                               {
+                                                       fields += "=" + string( odbx_field_value( m_result, i ) ) + ", ";
+                                               }
+                                               else
+                                               {
+                                                       fields += "=NULL, ";
+                                               }
+                                       }
+
+                                       L.log( m_myname + " Values: " + fields,  Logger::Error );
+#endif
+                                       return true;
+                               }
+
+                       }
+
+                       odbx_result_free( m_result );
+                       m_result = NULL;
+               }
+       }
+       while( ( err =  odbx_result( m_handle, &m_result, NULL, 0 ) ) > 0 );
+
+       if( err < 0 )
+       {
+               L.log( m_myname + " getRecord: Unable to get next result - " + string( odbx_error( m_handle, err ) ),  Logger::Error );
+               throw( AhuException( "Error: odbx_result() failed" ) );
+       }
+
+       m_result = NULL;
+       return false;
+}
+
+
+
+string OdbxBackend::escape( const string& str )
+{
+       int err;
+       unsigned long len = sizeof( m_escbuf );
+
+
+       DLOG( L.log( m_myname + " escape()", Logger::Debug ) );
+
+       if( ( err = odbx_escape( m_handle, str.c_str(), str.size(), m_escbuf, &len ) ) < 0 )
+       {
+               L.log( m_myname + " escape: Unable to escape string - " + string( odbx_error( m_handle, err ) ),  Logger::Error );
+               throw( AhuException( "Error: odbx_escape() failed" ) );
+       }
+
+       return string( m_escbuf, len );
+}
+
+
+
+void OdbxBackend::getDomainList( const string& stmt, vector<DomainInfo>* list, bool (*check_fcn)(u_int32_t,u_int32_t,SOAData*,DomainInfo*) )
+{
+       const char* tmp;
+       u_int32_t nlast, nserial;
+       DomainInfo di;
+       SOAData sd;
+
+
+       DLOG( L.log( m_myname + " getDomainList()", Logger::Debug ) );
+
+       execStmt( stmt.c_str(), stmt.size(), true );
+
+       if( !getRecord() ) { return; }
+
+       do
+       {
+               nlast = 0;
+               nserial = 0;
+               sd.serial = 0;
+               sd.refresh = 0;
+
+               if( ( tmp = odbx_field_value( m_result, 6 ) ) != NULL )
+               {
+                       DNSPacket::fillSOAData( string( tmp ), sd );
+               }
+
+               if( !sd.serial && ( tmp = odbx_field_value( m_result, 5 ) ) != NULL )
+               {
+                       sd.serial = strtol( tmp, NULL, 10 );
+               }
+
+               if( ( tmp = odbx_field_value( m_result, 4 ) ) != NULL )
+               {
+                       nserial = strtol( tmp, NULL, 10 );
+               }
+
+               if( ( tmp = odbx_field_value( m_result, 3 ) ) != NULL )
+               {
+                       nlast = strtol( tmp, NULL, 10 );
+               }
+
+               if( (*check_fcn)( nlast, nserial, &sd, &di ) )
+               {
+                       if( ( tmp = odbx_field_value( m_result, 2 ) ) != NULL )
+                       {
+                               di.master = string( tmp, odbx_field_length( m_result, 2 ) );
+                       }
+
+                       if( ( tmp = odbx_field_value( m_result, 1 ) ) != NULL )
+                       {
+                               di.zone = string( tmp, odbx_field_length( m_result, 1 ) );
+                       }
+
+                       if( ( tmp = odbx_field_value( m_result, 0 ) ) != NULL )
+                       {
+                               di.id = strtol( tmp, NULL, 10 );
+                       }
+
+                       di.last_check = nlast;
+                       di.notified_serial = nserial;
+                       di.serial = sd.serial;
+                       di.backend = this;
+
+                       list->push_back( di );
+               }
+       }
+       while( getRecord() );
+}
+
+
+
+bool checkSlave( u_int32_t nlast, u_int32_t nserial, SOAData* sd, DomainInfo* di )
+{
+       if( nlast + sd->refresh < (u_int32_t) time( 0 ) )
+       {
+               di->kind = DomainInfo::Slave;
+               return true;
+       }
+
+       return false;
+}
+
+
+
+bool checkMaster( u_int32_t nlast, u_int32_t nserial, SOAData* sd, DomainInfo* di )
+{
+       if( nserial != sd->serial )
+       {
+               di->kind = DomainInfo::Master;
+               return true;
+       }
+
+       return false;
+}
diff --git a/modules/opendbxbackend/tables-mysql.sql b/modules/opendbxbackend/tables-mysql.sql
new file mode 100644 (file)
index 0000000..fbddd7e
--- /dev/null
@@ -0,0 +1,48 @@
+CREATE TABLE domains (
+       id INT auto_increment,
+       type VARCHAR(6) NOT NULL,
+       name VARCHAR(255) NOT NULL,
+       master VARCHAR(40) DEFAULT NULL,
+       account VARCHAR(40) DEFAULT NULL,
+       notified_serial INT DEFAULT NULL,
+       last_check INT DEFAULT NULL,
+CONSTRAINT pk_id
+       PRIMARY KEY (id),
+CONSTRAINT unq_name
+       UNIQUE (name)
+) type=InnoDB;
+
+
+CREATE TABLE records (
+       id INT auto_increment,
+       domain_id INT DEFAULT NULL,
+       name VARCHAR(255) DEFAULT NULL,
+       type VARCHAR(6) DEFAULT NULL,
+       ttl INT DEFAULT NULL,
+       prio INT DEFAULT NULL,
+       content VARCHAR(255) DEFAULT NULL,
+       change_date INT DEFAULT NULL,
+CONSTRAINT pk_id
+       PRIMARY KEY (id),
+CONSTRAINT fk_domainid
+       FOREIGN KEY (domain_id)
+       REFERENCES domains(id)
+       ON UPDATE CASCADE
+       ON DELETE CASCADE
+) type=InnoDB;
+
+CREATE INDEX idx_rname ON records(name);
+CREATE INDEX idx_rname_rtype ON records(name,type);
+CREATE INDEX idx_rdomainid ON records(domain_id);
+
+
+CREATE TABLE supermasters (
+       ip VARCHAR(40) NOT NULL,
+       nameserver VARCHAR(255) NOT NULL,
+       account VARCHAR(40) DEFAULT NULL
+);
+
+
+GRANT SELECT ON supermasters TO powerdns;
+GRANT ALL ON domains TO powerdns;
+GRANT ALL ON records TO powerdns;
diff --git a/modules/opendbxbackend/tables-pgsql.sql b/modules/opendbxbackend/tables-pgsql.sql
new file mode 100644 (file)
index 0000000..5c62e7d
--- /dev/null
@@ -0,0 +1,50 @@
+CREATE TABLE domains (
+       id SERIAL,
+       type VARCHAR(6) NOT NULL,
+       name VARCHAR(255) NOT NULL,
+       master VARCHAR(40) DEFAULT NULL,
+       account VARCHAR(40) DEFAULT NULL
+       notified_serial INT DEFAULT NULL,
+       last_check INT DEFAULT NULL,
+CONSTRAINT pk_id
+       PRIMARY KEY (id),
+CONSTRAINT unq_name
+       UNIQUE (name)
+);
+
+
+CREATE TABLE records (
+       id SERIAL,
+       domain_id INT DEFAULT NULL,
+       name VARCHAR(255) DEFAULT NULL,
+       type VARCHAR(6) DEFAULT NULL,
+       ttl INT DEFAULT NULL,
+       prio INT DEFAULT NULL,
+       content VARCHAR(255) DEFAULT NULL,
+       change_date INT DEFAULT NULL,
+CONSTRAINT pk_id
+       PRIMARY KEY (id),
+CONSTRAINT fk_domainid
+       FOREIGN KEY (domain_id)
+       REFERENCES domains(id)
+       ON UPDATE CASCADE
+       ON DELETE CASCADE
+);
+
+CREATE INDEX idx_rname ON records(name);
+CREATE INDEX idx_rname_rtype ON records(name,type);
+CREATE INDEX idx_rdomainid ON records(domain_id);
+
+
+CREATE TABLE supermasters (
+       ip VARCHAR(40) NOT NULL,
+       nameserver VARCHAR(255) NOT NULL,
+       account VARCHAR(40) DEFAULT NULL
+);
+
+
+GRANT SELECT ON supermasters TO powerdns;
+GRANT ALL ON domains TO powerdns;
+GRANT ALL ON domains_id_seq TO powerdns;
+GRANT ALL ON records TO powerdns;
+GRANT ALL ON records_id_seq TO powerdns;
diff --git a/modules/opendbxbackend/tables-sqlite.sql b/modules/opendbxbackend/tables-sqlite.sql
new file mode 100644 (file)
index 0000000..ec3052f
--- /dev/null
@@ -0,0 +1,43 @@
+CREATE TABLE domains (
+       id INT AUTOINCREMENT,
+       type VARCHAR(6) NOT NULL,
+       name VARCHAR(255) NOT NULL,
+       master VARCHAR(40) DEFAULT NULL,
+       account VARCHAR(40) DEFAULT NULL,
+       notified_serial INT DEFAULT NULL,
+       last_check INT DEFAULT NULL,
+CONSTRAINT pk_id
+       PRIMARY KEY (id),
+CONSTRAINT unq_name
+       UNIQUE (name)
+);
+
+
+CREATE TABLE records (
+       id INT AUTOINCREMENT,
+       domain_id INT DEFAULT NULL,
+       name VARCHAR(255) DEFAULT NULL,
+       type VARCHAR(6) DEFAULT NULL,
+       ttl INT DEFAULT NULL,
+       prio INT DEFAULT NULL,
+       content VARCHAR(255) DEFAULT NULL,
+       change_date INT DEFAULT NULL,
+CONSTRAINT pk_id
+       PRIMARY KEY (id),
+CONSTRAINT fk_domainid
+       FOREIGN KEY (domain_id)
+       REFERENCES domains(id)
+       ON UPDATE CASCADE
+       ON DELETE CASCADE
+);
+
+CREATE INDEX idx_rname ON records(name);
+CREATE INDEX idx_rname_rtype ON records(name,type);
+CREATE INDEX idx_rdomainid ON records(domain_id);
+
+
+CREATE TABLE supermasters (
+       ip VARCHAR(40) NOT NULL,
+       nameserver VARCHAR(255) NOT NULL,
+       account VARCHAR(40) DEFAULT NULL
+);
index feb1562ac0220b3d82d4b161155d5dd5aab9f51b..4b79120ea7624b2bd9712729ba69ce04ffddd279 100644 (file)
@@ -13,10 +13,25 @@ DNSPacketWriter::DNSPacketWriter(vector<uint8_t>& content, const string& qname,
   dnsheader.qdcount=htons(1);
   
   const uint8_t* ptr=(const uint8_t*)&dnsheader;
-  d_content.insert(d_content.end(), ptr, ptr + sizeof(dnsheader));    
+  uint32_t len=d_content.size();
+  d_content.resize(len + sizeof(dnsheader));
+  uint8_t* dptr=(&*d_content.begin()) + len;
+
+
+  memcpy(dptr, ptr, sizeof(dnsheader));
+
+  //  d_content.insert(d_content.end(), ptr, ptr + sizeof(dnsheader));    
   
   xfrLabel(qname, false);
-  d_content.insert(d_content.end(), d_record.begin(), d_record.end());
+  
+  len=d_content.size();
+  d_content.resize(len + d_record.size());
+  ptr=&*d_record.begin();
+  dptr=(&*d_content.begin()) + len;
+  
+  memcpy(dptr, ptr, d_record.size());
+  //  d_content.insert(d_content.end(), d_record.begin(), d_record.end());
+
   d_record.clear();
 
   qtype=htons(qtype);