- zone parser now allows both $include and $INCLUDE
- wildcard ANY queries work again (colemarcus)
- resolved crashes after failed gmysql/gpgsql connections
+ - major brokenness in slave support in gmysql/gpgsql (mark)
+ - solaris compilation fixes
+ - make IPv6 work again on FreeBSD (Peter van Dijk)
+
Changes since 2.9.2:
- windows compilation patches
Please don't use the 'mysql' backend, it is deprecated. Use the 'gmysql'
one!
+CVS
+---
+
+If you need code from CVS, read HACKING.
+
SOLARIS NOTES
-------------
You need gcc 3.x, preferably 3.2! The 'Sunpro' compiler is currently not
Small things, great for coders new to PowerDNS:
- - add LOC record
+done - add LOC record
- add KEY record
- add SIG record
- - get the xdb backend building again
+done - get the xdb backend building again
- 'make distclean' tries to calculate dependencies in
modules/pgmysqlbackend, which is not needed
+ - remove 'handle' from UeberBackend and BindBackend
+
- investigate if the following is better for the spgsql driver:
int SPgSQL::doQuery(const string &query)
dnl intro
AC_INIT(pdns/receiver.cc)
-AM_INIT_AUTOMAKE(pdns, 2.9.3a)
+AM_INIT_AUTOMAKE(pdns, 2.9.4)
AC_CANONICAL_HOST
AM_CONFIG_HEADER(config.h)
AC_C_BIGENDIAN
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-// $Id: bindbackend.cc,v 1.9 2002/12/20 16:12:06 ahu Exp $
+// $Id: bindbackend.cc,v 1.10 2002/12/30 21:00:56 ahu Exp $
#include <errno.h>
#include <string>
#include <map>
make.qtype=QType::chartocode(qtype.c_str());
if(!make.qtype)
- throw AhuException("Unknown qtype '"+qtype+"'");
+ throw AhuException("Unknown qtype '"+qtype+"'"); // never leaves the BindBackend
set<string>::const_iterator i=s_contents.find(content);
if(i==s_contents.end()) {
-// $Id: gsqlbackend.cc,v 1.2 2002/12/29 19:47:25 ahu Exp $
+// $Id: gsqlbackend.cc,v 1.3 2002/12/30 21:00:56 ahu Exp $
#include <string>
#include <map>
di.last_check=atol(d_result[0][3].c_str());
di.backend=this;
- string type=d_result[0][4];
- if(type=="SLAVE")
+ string type=d_result[0][5];
+ if(type=="SLAVE") {
+ di.serial=0;
+ try {
+ SOAData sd;
+ if(!getSOA(domain,sd))
+ L<<Logger::Error<<"No serial for '"<<domain<<"' found - zone is missing?"<<endl;
+ di.serial=sd.serial;
+ }
+ catch(AhuException &ae){
+ L<<Logger::Error<<"Error retrieving serial for '"<<domain<<"': "<<ae.reason<<endl;
+ }
+
di.kind=DomainInfo::Slave;
+ }
else if(type=="MASTER")
di.kind=DomainInfo::Slave;
else
/** the Distributor template class enables you to multithread slow question/answer
processes.
- Generally, you will run 2 threads. One that inserts questions and one that handles
- the answers.
-*/
+ Questions are posed to the Distributor, which can either hand back the answer,
+ or give it directly to a callback. Only the latter mode of operation is used in
+ PowerDNS.
+
+ The Distributor takes care that there are enough Backends alive at any one
+ time and will try to spawn additional ones should they die.
+ The Backend needs to count the number of living instances and supply this number to
+ the Distributor using its numBackends() method. This is silly.
+ If an exception escapes a Backend, the distributor retires it.
+*/
template<class Answer, class Question, class Backend> class Distributor
{
public:
sleep(1);
int qcount, acount;
- us->numquestions.getvalue( &qcount );
- us->numanswers.getvalue( &acount );
+ us->numquestions.getvalue( &qcount );
+ us->numanswers.getvalue( &acount );
L <<"queued questions: "<<qcount<<", pending answers: "<<acount<<endl;
}
}
catch(...) {
// and cleanup
- L<<Logger::Error<<"Caught an exception instantiating a backend, details should follow"<<endl;
+ L<<Logger::Error<<"Caught an exception instantiating a backend, cleaning up"<<endl;
for(vector<DNSBackend *>::const_iterator i=ret.begin();i!=ret.end();++i)
delete *i;
throw;
return ret;
}
+/** getSOA() is a function that is called to get the SOA of a domain. Callers should ONLY
+ use getSOA() and no perform a lookup() themselves as backends may decide to special case
+ the SOA record.
+
+ Returns false if there is definitely no SOA for the domain. May throw a DBException
+ to indicate that the backend is currently unable to supply an answer.
+
+ \param domain Domain we want to get the SOA details of
+ \param sd SOAData which is filled with the SOA details
+*/
bool DNSBackend::getSOA(const string &domain, SOAData &sd)
{
this->lookup(QType(QType::SOA),domain,0);
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-// $Id: dnsbackend.hh,v 1.4 2002/12/20 14:25:29 ahu Exp $
+// $Id: dnsbackend.hh,v 1.5 2002/12/30 21:00:56 ahu Exp $
/* (C) 2002 POWERDNS.COM BV */
#ifndef DNSBACKEND_HH
#include "dns.hh"
using namespace std;
-/** This virtual base class defines the interface for backends for the ahudns. To create a backend,
- inherit from this class and implement functions for all virtual methods.
-*/
class DNSBackend;
struct DomainInfo
};
class DNSPacket;
+
+
+//! This virtual base class defines the interface for backends for the ahudns.
+/** To create a backend, inherit from this class and implement functions for all virtual methods.
+ Methods should not throw an exception if they are sure they did not find the requested data. However,
+ if an error occurred which prevented them temporarily from performing a lockup, they should throw a DBException,
+ which will cause the nameserver to send out a ServFail or take other evasive action. Probably only locking
+ issues should lead to DBExceptions.
+
+ More serious errors, which may indicate that the database connection is hosed, or a configuration error occurred, should
+ lead to the throwing of an AhuException. This exception will fall straight through the UeberBackend and the PacketHandler
+ and be caught by the Distributor, which will delete your DNSBackend instance and spawn a new one.
+*/
class DNSBackend
{
public:
+ //! lookup() initiates a lookup. A lookup without results should not throw!
virtual void lookup(const QType &qtype, const string &qdomain, DNSPacket *pkt_p=0, int zoneId=-1)=0;
- virtual bool get(DNSResourceRecord &)=0;
- virtual bool list(int domain_id)=0;
+ virtual bool get(DNSResourceRecord &)=0; //!< retrieves one DNSResource record, returns false if no more were available
+ //! Initiates a list of the specified domain
+ /** Once initiated, DNSResourceRecord objects can be retrieved using get(). Should return false
+ if the backend does not consider itself responsible for the id passed.
+ \param domain_id ID of which a list is requested
+ */
+ virtual bool list(int domain_id)=0;
virtual ~DNSBackend(){};
- static void reconfigure(const string &);
-
+ //! fills the soadata struct with the SOA details. Returns false if there is no SOA.
virtual bool getSOA(const string &name, SOAData &soadata);
+ //! returns true if master ip is master for domain name.
virtual bool isMaster(const string &name, const string &ip)
{
return false;
}
+ //! starts the transaction for updating domain qname (FIXME: what is id?)
virtual bool startTransaction(const string &qname, int id=-1)
{
return false;
}
+ //! commits the transaction started by startTransaction
virtual bool commitTransaction()
{
return false;
}
+ //! aborts the transaction started by strartTransaction, should leave state unaltered
virtual bool abortTransaction()
{
return false;
{
}
+ //! feeds a record to a zone, needs a call to startTransaction first
virtual bool feedRecord(const DNSResourceRecord &rr)
{
return false; // no problem!
}
+ //! if this returns true, DomainInfo di contains information about the domain
virtual bool getDomainInfo(const string &domain, DomainInfo &di)
{
return false;
}
+ //! slave capable backends should return a list of slaves that should be rechecked for staleness
virtual void getUnfreshSlaveInfos(vector<DomainInfo>* domains)
{
}
+ //! get a list of IP addresses that should also be notified for a domain
virtual void alsoNotifies(const string &domain, set<string> *ips)
{
}
+
+ //! get list of domains that have been changed since their last notification to slaves
virtual void getUpdatedMasters(vector<DomainInfo>* domains)
{
}
- virtual DNSBackend *getBackendAndID(const string &qdomain, u_int32_t *id)
- {
- return 0;
- }
+
+ //! Called by PowerDNS to inform a backend that a domain has been checked for freshness
virtual void setFresh(u_int32_t domain_id)
{
}
+ //! Called by PowerDNS to inform a backend that the changes in the domain have been reported to slaves
virtual void setNotified(u_int32_t id, u_int32_t serial)
{
}
+ //! Can be called to seed the getArg() function with a prefix
void setArgPrefix(const string &prefix);
+
+ //! determine if ip is a supermaster or a domain
virtual bool superMasterBackend(const string &ip, const string &domain, const vector<DNSResourceRecord>&nsset, string *account, DNSBackend **db)
{
return false;
}
+
+ //! called by PowerDNS to create a slave record for a superMaster
virtual bool createSlaveDomain(const string &ip, const string &domain, const string &account)
{
return false;
extern BackendMakerClass &BackendMakers();
+//! Exception that can be thrown by a DNSBackend to indicate a failure
class DBException : public AhuException
{
public:
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-// $Id: dnspacket.hh,v 1.7 2002/12/18 09:30:13 ahu Exp $
+// $Id: dnspacket.hh,v 1.8 2002/12/30 21:00:56 ahu Exp $
#ifndef DNSPACKET_HH
#define DNSPACKET_HH
number of seconds since 1 jan 1970 (unix timestamp). The other values are substituted as indicated
*/
-
-
void addSOARecord(const string &domain, const string &content, u_int32_t ttl, DNSResourceRecord::Place place);
void addSOARecord(const DNSResourceRecord &); //!< add a SOA record to the packet
-
void addTXTRecord(string domain, string, u_int32_t ttl); //!< add a TXT record to the packet
void addTXTRecord(const DNSResourceRecord &); //!< add a TXT record to the packet
#include <stdio.h>
#include <iostream>
-/** \mainpage
+/** \page MTasker
Simple system for implementing cooperative multitasking of functions, with
support for waiting on events which can return values.
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-// $Id: nameserver.cc,v 1.3 2002/12/10 13:36:26 ahu Exp $
+// $Id: nameserver.cc,v 1.4 2002/12/30 21:00:56 ahu Exp $
#include "utility.hh"
#include <cstdio>
#include <cstring>
own backend, see the documentation for the DNSBackend class.
\section copyright Copyright and License
- AhuDNS is (C) 2002 PowerDNS BV.
-
- AhuDNS is NOT open source (yet), so treat this code as a trade secret. If it has been supplied to you for evaluation,
- this does not mean that you can deploy the code!
+ AhuDNS is (C) 2002 PowerDNS BV. It is distributed according to the terms of the General Public License version 2.
\section overview High level overview
- AhuDNS is highly threaded, which means that several tasks each have their own process thread. Two of the pivotal
- threads are the qthread() and the athread().
-
- - The qthread() receives questions over the network (via the Nameserver class, which returns DNSPacket objects), and gives them to the Distributor.
- - The athread() waits on the Distributor to return answers, ready to send back over the network, again via UDPNameserver.
-
- The Distributor contains a configurable number of PacketHandler instances, each in its own thread, for connection pooling
+ The Distributor contains a configurable number of PacketHandler instances, each in its own thread, for connection pooling.
+ PacketHandler instances are recycled of they let escape an AhuException.
The PacketHandler implements the RFC1034 algorithm and converts question packets into DNSBackend queries.
A DNSBackend is an entity that returns DNSResourceRecord objects in return to explicit questions for domains with a specified QType
- AhuDNS uses the UeberBackend as its DNSBackend. The UeberBackend by default has no DNSBackends within itself, those are loaded
- using the dynloader tool. This way DNSBackend implementations can be kept completely separate.
+ PowerDNS uses the UeberBackend as its DNSBackend. The UeberBackend by default has no DNSBackends within itself, those are loaded
+ using the pdns_control tool. This way DNSBackend implementations can be kept completely separate (but they often aren't).s
If one or more DNSBackends are loaded, the UeberBackend fields the queries to all of them until one answers.
These statistics are made available via the UeberBackend on the same socket that is used for dynamic module commands.
\section Main Main
- The main() of AhuDNS can be found in receiver.cc - start reading there for further insights into the operation of the nameserver
+ The main() of PowerDNS can be found in receiver.cc - start reading there for further insights into the operation of the nameserver
*/
sockaddr_in6 locala;
locala.sin6_port=ntohs(arg().asNum("local-port"));
+ locala.sin6_family=AF_INET6;
+ locala.sin6_flowinfo=0;
+
if(!inet_pton(AF_INET6, localname.c_str(), (void *)&locala.sin6_addr)) {
addrinfo *addrinfos;
addrinfo hints;
memcpy(&locala,addrinfos->ai_addr,addrinfos->ai_addrlen);
}
+
if(bind(s, (sockaddr*)&locala, sizeof(locala))<0) {
L<<Logger::Error<<"binding to UDP ipv6 socket: "<<strerror(errno)<<endl;
throw AhuException("Unable to bind to UDP ipv6 socket");
{
--s_count;
DLOG(L<<Logger::Error<<"PacketHandler destructor called - "<<s_count<<" left"<<endl);
-
}
DNSResourceRecord rr;
if (p->qclass == 3 && p->qtype.getName() == "HINFO") {
- rr.content = "PowerDNS $Id: packethandler.cc,v 1.3 2002/12/29 19:47:25 ahu Exp $";
+ rr.content = "PowerDNS $Id: packethandler.cc,v 1.4 2002/12/30 21:00:56 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.3 2002/12/29 19:47:25 ahu Exp $";
+ rr.content="Served by POWERDNS "VERSION" $Id: packethandler.cc,v 1.4 2002/12/30 21:00:56 ahu Exp $";
rr.ttl=5;
rr.qname=target;
rr.qtype=QType::TXT; // TXT
L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but slave support is disabled in the configuration"<<endl;
return RCode::NotImp;
}
- SOAData sd;
- sd.serial=0;
DNSBackend *db=0;
DomainInfo di;
if(!B.getDomainInfo(p->qdomain,di) || !(db=di.backend)) {
return RCode::ServFail;
}
- if(theirserial<=sd.serial) {
+
+ if(theirserial<=di.serial) {
L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from master "<<p->getRemote()<<", we are up to date: "<<
- theirserial<<"<="<<sd.serial<<endl;
+ theirserial<<"<="<<di.serial<<endl;
return RCode::NoError;
}
else {
- L<<Logger::Error<<"Received valid NOTIFY for "<<p->qdomain<<" (id="<<sd.domain_id<<") from master "<<p->getRemote()<<": "<<
- theirserial<<" > "<<sd.serial<<endl;
+ L<<Logger::Error<<"Received valid NOTIFY for "<<p->qdomain<<" (id="<<di.id<<") from master "<<p->getRemote()<<": "<<
+ theirserial<<" > "<<di.serial<<endl;
Communicator.addSuckRequest(p->qdomain, p->getRemote());
}
DNSPacket *question(DNSPacket *); //!< hand us a DNS packet with a question, we give you an answer
PacketHandler();
~PacketHandler(); // defined in packethandler.cc, and does --count
- static int numRunning(){return s_count;}; //!< Returns the number of running PacketHandlers
+ static int numRunning(){return s_count;}; //!< Returns the number of running PacketHandlers. Called by Distributor
void soaMagic(DNSResourceRecord *rr);
DNSBackend *getBackend();
sockaddr_in6 locala;
locala.sin6_port=ntohs(arg().asNum("local-port"));
+ locala.sin6_family=AF_INET6;
+ locala.sin6_flowinfo=0;
+
if(!inet_pton(AF_INET6, laddr->c_str(), (void *)&locala.sin6_addr)) {
addrinfo *addrinfos;
exit(1);
}
+
if(bind(s, (const sockaddr*)&locala, sizeof(locala))<0) {
L<<Logger::Error<<"binding to TCP socket: "<<strerror(errno)<<endl;
throw AhuException("Unable to bind to TCPv6 socket");
/** This is a very magic backend that allows us to load modules dynamically,
and query them in order. This is persistent over all UeberBackend instantiations
- across multiple threads. Very magic */
+ across multiple threads.
+
+ The UeberBackend is transparent for exceptions, which should fall straight through.
+*/
class UeberBackend : public DNSBackend
{
#endif // WIN32
#ifdef NEED_POSIX_TYPEDEF
+typedef unsigned char u_int8_t;
typedef unsigned short int u_int16_t;
typedef unsigned int u_int32_t;
#endif