- pdns_recursor has gained an init.d script
- sqlite support from
- bindbackend2 gains supermaster support (Mark Bergsma), untested
-
+ - slave communicator more robust against misconfiguration (empty
+ master field)
+ - postgresql backend gains error checking support
+
changes since 2.9.10:
- pdns_recursor now cleans its cache
- pdns_recursor writes its pid to disk now (FreeBSD port maintainer)
/* Copyright 2001 Netherlabs BV, bert.hubert@netherlabs.nl. See LICENSE
for more information.
- $Id: smysql.cc,v 1.3 2003/09/28 17:37:43 ahu Exp $ */
+ $Id: smysql.cc,v 1.4 2003/10/11 19:57:19 ahu Exp $ */
#include "smysql.hh"
#include <string>
#include <iostream>
return SSqlException(reason+string(": ")+mysql_error(&d_db));
}
+int SMySQL::doCommand(const string &query)
+{
+ return doQuery(query);
+}
+
int SMySQL::doQuery(const string &query)
{
if(d_rres)
/* Copyright 2001 Netherlabs BV, bert.hubert@netherlabs.nl. See LICENSE
for more information.
- $Id: smysql.hh,v 1.3 2002/12/19 16:28:31 ahu Exp $ */
+ $Id: smysql.hh,v 1.4 2003/10/11 19:57:19 ahu Exp $ */
#ifndef SMYSQL_HH
#define SMYSQL_HH
SSqlException sPerrorException(const string &reason);
int doQuery(const string &query, result_t &result);
int doQuery(const string &query);
+ int doCommand(const string &query);
bool getRow(row_t &row);
string escape(const string &str);
void setLog(bool state);
-/* Copyright 200w Netherlabs BV, bert.hubert@netherlabs.nl. See LICENSE
+/* Copyright 2003 Netherlabs BV, bert.hubert@netherlabs.nl. See LICENSE
for more information.
- $Id: spgsql.cc,v 1.2 2002/12/17 10:39:53 ahu Exp $ */
+ $Id: spgsql.cc,v 1.3 2003/10/11 19:57:19 ahu Exp $ */
#include <string>
#include "spgsql.hh"
connectstr+=" password="+password;
d_db=new PgDatabase(connectstr.c_str());
-
+ // L<<Logger::Error<<"Connectstr: "<<connectstr<<endl;
// Check to see that the backend connection was successfully made
if (d_db->ConnectionBad() ) {
- throw sPerrorException("Unable to connect to database");
+ throw sPerrorException("Unable to connect to database, connect string: "+connectstr);
}
}
return SSqlException(reason+string(": ")+d_db->ErrorMessage());
}
+int SPgSQL::doCommand(const string &query)
+{
+ if(s_dolog)
+ L<<Logger::Warning<<"Command: "<<query<<endl;
+
+ if(!d_db->ExecCommandOk(query.c_str())) {
+ throw sPerrorException("PostgreSQL failed to execute command");
+ }
+
+ d_count=0;
+ return 0;
+}
+
+
int SPgSQL::doQuery(const string &query)
{
if(s_dolog)
L<<Logger::Warning<<"Query: "<<query<<endl;
- if(!d_db->Exec(query.c_str())) {
+ if(!d_db->ExecTuplesOk(query.c_str())) { // was Exec, without TuplesOk
throw sPerrorException("PostgreSQL failed to execute command");
}
+
d_count=0;
return 0;
}
bool SPgSQL::getRow(row_t &row)
{
row.clear();
-
+
if(d_count>=d_db->Tuples())
return false;
/* Copyright 2001 Netherlabs BV, bert.hubert@netherlabs.nl. See LICENSE
for more information.
- $Id: spgsql.hh,v 1.3 2003/01/06 16:13:59 ahu Exp $ */
+ $Id: spgsql.hh,v 1.4 2003/10/11 19:57:19 ahu Exp $ */
#ifndef SPGSQL_HH
#define SPGSQL_HH
using namespace std;
SSqlException sPerrorException(const string &reason);
int doQuery(const string &query, result_t &result);
int doQuery(const string &query);
+ int doCommand(const string &query);
bool getRow(row_t &row);
string escape(const string &str);
void setLog(bool state);
//! Destructor.
~SSQLite( void );
- //! Performs a query.
+ //! Performs a query and puts answers in result
int doQuery( const std::string & query, result_t & result );
- //! Performs a query.
+ //! Performs a query, caller can retrieve answers with getRow
int doQuery( const std::string & query );
+
+ //! Performs a command that does not return rows
+ int doCommand( const std::string & query )
+ {
+ return doQuery(query);
+ }
+
//! Returns a row from a result set.
bool getRow( row_t & row );
-static int Toupper(int c)
-{
- return toupper(c);
-}
-
-
LdapBackend::LdapBackend( const string &suffix )
{
- m_msgid = 0;
- m_qname = "";
+ unsigned int i;
setArgPrefix( "ldap" + suffix );
+ string hosts = getArg( "host" );
-
- m_default_ttl = (u_int32_t) strtol( getArg( "default-ttl" ).c_str(), NULL, 10 );
+ m_msgid = 0;
+ m_qname = "";
+ m_default_ttl = arg().asNum( "default-ttl" );
try
{
- L << Logger::Info << backendname << " LDAP Server = " << getArg( "host" ) << ":" << getArg( "port" ) << endl;
- m_pldap = new PowerLDAP( getArg( "host" ), (u_int16_t) atoi( getArg( "port" ).c_str() ) );
+ for( i = 0; i < hosts.length(); i++ )
+ {
+ if( hosts[i] == ',' ) { hosts[i] = ' '; }
+ }
+
+ L << Logger::Info << backendname << " LDAP servers = " << hosts << endl;
+
+ m_pldap = new PowerLDAP( hosts.c_str(), atoi( getArg( "port" ).c_str() ) );
m_pldap->simpleBind( getArg( "binddn" ), getArg( "secret" ) );
}
catch( LDAPException &e )
try
{
- L << Logger::Notice << backendname << " AXFR request for " << target << endl;
-
// search for DN of SOA record which is SOA for target zone
filter = "(&(associatedDomain=" + target + ")(SOARecord=*))";
return false;
}
- if( m_result.empty() || m_result.find( "dn" ) == m_result.end() || m_result["dn"].empty() )
+ if( m_result.empty() || !m_result.count( "dn" ) || m_result["dn"].empty() )
{
L << Logger::Error << backendname << " No SOA record for " << target << endl;
return false;
// list all records one level below but not entries containing SOA records (these are seperate zones)
+ DLOG( L << Logger::Debug << backendname << " List = target: " << target << ", basedn: = " << dn << endl );
+
m_qname = "";
m_adomain = m_adomains.end(); // skip loops in get() first time
filter = "(&(associatedDomain=*" + target + ")(!(SOARecord=*)))";
m_msgid = m_pldap->search( dn, LDAP_SCOPE_ONELEVEL, filter, (const char**) attrany );
}
+ catch( LDAPTimeout < )
+ {
+ L << Logger::Error << backendname << " Unable to get zone " + target + " from LDAP directory: " << lt.what() << endl;
+ return false;
+ }
catch( LDAPException &le )
{
L << Logger::Error << backendname << " Unable to get zone " + target + " from LDAP directory: " << le.what() << endl;
- return false;
+ throw( AhuException( "LDAP server unreachable" ) ); // try to reconnect to another server
}
catch( exception &e )
{
{
m_qtype = qtype;
m_qname = qname;
- qesc = m_pldap->escape( qname );
+ qesc = toLower( m_pldap->escape( qname ) );
if( mustDo( "disable-ptrrecord" ) ) // PTRRecords will be derived from ARecords
{
- len = qesc.length();
stringtok( parts, qesc, "." );
+ len = qesc.length();
if( parts.size() == 6 && len > 13 && qesc.substr( len - 13, 13 ) == ".in-addr.arpa" ) // IPv4 reverse lookups
{
}
}
+ DLOG( L << Logger::Debug << backendname << " Search = basedn: " << getArg( "basedn" ) << ", filter: " << filter << ", qtype: " << qtype.getName() << endl );
+
m_adomain = m_adomains.end(); // skip loops in get() first time
- L << Logger::Info << backendname << " Search = basedn: " << getArg( "basedn" ) << ", filter: " << filter << ", qtype: " << qtype.getName() << endl;
m_msgid = m_pldap->search( getArg("basedn"), LDAP_SCOPE_SUBTREE, filter, (const char**) attributes );
}
- catch( LDAPException &le )
+ catch( LDAPTimeout < )
{
- L << Logger::Warning << backendname << " Unable to search LDAP directory: " << le.what() << endl;
+ L << Logger::Error << backendname << " Unable to search LDAP directory: " << lt.what() << endl;
return;
}
+ catch( LDAPException &le )
+ {
+ L << Logger::Error << backendname << " Unable to search LDAP directory: " << le.what() << endl;
+ throw( AhuException( "LDAP server unreachable" ) ); // try to reconnect to another server
+ }
catch( exception &e )
{
L << Logger::Error << backendname << " Caught STL exception: " << e.what() << endl;
{
attrname = m_attribute->first;
qstr = attrname.substr( 0, attrname.length() - 6 ); // extract qtype string from ldap attribute name
- transform( qstr.begin(), qstr.end(), qstr.begin(), &Toupper );
- qt = QType( const_cast<char*>(qstr.c_str()) );
+ qt = QType( const_cast<char*>(toUpper( qstr ).c_str()) );
while( m_value != m_attribute->second.end() )
{
rr.content = content;
m_value++;
- L << Logger::Info << backendname << " Record = qname: " << rr.qname << ", qtype: " << (rr.qtype).getName() << ", priority: " << rr.priority << ", content: " << rr.content << endl;
+ DLOG( L << Logger::Debug << backendname << " Record = qname: " << rr.qname << ", qtype: " << (rr.qtype).getName() << ", priority: " << rr.priority << ", content: " << rr.content << endl );
return true;
}
while( m_pldap->getSearchEntry( m_msgid, m_result, false ) && prepareEntry() );
}
+ catch( LDAPTimeout < )
+ {
+ L << Logger::Error << backendname << " Search failed: " << lt.what() << endl;
+ }
catch( LDAPException &le )
{
- L << Logger::Warning << backendname << " Search failed: " << le.what() << endl;
+ L << Logger::Error << backendname << " Search failed: " << le.what() << endl;
+ throw( AhuException( "LDAP server unreachable" ) ); // try to reconnect to another server
}
catch( exception &e )
{
m_adomains.clear();
m_ttl = m_default_ttl;
- if( m_result.find( "dNSTTL" ) != m_result.end() && !m_result["dNSTTL"].empty() )
+ if( m_result.count( "dNSTTL" ) && !m_result["dNSTTL"].empty() )
{
m_ttl = (u_int32_t) strtol( m_result["dNSTTL"][0].c_str(), NULL, 10 );
m_result.erase( "dNSTTL" );
if( !m_qname.empty() ) // request was a normal lookup()
{
m_adomains.push_back( m_qname );
- if( m_result.find( "associatedDomain" ) != m_result.end() )
+ if( m_result.count( "associatedDomain" ) )
{
m_result["PTRRecord"] = m_result["associatedDomain"];
m_result.erase( "associatedDomain" );
}
else // request was a list() for AXFR
{
- if( m_result.find( "associatedDomain" ) != m_result.end() )
+ if( m_result.count( "associatedDomain" ) )
{
m_adomains = m_result["associatedDomain"];
m_result.erase( "associatedDomain" );
void declareArguments( const string &suffix="" )
{
- declare( suffix, "host", "your ldap server","localhost" );
- declare( suffix, "port", "ldap server port","389" );
+ declare( suffix, "host", "one or more ldap server","localhost:389" );
+ declare( suffix, "port", "ldap server port (depricated, use ldap-host)","389" );
declare( suffix, "basedn", "search root in ldap tree (must be set)","" );
declare( suffix, "binddn", "user dn for non anonymous binds","" );
declare( suffix, "secret", "user password for non anonymous binds", "" );
declare( suffix, "disable-ptrrecord", "disable necessity for seperate PTR records", "no" );
- declare( suffix, "default-ttl", "default ttl if DNSTTL is not set", "86400" );
+ declare( suffix, "default-ttl", "default ttl if DNSTTL is not set (depricated, use default-ttl)", "3600" );
}
Loader()
{
BackendMakers().report( new LdapFactory );
- L << Logger::Notice << backendname << " This is the ldap module version "VERSION" ("__DATE__", "__TIME__") reporting" << endl;
+ L << Logger::Info << backendname << " This is the ldap module version "VERSION" ("__DATE__", "__TIME__") reporting" << endl;
}
};
-// $Id: gsqlbackend.cc,v 1.9 2003/08/22 13:33:31 ahu Exp $
+// $Id: gsqlbackend.cc,v 1.10 2003/10/11 19:57:19 ahu Exp $
#include <string>
#include <map>
#include "pdns/logger.hh"
#include "pdns/arguments.hh"
-
-
#include <sstream>
void GSQLBackend::setNotified(u_int32_t domain_id, u_int32_t serial)
domain_id);
try {
- d_db->doQuery(output);
+ d_db->doCommand(output);
}
catch (SSqlException &e) {
throw AhuException("GSQLBackend unable to refresh domain_id "+itoa(domain_id)+": "+e.txtReason());
format = d_InsertSlaveZoneQuery;
snprintf(output,sizeof(output)-1,format.c_str(),sqlEscape(domain).c_str(),sqlEscape(ip).c_str(),sqlEscape(account).c_str());
try {
- d_db->doQuery(output);
+ d_db->doCommand(output);
}
catch(SSqlException &e) {
throw AhuException("Database error trying to insert new slave '"+domain+"': "+ e.txtReason());
sqlEscape(r.qtype.getName()).c_str(),
r.domain_id, toLower(sqlEscape(r.qname)).c_str());
try {
- d_db->doQuery(output);
+ d_db->doCommand(output);
}
catch (SSqlException &e) {
throw AhuException(e.txtReason());
char output[1024];
snprintf(output,sizeof(output)-1,d_DeleteZoneQuery.c_str(),domain_id);
try {
- d_db->doQuery("begin");
- d_db->doQuery(output);
+ d_db->doCommand("begin");
+ d_db->doCommand(output);
}
catch (SSqlException &e) {
throw AhuException("Database failed to start transaction: "+e.txtReason());
bool GSQLBackend::commitTransaction()
{
try {
- d_db->doQuery("commit");
+ d_db->doCommand("commit");
}
catch (SSqlException &e) {
throw AhuException("Database failed to commit transaction: "+e.txtReason());
bool GSQLBackend::abortTransaction()
{
try {
- d_db->doQuery("rollback");
+ d_db->doCommand("rollback");
}
catch(SSqlException &e) {
throw AhuException("MySQL failed to abort transaction: "+string(e.txtReason()));
/* Copyright 2001 Netherlabs BV, bert.hubert@netherlabs.nl. See LICENSE
for more information.
- $Id: ssql.hh,v 1.1 2002/12/16 20:34:29 ahu Exp $ */
+ $Id: ssql.hh,v 1.2 2003/10/11 19:57:19 ahu Exp $ */
#ifndef SSQL_HH
#define SSQL_HH
virtual SSqlException sPerrorException(const string &reason)=0;
virtual int doQuery(const string &query, result_t &result)=0;
virtual int doQuery(const string &query)=0;
+ virtual int doCommand(const string &query)=0;
virtual bool getRow(row_t &row)=0;
virtual string escape(const string &name)=0;
virtual void setLog(bool state){}
arg().set("negquery-cache-ttl","Seconds to store packets in the PacketCache")="60";
arg().set("query-cache-ttl","Seconds to store packets in the PacketCache")="20";
arg().set("soa-minimum-ttl","Default SOA mininum ttl")="3600";
+ arg().set("default-ttl","Seconds a result is valid if not set otherwise")="3600";
arg().set("max-tcp-connections","Maximum number of TCP connections")="10";
arg().setSwitch( "use-logfile", "Use a log file" )= "no";
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-// $Id: dynlistener.cc,v 1.6 2003/09/16 21:02:35 ahu Exp $
+// $Id: dynlistener.cc,v 1.7 2003/10/11 19:57:19 ahu Exp $
/* (C) Copyright 2002 PowerDNS.COM BV */
#include <cstring>
#include <string>
sendLine("Empty line");
continue;
}
- upperCase(parts[0]);
+ parts[0] = toUpper( parts[0] );
if(!d_funcdb[parts[0]]) {
if(d_restfunc)
sendLine((*d_restfunc)(parts,d_ppid));
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
+#include "ahuexception.hh"
#include <sys/types.h>
#ifndef WIN32
void parseService(const string &descr, ServiceTuple &st)
{
+
vector<string>parts;
stringtok(parts,descr,":");
+ if(parts.empty())
+ throw AhuException("Unable to parse '"+descr+"' as a service");
st.host=parts[0];
if(parts.size()>1)
st.port=atoi(parts[1].c_str());
return d_set.tv_sec;
}
-// Make s uppercase:
-void upperCase(string& s) {
- for(unsigned int i = 0; i < s.length(); i++)
- s[i] = toupper(s[i]);
-}
-
void chomp(string &line, const string &delim)
{
return (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
}
-void upperCase(string& s);
struct ServiceTuple
{
}
+// Make s uppercase:
+inline string toUpper( const string& s )
+{
+ string r(s);
+ for( unsigned int i = 0; i < s.length(); i++ ) {
+ r[i] = toupper( r[i] );
+ }
+ return r;
+}
+
+
#endif
DNSResourceRecord rr;
if (p->qclass == 3 && p->qtype.getName() == "HINFO") {
- rr.content = "PowerDNS $Id: packethandler.cc,v 1.17 2003/09/16 21:02:35 ahu Exp $";
+ rr.content = "PowerDNS $Id: packethandler.cc,v 1.18 2003/10/11 19:57:19 ahu Exp $";
rr.ttl = 5;
rr.qname=target;
rr.qtype=13; // hinfo
{
DNSResourceRecord rr;
if(p->qtype.getCode()==QType::TXT && target=="version.bind") {// TXT
- rr.content="Served by POWERDNS "VERSION" $Id: packethandler.cc,v 1.17 2003/09/16 21:02:35 ahu Exp $";
+ rr.content="Served by POWERDNS "VERSION" $Id: packethandler.cc,v 1.18 2003/10/11 19:57:19 ahu Exp $";
rr.ttl=5;
rr.qname=target;
rr.qtype=QType::TXT; // TXT
{
string subdomain(target);
do {
- cout<<"Trying: '"<<subdomain<<"'"<<endl;
if( B.getSOA( subdomain, *sd ) ) {
sd->qname = subdomain;
*zoneId = sd->domain_id;
void Resolver::sendResolve(const string &ip, const char *domain, int type)
{
-
DNSPacket p;
p.setQuestion(Opcode::Query,domain,type);
struct in_addr inp;
ServiceTuple st;
st.port=53;
- parseService(ip, st);
+ try {
+ parseService(ip, st);
+ }
+ catch(AhuException &ae) {
+ throw ResolverException("Sending a dns question to '"+ip+"': "+ae.reason);
+ }
+
Utility::inet_aton(st.host.c_str(),&inp);
toaddr.sin_addr.s_addr=inp.s_addr;
void throttle(const Thing& t, unsigned int ttl=0, unsigned int tries=0)
{
entry e;
- e.ttd=time(0)+ (ttl ? ttl : d_ttl) ;
+ e.ttd=time(0)+ (ttl ?: d_ttl) ;
e.T=t;
e.count=tries ? tries : d_limit;
d_dq.push_front(e);