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
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
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
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}
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
--- /dev/null
+lib_LTLIBRARIES = libopendbxbackend.la
+libopendbxbackend_la_SOURCES = odbxbackend.hh odbxbackend.cc odbxprivate.cc
+libopendbxbackend_la_LIBADD = -lopendbx
+
+EXTRA_DIST = OBJECTFILES OBJECTLIBS
--- /dev/null
+odbxbackend.o odbxprivate.o
--- /dev/null
+-lopendbx
\ No newline at end of file
--- /dev/null
+#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;
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+#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;
+}
--- /dev/null
+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;
--- /dev/null
+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;
--- /dev/null
+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
+);
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);