+++ /dev/null
-// $Id$
-
-#include <string>
-#include <unistd.h>
-#include <stdlib.h>
-#include <sstream>
-
-#include "pdns/namespaces.hh"
-
-#include "pdns/dns.hh"
-#include "pdns/dnsbackend.hh"
-#include "pdns/dnspacket.hh"
-#include "pdns/ueberbackend.hh"
-#include "pdns/pdnsexception.hh"
-#include "pdns/logger.hh"
-#include "pdns/arguments.hh"
-
-#include "DB2Exception.hh"
-#include "DB2Backend.hh"
-
-static const string kBackendName="[DB2Backend]";
-
-static const int kForwardQuery = 0;
-static const int kForwardByZoneQuery = 1;
-static const int kForwardAnyQuery = 2;
-static const int kForwardWildcardQuery = 3;
-static const int kForwardWildcardAnyQuery = 4;
-
-static const int kListQuery = 5;
-
-static const int kNumQueries = 6;
-
-static const char *kQueries[kNumQueries] =
-{
- // ForwardQuery
- "select Content, TimeToLive, Priority, Type, ZoneId, 0 as ChangeDate, Name from Records where Name = ? and type = ?",
-
- // ForwardByZoneQuery
- "select Content, TimeToLive, Priority, Type, ZoneId, 0 as ChangeDate, Name from Records where Name = ? and Type = ? and ZoneId = ?",
-
- // ForwardAnyQuery
- "select Content, TimeToLive, Priority, Type, ZoneId, 0 as ChangeDate, Name from Records where Name = ?",
-
- // ForwardWildcardQuery
- "select Content, TimeToLive, Priority, Type, ZoneId, 0 as ChangeDate, Name from Records where Name like ? and Type = ?",
-
- // ForwardWildcardAnyQuery
- "select Content, TimeToLive, Priority, Type, ZoneId, 0 as ChangeDate, Name from Records where Name like ?",
-
- // ListQuery
- "select Content, TimeToLive, Priority, Type, ZoneId, 0 as ChangeDate, Name from Records where ZoneId = ?"
-};
-
-static const char *kSoaQuery = "select Id,Hostmaster,Serial from Zones where Active = 1 and Name = ?";
-
-DB2Backend::DB2Backend(const string &suffix)
-{
- SQLRETURN theError;
-
- // Initialize the handles
- mConnection = SQL_NULL_HANDLE;
- mEnvironment = SQL_NULL_HANDLE;
- for (int i = 0; i < kNumQueries; i++) {
- mStatements[i] = SQL_NULL_HANDLE;
- }
-
- try
- {
- // Allocate the Environment Handle
- theError = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &mEnvironment);
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError);
- }
-
- // Allocate a Connection Handle
- theError = SQLAllocHandle(SQL_HANDLE_DBC, mEnvironment, &mConnection);
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError, SQL_HANDLE_ENV, mEnvironment);
- }
-
- // Try to connect to the database
- theError = SQLConnect(mConnection, (SQLCHAR*) arg()["db2-"+suffix+"server"].c_str(), SQL_NTS, (SQLCHAR*) arg()["db2-"+suffix+"user"].c_str(), SQL_NTS, (SQLCHAR*) arg()["db2-"+suffix+"password"].c_str(), SQL_NTS);
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError, SQL_HANDLE_DBC, mConnection);
- }
-
- // Set autocommit to off
- theError = SQLSetConnectAttr(mConnection, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER) SQL_AUTOCOMMIT_OFF, SQL_NTS);
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError, SQL_HANDLE_DBC, mConnection);
- }
-
- // Prepare the statements
- for (int i = 0; i < kNumQueries; i++)
- {
- // Allocate a Statement Handle
- theError = SQLAllocHandle(SQL_HANDLE_STMT, mConnection, &(mStatements[i]));
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError, SQL_HANDLE_DBC, mConnection);
- }
-
- // Prepare the statement
- theError = SQLPrepare(mStatements[i], (SQLCHAR*) kQueries[i], SQL_NTS);
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError, SQL_HANDLE_DBC, mStatements[i]);
- }
-
- //
- // Bind Parameters
- //
-
- // Bind the Name parameter to all queries except the list statements
- if (i != kListQuery) {
- theError = SQLBindParameter(mStatements[i], 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 256, 0, mParamName, 256, NULL);
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError, SQL_HANDLE_DBC, mStatements[i]);
- }
- }
-
- // Bind the Type parameter only to the kForwardQuery, kForwardByZoneQuery and kForwardWildcardQuery statements
- if (i == kForwardQuery || i == kForwardByZoneQuery || i == kForwardWildcardQuery) {
- theError = SQLBindParameter(mStatements[i], 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 256, 0, mParamType, 256, NULL);
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError, SQL_HANDLE_DBC, mStatements[i]);
- }
- }
-
- // Bind the ZoneId parameter for the kForwardByZoneQuery and kListQuery queries
- if (i == kForwardByZoneQuery || i == kListQuery) {
- int theIndex = (i == kForwardByZoneQuery) ? 3 : 1;
- theError = SQLBindParameter(mStatements[i], theIndex, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &mParamZoneId, 0, NULL);
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError, SQL_HANDLE_DBC, mStatements[i]);
- }
- }
-
- //
- // Bind Columns
- //
-
- // Bind the Content column
- mResultContentIndicator = 0;
- theError = SQLBindCol(mStatements[i], 1, SQL_C_CHAR, mResultContent, sizeof(mResultContent), &mResultContentIndicator);
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError, SQL_HANDLE_DBC, mStatements[i]);
- }
-
- // Bind the TimeToLive column
- mResultTimeToLiveIndicator = 0;
- theError = SQLBindCol(mStatements[i], 2, SQL_C_LONG, &mResultTimeToLive, sizeof(mResultTimeToLive), &mResultTimeToLiveIndicator);
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError, SQL_HANDLE_DBC, mStatements[i]);
- }
-
- // Bind the Priority column
- mResultPriorityIndicator = 0;
- theError = SQLBindCol(mStatements[i], 3, SQL_C_LONG, &mResultPriority, sizeof(mResultZoneId), &mResultPriorityIndicator);
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError, SQL_HANDLE_DBC, mStatements[i]);
- }
-
- // Bind the Type column
- mResultTypeIndicator = 0;
- theError = SQLBindCol(mStatements[i], 4, SQL_C_CHAR, mResultType, sizeof(mResultType), &mResultTypeIndicator);
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError, SQL_HANDLE_DBC, mStatements[i]);
- }
-
- // Bind the ZoneId column
- mResultZoneIdIndicator = 0;
- theError = SQLBindCol(mStatements[i], 5, SQL_C_LONG, &mResultZoneId, sizeof(mResultZoneId), &mResultZoneIdIndicator);
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError, SQL_HANDLE_DBC, mStatements[i]);
- }
-
- // Bind the ChangeDate column
- mResultChangeDateIndicator = 0;
- theError = SQLBindCol(mStatements[i], 6, SQL_C_LONG, &mResultChangeDate, sizeof(mResultChangeDate), &mResultChangeDateIndicator);
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError, SQL_HANDLE_DBC, mStatements[i]);
- }
-
- // Bind the Name column
- mResultNameIndicator = 0;
- theError = SQLBindCol(mStatements[i], 7, SQL_C_CHAR, mResultName, sizeof(mResultName), &mResultNameIndicator);
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError, SQL_HANDLE_DBC, mStatements[i]);
- }
-
- mStatementStates[i] = false;
- }
-
- //
- // Construct the SOA Query
- //
-
- // Prepare the SOA Query
- theError = SQLAllocHandle(SQL_HANDLE_STMT, mConnection, &mSoaStatement);
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError, SQL_HANDLE_DBC, mConnection);
- }
-
- theError = SQLPrepare(mSoaStatement, (SQLCHAR*) kSoaQuery, SQL_NTS);
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError, SQL_HANDLE_STMT, mSoaStatement);
- }
-
- // Bind the Name parameter
- theError = SQLBindParameter(mSoaStatement, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 256, 0, mSoaParamName, 256, NULL);
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError, SQL_HANDLE_STMT, mSoaStatement);
- }
-
- // Bind the ZoneId column
- mSoaResultZoneIdIndicator = 0;
- theError = SQLBindCol(mSoaStatement, 1, SQL_C_LONG, &mSoaResultZoneId, sizeof(mSoaResultZoneId), &mSoaResultZoneIdIndicator);
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError, SQL_HANDLE_STMT, mSoaStatement);
- }
-
- // Bind the Hostmaster column
- mSoaResultHostmasterIndicator = 0;
- theError = SQLBindCol(mSoaStatement, 2, SQL_C_CHAR, mSoaResultHostmaster, 256, &mSoaResultHostmasterIndicator);
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError, SQL_HANDLE_STMT, mSoaStatement);
- }
-
- // Bind the Serial column
- mSoaResultSerialIndicator = 0;
- theError = SQLBindCol(mSoaStatement, 3, SQL_C_LONG, &mSoaResultSerial, sizeof(mSoaResultSerial), &mSoaResultSerialIndicator);
- if (theError != SQL_SUCCESS) {
- throw DB2Exception(theError, SQL_HANDLE_STMT, mSoaStatement);
- }
- }
-
- catch (DB2Exception& theException)
- {
- //
- // Print out diagnostics
- //
-
- int theNativeError;
- string theSqlState, theSqlMessage;
-
- while (theException.GetNextSqlError(theNativeError, theSqlState, theSqlMessage) == true) {
- L << Logger::Warning << kBackendName << " Statement initialization failed with error " << theNativeError << endl;
- L << Logger::Warning << kBackendName << " SQL State : " << theSqlState << endl;
- L << Logger::Warning << kBackendName << " SQL Msg : " << theSqlMessage << endl;
- }
-
- this->Cleanup();
- throw PDNSException("DB2Backend Failed to Start");
- }
-
- L << Logger::Warning << kBackendName << " Connection succeeded" << endl;
-}
-
-void DB2Backend::Cleanup()
-{
- for (int i = 0; i < kNumQueries; i++) {
- if (mStatements[i] != SQL_NULL_HANDLE) {
- (void) SQLFreeHandle(SQL_HANDLE_STMT, mStatements[i]);
- }
- }
-
- if (mConnection != SQL_NULL_HANDLE) {
- (void) SQLFreeHandle(SQL_HANDLE_DBC, mConnection);
- }
-
- if (mEnvironment != SQL_NULL_HANDLE) {
- (void) SQLFreeHandle(SQL_HANDLE_ENV, mEnvironment);
- }
-}
-
-DB2Backend::~DB2Backend()
-{
- this->Cleanup();
-}
-
-void DB2Backend::lookup(const QType &qtype, const string &qname, DNSPacket *pkt_p, int zoneId )
-{
- SQLRETURN theError;
-
- //
- // Choose the right query. All this logic and the query types could be
- // moved to the API. Saves duplicate code in backends.
- //
-
- int theQueryType = -1;
-
- if (qname[0] == '%') {
- if (qtype.getCode() == 255) {
- theQueryType = kForwardWildcardAnyQuery;
- } else {
- theQueryType = kForwardWildcardQuery;
- }
- } else {
- if (qtype.getCode() == 255) {
- theQueryType = kForwardAnyQuery;
- } else {
- if (zoneId != -1) {
- theQueryType = kForwardByZoneQuery;
- } else {
- theQueryType = kForwardQuery;
- }
- }
- }
-
- //
- // Fill in the correct query parameters
- //
-
- //cerr << ">>>>>>>> Query = " << kQueries[theQueryType] << endl;
-
- switch (theQueryType)
- {
- case kForwardQuery:
- case kForwardWildcardQuery:
- strncpy(mParamName, qname.c_str(), sizeof(mParamName));
- strncpy(mParamType, qtype.getName().c_str(), sizeof(mParamType));
- //cerr << ">>>>>>>> Name = " << mParamName << " Type = " << mParamType << endl;
- break;
-
- case kForwardByZoneQuery:
- strncpy(mParamName, qname.c_str(), sizeof(mParamName));
- strncpy(mParamType, qtype.getName().c_str(), sizeof(mParamType));
- mParamZoneId = zoneId;
- //cerr << ">>>>>>>> Name = " << mParamName << " Type = " << mParamType << " ZoneId = " << mParamZoneId << endl;
- break;
-
- case kForwardAnyQuery:
- case kForwardWildcardAnyQuery:
- strncpy(mParamName, qname.c_str(), sizeof(mParamName));
- //cerr << ">>>>>>>> Name = " << mParamName << endl;
- break;
- }
-
- //
- // Execute the query
- //
-
- try
- {
- //
- // Close the cursor if it is in use
- //
-
- if (mStatementStates[theQueryType] == true) {
- theError = SQLCloseCursor(mStatements[theQueryType]);
- if (theError != SQL_SUCCESS && theError != SQL_SUCCESS_WITH_INFO) {
- throw DB2Exception(theError, SQL_HANDLE_STMT, mStatements[theQueryType]);
- }
- }
-
- //
- // Execute the query
- //
-
- mResultContent[0] = mResultType[0] = mResultName[0] = 0x00;
- mResultTimeToLive = mResultPriority = mResultZoneId = mResultChangeDate = 0;
-
- theError = SQLExecute(mStatements[theQueryType]);
- if (theError != SQL_SUCCESS && theError != SQL_SUCCESS_WITH_INFO && theError != SQL_NO_DATA_FOUND) {
- throw DB2Exception(theError, SQL_HANDLE_STMT, mStatements[theQueryType]);
- }
-
- mCurrentStatement = mStatements[theQueryType];
- mStatementStates[theQueryType] = true;
- }
-
- catch (DB2Exception& theException)
- {
- //
- // Print out diagnostics
- //
-
- int theNativeError;
- string theSqlState, theSqlMessage;
-
- while (theException.GetNextSqlError(theNativeError, theSqlState, theSqlMessage) == true) {
- L << Logger::Warning << kBackendName << " SQLExecute() failed with error " << theNativeError << endl;
- L << Logger::Warning << kBackendName << " SQL State : " << theSqlState << endl;
- L << Logger::Warning << kBackendName << " SQL Msg : " << theSqlMessage << endl;
- }
-
- //
- // Rethrow for the nameserver
- //
-
- throw PDNSException("Execute failed");
- }
-}
-
-bool DB2Backend::list(int inZoneId)
-{
- SQLRETURN theError;
- bool theResult = false;
-
- try
- {
- //
- // Close the cursor
- //
-
- if (mStatementStates[kListQuery] == true) {
- theError = SQLCloseCursor(mStatements[kListQuery]);
- if (theError != SQL_SUCCESS && theError != SQL_SUCCESS_WITH_INFO) {
- throw DB2Exception(theError, SQL_HANDLE_STMT, mCurrentStatement);
- }
- }
-
- //
- // Execute the query
- //
-
- mParamZoneId = inZoneId;
-
- theError = SQLExecute(mStatements[kListQuery]);
- if (theError != SQL_SUCCESS && theError != SQL_SUCCESS_WITH_INFO && theError != SQL_NO_DATA_FOUND) {
- throw DB2Exception(theError, SQL_HANDLE_STMT, mStatements[kListQuery]);
- }
-
- mCurrentStatement = mStatements[kListQuery];
- mStatementStates[kListQuery] = true;
-
- if (theResult != SQL_NO_DATA_FOUND) {
- theResult = true;
- }
- }
-
- catch (DB2Exception& theException)
- {
- throw PDNSException("List failed");
- }
-
- return theResult;
-}
-
-bool DB2Backend::get(DNSResourceRecord& outRecord)
-{
- bool theResult = false;
-
- try
- {
- //
- // Fetch a record
- //
-
- SQLRETURN theError = SQLFetch(mCurrentStatement);
- if (theError != SQL_SUCCESS && theError != SQL_SUCCESS_WITH_INFO && theError != SQL_NO_DATA_FOUND) {
- throw DB2Exception(theError, SQL_HANDLE_STMT, mCurrentStatement);
- }
-
- //
- // If we have data then return it
- //
-
- //cerr << ">>>>>>>> Get theError = " << theError << endl;
-
- if (theError != SQL_NO_DATA_FOUND)
- {
- //cerr << ">>>>>>>> Name = " << mResultName << endl;
- //cerr << ">>>>>>>> Content = " << mResultContent << endl;
- //cerr << ">>>>>>>> Type = " << mResultType << endl;
-
- outRecord.content = mResultContent;
- outRecord.ttl = mResultTimeToLive;
- outRecord.priority = mResultPriority;
- outRecord.qtype = mResultType;
- outRecord.domain_id = mResultZoneId;
- outRecord.last_modified = mResultChangeDate;
- outRecord.qname = mResultName;
-
- theResult = true;
- }
- }
-
- catch (DB2Exception& theException)
- {
- //
- // Print out diagnostics
- //
-
- int theNativeError;
- string theSqlState, theSqlMessage;
-
- while (theException.GetNextSqlError(theNativeError, theSqlState, theSqlMessage) == true) {
- L << Logger::Warning << kBackendName << " SQLFetch() failed with error " << theNativeError << endl;
- L << Logger::Warning << kBackendName << " SQL State : " << theSqlState << endl;
- L << Logger::Warning << kBackendName << " SQL Msg : " << theSqlMessage << endl;
- }
-
- //
- // Rethrow for the nameserver
- //
-
- throw PDNSException("Fetch failed");
- }
-
- return theResult;
-}
-
-bool DB2Backend::getSOA(const string& inZoneName, SOAData& outSoaData)
-{
- bool theResult = false;
-
- try
- {
- //
- // Execute the query
- //
-
- strncpy(mSoaParamName, inZoneName.c_str(), sizeof(mSoaParamName));
-
- SQLRETURN theError = SQLExecute(mSoaStatement);
- if (theError != SQL_SUCCESS && theError != SQL_SUCCESS_WITH_INFO && theError != SQL_NO_DATA_FOUND) {
- throw DB2Exception(theError, SQL_HANDLE_STMT, mSoaStatement);
- }
-
- if (theError != SQL_NO_DATA_FOUND)
- {
- mSoaResultZoneId = mSoaResultSerial = 0;
- mSoaResultHostmaster[0] = mSoaResultNameserver[0] = 0x00;
-
- theError = SQLFetch(mSoaStatement);
- if (theError != SQL_SUCCESS && theError != SQL_SUCCESS_WITH_INFO) {
- throw DB2Exception(theError, SQL_HANDLE_STMT, mSoaStatement);
- }
-
- outSoaData.domain_id = mSoaResultZoneId;
- outSoaData.nameserver = arg()["default-soa-name"];
- outSoaData.hostmaster = mSoaResultHostmaster;
- outSoaData.serial = mSoaResultSerial;
- outSoaData.refresh = 10800;
- outSoaData.retry = 3600;
- outSoaData.expire = 604800;
- outSoaData.default_ttl = 3600;
-
- theResult = true;
- }
-
- //
- // Close the cursor
- //
-
- theError = SQLCloseCursor(mSoaStatement);
- if (theError != SQL_SUCCESS && theError != SQL_SUCCESS_WITH_INFO) {
- throw DB2Exception(theError, SQL_HANDLE_STMT, mSoaStatement);
- }
- }
-
- catch (DB2Exception& theException)
- {
- //
- // Print out diagnostics
- //
-
- int theNativeError;
- string theSqlState, theSqlMessage;
-
- while (theException.GetNextSqlError(theNativeError, theSqlState, theSqlMessage) == true) {
- L << Logger::Warning << kBackendName << " SOA Record Lookup Failed: " << theNativeError << endl;
- L << Logger::Warning << kBackendName << " SQL State : " << theSqlState << endl;
- L << Logger::Warning << kBackendName << " SQL Msg : " << theSqlMessage << endl;
- }
-
- //
- // Rethrow for the nameserver
- //
-
- throw PDNSException("GetSOA failed");
- }
-
- return theResult;
-}
-
-//! For the dynamic loader
-DNSBackend *DB2Backend::maker()
-{
- DNSBackend *theBackend;
-
- try {
- theBackend = new DB2Backend;
- } catch (...) {
- theBackend = NULL;
- }
-
- return theBackend;
-}
-
-class DB2Factory : public BackendFactory
-{
- public:
-
- DB2Factory() : BackendFactory("db2") {}
-
- void declareArguments(const string &suffix="")
- {
- declare(suffix,"server","Server","powerdns");
- declare(suffix,"user","User","powerdns");
- declare(suffix,"password","Password","powerdns");
- }
-
- DNSBackend *make(const string &suffix="")
- {
- return new DB2Backend(suffix);
- }
-};
-
-
-//! Magic class that is activated when the dynamic library is loaded
-class DB2Loader
-{
- public:
-
- Loader()
- {
- BackendMakers().report(new DB2Factory);
- L << Logger::Info << "[db2backend] This is the db2 backend version " VERSION " (" __DATE__ ", " __TIME__ ") reporting" << endl;
- }
-};
-
-static DB2Loader db2loader;