- zone2sql no longer silently tries to read directories
- improved error reporting if unable to figure out IP addresses for
slaves
+ - removed vestigal receiver-threads setting
+ - ldapbackend needs to include utility.hh (Remco Post)
+ - pdns_control could sometimes leave files behind in /tmp (dG)
+ - ldapbackend updates
Changes since 2.9.5:
- implemented isMaster in bindbackend (we now react to notifies)
#include "ldapbackend.hh"
+
#include <algorithm>
#include <utility>
#include <ctype.h>
+static int Toupper(int c)
+{
+ return toupper(c);
+}
+
+
LdapBackend::LdapBackend( const string &suffix )
{
m_msgid = 0;
m_qname = "";
+ m_revlookup = 0;
setArgPrefix( "ldap" + suffix );
L << Logger::Notice << backendname << " Server = " << getArg( "host" ) << ":" << getArg( "port" ) << endl;
void LdapBackend::lookup( const QType &qtype, const string &qname, DNSPacket *dnspkt, int zoneid )
{
- string filter, attr;
+ int len = 0;
+ vector<string> parts;
+ string filter, attr, ipaddr;
char** attributes = attrany;
- char* attronly[] = { NULL, NULL };
+ char* attronly[] = { "associatedDomain", NULL, NULL };
m_qtype = qtype;
- m_qname = m_pldap->escape( qname );
- filter = "(associatedDomain=" + m_qname + ")";
+ m_qname = qname;
+ len = qname.length();
- if( qtype.getCode() != 255 ) // qtype != ANY
+ if( len > 20 && qname.substr( len - 13, 13 ) == ".in-addr.arpa" )
+ {
+ m_revlookup = 1;
+ stringtok( parts, qname.substr( 0, len - 13 ), "." );
+ filter = "(aRecord=" + parts[3] + "." + parts[2] + "." + parts[1] + "." + parts[0] + ")";
+ attributes = attronly;
+ }
+ else
+ {
+ m_revlookup = 0;
+ filter = "(associatedDomain=" + m_pldap->escape( m_qname ) + ")";
+ }
+
+ if( qtype.getCode() != QType::ANY )
{
attr = qtype.getName() + "Record";
filter = "(&" + filter + "(" + attr + "=*))";
- attronly[0] = (char*) attr.c_str();
+ attronly[1] = (char*) attr.c_str();
attributes = attronly;
}
L << Logger::Info << backendname << " Search = basedn: " << getArg( "basedn" ) << ", filter: " << filter << ", qtype: " << qtype.getName() << endl;
}
-static int Toupper(int c)
-{
- return toupper(c);
-}
bool LdapBackend::get( DNSResourceRecord &rr )
{
{
while( !m_result.empty() )
{
+ if( m_revlookup == 1 && m_result.find( "associatedDomain" ) != m_result.end() )
+ {
+ m_result["PTRRecord"] = m_result["associatedDomain"];
+ }
+ m_result.erase( "associatedDomain" );
+
attribute = m_result.begin();
attrname = 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()) );
- while( !attribute->second.empty() && ( m_qtype == "ANY" || qt.getCode() == m_qtype.getCode() ) )
+ while( !attribute->second.empty() && ( m_qtype.getCode() == QType::ANY || m_qtype.getCode() == qt.getCode() ) )
{
content = attribute->second.back();
attribute->second.pop_back();
rr.qname = m_qname;
rr.priority = 0;
- if( qt.getCode() == 15 ) // MX Record, e.g. 10 smtp.example.com
+ if( qt.getCode() == QType::MX ) // MX Record, e.g. 10 smtp.example.com
{
- stringtok( parts, content );
+ stringtok( parts, content, " " );
rr.priority = (u_int16_t) strtol( parts[0].c_str(), NULL, 10 );
content = parts[1];
}
#include <stdlib.h>
#include <unistd.h>
#include <pdns/dns.hh>
+#include <pdns/utility.hh>
#include <pdns/dnspacket.hh>
#include <pdns/dnsbackend.hh>
#include <pdns/ueberbackend.hh>
static string backendname="[LdapBackend]";
static char* attrany[] = {
+ "associatedDomain",
"ARecord",
"NSRecord",
"CNAMERecord",
private:
int m_msgid;
+ int m_revlookup;
+
QType m_qtype;
string m_qname;
PowerLDAP* m_pldap;
resolver.hh resolver.cc communicator.cc communicator.hh dnsproxy.cc \
dnsproxy.hh randombackend.cc unix_utility.cc common_startup.cc \
utility.hh iputils.hh common_startup.hh \
-backends/bind/bindbackend.cc backends/bind/zoneparser2.cc \
+backends/bind/bindbackend2.cc backends/bind/zoneparser2.cc \
backends/bind/bindparser.cc backends/bind/bindlexer.c \
backends/bind/huffman.cc backends/gsql/gsqlbackend.cc \
backends/gsql/gsqlbackend.hh backends/gsql/ssql.hh \
INCLUDES=-I../..
noinst_LTLIBRARIES = libbindbackend.la
-libbindbackend_la_SOURCES=bindbackend.cc bindbackend.hh bindparser.yy \
+libbindbackend_la_SOURCES=bindbackend2.cc bindbackend2.hh bindparser.yy \
bindlexer.l zoneparser2.cc ../../misc.cc huffman.cc huffman.hh zoneparser.hh \
bindparser.hh ../../unix_utility.cc
void setCallback(callback_t *callback);
callback_t *d_callback;
bool parseLine(const vector<string>&words, vector<Record> &);
- bool eatLine(string line, vector<Record>&);
+ bool eatLine(const string& line, vector<Record>&);
void setDirectory(const string &dir);
static string canonic(const string& dom);
stack<FILE *>fds;
fds.push(zonein);
+
while(!fds.empty()) {
- while(fgets(cline,sizeof(cline)-1,fds.top())) {
+ while(fgets_unlocked(cline,sizeof(cline)-1,fds.top())) {
line=cline;
chomp(line," \x1a\r\n");
cutOff(line,";");
d_lineno++;
- if(!line.find("$INCLUDE ") || !line.find("$include ")) {
+ if(line.empty())
+ continue;
+
+ if(line[0]=='$' && (!line.find("$INCLUDE ") || !line.find("$include "))) {
vector<string> parts;
stringtok(parts,line," \t\n");
if(parts.size()!=2)
vector<Record> rec;
stack<FILE *>fds;
fds.push(zonein);
+
while(!fds.empty()) {
- while(fgets(cline,sizeof(cline)-1,fds.top())) {
+ while(fgets_unlocked(cline,sizeof(cline)-1,fds.top())) {
line=cline;
chomp(line," \x1a\r\n");
cutOff(line,";");
d_lineno++;
- if(!line.find("$INCLUDE ") || !line.find("$include ")) {
+ if(line.empty())
+ continue;
+
+ if(line[0]=='$' && (!line.find("$INCLUDE ") || !line.find("$include "))) {
vector<string> parts;
stringtok(parts,line," \t\r\n");
if(parts.size()!=2)
fclose(fds.top());
fds.pop();
}
-
-
}
rec.ttl=ttl;
rec.prio=prio;
recs.push_back(rec);
-
}
unsigned int pos=line.find_first_of(delim);
if(pos==string::npos)
return;
- line=line.substr(0,pos);
+ line.resize(pos);
}
-bool ZoneParser::eatLine(string line, vector<Record> &rec)
+bool ZoneParser::eatLine(const string& line, vector<Record> &rec)
{
-
rec.clear();
static string tline;
static string lastfirstword;
unsigned int pos=string::npos;
if(tline.empty()) {
- pos=line.find("(");
+ pos=line.find_first_of("(");
if(pos!=string::npos) { // this is a line that continues
tline=line.substr(0,pos);
return false;
void ZoneParser::setCallback(callback_t *callback)
{
- d_callback=callback;
+ d_callback=callback;
}
bool ZoneParser::isNumber(const string &s)
bool ZoneParser::isClass(const string &s)
{
- return (s=="IN" || s=="CH" || s=="HS" || s=="in" || s=="ch" || s=="hs");
+ return (s.size()==2 && (s=="IN" || s=="CH" || s=="HS" || s=="in" || s=="ch" || s=="hs"));
}
unsigned int ZoneParser::zoneNumber(const string &str)
arg().set("webserver-port","Port of webserver to listen on")="8081";
arg().set("webserver-password","Password required for accessing the webserver")="";
- arg().set("receiver-threads","Number of receiver threads to launch")="1";
-
arg().setSwitch("out-of-zone-additional-processing","Do out of zone additional processing")="no";
arg().setSwitch("query-logging","Hint backends that queries should be logged")="no";
TN->go(); // tcp nameserver launch
// fork(); (this worked :-))
- for(int n=0;n<arg().asNum("receiver-threads");++n) {
- DNSDistributor *D= new DNSDistributor(arg().asNum("distributor-threads")); // the big dispatcher!
- pthread_create(&qtid,0,qthread,static_cast<void *>(D)); // receives packets
- }
+ DNSDistributor *D= new DNSDistributor(arg().asNum("distributor-threads")); // the big dispatcher!
+ pthread_create(&qtid,0,qthread,static_cast<void *>(D)); // receives packets
void *p;
pthread_join(qtid, &p);
</affiliation>
</author>
- <PubDate>v2.1 $Date: 2003/02/15 11:30:17 $</PubDate>
+ <PubDate>v2.1 $Date: 2003/03/04 18:33:39 $</PubDate>
<Abstract>
<para>
<Chapter id="configuring-db-connection">
<title>Configure database connectivity</title>
<para>
- The default PDNS distribution comes with a simple MySQL backend built in, which we will now use for
- demonstrating database connectivity. This backend is called 'mysql', and needs to be configured
+ This chapter shows you how to configure the Generic MySQL backend, which we like a lot. But feel free to use any of the myriad
+ other backends.
+ This backend is called 'gmysql', and needs to be configured
in <filename>pdns.conf</filename>. Add the following lines, adjusted for your local setup:
<screen>
- launch=mysql
- mysql-host=127.0.0.1
- mysql-user=root
- mysql-dbname=pdnstest
+ launch=gmysql
+ gmysql-host=127.0.0.1
+ gmysql-user=root
+ gmysql-dbname=pdnstest
</screen>
Remove any earlier <command>launch</command> statements. Also remove the <command>bind-example-zones</command>
</warning>
<warning>
<para>
- This section describes the deprecated MySQL backend, which should no longer be used! Use the Generic MySQL backend! See
- <xref linkend="generic-mypgsql-backends">.
+ Be very very sure that you configure the *g*mysql backend and not the mysql backend. See
+ <xref linkend="generic-mypgsql-backends">. If you use the 'mysql' backend things will only appear to work.
</para>
</warning>
</para>
(...)
15:31:30 PowerDNS 1.99.0 (Mar 12 2002, 15:00:28) starting up
15:31:30 About to create 3 backend threads
- 15:31:30 [MySQLbackend] Failed to connect to database: Error: Unknown database 'pdnstest'
- 15:31:30 [MySQLbackend] Failed to connect to database: Error: Unknown database 'pdnstest'
- 15:31:30 [MySQLbackend] Failed to connect to database: Error: Unknown database 'pdnstest'
+ 15:31:30 [gMySQLbackend] Failed to connect to database: Error: Unknown database 'pdnstest'
+ 15:31:30 [gMySQLbackend] Failed to connect to database: Error: Unknown database 'pdnstest'
+ 15:31:30 [gMySQLbackend] Failed to connect to database: Error: Unknown database 'pdnstest'
</screen>
This is as to be expected - we did not yet add anything to MySQL for PDNS to read from. At this point you may also see
<para>
Connect to MySQL as a user with sufficient privileges and issue the following commands:
<screen>
- # mysql
- mysql> CREATE DATABASE pdnstest;
- mysql> use pdnstest;
+create table domains (
+ id INT auto_increment,
+ name VARCHAR(255) NOT NULL,
+ master VARCHAR(20) DEFAULT NULL,
+ last_check INT DEFAULT NULL,
+ type VARCHAR(6) NOT NULL,
+ notified_serial INT DEFAULT NULL,
+ account VARCHAR(40) DEFAULT NULL,
+ primary key (id)
+)type=InnoDB;
- mysql> CREATE TABLE records (
- id int(11) NOT NULL auto_increment,
- domain_id int(11) NOT NULL,
- name varchar(255) NOT NULL,
- type varchar(6) NOT NULL,
- content varchar(255) default NULL,
- ttl int(11) NOT NULL,
- prio int(11) default NULL,
- change_date int(11) default NULL,
- PRIMARY KEY (id),
- KEY name_index(name),
- KEY nametype_index(name,type),
- KEY domainid_index(domain_id)
- );
+CREATE UNIQUE INDEX name_index ON domains(name);
+
+CREATE TABLE records (
+ id INT auto_increment,
+ domain_id INT DEFAULT NULL,
+ name VARCHAR(255) DEFAULT NULL,
+ type VARCHAR(6) DEFAULT NULL,
+ content VARCHAR(255) DEFAULT NULL,
+ ttl INT DEFAULT NULL,
+ prio INT DEFAULT NULL,
+ change_date INT DEFAULT NULL,
+ primary key(id)
+)type=InnoDB;
+
+CREATE INDEX rec_name_index ON records(name);
+CREATE INDEX nametype_index ON records(name,type);
+CREATE INDEX domain_id ON records(domain_id);
+
+create table supermasters (
+ ip VARCHAR(25) NOT NULL,
+ nameserver VARCHAR(255) NOT NULL,
+ account VARCHAR(40) DEFAULT NULL
+);
+
+GRANT SELECT ON supermasters TO pdns;
+GRANT ALL ON domains TO pdns;
+GRANT ALL ON records TO pdns;
</screen>
Now we have a database and an empty table. PDNS should now be able to launch in monitor mode and display no errors:
(...)
15:31:30 PowerDNS 1.99.0 (Mar 12 2002, 15:00:28) starting up
15:31:30 About to create 3 backend threads
- 15:39:55 [MySQLbackend] MySQL connection succeeded
- 15:39:55 [MySQLbackend] MySQL connection succeeded
- 15:39:55 [MySQLbackend] MySQL connection succeeded
+ 15:39:55 [gMySQLbackend] MySQL connection succeeded
+ 15:39:55 [gMySQLbackend] MySQL connection succeeded
+ 15:39:55 [gMySQLbackend] MySQL connection succeeded
</screen>
A sample query sent to the database should now return quickly without data:
Now we need to add some records to our database:
<screen>
# mysql pdnstest
- mysql>
+ mysql> INSERT INTO domains (name, type) values ('test.com', 'NATIVE');
INSERT INTO records (domain_id, name, content, type,ttl,prio)
VALUES (1,'test.com','localhost ahu@ds9a.nl 1','SOA',86400,NULL);
INSERT INTO records (domain_id, name, content, type,ttl,prio)
<para>
Your MySQL installation is probably defaulting to another location for its socket. Can be resolved
by figuring out this location (often <filename>/var/run/mysqld.sock</filename>), and specifying it
- in the configuration file with the <command>mysql-socket</command> parameter.
+ in the configuration file with the <command>gmysql-socket</command> parameter.
</para>
<para>
Another solution is to not connect to the socket, but to 127.0.0.1, which can be achieved by specifying
- <command>mysql-host=127.0.0.1</command>.
+ <command>gmysql-host=127.0.0.1</command>.
</para>
</listitem>
</varlistentry>
unlink(d_local.sun_path);
- if(bind(d_s, (sockaddr*)&d_local,sizeof(d_local))<0)
+ if(bind(d_s, (sockaddr*)&d_local,sizeof(d_local))<0) {
+ unlink(d_local.sun_path);
throw AhuException("Unable to bind to local temporary file: "+string(strerror(errno)));
+ }
if(chmod(d_local.sun_path,0666)<0) { // make sure that pdns can reply!
+ unlink(d_local.sun_path);
perror("fchmod");
exit(1);
}
d_remote.sun_family=AF_UNIX;
strcpy(d_remote.sun_path,fname.c_str());
- if(connect(d_s,(sockaddr*)&d_remote,sizeof(d_remote))<0)
+ if(connect(d_s,(sockaddr*)&d_remote,sizeof(d_remote))<0) {
+ unlink(d_local.sun_path);
throw AhuException("Unable to connect to remote '"+fname+"': "+string(strerror(errno)));
+ }
}
FD_ZERO( &readfds );
FD_SET( d_clientsock, &readfds );
FD_SET( d_serversock, &readfds );
+
+
+ /* this should listen on a TCP port as well for new connections, */
int selret = select( max(d_clientsock,d_serversock) + 1, &readfds, NULL, NULL, &tv );
if(selret<=0)
if (selret == -1 && errno!=EINTR)
/*
PowerDNS Versatile Database Driven Nameserver
- Copyright (C) 2002 PowerDNS.COM BV
+ Copyright (C) 2003 PowerDNS.COM BV
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
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-// $Id: receiver.cc,v 1.6 2003/01/02 15:43:00 ahu Exp $
+// $Id: receiver.cc,v 1.7 2003/03/04 18:33:39 ahu Exp $
#include <cstdio>
#include <signal.h>
#include <cstring>
declareStats();
DLOG(L<<Logger::Warning<<"Verbose logging in effect"<<endl);
- L<<Logger::Warning<<"PowerDNS "<<VERSION<<" (C) 2002 PowerDNS.COM BV ("<<__DATE__", "__TIME__<<") starting up"<<endl;
+ L<<Logger::Warning<<"PowerDNS "<<VERSION<<" (C) 2001-2003 PowerDNS.COM BV ("<<__DATE__", "__TIME__<<") starting up"<<endl;
L<<Logger::Warning<<"PowerDNS comes with ABSOLUTELY NO WARRANTY. "
"This is free software, and you are welcome to redistribute it "
if(packet->d.rd && arg().mustDo("recursor")) {
// now what
// this is a pretty rare event all in all, so we can afford to be slow
+
+ // this code SHOULD attempt to answer from the local cache first!
S.inc("recursing-questions");
Resolver res;
unsigned int len;