]> granicus.if.org Git - pdns/commitdiff
implement incoming AXFR editing with Lua scripts. Useful when operating as a 'signer...
authorBert Hubert <bert.hubert@netherlabs.nl>
Wed, 16 Mar 2011 08:35:09 +0000 (08:35 +0000)
committerBert Hubert <bert.hubert@netherlabs.nl>
Wed, 16 Mar 2011 08:35:09 +0000 (08:35 +0000)
about when the zone was last signed, but can also be used to fiddle with the SOA serial number.
To enable for zone with domain_id=5: insert into domainmetadata (domain_id, kind, content) values (5, 'LUA-AXFR-SCRIPT', './powerdns-example-script.lua');
Use absolute paths pls.

git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@2065 d19b8d6e-7fed-0310-83ef-9ca221ded41b

pdns/Makefile.am
pdns/lua-pdns-recursor.cc
pdns/lua-pdns-recursor.hh
pdns/powerdns-example-script.lua
pdns/slavecommunicator.cc

index 918e1367cb5632ecb49ba9e62fa847b14974757a..7cc7b85187646af2d7aa62214067d321507ad9a2 100644 (file)
@@ -41,11 +41,11 @@ aes/aescrypt.c aes/aes.h aes/aeskey.c aes/aes_modes.c aes/aesopt.h \
 aes/aestab.c aes/aestab.h aes/brg_endian.h aes/brg_types.h aes/dns_random.cc \
 randomhelper.cc namespaces.hh nsecrecords.cc base32.cc dbdnsseckeeper.cc dnssecinfra.cc \
 dnsseckeeper.hh dnssecinfra.hh base32.hh dns.cc dnssecsigner.cc polarrsakeyinfra.cc md5.cc \
-md5.hh signingpipe.cc signingpipe.hh dnslabeltext.cc
+md5.hh signingpipe.cc signingpipe.hh dnslabeltext.cc lua-pdns-recursor.cc
 
 #
 pdns_server_LDFLAGS=@moduleobjects@ @modulelibs@ @DYNLINKFLAGS@ @LIBDL@ @THREADFLAGS@  -Lext/polarssl/library $(BOOST_SERIALIZATION_LDFLAGS) 
-pdns_server_LDADD= -lpolarssl $(BOOST_SERIALIZATION_LIBS) 
+pdns_server_LDADD= -lpolarssl $(BOOST_SERIALIZATION_LIBS) -llua5.1 
 
 if BOTAN19
 pdns_server_SOURCES += botan19signers.cc botansigners.cc
index 9abe0522ddefcbdedf92dbc1efab1e7d9d25a92a..5e0dd7fe39b0ac2b878a6c02b11dc67516ad7706 100644 (file)
@@ -19,6 +19,12 @@ bool PowerDNSLua::preresolve(const ComboAddress& remote, const ComboAddress& loc
   return false;
 }
 
