+Changes since 2.9.7:
+ - NS queries for zones we are not authoritative about now get their NS
+ records in the authority section
+ - powerldap.hh doesn't need crypt.h (Richard Arends)
+ - can't handle binary labels, print a warning about that
+ - recursor sometimes did very extended negative caching, sometimes for *days*
+
Changes since 2.9.6:
* need to do work on ( and ) in zones!
feat - added local-query-address (Mark Bergsma)
--sysconfdir=/etc/powerdns \
--infodir='$${datadir}/info' \
--mandir='$${datadir}/man' \
- --with-modules="mysql gmysql gpgsql pipe pdns xdb" --with-dynmodules="" \
- --enable-static-binaries --with-pgsql-lib=/opt/postgresql-with-3.2/lib/
+ --with-modules="mysql gmysql gpgsql pipe pdns xdb" \
+ --with-dynmodules="" \
+ --enable-static-binaries --enable-recursor \
+ --with-pgsql-lib=/opt/postgresql-with-3.2/lib/
make
touch stamp-build-static
--infodir='$${datadir}/info' \
--mandir='$${datadir}/man' \
--with-dynmodules="$(backends)" \
- --with-modules=""
+ --with-modules="" \
+ --enable-recursor
make
touch stamp-build
--strip-unneeded \
"$(tmpdir)"/usr/bin/zone2sql \
"$(tmpdir)"/usr/sbin/pdns_server \
+ "$(tmpdir)"/usr/sbin/pdns_recursor \
"$(tmpdir)"/usr/bin/pdns_control
mv "$(tmpdir)"/etc/powerdns/pdns.conf-dist "$(tmpdir)"/etc/powerdns/pdns.conf
binary-arch: binary-main binary-backend
clean:
- rm -f debian/files debian/substvars stamp-build stamp-build-static
- rm -rf "$(tmpdir)" "$(be_tmpdir)"
-make distclean
-make -C pdns/docs clean
+ rm -f debian/files debian/substvars stamp-build stamp-build-static
+ rm -rf "$(tmpdir)" "$(be_tmpdir)"
.PHONY: clean build binary binary-arch binary-indep
.PHONY: binary-doc binary-main binary-backend
#include "ldapbackend.hh"
-#include <algorithm>
#include <utility>
-#include <ctype.h>
static int Toupper(int c)
{
{
m_msgid = 0;
m_qname = "";
- m_revlookup = 0;
setArgPrefix( "ldap" + suffix );
L << Logger::Notice << backendname << " Server = " << getArg( "host" ) << ":" << getArg( "port" ) << endl;
- // Initialize connections and pass exeptions to caller
+ try
+ {
m_pldap = new PowerLDAP( getArg( "host" ), (u_int16_t) atoi( getArg( "port" ).c_str() ) );
m_pldap->simpleBind( getArg( "binddn" ), getArg( "secret" ) );
+ }
+ catch( LDAPException &e )
+ {
+ L << Logger::Error << backendname << " Ldap connection failed: " << e.what() << endl;
+ throw( AhuException( "Unable to bind to ldap server" ) );
+ }
L << Logger::Notice << backendname << " Ldap connection succeeded" << endl;
}
void LdapBackend::lookup( const QType &qtype, const string &qname, DNSPacket *dnspkt, int zoneid )
{
- int len = 0;
+ int i, len;
vector<string> parts;
string filter, attr, ipaddr;
char** attributes = attrany;
- char* attronly[] = { "associatedDomain", NULL, NULL };
+ char* attronly[] = { NULL, NULL };
m_qtype = qtype;
m_qname = qname;
len = qname.length();
- if( len > 20 && qname.substr( len - 13, 13 ) == ".in-addr.arpa" )
+ if( qname.substr( len - 5, 5 ) == ".arpa" || qname.substr( len - 4, 4 ) == ".int" )
+ {
+ stringtok( parts, qname, "." );
+ if (parts[parts.size()-2] == "ip6" )
+ {
+ filter = "(aaaaRecord=" + parts[parts.size()-3];
+ for( i = parts.size() - 4; i >= 0; i-- ) // reverse and cut .ip6.arpa or .ip6.int
+ {
+ filter += ":" + parts[i];
+ }
+ filter = + ")";
+ }
+ else
{
- m_revlookup = 1;
- stringtok( parts, qname.substr( 0, len - 13 ), "." );
filter = "(aRecord=" + parts[3] + "." + parts[2] + "." + parts[1] + "." + parts[0] + ")";
+ }
+
+ filter = m_pldap->escape( filter );
+ attronly[0] = "associatedDomain";
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[1] = (char*) attr.c_str();
+ attronly[0] = (char*) attr.c_str();
attributes = attronly;
}
+ }
- // Pass exception if an error occurs
+ try
+ {
m_msgid = m_pldap->search( getArg("basedn"), filter, (const char**) attributes );
+ }
+ catch( LDAPException &e )
+ {
+ L << Logger::Warning << backendname << " Unable to initiate search: " << e.what() << endl;
+ return;
+ }
+
L << Logger::Info << backendname << " Search = basedn: " << getArg( "basedn" ) << ", filter: " << filter << ", qtype: " << qtype.getName() << endl;
}
PowerLDAP::sentry_t::iterator attribute;
- do
- {
+Redo:
+
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();
+ if( attribute != m_result.end() && !attribute->second.empty() )
+ {
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.getCode() == QType::ANY || m_qtype.getCode() == qt.getCode() ) )
+ if( m_qtype.getCode() == QType::ANY || m_qtype.getCode() == qt.getCode() )
{
content = attribute->second.back();
attribute->second.pop_back();
L << Logger::Info << backendname << " Record = qname: " << rr.qname << ", qtype: " << (rr.qtype).getName() << ", priority: " << rr.priority << ", content: " << rr.content << endl;
return true;
}
+ }
m_result.erase( attribute );
}
+
+ try
+ {
+ if( m_pldap->getSearchEntry( m_msgid, m_result ) == true )
+ {
+ if( m_result.find( "associatedDomain" ) != m_result.end() )
+ {
+ m_result["PTRRecord"] = m_result["associatedDomain"];
+ m_result.erase( "associatedDomain" );
+ }
+ goto Redo;
+ }
+ }
+ catch( LDAPException &e )
+ {
+ L << Logger::Warning << backendname << " Search failed: " << e.what() << endl;
}
- while( m_pldap->getSearchEntry( m_msgid, m_result ) );
return false;
}
+#include <algorithm>
#include <sstream>
#include <utility>
#include <string>
#include <ldap.h>
#include <stdlib.h>
+#include <ctype.h>
#include <unistd.h>
#include <pdns/dns.hh>
#include <pdns/utility.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;
#define POWERLDAP_HH
#include <map>
#include <vector>
-#include <crypt.h>
#include <exception>
#include <stdexcept>
#include <string>
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.cc,v 1.19 2003/03/20 13:29:29 ahu Exp $
+// $Id: dnspacket.cc,v 1.20 2003/03/27 10:40:40 ahu Exp $
#include "utility.hh"
#include <cstdio>
while((n=*(unsigned char *)p++)) {
char tmp[256];
- if((n & 0xc0) == 0xc0 ) {
- unsigned int labelOffset=(n&~0xc0)*256+ (int)*(unsigned char *)p;
- expand((unsigned char *)stringbuffer.c_str()+labelOffset,end,expanded,depth++);
- return 1+p-begin;
- }
-
- if(p+n>=end) { // this is a bogus packet, references beyond the end of the buffer
- throw AhuException("Label claims to be longer than packet");
- }
- strncpy((char *)tmp,(const char *)p,n);
-
- if(*(p+n)) { // add a ., except at the end
- tmp[n]='.';
- tmp[n+1]=0;
- }
- else
- tmp[n]=0;
+ if(n==0x41)
+ throw AhuException("unable to expand binary label, generally caused by deprecated IPv6 reverse lookups");
- expanded+=tmp;
+ if((n & 0xc0) == 0xc0 ) {
+ unsigned int labelOffset=(n&~0xc0)*256+ (int)*(unsigned char *)p;
+ expand((unsigned char *)stringbuffer.c_str()+labelOffset,end,expanded,depth++);
+ return 1+p-begin;
+ }
- p+=n;
+ if(p+n>=end) { // this is a bogus packet, references beyond the end of the buffer
+ throw AhuException("Label claims to be longer than packet");
}
+ strncpy((char *)tmp,(const char *)p,n);
+ if(*(p+n)) { // add a ., except at the end
+ tmp[n]='.';
+ tmp[n+1]=0;
+ }
+ else
+ tmp[n]=0;
+
+ expanded+=tmp;
+
+ p+=n;
+ }
+
// lowercase(qdomain); (why was this?)
-
+
return p-begin;
}
return expand(orig,end,qdomain);
}
catch(AhuException &ae) {
- L<<Logger::Error<<"On retrieving question of packet, encountered error: "<<ae.reason<<endl;
+ L<<Logger::Error<<"On retrieving question of packet from "<<getRemote()<<", encountered error: "<<ae.reason<<endl;
}
return -1;
}
</affiliation>
</author>
- <PubDate>v2.1 $Date: 2003/03/20 12:53:44 $</PubDate>
+ <PubDate>v2.1 $Date: 2003/03/27 10:40:40 $</PubDate>
<Abstract>
<para>
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>config-dir</term>
+ <listitem>
+ <para>
+ Directory where the configuration file can be found.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term>daemon</term>
<listitem>
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>quiet</term>
+ <listitem>
+ <para>
+ Don't log queries.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term>trace</term>
<listitem>
#include "arguments.hh"
#include "lwres.hh"
-map<string,string> SyncRes::s_negcache;
+map<string,NegCacheEntry> SyncRes::s_negcache;
unsigned int SyncRes::s_queries;
unsigned int SyncRes::s_outqueries;
unsigned int SyncRes::s_throttledqueries;
return false;
}
+
+
+
bool SyncRes::doCacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res)
{
bool giveNegative=false;
string sqname(qname);
QType sqt(qtype);
+ u_int32_t sttl=0;
if(s_negcache.count(toLower(qname))) {
res=0;
- map<string,string>::const_iterator ni=s_negcache.find(toLower(qname));
+ map<string,NegCacheEntry>::const_iterator ni=s_negcache.find(toLower(qname));
+ if(time(0) < ni->second.ttd) {
+ sttl=ni->second.ttd-time(0);
+ LOG<<prefix<<qname<<": Entire record '"<<toLower(qname)<<"', is negatively cached for another "<<sttl<<" seconds"<<endl;
+ res=RCode::NXDomain;
+ giveNegative=true;
+ sqname=ni->second.name;
+ sqt="SOA";
- LOG<<prefix<<qname<<": Entire record '"<<toLower(qname)<<"', is negatively cached "<<endl;
- res=RCode::NXDomain;
- giveNegative=true;
- sqname=ni->second;
- sqt="SOA";
+ }
+ else {
+ LOG<<prefix<<qname<<": Entire record '"<<toLower(qname)<<"' was negatively cached, but entry expired"<<endl;
+ s_negcache.erase(toLower(qname));
+ }
}
- else {
+
+ if(!giveNegative) { // let's try some more
tuple=toLower(qname)+"|"+qtype.getName();
LOG<<prefix<<qname<<": Looking for direct cache hit of '"<<tuple<<"', "<<s_negcache.count(tuple)<<endl;
res=0;
- map<string,string>::const_iterator ni=s_negcache.find(tuple);
+ map<string,NegCacheEntry>::const_iterator ni=s_negcache.find(tuple);
if(ni!=s_negcache.end()) {
- LOG<<prefix<<qname<<": "<<qtype.getName()<<" is negatively cached, will return immediately if we still have SOA ("<<ni->second<<") to prove it"<<endl;
- res=RCode::NoError; // only this record doesn't exist
- giveNegative=true;
- sqname=ni->second;
- sqt="SOA";
+ if(time(0) < ni->second.ttd) {
+ sttl=ni->second.ttd-time(0);
+ LOG<<prefix<<qname<<": "<<qtype.getName()<<" is negatively cached for another "<<sttl<<" seconds"<<endl;
+ res=RCode::NoError; // only this record doesn't exist
+ giveNegative=true;
+ sqname=ni->second.name;
+ sqt="SOA";
+ }
+ else {
+ LOG<<prefix<<qname<<": "<<qtype.getName()<<" was negatively cached, but entry expired"<<endl;
+ s_negcache.erase(toLower(tuple));
+ }
}
}
if(j->ttl>(unsigned int)time(0)) {
DNSResourceRecord rr=*j;
rr.ttl-=time(0);
- if(giveNegative)
+ if(giveNegative) {
rr.d_place=DNSResourceRecord::AUTHORITY;
+ rr.ttl=sttl;
+ }
ret.push_back(rr);
LOG<<"[ttl="<<rr.ttl<<"] ";
found=true;
LOG<<prefix<<qname<<": got negative caching indication for RECORD '"<<toLower(qname)+"'"<<endl;
ret.push_back(*i);
- s_negcache[toLower(qname)]=i->qname;
+ NegCacheEntry ne;
+ ne.name=i->qname;
+ ne.ttd=time(0)+i->ttl;
+ s_negcache[toLower(qname)]=ne;
negindic=true;
}
else if(i->d_place==DNSResourceRecord::ANSWER && i->qname==qname && i->qtype.getCode()==QType::CNAME && (!(qtype==QType(QType::CNAME)))) {
d_lwr.d_rcode==RCode::NoError) {
LOG<<prefix<<qname<<": got negative caching indication for '"<<toLower(qname)+"|"+i->qtype.getName()+"'"<<endl;
ret.push_back(*i);
-
- s_negcache[toLower(qname)+"|"+qtype.getName()]=i->qname;
+
+ NegCacheEntry ne;
+ ne.name=i->qname;
+ ne.ttd=time(0)+i->ttl;
+ s_negcache[toLower(qname)+"|"+qtype.getName()]=ne;
negindic=true;
}
}
void replaceCache(const string &qname, const QType &qt, const set<DNSResourceRecord>& content);
int getCache(const string &qname, const QType& qt, set<DNSResourceRecord>* res=0);
+struct NegCacheEntry
+{
+ string name;
+ time_t ttd;
+};
template<class Thing> class Throttle
{
static unsigned int s_outqueries;
unsigned int d_outqueries;
unsigned int d_throttledqueries;
- static map<string,string> s_negcache;
+ static map<string,NegCacheEntry> s_negcache;
static Throttle<string> s_throttle;
private:
struct GetBestNSAnswer;