@@ -0,0 +1,407 @@
+Index: modules/gmysqlbackend/gmysqlbackend.cc
+===================================================================
+--- modules/gmysqlbackend/gmysqlbackend.cc (.../Original%20sources.) (revision 13)
++++ modules/gmysqlbackend/gmysqlbackend.cc (.../withAXFRpatch) (revision 13)
+@@ -35,6 +35,24 @@
+ throw AhuException("Unable to launch "+mode+" connection: "+e.txtReason());
+ }
+ L<<Logger::Warning<<mode<<" Connection succesful"<<endl;
++
++ if(!getArg("slave-socket").empty() || !getArg("slave-host").empty()) {
++ try {
++ setDBSlave(new SMySQL(getArg("slave-dbname"),
++ getArg("slave-host"),
++ getArgAsNum("slave-port"),
++ getArg("slave-socket"),
++ getArg("slave-user"),
++ getArg("slave-password")));
++ L<<Logger::Warning<<mode<<" Slave connection successful."<<endl;
++ } catch(ArgException &e) {
++ // Ignore exception, slave not
++ L<<Logger::Warning<<mode<<" Slave configuration."<<endl;
++ } catch(SSqlException &e) {
++ // Ignore exception, slave not
++ L<<Logger::Warning<<mode<<" Unable to connect to slave."<<endl;
++ }
++ }
+ }
+
+ class gMySQLFactory : public BackendFactory
+@@ -51,6 +69,13 @@
+ declare(suffix,"socket","Pdns backend socket to connect to","");
+ declare(suffix,"password","Pdns backend password to connect with","");
+
++ declare(suffix,"slave-dbname","Pdns backend database name to connect to","");
++ declare(suffix,"slave-user","Database backend user to connect as","");
++ declare(suffix,"slave-host","Database backend host to connect to","");
++ declare(suffix,"slave-port","Database backend port to connect to","0");
++ declare(suffix,"slave-socket","Pdns backend socket to connect to","");
++ declare(suffix,"slave-password","Pdns backend password to connect with","");
++
+ declare(suffix,"basic-query","Basic query","select content,ttl,prio,type,domain_id,name from records where type='%s' and name='%s'");
+ declare(suffix,"id-query","Basic with ID query","select content,ttl,prio,type,domain_id,name from records where type='%s' and name='%s' and domain_id=%d");
+ declare(suffix,"wildcard-query","Wildcard query","select content,ttl,prio,type,domain_id,name from records where type='%s' and name like '%s'");
+@@ -75,6 +100,7 @@
+ declare(suffix,"info-all-master-query","", "select id,name,master,last_check,notified_serial,type from domains where type='MASTER'");
+ declare(suffix,"delete-zone-query","", "delete from records where domain_id=%d");
+
++ declare(suffix,"lookup-axfr-allow","", "select zone_grants from domains where name='%s'");
+
+ }
+
+Index: pdns/ueberbackend.cc
+===================================================================
+--- pdns/ueberbackend.cc (.../Original%20sources.) (revision 13)
++++ pdns/ueberbackend.cc (.../withAXFRpatch) (revision 13)
+@@ -60,6 +60,15 @@
+ #define RTLD_NOW RTLD_LAZY
+ #endif
+
++bool UeberBackend::checkAXFRByZone( const std::string& name , const std::string& ip)
++{
++ for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
++ {
++ if(( *i )->checkAXFRByZone( name , ip) ) return true;
++ }
++ return false;
++}
++
+ //! Loads a module and reports it to all UeberBackend threads
+ bool UeberBackend::loadmodule(const string &name)
+ {
+
+Index: pdns/tcpreceiver.cc
+===================================================================
+--- pdns/tcpreceiver.cc (.../Original%20sources.) (revision 13)
++++ pdns/tcpreceiver.cc (.../withAXFRpatch) (revision 13)
+@@ -346,16 +346,42 @@
+ if(::arg().mustDo("disable-axfr"))
+ return false;
+
+- if( ::arg()["allow-axfr-ips"].empty() || d_ng.match( (ComboAddress *) &q->remote ) )
+- return true;
++ if(::arg().mustDo("axfr-by-zone") )
++ {
++ //DNSBackend *backend = s_P->getBackend();
++ PacketHandler P;
++ DNSBackend *backend = P.getBackend();
++ if(backend->checkAXFRByZone( q->qdomain , q->getRemote()) )
++ {
++ L << Logger::Warning
++ <<"Approved zone-based AXFR of '"<<q->qdomain
++ << q->getRemote()<<endl;
++ return true;
++ }
++ //a empty list is a failure in case of 'axfr-by-zone'
++ else if(d_ng.match( (ComboAddress *) &q->remote ) )
++ {
++ L << Logger::Warning << "allowed by config file" << endl;
++ return true;
++ }
++ }
++ else
++ {
++ // L << Logger::Warning<< "no axfr-by-zone" <<endl;
++ if(::arg()["allow-axfr-ips"].empty()
++ || d_ng.match( (ComboAddress *) &q->remote ) )
++ return true;
++ }
+
+ extern CommunicatorClass Communicator;
+
+ if(Communicator.justNotified(q->qdomain, q->getRemote())) { // we just notified this ip
+- L<<Logger::Warning<<"Approved AXFR of '"<<q->qdomain<<"' from recently notified slave "<<q->getRemote()<<endl;
++ L << Logger::Warning << "Approved AXFR of '" << q->qdomain << "' from recently notified slave " << q->getRemote() << endl;
+ return true;
+ }
+
++ L << Logger::Warning << "AXFR FAILED" << endl;
++
+ return false;
+ }
+
+Index: pdns/common_startup.cc
+===================================================================
+--- pdns/common_startup.cc (.../Original%20sources.) (revision 13)
++++ pdns/common_startup.cc (.../withAXFRpatch) (revision 13)
+@@ -127,6 +127,9 @@
+
+ ::arg().set("max-cache-entries", "Maximum number of cache entries")="1000000";
+ ::arg().set("entropy-source", "If set, read entropy from this file")="/dev/urandom";
++
++ ::arg().set("axfr-by-zone","allows configuration of axfr-allows by zone")="yes";
++ ::arg().setSwitch("axfr-by-zone","allows configuration of axfr-allows by zone")="yes";
+ }
+
+ void declareStats(void)
+Index: pdns/backends/gsql/gsqlbackend.cc
+===================================================================
+--- pdns/backends/gsql/gsqlbackend.cc (.../Original%20sources.) (revision 13)
++++ pdns/backends/gsql/gsqlbackend.cc (.../withAXFRpatch) (revision 13)
+@@ -16,10 +16,78 @@
+ #include "pdns/ahuexception.hh"
+ #include "pdns/logger.hh"
+ #include "pdns/arguments.hh"
++#include "pdns/iputils.hh"
+ #include <boost/algorithm/string.hpp>
+ #include <sstream>
++
+ using namespace boost;
+
++bool GSQLBackend::checkAXFRByZone(const std::string& name , const std::string& ip)
++{
++// L << Logger::Warning
++// << "ZONE-AXFR: checking " << name << " with " << ip << std::endl;
++
++ char output[1024];
++
++ snprintf( output,sizeof(output)-1,
++ d_LookupAxfrAllow.c_str(),name.c_str()
++ );
++
++ L << Logger::Warning
++ << "ZONE-AXFR: checking " << name << " with " << ip << std::endl
++ << "STATEMENT: "<< output << std::endl;
++
++ try
++ {
++ d_db->doQuery(output, d_result);
++ }
++ catch(SSqlException &e)
++ {
++ throw AhuException("GSQLBackend unable to select AXFR-by Zone . name "
++ + name
++ + " with ip "
++ + ip
++ + " : "
++ + e.txtReason());
++ }
++
++ if(!d_result.size())
++ return false;
++
++ if(d_result.size() > 1)
++ throw AhuException("Ambigous entries ' "
++ + name
++ + "' exists more than once");
++
++ SSql::row_t row(d_result[0]);
++ SSql::row_t::const_reverse_iterator zone_str_iter(row.rbegin());
++ std::vector<std::string> allowed_ips;
++
++ stringtok(allowed_ips, *zone_str_iter, ";");
++ std::vector<std::string>::iterator iter(allowed_ips.begin()),
++ end(allowed_ips.end());
++
++ for(;iter!=end;++iter)
++ {
++ trim(*iter);
++
|