+bool PowerDNSLua::axfrfilter(const ComboAddress& remote, const string& zone, const DNSResourceRecord& in, vector<DNSResourceRecord>& out)
+{
+  return false;
+}
+
+
 PowerDNSLua::~PowerDNSLua()
 {
 
@@ -166,6 +172,86 @@ bool PowerDNSLua::preresolve(const ComboAddress& remote, const ComboAddress& loc
   return passthrough("preresolve", remote, local, query, qtype, ret, res, variable);
 }
 
+bool PowerDNSLua::axfrfilter(const ComboAddress& remote, const string& zone, const DNSResourceRecord& in, vector<DNSResourceRecord>& out)
+{
+  lua_getglobal(d_lua,  "axfrfilter");
+  if(!lua_isfunction(d_lua, -1)) {
+    cerr<<"No such function 'axfrfilter'\n";
+    lua_pop(d_lua, 1);
+    return false;
+  }
+  
+  lua_pushstring(d_lua,  remote.toString().c_str() );
+  lua_pushstring(d_lua,  zone.c_str() );
+  lua_pushstring(d_lua,  in.qname.c_str() );
+  lua_pushnumber(d_lua,  in.qtype.getCode() );
+  lua_pushnumber(d_lua,  in.ttl );
+  lua_pushnumber(d_lua,  in.priority );
+  lua_pushstring(d_lua,  in.content.c_str() );
+
+  if(lua_pcall(d_lua,  7, 2, 0)) { // error 
+    string error=string("lua error in axfrfilter: ")+lua_tostring(d_lua, -1);
+    lua_pop(d_lua, 1);
+    throw runtime_error(error);
+    return false;
+  }
+  
+  int newres = (int)lua_tonumber(d_lua, 1); // did we handle it?
+  if(newres < 0) {
+    //cerr << "handler did not handle"<<endl;
+    lua_pop(d_lua, 2);
+    return false;
+  }
+
+  /* get the result */
+  DNSResourceRecord rr;
+  rr.d_place = DNSResourceRecord::ANSWER;
+  rr.ttl = 3600;
+  rr.domain_id = in.domain_id;
+
+  out.clear();
+
+  /*           1       2   3   4   */
+  /* stack:  boolean table key row */
+
+#ifndef LUA_VERSION_NUM
+  int tableLen = luaL_getn(d_lua, 2);
+#else
+  int tableLen = lua_objlen(d_lua, 2);
+#endif
+  cerr<<"Returned "<<tableLen<<" rows"<<endl;
+  for(int n=1; n < tableLen + 1; ++n) {
+    lua_pushnumber(d_lua, n);
+    lua_gettable(d_lua, 2);
+
+    uint32_t tmpnum=0;
+    if(!getFromTable("qtype", tmpnum)) 
+      rr.qtype=QType::A;
+    else
+      rr.qtype=tmpnum;
+
+    getFromTable("content", rr.content);
+    if(!getFromTable("ttl", rr.ttl))
+      rr.ttl=3600;
+
+    if(!getFromTable("qname", rr.qname))
+      rr.qname = zone;
+
+    if(!getFromTable("place", tmpnum))
+      rr.d_place = DNSResourceRecord::ANSWER;
+    else
+      rr.d_place = (DNSResourceRecord::Place) tmpnum;
+
+    /* removes 'value'; keeps 'key' for next iteration */
+    lua_pop(d_lua, 1); // table
+
+    //    cerr<<"Adding content '"<<rr.content<<"' with place "<<(int)rr.d_place<<" \n";
+    out.push_back(rr);
+  }
+  lua_pop(d_lua, 2); // c
+  return true;
+}
+
 bool PowerDNSLua::getFromTable(const std::string& key, std::string& value)
 {
   lua_pushstring(d_lua, key.c_str()); // 4 is now '1'
@@ -272,7 +358,7 @@ bool PowerDNSLua::passthrough(const string& func, const ComboAddress& remote, co
     /* removes 'value'; keeps 'key' for next iteration */
     lua_pop(d_lua, 1); // table
 
-    //    cerr<<"Adding content '"<<rr.content<<"' with place "<<(int)rr.d_place<<" \n";
+    // cerr<<"Adding content '"<<rr.content<<"' with place "<<(int)rr.d_place<<" \n";
     ret.push_back(rr);
   }
 
index d88f73871f5d12ec479cffd7a96e01a7f8013c61..744a5f249c2eecb7454451d2371c0d970c5ed036 100644 (file)
@@ -13,7 +13,7 @@ public:
   void reload();
   bool preresolve(const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector<DNSResourceRecord>& res, int& ret, bool* variable);
   bool nxdomain(const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector<DNSResourceRecord>& res, int& ret, bool* variable);
-  
+  bool axfrfilter(const ComboAddress& remote, const string& zone, const DNSResourceRecord& in, vector<DNSResourceRecord>& out);
   ComboAddress getLocal()
   {
     return d_local;
index 21fb7930158ebdcd234d9cec66413e2fec8a75f9..8d25ff5d19cdfc2052b446e7a29edbf95f7b6719 100644 (file)
@@ -52,3 +52,17 @@ function nxdomain ( remoteip, domain, qtype )
                return -1, ret
        end
 end
+
+function axfrfilter(remoteip, zone, qname, qtype, ttl, priority, content)
+       if qtype ~= pdns.SOA or zone ~= "secured-by-gost.org"
+       then
+               ret = {}
+               return -1, ret
+       end
+
+       print "got soa!"
+       ret={}
+       ret[1]={qname=qname, qtype=qtype, content=content, ttl=ttl}
+       ret[2]={qname=qname, qtype=pdns.TXT, content=os.date("Retrieved at %Y-%m-%d %H:%M"), ttl=ttl}
+       return 0, ret
+end
index 1e98eee336a624aed0f749bb8dfa48802f61b309..fe85e1b956dba7a5085f462de84e56c7d8772d3e 100644 (file)
 #include <boost/lexical_cast.hpp>
 #include "base64.hh"
 #include "inflighter.cc"
-
+#include "lua-pdns-recursor.hh"
 #include "namespaces.hh"
+#include <boost/scoped_ptr.hpp>
+using boost::scoped_ptr;
 
 void CommunicatorClass::addSuckRequest(const string &domain, const string &master, bool priority)
 {
@@ -109,6 +111,12 @@ void CommunicatorClass::suck(const string &domain,const string &remote)
       B64Decode(tsigsecret64, tsigsecret);
     }
     
+    scoped_ptr<PowerDNSLua> pdl;
+    vector<string> scripts;
+    if(B->getDomainMetadata(domain, "LUA-AXFR-SCRIPT", scripts) && !scripts.empty()) {
+      pdl.reset(new PowerDNSLua(scripts[0]));
+      L<<Logger::Info<<"Loaded Lua script '"<<scripts[0]<<"' to edit the incoming AXFR of '"<<domain<<"'"<<endl;
+    }
     AXFRRetriever retriever(raddr, domain.c_str(), tsigkeyname, tsigalgorithm, tsigsecret);
     
     while(retriever.getChunk(recs)) {
@@ -142,7 +150,15 @@ void CommunicatorClass::suck(const string &domain,const string &remote)
         if(i->qtype.getCode()>=60000)
           throw DBException("Database can't store unknown record type "+lexical_cast<string>(i->qtype.getCode()-1024));
 #endif
-        di.backend->feedRecord(*i);
+        vector<DNSResourceRecord> out;
+        if(pdl && pdl->axfrfilter(raddr, domain, *i, out)) {
+          BOOST_FOREACH(const DNSResourceRecord& rr, out) {
+            di.backend->feedRecord(rr);
+          }
+        }
+        else {
+          di.backend->feedRecord(*i);
+        }
       }
     }